1 /* $OpenBSD: bio_asn1.c,v 1.13 2018/05/01 13:29:09 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 /* 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 112 static int asn1_bio_write(BIO *h, const char *buf, int num); 113 static int asn1_bio_read(BIO *h, char *buf, int size); 114 static int asn1_bio_puts(BIO *h, const char *str); 115 static int asn1_bio_gets(BIO *h, char *str, int size); 116 static long asn1_bio_ctrl(BIO *h, int cmd, long arg1, void *arg2); 117 static int asn1_bio_new(BIO *h); 118 static int asn1_bio_free(BIO *data); 119 static long asn1_bio_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp); 120 121 static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size); 122 static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx, 123 asn1_ps_func *cleanup, asn1_bio_state_t next); 124 static int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx, 125 asn1_ps_func *setup, asn1_bio_state_t ex_state, 126 asn1_bio_state_t other_state); 127 128 static const BIO_METHOD methods_asn1 = { 129 .type = BIO_TYPE_ASN1, 130 .name = "asn1", 131 .bwrite = asn1_bio_write, 132 .bread = asn1_bio_read, 133 .bputs = asn1_bio_puts, 134 .bgets = asn1_bio_gets, 135 .ctrl = asn1_bio_ctrl, 136 .create = asn1_bio_new, 137 .destroy = asn1_bio_free, 138 .callback_ctrl = asn1_bio_callback_ctrl 139 }; 140 141 const BIO_METHOD * 142 BIO_f_asn1(void) 143 { 144 return (&methods_asn1); 145 } 146 147 static int 148 asn1_bio_new(BIO *b) 149 { 150 BIO_ASN1_BUF_CTX *ctx; 151 ctx = malloc(sizeof(BIO_ASN1_BUF_CTX)); 152 if (!ctx) 153 return 0; 154 if (!asn1_bio_init(ctx, DEFAULT_ASN1_BUF_SIZE)) { 155 free(ctx); 156 return 0; 157 } 158 b->init = 1; 159 b->ptr = (char *)ctx; 160 b->flags = 0; 161 return 1; 162 } 163 164 static int 165 asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size) 166 { 167 ctx->buf = malloc(size); 168 if (!ctx->buf) 169 return 0; 170 ctx->bufsize = size; 171 ctx->bufpos = 0; 172 ctx->buflen = 0; 173 ctx->copylen = 0; 174 ctx->asn1_class = V_ASN1_UNIVERSAL; 175 ctx->asn1_tag = V_ASN1_OCTET_STRING; 176 ctx->ex_buf = NULL; 177 ctx->ex_pos = 0; 178 ctx->ex_len = 0; 179 ctx->state = ASN1_STATE_START; 180 return 1; 181 } 182 183 static int 184 asn1_bio_free(BIO *b) 185 { 186 BIO_ASN1_BUF_CTX *ctx; 187 188 ctx = (BIO_ASN1_BUF_CTX *) b->ptr; 189 if (ctx == NULL) 190 return 0; 191 free(ctx->buf); 192 free(ctx); 193 b->init = 0; 194 b->ptr = NULL; 195 b->flags = 0; 196 return 1; 197 } 198 199 static int 200 asn1_bio_write(BIO *b, const char *in , int inl) 201 { 202 BIO_ASN1_BUF_CTX *ctx; 203 int wrmax, wrlen, ret, buflen; 204 unsigned char *p; 205 206 if (!in || (inl < 0) || (b->next_bio == NULL)) 207 return 0; 208 ctx = (BIO_ASN1_BUF_CTX *) b->ptr; 209 if (ctx == NULL) 210 return 0; 211 212 wrlen = 0; 213 ret = -1; 214 215 for (;;) { 216 switch (ctx->state) { 217 218 /* Setup prefix data, call it */ 219 case ASN1_STATE_START: 220 if (!asn1_bio_setup_ex(b, ctx, ctx->prefix, 221 ASN1_STATE_PRE_COPY, ASN1_STATE_HEADER)) 222 return 0; 223 break; 224 225 /* Copy any pre data first */ 226 case ASN1_STATE_PRE_COPY: 227 ret = asn1_bio_flush_ex(b, ctx, ctx->prefix_free, 228 ASN1_STATE_HEADER); 229 if (ret <= 0) 230 goto done; 231 break; 232 233 case ASN1_STATE_HEADER: 234 buflen = ASN1_object_size(0, inl, ctx->asn1_tag) - inl; 235 if (buflen <= 0 || buflen > ctx->bufsize) 236 return -1; 237 ctx->buflen = buflen; 238 p = ctx->buf; 239 ASN1_put_object(&p, 0, inl, 240 ctx->asn1_tag, ctx->asn1_class); 241 ctx->copylen = inl; 242 ctx->state = ASN1_STATE_HEADER_COPY; 243 break; 244 245 case ASN1_STATE_HEADER_COPY: 246 ret = BIO_write(b->next_bio, 247 ctx->buf + ctx->bufpos, ctx->buflen); 248 if (ret <= 0) 249 goto done; 250 251 ctx->buflen -= ret; 252 if (ctx->buflen) 253 ctx->bufpos += ret; 254 else { 255 ctx->bufpos = 0; 256 ctx->state = ASN1_STATE_DATA_COPY; 257 } 258 break; 259 260 case ASN1_STATE_DATA_COPY: 261 262 if (inl > ctx->copylen) 263 wrmax = ctx->copylen; 264 else 265 wrmax = inl; 266 ret = BIO_write(b->next_bio, in, wrmax); 267 if (ret <= 0) 268 break; 269 wrlen += ret; 270 ctx->copylen -= ret; 271 in += ret; 272 inl -= ret; 273 274 if (ctx->copylen == 0) 275 ctx->state = ASN1_STATE_HEADER; 276 if (inl == 0) 277 goto done; 278 break; 279 280 default: 281 BIO_clear_retry_flags(b); 282 return 0; 283 } 284 285 } 286 287 done: 288 BIO_clear_retry_flags(b); 289 BIO_copy_next_retry(b); 290 291 return (wrlen > 0) ? wrlen : ret; 292 } 293 294 static int 295 asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx, asn1_ps_func *cleanup, 296 asn1_bio_state_t next) 297 { 298 int ret; 299 300 if (ctx->ex_len <= 0) 301 return 1; 302 for (;;) { 303 ret = BIO_write(b->next_bio, ctx->ex_buf + ctx->ex_pos, 304 ctx->ex_len); 305 if (ret <= 0) 306 break; 307 ctx->ex_len -= ret; 308 if (ctx->ex_len > 0) 309 ctx->ex_pos += ret; 310 else { 311 if (cleanup) 312 cleanup(b, &ctx->ex_buf, &ctx->ex_len, 313 &ctx->ex_arg); 314 ctx->state = next; 315 ctx->ex_pos = 0; 316 break; 317 } 318 } 319 return ret; 320 } 321 322 static int 323 asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx, asn1_ps_func *setup, 324 asn1_bio_state_t ex_state, asn1_bio_state_t other_state) 325 { 326 if (setup && !setup(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg)) { 327 BIO_clear_retry_flags(b); 328 return 0; 329 } 330 if (ctx->ex_len > 0) 331 ctx->state = ex_state; 332 else 333 ctx->state = other_state; 334 return 1; 335 } 336 337 static int 338 asn1_bio_read(BIO *b, char *in , int inl) 339 { 340 if (!b->next_bio) 341 return 0; 342 return BIO_read(b->next_bio, in , inl); 343 } 344 345 static int 346 asn1_bio_puts(BIO *b, const char *str) 347 { 348 return asn1_bio_write(b, str, strlen(str)); 349 } 350 351 static int 352 asn1_bio_gets(BIO *b, char *str, int size) 353 { 354 if (!b->next_bio) 355 return 0; 356 return BIO_gets(b->next_bio, str , size); 357 } 358 359 static long 360 asn1_bio_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp) 361 { 362 if (b->next_bio == NULL) 363 return (0); 364 return BIO_callback_ctrl(b->next_bio, cmd, fp); 365 } 366 367 static long 368 asn1_bio_ctrl(BIO *b, int cmd, long arg1, void *arg2) 369 { 370 BIO_ASN1_BUF_CTX *ctx; 371 BIO_ASN1_EX_FUNCS *ex_func; 372 long ret = 1; 373 374 ctx = (BIO_ASN1_BUF_CTX *) b->ptr; 375 if (ctx == NULL) 376 return 0; 377 switch (cmd) { 378 379 case BIO_C_SET_PREFIX: 380 ex_func = arg2; 381 ctx->prefix = ex_func->ex_func; 382 ctx->prefix_free = ex_func->ex_free_func; 383 break; 384 385 case BIO_C_GET_PREFIX: 386 ex_func = arg2; 387 ex_func->ex_func = ctx->prefix; 388 ex_func->ex_free_func = ctx->prefix_free; 389 break; 390 391 case BIO_C_SET_SUFFIX: 392 ex_func = arg2; 393 ctx->suffix = ex_func->ex_func; 394 ctx->suffix_free = ex_func->ex_free_func; 395 break; 396 397 case BIO_C_GET_SUFFIX: 398 ex_func = arg2; 399 ex_func->ex_func = ctx->suffix; 400 ex_func->ex_free_func = ctx->suffix_free; 401 break; 402 403 case BIO_C_SET_EX_ARG: 404 ctx->ex_arg = arg2; 405 break; 406 407 case BIO_C_GET_EX_ARG: 408 *(void **)arg2 = ctx->ex_arg; 409 break; 410 411 case BIO_CTRL_FLUSH: 412 if (!b->next_bio) 413 return 0; 414 415 /* Call post function if possible */ 416 if (ctx->state == ASN1_STATE_HEADER) { 417 if (!asn1_bio_setup_ex(b, ctx, ctx->suffix, 418 ASN1_STATE_POST_COPY, ASN1_STATE_DONE)) 419 return 0; 420 } 421 422 if (ctx->state == ASN1_STATE_POST_COPY) { 423 ret = asn1_bio_flush_ex(b, ctx, ctx->suffix_free, 424 ASN1_STATE_DONE); 425 if (ret <= 0) 426 return ret; 427 } 428 429 if (ctx->state == ASN1_STATE_DONE) 430 return BIO_ctrl(b->next_bio, cmd, arg1, arg2); 431 else { 432 BIO_clear_retry_flags(b); 433 return 0; 434 } 435 break; 436 437 438 default: 439 if (!b->next_bio) 440 return 0; 441 return BIO_ctrl(b->next_bio, cmd, arg1, arg2); 442 443 } 444 445 return ret; 446 } 447 448 static int 449 asn1_bio_set_ex(BIO *b, int cmd, asn1_ps_func *ex_func, asn1_ps_func 450 *ex_free_func) 451 { 452 BIO_ASN1_EX_FUNCS extmp; 453 454 extmp.ex_func = ex_func; 455 extmp.ex_free_func = ex_free_func; 456 return BIO_ctrl(b, cmd, 0, &extmp); 457 } 458 459 static int 460 asn1_bio_get_ex(BIO *b, int cmd, asn1_ps_func **ex_func, 461 asn1_ps_func **ex_free_func) 462 { 463 BIO_ASN1_EX_FUNCS extmp; 464 int ret; 465 466 ret = BIO_ctrl(b, cmd, 0, &extmp); 467 if (ret > 0) { 468 *ex_func = extmp.ex_func; 469 *ex_free_func = extmp.ex_free_func; 470 } 471 return ret; 472 } 473 474 int 475 BIO_asn1_set_prefix(BIO *b, asn1_ps_func *prefix, asn1_ps_func *prefix_free) 476 { 477 return asn1_bio_set_ex(b, BIO_C_SET_PREFIX, prefix, prefix_free); 478 } 479 480 int 481 BIO_asn1_get_prefix(BIO *b, asn1_ps_func **pprefix, asn1_ps_func **pprefix_free) 482 { 483 return asn1_bio_get_ex(b, BIO_C_GET_PREFIX, pprefix, pprefix_free); 484 } 485 486 int 487 BIO_asn1_set_suffix(BIO *b, asn1_ps_func *suffix, asn1_ps_func *suffix_free) 488 { 489 return asn1_bio_set_ex(b, BIO_C_SET_SUFFIX, suffix, suffix_free); 490 } 491 492 int 493 BIO_asn1_get_suffix(BIO *b, asn1_ps_func **psuffix, asn1_ps_func **psuffix_free) 494 { 495 return asn1_bio_get_ex(b, BIO_C_GET_SUFFIX, psuffix, psuffix_free); 496 } 497