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, const char *server_name)
193 br_x509_minimal_context *cc;
196 cc = (br_x509_minimal_context *)ctx;
197 for (u = 0; u < cc->num_name_elts; u ++) {
198 cc->name_elts[u].status = 0;
199 cc->name_elts[u].buf[0] = 0;
201 memset(&cc->pkey, 0, sizeof cc->pkey);
204 cc->cpu.dp = cc->dp_stack;
205 cc->cpu.rp = cc->rp_stack;
206 br_x509_minimal_init_main(&cc->cpu);
207 if (server_name == NULL || *server_name == 0) {
208 cc->server_name = NULL;
210 cc->server_name = server_name;
215 xm_start_cert(const br_x509_class **ctx, uint32_t length)
217 br_x509_minimal_context *cc;
219 cc = (br_x509_minimal_context *)ctx;
224 cc->err = BR_ERR_X509_TRUNCATED;
227 cc->cert_length = length;
231 xm_append(const br_x509_class **ctx, const unsigned char *buf, size_t len)
233 br_x509_minimal_context *cc;
235 cc = (br_x509_minimal_context *)ctx;
241 br_x509_minimal_run(&cc->cpu);
245 xm_end_cert(const br_x509_class **ctx)
247 br_x509_minimal_context *cc;
249 cc = (br_x509_minimal_context *)ctx;
250 if (cc->err == 0 && cc->cert_length != 0) {
251 cc->err = BR_ERR_X509_TRUNCATED;
257 xm_end_chain(const br_x509_class **ctx)
259 br_x509_minimal_context *cc;
261 cc = (br_x509_minimal_context *)ctx;
263 if (cc->num_certs == 0) {
264 cc->err = BR_ERR_X509_EMPTY_CHAIN;
266 cc->err = BR_ERR_X509_NOT_TRUSTED;
268 } else if (cc->err == BR_ERR_X509_OK) {
271 return (unsigned)cc->err;
274 static const br_x509_pkey *
275 xm_get_pkey(const br_x509_class *const *ctx, unsigned *usages)
277 br_x509_minimal_context *cc;
279 cc = (br_x509_minimal_context *)ctx;
280 if (cc->err == BR_ERR_X509_OK
281 || cc->err == BR_ERR_X509_NOT_TRUSTED)
283 if (usages != NULL) {
284 *usages = cc->key_usages;
286 return &((br_x509_minimal_context *)ctx)->pkey;
292 /* see bearssl_x509.h */
293 const br_x509_class br_x509_minimal_vtable = {
294 sizeof(br_x509_minimal_context),
303 #define CTX ((br_x509_minimal_context *)((unsigned char *)t0ctx - offsetof(br_x509_minimal_context, cpu)))
304 #define CONTEXT_NAME br_x509_minimal_context
306 #define DNHASH_LEN ((CTX->dn_hash_impl->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK)
309 * Hash a DN (from a trust anchor) into the provided buffer. This uses the
310 * DN hash implementation and context structure from the X.509 engine
314 hash_dn(br_x509_minimal_context *ctx, const void *dn, size_t len,
317 ctx->dn_hash_impl->init(&ctx->dn_hash.vtable);
318 ctx->dn_hash_impl->update(&ctx->dn_hash.vtable, dn, len);
319 ctx->dn_hash_impl->out(&ctx->dn_hash.vtable, out);
323 * Compare two big integers for equality. The integers use unsigned big-endian
324 * encoding; extra leading bytes (of value 0) are allowed.
327 eqbigint(const unsigned char *b1, size_t len1,
328 const unsigned char *b2, size_t len2)
330 while (len1 > 0 && *b1 == 0) {
334 while (len2 > 0 && *b2 == 0) {
341 return memcmp(b1, b2, len1) == 0;
345 * Verify the signature on the certificate with the provided public key.
346 * This function checks the public key type with regards to the expected
347 * type. Returned value is either 0 on success, or a non-zero error code.
350 verify_signature(br_x509_minimal_context *ctx, const br_x509_pkey *pk)
354 kt = ctx->cert_signer_key_type;
355 if ((pk->key_type & 0x0F) != kt) {
356 return BR_ERR_X509_WRONG_KEY_TYPE;
359 unsigned char tmp[64];
362 if (ctx->irsa == 0) {
363 return BR_ERR_X509_UNSUPPORTED;
365 if (!ctx->irsa(ctx->cert_sig, ctx->cert_sig_len,
366 &t0_datablock[ctx->cert_sig_hash_oid],
367 ctx->cert_sig_hash_len, &pk->key.rsa, tmp))
369 return BR_ERR_X509_BAD_SIGNATURE;
371 if (memcmp(ctx->tbs_hash, tmp, ctx->cert_sig_hash_len) != 0) {
372 return BR_ERR_X509_BAD_SIGNATURE;
377 if (ctx->iecdsa == 0) {
378 return BR_ERR_X509_UNSUPPORTED;
380 if (!ctx->iecdsa(ctx->iec, ctx->tbs_hash,
381 ctx->cert_sig_hash_len, &pk->key.ec,
382 ctx->cert_sig, ctx->cert_sig_len))
384 return BR_ERR_X509_BAD_SIGNATURE;
389 return BR_ERR_X509_UNSUPPORTED;
394 * Compare two strings for equality, in a case-insensitive way. This
395 * function handles casing only for ASCII letters.
398 eqnocase(const void *s1, const void *s2, size_t len)
400 const unsigned char *buf1, *buf2;
409 if (x1 >= 'A' && x1 <= 'Z') {
412 if (x2 >= 'A' && x2 <= 'Z') {
424 cc: read8-low ( -- x ) {
425 if (CTX->hlen == 0) {
428 unsigned char x = *CTX->hbuf ++;
430 br_multihash_update(&CTX->mhash, &x, 1);
432 if (CTX->do_dn_hash) {
433 CTX->dn_hash_impl->update(&CTX->dn_hash.vtable, &x, 1);
443 cc: read-blob-inner ( addr len -- addr len ) {
444 uint32_t len = T0_POP();
445 uint32_t addr = T0_POP();
446 size_t clen = CTX->hlen;
451 memcpy((unsigned char *)CTX + addr, CTX->hbuf, clen);
454 br_multihash_update(&CTX->mhash, CTX->hbuf, clen);
456 if (CTX->do_dn_hash) {
457 CTX->dn_hash_impl->update(
458 &CTX->dn_hash.vtable, CTX->hbuf, clen);
462 T0_PUSH(addr + clen);
466 \ Compute the TBS hash, using the provided hash ID. The hash value is
467 \ written in the tbs_hash[] array, and the hash length is returned. If
468 \ the requested hash function is not supported, then 0 is returned.
469 cc: compute-tbs-hash ( id -- hashlen ) {
472 len = br_multihash_out(&CTX->mhash, id, CTX->tbs_hash);
476 \ Push true (-1) if no server name is expected in the EE certificate.
477 cc: zero-server-name ( -- bool ) {
478 T0_PUSHi(-(CTX->server_name == NULL));
484 addr: cert_signer_key_type
485 addr: cert_sig_hash_oid
486 addr: cert_sig_hash_len
490 \ Start TBS hash computation. The hash functions are reinitialised.
491 cc: start-tbs-hash ( -- ) {
492 br_multihash_init(&CTX->mhash);
496 \ Stop TBS hash computation.
497 cc: stop-tbs-hash ( -- ) {
501 \ Start DN hash computation.
502 cc: start-dn-hash ( -- ) {
503 CTX->dn_hash_impl->init(&CTX->dn_hash.vtable);
507 \ Terminate DN hash computation and write the DN hash into the
508 \ current_dn_hash buffer.
509 cc: compute-dn-hash ( -- ) {
510 CTX->dn_hash_impl->out(&CTX->dn_hash.vtable, CTX->current_dn_hash);
514 \ Get the length of hash values obtained with the DN hasher.
515 cc: dn-hash-length ( -- len ) {
519 \ Copy data between two areas in the context.
520 cc: blobcopy ( addr-dst addr-src len -- ) {
521 size_t len = T0_POP();
522 unsigned char *src = (unsigned char *)CTX + T0_POP();
523 unsigned char *dst = (unsigned char *)CTX + T0_POP();
524 memcpy(dst, src, len);
527 addr: current_dn_hash
531 \ Read a DN, hashing it into current_dn_hash. The DN contents are not
532 \ inspected (only the outer tag, for SEQUENCE, is checked).
533 : read-DN ( lim -- lim )
535 read-sequence-open skip-close-elt
538 cc: offset-name-element ( san -- n ) {
539 unsigned san = T0_POP();
542 for (u = 0; u < CTX->num_name_elts; u ++) {
543 if (CTX->name_elts[u].status == 0) {
544 const unsigned char *oid;
547 oid = CTX->name_elts[u].oid;
549 if (oid[0] != 0 || oid[1] != 0) {
557 if (len != 0 && len == CTX->pad[0]
558 && memcmp(oid + off + 1,
559 CTX->pad + 1, len) == 0)
569 cc: copy-name-element ( bool offbuf -- ) {
571 int32_t off = T0_POPi();
575 br_name_element *ne = &CTX->name_elts[off];
580 memcpy(ne->buf, CTX->pad + 1, len);
592 cc: copy-name-SAN ( bool tag -- ) {
593 unsigned tag = T0_POP();
594 unsigned ok = T0_POP();
598 for (u = 0; u < CTX->num_name_elts; u ++) {
601 ne = &CTX->name_elts[u];
602 if (ne->status == 0 && ne->oid[0] == 0 && ne->oid[1] == tag) {
603 if (ok && ne->len > len) {
604 memcpy(ne->buf, CTX->pad + 1, len);
615 \ Read a value, decoding string types. If the string type is recognised
616 \ and the value could be converted to UTF-8 into the pad, then true (-1)
617 \ is returned; in all other cases, false (0) is returned. Either way, the
618 \ object is consumed.
619 : read-string ( lim -- lim bool )
622 12 of check-primitive read-value-UTF8 endof
624 18 of check-primitive read-value-latin1 endof
626 19 of check-primitive read-value-latin1 endof
628 20 of check-primitive read-value-latin1 endof
630 22 of check-primitive read-value-latin1 endof
632 30 of check-primitive read-value-UTF16 endof
633 2drop read-length-skip 0 0
636 \ Read a DN for the EE. The normalized DN hash is computed and stored in the
638 \ Name elements are gathered. Also, the Common Name is matched against the
639 \ intended server name.
640 \ Returned value is true (-1) if the CN matches the intended server name,
641 \ false (0) otherwise.
642 : read-DN-EE ( lim -- lim bool )
643 \ Flag will be set to true if there is a CN and it matches the
644 \ intended server name.
647 \ Activate DN hashing.
650 \ Parse the DN structure: it is a SEQUENCE of SET of
651 \ AttributeTypeAndValue. Each AttributeTypeAndValue is a
652 \ SEQUENCE { OBJECT IDENTIFIER, ANY }.
657 read-tag 0x11 check-tag-constructed read-length-open-elt
658 dup ifnot ERR_X509_BAD_DN fail then
664 \ Read the OID. If the OID could not be read (too
665 \ long) then the first pad byte will be 0.
668 \ If it is the Common Name then we'll need to
669 \ match it against the intended server name (if
671 id-at-commonName eqOID { isCN }
673 \ Get offset for reception buffer for that element
675 0 offset-name-element { offbuf }
677 \ Try to read the value as a string.
680 \ If the value could be decoded as a string,
681 \ copy it and/or match it, as appropriate.
687 offbuf copy-name-element
697 \ Compute DN hash and deactivate DN hashing.
700 \ Return the CN match flag.
703 \ Get the validation date and time from the context or system.
704 cc: get-system-date ( -- days seconds ) {
705 if (CTX->days == 0 && CTX->seconds == 0) {
707 time_t x = time(NULL);
709 T0_PUSH((uint32_t)(x / 86400) + 719528);
710 T0_PUSH((uint32_t)(x % 86400));
711 #elif BR_USE_WIN32_TIME
715 GetSystemTimeAsFileTime(&ft);
716 x = ((uint64_t)ft.dwHighDateTime << 32)
717 + (uint64_t)ft.dwLowDateTime;
719 T0_PUSH((uint32_t)(x / 86400) + 584754);
720 T0_PUSH((uint32_t)(x % 86400));
722 CTX->err = BR_ERR_X509_TIME_UNKNOWN;
727 T0_PUSH(CTX->seconds);
731 \ Compare two dates (days+seconds) together.
732 : before ( days1 seconds1 days2 seconds2 -- bool )
734 d1 d2 = if s1 s2 < else d1 d2 < then ;
736 : after ( days1 seconds1 days2 seconds2 -- bool )
739 \ Swap the top two elements with the two elements immediately below.
740 : swap2 ( a b c d -- c d a b )
743 \ Match the name in the pad with the expected server name. Returned value
744 \ is true (-1) on match, false (0) otherwise. If there is no expected
745 \ server name, then 0 is returned.
746 \ Match conditions: either an exact match (case insensitive), or a
747 \ wildcard match, if the found name starts with "*.". We only match a
748 \ starting wildcard, and only against a complete DN name component.
749 cc: match-server-name ( -- bool ) {
752 if (CTX->server_name == NULL) {
756 n1 = strlen(CTX->server_name);
758 if (n1 == n2 && eqnocase(&CTX->pad[1], CTX->server_name, n1)) {
762 if (n2 >= 2 && CTX->pad[1] == '*' && CTX->pad[2] == '.') {
766 while (u < n1 && CTX->server_name[u] != '.') {
772 && eqnocase(&CTX->pad[3], CTX->server_name + u, n1))
781 \ Get the address and length for the pkey_data buffer.
782 : addr-len-pkey_data ( -- addr len )
783 CX 0 8191 { offsetof(br_x509_minimal_context, pkey_data) }
784 CX 0 8191 { BR_X509_BUFSIZE_KEY } ;
786 \ Copy the EE public key to the permanent buffer (RSA).
787 cc: copy-ee-rsa-pkey ( nlen elen -- ) {
788 size_t elen = T0_POP();
789 size_t nlen = T0_POP();
790 memcpy(CTX->ee_pkey_data, CTX->pkey_data, nlen + elen);
791 CTX->pkey.key_type = BR_KEYTYPE_RSA;
792 CTX->pkey.key.rsa.n = CTX->ee_pkey_data;
793 CTX->pkey.key.rsa.nlen = nlen;
794 CTX->pkey.key.rsa.e = CTX->ee_pkey_data + nlen;
795 CTX->pkey.key.rsa.elen = elen;
798 \ Copy the EE public key to the permanent buffer (EC).
799 cc: copy-ee-ec-pkey ( curve qlen -- ) {
800 size_t qlen = T0_POP();
801 uint32_t curve = T0_POP();
802 memcpy(CTX->ee_pkey_data, CTX->pkey_data, qlen);
803 CTX->pkey.key_type = BR_KEYTYPE_EC;
804 CTX->pkey.key.ec.curve = curve;
805 CTX->pkey.key.ec.q = CTX->ee_pkey_data;
806 CTX->pkey.key.ec.qlen = qlen;
809 \ Check whether the current certificate (EE) is directly trusted.
810 cc: check-direct-trust ( -- ) {
813 for (u = 0; u < CTX->trust_anchors_num; u ++) {
814 const br_x509_trust_anchor *ta;
815 unsigned char hashed_DN[64];
818 ta = &CTX->trust_anchors[u];
819 if (ta->flags & BR_X509_TA_CA) {
822 hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN);
823 if (memcmp(hashed_DN, CTX->current_dn_hash, DNHASH_LEN)) {
826 kt = CTX->pkey.key_type;
827 if ((ta->pkey.key_type & 0x0F) != kt) {
833 if (!eqbigint(CTX->pkey.key.rsa.n,
834 CTX->pkey.key.rsa.nlen,
836 ta->pkey.key.rsa.nlen)
837 || !eqbigint(CTX->pkey.key.rsa.e,
838 CTX->pkey.key.rsa.elen,
840 ta->pkey.key.rsa.elen))
847 if (CTX->pkey.key.ec.curve != ta->pkey.key.ec.curve
848 || CTX->pkey.key.ec.qlen != ta->pkey.key.ec.qlen
849 || memcmp(CTX->pkey.key.ec.q,
851 ta->pkey.key.ec.qlen) != 0)
862 * Direct trust match!
864 CTX->err = BR_ERR_X509_OK;
869 \ Check the signature on the certificate with regards to all trusted CA.
870 \ We use the issuer hash (in saved_dn_hash[]) as CA identifier.
871 cc: check-trust-anchor-CA ( -- ) {
874 for (u = 0; u < CTX->trust_anchors_num; u ++) {
875 const br_x509_trust_anchor *ta;
876 unsigned char hashed_DN[64];
878 ta = &CTX->trust_anchors[u];
879 if (!(ta->flags & BR_X509_TA_CA)) {
882 hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN);
883 if (memcmp(hashed_DN, CTX->saved_dn_hash, DNHASH_LEN)) {
886 if (verify_signature(CTX, &ta->pkey) == 0) {
887 CTX->err = BR_ERR_X509_OK;
893 \ Verify RSA signature. This uses the public key that was just decoded
894 \ into CTX->pkey_data; the modulus and exponent length are provided as
895 \ parameters. The resulting hash value is compared with the one in
896 \ tbs_hash. Returned value is 0 on success, or a non-zero error code.
897 cc: do-rsa-vrfy ( nlen elen -- err ) {
898 size_t elen = T0_POP();
899 size_t nlen = T0_POP();
902 pk.key_type = BR_KEYTYPE_RSA;
903 pk.key.rsa.n = CTX->pkey_data;
904 pk.key.rsa.nlen = nlen;
905 pk.key.rsa.e = CTX->pkey_data + nlen;
906 pk.key.rsa.elen = elen;
907 T0_PUSH(verify_signature(CTX, &pk));
910 \ Verify ECDSA signature. This uses the public key that was just decoded
911 \ into CTX->pkey_dayta; the curve ID and public point length are provided
912 \ as parameters. The hash value in tbs_hash is used. Returned value is 0
913 \ on success, or non-zero error code.
914 cc: do-ecdsa-vrfy ( curve qlen -- err ) {
915 size_t qlen = T0_POP();
916 int curve = T0_POP();
919 pk.key_type = BR_KEYTYPE_EC;
920 pk.key.ec.curve = curve;
921 pk.key.ec.q = CTX->pkey_data;
922 pk.key.ec.qlen = qlen;
923 T0_PUSH(verify_signature(CTX, &pk));
926 cc: print-bytes ( addr len -- ) {
927 extern int printf(const char *fmt, ...);
928 size_t len = T0_POP();
929 unsigned char *buf = (unsigned char *)CTX + T0_POP();
932 for (u = 0; u < len; u ++) {
933 printf("%02X", buf[u]);
937 cc: printOID ( -- ) {
938 extern int printf(const char *fmt, ...);
946 printf("%u.%u", CTX->pad[1] / 40, CTX->pad[1] % 40);
960 ul = (ul << 7) + (x & 0x7F);
969 \ Extensions with specific processing.
970 OID: basicConstraints 2.5.29.19
971 OID: keyUsage 2.5.29.15
972 OID: subjectAltName 2.5.29.17
974 \ Extensions which are ignored when encountered, even if critical.
975 OID: authorityKeyIdentifier 2.5.29.35
976 OID: subjectKeyIdentifier 2.5.29.14
977 OID: issuerAltName 2.5.29.18
978 OID: subjectDirectoryAttributes 2.5.29.9
979 OID: crlDistributionPoints 2.5.29.31
980 OID: freshestCRL 2.5.29.46
981 OID: authorityInfoAccess 1.3.6.1.5.5.7.1.1
982 OID: subjectInfoAccess 1.3.6.1.5.5.7.1.11
984 \ Process a Basic Constraints extension. This should be called only if
985 \ the certificate is not the EE. We check that the extension contains
986 \ the "CA" flag, and that the path length, if specified, is compatible
987 \ with the current chain length.
988 : process-basicConstraints ( lim -- lim )
992 read-boolean ifnot ERR_X509_NOT_CA fail then
998 drop check-primitive read-small-int-value
999 addr-num_certs get32 1- < if ERR_X509_NOT_CA fail then
1002 -1 <> if ERR_X509_UNEXPECTED fail then
1007 \ Process a Key Usage extension.
1008 \ For the EE certificate:
1009 \ -- if the key usage contains keyEncipherment (2), dataEncipherment (3)
1010 \ or keyAgreement (4), then the "key exchange" usage is allowed;
1011 \ -- if the key usage contains digitalSignature (0) or nonRepudiation (1),
1012 \ then the "signature" usage is allowed.
1013 \ For CA certificates, the extension must contain keyCertSign (5).
1014 : process-keyUsage ( lim ee -- lim )
1017 \ Read tag for the BIT STRING and open it.
1018 read-tag 0x03 check-tag-primitive
1019 read-length-open-elt
1020 \ First byte indicates number of ignored bits in the last byte. It
1021 \ must be between 0 and 7.
1023 ign 7 > if ERR_X509_UNEXPECTED fail then
1024 \ Depending on length, we have either 0, 1 or more bytes to read.
1026 0 of ERR_X509_FORBIDDEN_KEY_USAGE fail endof
1027 1 of read8 ign >> ign << endof
1035 over 0x38 and if 0x10 or then
1036 swap 0xC0 and if 0x20 or then
1037 addr-key_usages set8
1039 \ Not EE: keyCertSign must be set.
1040 0x04 and ifnot ERR_X509_FORBIDDEN_KEY_USAGE fail then
1043 \ We don't care about subsequent bytes.
1046 \ Process a Subject Alt Name extension. Returned value is a boolean set
1047 \ to true if the expected server name was matched against a dNSName in
1049 : process-SAN ( lim -- lim bool )
1053 \ Read the tag. If the tag is context-0, then parse an
1054 \ 'otherName'. If the tag is context-2, then parse a
1055 \ dNSName. If the tag is context-1 or context-6,
1060 \ OtherName ::= SEQUENCE {
1061 \ type-id OBJECT IDENTIFIER,
1062 \ value [0] EXPLICIT ANY
1064 check-constructed read-length-open-elt
1066 -1 offset-name-element { offbuf }
1067 read-tag 0x20 check-tag-constructed
1068 read-length-open-elt
1069 read-string offbuf copy-name-element
1073 \ rfc822Name (IA5String)
1076 read-value-UTF8 1 copy-name-SAN
1078 \ dNSName (IA5String)
1082 dup if match-server-name m or >m then
1085 \ uniformResourceIdentifier (IA5String)
1088 read-value-UTF8 6 copy-name-SAN
1090 2drop read-length-skip 0
1093 \ We check only names of type dNSName; they use IA5String,
1094 \ which is basically ASCII.
1095 \ read-tag 0x22 = if
1097 \ read-small-value drop
1098 \ match-server-name m or >m
1100 \ drop read-length-skip
1106 \ Decode a certificate. The "ee" boolean must be true for the EE.
1107 : decode-certificate ( ee -- )
1110 \ Obtain the total certificate length.
1111 addr-cert_length get32
1113 \ Open the outer SEQUENCE.
1121 \ First element may be an explicit version. We accept only
1122 \ versions 0 to 2 (certificates v1 to v3).
1123 read-tag dup 0x20 = if
1124 drop check-constructed read-length-open-elt
1126 0x02 check-tag-primitive
1127 read-small-int-value
1128 2 > if ERR_X509_UNSUPPORTED fail then
1133 \ Serial number. We just check that the tag is correct.
1134 0x02 check-tag-primitive
1137 \ Signature algorithm. This structure is redundant with the one
1138 \ on the outside; we just skip it.
1139 read-sequence-open skip-close-elt
1141 \ Issuer name: hashed, then copied into next_dn_hash[].
1143 addr-next_dn_hash addr-current_dn_hash dn-hash-length blobcopy
1147 read-date get-system-date after if ERR_X509_EXPIRED fail then
1148 read-date get-system-date before if ERR_X509_EXPIRED fail then
1153 \ For the EE, we must check whether the Common Name, if
1154 \ any, matches the expected server name.
1155 read-DN-EE { eename }
1157 \ For a non-EE certificate, the hashed subject DN must match
1158 \ the saved hashed issuer DN from the previous certificate.
1160 addr-current_dn_hash addr-saved_dn_hash dn-hash-length eqblob
1161 ifnot ERR_X509_DN_MISMATCH fail then
1163 \ Move the hashed issuer DN for this certificate into the
1164 \ saved_dn_hash[] array.
1165 addr-saved_dn_hash addr-next_dn_hash dn-hash-length blobcopy
1169 \ Algorithm Identifier. Right now we are only interested in the
1170 \ OID, since we only support RSA keys.
1172 read-OID ifnot ERR_X509_UNSUPPORTED fail then
1176 rsaEncryption eqOID uf
1178 \ Public key itself: the BIT STRING contains bytes
1179 \ (no partial byte) and these bytes encode the
1182 \ RSA public key is a SEQUENCE of two
1183 \ INTEGER. We get both INTEGER values into
1184 \ the pkey_data[] buffer, if they fit.
1187 read-integer { nlen }
1188 addr-len-pkey_data swap nlen + swap nlen -
1189 read-integer { elen }
1192 \ Check that the public key fits our minimal
1193 \ size requirements. Note that the integer
1194 \ decoder already skipped the leading bytes
1195 \ of value 0, so we are working on the true
1196 \ modulus length here.
1197 addr-min_rsa_size get16 128 + nlen > if
1198 ERR_X509_WEAK_PUBLIC_KEY fail
1201 KEYTYPE_RSA >pkey-type
1205 id-ecPublicKey eqOID uf
1206 \ We support only named curves, for which the
1207 \ "parameters" field in the AlgorithmIdentifier
1208 \ field should be an OID.
1209 read-OID ifnot ERR_X509_UNSUPPORTED fail then
1211 ansix9p256r1 eqOID uf 23 enduf
1212 ansix9p384r1 eqOID uf 24 enduf
1213 ansix9p521r1 eqOID uf 25 enduf
1214 ERR_X509_UNSUPPORTED fail
1220 dup addr-len-pkey_data rot < if
1221 ERR_X509_LIMIT_EXCEEDED fail
1224 KEYTYPE_EC >pkey-type
1227 \ Not a recognised public key type.
1228 ERR_X509_UNSUPPORTED fail
1232 \ Process public key.
1234 \ For the EE certificate, copy the key data to the
1237 KEYTYPE_RSA of nlen elen copy-ee-rsa-pkey endof
1238 KEYTYPE_EC of curve qlen copy-ee-ec-pkey endof
1239 ERR_X509_UNSUPPORTED fail
1242 \ Verify signature on previous certificate. We invoke
1243 \ the RSA implementation.
1245 KEYTYPE_RSA of nlen elen do-rsa-vrfy endof
1246 KEYTYPE_EC of curve qlen do-ecdsa-vrfy endof
1247 ERR_X509_UNSUPPORTED fail
1253 \ This flag will be set to true if the Basic Constraints extension
1257 \ Skip issuerUniqueID and subjectUniqueID, and process extensions
1258 \ if present. Extensions are an explicit context tag of value 3
1259 \ around a SEQUENCE OF extensions. Each extension is a SEQUENCE
1260 \ with an OID, an optional boolean, and a value; the value is
1267 check-constructed read-length-open-elt
1273 read-tag dup 0x01 = if
1274 read-boolean >critical
1277 0x04 check-tag-primitive read-length-open-elt
1279 \ Extensions with specific processing.
1280 basicConstraints eqOID uf
1284 process-basicConstraints
1291 subjectAltName eqOID uf
1300 \ Extensions which are always ignored,
1302 authorityKeyIdentifier eqOID uf
1305 subjectKeyIdentifier eqOID uf
1308 issuerAltName eqOID uf
1311 subjectDirectoryAttributes eqOID uf
1314 crlDistributionPoints eqOID uf
1317 freshestCRL eqOID uf
1320 authorityInfoAccess eqOID uf
1323 subjectInfoAccess eqOID uf
1327 \ Unrecognized extensions trigger a failure
1328 \ if critical; otherwise, they are just
1331 ERR_X509_CRITICAL_EXTENSION fail
1341 -1 = ifnot ERR_X509_UNEXPECTED fail then
1346 \ Terminate hashing.
1349 \ For the EE certificate, verify that the intended server name
1352 eename zero-server-name or ifnot
1353 ERR_X509_BAD_SERVER_NAME fail
1357 \ If this is the EE certificate, then direct trust may apply.
1358 \ Note: we do this at this point, not immediately after decoding
1359 \ the public key, because even in case of direct trust we still
1360 \ want to check the server name with regards to the SAN extension.
1361 \ However, we want to check direct trust before trying to decode
1362 \ the signature algorithm, because it should work even if that
1363 \ algorithm is not supported.
1364 ee if check-direct-trust then
1366 \ Non-EE certificates MUST have a Basic Constraints extension
1367 \ (that marks them as being CA).
1368 ee seenBC or ifnot ERR_X509_NOT_CA fail then
1370 \ signature algorithm
1371 read-tag check-sequence read-length-open-elt
1372 \ Read and understand the OID. Right now, we support only
1373 \ RSA with PKCS#1 v1.5 padding, and hash functions SHA-1,
1374 \ SHA-224, SHA-256, SHA-384 and SHA-512. We purposely do NOT
1376 \ TODO: add support for RSA/PSS
1378 \ Based on the signature OID, we get:
1379 \ -- the signing key type
1380 \ -- the hash function numeric identifier
1381 \ -- the hash function OID
1383 sha1WithRSAEncryption eqOID
1384 uf 2 KEYTYPE_RSA id-sha1 enduf
1385 sha224WithRSAEncryption eqOID
1386 uf 3 KEYTYPE_RSA id-sha224 enduf
1387 sha256WithRSAEncryption eqOID
1388 uf 4 KEYTYPE_RSA id-sha256 enduf
1389 sha384WithRSAEncryption eqOID
1390 uf 5 KEYTYPE_RSA id-sha384 enduf
1391 sha512WithRSAEncryption eqOID
1392 uf 6 KEYTYPE_RSA id-sha512 enduf
1394 ecdsa-with-SHA1 eqOID
1395 uf 2 KEYTYPE_EC id-sha1 enduf
1396 ecdsa-with-SHA224 eqOID
1397 uf 3 KEYTYPE_EC id-sha224 enduf
1398 ecdsa-with-SHA256 eqOID
1399 uf 4 KEYTYPE_EC id-sha256 enduf
1400 ecdsa-with-SHA384 eqOID
1401 uf 5 KEYTYPE_EC id-sha384 enduf
1402 ecdsa-with-SHA512 eqOID
1403 uf 6 KEYTYPE_EC id-sha512 enduf
1404 ERR_X509_UNSUPPORTED fail
1406 addr-cert_sig_hash_oid set16
1407 addr-cert_signer_key_type set8
1409 \ Compute the TBS hash into tbs_hash.
1411 dup ifnot ERR_X509_UNSUPPORTED fail then
1412 addr-cert_sig_hash_len set8
1414 ERR_X509_UNSUPPORTED fail
1416 \ We ignore the parameters, whether they are present or not,
1417 \ because we got all the information from the OID.
1422 dup CX 0 8191 { BR_X509_BUFSIZE_SIG } > if
1423 ERR_X509_LIMIT_EXCEEDED fail
1425 dup addr-cert_sig_len set16
1426 addr-cert_sig read-blob
1428 \ Close the outer SEQUENCE.
1431 \ Close the advertised total certificate length. This checks that
1432 \ there is no trailing garbage after the certificate.
1435 \ Flag the certificate as fully processed.
1436 0 addr-cert_length set32
1438 \ Check whether the issuer for the current certificate is known
1439 \ as a trusted CA; in which case, verify the signature.
1440 check-trust-anchor-CA ;
1443 \ Unless restricted by a Key Usage extension, all usages are
1445 0x30 addr-key_usages set8
1446 -1 decode-certificate
1449 0 decode-certificate co