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
61#include <openssl/bio.h>
62#include <openssl/mem.h>
63
64
65/* Must be large enough for biggest tag+length */
66#define DEFAULT_ASN1_BUF_SIZE 20
67
68typedef enum
69	{
70	ASN1_STATE_START,
71	ASN1_STATE_PRE_COPY,
72	ASN1_STATE_HEADER,
73	ASN1_STATE_HEADER_COPY,
74	ASN1_STATE_DATA_COPY,
75	ASN1_STATE_POST_COPY,
76	ASN1_STATE_DONE
77	} asn1_bio_state_t;
78
79typedef struct BIO_ASN1_EX_FUNCS_st
80	{
81	asn1_ps_func	*ex_func;
82	asn1_ps_func	*ex_free_func;
83	} BIO_ASN1_EX_FUNCS;
84
85typedef struct BIO_ASN1_BUF_CTX_t
86	{
87	/* Internal state */
88	asn1_bio_state_t state;
89	/* Internal buffer */
90	unsigned char *buf;
91	/* Size of buffer */
92	int bufsize;
93	/* Current position in buffer */
94	int bufpos;
95	/* Current buffer length */
96	int buflen;
97	/* Amount of data to copy */
98	int copylen;
99	/* Class and tag to use */
100	int asn1_class, asn1_tag;
101	asn1_ps_func *prefix, *prefix_free, *suffix, *suffix_free;
102	/* Extra buffer for prefix and suffix data */
103	unsigned char *ex_buf;
104	int ex_len;
105	int ex_pos;
106	void *ex_arg;
107	} BIO_ASN1_BUF_CTX;
108
109
110static int asn1_bio_write(BIO *h, const char *buf,int num);
111static int asn1_bio_read(BIO *h, char *buf, int size);
112static int asn1_bio_puts(BIO *h, const char *str);
113static int asn1_bio_gets(BIO *h, char *str, int size);
114static long asn1_bio_ctrl(BIO *h, int cmd, long arg1, void *arg2);
115static int asn1_bio_new(BIO *h);
116static int asn1_bio_free(BIO *data);
117static long asn1_bio_callback_ctrl(BIO *h, int cmd, bio_info_cb fp);
118
119static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size);
120static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
121				asn1_ps_func *cleanup, asn1_bio_state_t next);
122static int asn1_bio_setup_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
123				asn1_ps_func *setup,
124				asn1_bio_state_t ex_state,
125				asn1_bio_state_t other_state);
126
127static BIO_METHOD methods_asn1=
128	{
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
146
147static int asn1_bio_new(BIO *b)
148	{
149	BIO_ASN1_BUF_CTX *ctx;
150	ctx = OPENSSL_malloc(sizeof(BIO_ASN1_BUF_CTX));
151	if (!ctx)
152		return 0;
153	if (!asn1_bio_init(ctx, DEFAULT_ASN1_BUF_SIZE))
154		{
155		OPENSSL_free(ctx);
156		return 0;
157		}
158	b->init = 1;
159	b->ptr = (char *)ctx;
160	b->flags = 0;
161	return 1;
162	}
163
164static 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
182static 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
197static 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			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
301static 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
329static 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
346static 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
353static int asn1_bio_puts(BIO *b, const char *str)
354	{
355	return asn1_bio_write(b, str, strlen(str));
356	}
357
358static 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
365static 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
371static 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
454static 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
463static 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
477int 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
482int 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
487int 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
492int 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