1 | /* |
2 | * Copyright 2008-2018 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 | /* unfortunately cannot constify this due to CMS_stream() and PKCS7_stream() */ |
53 | BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it) |
54 | { |
55 | NDEF_SUPPORT *ndef_aux = NULL; |
56 | BIO *asn_bio = NULL; |
57 | const ASN1_AUX *aux = it->funcs; |
58 | ASN1_STREAM_ARG sarg; |
59 | |
60 | if (!aux || !aux->asn1_cb) { |
61 | ASN1err(ASN1_F_BIO_NEW_NDEF, ASN1_R_STREAMING_NOT_SUPPORTED); |
62 | return NULL; |
63 | } |
64 | ndef_aux = OPENSSL_zalloc(sizeof(*ndef_aux)); |
65 | asn_bio = BIO_new(BIO_f_asn1()); |
66 | if (ndef_aux == NULL || asn_bio == NULL) |
67 | goto err; |
68 | |
69 | /* ASN1 bio needs to be next to output BIO */ |
70 | out = BIO_push(asn_bio, out); |
71 | if (out == NULL) |
72 | goto err; |
73 | |
74 | BIO_asn1_set_prefix(asn_bio, ndef_prefix, ndef_prefix_free); |
75 | BIO_asn1_set_suffix(asn_bio, ndef_suffix, ndef_suffix_free); |
76 | |
77 | /* |
78 | * Now let callback prepends any digest, cipher etc BIOs ASN1 structure |
79 | * needs. |
80 | */ |
81 | |
82 | sarg.out = out; |
83 | sarg.ndef_bio = NULL; |
84 | sarg.boundary = NULL; |
85 | |
86 | if (aux->asn1_cb(ASN1_OP_STREAM_PRE, &val, it, &sarg) <= 0) |
87 | goto err; |
88 | |
89 | ndef_aux->val = val; |
90 | ndef_aux->it = it; |
91 | ndef_aux->ndef_bio = sarg.ndef_bio; |
92 | ndef_aux->boundary = sarg.boundary; |
93 | ndef_aux->out = out; |
94 | |
95 | BIO_ctrl(asn_bio, BIO_C_SET_EX_ARG, 0, ndef_aux); |
96 | |
97 | return sarg.ndef_bio; |
98 | |
99 | err: |
100 | BIO_free(asn_bio); |
101 | OPENSSL_free(ndef_aux); |
102 | return NULL; |
103 | } |
104 | |
105 | static int ndef_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg) |
106 | { |
107 | NDEF_SUPPORT *ndef_aux; |
108 | unsigned char *p; |
109 | int derlen; |
110 | |
111 | if (parg == NULL) |
112 | return 0; |
113 | |
114 | ndef_aux = *(NDEF_SUPPORT **)parg; |
115 | |
116 | derlen = ASN1_item_ndef_i2d(ndef_aux->val, NULL, ndef_aux->it); |
117 | if ((p = OPENSSL_malloc(derlen)) == NULL) { |
118 | ASN1err(ASN1_F_NDEF_PREFIX, ERR_R_MALLOC_FAILURE); |
119 | return 0; |
120 | } |
121 | |
122 | ndef_aux->derbuf = p; |
123 | *pbuf = p; |
124 | derlen = ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it); |
125 | |
126 | if (*ndef_aux->boundary == NULL) |
127 | return 0; |
128 | |
129 | *plen = *ndef_aux->boundary - *pbuf; |
130 | |
131 | return 1; |
132 | } |
133 | |
134 | static int ndef_prefix_free(BIO *b, unsigned char **pbuf, int *plen, |
135 | void *parg) |
136 | { |
137 | NDEF_SUPPORT *ndef_aux; |
138 | |
139 | if (parg == NULL) |
140 | return 0; |
141 | |
142 | ndef_aux = *(NDEF_SUPPORT **)parg; |
143 | |
144 | OPENSSL_free(ndef_aux->derbuf); |
145 | |
146 | ndef_aux->derbuf = NULL; |
147 | *pbuf = NULL; |
148 | *plen = 0; |
149 | return 1; |
150 | } |
151 | |
152 | static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen, |
153 | void *parg) |
154 | { |
155 | NDEF_SUPPORT **pndef_aux = (NDEF_SUPPORT **)parg; |
156 | if (!ndef_prefix_free(b, pbuf, plen, parg)) |
157 | return 0; |
158 | OPENSSL_free(*pndef_aux); |
159 | *pndef_aux = NULL; |
160 | return 1; |
161 | } |
162 | |
163 | static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg) |
164 | { |
165 | NDEF_SUPPORT *ndef_aux; |
166 | unsigned char *p; |
167 | int derlen; |
168 | const ASN1_AUX *aux; |
169 | ASN1_STREAM_ARG sarg; |
170 | |
171 | if (parg == NULL) |
172 | return 0; |
173 | |
174 | ndef_aux = *(NDEF_SUPPORT **)parg; |
175 | |
176 | aux = ndef_aux->it->funcs; |
177 | |
178 | /* Finalize structures */ |
179 | sarg.ndef_bio = ndef_aux->ndef_bio; |
180 | sarg.out = ndef_aux->out; |
181 | sarg.boundary = ndef_aux->boundary; |
182 | if (aux->asn1_cb(ASN1_OP_STREAM_POST, |
183 | &ndef_aux->val, ndef_aux->it, &sarg) <= 0) |
184 | return 0; |
185 | |
186 | derlen = ASN1_item_ndef_i2d(ndef_aux->val, NULL, ndef_aux->it); |
187 | if (derlen < 0) |
188 | return 0; |
189 | if ((p = OPENSSL_malloc(derlen)) == NULL) { |
190 | ASN1err(ASN1_F_NDEF_SUFFIX, ERR_R_MALLOC_FAILURE); |
191 | return 0; |
192 | } |
193 | |
194 | ndef_aux->derbuf = p; |
195 | *pbuf = p; |
196 | derlen = ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it); |
197 | |
198 | if (*ndef_aux->boundary == NULL) |
199 | return 0; |
200 | *pbuf = *ndef_aux->boundary; |
201 | *plen = derlen - (*ndef_aux->boundary - ndef_aux->derbuf); |
202 | |
203 | return 1; |
204 | } |
205 | |