]>
Commit | Line | Data |
---|---|---|
0f113f3e | 1 | /* |
605856d7 | 2 | * Copyright 2008-2020 The OpenSSL Project Authors. All Rights Reserved. |
8931b30d | 3 | * |
365a2d99 | 4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
b1322259 RS |
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 | |
8931b30d DSH |
8 | */ |
9 | ||
10 | #include <openssl/asn1.h> | |
11 | #include <openssl/asn1t.h> | |
12 | #include <openssl/bio.h> | |
13 | #include <openssl/err.h> | |
14 | ||
8931b30d DSH |
15 | #include <stdio.h> |
16 | ||
17 | /* Experimental NDEF ASN1 BIO support routines */ | |
18 | ||
0f113f3e MC |
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 | |
b6453a68 | 22 | * appropriate format on the fly. The data is streamed out and does *not* |
0f113f3e MC |
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*... | |
8931b30d DSH |
27 | */ |
28 | ||
29 | /* BIO support data stored in the ASN1 BIO ex_arg */ | |
30 | ||
0f113f3e MC |
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; | |
8931b30d DSH |
44 | |
45 | static int ndef_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg); | |
0f113f3e MC |
46 | static int ndef_prefix_free(BIO *b, unsigned char **pbuf, int *plen, |
47 | void *parg); | |
8931b30d | 48 | static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg); |
0f113f3e MC |
49 | static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen, |
50 | void *parg); | |
8931b30d | 51 | |
9fdcc21f | 52 | /* unfortunately cannot constify this due to CMS_stream() and PKCS7_stream() */ |
8931b30d | 53 | BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it) |
0f113f3e MC |
54 | { |
55 | NDEF_SUPPORT *ndef_aux = NULL; | |
56 | BIO *asn_bio = NULL; | |
57 | const ASN1_AUX *aux = it->funcs; | |
58 | ASN1_STREAM_ARG sarg; | |
8931b30d | 59 | |
0f113f3e | 60 | if (!aux || !aux->asn1_cb) { |
9311d0c4 | 61 | ERR_raise(ERR_LIB_ASN1, ASN1_R_STREAMING_NOT_SUPPORTED); |
0f113f3e MC |
62 | return NULL; |
63 | } | |
f59f23c3 | 64 | ndef_aux = OPENSSL_zalloc(sizeof(*ndef_aux)); |
0f113f3e | 65 | asn_bio = BIO_new(BIO_f_asn1()); |
f59f23c3 F |
66 | if (ndef_aux == NULL || asn_bio == NULL) |
67 | goto err; | |
8931b30d | 68 | |
0f113f3e | 69 | /* ASN1 bio needs to be next to output BIO */ |
0f113f3e | 70 | out = BIO_push(asn_bio, out); |
f59f23c3 | 71 | if (out == NULL) |
0f113f3e | 72 | goto err; |
8931b30d | 73 | |
0f113f3e MC |
74 | BIO_asn1_set_prefix(asn_bio, ndef_prefix, ndef_prefix_free); |
75 | BIO_asn1_set_suffix(asn_bio, ndef_suffix, ndef_suffix_free); | |
8931b30d | 76 | |
0f113f3e | 77 | /* |
8483a003 | 78 | * Now let callback prepends any digest, cipher etc BIOs ASN1 structure |
0f113f3e MC |
79 | * needs. |
80 | */ | |
8931b30d | 81 | |
0f113f3e MC |
82 | sarg.out = out; |
83 | sarg.ndef_bio = NULL; | |
84 | sarg.boundary = NULL; | |
8931b30d | 85 | |
0f113f3e MC |
86 | if (aux->asn1_cb(ASN1_OP_STREAM_PRE, &val, it, &sarg) <= 0) |
87 | goto err; | |
8931b30d | 88 | |
0f113f3e MC |
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; | |
8931b30d | 94 | |
0f113f3e | 95 | BIO_ctrl(asn_bio, BIO_C_SET_EX_ARG, 0, ndef_aux); |
8931b30d | 96 | |
0f113f3e | 97 | return sarg.ndef_bio; |
8931b30d | 98 | |
0f113f3e | 99 | err: |
ca3a82c3 | 100 | BIO_free(asn_bio); |
b548a1f1 | 101 | OPENSSL_free(ndef_aux); |
0f113f3e MC |
102 | return NULL; |
103 | } | |
8931b30d DSH |
104 | |
105 | static int ndef_prefix(BIO *b, unsigned char **pbuf, int *plen, void *parg) | |
0f113f3e MC |
106 | { |
107 | NDEF_SUPPORT *ndef_aux; | |
108 | unsigned char *p; | |
109 | int derlen; | |
8931b30d | 110 | |
12a765a5 | 111 | if (parg == NULL) |
0f113f3e | 112 | return 0; |
8931b30d | 113 | |
0f113f3e | 114 | ndef_aux = *(NDEF_SUPPORT **)parg; |
8931b30d | 115 | |
0f113f3e | 116 | derlen = ASN1_item_ndef_i2d(ndef_aux->val, NULL, ndef_aux->it); |
cdb10bae | 117 | if ((p = OPENSSL_malloc(derlen)) == NULL) { |
9311d0c4 | 118 | ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE); |
918bb865 | 119 | return 0; |
cdb10bae | 120 | } |
918bb865 | 121 | |
0f113f3e MC |
122 | ndef_aux->derbuf = p; |
123 | *pbuf = p; | |
124 | derlen = ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it); | |
8931b30d | 125 | |
12a765a5 | 126 | if (*ndef_aux->boundary == NULL) |
0f113f3e | 127 | return 0; |
8931b30d | 128 | |
0f113f3e | 129 | *plen = *ndef_aux->boundary - *pbuf; |
8931b30d | 130 | |
0f113f3e MC |
131 | return 1; |
132 | } | |
8931b30d | 133 | |
0f113f3e MC |
134 | static int ndef_prefix_free(BIO *b, unsigned char **pbuf, int *plen, |
135 | void *parg) | |
136 | { | |
137 | NDEF_SUPPORT *ndef_aux; | |
8931b30d | 138 | |
12a765a5 | 139 | if (parg == NULL) |
0f113f3e | 140 | return 0; |
8931b30d | 141 | |
0f113f3e | 142 | ndef_aux = *(NDEF_SUPPORT **)parg; |
8931b30d | 143 | |
b548a1f1 | 144 | OPENSSL_free(ndef_aux->derbuf); |
8931b30d | 145 | |
0f113f3e MC |
146 | ndef_aux->derbuf = NULL; |
147 | *pbuf = NULL; | |
148 | *plen = 0; | |
149 | return 1; | |
150 | } | |
8931b30d | 151 | |
0f113f3e MC |
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 | } | |
8931b30d DSH |
162 | |
163 | static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg) | |
0f113f3e MC |
164 | { |
165 | NDEF_SUPPORT *ndef_aux; | |
166 | unsigned char *p; | |
167 | int derlen; | |
168 | const ASN1_AUX *aux; | |
169 | ASN1_STREAM_ARG sarg; | |
170 | ||
12a765a5 | 171 | if (parg == NULL) |
0f113f3e MC |
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); | |
35e264c0 P |
187 | if (derlen < 0) |
188 | return 0; | |
cdb10bae | 189 | if ((p = OPENSSL_malloc(derlen)) == NULL) { |
9311d0c4 | 190 | ERR_raise(ERR_LIB_ASN1, ERR_R_MALLOC_FAILURE); |
918bb865 | 191 | return 0; |
cdb10bae | 192 | } |
918bb865 | 193 | |
0f113f3e MC |
194 | ndef_aux->derbuf = p; |
195 | *pbuf = p; | |
196 | derlen = ASN1_item_ndef_i2d(ndef_aux->val, &p, ndef_aux->it); | |
197 | ||
12a765a5 | 198 | if (*ndef_aux->boundary == NULL) |
0f113f3e MC |
199 | return 0; |
200 | *pbuf = *ndef_aux->boundary; | |
201 | *plen = derlen - (*ndef_aux->boundary - ndef_aux->derbuf); | |
202 | ||
203 | return 1; | |
204 | } |