bio_asn1.c revision e45f106cb6b47af1f21efe76e933bdea2f5dd1ca
1/* bio_asn1.c */
2/* Written by Dr Stephen N Henson (steve@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@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@cryptsoft.com).  This product includes software written by Tim
55 * Hudson (tjh@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
71typedef 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
82typedef 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
88typedef 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
113static int asn1_bio_write(BIO *h, const char *buf,int num);
114static int asn1_bio_read(BIO *h, char *buf, int size);
115static int asn1_bio_puts(BIO *h, const char *str);
116static int asn1_bio_gets(BIO *h, char *str, int size);
117static long asn1_bio_ctrl(BIO *h, int cmd, long arg1, void *arg2);
118static int asn1_bio_new(BIO *h);
119static int asn1_bio_free(BIO *data);
120static long asn1_bio_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp);
121
122static int asn1_bio_init(BIO_ASN1_BUF_CTX *ctx, int size);
123static int asn1_bio_flush_ex(BIO *b, BIO_ASN1_BUF_CTX *ctx,
124				asn1_ps_func *cleanup, asn1_bio_state_t next);
125static 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
130static 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
144BIO_METHOD *BIO_f_asn1(void)
145	{
146	return(&methods_asn1);
147	}
148
149
150static 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
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			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
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