Home | History | Annotate | Download | only in asn1
      1 /* bio_asn1.c */
      2 /* Written by Dr Stephen N Henson (steve (at) 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 (at) 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 (at) cryptsoft.com).  This product includes software written by Tim
     55  * Hudson (tjh (at) 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 <string.h>
     65 #include <openssl/bio.h>
     66 #include <openssl/asn1.h>
     67 
     68 /* Must be large enough for biggest tag+length */
     69 #define DEFAULT_ASN1_BUF_SIZE 20
     70 
     71 typedef enum
     72 	{
     73 	ASN1_STATE_START,
     74 	ASN1_STATE_PRE_COPY,
     75 	ASN1_STATE_HEADER,
     76 	ASN1_STATE_HEADER_COPY,
     77 	ASN1_STATE_DATA_COPY,
     78 	ASN1_STATE_POST_COPY,
     79 	ASN1_STATE_DONE
     80 	} asn1_bio_state_t;
     81 
     82 typedef struct BIO_ASN1_EX_FUNCS_st
     83 	{
     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 	{
     90 	/* Internal state */
     91 	asn1_bio_state_t state;
     92 	/* Internal buffer */
     93 	unsigned char *buf;
     94 	/* Size of buffer */
     95 	int bufsize;
     96 	/* Current position in buffer */
     97 	int bufpos;
     98 	/* Current buffer length */
     99 	int buflen;
    100 	/* Amount of data to copy */
    101 	int copylen;
    102 	/* Class and tag to use */
    103 	int asn1_class, asn1_tag;
    104 	asn1_ps_func *prefix, *prefix_free, *suffix, *suffix_free;
    105 	/* Extra buffer for prefix and suffix data */
    106 	unsigned char *ex_buf;
    107 	int ex_len;
    108 	int ex_pos;
    109 	void *ex_arg;
    110 	} BIO_ASN1_BUF_CTX;
    111 
    112 
    113 static int asn1_bio_write(BIO *h, const char *buf,int num);
    114 static int asn1_bio_read(BIO *h, char *buf, int size);
    115 static int asn1_bio_puts(BIO *h, const char *str);
    116 static int asn1_bio_gets(BIO *h, char *str, int size);
    117 static long asn1_bio_ctrl(BIO *h, int cmd, long arg1, void *arg2);
    118 static int asn1_bio_new(BIO *h);
    119 static int asn1_bio_free(BIO *data);
    120 static long asn1_bio_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp);
    121 
    122 static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size);
    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,
    127 				asn1_bio_state_t ex_state,
    128 				asn1_bio_state_t other_state);
    129 
    130 static BIO_METHOD methods_asn1=
    131 	{
    132 	BIO_TYPE_ASN1,
    133 	"asn1",
    134 	asn1_bio_write,
    135 	asn1_bio_read,
    136 	asn1_bio_puts,
    137 	asn1_bio_gets,
    138 	asn1_bio_ctrl,
    139 	asn1_bio_new,
    140 	asn1_bio_free,
    141 	asn1_bio_callback_ctrl,
    142 	};
    143 
    144 BIO_METHOD *BIO_f_asn1(void)
    145 	{
    146 	return(&methods_asn1);
    147 	}
    148 
    149 
    150 static int asn1_bio_new(BIO *b)
    151 	{
    152 	BIO_ASN1_BUF_CTX *ctx;
    153 	ctx = OPENSSL_malloc(sizeof(BIO_ASN1_BUF_CTX));
    154 	if (!ctx)
    155 		return 0;
    156 	if (!asn1_bio_init(ctx, DEFAULT_ASN1_BUF_SIZE))
    157 		return 0;
    158 	b->init = 1;
    159 	b->ptr = (char *)ctx;
    160 	b->flags = 0;
    161 	return 1;
    162 	}
    163 
    164 static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size)
    165 	{
    166 	ctx->buf = OPENSSL_malloc(size);
    167 	if (!ctx->buf)
    168 		return 0;
    169 	ctx->bufsize = size;
    170 	ctx->bufpos = 0;
    171 	ctx->buflen = 0;
    172 	ctx->copylen = 0;
    173 	ctx->asn1_class = V_ASN1_UNIVERSAL;
    174 	ctx->asn1_tag = V_ASN1_OCTET_STRING;
    175 	ctx->ex_buf = 0;
    176 	ctx->ex_pos = 0;
    177 	ctx->ex_len = 0;
    178 	ctx->state = ASN1_STATE_START;
    179 	return 1;
    180 	}
    181 
    182 static int asn1_bio_free(BIO *b)
    183 	{
    184 	BIO_ASN1_BUF_CTX *ctx;
    185 	ctx = (BIO_ASN1_BUF_CTX *) b->ptr;
    186 	if (ctx == NULL)
    187 		return 0;
    188 	if (ctx->buf)
    189 		OPENSSL_free(ctx->buf);
    190 	OPENSSL_free(ctx);
    191 	b->init = 0;
    192 	b->ptr = NULL;
    193 	b->flags = 0;
    194 	return 1;
    195 	}
    196 
    197 static int asn1_bio_write(BIO *b, const char *in , int inl)
    198 	{
    199 	BIO_ASN1_BUF_CTX *ctx;
    200 	int wrmax, wrlen, ret;
    201 	unsigned char *p;
    202 	if (!in || (inl < 0) || (b->next_bio == NULL))
    203 		return 0;
    204 	ctx = (BIO_ASN1_BUF_CTX *) b->ptr;
    205 	if (ctx == NULL)
    206 		return 0;
    207 
    208 	wrlen = 0;
    209 	ret = -1;
    210 
    211 	for(;;)
    212 		{
    213 		switch (ctx->state)
    214 			{
    215 
    216 			/* Setup prefix data, call it */
    217 			case ASN1_STATE_START:
    218 			if (!asn1_bio_setup_ex(b, ctx, ctx->prefix,
    219 				ASN1_STATE_PRE_COPY, ASN1_STATE_HEADER))
    220 				return 0;
    221 			break;
    222 
    223 			/* Copy any pre data first */
    224 			case ASN1_STATE_PRE_COPY:
    225 
    226 			ret = asn1_bio_flush_ex(b, ctx, ctx->prefix_free,
    227 							ASN1_STATE_HEADER);
    228 
    229 			if (ret <= 0)
    230 				goto done;
    231 
    232 			break;
    233 
    234 			case ASN1_STATE_HEADER:
    235 			ctx->buflen =
    236 				ASN1_object_size(0, inl, ctx->asn1_tag) - inl;
    237 			OPENSSL_assert(ctx->buflen <= ctx->bufsize);
    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 
    244 			break;
    245 
    246 			case ASN1_STATE_HEADER_COPY:
    247 			ret = BIO_write(b->next_bio,
    248 					ctx->buf + ctx->bufpos, ctx->buflen);
    249 			if (ret <= 0)
    250 				goto done;
    251 
    252 			ctx->buflen -= ret;
    253 			if (ctx->buflen)
    254 				ctx->bufpos += ret;
    255 			else
    256 				{
    257 				ctx->bufpos = 0;
    258 				ctx->state = ASN1_STATE_DATA_COPY;
    259 				}
    260 
    261 			break;
    262 
    263 			case ASN1_STATE_DATA_COPY:
    264 
    265 			if (inl > ctx->copylen)
    266 				wrmax = ctx->copylen;
    267 			else
    268 				wrmax = inl;
    269 			ret = BIO_write(b->next_bio, in, wrmax);
    270 			if (ret <= 0)
    271 				break;
    272 			wrlen += ret;
    273 			ctx->copylen -= ret;
    274 			in += ret;
    275 			inl -= ret;
    276 
    277 			if (ctx->copylen == 0)
    278 				ctx->state = ASN1_STATE_HEADER;
    279 
    280 			if (inl == 0)
    281 				goto done;
    282 
    283 			break;
    284 
    285 			default:
    286 			BIO_clear_retry_flags(b);
    287 			return 0;
    288 
    289 			}
    290 
    291 		}
    292 
    293 	done:
    294 	BIO_clear_retry_flags(b);
    295 	BIO_copy_next_retry(b);
    296 
    297 	return (wrlen > 0) ? wrlen : ret;
    298 
    299 	}
    300 
    301 static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
    302 				asn1_ps_func *cleanup, asn1_bio_state_t next)
    303 	{
    304 	int ret;
    305 	if (ctx->ex_len <= 0)
    306 		return 1;
    307 	for(;;)
    308 		{
    309 		ret = BIO_write(b->next_bio, ctx->ex_buf + ctx->ex_pos,
    310 								ctx->ex_len);
    311 		if (ret <= 0)
    312 			break;
    313 		ctx->ex_len -= ret;
    314 		if (ctx->ex_len > 0)
    315 			ctx->ex_pos += ret;
    316 		else
    317 			{
    318 			if(cleanup)
    319 				cleanup(b, &ctx->ex_buf, &ctx->ex_len,
    320 								&ctx->ex_arg);
    321 			ctx->state = next;
    322 			ctx->ex_pos = 0;
    323 			break;
    324 			}
    325 		}
    326 	return ret;
    327 	}
    328 
    329 static int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
    330 				asn1_ps_func *setup,
    331 				asn1_bio_state_t ex_state,
    332 				asn1_bio_state_t other_state)
    333 	{
    334 	if (setup && !setup(b, &ctx->ex_buf, &ctx->ex_len, &ctx->ex_arg))
    335 		{
    336 		BIO_clear_retry_flags(b);
    337 		return 0;
    338 		}
    339 	if (ctx->ex_len > 0)
    340 		ctx->state = ex_state;
    341 	else
    342 		ctx->state = other_state;
    343 	return 1;
    344 	}
    345 
    346 static int asn1_bio_read(BIO *b, char *in , int inl)
    347 	{
    348 	if (!b->next_bio)
    349 		return 0;
    350 	return BIO_read(b->next_bio, in , inl);
    351 	}
    352 
    353 static int asn1_bio_puts(BIO *b, const char *str)
    354 	{
    355 	return asn1_bio_write(b, str, strlen(str));
    356 	}
    357 
    358 static int asn1_bio_gets(BIO *b, char *str, int size)
    359 	{
    360 	if (!b->next_bio)
    361 		return 0;
    362 	return BIO_gets(b->next_bio, str , size);
    363 	}
    364 
    365 static long asn1_bio_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
    366 	{
    367 	if (b->next_bio == NULL) return(0);
    368 	return BIO_callback_ctrl(b->next_bio,cmd,fp);
    369 	}
    370 
    371 static long asn1_bio_ctrl(BIO *b, int cmd, long arg1, void *arg2)
    372 	{
    373 	BIO_ASN1_BUF_CTX *ctx;
    374 	BIO_ASN1_EX_FUNCS *ex_func;
    375 	long ret = 1;
    376 	ctx = (BIO_ASN1_BUF_CTX *) b->ptr;
    377 	if (ctx == NULL)
    378 		return 0;
    379 	switch(cmd)
    380 		{
    381 
    382 		case BIO_C_SET_PREFIX:
    383 		ex_func = arg2;
    384 		ctx->prefix  = ex_func->ex_func;
    385 		ctx->prefix_free  = ex_func->ex_free_func;
    386 		break;
    387 
    388 		case BIO_C_GET_PREFIX:
    389 		ex_func = arg2;
    390 		ex_func->ex_func = ctx->prefix;
    391 		ex_func->ex_free_func = ctx->prefix_free;
    392 		break;
    393 
    394 		case BIO_C_SET_SUFFIX:
    395 		ex_func = arg2;
    396 		ctx->suffix  = ex_func->ex_func;
    397 		ctx->suffix_free  = ex_func->ex_free_func;
    398 		break;
    399 
    400 		case BIO_C_GET_SUFFIX:
    401 		ex_func = arg2;
    402 		ex_func->ex_func = ctx->suffix;
    403 		ex_func->ex_free_func = ctx->suffix_free;
    404 		break;
    405 
    406 		case BIO_C_SET_EX_ARG:
    407 		ctx->ex_arg = arg2;
    408 		break;
    409 
    410 		case BIO_C_GET_EX_ARG:
    411 		*(void **)arg2 = ctx->ex_arg;
    412 		break;
    413 
    414 		case BIO_CTRL_FLUSH:
    415 		if (!b->next_bio)
    416 			return 0;
    417 
    418 		/* Call post function if possible */
    419 		if (ctx->state == ASN1_STATE_HEADER)
    420 			{
    421 			if (!asn1_bio_setup_ex(b, ctx, ctx->suffix,
    422 				ASN1_STATE_POST_COPY, ASN1_STATE_DONE))
    423 				return 0;
    424 			}
    425 
    426 		if (ctx->state == ASN1_STATE_POST_COPY)
    427 			{
    428 			ret = asn1_bio_flush_ex(b, ctx, ctx->suffix_free,
    429 							ASN1_STATE_DONE);
    430 			if (ret <= 0)
    431 				return ret;
    432 			}
    433 
    434 		if (ctx->state == ASN1_STATE_DONE)
    435 			return BIO_ctrl(b->next_bio, cmd, arg1, arg2);
    436 		else
    437 			{
    438 			BIO_clear_retry_flags(b);
    439 			return 0;
    440 			}
    441 		break;
    442 
    443 
    444 		default:
    445 		if (!b->next_bio)
    446 			return 0;
    447 		return BIO_ctrl(b->next_bio, cmd, arg1, arg2);
    448 
    449 		}
    450 
    451 	return ret;
    452 	}
    453 
    454 static int asn1_bio_set_ex(BIO *b, int cmd,
    455 		asn1_ps_func *ex_func, asn1_ps_func *ex_free_func)
    456 	{
    457 	BIO_ASN1_EX_FUNCS extmp;
    458 	extmp.ex_func = ex_func;
    459 	extmp.ex_free_func = ex_free_func;
    460 	return BIO_ctrl(b, cmd, 0, &extmp);
    461 	}
    462 
    463 static int asn1_bio_get_ex(BIO *b, int cmd,
    464 		asn1_ps_func **ex_func, asn1_ps_func **ex_free_func)
    465 	{
    466 	BIO_ASN1_EX_FUNCS extmp;
    467 	int ret;
    468 	ret = BIO_ctrl(b, cmd, 0, &extmp);
    469 	if (ret > 0)
    470 		{
    471 		*ex_func = extmp.ex_func;
    472 		*ex_free_func = extmp.ex_free_func;
    473 		}
    474 	return ret;
    475 	}
    476 
    477 int BIO_asn1_set_prefix(BIO *b, asn1_ps_func *prefix, asn1_ps_func *prefix_free)
    478 	{
    479 	return asn1_bio_set_ex(b, BIO_C_SET_PREFIX, prefix, prefix_free);
    480 	}
    481 
    482 int BIO_asn1_get_prefix(BIO *b, asn1_ps_func **pprefix, asn1_ps_func **pprefix_free)
    483 	{
    484 	return asn1_bio_get_ex(b, BIO_C_GET_PREFIX, pprefix, pprefix_free);
    485 	}
    486 
    487 int 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 BIO_asn1_get_suffix(BIO *b, asn1_ps_func **psuffix, asn1_ps_func **psuffix_free)
    493 	{
    494 	return asn1_bio_get_ex(b, BIO_C_GET_SUFFIX, psuffix, psuffix_free);
    495 	}
    496