1 \ Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
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:
11 \ The above copyright notice and this permission notice shall be
12 \ included in all copies or substantial portions of the Software.
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
27 #define CTX ((br_x509_decoder_context *)(void *)((unsigned char *)t0ctx - offsetof(br_x509_decoder_context, cpu)))
28 #define CONTEXT_NAME br_x509_decoder_context
30 /* see bearssl_x509.h */
32 br_x509_decoder_init(br_x509_decoder_context *ctx,
33 void (*append_dn)(void *ctx, const void *buf, size_t len),
36 memset(ctx, 0, sizeof *ctx);
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);
50 /* see bearssl_x509.h */
52 br_x509_decoder_push(br_x509_decoder_context *ctx,
53 const void *data, size_t len)
57 br_x509_decoder_run(&ctx->cpu);
64 addr: notbefore_seconds
66 addr: notafter_seconds
72 cc: read8-low ( -- x ) {
76 unsigned char x = *CTX->hbuf ++;
77 if (CTX->copy_dn && CTX->append_dn) {
78 CTX->append_dn(CTX->append_dn_ctx, &x, 1);
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;
93 memcpy((unsigned char *)CTX + addr, CTX->hbuf, clen);
95 if (CTX->copy_dn && CTX->append_dn) {
96 CTX->append_dn(CTX->append_dn_ctx, CTX->hbuf, clen);
100 T0_PUSH(addr + clen);
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 } ;
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;
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;
130 \ Extensions with specific processing.
131 OID: basicConstraints 2.5.29.19
133 \ Process a Basic Constraints extension. We want the "CA" flag only.
134 : process-basicConstraints ( lim -- lim )
136 read-tag-or-end dup 0x01 = if
137 read-boolean 1 and addr-isCA set8
144 \ Decode a certificate.
147 \ Initialise state flags.
151 \ An arbitrary limit for the total certificate size.
154 \ Open the outer SEQUENCE.
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
165 0x02 check-tag-primitive
167 2 > if ERR_X509_UNSUPPORTED fail then
172 \ Serial number. We just check that the tag is correct.
173 0x02 check-tag-primitive read-length-skip
175 \ Signature algorithm.
176 read-sequence-open skip-close-elt
179 read-sequence-open skip-close-elt
183 read-date addr-notbefore_seconds set32 addr-notbefore_days set32
184 read-date addr-notafter_seconds set32 addr-notafter_days set32
189 read-sequence-open skip-close-elt
194 \ Algorithm Identifier. Right now we are only interested in the
195 \ OID, since we only support RSA keys.
196 \ TODO: support EC keys
198 read-OID ifnot ERR_X509_UNSUPPORTED fail then
201 rsaEncryption eqOID uf
203 \ Public key itself: the BIT STRING contains bytes
204 \ (no partial byte) and these bytes encode the
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.
212 read-integer { nlen }
213 addr-len-pkey_data swap nlen + swap nlen -
214 read-integer { elen }
217 nlen elen copy-rsa-pkey
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 }
229 dup addr-len-pkey_data rot < if
230 ERR_X509_LIMIT_EXCEEDED fail
233 curve qlen copy-ec-pkey
235 ERR_X509_UNSUPPORTED fail
239 \ This flag will be set to true if the Basic Constraints extension
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
253 check-constructed read-length-open-elt
258 read-tag dup 0x01 = if
262 0x04 check-tag-primitive read-length-open-elt
264 \ Extensions with specific processing.
265 basicConstraints eqOID uf
266 process-basicConstraints
276 -1 = ifnot ERR_X509_UNEXPECTED fail then
282 \ signature algorithm
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
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
303 addr-signer_key_type set8
304 addr-signer_hash_id set8
306 \ read-sequence-open skip-close-elt
309 read-bits-open skip-close-elt
311 \ Close the outer SEQUENCE.
315 \ Mark the decoding as successful.
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