Home | History | Annotate | Download | only in asn1
      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