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 length 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.
156 #if BR_USE_WIN32_TIME
161 * The T0 compiler will produce these prototypes declarations in the
164 void br_x509_minimal_init_main(void *ctx);
165 void br_x509_minimal_run(void *ctx);
168 /* see bearssl_x509.h */
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)
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;
182 xm_start_chain(const br_x509_class **ctx, const char *server_name)
184 br_x509_minimal_context *cc;
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;
192 memset(&cc->pkey, 0, sizeof cc->pkey);
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;
201 cc->server_name = server_name;
206 xm_start_cert(const br_x509_class **ctx, uint32_t length)
208 br_x509_minimal_context *cc;
210 cc = (br_x509_minimal_context *)(void *)ctx;
215 cc->err = BR_ERR_X509_TRUNCATED;
218 cc->cert_length = length;
222 xm_append(const br_x509_class **ctx, const unsigned char *buf, size_t len)
224 br_x509_minimal_context *cc;
226 cc = (br_x509_minimal_context *)(void *)ctx;
232 br_x509_minimal_run(&cc->cpu);
236 xm_end_cert(const br_x509_class **ctx)
238 br_x509_minimal_context *cc;
240 cc = (br_x509_minimal_context *)(void *)ctx;
241 if (cc->err == 0 && cc->cert_length != 0) {
242 cc->err = BR_ERR_X509_TRUNCATED;
248 xm_end_chain(const br_x509_class **ctx)
250 br_x509_minimal_context *cc;
252 cc = (br_x509_minimal_context *)(void *)ctx;
254 if (cc->num_certs == 0) {
255 cc->err = BR_ERR_X509_EMPTY_CHAIN;
257 cc->err = BR_ERR_X509_NOT_TRUSTED;
259 } else if (cc->err == BR_ERR_X509_OK) {
262 return (unsigned)cc->err;
265 static const br_x509_pkey *
266 xm_get_pkey(const br_x509_class *const *ctx, unsigned *usages)
268 br_x509_minimal_context *cc;
270 cc = (br_x509_minimal_context *)(void *)ctx;
271 if (cc->err == BR_ERR_X509_OK
272 || cc->err == BR_ERR_X509_NOT_TRUSTED)
274 if (usages != NULL) {
275 *usages = cc->key_usages;
277 return &((br_x509_minimal_context *)(void *)ctx)->pkey;
283 /* see bearssl_x509.h */
284 const br_x509_class br_x509_minimal_vtable = {
285 sizeof(br_x509_minimal_context),
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
297 #define DNHASH_LEN ((CTX->dn_hash_impl->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK)
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
305 hash_dn(br_x509_minimal_context *ctx, const void *dn, size_t len,
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);
314 * Compare two big integers for equality. The integers use unsigned big-endian
315 * encoding; extra leading bytes (of value 0) are allowed.
318 eqbigint(const unsigned char *b1, size_t len1,
319 const unsigned char *b2, size_t len2)
321 while (len1 > 0 && *b1 == 0) {
325 while (len2 > 0 && *b2 == 0) {
332 return memcmp(b1, b2, len1) == 0;
336 * Compare two strings for equality, in a case-insensitive way. This
337 * function handles casing only for ASCII letters.
340 eqnocase(const void *s1, const void *s2, size_t len)
342 const unsigned char *buf1, *buf2;
351 if (x1 >= 'A' && x1 <= 'Z') {
354 if (x2 >= 'A' && x2 <= 'Z') {
364 static int verify_signature(br_x509_minimal_context *ctx,
365 const br_x509_pkey *pk);
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.
377 verify_signature(br_x509_minimal_context *ctx, const br_x509_pkey *pk)
381 kt = ctx->cert_signer_key_type;
382 if ((pk->key_type & 0x0F) != kt) {
383 return BR_ERR_X509_WRONG_KEY_TYPE;
386 unsigned char tmp[64];
389 if (ctx->irsa == 0) {
390 return BR_ERR_X509_UNSUPPORTED;
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))
396 return BR_ERR_X509_BAD_SIGNATURE;
398 if (memcmp(ctx->tbs_hash, tmp, ctx->cert_sig_hash_len) != 0) {
399 return BR_ERR_X509_BAD_SIGNATURE;
404 if (ctx->iecdsa == 0) {
405 return BR_ERR_X509_UNSUPPORTED;
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))
411 return BR_ERR_X509_BAD_SIGNATURE;
416 return BR_ERR_X509_UNSUPPORTED;
422 cc: read8-low ( -- x ) {
423 if (CTX->hlen == 0) {
426 unsigned char x = *CTX->hbuf ++;
428 br_multihash_update(&CTX->mhash, &x, 1);
430 if (CTX->do_dn_hash) {
431 CTX->dn_hash_impl->update(&CTX->dn_hash.vtable, &x, 1);
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;
449 memcpy((unsigned char *)CTX + addr, CTX->hbuf, clen);
452 br_multihash_update(&CTX->mhash, CTX->hbuf, clen);
454 if (CTX->do_dn_hash) {
455 CTX->dn_hash_impl->update(
456 &CTX->dn_hash.vtable, CTX->hbuf, clen);
460 T0_PUSH(addr + clen);
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 ) {
470 len = br_multihash_out(&CTX->mhash, id, CTX->tbs_hash);
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));
482 addr: cert_signer_key_type
483 addr: cert_sig_hash_oid
484 addr: cert_sig_hash_len
488 \ Start TBS hash computation. The hash functions are reinitialised.
489 cc: start-tbs-hash ( -- ) {
490 br_multihash_init(&CTX->mhash);
494 \ Stop TBS hash computation.
495 cc: stop-tbs-hash ( -- ) {
499 \ Start DN hash computation.
500 cc: start-dn-hash ( -- ) {
501 CTX->dn_hash_impl->init(&CTX->dn_hash.vtable);
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);
512 \ Get the length of hash values obtained with the DN hasher.
513 cc: dn-hash-length ( -- len ) {
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);
525 addr: current_dn_hash
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 )
533 read-sequence-open skip-close-elt
536 cc: offset-name-element ( san -- n ) {
537 unsigned san = T0_POP();
540 for (u = 0; u < CTX->num_name_elts; u ++) {
541 if (CTX->name_elts[u].status == 0) {
542 const unsigned char *oid;
545 oid = CTX->name_elts[u].oid;
547 if (oid[0] != 0 || oid[1] != 0) {
555 if (len != 0 && len == CTX->pad[0]
556 && memcmp(oid + off + 1,
557 CTX->pad + 1, len) == 0)
567 cc: copy-name-element ( bool offbuf -- ) {
569 int32_t off = T0_POPi();
573 br_name_element *ne = &CTX->name_elts[off];
578 memcpy(ne->buf, CTX->pad + 1, len);
590 cc: copy-name-SAN ( bool tag -- ) {
591 unsigned tag = T0_POP();
592 unsigned ok = T0_POP();
596 for (u = 0; u < CTX->num_name_elts; u ++) {
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);
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 )
620 12 of check-primitive read-value-UTF8 endof
622 18 of check-primitive read-value-latin1 endof
624 19 of check-primitive read-value-latin1 endof
626 20 of check-primitive read-value-latin1 endof
628 22 of check-primitive read-value-latin1 endof
630 30 of check-primitive read-value-UTF16 endof
631 2drop read-length-skip 0 0
634 \ Read a DN for the EE. The normalized DN hash is computed and stored in the
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.
645 \ Activate DN hashing.
648 \ Parse the DN structure: it is a SEQUENCE of SET of
649 \ AttributeTypeAndValue. Each AttributeTypeAndValue is a
650 \ SEQUENCE { OBJECT IDENTIFIER, ANY }.
655 read-tag 0x11 check-tag-constructed read-length-open-elt
656 dup ifnot ERR_X509_BAD_DN fail then
662 \ Read the OID. If the OID could not be read (too
663 \ long) then the first pad byte will be 0.
666 \ If it is the Common Name then we'll need to
667 \ match it against the intended server name (if
669 id-at-commonName eqOID { isCN }
671 \ Get offset for reception buffer for that element
673 0 offset-name-element { offbuf }
675 \ Try to read the value as a string.
678 \ If the value could be decoded as a string,
679 \ copy it and/or match it, as appropriate.
685 offbuf copy-name-element
695 \ Compute DN hash and deactivate DN hashing.
698 \ Return the CN match flag.
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();
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;
721 uint32_t vd = CTX->days;
722 uint32_t vs = CTX->seconds;
723 if (vd == 0 && vs == 0) {
725 time_t x = time(NULL);
727 vd = (uint32_t)(x / 86400) + 719528;
728 vs = (uint32_t)(x % 86400);
729 #elif BR_USE_WIN32_TIME
733 GetSystemTimeAsFileTime(&ft);
734 x = ((uint64_t)ft.dwHighDateTime << 32)
735 + (uint64_t)ft.dwLowDateTime;
737 vd = (uint32_t)(x / 86400) + 584754;
738 vs = (uint32_t)(x % 86400);
740 CTX->err = BR_ERR_X509_TIME_UNKNOWN;
744 if (vd < nbd || (vd == nbd && vs < nbs)) {
746 } else if (vd > nad || (vd == nad && vs > nas)) {
755 \ Swap the top two elements with the two elements immediately below.
756 : swap2 ( a b c d -- c d a b )
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 ) {
768 if (CTX->server_name == NULL) {
772 n1 = strlen(CTX->server_name);
774 if (n1 == n2 && eqnocase(&CTX->pad[1], CTX->server_name, n1)) {
778 if (n2 >= 2 && CTX->pad[1] == '*' && CTX->pad[2] == '.') {
782 while (u < n1 && CTX->server_name[u] != '.') {
788 && eqnocase(&CTX->pad[3], CTX->server_name + u, n1))
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 } ;
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;
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;
825 \ Check whether the current certificate (EE) is directly trusted.
826 cc: check-direct-trust ( -- ) {
829 for (u = 0; u < CTX->trust_anchors_num; u ++) {
830 const br_x509_trust_anchor *ta;
831 unsigned char hashed_DN[64];
834 ta = &CTX->trust_anchors[u];
835 if (ta->flags & BR_X509_TA_CA) {
838 hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN);
839 if (memcmp(hashed_DN, CTX->current_dn_hash, DNHASH_LEN)) {
842 kt = CTX->pkey.key_type;
843 if ((ta->pkey.key_type & 0x0F) != kt) {
849 if (!eqbigint(CTX->pkey.key.rsa.n,
850 CTX->pkey.key.rsa.nlen,
852 ta->pkey.key.rsa.nlen)
853 || !eqbigint(CTX->pkey.key.rsa.e,
854 CTX->pkey.key.rsa.elen,
856 ta->pkey.key.rsa.elen))
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,
867 ta->pkey.key.ec.qlen) != 0)
878 * Direct trust match!
880 CTX->err = BR_ERR_X509_OK;
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 ( -- ) {
890 for (u = 0; u < CTX->trust_anchors_num; u ++) {
891 const br_x509_trust_anchor *ta;
892 unsigned char hashed_DN[64];
894 ta = &CTX->trust_anchors[u];
895 if (!(ta->flags & BR_X509_TA_CA)) {
898 hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN);
899 if (memcmp(hashed_DN, CTX->saved_dn_hash, DNHASH_LEN)) {
902 if (verify_signature(CTX, &ta->pkey) == 0) {
903 CTX->err = BR_ERR_X509_OK;
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();
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));
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();
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));
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();
948 for (u = 0; u < len; u ++) {
949 printf("%02X", buf[u]);
953 cc: printOID ( -- ) {
954 extern int printf(const char *fmt, ...);
962 printf("%u.%u", CTX->pad[1] / 40, CTX->pad[1] % 40);
976 ul = (ul << 7) + (x & 0x7F);
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
991 \ Policy qualifier "pointer to CPS"
992 OID: id-qt-cps 1.3.6.1.5.5.7.2.1
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
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 )
1012 read-boolean ifnot ERR_X509_NOT_CA fail then
1015 ERR_X509_NOT_CA fail
1018 drop check-primitive read-small-int-value
1019 addr-num_certs get32 1- < if ERR_X509_NOT_CA fail then
1022 -1 <> if ERR_X509_UNEXPECTED fail then
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 )
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.
1043 ign 7 > if ERR_X509_UNEXPECTED fail then
1044 \ Depending on length, we have either 0, 1 or more bytes to read.
1046 0 of ERR_X509_FORBIDDEN_KEY_USAGE fail endof
1047 1 of read8 ign >> ign << endof
1055 over 0x38 and if 0x10 or then
1056 swap 0xC0 and if 0x20 or then
1057 addr-key_usages set8
1059 \ Not EE: keyCertSign must be set.
1060 0x04 and ifnot ERR_X509_FORBIDDEN_KEY_USAGE fail then
1063 \ We don't care about subsequent bytes.
1066 \ Process a Certificate Policies extension.
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).
1079 \ This function is called only if the extension is critical.
1080 : process-certPolicies ( lim -- lim )
1081 \ Extension value is a SEQUENCE OF PolicyInformation.
1084 \ PolicyInformation ::= SEQUENCE {
1085 \ policyIdentifier OBJECT IDENTIFIER,
1086 \ policyQualifiers SEQUENCE OF PolicyQualifierInfo OPTIONAL
1093 \ PolicyQualifierInfo ::= SEQUENCE {
1094 \ policyQualifierId OBJECT IDENTIFIER,
1098 read-OID drop id-qt-cps eqOID ifnot
1099 ERR_X509_CRITICAL_EXTENSION fail
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
1112 : process-SAN ( lim -- lim bool )
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,
1123 \ OtherName ::= SEQUENCE {
1124 \ type-id OBJECT IDENTIFIER,
1125 \ value [0] EXPLICIT ANY
1127 check-constructed read-length-open-elt
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
1136 \ rfc822Name (IA5String)
1139 read-value-UTF8 1 copy-name-SAN
1141 \ dNSName (IA5String)
1145 dup if match-server-name m or >m then
1148 \ uniformResourceIdentifier (IA5String)
1151 read-value-UTF8 6 copy-name-SAN
1153 2drop read-length-skip 0
1156 \ We check only names of type dNSName; they use IA5String,
1157 \ which is basically ASCII.
1158 \ read-tag 0x22 = if
1160 \ read-small-value drop
1161 \ match-server-name m or >m
1163 \ drop read-length-skip
1169 \ Decode a certificate. The "ee" boolean must be true for the EE.
1170 : decode-certificate ( ee -- )
1173 \ Obtain the total certificate length.
1174 addr-cert_length get32
1176 \ Open the outer SEQUENCE.
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
1189 0x02 check-tag-primitive
1190 read-small-int-value
1191 2 > if ERR_X509_UNSUPPORTED fail then
1196 \ Serial number. We just check that the tag is correct.
1197 0x02 check-tag-primitive
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
1204 \ Issuer name: hashed, then copied into next_dn_hash[].
1206 addr-next_dn_hash addr-current_dn_hash dn-hash-length blobcopy
1210 read-date { nbd nbs } read-date nbd nbs check-validity-range
1211 if ERR_X509_EXPIRED fail then
1216 \ For the EE, we must check whether the Common Name, if
1217 \ any, matches the expected server name.
1218 read-DN-EE { eename }
1220 \ For a non-EE certificate, the hashed subject DN must match
1221 \ the saved hashed issuer DN from the previous certificate.
1223 addr-current_dn_hash addr-saved_dn_hash dn-hash-length eqblob
1224 ifnot ERR_X509_DN_MISMATCH fail 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
1232 \ Algorithm Identifier. Right now we are only interested in the
1233 \ OID, since we only support RSA keys.
1235 read-OID ifnot ERR_X509_UNSUPPORTED fail then
1239 rsaEncryption eqOID uf
1241 \ Public key itself: the BIT STRING contains bytes
1242 \ (no partial byte) and these bytes encode the
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.
1250 read-integer { nlen }
1251 addr-len-pkey_data swap nlen + swap nlen -
1252 read-integer { elen }
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
1264 KEYTYPE_RSA >pkey-type
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
1274 ansix9p256r1 eqOID uf 23 enduf
1275 ansix9p384r1 eqOID uf 24 enduf
1276 ansix9p521r1 eqOID uf 25 enduf
1277 ERR_X509_UNSUPPORTED fail
1283 dup addr-len-pkey_data rot < if
1284 ERR_X509_LIMIT_EXCEEDED fail
1287 KEYTYPE_EC >pkey-type
1290 \ Not a recognised public key type.
1291 ERR_X509_UNSUPPORTED fail
1295 \ Process public key.
1297 \ For the EE certificate, copy the key data to the
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
1305 \ Verify signature on previous certificate. We invoke
1306 \ the RSA implementation.
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
1316 \ This flag will be set to true if the Basic Constraints extension
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
1330 check-constructed read-length-open-elt
1336 read-tag dup 0x01 = if
1337 read-boolean >critical
1340 0x04 check-tag-primitive read-length-open-elt
1342 \ Extensions with specific processing.
1343 basicConstraints eqOID uf
1347 process-basicConstraints
1354 subjectAltName eqOID uf
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
1369 process-certPolicies
1375 \ Extensions which are always ignored,
1377 authorityKeyIdentifier eqOID uf
1380 subjectKeyIdentifier eqOID uf
1383 issuerAltName eqOID uf
1386 subjectDirectoryAttributes eqOID uf
1389 crlDistributionPoints eqOID uf
1392 freshestCRL eqOID uf
1395 authorityInfoAccess eqOID uf
1398 subjectInfoAccess eqOID uf
1402 \ Unrecognized extensions trigger a failure
1403 \ if critical; otherwise, they are just
1406 ERR_X509_CRITICAL_EXTENSION fail
1416 -1 = ifnot ERR_X509_UNEXPECTED fail then
1421 \ Terminate hashing.
1424 \ For the EE certificate, verify that the intended server name
1427 eename zero-server-name or ifnot
1428 ERR_X509_BAD_SERVER_NAME fail
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
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
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
1451 \ TODO: add support for RSA/PSS
1453 \ Based on the signature OID, we get:
1454 \ -- the signing key type
1455 \ -- the hash function numeric identifier
1456 \ -- the hash function OID
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
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
1481 addr-cert_sig_hash_oid set16
1482 addr-cert_signer_key_type set8
1484 \ Compute the TBS hash into tbs_hash.
1486 dup ifnot ERR_X509_UNSUPPORTED fail then
1487 addr-cert_sig_hash_len set8
1489 ERR_X509_UNSUPPORTED fail
1491 \ We ignore the parameters, whether they are present or not,
1492 \ because we got all the information from the OID.
1497 dup CX 0 8191 { BR_X509_BUFSIZE_SIG } > if
1498 ERR_X509_LIMIT_EXCEEDED fail
1500 dup addr-cert_sig_len set16
1501 addr-cert_sig read-blob
1503 \ Close the outer SEQUENCE.
1506 \ Close the advertised total certificate length. This checks that
1507 \ there is no trailing garbage after the certificate.
1510 \ Flag the certificate as fully processed.
1511 0 addr-cert_length set32
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 ;
1518 \ Unless restricted by a Key Usage extension, all usages are
1520 0x30 addr-key_usages set8
1521 -1 decode-certificate
1524 0 decode-certificate co