]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bearssl/src/x509/x509_minimal.t0
zfs: merge openzfs/zfs@dbda45160
[FreeBSD/FreeBSD.git] / contrib / bearssl / src / x509 / x509_minimal.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 /*
28  * Implementation Notes
29  * --------------------
30  *
31  * The C code pushes the data by chunks; all decoding is done in the
32  * T0 code. The cert_length value is set to the certificate length when
33  * a new certificate is started; the T0 code picks it up as outer limit,
34  * and decoding functions use it to ensure that no attempt is made at
35  * reading past it. The T0 code also checks that once the certificate is
36  * decoded, there are no trailing bytes.
37  *
38  * The T0 code sets cert_length to 0 when the certificate is fully
39  * decoded.
40  *
41  * The C code must still perform two checks:
42  *
43  *  -- If the certificate length is 0, then the T0 code will not be
44  *  invoked at all. This invalid condition must thus be reported by the
45  *  C code.
46  *
47  *  -- When reaching the end of certificate, the C code must verify that
48  *  the certificate length has been set to 0, thereby signaling that
49  *  the T0 code properly decoded a certificate.
50  *
51  * Processing of a chain works in the following way:
52  *
53  *  -- The error flag is set to a non-zero value when validation is
54  *  finished. The value is either BR_ERR_X509_OK (validation is
55  *  successful) or another non-zero error code. When a non-zero error
56  *  code is obtained, the remaining bytes in the current certificate and
57  *  the subsequent certificates (if any) are completely ignored.
58  *
59  *  -- Each certificate is decoded in due course, with the following
60  *  "interesting points":
61  *
62  *     -- Start of the TBS: the multihash engine is reset and activated.
63  *
64  *     -- Start of the issuer DN: the secondary hash engine is started,
65  *     to process the encoded issuer DN.
66  *
67  *     -- End of the issuer DN: the secondary hash engine is stopped. The
68  *     resulting hash value is computed and then copied into the
69  *     next_dn_hash[] buffer.
70  *
71  *     -- Start of the subject DN: the secondary hash engine is started,
72  *     to process the encoded subject DN.
73  *
74  *     -- For the EE certificate only: the Common Name, if any, is matched
75  *     against the expected server name.
76  *
77  *     -- End of the subject DN: the secondary hash engine is stopped. The
78  *     resulting hash value is computed into the pad. It is then processed:
79  *
80  *        -- If this is the EE certificate, then the hash is ignored
81  *        (except for direct trust processing, see later; the hash is
82  *        simply left in current_dn_hash[]).
83  *
84  *        -- Otherwise, the hashed subject DN is compared with the saved
85  *        hash value (in saved_dn_hash[]). They must match.
86  *
87  *     Either way, the next_dn_hash[] value is then copied into the
88  *     saved_dn_hash[] value. Thus, at that point, saved_dn_hash[]
89  *     contains the hash of the issuer DN for the current certificate,
90  *     and current_dn_hash[] contains the hash of the subject DN for the
91  *     current certificate.
92  *
93  *     -- Public key: it is decoded into the cert_pkey[] buffer. Unknown
94  *     key types are reported at that point.
95  *
96  *        -- If this is the EE certificate, then the key type is compared
97  *        with the expected key type (initialization parameter). The public
98  *        key data is copied to ee_pkey_data[]. The key and hashed subject
99  *        DN are also compared with the "direct trust" keys; if the key
100  *        and DN are matched, then validation ends with a success.
101  *
102  *        -- Otherwise, the saved signature (cert_sig[]) is verified
103  *        against the saved TBS hash (tbs_hash[]) and that freshly
104  *        decoded public key. Failure here ends validation with an error.
105  *
106  *     -- Extensions: extension values are processed in due order.
107  *
108  *        -- Basic Constraints: for all certificates except EE, must be
109  *        present, indicate a CA, and have a path length compatible with
110  *        the chain length so far.
111  *
112  *        -- Key Usage: for the EE, if present, must allow signatures
113  *        or encryption/key exchange, as required for the cipher suite.
114  *        For non-EE, if present, must have the "certificate sign" bit.
115  *
116  *        -- Subject Alt Name: for the EE, dNSName names are matched
117  *        against the server name. Ignored for non-EE.
118  *
119  *        -- Authority Key Identifier, Subject Key Identifier, Issuer
120  *        Alt Name, Subject Directory Attributes, CRL Distribution Points
121  *        Freshest CRL, Authority Info Access and Subject Info Access
122  *        extensions are always ignored: they either contain only
123  *        informative data, or they relate to revocation processing, which
124  *        we explicitly do not support.
125  *
126  *        -- All other extensions are ignored if non-critical. If a
127  *        critical extension other than the ones above is encountered,
128  *        then a failure is reported.
129  *
130  *     -- End of the TBS: the multihash engine is stopped.
131  *
132  *     -- Signature algorithm: the signature algorithm on the
133  *     certificate is decoded. A failure is reported if that algorithm
134  *     is unknown. The hashed TBS corresponding to the signature hash
135  *     function is computed and stored in tbs_hash[] (if not supported,
136  *     then a failure is reported). The hash OID and length are stored
137  *     in cert_sig_hash_oid and cert_sig_hash_len.
138  *
139  *     -- Signature value: the signature value is copied into the
140  *     cert_sig[] array.
141  *
142  *     -- Certificate end: the hashed issuer DN (saved_dn_hash[]) is
143  *     looked up in the trust store (CA trust anchors only); for all
144  *     that match, the signature (cert_sig[]) is verified against the
145  *     anchor public key (hashed TBS is in tbs_hash[]). If one of these
146  *     signatures is valid, then validation ends with a success.
147  *
148  *  -- If the chain end is reached without obtaining a validation success,
149  *  then validation is reported as failed.
150  */
151
152 #if BR_USE_UNIX_TIME
153 #include <time.h>
154 #endif
155
156 #if BR_USE_WIN32_TIME
157 #include <windows.h>
158 #endif
159
160 /*
161  * The T0 compiler will produce these prototypes declarations in the
162  * header.
163  *
164 void br_x509_minimal_init_main(void *ctx);
165 void br_x509_minimal_run(void *ctx);
166  */
167
168 /* see bearssl_x509.h */
169 void
170 br_x509_minimal_init(br_x509_minimal_context *ctx,
171         const br_hash_class *dn_hash_impl,
172         const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num)
173 {
174         memset(ctx, 0, sizeof *ctx);
175         ctx->vtable = &br_x509_minimal_vtable;
176         ctx->dn_hash_impl = dn_hash_impl;
177         ctx->trust_anchors = trust_anchors;
178         ctx->trust_anchors_num = trust_anchors_num;
179 }
180
181 static void
182 xm_start_chain(const br_x509_class **ctx, const char *server_name)
183 {
184         br_x509_minimal_context *cc;
185         size_t u;
186
187         cc = (br_x509_minimal_context *)(void *)ctx;
188         for (u = 0; u < cc->num_name_elts; u ++) {
189                 cc->name_elts[u].status = 0;
190                 cc->name_elts[u].buf[0] = 0;
191         }
192         memset(&cc->pkey, 0, sizeof cc->pkey);
193         cc->num_certs = 0;
194         cc->err = 0;
195         cc->cpu.dp = cc->dp_stack;
196         cc->cpu.rp = cc->rp_stack;
197         br_x509_minimal_init_main(&cc->cpu);
198         if (server_name == NULL || *server_name == 0) {
199                 cc->server_name = NULL;
200         } else {
201                 cc->server_name = server_name;
202         }
203 }
204
205 static void
206 xm_start_cert(const br_x509_class **ctx, uint32_t length)
207 {
208         br_x509_minimal_context *cc;
209
210         cc = (br_x509_minimal_context *)(void *)ctx;
211         if (cc->err != 0) {
212                 return;
213         }
214         if (length == 0) {
215                 cc->err = BR_ERR_X509_TRUNCATED;
216                 return;
217         }
218         cc->cert_length = length;
219 }
220
221 static void
222 xm_append(const br_x509_class **ctx, const unsigned char *buf, size_t len)
223 {
224         br_x509_minimal_context *cc;
225
226         cc = (br_x509_minimal_context *)(void *)ctx;
227         if (cc->err != 0) {
228                 return;
229         }
230         cc->hbuf = buf;
231         cc->hlen = len;
232         br_x509_minimal_run(&cc->cpu);
233 }
234
235 static void
236 xm_end_cert(const br_x509_class **ctx)
237 {
238         br_x509_minimal_context *cc;
239
240         cc = (br_x509_minimal_context *)(void *)ctx;
241         if (cc->err == 0 && cc->cert_length != 0) {
242                 cc->err = BR_ERR_X509_TRUNCATED;
243         }
244         cc->num_certs ++;
245 }
246
247 static unsigned
248 xm_end_chain(const br_x509_class **ctx)
249 {
250         br_x509_minimal_context *cc;
251
252         cc = (br_x509_minimal_context *)(void *)ctx;
253         if (cc->err == 0) {
254                 if (cc->num_certs == 0) {
255                         cc->err = BR_ERR_X509_EMPTY_CHAIN;
256                 } else {
257                         cc->err = BR_ERR_X509_NOT_TRUSTED;
258                 }
259         } else if (cc->err == BR_ERR_X509_OK) {
260                 return 0;
261         }
262         return (unsigned)cc->err;
263 }
264
265 static const br_x509_pkey *
266 xm_get_pkey(const br_x509_class *const *ctx, unsigned *usages)
267 {
268         br_x509_minimal_context *cc;
269
270         cc = (br_x509_minimal_context *)(void *)ctx;
271         if (cc->err == BR_ERR_X509_OK
272                 || cc->err == BR_ERR_X509_NOT_TRUSTED)
273         {
274                 if (usages != NULL) {
275                         *usages = cc->key_usages;
276                 }
277                 return &((br_x509_minimal_context *)(void *)ctx)->pkey;
278         } else {
279                 return NULL;
280         }
281 }
282
283 /* see bearssl_x509.h */
284 const br_x509_class br_x509_minimal_vtable = {
285         sizeof(br_x509_minimal_context),
286         xm_start_chain,
287         xm_start_cert,
288         xm_append,
289         xm_end_cert,
290         xm_end_chain,
291         xm_get_pkey
292 };
293
294 #define CTX   ((br_x509_minimal_context *)(void *)((unsigned char *)t0ctx - offsetof(br_x509_minimal_context, cpu)))
295 #define CONTEXT_NAME   br_x509_minimal_context
296
297 #define DNHASH_LEN   ((CTX->dn_hash_impl->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK)
298
299 /*
300  * Hash a DN (from a trust anchor) into the provided buffer. This uses the
301  * DN hash implementation and context structure from the X.509 engine
302  * context.
303  */
304 static void
305 hash_dn(br_x509_minimal_context *ctx, const void *dn, size_t len,
306         unsigned char *out)
307 {
308         ctx->dn_hash_impl->init(&ctx->dn_hash.vtable);
309         ctx->dn_hash_impl->update(&ctx->dn_hash.vtable, dn, len);
310         ctx->dn_hash_impl->out(&ctx->dn_hash.vtable, out);
311 }
312
313 /*
314  * Compare two big integers for equality. The integers use unsigned big-endian
315  * encoding; extra leading bytes (of value 0) are allowed.
316  */
317 static int
318 eqbigint(const unsigned char *b1, size_t len1,
319         const unsigned char *b2, size_t len2)
320 {
321         while (len1 > 0 && *b1 == 0) {
322                 b1 ++;
323                 len1 --;
324         }
325         while (len2 > 0 && *b2 == 0) {
326                 b2 ++;
327                 len2 --;
328         }
329         if (len1 != len2) {
330                 return 0;
331         }
332         return memcmp(b1, b2, len1) == 0;
333 }
334
335 /*
336  * Compare two strings for equality, in a case-insensitive way. This
337  * function handles casing only for ASCII letters.
338  */
339 static int
340 eqnocase(const void *s1, const void *s2, size_t len)
341 {
342         const unsigned char *buf1, *buf2;
343
344         buf1 = s1;
345         buf2 = s2;
346         while (len -- > 0) {
347                 int x1, x2;
348
349                 x1 = *buf1 ++;
350                 x2 = *buf2 ++;
351                 if (x1 >= 'A' && x1 <= 'Z') {
352                         x1 += 'a' - 'A';
353                 }
354                 if (x2 >= 'A' && x2 <= 'Z') {
355                         x2 += 'a' - 'A';
356                 }
357                 if (x1 != x2) {
358                         return 0;
359                 }
360         }
361         return 1;
362 }
363
364 static int verify_signature(br_x509_minimal_context *ctx,
365         const br_x509_pkey *pk);
366
367 }
368
369 postamble {
370
371 /*
372  * Verify the signature on the certificate with the provided public key.
373  * This function checks the public key type with regards to the expected
374  * type. Returned value is either 0 on success, or a non-zero error code.
375  */
376 static int
377 verify_signature(br_x509_minimal_context *ctx, const br_x509_pkey *pk)
378 {
379         int kt;
380
381         kt = ctx->cert_signer_key_type;
382         if ((pk->key_type & 0x0F) != kt) {
383                 return BR_ERR_X509_WRONG_KEY_TYPE;
384         }
385         switch (kt) {
386                 unsigned char tmp[64];
387
388         case BR_KEYTYPE_RSA:
389                 if (ctx->irsa == 0) {
390                         return BR_ERR_X509_UNSUPPORTED;
391                 }
392                 if (!ctx->irsa(ctx->cert_sig, ctx->cert_sig_len,
393                         &t0_datablock[ctx->cert_sig_hash_oid],
394                         ctx->cert_sig_hash_len, &pk->key.rsa, tmp))
395                 {
396                         return BR_ERR_X509_BAD_SIGNATURE;
397                 }
398                 if (memcmp(ctx->tbs_hash, tmp, ctx->cert_sig_hash_len) != 0) {
399                         return BR_ERR_X509_BAD_SIGNATURE;
400                 }
401                 return 0;
402
403         case BR_KEYTYPE_EC:
404                 if (ctx->iecdsa == 0) {
405                         return BR_ERR_X509_UNSUPPORTED;
406                 }
407                 if (!ctx->iecdsa(ctx->iec, ctx->tbs_hash,
408                         ctx->cert_sig_hash_len, &pk->key.ec,
409                         ctx->cert_sig, ctx->cert_sig_len))
410                 {
411                         return BR_ERR_X509_BAD_SIGNATURE;
412                 }
413                 return 0;
414
415         default:
416                 return BR_ERR_X509_UNSUPPORTED;
417         }
418 }
419
420 }
421
422 cc: read8-low ( -- x ) {
423         if (CTX->hlen == 0) {
424                 T0_PUSHi(-1);
425         } else {
426                 unsigned char x = *CTX->hbuf ++;
427                 if (CTX->do_mhash) {
428                         br_multihash_update(&CTX->mhash, &x, 1);
429                 }
430                 if (CTX->do_dn_hash) {
431                         CTX->dn_hash_impl->update(&CTX->dn_hash.vtable, &x, 1);
432                 }
433                 CTX->hlen --;
434                 T0_PUSH(x);
435         }
436 }
437
438 addr: cert_length
439 addr: num_certs
440
441 cc: read-blob-inner ( addr len -- addr len ) {
442         uint32_t len = T0_POP();
443         uint32_t addr = T0_POP();
444         size_t clen = CTX->hlen;
445         if (clen > len) {
446                 clen = (size_t)len;
447         }
448         if (addr != 0) {
449                 memcpy((unsigned char *)CTX + addr, CTX->hbuf, clen);
450         }
451         if (CTX->do_mhash) {
452                 br_multihash_update(&CTX->mhash, CTX->hbuf, clen);
453         }
454         if (CTX->do_dn_hash) {
455                 CTX->dn_hash_impl->update(
456                         &CTX->dn_hash.vtable, CTX->hbuf, clen);
457         }
458         CTX->hbuf += clen;
459         CTX->hlen -= clen;
460         T0_PUSH(addr + clen);
461         T0_PUSH(len - clen);
462 }
463
464 \ Compute the TBS hash, using the provided hash ID. The hash value is
465 \ written in the tbs_hash[] array, and the hash length is returned. If
466 \ the requested hash function is not supported, then 0 is returned.
467 cc: compute-tbs-hash ( id -- hashlen ) {
468         int id = T0_POPi();
469         size_t len;
470         len = br_multihash_out(&CTX->mhash, id, CTX->tbs_hash);
471         T0_PUSH(len);
472 }
473
474 \ Push true (-1) if no server name is expected in the EE certificate.
475 cc: zero-server-name ( -- bool ) {
476         T0_PUSHi(-(CTX->server_name == NULL));
477 }
478
479 addr: key_usages
480 addr: cert_sig
481 addr: cert_sig_len
482 addr: cert_signer_key_type
483 addr: cert_sig_hash_oid
484 addr: cert_sig_hash_len
485 addr: tbs_hash
486 addr: min_rsa_size
487
488 \ Start TBS hash computation. The hash functions are reinitialised.
489 cc: start-tbs-hash ( -- ) {
490         br_multihash_init(&CTX->mhash);
491         CTX->do_mhash = 1;
492 }
493
494 \ Stop TBS hash computation.
495 cc: stop-tbs-hash ( -- ) {
496         CTX->do_mhash = 0;
497 }
498
499 \ Start DN hash computation.
500 cc: start-dn-hash ( -- ) {
501         CTX->dn_hash_impl->init(&CTX->dn_hash.vtable);
502         CTX->do_dn_hash = 1;
503 }
504
505 \ Terminate DN hash computation and write the DN hash into the
506 \ current_dn_hash buffer.
507 cc: compute-dn-hash ( -- ) {
508         CTX->dn_hash_impl->out(&CTX->dn_hash.vtable, CTX->current_dn_hash);
509         CTX->do_dn_hash = 0;
510 }
511
512 \ Get the length of hash values obtained with the DN hasher.
513 cc: dn-hash-length ( -- len ) {
514         T0_PUSH(DNHASH_LEN);
515 }
516
517 \ Copy data between two areas in the context.
518 cc: blobcopy ( addr-dst addr-src len -- ) {
519         size_t len = T0_POP();
520         unsigned char *src = (unsigned char *)CTX + T0_POP();
521         unsigned char *dst = (unsigned char *)CTX + T0_POP();
522         memcpy(dst, src, len);
523 }
524
525 addr: current_dn_hash
526 addr: next_dn_hash
527 addr: saved_dn_hash
528
529 \ Read a DN, hashing it into current_dn_hash. The DN contents are not
530 \ inspected (only the outer tag, for SEQUENCE, is checked).
531 : read-DN ( lim -- lim )
532         start-dn-hash
533         read-sequence-open skip-close-elt
534         compute-dn-hash ;
535
536 cc: offset-name-element ( san -- n ) {
537         unsigned san = T0_POP();
538         size_t u;
539
540         for (u = 0; u < CTX->num_name_elts; u ++) {
541                 if (CTX->name_elts[u].status == 0) {
542                         const unsigned char *oid;
543                         size_t len, off;
544
545                         oid = CTX->name_elts[u].oid;
546                         if (san) {
547                                 if (oid[0] != 0 || oid[1] != 0) {
548                                         continue;
549                                 }
550                                 off = 2;
551                         } else {
552                                 off = 0;
553                         }
554                         len = oid[off];
555                         if (len != 0 && len == CTX->pad[0]
556                                 && memcmp(oid + off + 1,
557                                         CTX->pad + 1, len) == 0)
558                         {
559                                 T0_PUSH(u);
560                                 T0_RET();
561                         }
562                 }
563         }
564         T0_PUSHi(-1);
565 }
566
567 cc: copy-name-element ( bool offbuf -- ) {
568         size_t len;
569         int32_t off = T0_POPi();
570         int ok = T0_POPi();
571
572         if (off >= 0) {
573                 br_name_element *ne = &CTX->name_elts[off];
574
575                 if (ok) {
576                         len = CTX->pad[0];
577                         if (len < ne->len) {
578                                 memcpy(ne->buf, CTX->pad + 1, len);
579                                 ne->buf[len] = 0;
580                                 ne->status = 1;
581                         } else {
582                                 ne->status = -1;
583                         }
584                 } else {
585                         ne->status = -1;
586                 }
587         }
588 }
589
590 cc: copy-name-SAN ( bool tag -- ) {
591         unsigned tag = T0_POP();
592         unsigned ok = T0_POP();
593         size_t u, len;
594
595         len = CTX->pad[0];
596         for (u = 0; u < CTX->num_name_elts; u ++) {
597                 br_name_element *ne;
598
599                 ne = &CTX->name_elts[u];
600                 if (ne->status == 0 && ne->oid[0] == 0 && ne->oid[1] == tag) {
601                         if (ok && ne->len > len) {
602                                 memcpy(ne->buf, CTX->pad + 1, len);
603                                 ne->buf[len] = 0;
604                                 ne->status = 1;
605                         } else {
606                                 ne->status = -1;
607                         }
608                         break;
609                 }
610         }
611 }
612
613 \ Read a value, decoding string types. If the string type is recognised
614 \ and the value could be converted to UTF-8 into the pad, then true (-1)
615 \ is returned; in all other cases, false (0) is returned. Either way, the
616 \ object is consumed.
617 : read-string ( lim -- lim bool )
618         read-tag case
619                 \ UTF8String
620                 12 of check-primitive read-value-UTF8 endof
621                 \ NumericString
622                 18 of check-primitive read-value-latin1 endof
623                 \ PrintableString
624                 19 of check-primitive read-value-latin1 endof
625                 \ TeletexString
626                 20 of check-primitive read-value-latin1 endof
627                 \ IA5String
628                 22 of check-primitive read-value-latin1 endof
629                 \ BMPString
630                 30 of check-primitive read-value-UTF16 endof
631                 2drop read-length-skip 0 0
632         endcase ;
633
634 \ Read a DN for the EE. The normalized DN hash is computed and stored in the
635 \ current_dn_hash.
636 \ Name elements are gathered. Also, the Common Name is matched against the
637 \ intended server name.
638 \ Returned value is true (-1) if the CN matches the intended server name,
639 \ false (0) otherwise.
640 : read-DN-EE ( lim -- lim bool )
641         \ Flag will be set to true if there is a CN and it matches the
642         \ intended server name.
643         0 { eename-matches }
644
645         \ Activate DN hashing.
646         start-dn-hash
647
648         \ Parse the DN structure: it is a SEQUENCE of SET of
649         \ AttributeTypeAndValue. Each AttributeTypeAndValue is a
650         \ SEQUENCE { OBJECT IDENTIFIER, ANY }.
651         read-sequence-open
652         begin
653                 dup while
654
655                 read-tag 0x11 check-tag-constructed read-length-open-elt
656                 dup ifnot ERR_X509_BAD_DN fail then
657                 begin
658                         dup while
659
660                         read-sequence-open
661
662                         \ Read the OID. If the OID could not be read (too
663                         \ long) then the first pad byte will be 0.
664                         read-OID drop
665
666                         \ If it is the Common Name then we'll need to
667                         \ match it against the intended server name (if
668                         \ applicable).
669                         id-at-commonName eqOID { isCN }
670
671                         \ Get offset for reception buffer for that element
672                         \ (or -1).
673                         0 offset-name-element { offbuf }
674
675                         \ Try to read the value as a string.
676                         read-string
677
678                         \ If the value could be decoded as a string,
679                         \ copy it and/or match it, as appropriate.
680                         dup isCN and if
681                                 match-server-name if
682                                         -1 >eename-matches
683                                 then
684                         then
685                         offbuf copy-name-element
686
687                         \ Close the SEQUENCE
688                         close-elt
689
690                 repeat
691                 close-elt
692         repeat
693         close-elt
694
695         \ Compute DN hash and deactivate DN hashing.
696         compute-dn-hash
697
698         \ Return the CN match flag.
699         eename-matches ;
700
701 \ Check the provided validity range against the current (or configured)
702 \ date and time ("na" = notAfter, "nb = notBefore). Returned value:
703 \   -1   current date/time is before the notBefore date
704 \    0   current date/time is within the allowed range
705 \   +1   current date/time is after the notAfter range
706 \ If the current date/time is not available, then this function triggers a
707 \ failure and does not return.
708 cc: check-validity-range ( na-days na-seconds nb-days nb-seconds -- int ) {
709         uint32_t nbs = T0_POP();
710         uint32_t nbd = T0_POP();
711         uint32_t nas = T0_POP();
712         uint32_t nad = T0_POP();
713         int r;
714         if (CTX->itime != 0) {
715                 r = CTX->itime(CTX->itime_ctx, nbd, nbs, nad, nas);
716                 if (r < -1 || r > 1) {
717                         CTX->err = BR_ERR_X509_TIME_UNKNOWN;
718                         T0_CO();
719                 }
720         } else {
721                 uint32_t vd = CTX->days;
722                 uint32_t vs = CTX->seconds;
723                 if (vd == 0 && vs == 0) {
724 #if BR_USE_UNIX_TIME
725                         time_t x = time(NULL);
726
727                         vd = (uint32_t)(x / 86400) + 719528;
728                         vs = (uint32_t)(x % 86400);
729 #elif BR_USE_WIN32_TIME
730                         FILETIME ft;
731                         uint64_t x;
732
733                         GetSystemTimeAsFileTime(&ft);
734                         x = ((uint64_t)ft.dwHighDateTime << 32)
735                                 + (uint64_t)ft.dwLowDateTime;
736                         x = (x / 10000000);
737                         vd = (uint32_t)(x / 86400) + 584754;
738                         vs = (uint32_t)(x % 86400);
739 #else
740                         CTX->err = BR_ERR_X509_TIME_UNKNOWN;
741                         T0_CO();
742 #endif
743                 }
744                 if (vd < nbd || (vd == nbd && vs < nbs)) {
745                         r = -1;
746                 } else if (vd > nad || (vd == nad && vs > nas)) {
747                         r = 1;
748                 } else {
749                         r = 0;
750                 }
751         }
752         T0_PUSHi(r);
753 }
754
755 \ Swap the top two elements with the two elements immediately below.
756 : swap2 ( a b c d -- c d a b )
757         3 roll 3 roll ;
758
759 \ Match the name in the pad with the expected server name. Returned value
760 \ is true (-1) on match, false (0) otherwise. If there is no expected
761 \ server name, then 0 is returned.
762 \ Match conditions: either an exact match (case insensitive), or a
763 \ wildcard match, if the found name starts with "*.". We only match a
764 \ starting wildcard, and only against a complete DN name component.
765 cc: match-server-name ( -- bool ) {
766         size_t n1, n2;
767
768         if (CTX->server_name == NULL) {
769                 T0_PUSH(0);
770                 T0_RET();
771         }
772         n1 = strlen(CTX->server_name);
773         n2 = CTX->pad[0];
774         if (n1 == n2 && eqnocase(&CTX->pad[1], CTX->server_name, n1)) {
775                 T0_PUSHi(-1);
776                 T0_RET();
777         }
778         if (n2 >= 2 && CTX->pad[1] == '*' && CTX->pad[2] == '.') {
779                 size_t u;
780
781                 u = 0;
782                 while (u < n1 && CTX->server_name[u] != '.') {
783                         u ++;
784                 }
785                 u ++;
786                 n1 -= u;
787                 if ((n2 - 2) == n1
788                         && eqnocase(&CTX->pad[3], CTX->server_name + u, n1))
789                 {
790                         T0_PUSHi(-1);
791                         T0_RET();
792                 }
793         }
794         T0_PUSH(0);
795 }
796
797 \ Get the address and length for the pkey_data buffer.
798 : addr-len-pkey_data ( -- addr len )
799         CX 0 8191 { offsetof(br_x509_minimal_context, pkey_data) }
800         CX 0 8191 { BR_X509_BUFSIZE_KEY } ;
801
802 \ Copy the EE public key to the permanent buffer (RSA).
803 cc: copy-ee-rsa-pkey ( nlen elen -- ) {
804         size_t elen = T0_POP();
805         size_t nlen = T0_POP();
806         memcpy(CTX->ee_pkey_data, CTX->pkey_data, nlen + elen);
807         CTX->pkey.key_type = BR_KEYTYPE_RSA;
808         CTX->pkey.key.rsa.n = CTX->ee_pkey_data;
809         CTX->pkey.key.rsa.nlen = nlen;
810         CTX->pkey.key.rsa.e = CTX->ee_pkey_data + nlen;
811         CTX->pkey.key.rsa.elen = elen;
812 }
813
814 \ Copy the EE public key to the permanent buffer (EC).
815 cc: copy-ee-ec-pkey ( curve qlen -- ) {
816         size_t qlen = T0_POP();
817         uint32_t curve = T0_POP();
818         memcpy(CTX->ee_pkey_data, CTX->pkey_data, qlen);
819         CTX->pkey.key_type = BR_KEYTYPE_EC;
820         CTX->pkey.key.ec.curve = curve;
821         CTX->pkey.key.ec.q = CTX->ee_pkey_data;
822         CTX->pkey.key.ec.qlen = qlen;
823 }
824
825 \ Check whether the current certificate (EE) is directly trusted.
826 cc: check-direct-trust ( -- ) {
827         size_t u;
828
829         for (u = 0; u < CTX->trust_anchors_num; u ++) {
830                 const br_x509_trust_anchor *ta;
831                 unsigned char hashed_DN[64];
832                 int kt;
833
834                 ta = &CTX->trust_anchors[u];
835                 if (ta->flags & BR_X509_TA_CA) {
836                         continue;
837                 }
838                 hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN);
839                 if (memcmp(hashed_DN, CTX->current_dn_hash, DNHASH_LEN)) {
840                         continue;
841                 }
842                 kt = CTX->pkey.key_type;
843                 if ((ta->pkey.key_type & 0x0F) != kt) {
844                         continue;
845                 }
846                 switch (kt) {
847
848                 case BR_KEYTYPE_RSA:
849                         if (!eqbigint(CTX->pkey.key.rsa.n,
850                                 CTX->pkey.key.rsa.nlen,
851                                 ta->pkey.key.rsa.n,
852                                 ta->pkey.key.rsa.nlen)
853                                 || !eqbigint(CTX->pkey.key.rsa.e,
854                                 CTX->pkey.key.rsa.elen,
855                                 ta->pkey.key.rsa.e,
856                                 ta->pkey.key.rsa.elen))
857                         {
858                                 continue;
859                         }
860                         break;
861
862                 case BR_KEYTYPE_EC:
863                         if (CTX->pkey.key.ec.curve != ta->pkey.key.ec.curve
864                                 || CTX->pkey.key.ec.qlen != ta->pkey.key.ec.qlen
865                                 || memcmp(CTX->pkey.key.ec.q,
866                                         ta->pkey.key.ec.q,
867                                         ta->pkey.key.ec.qlen) != 0)
868                         {
869                                 continue;
870                         }
871                         break;
872
873                 default:
874                         continue;
875                 }
876
877                 /*
878                  * Direct trust match!
879                  */
880                 CTX->err = BR_ERR_X509_OK;
881                 T0_CO();
882         }
883 }
884
885 \ Check the signature on the certificate with regards to all trusted CA.
886 \ We use the issuer hash (in saved_dn_hash[]) as CA identifier.
887 cc: check-trust-anchor-CA ( -- ) {
888         size_t u;
889
890         for (u = 0; u < CTX->trust_anchors_num; u ++) {
891                 const br_x509_trust_anchor *ta;
892                 unsigned char hashed_DN[64];
893
894                 ta = &CTX->trust_anchors[u];
895                 if (!(ta->flags & BR_X509_TA_CA)) {
896                         continue;
897                 }
898                 hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN);
899                 if (memcmp(hashed_DN, CTX->saved_dn_hash, DNHASH_LEN)) {
900                         continue;
901                 }
902                 if (verify_signature(CTX, &ta->pkey) == 0) {
903                         CTX->err = BR_ERR_X509_OK;
904                         T0_CO();
905                 }
906         }
907 }
908
909 \ Verify RSA signature. This uses the public key that was just decoded
910 \ into CTX->pkey_data; the modulus and exponent length are provided as
911 \ parameters. The resulting hash value is compared with the one in
912 \ tbs_hash. Returned value is 0 on success, or a non-zero error code.
913 cc: do-rsa-vrfy ( nlen elen -- err ) {
914         size_t elen = T0_POP();
915         size_t nlen = T0_POP();
916         br_x509_pkey pk;
917
918         pk.key_type = BR_KEYTYPE_RSA;
919         pk.key.rsa.n = CTX->pkey_data;
920         pk.key.rsa.nlen = nlen;
921         pk.key.rsa.e = CTX->pkey_data + nlen;
922         pk.key.rsa.elen = elen;
923         T0_PUSH(verify_signature(CTX, &pk));
924 }
925
926 \ Verify ECDSA signature. This uses the public key that was just decoded
927 \ into CTX->pkey_dayta; the curve ID and public point length are provided
928 \ as parameters. The hash value in tbs_hash is used. Returned value is 0
929 \ on success, or non-zero error code.
930 cc: do-ecdsa-vrfy ( curve qlen -- err ) {
931         size_t qlen = T0_POP();
932         int curve = T0_POP();
933         br_x509_pkey pk;
934
935         pk.key_type = BR_KEYTYPE_EC;
936         pk.key.ec.curve = curve;
937         pk.key.ec.q = CTX->pkey_data;
938         pk.key.ec.qlen = qlen;
939         T0_PUSH(verify_signature(CTX, &pk));
940 }
941
942 cc: print-bytes ( addr len -- ) {
943         extern int printf(const char *fmt, ...);
944         size_t len = T0_POP();
945         unsigned char *buf = (unsigned char *)CTX + T0_POP();
946         size_t u;
947
948         for (u = 0; u < len; u ++) {
949                 printf("%02X", buf[u]);
950         }
951 }
952
953 cc: printOID ( -- ) {
954         extern int printf(const char *fmt, ...);
955         size_t u, len;
956
957         len = CTX->pad[0];
958         if (len == 0) {
959                 printf("*");
960                 T0_RET();
961         }
962         printf("%u.%u", CTX->pad[1] / 40, CTX->pad[1] % 40);
963         u = 2;
964         while (u <= len) {
965                 unsigned long ul;
966
967                 ul = 0;
968                 for (;;) {
969                         int x;
970
971                         if (u > len) {
972                                 printf("BAD");
973                                 T0_RET();
974                         }
975                         x = CTX->pad[u ++];
976                         ul = (ul << 7) + (x & 0x7F);
977                         if (!(x & 0x80)) {
978                                 break;
979                         }
980                 }
981                 printf(".%lu", ul);
982         }
983 }
984
985 \ Extensions with specific processing.
986 OID: basicConstraints      2.5.29.19
987 OID: keyUsage              2.5.29.15
988 OID: subjectAltName        2.5.29.17
989 OID: certificatePolicies   2.5.29.32
990
991 \ Policy qualifier "pointer to CPS"
992 OID: id-qt-cps             1.3.6.1.5.5.7.2.1
993
994 \ Extensions which are ignored when encountered, even if critical.
995 OID: authorityKeyIdentifier        2.5.29.35
996 OID: subjectKeyIdentifier          2.5.29.14
997 OID: issuerAltName                 2.5.29.18
998 OID: subjectDirectoryAttributes    2.5.29.9
999 OID: crlDistributionPoints         2.5.29.31
1000 OID: freshestCRL                   2.5.29.46
1001 OID: authorityInfoAccess           1.3.6.1.5.5.7.1.1
1002 OID: subjectInfoAccess             1.3.6.1.5.5.7.1.11
1003
1004 \ Process a Basic Constraints extension. This should be called only if
1005 \ the certificate is not the EE. We check that the extension contains
1006 \ the "CA" flag, and that the path length, if specified, is compatible
1007 \ with the current chain length.
1008 : process-basicConstraints ( lim -- lim )
1009         read-sequence-open
1010         read-tag-or-end
1011         dup 0x01 = if
1012                 read-boolean ifnot ERR_X509_NOT_CA fail then
1013                 read-tag-or-end
1014         else
1015                 ERR_X509_NOT_CA fail
1016         then
1017         dup 0x02 = if
1018                 drop check-primitive read-small-int-value
1019                 addr-num_certs get32 1- < if ERR_X509_NOT_CA fail then
1020                 read-tag-or-end
1021         then
1022         -1 <> if ERR_X509_UNEXPECTED fail then
1023         drop
1024         close-elt
1025         ;
1026
1027 \ Process a Key Usage extension.
1028 \ For the EE certificate:
1029 \   -- if the key usage contains keyEncipherment (2), dataEncipherment (3)
1030 \      or keyAgreement (4), then the "key exchange" usage is allowed;
1031 \   -- if the key usage contains digitalSignature (0) or nonRepudiation (1),
1032 \      then the "signature" usage is allowed.
1033 \ For CA certificates, the extension must contain keyCertSign (5).
1034 : process-keyUsage ( lim ee -- lim )
1035         { ee }
1036
1037         \ Read tag for the BIT STRING and open it.
1038         read-tag 0x03 check-tag-primitive
1039         read-length-open-elt
1040         \ First byte indicates number of ignored bits in the last byte. It
1041         \ must be between 0 and 7.
1042         read8 { ign }
1043         ign 7 > if ERR_X509_UNEXPECTED fail then
1044         \ Depending on length, we have either 0, 1 or more bytes to read.
1045         dup case
1046                 0 of ERR_X509_FORBIDDEN_KEY_USAGE fail endof
1047                 1 of read8 ign >> ign << endof
1048                 drop read8 0
1049         endcase
1050
1051         \ Check bits.
1052         ee if
1053                 \ EE: get usages.
1054                 0
1055                 over 0x38 and if 0x10 or then
1056                 swap 0xC0 and if 0x20 or then
1057                 addr-key_usages set8
1058         else
1059                 \ Not EE: keyCertSign must be set.
1060                 0x04 and ifnot ERR_X509_FORBIDDEN_KEY_USAGE fail then
1061         then
1062
1063         \ We don't care about subsequent bytes.
1064         skip-close-elt ;
1065
1066 \ Process a Certificate Policies extension.
1067 \
1068 \ Since we don't actually support full policies processing, this function
1069 \ only checks that the extension contents can be safely ignored. Indeed,
1070 \ we don't validate against a specific set of policies (in RFC 5280
1071 \ terminology, user-initial-policy-set only contains the special value
1072 \ any-policy). Moreover, we don't support policy constraints (if a
1073 \ critical Policy Constraints extension is encountered, the validation
1074 \ will fail). Therefore, we can safely ignore the contents of this
1075 \ extension, except if it is critical AND one of the policy OID has a
1076 \ qualifier which is distinct from id-qt-cps (because id-qt-cps is
1077 \ specially designated by RFC 5280 has having no mandated action).
1078 \
1079 \ This function is called only if the extension is critical.
1080 : process-certPolicies ( lim -- lim )
1081         \ Extension value is a SEQUENCE OF PolicyInformation.
1082         read-sequence-open
1083         begin dup while
1084                 \ PolicyInformation ::= SEQUENCE {
1085                 \    policyIdentifier  OBJECT IDENTIFIER,
1086                 \    policyQualifiers  SEQUENCE OF PolicyQualifierInfo OPTIONAL
1087                 \ }
1088                 read-sequence-open
1089                 read-OID drop
1090                 dup if
1091                         read-sequence-open
1092                         begin dup while
1093                                 \ PolicyQualifierInfo ::= SEQUENCE {
1094                                 \    policyQualifierId  OBJECT IDENTIFIER,
1095                                 \    qualifier          ANY
1096                                 \ }
1097                                 read-sequence-open
1098                                 read-OID drop id-qt-cps eqOID ifnot
1099                                         ERR_X509_CRITICAL_EXTENSION fail
1100                                 then
1101                                 skip-close-elt
1102                         repeat
1103                         close-elt
1104                 then
1105                 close-elt
1106         repeat
1107         close-elt ;
1108
1109 \ Process a Subject Alt Name extension. Returned value is a boolean set
1110 \ to true if the expected server name was matched against a dNSName in
1111 \ the extension.
1112 : process-SAN ( lim -- lim bool )
1113         0 { m }
1114         read-sequence-open
1115         begin dup while
1116                 \ Read the tag. If the tag is context-0, then parse an
1117                 \ 'otherName'. If the tag is context-2, then parse a
1118                 \ dNSName. If the tag is context-1 or context-6,
1119                 \ parse 
1120                 read-tag case
1121                         \ OtherName
1122                         0x20 of
1123                                 \ OtherName ::= SEQUENCE {
1124                                 \     type-id   OBJECT IDENTIFIER,
1125                                 \     value     [0] EXPLICIT ANY
1126                                 \ }
1127                                 check-constructed read-length-open-elt
1128                                 read-OID drop
1129                                 -1 offset-name-element { offbuf }
1130                                 read-tag 0x20 check-tag-constructed
1131                                 read-length-open-elt
1132                                 read-string offbuf copy-name-element
1133                                 close-elt
1134                                 close-elt
1135                         endof
1136                         \ rfc822Name (IA5String)
1137                         0x21 of
1138                                 check-primitive
1139                                 read-value-UTF8 1 copy-name-SAN
1140                         endof
1141                         \ dNSName (IA5String)
1142                         0x22 of
1143                                 check-primitive
1144                                 read-value-UTF8
1145                                 dup if match-server-name m or >m then
1146                                 2 copy-name-SAN
1147                         endof
1148                         \ uniformResourceIdentifier (IA5String)
1149                         0x26 of
1150                                 check-primitive
1151                                 read-value-UTF8 6 copy-name-SAN
1152                         endof
1153                         2drop read-length-skip 0
1154                 endcase
1155
1156                 \ We check only names of type dNSName; they use IA5String,
1157                 \ which is basically ASCII.
1158                 \ read-tag 0x22 = if
1159                 \       check-primitive
1160                 \       read-small-value drop
1161                 \       match-server-name m or >m
1162                 \ else
1163                 \       drop read-length-skip
1164                 \ then
1165         repeat
1166         close-elt
1167         m ;
1168
1169 \ Decode a certificate. The "ee" boolean must be true for the EE.
1170 : decode-certificate ( ee -- )
1171         { ee }
1172
1173         \ Obtain the total certificate length.
1174         addr-cert_length get32
1175
1176         \ Open the outer SEQUENCE.
1177         read-sequence-open
1178
1179         \ TBS
1180         \ Activate hashing.
1181         start-tbs-hash
1182         read-sequence-open
1183
1184         \ First element may be an explicit version. We accept only
1185         \ versions 0 to 2 (certificates v1 to v3).
1186         read-tag dup 0x20 = if
1187                 drop check-constructed read-length-open-elt
1188                 read-tag
1189                 0x02 check-tag-primitive
1190                 read-small-int-value
1191                 2 > if ERR_X509_UNSUPPORTED fail then
1192                 close-elt
1193                 read-tag
1194         then
1195
1196         \ Serial number. We just check that the tag is correct.
1197         0x02 check-tag-primitive
1198         read-length-skip
1199
1200         \ Signature algorithm. This structure is redundant with the one
1201         \ on the outside; we just skip it.
1202         read-sequence-open skip-close-elt
1203
1204         \ Issuer name: hashed, then copied into next_dn_hash[].
1205         read-DN
1206         addr-next_dn_hash addr-current_dn_hash dn-hash-length blobcopy
1207
1208         \ Validity dates.
1209         read-sequence-open
1210         read-date { nbd nbs } read-date nbd nbs check-validity-range
1211         if ERR_X509_EXPIRED fail then
1212         close-elt
1213
1214         \ Subject name.
1215         ee if
1216                 \ For the EE, we must check whether the Common Name, if
1217                 \ any, matches the expected server name.
1218                 read-DN-EE { eename }
1219         else
1220                 \ For a non-EE certificate, the hashed subject DN must match
1221                 \ the saved hashed issuer DN from the previous certificate.
1222                 read-DN
1223                 addr-current_dn_hash addr-saved_dn_hash dn-hash-length eqblob
1224                 ifnot ERR_X509_DN_MISMATCH fail then
1225         then
1226         \ Move the hashed issuer DN for this certificate into the
1227         \ saved_dn_hash[] array.
1228         addr-saved_dn_hash addr-next_dn_hash dn-hash-length blobcopy
1229
1230         \ Public Key.
1231         read-sequence-open
1232         \ Algorithm Identifier. Right now we are only interested in the
1233         \ OID, since we only support RSA keys.
1234         read-sequence-open
1235         read-OID ifnot ERR_X509_UNSUPPORTED fail then
1236         { ; pkey-type }
1237         choice
1238                 \ RSA public key.
1239                 rsaEncryption eqOID uf
1240                         skip-close-elt
1241                         \ Public key itself: the BIT STRING contains bytes
1242                         \ (no partial byte) and these bytes encode the
1243                         \ actual value.
1244                         read-bits-open
1245                                 \ RSA public key is a SEQUENCE of two
1246                                 \ INTEGER. We get both INTEGER values into
1247                                 \ the pkey_data[] buffer, if they fit.
1248                                 read-sequence-open
1249                                 addr-len-pkey_data
1250                                 read-integer { nlen }
1251                                 addr-len-pkey_data swap nlen + swap nlen -
1252                                 read-integer { elen }
1253                                 close-elt
1254
1255                                 \ Check that the public key fits our minimal
1256                                 \ size requirements. Note that the integer
1257                                 \ decoder already skipped the leading bytes
1258                                 \ of value 0, so we are working on the true
1259                                 \ modulus length here.
1260                                 addr-min_rsa_size get16 128 + nlen > if
1261                                         ERR_X509_WEAK_PUBLIC_KEY fail
1262                                 then
1263                         close-elt
1264                         KEYTYPE_RSA >pkey-type
1265                 enduf
1266
1267                 \ EC public key.
1268                 id-ecPublicKey eqOID uf
1269                         \ We support only named curves, for which the
1270                         \ "parameters" field in the AlgorithmIdentifier
1271                         \ field should be an OID.
1272                         read-OID ifnot ERR_X509_UNSUPPORTED fail then
1273                         choice
1274                                 ansix9p256r1 eqOID uf 23 enduf
1275                                 ansix9p384r1 eqOID uf 24 enduf
1276                                 ansix9p521r1 eqOID uf 25 enduf
1277                                 ERR_X509_UNSUPPORTED fail
1278                         endchoice
1279                         { curve }
1280                         close-elt
1281                         read-bits-open
1282                         dup { qlen }
1283                         dup addr-len-pkey_data rot < if
1284                                 ERR_X509_LIMIT_EXCEEDED fail
1285                         then
1286                         read-blob
1287                         KEYTYPE_EC >pkey-type
1288                 enduf
1289
1290                 \ Not a recognised public key type.
1291                 ERR_X509_UNSUPPORTED fail
1292         endchoice
1293         close-elt
1294
1295         \ Process public key.
1296         ee if
1297                 \ For the EE certificate, copy the key data to the
1298                 \ relevant buffer.
1299                 pkey-type case
1300                         KEYTYPE_RSA of nlen elen copy-ee-rsa-pkey endof
1301                         KEYTYPE_EC of curve qlen copy-ee-ec-pkey endof
1302                         ERR_X509_UNSUPPORTED fail
1303                 endcase
1304         else
1305                 \ Verify signature on previous certificate. We invoke
1306                 \ the RSA implementation.
1307                 pkey-type case
1308                         KEYTYPE_RSA of nlen elen do-rsa-vrfy endof
1309                         KEYTYPE_EC of curve qlen do-ecdsa-vrfy endof
1310                         ERR_X509_UNSUPPORTED fail
1311                 endcase
1312                 dup if fail then
1313                 drop
1314         then
1315
1316         \ This flag will be set to true if the Basic Constraints extension
1317         \ is encountered.
1318         0 { seenBC }
1319
1320         \ Skip issuerUniqueID and subjectUniqueID, and process extensions
1321         \ if present. Extensions are an explicit context tag of value 3
1322         \ around a SEQUENCE OF extensions. Each extension is a SEQUENCE
1323         \ with an OID, an optional boolean, and a value; the value is
1324         \ an OCTET STRING.
1325         read-tag-or-end
1326         0x21 iftag-skip
1327         0x22 iftag-skip
1328         dup 0x23 = if
1329                 drop
1330                 check-constructed read-length-open-elt
1331                 read-sequence-open
1332                 begin dup while
1333                         0 { critical }
1334                         read-sequence-open
1335                         read-OID drop
1336                         read-tag dup 0x01 = if
1337                                 read-boolean >critical
1338                                 read-tag
1339                         then
1340                         0x04 check-tag-primitive read-length-open-elt
1341                         choice
1342                                 \ Extensions with specific processing.
1343                                 basicConstraints eqOID uf
1344                                         ee if
1345                                                 skip-remaining
1346                                         else
1347                                                 process-basicConstraints
1348                                                 -1 >seenBC
1349                                         then
1350                                 enduf
1351                                 keyUsage         eqOID uf
1352                                         ee process-keyUsage
1353                                 enduf
1354                                 subjectAltName   eqOID uf
1355                                         ee if
1356                                                 0 >eename
1357                                                 process-SAN >eename
1358                                         else
1359                                                 skip-remaining
1360                                         then
1361                                 enduf
1362
1363                                 \ We don't implement full processing of
1364                                 \ policies. The call below mostly checks
1365                                 \ that the contents of the Certificate
1366                                 \ Policies extension can be safely ignored.
1367                                 certificatePolicies eqOID uf
1368                                         critical if
1369                                                 process-certPolicies
1370                                         else
1371                                                 skip-remaining
1372                                         then
1373                                 enduf
1374
1375                                 \ Extensions which are always ignored,
1376                                 \ even if critical.
1377                                 authorityKeyIdentifier     eqOID uf
1378                                         skip-remaining
1379                                 enduf
1380                                 subjectKeyIdentifier       eqOID uf
1381                                         skip-remaining
1382                                 enduf
1383                                 issuerAltName              eqOID uf
1384                                         skip-remaining
1385                                 enduf
1386                                 subjectDirectoryAttributes eqOID uf
1387                                         skip-remaining
1388                                 enduf
1389                                 crlDistributionPoints      eqOID uf
1390                                         skip-remaining
1391                                 enduf
1392                                 freshestCRL                eqOID uf
1393                                         skip-remaining
1394                                 enduf
1395                                 authorityInfoAccess        eqOID uf
1396                                         skip-remaining
1397                                 enduf
1398                                 subjectInfoAccess          eqOID uf
1399                                         skip-remaining
1400                                 enduf
1401
1402                                 \ Unrecognized extensions trigger a failure
1403                                 \ if critical; otherwise, they are just
1404                                 \ ignored.
1405                                 critical if
1406                                         ERR_X509_CRITICAL_EXTENSION fail
1407                                 then
1408                                 skip-remaining
1409                         endchoice
1410                         close-elt
1411                         close-elt
1412                 repeat
1413                 close-elt
1414                 close-elt
1415         else
1416                 -1 = ifnot ERR_X509_UNEXPECTED fail then
1417                 drop
1418         then
1419
1420         close-elt
1421         \ Terminate hashing.
1422         stop-tbs-hash
1423
1424         \ For the EE certificate, verify that the intended server name
1425         \ was matched.
1426         ee if
1427                 eename zero-server-name or ifnot
1428                         ERR_X509_BAD_SERVER_NAME fail
1429                 then
1430         then
1431
1432         \ If this is the EE certificate, then direct trust may apply.
1433         \ Note: we do this at this point, not immediately after decoding
1434         \ the public key, because even in case of direct trust we still
1435         \ want to check the server name with regards to the SAN extension.
1436         \ However, we want to check direct trust before trying to decode
1437         \ the signature algorithm, because it should work even if that
1438         \ algorithm is not supported.
1439         ee if check-direct-trust then
1440
1441         \ Non-EE certificates MUST have a Basic Constraints extension
1442         \ (that marks them as being CA).
1443         ee seenBC or ifnot ERR_X509_NOT_CA fail then
1444
1445         \ signature algorithm
1446         read-tag check-sequence read-length-open-elt
1447         \ Read and understand the OID. Right now, we support only
1448         \ RSA with PKCS#1 v1.5 padding, and hash functions SHA-1,
1449         \ SHA-224, SHA-256, SHA-384 and SHA-512. We purposely do NOT
1450         \ support MD5 here.
1451         \ TODO: add support for RSA/PSS
1452         read-OID if
1453                 \ Based on the signature OID, we get:
1454                 \ -- the signing key type
1455                 \ -- the hash function numeric identifier
1456                 \ -- the hash function OID
1457                 choice
1458                         sha1WithRSAEncryption   eqOID
1459                                 uf 2 KEYTYPE_RSA id-sha1   enduf
1460                         sha224WithRSAEncryption eqOID
1461                                 uf 3 KEYTYPE_RSA id-sha224 enduf
1462                         sha256WithRSAEncryption eqOID
1463                                 uf 4 KEYTYPE_RSA id-sha256 enduf
1464                         sha384WithRSAEncryption eqOID
1465                                 uf 5 KEYTYPE_RSA id-sha384 enduf
1466                         sha512WithRSAEncryption eqOID
1467                                 uf 6 KEYTYPE_RSA id-sha512 enduf
1468
1469                         ecdsa-with-SHA1   eqOID
1470                                 uf 2 KEYTYPE_EC id-sha1 enduf
1471                         ecdsa-with-SHA224 eqOID
1472                                 uf 3 KEYTYPE_EC id-sha224 enduf
1473                         ecdsa-with-SHA256 eqOID
1474                                 uf 4 KEYTYPE_EC id-sha256 enduf
1475                         ecdsa-with-SHA384 eqOID
1476                                 uf 5 KEYTYPE_EC id-sha384 enduf
1477                         ecdsa-with-SHA512 eqOID
1478                                 uf 6 KEYTYPE_EC id-sha512 enduf
1479                         ERR_X509_UNSUPPORTED fail
1480                 endchoice
1481                 addr-cert_sig_hash_oid set16
1482                 addr-cert_signer_key_type set8
1483
1484                 \ Compute the TBS hash into tbs_hash.
1485                 compute-tbs-hash
1486                 dup ifnot ERR_X509_UNSUPPORTED fail then
1487                 addr-cert_sig_hash_len set8
1488         else
1489                 ERR_X509_UNSUPPORTED fail
1490         then
1491         \ We ignore the parameters, whether they are present or not,
1492         \ because we got all the information from the OID.
1493         skip-close-elt
1494
1495         \ signature value
1496         read-bits-open
1497         dup CX 0 8191 { BR_X509_BUFSIZE_SIG } > if
1498                 ERR_X509_LIMIT_EXCEEDED fail
1499         then
1500         dup addr-cert_sig_len set16
1501         addr-cert_sig read-blob
1502
1503         \ Close the outer SEQUENCE.
1504         close-elt
1505
1506         \ Close the advertised total certificate length. This checks that
1507         \ there is no trailing garbage after the certificate.
1508         close-elt
1509
1510         \ Flag the certificate as fully processed.
1511         0 addr-cert_length set32
1512
1513         \ Check whether the issuer for the current certificate is known
1514         \ as a trusted CA; in which case, verify the signature.
1515         check-trust-anchor-CA ;
1516
1517 : main
1518         \ Unless restricted by a Key Usage extension, all usages are
1519         \ deemed allowed.
1520         0x30 addr-key_usages set8
1521         -1 decode-certificate
1522         co
1523         begin
1524                 0 decode-certificate co
1525         again
1526         ;