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 return 0;
145
146 ndef_aux->derbuf = p;
147 *pbuf = p;
148 ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it);
149
150 if (*ndef_aux->boundary == NULL)
151 return 0;
152
153 *plen = *ndef_aux->boundary - *pbuf;
154
155 return 1;
156 }
157
ndef_prefix_free(BIO * b,unsigned char ** pbuf,int * plen,void * parg)158 static int ndef_prefix_free(BIO *b, unsigned char **pbuf, int *plen,
159 void *parg)
160 {
161 NDEF_SUPPORT *ndef_aux;
162
163 if (parg == NULL)
164 return 0;
165
166 ndef_aux = *(NDEF_SUPPORT **)parg;
167
168 if (ndef_aux == NULL)
169 return 0;
170
171 OPENSSL_free(ndef_aux->derbuf);
172
173 ndef_aux->derbuf = NULL;
174 *pbuf = NULL;
175 *plen = 0;
176 return 1;
177 }
178
ndef_suffix_free(BIO * b,unsigned char ** pbuf,int * plen,void * parg)179 static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen,
180 void *parg)
181 {
182 NDEF_SUPPORT **pndef_aux = (NDEF_SUPPORT **)parg;
183 if (!ndef_prefix_free(b, pbuf, plen, parg))
184 return 0;
185 OPENSSL_free(*pndef_aux);
186 *pndef_aux = NULL;
187 return 1;
188 }
189
ndef_suffix(BIO * b,unsigned char ** pbuf,int * plen,void * parg)190 static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg)
191 {
192 NDEF_SUPPORT *ndef_aux;
193 unsigned char *p;
194 int derlen;
195 const ASN1_AUX *aux;
196 ASN1_STREAM_ARG sarg;
197
198 if (parg == NULL)
199 return 0;
200
201 ndef_aux = *(NDEF_SUPPORT **)parg;
202
203 aux = ndef_aux->it->funcs;
204
205 /* Finalize structures */
206 sarg.ndef_bio = ndef_aux->ndef_bio;
207 sarg.out = ndef_aux->out;
208 sarg.boundary = ndef_aux->boundary;
209 if (aux->asn1_cb(ASN1_OP_STREAM_POST,
210 &ndef_aux->val, ndef_aux->it, &sarg) <= 0)
211 return 0;
212
213 derlen = ASN1_item_ndef_i2d(ndef_aux->val, NULL, ndef_aux->it);
214 if (derlen < 0)
215 return 0;
216 if ((p = OPENSSL_malloc(derlen)) == NULL)
217 return 0;
218
219 ndef_aux->derbuf = p;
220 *pbuf = p;
221 derlen = ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it);
222
223 if (*ndef_aux->boundary == NULL)
224 return 0;
225 *pbuf = *ndef_aux->boundary;
226 *plen = derlen - (*ndef_aux->boundary - ndef_aux->derbuf);
227
228 return 1;
229 }
230