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