1 /*
2 * Copyright 2008-2023 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
8 */
9
10 #include <openssl/asn1.h>
11 #include <openssl/asn1t.h>
12 #include <openssl/bio.h>
13 #include <openssl/err.h>
14
15 #include <stdio.h>
16
17 /* Experimental NDEF ASN1 BIO support routines */
18
19 /*
20 * The usage is quite simple, initialize an ASN1 structure, get a BIO from it
21 * then any data written through the BIO will end up translated to
22 * appropriate format on the fly. The data is streamed out and does *not*
23 * need to be all held in memory at once. When the BIO is flushed the output
24 * is finalized and any signatures etc written out. The BIO is a 'proper'
25 * BIO and can handle non blocking I/O correctly. The usage is simple. The
26 * implementation is *not*...
27 */
28
29 /* BIO support data stored in the ASN1 BIO ex_arg */
30
31 typedef struct ndef_aux_st {
32 /* ASN1 structure this BIO refers to */
33 ASN1_VALUE *val;
34 const ASN1_ITEM *it;
35 /* Top of the BIO chain */
36 BIO *ndef_bio;
37 /* Output BIO */
38 BIO *out;
39 /* Boundary where content is inserted */
40 unsigned char **boundary;
41 /* DER buffer start */
42 unsigned char *derbuf;
43 } NDEF_SUPPORT;
44
45 static int ndef_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg);
46 static int ndef_prefix_free(BIO *b, unsigned char **pbuf, int *plen,
47 void *parg);
48 static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg);
49 static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen,
50 void *parg);
51
52 /*
53 * On success, the returned BIO owns the input BIO as part of its BIO chain.
54 * On failure, NULL is returned and the input BIO is owned by the caller.
55 *
56 * Unfortunately cannot constify this due to CMS_stream() and PKCS7_stream()
57 */
BIO_new_NDEF(BIO * out,ASN1_VALUE * val,const ASN1_ITEM * it)58 BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it)
59 {
60 NDEF_SUPPORT *ndef_aux = NULL;
61 BIO *asn_bio = NULL;
62 const ASN1_AUX *aux = it->funcs;
63 ASN1_STREAM_ARG sarg;
64 BIO *pop_bio = NULL;
65
66 if (!aux || !aux->asn1_cb) {
67 ERR_raise(ERR_LIB_ASN1, ASN1_R_STREAMING_NOT_SUPPORTED);
68 return NULL;
69 }
70 ndef_aux = OPENSSL_zalloc(sizeof(*ndef_aux));
71 asn_bio = BIO_new(BIO_f_asn1());
72 if (ndef_aux == NULL || asn_bio == NULL)
73 goto err;
74
75 /* ASN1 bio needs to be next to output BIO */
76 out = BIO_push(asn_bio, out);
77 if (out == NULL)
78 goto err;
79 pop_bio = asn_bio;
80
81 if (BIO_asn1_set_prefix(asn_bio, ndef_prefix, ndef_prefix_free) <= 0
82 || BIO_asn1_set_suffix(asn_bio, ndef_suffix, ndef_suffix_free) <= 0
83 || BIO_ctrl(asn_bio, BIO_C_SET_EX_ARG, 0, ndef_aux) <= 0)
84 goto err;
85
86 /*
87 * Now let the callback prepend any digest, cipher, etc., that the BIO's
88 * ASN1 structure needs.
89 */
90
91 sarg.out = out;
92 sarg.ndef_bio = NULL;
93 sarg.boundary = NULL;
94
95 /*
96 * The asn1_cb(), must not have mutated asn_bio on error, leaving it in the
97 * middle of some partially built, but not returned BIO chain.
98 */
99 if (aux->asn1_cb(ASN1_OP_STREAM_PRE, &val, it, &sarg) <= 0) {
100 /*
101 * ndef_aux is now owned by asn_bio so we must not free it in the err
102 * clean up block
103 */
104 ndef_aux = NULL;
105 goto err;
106 }
107
108 /*
109 * We must not fail now because the callback has prepended additional
110 * BIOs to the chain
111 */
112
113 ndef_aux->val = val;
114 ndef_aux->it = it;
115 ndef_aux->ndef_bio = sarg.ndef_bio;
116 ndef_aux->boundary = sarg.boundary;
117 ndef_aux->out = out;
118
119 return sarg.ndef_bio;
120
121 err:
122 /* BIO_pop() is NULL safe */
123 (void)BIO_pop(pop_bio);
124 BIO_free(asn_bio);
125 OPENSSL_free(ndef_aux);
126 return NULL;
127 }
128
ndef_prefix(BIO * b,unsigned char ** pbuf,int * plen,void * parg)129 static int ndef_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg)
130 {
131 NDEF_SUPPORT *ndef_aux;
132 unsigned char *p;
133 int derlen;
134
135 if (parg == NULL)
136 return 0;
137
138 ndef_aux = *(NDEF_SUPPORT **)parg;
139
140 derlen = ASN1_item_ndef_i2d(ndef_aux->val, NULL, ndef_aux->it);
141 if (derlen < 0)
142 return 0;
143 if ((p = OPENSSL_malloc(derlen)) == NULL) {
144 ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE);
145 return 0;
146 }
147
148 ndef_aux->derbuf = p;
149 *pbuf = p;
150 ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it);
151
152 if (*ndef_aux->boundary == NULL)
153 return 0;
154
155 *plen = *ndef_aux->boundary - *pbuf;
156
157 return 1;
158 }
159
ndef_prefix_free(BIO * b,unsigned char ** pbuf,int * plen,void * parg)160 static int ndef_prefix_free(BIO *b, unsigned char **pbuf, int *plen,
161 void *parg)
162 {
163 NDEF_SUPPORT *ndef_aux;
164
165 if (parg == NULL)
166 return 0;
167
168 ndef_aux = *(NDEF_SUPPORT **)parg;
169
170 if (ndef_aux == NULL)
171 return 0;
172
173 OPENSSL_free(ndef_aux->derbuf);
174
175 ndef_aux->derbuf = NULL;
176 *pbuf = NULL;
177 *plen = 0;
178 return 1;
179 }
180
ndef_suffix_free(BIO * b,unsigned char ** pbuf,int * plen,void * parg)181 static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen,
182 void *parg)
183 {
184 NDEF_SUPPORT **pndef_aux = (NDEF_SUPPORT **)parg;
185 if (!ndef_prefix_free(b, pbuf, plen, parg))
186 return 0;
187 OPENSSL_free(*pndef_aux);
188 *pndef_aux = NULL;
189 return 1;
190 }
191
ndef_suffix(BIO * b,unsigned char ** pbuf,int * plen,void * parg)192 static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg)
193 {
194 NDEF_SUPPORT *ndef_aux;
195 unsigned char *p;
196 int derlen;
197 const ASN1_AUX *aux;
198 ASN1_STREAM_ARG sarg;
199
200 if (parg == NULL)
201 return 0;
202
203 ndef_aux = *(NDEF_SUPPORT **)parg;
204
205 aux = ndef_aux->it->funcs;
206
207 /* Finalize structures */
208 sarg.ndef_bio = ndef_aux->ndef_bio;
209 sarg.out = ndef_aux->out;
210 sarg.boundary = ndef_aux->boundary;
211 if (aux->asn1_cb(ASN1_OP_STREAM_POST,
212 &ndef_aux->val, ndef_aux->it, &sarg) <= 0)
213 return 0;
214
215 derlen = ASN1_item_ndef_i2d(ndef_aux->val, NULL, ndef_aux->it);
216 if (derlen < 0)
217 return 0;
218 if ((p = OPENSSL_malloc(derlen)) == NULL) {
219 ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE);
220 return 0;
221 }
222
223 ndef_aux->derbuf = p;
224 *pbuf = p;
225 derlen = ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it);
226
227 if (*ndef_aux->boundary == NULL)
228 return 0;
229 *pbuf = *ndef_aux->boundary;
230 *plen = derlen - (*ndef_aux->boundary - ndef_aux->derbuf);
231
232 return 1;
233 }
234