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