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 * 143 BIO_f_asn1(void) 144 { 145 return (&methods_asn1); 146 } 147 148 static int 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 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 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 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 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 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 335 asn1_bio_puts(BIO *b, const char *str) 336 { 337 return asn1_bio_write(b, str, strlen(str)); 338 } 339 340 static int 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 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 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 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 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 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 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 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 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