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