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
28 * Implementation Notes
29 * --------------------
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.
38 * The T0 code sets cert_length to 0 when the certificate is fully
41 * The C code must still perform two checks:
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
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.
51 * Processing of a chain works in the following way:
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.
59 * -- Each certificate is decoded in due course, with the following
60 * "interesting points":
62 * -- Start of the TBS: the multihash engine is reset and activated.
64 * -- Start of the issuer DN: the secondary hash engine is started,
65 * to process the encoded issuer DN.
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.
71 * -- Start of the subject DN: the secondary hash engine is started,
72 * to process the encoded subject DN.
74 * -- For the EE certificate only: the Common Name, if any, is matched
75 * against the expected server name.
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:
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[]).
84 * -- Otherwise, the hashed subject DN is compared with the saved
85 * hash value (in saved_dn_hash[]). They must match.
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.
93 * -- Public key: it is decoded into the cert_pkey[] buffer. Unknown
94 * key types are reported at that point.
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.
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.
106 * -- Extensions: extension values are processed in due order.
108 * -- Basic Constraints: for all certificates except EE, must be
109 * present, indicate a CA, and have a path legnth compatible with
110 * the chain length so far.
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.
116 * -- Subject Alt Name: for the EE, dNSName names are matched
117 * against the server name. Ignored for non-EE.
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.
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.
130 * -- End of the TBS: the multihash engine is stopped.
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.
139 * -- Signature value: the signature value is copied into the
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.
148 * -- If the chain end is reached without obtaining a validation success,
149 * then validation is reported as failed.
152 #ifndef BR_USE_UNIX_TIME
153 #if defined __unix__ || defined __linux__ \
154 || defined _POSIX_SOURCE || defined _POSIX_C_SOURCE \
155 || (defined __APPLE__ && defined __MACH__)
156 #define BR_USE_UNIX_TIME 1
160 #ifndef BR_USE_WIN32_TIME
161 #if defined _WIN32 || defined _WIN64
162 #define BR_USE_WIN32_TIME 1
170 #if BR_USE_WIN32_TIME
174 void br_x509_minimal_init_main(void *ctx);
175 void br_x509_minimal_run(void *ctx);
177 /* see bearssl_x509.h */
179 br_x509_minimal_init(br_x509_minimal_context *ctx,
180 const br_hash_class *dn_hash_impl,
181 const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num)
183 memset(ctx, 0, sizeof *ctx);
184 ctx->vtable = &br_x509_minimal_vtable;
185 ctx->dn_hash_impl = dn_hash_impl;
186 ctx->trust_anchors = trust_anchors;
187 ctx->trust_anchors_num = trust_anchors_num;
191 xm_start_chain(const br_x509_class **ctx,
192 unsigned expected_key_type, const char *server_name)
194 br_x509_minimal_context *cc;
196 cc = (br_x509_minimal_context *)ctx;
197 memset(&cc->pkey, 0, sizeof cc->pkey);
200 cc->cpu.dp = cc->dp_stack;
201 cc->cpu.rp = cc->rp_stack;
202 br_x509_minimal_init_main(&cc->cpu);
203 cc->expected_key_type = expected_key_type;
204 if (server_name == NULL || *server_name == 0) {
205 cc->server_name = NULL;
207 cc->server_name = server_name;
212 xm_start_cert(const br_x509_class **ctx, uint32_t length)
214 br_x509_minimal_context *cc;
216 cc = (br_x509_minimal_context *)ctx;
221 cc->err = BR_ERR_X509_TRUNCATED;
224 cc->cert_length = length;
228 xm_append(const br_x509_class **ctx, const unsigned char *buf, size_t len)
230 br_x509_minimal_context *cc;
232 cc = (br_x509_minimal_context *)ctx;
238 br_x509_minimal_run(&cc->cpu);
242 xm_end_cert(const br_x509_class **ctx)
244 br_x509_minimal_context *cc;
246 cc = (br_x509_minimal_context *)ctx;
247 if (cc->err == 0 && cc->cert_length != 0) {
248 cc->err = BR_ERR_X509_TRUNCATED;
254 xm_end_chain(const br_x509_class **ctx)
256 br_x509_minimal_context *cc;
258 cc = (br_x509_minimal_context *)ctx;
260 if (cc->num_certs == 0) {
261 cc->err = BR_ERR_X509_EMPTY_CHAIN;
263 cc->err = BR_ERR_X509_NOT_TRUSTED;
265 } else if (cc->err == BR_ERR_X509_OK) {
268 return (unsigned)cc->err;
271 static const br_x509_pkey *
272 xm_get_pkey(const br_x509_class *const *ctx)
274 br_x509_minimal_context *cc;
276 cc = (br_x509_minimal_context *)ctx;
277 if (cc->err == BR_ERR_X509_OK
278 || cc->err == BR_ERR_X509_NOT_TRUSTED)
280 return &((br_x509_minimal_context *)ctx)->pkey;
286 /* see bearssl_x509.h */
287 const br_x509_class br_x509_minimal_vtable = {
288 sizeof(br_x509_minimal_context),
297 #define CTX ((br_x509_minimal_context *)((unsigned char *)t0ctx - offsetof(br_x509_minimal_context, cpu)))
298 #define CONTEXT_NAME br_x509_minimal_context
300 #define DNHASH_LEN ((CTX->dn_hash_impl->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK)
303 * Hash a DN (from a trust anchor) into the provided buffer. This uses the
304 * DN hash implementation and context structure from the X.509 engine
308 hash_dn(br_x509_minimal_context *ctx, const void *dn, size_t len,
311 ctx->dn_hash_impl->init(&ctx->dn_hash.vtable);
312 ctx->dn_hash_impl->update(&ctx->dn_hash.vtable, dn, len);
313 ctx->dn_hash_impl->out(&ctx->dn_hash.vtable, out);
317 * Compare two big integers for equality. The integers use unsigned big-endian
318 * encoding; extra leading bytes (of value 0) are allowed.
321 eqbigint(const unsigned char *b1, size_t len1,
322 const unsigned char *b2, size_t len2)
324 while (len1 > 0 && *b1 == 0) {
328 while (len2 > 0 && *b2 == 0) {
335 return memcmp(b1, b2, len1) == 0;
339 * Verify the signature on the certificate with the provided public key.
340 * This function checks the public key type with regards to the expected
341 * type. Returned value is either 0 on success, or a non-zero error code.
344 verify_signature(br_x509_minimal_context *ctx, const br_x509_pkey *pk)
348 kt = ctx->cert_signer_key_type;
349 if ((pk->key_type & 0x0F) != kt) {
350 return BR_ERR_X509_WRONG_KEY_TYPE;
353 unsigned char tmp[64];
356 if (ctx->irsa == 0) {
357 return BR_ERR_X509_UNSUPPORTED;
359 if (!ctx->irsa(ctx->cert_sig, ctx->cert_sig_len,
360 &t0_datablock[ctx->cert_sig_hash_oid],
361 ctx->cert_sig_hash_len, &pk->key.rsa, tmp))
363 return BR_ERR_X509_BAD_SIGNATURE;
365 if (memcmp(ctx->tbs_hash, tmp, ctx->cert_sig_hash_len) != 0) {
366 return BR_ERR_X509_BAD_SIGNATURE;
371 if (ctx->iecdsa == 0) {
372 return BR_ERR_X509_UNSUPPORTED;
374 if (!ctx->iecdsa(ctx->iec, ctx->tbs_hash,
375 ctx->cert_sig_hash_len, &pk->key.ec,
376 ctx->cert_sig, ctx->cert_sig_len))
378 return BR_ERR_X509_BAD_SIGNATURE;
383 return BR_ERR_X509_UNSUPPORTED;
388 * Compare two strings for equality, in a case-insensitive way. This
389 * function handles casing only for ASCII letters.
392 eqnocase(const void *s1, const void *s2, size_t len)
394 const unsigned char *buf1, *buf2;
403 if (x1 >= 'A' && x1 <= 'Z') {
406 if (x2 >= 'A' && x2 <= 'Z') {
418 cc: read8-low ( -- x ) {
419 if (CTX->hlen == 0) {
422 unsigned char x = *CTX->hbuf ++;
424 br_multihash_update(&CTX->mhash, &x, 1);
426 if (CTX->do_dn_hash) {
427 CTX->dn_hash_impl->update(&CTX->dn_hash.vtable, &x, 1);
437 cc: read-blob-inner ( addr len -- addr len ) {
438 uint32_t len = T0_POP();
439 uint32_t addr = T0_POP();
440 size_t clen = CTX->hlen;
445 memcpy((unsigned char *)CTX + addr, CTX->hbuf, clen);
448 br_multihash_update(&CTX->mhash, CTX->hbuf, clen);
450 if (CTX->do_dn_hash) {
451 CTX->dn_hash_impl->update(
452 &CTX->dn_hash.vtable, CTX->hbuf, clen);
456 T0_PUSH(addr + clen);
460 \ Compute the TBS hash, using the provided hash ID. The hash value is
461 \ written in the tbs_hash[] array, and the hash length is returned. If
462 \ the requested hash function is not supported, then 0 is returned.
463 cc: compute-tbs-hash ( id -- hashlen ) {
466 len = br_multihash_out(&CTX->mhash, id, CTX->tbs_hash);
470 \ Push true (-1) if no server name is expected in the EE certificate.
471 cc: zero-server-name ( -- bool ) {
472 T0_PUSHi(-(CTX->server_name == NULL));
475 addr: expected_key_type
478 addr: cert_signer_key_type
479 addr: cert_sig_hash_oid
480 addr: cert_sig_hash_len
484 \ Start TBS hash computation. The hash functions are reinitialised.
485 cc: start-tbs-hash ( -- ) {
486 br_multihash_init(&CTX->mhash);
490 \ Stop TBS hash computation.
491 cc: stop-tbs-hash ( -- ) {
495 \ Start DN hash computation.
496 cc: start-dn-hash ( -- ) {
497 CTX->dn_hash_impl->init(&CTX->dn_hash.vtable);
501 \ Terminate DN hash computation and write the DN hash into the
502 \ current_dn_hash buffer.
503 cc: compute-dn-hash ( -- ) {
504 CTX->dn_hash_impl->out(&CTX->dn_hash.vtable, CTX->current_dn_hash);
508 \ Get the length of hash values obtained with the DN hasher.
509 cc: dn-hash-length ( -- len ) {
513 \ Copy data between two areas in the context.
514 cc: blobcopy ( addr-dst addr-src len -- ) {
515 size_t len = T0_POP();
516 unsigned char *src = (unsigned char *)CTX + T0_POP();
517 unsigned char *dst = (unsigned char *)CTX + T0_POP();
518 memcpy(dst, src, len);
521 addr: current_dn_hash
525 \ Read a DN. The normalized DN hash is computed and stored in the
526 \ current_dn_hash. The Common Name is also extracted to the pad, if
527 \ it is present and small enough (255 bytes at most); the CN length is
528 \ then written in pad[0]. If these conditions are not met, then pad[0]
530 : read-DN ( lim -- lim )
531 \ Activate DN hashing.
537 \ Parse the DN structure: it is a SEQUENCE of SET of
538 \ AttributeTypeAndValue. Each AttributeTypeAndValue is a
539 \ SEQUENCE { OBJECT IDENTIFIER, ANY }.
544 read-tag 0x11 check-tag-constructed read-length-open-elt
545 dup ifnot ERR_X509_BAD_DN fail then
550 \ We want to recognize the OID for Common Name,
551 \ but we don't want to use read-OID because we
552 \ need to preserve the pad contents. Instead, we
553 \ use the fact that the encoding for the value of
554 \ id-at-commonName is 55 04 03 (three bytes).
555 read-tag 0x06 check-tag-primitive read-length-open-elt
558 read8 8 << tmp + >tmp
564 \ If this is a Common Name, then we want to copy
565 \ it to the pad, but only if it uses a mono-byte
566 \ encoding (Printable, Teletex or UTF-8).
569 dup dup 0x0C = swap 0x13 = or swap 0x14 = or if
571 read-small-value drop
586 \ Compute DN hash and deactivate DN hashing.
589 \ Get the validation date and time from the context or system.
590 cc: get-system-date ( -- days seconds ) {
591 if (CTX->days == 0 && CTX->seconds == 0) {
593 time_t x = time(NULL);
595 T0_PUSH((uint32_t)(x / 86400) + 719528);
596 T0_PUSH((uint32_t)(x % 86400));
597 #elif BR_USE_WIN32_TIME
601 GetSystemTimeAsFileTime(&ft);
602 x = ((uint64_t)ft.dwHighDateTime << 32)
603 + (uint64_t)ft.dwLowDateTime;
605 T0_PUSH((uint32_t)(x / 86400) + 584754);
606 T0_PUSH((uint32_t)(x % 86400));
608 CTX->err = BR_ERR_X509_TIME_UNKNOWN;
613 T0_PUSH(CTX->seconds);
617 \ Compare two dates (days+seconds) together.
618 : before ( days1 seconds1 days2 seconds2 -- bool )
620 d1 d2 = if s1 s2 < else d1 d2 < then ;
622 : after ( days1 seconds1 days2 seconds2 -- bool )
625 \ Swap the top two elements with the two elements immediately below.
626 : swap2 ( a b c d -- c d a b )
629 \ Match the name in the pad with the expected server name. Returned value
630 \ is true (-1) on match, false (0) otherwise. If there is no expected
631 \ server name, then 0 is returned.
632 \ Match conditions: either an exact match (case insensitive), or a
633 \ wildcard match, if the found name starts with "*.". We only match a
634 \ starting wildcard, and only against a complete DN name component.
635 cc: match-server-name ( -- bool ) {
638 if (CTX->server_name == NULL) {
642 n1 = strlen(CTX->server_name);
644 if (n1 == n2 && eqnocase(&CTX->pad[1], CTX->server_name, n1)) {
648 if (n2 >= 2 && CTX->pad[1] == '*' && CTX->pad[2] == '.') {
652 while (u < n1 && CTX->server_name[u] != '.') {
658 && eqnocase(&CTX->pad[3], CTX->server_name + u, n1))
667 \ Get the address and length for the pkey_data buffer.
668 : addr-len-pkey_data ( -- addr len )
669 CX 0 8191 { offsetof(br_x509_minimal_context, pkey_data) }
670 CX 0 8191 { BR_X509_BUFSIZE_KEY } ;
672 \ Copy the EE public key to the permanent buffer (RSA).
673 cc: copy-ee-rsa-pkey ( nlen elen -- ) {
674 size_t elen = T0_POP();
675 size_t nlen = T0_POP();
676 memcpy(CTX->ee_pkey_data, CTX->pkey_data, nlen + elen);
677 CTX->pkey.key_type = BR_KEYTYPE_RSA;
678 CTX->pkey.key.rsa.n = CTX->ee_pkey_data;
679 CTX->pkey.key.rsa.nlen = nlen;
680 CTX->pkey.key.rsa.e = CTX->ee_pkey_data + nlen;
681 CTX->pkey.key.rsa.elen = elen;
684 \ Copy the EE public key to the permanent buffer (EC).
685 cc: copy-ee-ec-pkey ( curve qlen -- ) {
686 size_t qlen = T0_POP();
687 uint32_t curve = T0_POP();
688 memcpy(CTX->ee_pkey_data, CTX->pkey_data, qlen);
689 CTX->pkey.key_type = BR_KEYTYPE_EC;
690 CTX->pkey.key.ec.curve = curve;
691 CTX->pkey.key.ec.q = CTX->ee_pkey_data;
692 CTX->pkey.key.ec.qlen = qlen;
695 \ Check whether the current certificate (EE) is directly trusted.
696 cc: check-direct-trust ( -- ) {
699 for (u = 0; u < CTX->trust_anchors_num; u ++) {
700 const br_x509_trust_anchor *ta;
701 unsigned char hashed_DN[64];
704 ta = &CTX->trust_anchors[u];
705 if (ta->flags & BR_X509_TA_CA) {
708 hash_dn(CTX, ta->dn, ta->dn_len, hashed_DN);
709 if (memcmp(hashed_DN, CTX->current_dn_hash, DNHASH_LEN)) {
712 kt = CTX->pkey.key_type;
713 if ((ta->pkey.key_type & 0x0F) != kt) {
719 if (!eqbigint(CTX->pkey.key.rsa.n,
720 CTX->pkey.key.rsa.nlen,
722 ta->pkey.key.rsa.nlen)
723 || !eqbigint(CTX->pkey.key.rsa.e,
724 CTX->pkey.key.rsa.elen,
726 ta->pkey.key.rsa.elen))
733 if (CTX->pkey.key.ec.curve != ta->pkey.key.ec.curve
734 || CTX->pkey.key.ec.qlen != ta->pkey.key.ec.qlen
735 || memcmp(CTX->pkey.key.ec.q,
737 ta->pkey.key.ec.qlen) != 0)
748 * Direct trust match!
750 CTX->err = BR_ERR_X509_OK;
755 \ Check the signature on the certificate with regards to all trusted CA.
756 \ We use the issuer hash (in saved_dn_hash[]) as CA identifier.
757 cc: check-trust-anchor-CA ( -- ) {
760 for (u = 0; u < CTX->trust_anchors_num; u ++) {
761 const br_x509_trust_anchor *ta;
762 unsigned char hashed_DN[64];
764 ta = &CTX->trust_anchors[u];
765 if (!(ta->flags & BR_X509_TA_CA)) {
768 hash_dn(CTX, ta->dn, ta->dn_len, hashed_DN);
769 if (memcmp(hashed_DN, CTX->saved_dn_hash, DNHASH_LEN)) {
772 if (verify_signature(CTX, &ta->pkey) == 0) {
773 CTX->err = BR_ERR_X509_OK;
779 \ Verify RSA signature. This uses the public key that was just decoded
780 \ into CTX->pkey_data; the modulus and exponent length are provided as
781 \ parameters. The resulting hash value is compared with the one in
782 \ tbs_hash. Returned value is 0 on success, or a non-zero error code.
783 cc: do-rsa-vrfy ( nlen elen -- err ) {
784 size_t elen = T0_POP();
785 size_t nlen = T0_POP();
788 pk.key_type = BR_KEYTYPE_RSA;
789 pk.key.rsa.n = CTX->pkey_data;
790 pk.key.rsa.nlen = nlen;
791 pk.key.rsa.e = CTX->pkey_data + nlen;
792 pk.key.rsa.elen = elen;
793 T0_PUSH(verify_signature(CTX, &pk));
796 \ Verify ECDSA signature. This uses the public key that was just decoded
797 \ into CTX->pkey_dayta; the curve ID and public point length are provided
798 \ as parameters. The hash value in tbs_hash is used. Returned value is 0
799 \ on success, or non-zero error code.
800 cc: do-ecdsa-vrfy ( curve qlen -- err ) {
801 size_t qlen = T0_POP();
802 int curve = T0_POP();
805 pk.key_type = BR_KEYTYPE_EC;
806 pk.key.ec.curve = curve;
807 pk.key.ec.q = CTX->pkey_data;
808 pk.key.ec.qlen = qlen;
809 T0_PUSH(verify_signature(CTX, &pk));
812 cc: print-bytes ( addr len -- ) {
813 extern int printf(const char *fmt, ...);
814 size_t len = T0_POP();
815 unsigned char *buf = (unsigned char *)CTX + T0_POP();
818 for (u = 0; u < len; u ++) {
819 printf("%02X", buf[u]);
823 cc: printOID ( -- ) {
824 extern int printf(const char *fmt, ...);
832 printf("%u.%u", CTX->pad[1] / 40, CTX->pad[1] % 40);
846 ul = (ul << 7) + (x & 0x7F);
855 \ Extensions with specific processing.
856 OID: basicConstraints 2.5.29.19
857 OID: keyUsage 2.5.29.15
858 OID: subjectAltName 2.5.29.17
860 \ Extensions which are ignored when encountered, even if critical.
861 OID: authorityKeyIdentifier 2.5.29.35
862 OID: subjectKeyIdentifier 2.5.29.14
863 OID: issuerAltName 2.5.29.18
864 OID: subjectDirectoryAttributes 2.5.29.9
865 OID: crlDistributionPoints 2.5.29.31
866 OID: freshestCRL 2.5.29.46
867 OID: authorityInfoAccess 1.3.6.1.5.5.7.1.1
868 OID: subjectInfoAccess 1.3.6.1.5.5.7.1.11
870 \ Process a Basic Constraints extension. This should be called only if
871 \ the certificate is not the EE. We check that the extension contains
872 \ the "CA" flag, and that the path length, if specified, is compatible
873 \ with the current chain length.
874 : process-basicConstraints ( lim -- lim )
878 read-boolean ifnot ERR_X509_NOT_CA fail then
884 drop check-primitive read-small-int-value
885 addr-num_certs get32 1- < if ERR_X509_NOT_CA fail then
888 -1 <> if ERR_X509_UNEXPECTED fail then
893 \ Process a Key Usage extension.
894 \ For the EE certificate:
895 \ -- if the expected key usage is "key exchange", then the extension
896 \ must contain either keyEncipherment (2) or dataEncipherment (3);
897 \ -- if the expected key usage is "signature", then the extension
898 \ must contain either digitalSignature (0) or nonRepudiation (1).
899 \ For CA certificates, the extension must contain keyCertSign (5).
900 : process-keyUsage ( lim ee -- lim )
901 \ Compute flags, depending on EE status and expected key usage.
902 \ This is a mask of bits in the first byte.
904 addr-expected_key_type get8 0x10 and if 0x30 else 0xC0 then
909 \ Read tag for the BIT STRING and open it.
910 read-tag 0x03 check-tag-primitive
912 \ First byte indicates number of ignored bits in the last byte. It
913 \ must be between 0 and 7.
915 ign 7 > if ERR_X509_UNEXPECTED fail then
916 \ Depending on length, we have either 0, 1 or more bytes to read.
918 0 of ERR_X509_FORBIDDEN_KEY_USAGE fail endof
919 1 of read8 ign >> ign << endof
922 mask and ifnot ERR_X509_FORBIDDEN_KEY_USAGE fail then
925 \ Process a Subject Alt Name extension. Returned value is a boolean set
926 \ to true if the expected server name was matched against a dNSName in
928 : process-SAN ( lim -- lim bool )
932 \ We check only names of type dNSName; they use IA5String,
933 \ which is basically ASCII.
936 read-small-value drop
937 match-server-name m or >m
939 drop read-length-skip
945 \ Decode a certificate. The "ee" boolean must be true for the EE.
946 : decode-certificate ( ee -- )
949 \ Obtain the total certificate length.
950 addr-cert_length get32
952 \ Open the outer SEQUENCE.
960 \ First element may be an explicit version. We accept only
961 \ versions 0 to 2 (certificates v1 to v3).
962 read-tag dup 0x20 = if
963 drop check-constructed read-length-open-elt
965 0x02 check-tag-primitive
967 2 > if ERR_X509_UNSUPPORTED fail then
972 \ Serial number. We just check that the tag is correct.
973 0x02 check-tag-primitive
976 \ Signature algorithm. This structure is redundant with the one
977 \ on the outside; we just skip it.
978 read-sequence-open skip-close-elt
980 \ Issuer name: hashed, then copied into next_dn_hash[].
982 addr-next_dn_hash addr-current_dn_hash dn-hash-length blobcopy
986 read-date get-system-date after if ERR_X509_EXPIRED fail then
987 read-date get-system-date before if ERR_X509_EXPIRED fail then
993 \ For the EE, we must check whether the Common Name, if
994 \ any, matches the expected server name.
995 match-server-name { eename }
997 \ For a non-EE certificate, the hashed subject DN must match
998 \ the saved hashed issuer DN from the previous certificate.
999 addr-current_dn_hash addr-saved_dn_hash dn-hash-length eqblob
1000 ifnot ERR_X509_DN_MISMATCH fail then
1002 \ Move the hashed issuer DN for this certificate into the
1003 \ saved_dn_hash[] array.
1004 addr-saved_dn_hash addr-next_dn_hash dn-hash-length blobcopy
1008 \ Algorithm Identifier. Right now we are only interested in the
1009 \ OID, since we only support RSA keys.
1011 read-OID ifnot ERR_X509_UNSUPPORTED fail then
1015 rsaEncryption eqOID uf
1017 \ Public key itself: the BIT STRING contains bytes
1018 \ (no partial byte) and these bytes encode the
1021 \ RSA public key is a SEQUENCE of two
1022 \ INTEGER. We get both INTEGER values into
1023 \ the pkey_data[] buffer, if they fit.
1026 read-integer { nlen }
1027 addr-len-pkey_data swap nlen + swap nlen -
1028 read-integer { elen }
1031 \ Check that the public key fits our minimal
1032 \ size requirements. Note that the integer
1033 \ decoder already skipped the leading bytes
1034 \ of value 0, so we are working on the true
1035 \ modulus length here.
1036 addr-min_rsa_size get16 128 + nlen > if
1037 ERR_X509_WEAK_PUBLIC_KEY fail
1040 KEYTYPE_RSA >pkey-type
1044 id-ecPublicKey eqOID uf
1045 \ We support only named curves, for which the
1046 \ "parameters" field in the AlgorithmIdentifier
1047 \ field should be an OID.
1048 read-OID ifnot ERR_X509_UNSUPPORTED fail then
1050 ansix9p256r1 eqOID uf 23 enduf
1051 ansix9p384r1 eqOID uf 24 enduf
1052 ansix9p521r1 eqOID uf 25 enduf
1053 ERR_X509_UNSUPPORTED fail
1059 dup addr-len-pkey_data rot < if
1060 ERR_X509_LIMIT_EXCEEDED fail
1063 KEYTYPE_EC >pkey-type
1066 \ Not a recognised public key type.
1067 ERR_X509_UNSUPPORTED fail
1071 \ Process public key.
1073 \ For the EE certificate, check that the key type
1074 \ matches that which was expected, then copy the
1075 \ data to the relevant buffer.
1076 addr-expected_key_type get8 0x0F and
1078 pkey-type = ifnot ERR_X509_WRONG_KEY_TYPE fail then
1083 KEYTYPE_RSA of nlen elen copy-ee-rsa-pkey endof
1084 KEYTYPE_EC of curve qlen copy-ee-ec-pkey endof
1085 ERR_X509_UNSUPPORTED fail
1088 \ Verify signature on previous certificate. We invoke
1089 \ the RSA implementation.
1091 KEYTYPE_RSA of nlen elen do-rsa-vrfy endof
1092 KEYTYPE_EC of curve qlen do-ecdsa-vrfy endof
1093 ERR_X509_UNSUPPORTED fail
1099 \ This flag will be set to true if the Basic Constraints extension
1103 \ Skip issuerUniqueID and subjectUniqueID, and process extensions
1104 \ if present. Extensions are an explicit context tag of value 3
1105 \ around a SEQUENCE OF extensions. Each extension is a SEQUENCE
1106 \ with an OID, an optional boolean, and a value; the value is
1113 check-constructed read-length-open-elt
1119 read-tag dup 0x01 = if
1120 read-boolean >critical
1123 0x04 check-tag-primitive read-length-open-elt
1125 \ Extensions with specific processing.
1126 basicConstraints eqOID uf
1130 process-basicConstraints
1137 subjectAltName eqOID uf
1146 \ Extensions which are always ignored,
1148 authorityKeyIdentifier eqOID uf
1151 subjectKeyIdentifier eqOID uf
1154 issuerAltName eqOID uf
1157 subjectDirectoryAttributes eqOID uf
1160 crlDistributionPoints eqOID uf
1163 freshestCRL eqOID uf
1166 authorityInfoAccess eqOID uf
1169 subjectInfoAccess eqOID uf
1173 \ Unrecognized extensions trigger a failure
1174 \ if critical; otherwise, they are just
1177 ERR_X509_CRITICAL_EXTENSION fail
1187 -1 = ifnot ERR_X509_UNEXPECTED fail then
1192 \ Terminate hashing.
1195 \ For the EE certificate, verify that the intended server name
1198 eename zero-server-name or ifnot
1199 ERR_X509_BAD_SERVER_NAME fail
1203 \ If this is the EE certificate, then direct trust may apply.
1204 \ Note: we do this at this point, not immediately after decoding
1205 \ the public key, because even in case of direct trust we still
1206 \ want to check the server name with regards to the SAN extension.
1207 \ However, we want to check direct trust before trying to decode
1208 \ the signature algorithm, because it should work even if that
1209 \ algorithm is not supported.
1210 ee if check-direct-trust then
1212 \ Non-EE certificates MUST have a Basic Constraints extension
1213 \ (that marks them as being CA).
1214 ee seenBC or ifnot ERR_X509_NOT_CA fail then
1216 \ signature algorithm
1217 read-tag check-sequence read-length-open-elt
1218 \ Read and understand the OID. Right now, we support only
1219 \ RSA with PKCS#1 v1.5 padding, and hash functions SHA-1,
1220 \ SHA-224, SHA-256, SHA-384 and SHA-512. We purposely do NOT
1222 \ TODO: add support for RSA/PSS
1224 \ Based on the signature OID, we get:
1225 \ -- the signing key type
1226 \ -- the hash function numeric identifier
1227 \ -- the hash function OID
1229 sha1WithRSAEncryption eqOID
1230 uf 2 KEYTYPE_RSA id-sha1 enduf
1231 sha224WithRSAEncryption eqOID
1232 uf 3 KEYTYPE_RSA id-sha224 enduf
1233 sha256WithRSAEncryption eqOID
1234 uf 4 KEYTYPE_RSA id-sha256 enduf
1235 sha384WithRSAEncryption eqOID
1236 uf 5 KEYTYPE_RSA id-sha384 enduf
1237 sha512WithRSAEncryption eqOID
1238 uf 6 KEYTYPE_RSA id-sha512 enduf
1240 ecdsa-with-SHA1 eqOID
1241 uf 2 KEYTYPE_EC id-sha1 enduf
1242 ecdsa-with-SHA224 eqOID
1243 uf 3 KEYTYPE_EC id-sha224 enduf
1244 ecdsa-with-SHA256 eqOID
1245 uf 4 KEYTYPE_EC id-sha256 enduf
1246 ecdsa-with-SHA384 eqOID
1247 uf 5 KEYTYPE_EC id-sha384 enduf
1248 ecdsa-with-SHA512 eqOID
1249 uf 6 KEYTYPE_EC id-sha512 enduf
1250 ERR_X509_UNSUPPORTED fail
1252 addr-cert_sig_hash_oid set16
1253 addr-cert_signer_key_type set8
1255 \ Compute the TBS hash into tbs_hash.
1257 dup ifnot ERR_X509_UNSUPPORTED fail then
1258 addr-cert_sig_hash_len set8
1260 ERR_X509_UNSUPPORTED fail
1262 \ We ignore the parameters, whether they are present or not,
1263 \ because we got all the information from the OID.
1268 dup CX 0 8191 { BR_X509_BUFSIZE_SIG } > if
1269 ERR_X509_LIMIT_EXCEEDED fail
1271 dup addr-cert_sig_len set16
1272 addr-cert_sig read-blob
1274 \ Close the outer SEQUENCE.
1277 \ Close the advertised total certificate length. This checks that
1278 \ there is no trailing garbage after the certificate.
1281 \ Flag the certificate as fully processed.
1282 0 addr-cert_length set32
1284 \ Check whether the issuer for the current certificate is known
1285 \ as a trusted CA; in which case, verify the signature.
1286 check-trust-anchor-CA ;
1289 -1 decode-certificate
1292 0 decode-certificate co