1 /* Copyright (C) 1995-1998 Eric Young (eay (at) cryptsoft.com) 2 * All rights reserved. 3 * 4 * This package is an SSL implementation written 5 * by Eric Young (eay (at) cryptsoft.com). 6 * The implementation was written so as to conform with Netscapes SSL. 7 * 8 * This library is free for commercial and non-commercial use as long as 9 * the following conditions are aheared to. The following conditions 10 * apply to all code found in this distribution, be it the RC4, RSA, 11 * lhash, DES, etc., code; not just the SSL code. The SSL documentation 12 * included with this distribution is covered by the same copyright terms 13 * except that the holder is Tim Hudson (tjh (at) cryptsoft.com). 14 * 15 * Copyright remains Eric Young's, and as such any Copyright notices in 16 * the code are not to be removed. 17 * If this package is used in a product, Eric Young should be given attribution 18 * as the author of the parts of the library used. 19 * This can be in the form of a textual message at program startup or 20 * in documentation (online or textual) provided with the package. 21 * 22 * Redistribution and use in source and binary forms, with or without 23 * modification, are permitted provided that the following conditions 24 * are met: 25 * 1. Redistributions of source code must retain the copyright 26 * notice, this list of conditions and the following disclaimer. 27 * 2. Redistributions in binary form must reproduce the above copyright 28 * notice, this list of conditions and the following disclaimer in the 29 * documentation and/or other materials provided with the distribution. 30 * 3. All advertising materials mentioning features or use of this software 31 * must display the following acknowledgement: 32 * "This product includes cryptographic software written by 33 * Eric Young (eay (at) cryptsoft.com)" 34 * The word 'cryptographic' can be left out if the rouines from the library 35 * being used are not cryptographic related :-). 36 * 4. If you include any Windows specific code (or a derivative thereof) from 37 * the apps directory (application code) you must include an acknowledgement: 38 * "This product includes software written by Tim Hudson (tjh (at) cryptsoft.com)" 39 * 40 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND 41 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 43 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 44 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 45 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 46 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 48 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 49 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 50 * SUCH DAMAGE. 51 * 52 * The licence and distribution terms for any publically available version or 53 * derivative of this code cannot be changed. i.e. this code cannot simply be 54 * copied and put under another distribution licence 55 * [including the GNU Public Licence.] */ 56 57 #include <openssl/asn1.h> 58 59 #include <assert.h> 60 #include <string.h> 61 62 #include <openssl/bio.h> 63 #include <openssl/mem.h> 64 65 66 /* Must be large enough for biggest tag+length */ 67 #define DEFAULT_ASN1_BUF_SIZE 20 68 69 typedef enum 70 { 71 ASN1_STATE_START, 72 ASN1_STATE_PRE_COPY, 73 ASN1_STATE_HEADER, 74 ASN1_STATE_HEADER_COPY, 75 ASN1_STATE_DATA_COPY, 76 ASN1_STATE_POST_COPY, 77 ASN1_STATE_DONE 78 } asn1_bio_state_t; 79 80 typedef struct BIO_ASN1_EX_FUNCS_st 81 { 82 asn1_ps_func *ex_func; 83 asn1_ps_func *ex_free_func; 84 } BIO_ASN1_EX_FUNCS; 85 86 typedef struct BIO_ASN1_BUF_CTX_t 87 { 88 /* Internal state */ 89 asn1_bio_state_t state; 90 /* Internal buffer */ 91 unsigned char *buf; 92 /* Size of buffer */ 93 int bufsize; 94 /* Current position in buffer */ 95 int bufpos; 96 /* Current buffer length */ 97 int buflen; 98 /* Amount of data to copy */ 99 int copylen; 100 /* Class and tag to use */ 101 int asn1_class, asn1_tag; 102 asn1_ps_func *prefix, *prefix_free, *suffix, *suffix_free; 103 /* Extra buffer for prefix and suffix data */ 104 unsigned char *ex_buf; 105 int ex_len; 106 int ex_pos; 107 void *ex_arg; 108 } BIO_ASN1_BUF_CTX; 109 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 const BIO_METHOD methods_asn1= 129 { 130 BIO_TYPE_ASN1, 131 "asn1", 132 asn1_bio_write, 133 asn1_bio_read, 134 asn1_bio_puts, 135 asn1_bio_gets, 136 asn1_bio_ctrl, 137 asn1_bio_new, 138 asn1_bio_free, 139 asn1_bio_callback_ctrl, 140 }; 141 142 const BIO_METHOD *BIO_f_asn1(void) 143 { 144 return(&methods_asn1); 145 } 146 147 148 static int asn1_bio_new(BIO *b) 149 { 150 BIO_ASN1_BUF_CTX *ctx; 151 ctx = OPENSSL_malloc(sizeof(BIO_ASN1_BUF_CTX)); 152 if (!ctx) 153 return 0; 154 if (!asn1_bio_init(ctx, DEFAULT_ASN1_BUF_SIZE)) 155 { 156 OPENSSL_free(ctx); 157 return 0; 158 } 159 b->init = 1; 160 b->ptr = (char *)ctx; 161 b->flags = 0; 162 return 1; 163 } 164 165 static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size) 166 { 167 ctx->buf = OPENSSL_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 = 0; 177 ctx->ex_pos = 0; 178 ctx->ex_len = 0; 179 ctx->state = ASN1_STATE_START; 180 return 1; 181 } 182 183 static int asn1_bio_free(BIO *b) 184 { 185 BIO_ASN1_BUF_CTX *ctx; 186 ctx = (BIO_ASN1_BUF_CTX *) b->ptr; 187 if (ctx == NULL) 188 return 0; 189 if (ctx->buf) 190 OPENSSL_free(ctx->buf); 191 OPENSSL_free(ctx); 192 b->init = 0; 193 b->ptr = NULL; 194 b->flags = 0; 195 return 1; 196 } 197 198 static int asn1_bio_write(BIO *b, const char *in , int inl) 199 { 200 BIO_ASN1_BUF_CTX *ctx; 201 int wrmax, wrlen, ret; 202 unsigned char *p; 203 if (!in || (inl < 0) || (b->next_bio == NULL)) 204 return 0; 205 ctx = (BIO_ASN1_BUF_CTX *) b->ptr; 206 if (ctx == NULL) 207 return 0; 208 209 wrlen = 0; 210 ret = -1; 211 212 for(;;) 213 { 214 switch (ctx->state) 215 { 216 217 /* Setup prefix data, call it */ 218 case ASN1_STATE_START: 219 if (!asn1_bio_setup_ex(b, ctx, ctx->prefix, 220 ASN1_STATE_PRE_COPY, ASN1_STATE_HEADER)) 221 return 0; 222 break; 223 224 /* Copy any pre data first */ 225 case ASN1_STATE_PRE_COPY: 226 227 ret = asn1_bio_flush_ex(b, ctx, ctx->prefix_free, 228 ASN1_STATE_HEADER); 229 230 if (ret <= 0) 231 goto done; 232 233 break; 234 235 case ASN1_STATE_HEADER: 236 ctx->buflen = 237 ASN1_object_size(0, inl, ctx->asn1_tag) - inl; 238 assert(ctx->buflen <= ctx->bufsize); 239 p = ctx->buf; 240 ASN1_put_object(&p, 0, inl, 241 ctx->asn1_tag, ctx->asn1_class); 242 ctx->copylen = inl; 243 ctx->state = ASN1_STATE_HEADER_COPY; 244 245 break; 246 247 case ASN1_STATE_HEADER_COPY: 248 ret = BIO_write(b->next_bio, 249 ctx->buf + ctx->bufpos, ctx->buflen); 250 if (ret <= 0) 251 goto done; 252 253 ctx->buflen -= ret; 254 if (ctx->buflen) 255 ctx->bufpos += ret; 256 else 257 { 258 ctx->bufpos = 0; 259 ctx->state = ASN1_STATE_DATA_COPY; 260 } 261 262 break; 263 264 case ASN1_STATE_DATA_COPY: 265 266 if (inl > ctx->copylen) 267 wrmax = ctx->copylen; 268 else 269 wrmax = inl; 270 ret = BIO_write(b->next_bio, in, wrmax); 271 if (ret <= 0) 272 break; 273 wrlen += ret; 274 ctx->copylen -= ret; 275 in += ret; 276 inl -= ret; 277 278 if (ctx->copylen == 0) 279 ctx->state = ASN1_STATE_HEADER; 280 281 if (inl == 0) 282 goto done; 283 284 break; 285 286 default: 287 BIO_clear_retry_flags(b); 288 return 0; 289 290 } 291 292 } 293 294 done: 295 BIO_clear_retry_flags(b); 296 BIO_copy_next_retry(b); 297 298 return (wrlen > 0) ? wrlen : ret; 299 300 } 301 302 static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx, 303 asn1_ps_func *cleanup, asn1_bio_state_t next) 304 { 305 int ret; 306 if (ctx->ex_len <= 0) 307 return 1; 308 for(;;) 309 { 310 ret = BIO_write(b->next_bio, ctx->ex_buf + ctx->ex_pos, 311 ctx->ex_len); 312 if (ret <= 0) 313 break; 314 ctx->ex_len -= ret; 315 if (ctx->ex_len > 0) 316 ctx->ex_pos += ret; 317 else 318 { 319 if(cleanup) 320 cleanup(b, &ctx->ex_buf, &ctx->ex_len, 321 &ctx->ex_arg); 322 ctx->state = next; 323 ctx->ex_pos = 0; 324 break; 325 } 326 } 327 return ret; 328 } 329 330 static int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx, 331 asn1_ps_func *setup, 332 asn1_bio_state_t ex_state, 333 asn1_bio_state_t other_state) 334 { 335 if (setup && !setup(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg)) 336 { 337 BIO_clear_retry_flags(b); 338 return 0; 339 } 340 if (ctx->ex_len > 0) 341 ctx->state = ex_state; 342 else 343 ctx->state = other_state; 344 return 1; 345 } 346 347 static int asn1_bio_read(BIO *b, char *in , int inl) 348 { 349 if (!b->next_bio) 350 return 0; 351 return BIO_read(b->next_bio, in , inl); 352 } 353 354 static int asn1_bio_puts(BIO *b, const char *str) 355 { 356 return asn1_bio_write(b, str, strlen(str)); 357 } 358 359 static int asn1_bio_gets(BIO *b, char *str, int size) 360 { 361 if (!b->next_bio) 362 return 0; 363 return BIO_gets(b->next_bio, str , size); 364 } 365 366 static long asn1_bio_callback_ctrl(BIO *b, int cmd, bio_info_cb fp) 367 { 368 if (b->next_bio == NULL) return(0); 369 return BIO_callback_ctrl(b->next_bio,cmd,fp); 370 } 371 372 static long asn1_bio_ctrl(BIO *b, int cmd, long arg1, void *arg2) 373 { 374 BIO_ASN1_BUF_CTX *ctx; 375 BIO_ASN1_EX_FUNCS *ex_func; 376 long ret = 1; 377 ctx = (BIO_ASN1_BUF_CTX *) b->ptr; 378 if (ctx == NULL) 379 return 0; 380 switch(cmd) 381 { 382 383 case BIO_C_SET_PREFIX: 384 ex_func = arg2; 385 ctx->prefix = ex_func->ex_func; 386 ctx->prefix_free = ex_func->ex_free_func; 387 break; 388 389 case BIO_C_GET_PREFIX: 390 ex_func = arg2; 391 ex_func->ex_func = ctx->prefix; 392 ex_func->ex_free_func = ctx->prefix_free; 393 break; 394 395 case BIO_C_SET_SUFFIX: 396 ex_func = arg2; 397 ctx->suffix = ex_func->ex_func; 398 ctx->suffix_free = ex_func->ex_free_func; 399 break; 400 401 case BIO_C_GET_SUFFIX: 402 ex_func = arg2; 403 ex_func->ex_func = ctx->suffix; 404 ex_func->ex_free_func = ctx->suffix_free; 405 break; 406 407 case BIO_C_SET_EX_ARG: 408 ctx->ex_arg = arg2; 409 break; 410 411 case BIO_C_GET_EX_ARG: 412 *(void **)arg2 = ctx->ex_arg; 413 break; 414 415 case BIO_CTRL_FLUSH: 416 if (!b->next_bio) 417 return 0; 418 419 /* Call post function if possible */ 420 if (ctx->state == ASN1_STATE_HEADER) 421 { 422 if (!asn1_bio_setup_ex(b, ctx, ctx->suffix, 423 ASN1_STATE_POST_COPY, ASN1_STATE_DONE)) 424 return 0; 425 } 426 427 if (ctx->state == ASN1_STATE_POST_COPY) 428 { 429 ret = asn1_bio_flush_ex(b, ctx, ctx->suffix_free, 430 ASN1_STATE_DONE); 431 if (ret <= 0) 432 return ret; 433 } 434 435 if (ctx->state == ASN1_STATE_DONE) 436 return BIO_ctrl(b->next_bio, cmd, arg1, arg2); 437 else 438 { 439 BIO_clear_retry_flags(b); 440 return 0; 441 } 442 break; 443 444 445 default: 446 if (!b->next_bio) 447 return 0; 448 return BIO_ctrl(b->next_bio, cmd, arg1, arg2); 449 450 } 451 452 return ret; 453 } 454 455 static int asn1_bio_set_ex(BIO *b, int cmd, 456 asn1_ps_func *ex_func, asn1_ps_func *ex_free_func) 457 { 458 BIO_ASN1_EX_FUNCS extmp; 459 extmp.ex_func = ex_func; 460 extmp.ex_free_func = ex_free_func; 461 return BIO_ctrl(b, cmd, 0, &extmp); 462 } 463 464 static int asn1_bio_get_ex(BIO *b, int cmd, 465 asn1_ps_func **ex_func, asn1_ps_func **ex_free_func) 466 { 467 BIO_ASN1_EX_FUNCS extmp; 468 int ret; 469 ret = BIO_ctrl(b, cmd, 0, &extmp); 470 if (ret > 0) 471 { 472 *ex_func = extmp.ex_func; 473 *ex_free_func = extmp.ex_free_func; 474 } 475 return ret; 476 } 477 478 int BIO_asn1_set_prefix(BIO *b, asn1_ps_func *prefix, asn1_ps_func *prefix_free) 479 { 480 return asn1_bio_set_ex(b, BIO_C_SET_PREFIX, prefix, prefix_free); 481 } 482 483 int BIO_asn1_get_prefix(BIO *b, asn1_ps_func **pprefix, asn1_ps_func **pprefix_free) 484 { 485 return asn1_bio_get_ex(b, BIO_C_GET_PREFIX, pprefix, pprefix_free); 486 } 487 488 int BIO_asn1_set_suffix(BIO *b, asn1_ps_func *suffix, asn1_ps_func *suffix_free) 489 { 490 return asn1_bio_set_ex(b, BIO_C_SET_SUFFIX, suffix, suffix_free); 491 } 492 493 int 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