Import OpenSSL 1.0.1m.
[dragonfly.git] / crypto / openssl / crypto / asn1 / bio_asn1.c
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 BIO_METHOD *BIO_f_asn1(void)
142 {
143     return (&methods_asn1);
144 }
145
146 static int asn1_bio_new(BIO *b)
147 {
148     BIO_ASN1_BUF_CTX *ctx;
149     ctx = OPENSSL_malloc(sizeof(BIO_ASN1_BUF_CTX));
150     if (!ctx)
151         return 0;
152     if (!asn1_bio_init(ctx, DEFAULT_ASN1_BUF_SIZE)) {
153         OPENSSL_free(ctx);
154         return 0;
155     }
156     b->init = 1;
157     b->ptr = (char *)ctx;
158     b->flags = 0;
159     return 1;
160 }
161
162 static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size)
163 {
164     ctx->buf = OPENSSL_malloc(size);
165     if (!ctx->buf)
166         return 0;
167     ctx->bufsize = size;
168     ctx->bufpos = 0;
169     ctx->buflen = 0;
170     ctx->copylen = 0;
171     ctx->asn1_class = V_ASN1_UNIVERSAL;
172     ctx->asn1_tag = V_ASN1_OCTET_STRING;
173     ctx->ex_buf = 0;
174     ctx->ex_pos = 0;
175     ctx->ex_len = 0;
176     ctx->state = ASN1_STATE_START;
177     return 1;
178 }
179
180 static int asn1_bio_free(BIO *b)
181 {
182     BIO_ASN1_BUF_CTX *ctx;
183     ctx = (BIO_ASN1_BUF_CTX *)b->ptr;
184     if (ctx == NULL)
185         return 0;
186     if (ctx->buf)
187         OPENSSL_free(ctx->buf);
188     OPENSSL_free(ctx);
189     b->init = 0;
190     b->ptr = NULL;
191     b->flags = 0;
192     return 1;
193 }
194
195 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     if (!in || (inl < 0) || (b->next_bio == NULL))
201         return 0;
202     ctx = (BIO_ASN1_BUF_CTX *)b->ptr;
203     if (ctx == NULL)
204         return 0;
205
206     wrlen = 0;
207     ret = -1;
208
209     for (;;) {
210         switch (ctx->state) {
211
212             /* Setup prefix data, call it */
213         case ASN1_STATE_START:
214             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             ret = asn1_bio_flush_ex(b, ctx, ctx->prefix_free,
223                                     ASN1_STATE_HEADER);
224
225             if (ret <= 0)
226                 goto done;
227
228             break;
229
230         case ASN1_STATE_HEADER:
231             ctx->buflen = ASN1_object_size(0, inl, ctx->asn1_tag) - inl;
232             OPENSSL_assert(ctx->buflen <= ctx->bufsize);
233             p = ctx->buf;
234             ASN1_put_object(&p, 0, inl, ctx->asn1_tag, ctx->asn1_class);
235             ctx->copylen = inl;
236             ctx->state = ASN1_STATE_HEADER_COPY;
237
238             break;
239
240         case ASN1_STATE_HEADER_COPY:
241             ret = BIO_write(b->next_bio, ctx->buf + ctx->bufpos, ctx->buflen);
242             if (ret <= 0)
243                 goto done;
244
245             ctx->buflen -= ret;
246             if (ctx->buflen)
247                 ctx->bufpos += ret;
248             else {
249                 ctx->bufpos = 0;
250                 ctx->state = ASN1_STATE_DATA_COPY;
251             }
252
253             break;
254
255         case ASN1_STATE_DATA_COPY:
256
257             if (inl > ctx->copylen)
258                 wrmax = ctx->copylen;
259             else
260                 wrmax = inl;
261             ret = BIO_write(b->next_bio, in, wrmax);
262             if (ret <= 0)
263                 break;
264             wrlen += ret;
265             ctx->copylen -= ret;
266             in += ret;
267             inl -= ret;
268
269             if (ctx->copylen == 0)
270                 ctx->state = ASN1_STATE_HEADER;
271
272             if (inl == 0)
273                 goto done;
274
275             break;
276
277         default:
278             BIO_clear_retry_flags(b);
279             return 0;
280
281         }
282
283     }
284
285  done:
286     BIO_clear_retry_flags(b);
287     BIO_copy_next_retry(b);
288
289     return (wrlen > 0) ? wrlen : ret;
290
291 }
292
293 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     if (ctx->ex_len <= 0)
298         return 1;
299     for (;;) {
300         ret = BIO_write(b->next_bio, ctx->ex_buf + ctx->ex_pos, ctx->ex_len);
301         if (ret <= 0)
302             break;
303         ctx->ex_len -= ret;
304         if (ctx->ex_len > 0)
305             ctx->ex_pos += ret;
306         else {
307             if (cleanup)
308                 cleanup(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg);
309             ctx->state = next;
310             ctx->ex_pos = 0;
311             break;
312         }
313     }
314     return ret;
315 }
316
317 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     if (setup && !setup(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg)) {
323         BIO_clear_retry_flags(b);
324         return 0;
325     }
326     if (ctx->ex_len > 0)
327         ctx->state = ex_state;
328     else
329         ctx->state = other_state;
330     return 1;
331 }
332
333 static int asn1_bio_read(BIO *b, char *in, int inl)
334 {
335     if (!b->next_bio)
336         return 0;
337     return BIO_read(b->next_bio, in, inl);
338 }
339
340 static int asn1_bio_puts(BIO *b, const char *str)
341 {
342     return asn1_bio_write(b, str, strlen(str));
343 }
344
345 static int asn1_bio_gets(BIO *b, char *str, int size)
346 {
347     if (!b->next_bio)
348         return 0;
349     return BIO_gets(b->next_bio, str, size);
350 }
351
352 static long asn1_bio_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
353 {
354     if (b->next_bio == NULL)
355         return (0);
356     return BIO_callback_ctrl(b->next_bio, cmd, fp);
357 }
358
359 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     ctx = (BIO_ASN1_BUF_CTX *)b->ptr;
365     if (ctx == NULL)
366         return 0;
367     switch (cmd) {
368
369     case BIO_C_SET_PREFIX:
370         ex_func = arg2;
371         ctx->prefix = ex_func->ex_func;
372         ctx->prefix_free = ex_func->ex_free_func;
373         break;
374
375     case BIO_C_GET_PREFIX:
376         ex_func = arg2;
377         ex_func->ex_func = ctx->prefix;
378         ex_func->ex_free_func = ctx->prefix_free;
379         break;
380
381     case BIO_C_SET_SUFFIX:
382         ex_func = arg2;
383         ctx->suffix = ex_func->ex_func;
384         ctx->suffix_free = ex_func->ex_free_func;
385         break;
386
387     case BIO_C_GET_SUFFIX:
388         ex_func = arg2;
389         ex_func->ex_func = ctx->suffix;
390         ex_func->ex_free_func = ctx->suffix_free;
391         break;
392
393     case BIO_C_SET_EX_ARG:
394         ctx->ex_arg = arg2;
395         break;
396
397     case BIO_C_GET_EX_ARG:
398         *(void **)arg2 = ctx->ex_arg;
399         break;
400
401     case BIO_CTRL_FLUSH:
402         if (!b->next_bio)
403             return 0;
404
405         /* Call post function if possible */
406         if (ctx->state == ASN1_STATE_HEADER) {
407             if (!asn1_bio_setup_ex(b, ctx, ctx->suffix,
408                                    ASN1_STATE_POST_COPY, ASN1_STATE_DONE))
409                 return 0;
410         }
411
412         if (ctx->state == ASN1_STATE_POST_COPY) {
413             ret = asn1_bio_flush_ex(b, ctx, ctx->suffix_free,
414                                     ASN1_STATE_DONE);
415             if (ret <= 0)
416                 return ret;
417         }
418
419         if (ctx->state == ASN1_STATE_DONE)
420             return BIO_ctrl(b->next_bio, cmd, arg1, arg2);
421         else {
422             BIO_clear_retry_flags(b);
423             return 0;
424         }
425         break;
426
427     default:
428         if (!b->next_bio)
429             return 0;
430         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     extmp.ex_func = ex_func;
442     extmp.ex_free_func = ex_free_func;
443     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     ret = BIO_ctrl(b, cmd, 0, &extmp);
453     if (ret > 0) {
454         *ex_func = extmp.ex_func;
455         *ex_free_func = extmp.ex_free_func;
456     }
457     return ret;
458 }
459
460 int BIO_asn1_set_prefix(BIO *b, asn1_ps_func *prefix,
461                         asn1_ps_func *prefix_free)
462 {
463     return asn1_bio_set_ex(b, BIO_C_SET_PREFIX, prefix, prefix_free);
464 }
465
466 int BIO_asn1_get_prefix(BIO *b, asn1_ps_func **pprefix,
467                         asn1_ps_func **pprefix_free)
468 {
469     return asn1_bio_get_ex(b, BIO_C_GET_PREFIX, pprefix, pprefix_free);
470 }
471
472 int BIO_asn1_set_suffix(BIO *b, asn1_ps_func *suffix,
473                         asn1_ps_func *suffix_free)
474 {
475     return asn1_bio_set_ex(b, BIO_C_SET_SUFFIX, suffix, suffix_free);
476 }
477
478 int BIO_asn1_get_suffix(BIO *b, asn1_ps_func **psuffix,
479                         asn1_ps_func **psuffix_free)
480 {
481     return asn1_bio_get_ex(b, BIO_C_GET_SUFFIX, psuffix, psuffix_free);
482 }