New Makefile structure; added compatibility with Windows + Visual C + nmake.
[BearSSL] / src / x509 / x509_decoder.t0
1 \ Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
2 \
3 \ Permission is hereby granted, free of charge, to any person obtaining
4 \ a copy of this software and associated documentation files (the
5 \ "Software"), to deal in the Software without restriction, including
6 \ without limitation the rights to use, copy, modify, merge, publish,
7 \ distribute, sublicense, and/or sell copies of the Software, and to
8 \ permit persons to whom the Software is furnished to do so, subject to
9 \ the following conditions:
10 \
11 \ The above copyright notice and this permission notice shall be
12 \ included in all copies or substantial portions of the Software.
13 \
14 \ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 \ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 \ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 \ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
18 \ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19 \ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 \ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 \ SOFTWARE.
22
23 preamble {
24
25 #include "inner.h"
26
27 #define CTX ((br_x509_decoder_context *)((unsigned char *)t0ctx - offsetof(br_x509_decoder_context, cpu)))
28 #define CONTEXT_NAME br_x509_decoder_context
29
30 /* see bearssl_x509.h */
31 void
32 br_x509_decoder_init(br_x509_decoder_context *ctx,
33 void (*append_dn)(void *ctx, const void *buf, size_t len),
34 void *append_dn_ctx)
35 {
36 memset(ctx, 0, sizeof *ctx);
37 /* obsolete
38 ctx->err = 0;
39 ctx->hbuf = NULL;
40 ctx->hlen = 0;
41 */
42 ctx->append_dn = append_dn;
43 ctx->append_dn_ctx = append_dn_ctx;
44 ctx->cpu.dp = &ctx->dp_stack[0];
45 ctx->cpu.rp = &ctx->rp_stack[0];
46 br_x509_decoder_init_main(&ctx->cpu);
47 br_x509_decoder_run(&ctx->cpu);
48 }
49
50 /* see bearssl_x509.h */
51 void
52 br_x509_decoder_push(br_x509_decoder_context *ctx,
53 const void *data, size_t len)
54 {
55 ctx->hbuf = data;
56 ctx->hlen = len;
57 br_x509_decoder_run(&ctx->cpu);
58 }
59
60 }
61
62 addr: decoded
63 addr: notbefore_days
64 addr: notbefore_seconds
65 addr: notafter_days
66 addr: notafter_seconds
67 addr: isCA
68 addr: copy_dn
69 addr: signer_key_type
70 addr: signer_hash_id
71
72 cc: read8-low ( -- x ) {
73 if (CTX->hlen == 0) {
74 T0_PUSHi(-1);
75 } else {
76 unsigned char x = *CTX->hbuf ++;
77 if (CTX->copy_dn && CTX->append_dn) {
78 CTX->append_dn(CTX->append_dn_ctx, &x, 1);
79 }
80 CTX->hlen --;
81 T0_PUSH(x);
82 }
83 }
84
85 cc: read-blob-inner ( addr len -- addr len ) {
86 uint32_t len = T0_POP();
87 uint32_t addr = T0_POP();
88 size_t clen = CTX->hlen;
89 if (clen > len) {
90 clen = (size_t)len;
91 }
92 if (addr != 0) {
93 memcpy((unsigned char *)CTX + addr, CTX->hbuf, clen);
94 }
95 if (CTX->copy_dn && CTX->append_dn) {
96 CTX->append_dn(CTX->append_dn_ctx, CTX->hbuf, clen);
97 }
98 CTX->hbuf += clen;
99 CTX->hlen -= clen;
100 T0_PUSH(addr + clen);
101 T0_PUSH(len - clen);
102 }
103
104 \ Get the address and length for the pkey_data buffer.
105 : addr-len-pkey_data ( -- addr len )
106 CX 0 8191 { offsetof(br_x509_decoder_context, pkey_data) }
107 CX 0 8191 { BR_X509_BUFSIZE_KEY } ;
108
109 \ Copy the public key (RSA) to the permanent buffer.
110 cc: copy-rsa-pkey ( nlen elen -- ) {
111 size_t elen = T0_POP();
112 size_t nlen = T0_POP();
113 CTX->pkey.key_type = BR_KEYTYPE_RSA;
114 CTX->pkey.key.rsa.n = CTX->pkey_data;
115 CTX->pkey.key.rsa.nlen = nlen;
116 CTX->pkey.key.rsa.e = CTX->pkey_data + nlen;
117 CTX->pkey.key.rsa.elen = elen;
118 }
119
120 \ Copy the public key (EC) to the permanent buffer.
121 cc: copy-ec-pkey ( curve qlen -- ) {
122 size_t qlen = T0_POP();
123 uint32_t curve = T0_POP();
124 CTX->pkey.key_type = BR_KEYTYPE_EC;
125 CTX->pkey.key.ec.curve = curve;
126 CTX->pkey.key.ec.q = CTX->pkey_data;
127 CTX->pkey.key.ec.qlen = qlen;
128 }
129
130 \ Extensions with specific processing.
131 OID: basicConstraints 2.5.29.19
132
133 \ Process a Basic Constraints extension. We want the "CA" flag only.
134 : process-basicConstraints ( lim -- lim )
135 read-sequence-open
136 read-tag-or-end dup 0x01 = if
137 read-boolean 1 and addr-isCA set8
138 else
139 2drop
140 then
141 skip-close-elt
142 ;
143
144 \ Decode a certificate.
145 : main ( -- ! )
146
147 \ Initialise state flags.
148 0 addr-decoded set8
149 0 addr-copy_dn set8
150
151 \ An arbitrary limit for the total certificate size.
152 0xFFFFFF
153
154 \ Open the outer SEQUENCE.
155 read-sequence-open
156
157 \ TBS
158 read-sequence-open
159
160 \ First element may be an explicit version. We accept only
161 \ versions 0 to 2 (certificates v1 to v3).
162 read-tag dup 0x20 = if
163 drop check-constructed read-length-open-elt
164 read-tag
165 0x02 check-tag-primitive
166 read-small-int-value
167 2 > if ERR_X509_UNSUPPORTED fail then
168 close-elt
169 read-tag
170 then
171
172 \ Serial number. We just check that the tag is correct.
173 0x02 check-tag-primitive read-length-skip
174
175 \ Signature algorithm.
176 read-sequence-open skip-close-elt
177
178 \ Issuer name.
179 read-sequence-open skip-close-elt
180
181 \ Validity dates.
182 read-sequence-open
183 read-date addr-notbefore_seconds set32 addr-notbefore_days set32
184 read-date addr-notafter_seconds set32 addr-notafter_days set32
185 close-elt
186
187 \ Subject name.
188 1 addr-copy_dn set8
189 read-sequence-open skip-close-elt
190 0 addr-copy_dn set8
191
192 \ Public Key.
193 read-sequence-open
194 \ Algorithm Identifier. Right now we are only interested in the
195 \ OID, since we only support RSA keys.
196 \ TODO: support EC keys
197 read-sequence-open
198 read-OID ifnot ERR_X509_UNSUPPORTED fail then
199 choice
200 \ RSA public key.
201 rsaEncryption eqOID uf
202 skip-close-elt
203 \ Public key itself: the BIT STRING contains bytes
204 \ (no partial byte) and these bytes encode the
205 \ actual value.
206 read-bits-open
207 \ RSA public key is a SEQUENCE of two
208 \ INTEGER. We get both INTEGER values into
209 \ the pkey_data[] buffer, if they fit.
210 read-sequence-open
211 addr-len-pkey_data
212 read-integer { nlen }
213 addr-len-pkey_data swap nlen + swap nlen -
214 read-integer { elen }
215 close-elt
216 close-elt
217 nlen elen copy-rsa-pkey
218 enduf
219
220 \ EC public key.
221 id-ecPublicKey eqOID uf
222 \ We support only named curves, for which the
223 \ "parameters" field in the AlgorithmIdentifier
224 \ field should be an OID.
225 read-curve-ID { curve }
226 close-elt
227 read-bits-open
228 dup { qlen }
229 dup addr-len-pkey_data rot < if
230 ERR_X509_LIMIT_EXCEEDED fail
231 then
232 read-blob
233 curve qlen copy-ec-pkey
234 enduf
235 ERR_X509_UNSUPPORTED fail
236 endchoice
237 close-elt
238
239 \ This flag will be set to true if the Basic Constraints extension
240 \ is encountered.
241 0 addr-isCA set8
242
243 \ Skip issuerUniqueID and subjectUniqueID, and process extensions
244 \ if present. Extensions are an explicit context tag of value 3
245 \ around a SEQUENCE OF extensions. Each extension is a SEQUENCE
246 \ with an OID, an optional boolean, and a value; the value is
247 \ an OCTET STRING.
248 read-tag-or-end
249 0x21 iftag-skip
250 0x22 iftag-skip
251 dup 0x23 = if
252 drop
253 check-constructed read-length-open-elt
254 read-sequence-open
255 begin dup while
256 read-sequence-open
257 read-OID drop
258 read-tag dup 0x01 = if
259 read-boolean drop
260 read-tag
261 then
262 0x04 check-tag-primitive read-length-open-elt
263 choice
264 \ Extensions with specific processing.
265 basicConstraints eqOID uf
266 process-basicConstraints
267 enduf
268 skip-remaining
269 endchoice
270 close-elt
271 close-elt
272 repeat
273 close-elt
274 close-elt
275 else
276 -1 = ifnot ERR_X509_UNEXPECTED fail then
277 drop
278 then
279
280 close-elt
281
282 \ signature algorithm
283 read-sequence-open
284 read-OID if
285 choice
286 sha1WithRSAEncryption eqOID uf 2 KEYTYPE_RSA enduf
287 sha224WithRSAEncryption eqOID uf 3 KEYTYPE_RSA enduf
288 sha256WithRSAEncryption eqOID uf 4 KEYTYPE_RSA enduf
289 sha384WithRSAEncryption eqOID uf 5 KEYTYPE_RSA enduf
290 sha512WithRSAEncryption eqOID uf 6 KEYTYPE_RSA enduf
291
292 ecdsa-with-SHA1 eqOID uf 2 KEYTYPE_EC enduf
293 ecdsa-with-SHA224 eqOID uf 3 KEYTYPE_EC enduf
294 ecdsa-with-SHA256 eqOID uf 4 KEYTYPE_EC enduf
295 ecdsa-with-SHA384 eqOID uf 5 KEYTYPE_EC enduf
296 ecdsa-with-SHA512 eqOID uf 6 KEYTYPE_EC enduf
297
298 0 0
299 endchoice
300 else
301 0 0
302 then
303 addr-signer_key_type set8
304 addr-signer_hash_id set8
305 skip-close-elt
306 \ read-sequence-open skip-close-elt
307
308 \ signature value
309 read-bits-open skip-close-elt
310
311 \ Close the outer SEQUENCE.
312 close-elt
313 drop
314
315 \ Mark the decoding as successful.
316 1 addr-decoded set8
317
318 \ Read one byte, then fail: if the read succeeds, then there is
319 \ some trailing byte.
320 read8-nc ERR_X509_EXTRA_ELEMENT fail
321 ;