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