Line data Source code
1 : /* bio_asn1.c */
2 : /*
3 : * Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
4 : * project.
5 : */
6 : /* ====================================================================
7 : * Copyright (c) 2006 The OpenSSL Project. All rights reserved.
8 : *
9 : * Redistribution and use in source and binary forms, with or without
10 : * modification, are permitted provided that the following conditions
11 : * are met:
12 : *
13 : * 1. Redistributions of source code must retain the above copyright
14 : * notice, this list of conditions and the following disclaimer.
15 : *
16 : * 2. Redistributions in binary form must reproduce the above copyright
17 : * notice, this list of conditions and the following disclaimer in
18 : * the documentation and/or other materials provided with the
19 : * distribution.
20 : *
21 : * 3. All advertising materials mentioning features or use of this
22 : * software must display the following acknowledgment:
23 : * "This product includes software developed by the OpenSSL Project
24 : * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
25 : *
26 : * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
27 : * endorse or promote products derived from this software without
28 : * prior written permission. For written permission, please contact
29 : * licensing@OpenSSL.org.
30 : *
31 : * 5. Products derived from this software may not be called "OpenSSL"
32 : * nor may "OpenSSL" appear in their names without prior written
33 : * permission of the OpenSSL Project.
34 : *
35 : * 6. Redistributions of any form whatsoever must retain the following
36 : * acknowledgment:
37 : * "This product includes software developed by the OpenSSL Project
38 : * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
39 : *
40 : * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
41 : * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43 : * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
44 : * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46 : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47 : * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49 : * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51 : * OF THE POSSIBILITY OF SUCH DAMAGE.
52 : * ====================================================================
53 : *
54 : * This product includes cryptographic software written by Eric Young
55 : * (eay@cryptsoft.com). This product includes software written by Tim
56 : * Hudson (tjh@cryptsoft.com).
57 : *
58 : */
59 :
60 : /*
61 : * Experimental ASN1 BIO. When written through the data is converted to an
62 : * ASN1 string type: default is OCTET STRING. Additional functions can be
63 : * provided to add prefix and suffix data.
64 : */
65 :
66 : #include <string.h>
67 : #include <openssl/bio.h>
68 : #include <openssl/asn1.h>
69 :
70 : /* Must be large enough for biggest tag+length */
71 : #define DEFAULT_ASN1_BUF_SIZE 20
72 :
73 : typedef enum {
74 : ASN1_STATE_START,
75 : ASN1_STATE_PRE_COPY,
76 : ASN1_STATE_HEADER,
77 : ASN1_STATE_HEADER_COPY,
78 : ASN1_STATE_DATA_COPY,
79 : ASN1_STATE_POST_COPY,
80 : ASN1_STATE_DONE
81 : } asn1_bio_state_t;
82 :
83 : typedef struct BIO_ASN1_EX_FUNCS_st {
84 : asn1_ps_func *ex_func;
85 : asn1_ps_func *ex_free_func;
86 : } BIO_ASN1_EX_FUNCS;
87 :
88 : typedef struct BIO_ASN1_BUF_CTX_t {
89 : /* Internal state */
90 : asn1_bio_state_t state;
91 : /* Internal buffer */
92 : unsigned char *buf;
93 : /* Size of buffer */
94 : int bufsize;
95 : /* Current position in buffer */
96 : int bufpos;
97 : /* Current buffer length */
98 : int buflen;
99 : /* Amount of data to copy */
100 : int copylen;
101 : /* Class and tag to use */
102 : int asn1_class, asn1_tag;
103 : asn1_ps_func *prefix, *prefix_free, *suffix, *suffix_free;
104 : /* Extra buffer for prefix and suffix data */
105 : unsigned char *ex_buf;
106 : int ex_len;
107 : int ex_pos;
108 : void *ex_arg;
109 : } BIO_ASN1_BUF_CTX;
110 :
111 : static int asn1_bio_write(BIO *h, const char *buf, int num);
112 : static int asn1_bio_read(BIO *h, char *buf, int size);
113 : static int asn1_bio_puts(BIO *h, const char *str);
114 : static int asn1_bio_gets(BIO *h, char *str, int size);
115 : static long asn1_bio_ctrl(BIO *h, int cmd, long arg1, void *arg2);
116 : static int asn1_bio_new(BIO *h);
117 : static int asn1_bio_free(BIO *data);
118 : static long asn1_bio_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp);
119 :
120 : static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size);
121 : static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
122 : asn1_ps_func *cleanup, asn1_bio_state_t next);
123 : static int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
124 : asn1_ps_func *setup,
125 : asn1_bio_state_t ex_state,
126 : asn1_bio_state_t other_state);
127 :
128 : static BIO_METHOD methods_asn1 = {
129 : BIO_TYPE_ASN1,
130 : "asn1",
131 : asn1_bio_write,
132 : asn1_bio_read,
133 : asn1_bio_puts,
134 : asn1_bio_gets,
135 : asn1_bio_ctrl,
136 : asn1_bio_new,
137 : asn1_bio_free,
138 : asn1_bio_callback_ctrl,
139 : };
140 :
141 0 : BIO_METHOD *BIO_f_asn1(void)
142 : {
143 0 : return (&methods_asn1);
144 : }
145 :
146 0 : static int asn1_bio_new(BIO *b)
147 : {
148 : BIO_ASN1_BUF_CTX *ctx;
149 0 : ctx = OPENSSL_malloc(sizeof(BIO_ASN1_BUF_CTX));
150 0 : if (!ctx)
151 : return 0;
152 0 : if (!asn1_bio_init(ctx, DEFAULT_ASN1_BUF_SIZE)) {
153 0 : OPENSSL_free(ctx);
154 0 : return 0;
155 : }
156 0 : b->init = 1;
157 0 : b->ptr = (char *)ctx;
158 0 : b->flags = 0;
159 0 : return 1;
160 : }
161 :
162 0 : static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size)
163 : {
164 0 : ctx->buf = OPENSSL_malloc(size);
165 0 : if (!ctx->buf)
166 : return 0;
167 0 : ctx->bufsize = size;
168 0 : ctx->bufpos = 0;
169 0 : ctx->buflen = 0;
170 0 : ctx->copylen = 0;
171 0 : ctx->asn1_class = V_ASN1_UNIVERSAL;
172 0 : ctx->asn1_tag = V_ASN1_OCTET_STRING;
173 0 : ctx->ex_buf = 0;
174 0 : ctx->ex_pos = 0;
175 0 : ctx->ex_len = 0;
176 0 : ctx->state = ASN1_STATE_START;
177 0 : return 1;
178 : }
179 :
180 0 : static int asn1_bio_free(BIO *b)
181 : {
182 : BIO_ASN1_BUF_CTX *ctx;
183 0 : ctx = (BIO_ASN1_BUF_CTX *)b->ptr;
184 0 : if (ctx == NULL)
185 : return 0;
186 0 : if (ctx->buf)
187 0 : OPENSSL_free(ctx->buf);
188 0 : OPENSSL_free(ctx);
189 0 : b->init = 0;
190 0 : b->ptr = NULL;
191 0 : b->flags = 0;
192 0 : return 1;
193 : }
194 :
195 0 : static int asn1_bio_write(BIO *b, const char *in, int inl)
196 : {
197 : BIO_ASN1_BUF_CTX *ctx;
198 : int wrmax, wrlen, ret;
199 : unsigned char *p;
200 0 : if (!in || (inl < 0) || (b->next_bio == NULL))
201 : return 0;
202 0 : ctx = (BIO_ASN1_BUF_CTX *)b->ptr;
203 0 : if (ctx == NULL)
204 : return 0;
205 :
206 : wrlen = 0;
207 : ret = -1;
208 :
209 : for (;;) {
210 0 : switch (ctx->state) {
211 :
212 : /* Setup prefix data, call it */
213 : case ASN1_STATE_START:
214 0 : if (!asn1_bio_setup_ex(b, ctx, ctx->prefix,
215 : ASN1_STATE_PRE_COPY, ASN1_STATE_HEADER))
216 : return 0;
217 : break;
218 :
219 : /* Copy any pre data first */
220 : case ASN1_STATE_PRE_COPY:
221 :
222 0 : ret = asn1_bio_flush_ex(b, ctx, ctx->prefix_free,
223 : ASN1_STATE_HEADER);
224 :
225 0 : if (ret <= 0)
226 : goto done;
227 :
228 : break;
229 :
230 : case ASN1_STATE_HEADER:
231 0 : ctx->buflen = ASN1_object_size(0, inl, ctx->asn1_tag) - inl;
232 0 : OPENSSL_assert(ctx->buflen <= ctx->bufsize);
233 0 : p = ctx->buf;
234 0 : ASN1_put_object(&p, 0, inl, ctx->asn1_tag, ctx->asn1_class);
235 0 : ctx->copylen = inl;
236 0 : ctx->state = ASN1_STATE_HEADER_COPY;
237 :
238 0 : break;
239 :
240 : case ASN1_STATE_HEADER_COPY:
241 0 : ret = BIO_write(b->next_bio, ctx->buf + ctx->bufpos, ctx->buflen);
242 0 : if (ret <= 0)
243 : goto done;
244 :
245 0 : ctx->buflen -= ret;
246 0 : if (ctx->buflen)
247 0 : ctx->bufpos += ret;
248 : else {
249 0 : ctx->bufpos = 0;
250 0 : ctx->state = ASN1_STATE_DATA_COPY;
251 : }
252 :
253 : break;
254 :
255 : case ASN1_STATE_DATA_COPY:
256 :
257 0 : if (inl > ctx->copylen)
258 : wrmax = ctx->copylen;
259 : else
260 : wrmax = inl;
261 0 : ret = BIO_write(b->next_bio, in, wrmax);
262 0 : if (ret <= 0)
263 : break;
264 0 : wrlen += ret;
265 0 : ctx->copylen -= ret;
266 0 : in += ret;
267 0 : inl -= ret;
268 :
269 0 : if (ctx->copylen == 0)
270 0 : ctx->state = ASN1_STATE_HEADER;
271 :
272 0 : if (inl == 0)
273 : goto done;
274 :
275 : break;
276 :
277 : default:
278 0 : BIO_clear_retry_flags(b);
279 0 : return 0;
280 :
281 : }
282 :
283 : }
284 :
285 : done:
286 0 : BIO_clear_retry_flags(b);
287 0 : BIO_copy_next_retry(b);
288 :
289 0 : return (wrlen > 0) ? wrlen : ret;
290 :
291 : }
292 :
293 0 : static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
294 : asn1_ps_func *cleanup, asn1_bio_state_t next)
295 : {
296 : int ret;
297 0 : if (ctx->ex_len <= 0)
298 : return 1;
299 : for (;;) {
300 0 : ret = BIO_write(b->next_bio, ctx->ex_buf + ctx->ex_pos, ctx->ex_len);
301 0 : if (ret <= 0)
302 : break;
303 0 : ctx->ex_len -= ret;
304 0 : if (ctx->ex_len > 0)
305 0 : ctx->ex_pos += ret;
306 : else {
307 0 : if (cleanup)
308 0 : cleanup(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg);
309 0 : ctx->state = next;
310 0 : ctx->ex_pos = 0;
311 0 : break;
312 : }
313 0 : }
314 0 : return ret;
315 : }
316 :
317 0 : static int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
318 : asn1_ps_func *setup,
319 : asn1_bio_state_t ex_state,
320 : asn1_bio_state_t other_state)
321 : {
322 0 : if (setup && !setup(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg)) {
323 0 : BIO_clear_retry_flags(b);
324 0 : return 0;
325 : }
326 0 : if (ctx->ex_len > 0)
327 0 : ctx->state = ex_state;
328 : else
329 0 : ctx->state = other_state;
330 : return 1;
331 : }
332 :
333 0 : static int asn1_bio_read(BIO *b, char *in, int inl)
334 : {
335 0 : if (!b->next_bio)
336 : return 0;
337 0 : return BIO_read(b->next_bio, in, inl);
338 : }
339 :
340 0 : static int asn1_bio_puts(BIO *b, const char *str)
341 : {
342 0 : return asn1_bio_write(b, str, strlen(str));
343 : }
344 :
345 0 : static int asn1_bio_gets(BIO *b, char *str, int size)
346 : {
347 0 : if (!b->next_bio)
348 : return 0;
349 0 : return BIO_gets(b->next_bio, str, size);
350 : }
351 :
352 0 : static long asn1_bio_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
353 : {
354 0 : if (b->next_bio == NULL)
355 : return (0);
356 0 : return BIO_callback_ctrl(b->next_bio, cmd, fp);
357 : }
358 :
359 0 : static long asn1_bio_ctrl(BIO *b, int cmd, long arg1, void *arg2)
360 : {
361 : BIO_ASN1_BUF_CTX *ctx;
362 : BIO_ASN1_EX_FUNCS *ex_func;
363 : long ret = 1;
364 0 : ctx = (BIO_ASN1_BUF_CTX *)b->ptr;
365 0 : if (ctx == NULL)
366 : return 0;
367 0 : switch (cmd) {
368 :
369 : case BIO_C_SET_PREFIX:
370 : ex_func = arg2;
371 0 : ctx->prefix = ex_func->ex_func;
372 0 : ctx->prefix_free = ex_func->ex_free_func;
373 0 : break;
374 :
375 : case BIO_C_GET_PREFIX:
376 : ex_func = arg2;
377 0 : ex_func->ex_func = ctx->prefix;
378 0 : ex_func->ex_free_func = ctx->prefix_free;
379 0 : break;
380 :
381 : case BIO_C_SET_SUFFIX:
382 : ex_func = arg2;
383 0 : ctx->suffix = ex_func->ex_func;
384 0 : ctx->suffix_free = ex_func->ex_free_func;
385 0 : break;
386 :
387 : case BIO_C_GET_SUFFIX:
388 : ex_func = arg2;
389 0 : ex_func->ex_func = ctx->suffix;
390 0 : ex_func->ex_free_func = ctx->suffix_free;
391 0 : break;
392 :
393 : case BIO_C_SET_EX_ARG:
394 0 : ctx->ex_arg = arg2;
395 0 : break;
396 :
397 : case BIO_C_GET_EX_ARG:
398 0 : *(void **)arg2 = ctx->ex_arg;
399 0 : break;
400 :
401 : case BIO_CTRL_FLUSH:
402 0 : if (!b->next_bio)
403 : return 0;
404 :
405 : /* Call post function if possible */
406 0 : if (ctx->state == ASN1_STATE_HEADER) {
407 0 : if (!asn1_bio_setup_ex(b, ctx, ctx->suffix,
408 : ASN1_STATE_POST_COPY, ASN1_STATE_DONE))
409 : return 0;
410 : }
411 :
412 0 : if (ctx->state == ASN1_STATE_POST_COPY) {
413 0 : ret = asn1_bio_flush_ex(b, ctx, ctx->suffix_free,
414 : ASN1_STATE_DONE);
415 0 : if (ret <= 0)
416 : return ret;
417 : }
418 :
419 0 : if (ctx->state == ASN1_STATE_DONE)
420 0 : return BIO_ctrl(b->next_bio, cmd, arg1, arg2);
421 : else {
422 0 : BIO_clear_retry_flags(b);
423 0 : return 0;
424 : }
425 : break;
426 :
427 : default:
428 0 : if (!b->next_bio)
429 : return 0;
430 0 : return BIO_ctrl(b->next_bio, cmd, arg1, arg2);
431 :
432 : }
433 :
434 : return ret;
435 : }
436 :
437 : static int asn1_bio_set_ex(BIO *b, int cmd,
438 : asn1_ps_func *ex_func, asn1_ps_func *ex_free_func)
439 : {
440 : BIO_ASN1_EX_FUNCS extmp;
441 0 : extmp.ex_func = ex_func;
442 0 : extmp.ex_free_func = ex_free_func;
443 0 : return BIO_ctrl(b, cmd, 0, &extmp);
444 : }
445 :
446 : static int asn1_bio_get_ex(BIO *b, int cmd,
447 : asn1_ps_func **ex_func,
448 : asn1_ps_func **ex_free_func)
449 : {
450 : BIO_ASN1_EX_FUNCS extmp;
451 : int ret;
452 0 : ret = BIO_ctrl(b, cmd, 0, &extmp);
453 0 : if (ret > 0) {
454 0 : *ex_func = extmp.ex_func;
455 0 : *ex_free_func = extmp.ex_free_func;
456 : }
457 : return ret;
458 : }
459 :
460 0 : int BIO_asn1_set_prefix(BIO *b, asn1_ps_func *prefix,
461 : asn1_ps_func *prefix_free)
462 : {
463 0 : return asn1_bio_set_ex(b, BIO_C_SET_PREFIX, prefix, prefix_free);
464 : }
465 :
466 0 : int BIO_asn1_get_prefix(BIO *b, asn1_ps_func **pprefix,
467 : asn1_ps_func **pprefix_free)
468 : {
469 0 : return asn1_bio_get_ex(b, BIO_C_GET_PREFIX, pprefix, pprefix_free);
470 : }
471 :
472 0 : int BIO_asn1_set_suffix(BIO *b, asn1_ps_func *suffix,
473 : asn1_ps_func *suffix_free)
474 : {
475 0 : return asn1_bio_set_ex(b, BIO_C_SET_SUFFIX, suffix, suffix_free);
476 : }
477 :
478 0 : int BIO_asn1_get_suffix(BIO *b, asn1_ps_func **psuffix,
479 : asn1_ps_func **psuffix_free)
480 : {
481 0 : return asn1_bio_get_ex(b, BIO_C_GET_SUFFIX, psuffix, psuffix_free);
482 : }
|