• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
2  * All rights reserved.
3  *
4  * This package is an SSL implementation written
5  * by Eric Young (eay@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@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@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@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 
BIO_f_asn1(void)142 const BIO_METHOD *BIO_f_asn1(void)
143 	{
144 	return(&methods_asn1);
145 	}
146 
147 
asn1_bio_new(BIO * b)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 
asn1_bio_init(BIO_ASN1_BUF_CTX * ctx,int size)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 
asn1_bio_free(BIO * b)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 
asn1_bio_write(BIO * b,const char * in,int inl)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 
asn1_bio_flush_ex(BIO * b,BIO_ASN1_BUF_CTX * ctx,asn1_ps_func * cleanup,asn1_bio_state_t next)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 
asn1_bio_setup_ex(BIO * b,BIO_ASN1_BUF_CTX * ctx,asn1_ps_func * setup,asn1_bio_state_t ex_state,asn1_bio_state_t other_state)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 
asn1_bio_read(BIO * b,char * in,int inl)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 
asn1_bio_puts(BIO * b,const char * str)354 static int asn1_bio_puts(BIO *b, const char *str)
355 	{
356 	return asn1_bio_write(b, str, strlen(str));
357 	}
358 
asn1_bio_gets(BIO * b,char * str,int size)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 
asn1_bio_callback_ctrl(BIO * b,int cmd,bio_info_cb fp)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 
asn1_bio_ctrl(BIO * b,int cmd,long arg1,void * arg2)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 
asn1_bio_set_ex(BIO * b,int cmd,asn1_ps_func * ex_func,asn1_ps_func * ex_free_func)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 
asn1_bio_get_ex(BIO * b,int cmd,asn1_ps_func ** ex_func,asn1_ps_func ** ex_free_func)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 
BIO_asn1_set_prefix(BIO * b,asn1_ps_func * prefix,asn1_ps_func * prefix_free)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 
BIO_asn1_get_prefix(BIO * b,asn1_ps_func ** pprefix,asn1_ps_func ** pprefix_free)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 
BIO_asn1_set_suffix(BIO * b,asn1_ps_func * suffix,asn1_ps_func * suffix_free)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 
BIO_asn1_get_suffix(BIO * b,asn1_ps_func ** psuffix,asn1_ps_func ** psuffix_free)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