1/* bio_ndef.c */
2/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3 * project.
4 */
5/* ====================================================================
6 * Copyright (c) 2008 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 */
54
55#include <openssl/asn1.h>
56#include <openssl/asn1t.h>
57#include <openssl/bio.h>
58#include <openssl/err.h>
59
60#ifndef OPENSSL_SYSNAME_NETWARE
61#include <memory.h>
62#endif
63#include <stdio.h>
64
65/* Experimental NDEF ASN1 BIO support routines */
66
67/* The usage is quite simple, initialize an ASN1 structure,
68 * get a BIO from it then any data written through the BIO
69 * will end up translated to approptiate format on the fly.
70 * The data is streamed out and does *not* need to be
71 * all held in memory at once.
72 *
73 * When the BIO is flushed the output is finalized and any
74 * signatures etc written out.
75 *
76 * The BIO is a 'proper' BIO and can handle non blocking I/O
77 * correctly.
78 *
79 * The usage is simple. The implementation is *not*...
80 */
81
82/* BIO support data stored in the ASN1 BIO ex_arg */
83
84typedef struct ndef_aux_st
85	{
86	/* ASN1 structure this BIO refers to */
87	ASN1_VALUE *val;
88	const ASN1_ITEM *it;
89	/* Top of the BIO chain */
90	BIO *ndef_bio;
91	/* Output BIO */
92	BIO *out;
93	/* Boundary where content is inserted */
94	unsigned char **boundary;
95	/* DER buffer start */
96	unsigned char *derbuf;
97	} NDEF_SUPPORT;
98
99static int ndef_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg);
100static int ndef_prefix_free(BIO *b, unsigned char **pbuf, int *plen, void *parg);
101static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg);
102static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen, void *parg);
103
104BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it)
105	{
106	NDEF_SUPPORT *ndef_aux = NULL;
107	BIO *asn_bio = NULL;
108	const ASN1_AUX *aux = it->funcs;
109	ASN1_STREAM_ARG sarg;
110
111	if (!aux || !aux->asn1_cb)
112		{
113		ASN1err(ASN1_F_BIO_NEW_NDEF, ASN1_R_STREAMING_NOT_SUPPORTED);
114		return NULL;
115		}
116	ndef_aux = OPENSSL_malloc(sizeof(NDEF_SUPPORT));
117	asn_bio = BIO_new(BIO_f_asn1());
118
119	/* ASN1 bio needs to be next to output BIO */
120
121	out = BIO_push(asn_bio, out);
122
123	if (!ndef_aux || !asn_bio || !out)
124		goto err;
125
126	BIO_asn1_set_prefix(asn_bio, ndef_prefix, ndef_prefix_free);
127	BIO_asn1_set_suffix(asn_bio, ndef_suffix, ndef_suffix_free);
128
129	/* Now let callback prepend any digest, cipher etc BIOs
130	 * ASN1 structure needs.
131	 */
132
133	sarg.out = out;
134	sarg.ndef_bio = NULL;
135	sarg.boundary = NULL;
136
137	if (aux->asn1_cb(ASN1_OP_STREAM_PRE, &val, it, &sarg) <= 0)
138		goto err;
139
140	ndef_aux->val = val;
141	ndef_aux->it = it;
142	ndef_aux->ndef_bio = sarg.ndef_bio;
143	ndef_aux->boundary = sarg.boundary;
144	ndef_aux->out = out;
145
146	BIO_ctrl(asn_bio, BIO_C_SET_EX_ARG, 0, ndef_aux);
147
148	return sarg.ndef_bio;
149
150	err:
151	if (asn_bio)
152		BIO_free(asn_bio);
153	if (ndef_aux)
154		OPENSSL_free(ndef_aux);
155	return NULL;
156	}
157
158static int ndef_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg)
159	{
160	NDEF_SUPPORT *ndef_aux;
161	unsigned char *p;
162	int derlen;
163
164	if (!parg)
165		return 0;
166
167	ndef_aux = *(NDEF_SUPPORT **)parg;
168
169	derlen = ASN1_item_ndef_i2d(ndef_aux->val, NULL, ndef_aux->it);
170	p = OPENSSL_malloc(derlen);
171	ndef_aux->derbuf = p;
172	*pbuf = p;
173	derlen = ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it);
174
175	if (!*ndef_aux->boundary)
176		return 0;
177
178	*plen = *ndef_aux->boundary - *pbuf;
179
180	return 1;
181	}
182
183static int ndef_prefix_free(BIO *b, unsigned char **pbuf, int *plen, void *parg)
184	{
185	NDEF_SUPPORT *ndef_aux;
186
187	if (!parg)
188		return 0;
189
190	ndef_aux = *(NDEF_SUPPORT **)parg;
191
192	if (ndef_aux->derbuf)
193		OPENSSL_free(ndef_aux->derbuf);
194
195	ndef_aux->derbuf = NULL;
196	*pbuf = NULL;
197	*plen = 0;
198	return 1;
199	}
200
201static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen, void *parg)
202	{
203	NDEF_SUPPORT **pndef_aux = (NDEF_SUPPORT **)parg;
204	if (!ndef_prefix_free(b, pbuf, plen, parg))
205		return 0;
206	OPENSSL_free(*pndef_aux);
207	*pndef_aux = NULL;
208	return 1;
209	}
210
211static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg)
212	{
213	NDEF_SUPPORT *ndef_aux;
214	unsigned char *p;
215	int derlen;
216	const ASN1_AUX *aux;
217	ASN1_STREAM_ARG sarg;
218
219	if (!parg)
220		return 0;
221
222	ndef_aux = *(NDEF_SUPPORT **)parg;
223
224	aux = ndef_aux->it->funcs;
225
226	/* Finalize structures */
227	sarg.ndef_bio = ndef_aux->ndef_bio;
228	sarg.out = ndef_aux->out;
229	sarg.boundary = ndef_aux->boundary;
230	if (aux->asn1_cb(ASN1_OP_STREAM_POST,
231				&ndef_aux->val, ndef_aux->it, &sarg) <= 0)
232		return 0;
233
234	derlen = ASN1_item_ndef_i2d(ndef_aux->val, NULL, ndef_aux->it);
235	p = OPENSSL_malloc(derlen);
236	ndef_aux->derbuf = p;
237	*pbuf = p;
238	derlen = ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it);
239
240	if (!*ndef_aux->boundary)
241		return 0;
242	*pbuf = *ndef_aux->boundary;
243	*plen = derlen - (*ndef_aux->boundary - ndef_aux->derbuf);
244
245	return 1;
246	}
247