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
175 * The T0 compiler will produce these prototypes declarations in the
178 void br_x509_minimal_init_main(void *ctx);
179 void br_x509_minimal_run(void *ctx);
182 /* see bearssl_x509.h */
184 br_x509_minimal_init(br_x509_minimal_context *ctx,
185 const br_hash_class *dn_hash_impl,
186 const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num)
188 memset(ctx, 0, sizeof *ctx);
189 ctx->vtable = &br_x509_minimal_vtable;
190 ctx->dn_hash_impl = dn_hash_impl;
191 ctx->trust_anchors = trust_anchors;
192 ctx->trust_anchors_num = trust_anchors_num;
196 xm_start_chain(const br_x509_class **ctx, const char *server_name)
198 br_x509_minimal_context *cc;
201 cc = (br_x509_minimal_context *)ctx;
202 for (u = 0; u < cc->num_name_elts; u ++) {
203 cc->name_elts[u].status = 0;
204 cc->name_elts[u].buf[0] = 0;
206 memset(&cc->pkey, 0, sizeof cc->pkey);
209 cc->cpu.dp = cc->dp_stack;
210 cc->cpu.rp = cc->rp_stack;
211 br_x509_minimal_init_main(&cc->cpu);
212 if (server_name == NULL || *server_name == 0) {
213 cc->server_name = NULL;
215 cc->server_name = server_name;
220 xm_start_cert(const br_x509_class **ctx, uint32_t length)
222 br_x509_minimal_context *cc;
224 cc = (br_x509_minimal_context *)ctx;
229 cc->err = BR_ERR_X509_TRUNCATED;
232 cc->cert_length = length;
236 xm_append(const br_x509_class **ctx, const unsigned char *buf, size_t len)
238 br_x509_minimal_context *cc;
240 cc = (br_x509_minimal_context *)ctx;
246 br_x509_minimal_run(&cc->cpu);
250 xm_end_cert(const br_x509_class **ctx)
252 br_x509_minimal_context *cc;
254 cc = (br_x509_minimal_context *)ctx;
255 if (cc->err == 0 && cc->cert_length != 0) {
256 cc->err = BR_ERR_X509_TRUNCATED;
262 xm_end_chain(const br_x509_class **ctx)
264 br_x509_minimal_context *cc;
266 cc = (br_x509_minimal_context *)ctx;
268 if (cc->num_certs == 0) {
269 cc->err = BR_ERR_X509_EMPTY_CHAIN;
271 cc->err = BR_ERR_X509_NOT_TRUSTED;
273 } else if (cc->err == BR_ERR_X509_OK) {
276 return (unsigned)cc->err;
279 static const br_x509_pkey *
280 xm_get_pkey(const br_x509_class *const *ctx, unsigned *usages)
282 br_x509_minimal_context *cc;
284 cc = (br_x509_minimal_context *)ctx;
285 if (cc->err == BR_ERR_X509_OK
286 || cc->err == BR_ERR_X509_NOT_TRUSTED)
288 if (usages != NULL) {
289 *usages = cc->key_usages;
291 return &((br_x509_minimal_context *)ctx)->pkey;
297 /* see bearssl_x509.h */
298 const br_x509_class br_x509_minimal_vtable = {
299 sizeof(br_x509_minimal_context),
308 #define CTX ((br_x509_minimal_context *)((unsigned char *)t0ctx - offsetof(br_x509_minimal_context, cpu)))
309 #define CONTEXT_NAME br_x509_minimal_context
311 #define DNHASH_LEN ((CTX->dn_hash_impl->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK)
314 * Hash a DN (from a trust anchor) into the provided buffer. This uses the
315 * DN hash implementation and context structure from the X.509 engine
319 hash_dn(br_x509_minimal_context *ctx, const void *dn, size_t len,
322 ctx->dn_hash_impl->init(&ctx->dn_hash.vtable);
323 ctx->dn_hash_impl->update(&ctx->dn_hash.vtable, dn, len);
324 ctx->dn_hash_impl->out(&ctx->dn_hash.vtable, out);
328 * Compare two big integers for equality. The integers use unsigned big-endian
329 * encoding; extra leading bytes (of value 0) are allowed.
332 eqbigint(const unsigned char *b1, size_t len1,
333 const unsigned char *b2, size_t len2)
335 while (len1 > 0 && *b1 == 0) {
339 while (len2 > 0 && *b2 == 0) {
346 return memcmp(b1, b2, len1) == 0;
350 * Compare two strings for equality, in a case-insensitive way. This
351 * function handles casing only for ASCII letters.
354 eqnocase(const void *s1, const void *s2, size_t len)
356 const unsigned char *buf1, *buf2;
365 if (x1 >= 'A' && x1 <= 'Z') {
368 if (x2 >= 'A' && x2 <= 'Z') {
378 static int verify_signature(br_x509_minimal_context *ctx,
379 const br_x509_pkey *pk);
386 * Verify the signature on the certificate with the provided public key.
387 * This function checks the public key type with regards to the expected
388 * type. Returned value is either 0 on success, or a non-zero error code.
391 verify_signature(br_x509_minimal_context *ctx, const br_x509_pkey *pk)
395 kt = ctx->cert_signer_key_type;
396 if ((pk->key_type & 0x0F) != kt) {
397 return BR_ERR_X509_WRONG_KEY_TYPE;
400 unsigned char tmp[64];
403 if (ctx->irsa == 0) {
404 return BR_ERR_X509_UNSUPPORTED;
406 if (!ctx->irsa(ctx->cert_sig, ctx->cert_sig_len,
407 &t0_datablock[ctx->cert_sig_hash_oid],
408 ctx->cert_sig_hash_len, &pk->key.rsa, tmp))
410 return BR_ERR_X509_BAD_SIGNATURE;
412 if (memcmp(ctx->tbs_hash, tmp, ctx->cert_sig_hash_len) != 0) {
413 return BR_ERR_X509_BAD_SIGNATURE;
418 if (ctx->iecdsa == 0) {
419 return BR_ERR_X509_UNSUPPORTED;
421 if (!ctx->iecdsa(ctx->iec, ctx->tbs_hash,
422 ctx->cert_sig_hash_len, &pk->key.ec,
423 ctx->cert_sig, ctx->cert_sig_len))
425 return BR_ERR_X509_BAD_SIGNATURE;
430 return BR_ERR_X509_UNSUPPORTED;
436 cc: read8-low ( -- x ) {
437 if (CTX->hlen == 0) {
440 unsigned char x = *CTX->hbuf ++;
442 br_multihash_update(&CTX->mhash, &x, 1);
444 if (CTX->do_dn_hash) {
445 CTX->dn_hash_impl->update(&CTX->dn_hash.vtable, &x, 1);
455 cc: read-blob-inner ( addr len -- addr len ) {
456 uint32_t len = T0_POP();
457 uint32_t addr = T0_POP();
458 size_t clen = CTX->hlen;
463 memcpy((unsigned char *)CTX + addr, CTX->hbuf, clen);
466 br_multihash_update(&CTX->mhash, CTX->hbuf, clen);
468 if (CTX->do_dn_hash) {
469 CTX->dn_hash_impl->update(
470 &CTX->dn_hash.vtable, CTX->hbuf, clen);
474 T0_PUSH(addr + clen);
478 \ Compute the TBS hash, using the provided hash ID. The hash value is
479 \ written in the tbs_hash[] array, and the hash length is returned. If
480 \ the requested hash function is not supported, then 0 is returned.
481 cc: compute-tbs-hash ( id -- hashlen ) {
484 len = br_multihash_out(&CTX->mhash, id, CTX->tbs_hash);
488 \ Push true (-1) if no server name is expected in the EE certificate.
489 cc: zero-server-name ( -- bool ) {
490 T0_PUSHi(-(CTX->server_name == NULL));
496 addr: cert_signer_key_type
497 addr: cert_sig_hash_oid
498 addr: cert_sig_hash_len
502 \ Start TBS hash computation. The hash functions are reinitialised.
503 cc: start-tbs-hash ( -- ) {
504 br_multihash_init(&CTX->mhash);
508 \ Stop TBS hash computation.
509 cc: stop-tbs-hash ( -- ) {
513 \ Start DN hash computation.
514 cc: start-dn-hash ( -- ) {
515 CTX->dn_hash_impl->init(&CTX->dn_hash.vtable);
519 \ Terminate DN hash computation and write the DN hash into the
520 \ current_dn_hash buffer.
521 cc: compute-dn-hash ( -- ) {
522 CTX->dn_hash_impl->out(&CTX->dn_hash.vtable, CTX->current_dn_hash);
526 \ Get the length of hash values obtained with the DN hasher.
527 cc: dn-hash-length ( -- len ) {
531 \ Copy data between two areas in the context.
532 cc: blobcopy ( addr-dst addr-src len -- ) {
533 size_t len = T0_POP();
534 unsigned char *src = (unsigned char *)CTX + T0_POP();
535 unsigned char *dst = (unsigned char *)CTX + T0_POP();
536 memcpy(dst, src, len);
539 addr: current_dn_hash
543 \ Read a DN, hashing it into current_dn_hash. The DN contents are not
544 \ inspected (only the outer tag, for SEQUENCE, is checked).
545 : read-DN ( lim -- lim )
547 read-sequence-open skip-close-elt
550 cc: offset-name-element ( san -- n ) {
551 unsigned san = T0_POP();
554 for (u = 0; u < CTX->num_name_elts; u ++) {
555 if (CTX->name_elts[u].status == 0) {
556 const unsigned char *oid;
559 oid = CTX->name_elts[u].oid;
561 if (oid[0] != 0 || oid[1] != 0) {
569 if (len != 0 && len == CTX->pad[0]
570 && memcmp(oid + off + 1,
571 CTX->pad + 1, len) == 0)
581 cc: copy-name-element ( bool offbuf -- ) {
583 int32_t off = T0_POPi();
587 br_name_element *ne = &CTX->name_elts[off];
592 memcpy(ne->buf, CTX->pad + 1, len);
604 cc: copy-name-SAN ( bool tag -- ) {
605 unsigned tag = T0_POP();
606 unsigned ok = T0_POP();
610 for (u = 0; u < CTX->num_name_elts; u ++) {
613 ne = &CTX->name_elts[u];
614 if (ne->status == 0 && ne->oid[0] == 0 && ne->oid[1] == tag) {
615 if (ok && ne->len > len) {
616 memcpy(ne->buf, CTX->pad + 1, len);
627 \ Read a value, decoding string types. If the string type is recognised
628 \ and the value could be converted to UTF-8 into the pad, then true (-1)
629 \ is returned; in all other cases, false (0) is returned. Either way, the
630 \ object is consumed.
631 : read-string ( lim -- lim bool )
634 12 of check-primitive read-value-UTF8 endof
636 18 of check-primitive read-value-latin1 endof
638 19 of check-primitive read-value-latin1 endof
640 20 of check-primitive read-value-latin1 endof
642 22 of check-primitive read-value-latin1 endof
644 30 of check-primitive read-value-UTF16 endof
645 2drop read-length-skip 0 0
648 \ Read a DN for the EE. The normalized DN hash is computed and stored in the
650 \ Name elements are gathered. Also, the Common Name is matched against the
651 \ intended server name.
652 \ Returned value is true (-1) if the CN matches the intended server name,
653 \ false (0) otherwise.
654 : read-DN-EE ( lim -- lim bool )
655 \ Flag will be set to true if there is a CN and it matches the
656 \ intended server name.
659 \ Activate DN hashing.
662 \ Parse the DN structure: it is a SEQUENCE of SET of
663 \ AttributeTypeAndValue. Each AttributeTypeAndValue is a
664 \ SEQUENCE { OBJECT IDENTIFIER, ANY }.
669 read-tag 0x11 check-tag-constructed read-length-open-elt
670 dup ifnot ERR_X509_BAD_DN fail then
676 \ Read the OID. If the OID could not be read (too
677 \ long) then the first pad byte will be 0.
680 \ If it is the Common Name then we'll need to
681 \ match it against the intended server name (if
683 id-at-commonName eqOID { isCN }
685 \ Get offset for reception buffer for that element
687 0 offset-name-element { offbuf }
689 \ Try to read the value as a string.
692 \ If the value could be decoded as a string,
693 \ copy it and/or match it, as appropriate.
699 offbuf copy-name-element
709 \ Compute DN hash and deactivate DN hashing.
712 \ Return the CN match flag.
715 \ Get the validation date and time from the context or system.
716 cc: get-system-date ( -- days seconds ) {
717 if (CTX->days == 0 && CTX->seconds == 0) {
719 time_t x = time(NULL);
721 T0_PUSH((uint32_t)(x / 86400) + 719528);
722 T0_PUSH((uint32_t)(x % 86400));
723 #elif BR_USE_WIN32_TIME
727 GetSystemTimeAsFileTime(&ft);
728 x = ((uint64_t)ft.dwHighDateTime << 32)
729 + (uint64_t)ft.dwLowDateTime;
731 T0_PUSH((uint32_t)(x / 86400) + 584754);
732 T0_PUSH((uint32_t)(x % 86400));
734 CTX->err = BR_ERR_X509_TIME_UNKNOWN;
739 T0_PUSH(CTX->seconds);
743 \ Compare two dates (days+seconds) together.
744 : before ( days1 seconds1 days2 seconds2 -- bool )
746 d1 d2 = if s1 s2 < else d1 d2 < then ;
748 : after ( days1 seconds1 days2 seconds2 -- bool )
751 \ Swap the top two elements with the two elements immediately below.
752 : swap2 ( a b c d -- c d a b )
755 \ Match the name in the pad with the expected server name. Returned value
756 \ is true (-1) on match, false (0) otherwise. If there is no expected
757 \ server name, then 0 is returned.
758 \ Match conditions: either an exact match (case insensitive), or a
759 \ wildcard match, if the found name starts with "*.". We only match a
760 \ starting wildcard, and only against a complete DN name component.
761 cc: match-server-name ( -- bool ) {
764 if (CTX->server_name == NULL) {
768 n1 = strlen(CTX->server_name);
770 if (n1 == n2 && eqnocase(&CTX->pad[1], CTX->server_name, n1)) {
774 if (n2 >= 2 && CTX->pad[1] == '*' && CTX->pad[2] == '.') {
778 while (u < n1 && CTX->server_name[u] != '.') {
784 && eqnocase(&CTX->pad[3], CTX->server_name + u, n1))
793 \ Get the address and length for the pkey_data buffer.
794 : addr-len-pkey_data ( -- addr len )
795 CX 0 8191 { offsetof(br_x509_minimal_context, pkey_data) }
796 CX 0 8191 { BR_X509_BUFSIZE_KEY } ;
798 \ Copy the EE public key to the permanent buffer (RSA).
799 cc: copy-ee-rsa-pkey ( nlen elen -- ) {
800 size_t elen = T0_POP();
801 size_t nlen = T0_POP();
802 memcpy(CTX->ee_pkey_data, CTX->pkey_data, nlen + elen);
803 CTX->pkey.key_type = BR_KEYTYPE_RSA;
804 CTX->pkey.key.rsa.n = CTX->ee_pkey_data;
805 CTX->pkey.key.rsa.nlen = nlen;
806 CTX->pkey.key.rsa.e = CTX->ee_pkey_data + nlen;
807 CTX->pkey.key.rsa.elen = elen;
810 \ Copy the EE public key to the permanent buffer (EC).
811 cc: copy-ee-ec-pkey ( curve qlen -- ) {
812 size_t qlen = T0_POP();
813 uint32_t curve = T0_POP();
814 memcpy(CTX->ee_pkey_data, CTX->pkey_data, qlen);
815 CTX->pkey.key_type = BR_KEYTYPE_EC;
816 CTX->pkey.key.ec.curve = curve;
817 CTX->pkey.key.ec.q = CTX->ee_pkey_data;
818 CTX->pkey.key.ec.qlen = qlen;
821 \ Check whether the current certificate (EE) is directly trusted.
822 cc: check-direct-trust ( -- ) {
825 for (u = 0; u < CTX->trust_anchors_num; u ++) {
826 const br_x509_trust_anchor *ta;
827 unsigned char hashed_DN[64];
830 ta = &CTX->trust_anchors[u];
831 if (ta->flags & BR_X509_TA_CA) {
834 hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN);
835 if (memcmp(hashed_DN, CTX->current_dn_hash, DNHASH_LEN)) {
838 kt = CTX->pkey.key_type;
839 if ((ta->pkey.key_type & 0x0F) != kt) {
845 if (!eqbigint(CTX->pkey.key.rsa.n,
846 CTX->pkey.key.rsa.nlen,
848 ta->pkey.key.rsa.nlen)
849 || !eqbigint(CTX->pkey.key.rsa.e,
850 CTX->pkey.key.rsa.elen,
852 ta->pkey.key.rsa.elen))
859 if (CTX->pkey.key.ec.curve != ta->pkey.key.ec.curve
860 || CTX->pkey.key.ec.qlen != ta->pkey.key.ec.qlen
861 || memcmp(CTX->pkey.key.ec.q,
863 ta->pkey.key.ec.qlen) != 0)
874 * Direct trust match!
876 CTX->err = BR_ERR_X509_OK;
881 \ Check the signature on the certificate with regards to all trusted CA.
882 \ We use the issuer hash (in saved_dn_hash[]) as CA identifier.
883 cc: check-trust-anchor-CA ( -- ) {
886 for (u = 0; u < CTX->trust_anchors_num; u ++) {
887 const br_x509_trust_anchor *ta;
888 unsigned char hashed_DN[64];
890 ta = &CTX->trust_anchors[u];
891 if (!(ta->flags & BR_X509_TA_CA)) {
894 hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN);
895 if (memcmp(hashed_DN, CTX->saved_dn_hash, DNHASH_LEN)) {
898 if (verify_signature(CTX, &ta->pkey) == 0) {
899 CTX->err = BR_ERR_X509_OK;
905 \ Verify RSA signature. This uses the public key that was just decoded
906 \ into CTX->pkey_data; the modulus and exponent length are provided as
907 \ parameters. The resulting hash value is compared with the one in
908 \ tbs_hash. Returned value is 0 on success, or a non-zero error code.
909 cc: do-rsa-vrfy ( nlen elen -- err ) {
910 size_t elen = T0_POP();
911 size_t nlen = T0_POP();
914 pk.key_type = BR_KEYTYPE_RSA;
915 pk.key.rsa.n = CTX->pkey_data;
916 pk.key.rsa.nlen = nlen;
917 pk.key.rsa.e = CTX->pkey_data + nlen;
918 pk.key.rsa.elen = elen;
919 T0_PUSH(verify_signature(CTX, &pk));
922 \ Verify ECDSA signature. This uses the public key that was just decoded
923 \ into CTX->pkey_dayta; the curve ID and public point length are provided
924 \ as parameters. The hash value in tbs_hash is used. Returned value is 0
925 \ on success, or non-zero error code.
926 cc: do-ecdsa-vrfy ( curve qlen -- err ) {
927 size_t qlen = T0_POP();
928 int curve = T0_POP();
931 pk.key_type = BR_KEYTYPE_EC;
932 pk.key.ec.curve = curve;
933 pk.key.ec.q = CTX->pkey_data;
934 pk.key.ec.qlen = qlen;
935 T0_PUSH(verify_signature(CTX, &pk));
938 cc: print-bytes ( addr len -- ) {
939 extern int printf(const char *fmt, ...);
940 size_t len = T0_POP();
941 unsigned char *buf = (unsigned char *)CTX + T0_POP();
944 for (u = 0; u < len; u ++) {
945 printf("%02X", buf[u]);
949 cc: printOID ( -- ) {
950 extern int printf(const char *fmt, ...);
958 printf("%u.%u", CTX->pad[1] / 40, CTX->pad[1] % 40);
972 ul = (ul << 7) + (x & 0x7F);
981 \ Extensions with specific processing.
982 OID: basicConstraints 2.5.29.19
983 OID: keyUsage 2.5.29.15
984 OID: subjectAltName 2.5.29.17
985 OID: certificatePolicies 2.5.29.32
987 \ Policy qualifier "pointer to CPS"
988 OID: id-qt-cps 1.3.6.1.5.5.7.2.1
990 \ Extensions which are ignored when encountered, even if critical.
991 OID: authorityKeyIdentifier 2.5.29.35
992 OID: subjectKeyIdentifier 2.5.29.14
993 OID: issuerAltName 2.5.29.18
994 OID: subjectDirectoryAttributes 2.5.29.9
995 OID: crlDistributionPoints 2.5.29.31
996 OID: freshestCRL 2.5.29.46
997 OID: authorityInfoAccess 1.3.6.1.5.5.7.1.1
998 OID: subjectInfoAccess 1.3.6.1.5.5.7.1.11
1000 \ Process a Basic Constraints extension. This should be called only if
1001 \ the certificate is not the EE. We check that the extension contains
1002 \ the "CA" flag, and that the path length, if specified, is compatible
1003 \ with the current chain length.
1004 : process-basicConstraints ( lim -- lim )
1008 read-boolean ifnot ERR_X509_NOT_CA fail then
1011 ERR_X509_NOT_CA fail
1014 drop check-primitive read-small-int-value
1015 addr-num_certs get32 1- < if ERR_X509_NOT_CA fail then
1018 -1 <> if ERR_X509_UNEXPECTED fail then
1023 \ Process a Key Usage extension.
1024 \ For the EE certificate:
1025 \ -- if the key usage contains keyEncipherment (2), dataEncipherment (3)
1026 \ or keyAgreement (4), then the "key exchange" usage is allowed;
1027 \ -- if the key usage contains digitalSignature (0) or nonRepudiation (1),
1028 \ then the "signature" usage is allowed.
1029 \ For CA certificates, the extension must contain keyCertSign (5).
1030 : process-keyUsage ( lim ee -- lim )
1033 \ Read tag for the BIT STRING and open it.
1034 read-tag 0x03 check-tag-primitive
1035 read-length-open-elt
1036 \ First byte indicates number of ignored bits in the last byte. It
1037 \ must be between 0 and 7.
1039 ign 7 > if ERR_X509_UNEXPECTED fail then
1040 \ Depending on length, we have either 0, 1 or more bytes to read.
1042 0 of ERR_X509_FORBIDDEN_KEY_USAGE fail endof
1043 1 of read8 ign >> ign << endof
1051 over 0x38 and if 0x10 or then
1052 swap 0xC0 and if 0x20 or then
1053 addr-key_usages set8
1055 \ Not EE: keyCertSign must be set.
1056 0x04 and ifnot ERR_X509_FORBIDDEN_KEY_USAGE fail then
1059 \ We don't care about subsequent bytes.
1062 \ Process a Certificate Policies extension.
1064 \ Since we don't actually support full policies processing, this function
1065 \ only checks that the extension contents can be safely ignored. Indeed,
1066 \ we don't validate against a specific set of policies (in RFC 5280
1067 \ terminology, user-initial-policy-set only contains the special value
1068 \ any-policy). Moreover, we don't support policy constraints (if a
1069 \ critical Policy Constraints extension is encountered, the validation
1070 \ will fail). Therefore, we can safely ignore the contents of this
1071 \ extension, except if it is critical AND one of the policy OID has a
1072 \ qualifier which is distinct from id-qt-cps (because id-qt-cps is
1073 \ specially designated by RFC 5280 has having no mandated action).
1075 \ This function is called only if the extension is critical.
1076 : process-certPolicies ( lim -- lim )
1077 \ Extension value is a SEQUENCE OF PolicyInformation.
1080 \ PolicyInformation ::= SEQUENCE {
1081 \ policyIdentifier OBJECT IDENTIFIER,
1082 \ policyQualifiers SEQUENCE OF PolicyQualifierInfo OPTIONAL
1089 \ PolicyQualifierInfo ::= SEQUENCE {
1090 \ policyQualifierId OBJECT IDENTIFIER,
1094 read-OID drop id-qt-cps eqOID ifnot
1095 ERR_X509_CRITICAL_EXTENSION fail
1105 \ Process a Subject Alt Name extension. Returned value is a boolean set
1106 \ to true if the expected server name was matched against a dNSName in
1108 : process-SAN ( lim -- lim bool )
1112 \ Read the tag. If the tag is context-0, then parse an
1113 \ 'otherName'. If the tag is context-2, then parse a
1114 \ dNSName. If the tag is context-1 or context-6,
1119 \ OtherName ::= SEQUENCE {
1120 \ type-id OBJECT IDENTIFIER,
1121 \ value [0] EXPLICIT ANY
1123 check-constructed read-length-open-elt
1125 -1 offset-name-element { offbuf }
1126 read-tag 0x20 check-tag-constructed
1127 read-length-open-elt
1128 read-string offbuf copy-name-element
1132 \ rfc822Name (IA5String)
1135 read-value-UTF8 1 copy-name-SAN
1137 \ dNSName (IA5String)
1141 dup if match-server-name m or >m then
1144 \ uniformResourceIdentifier (IA5String)
1147 read-value-UTF8 6 copy-name-SAN
1149 2drop read-length-skip 0
1152 \ We check only names of type dNSName; they use IA5String,
1153 \ which is basically ASCII.
1154 \ read-tag 0x22 = if
1156 \ read-small-value drop
1157 \ match-server-name m or >m
1159 \ drop read-length-skip
1165 \ Decode a certificate. The "ee" boolean must be true for the EE.
1166 : decode-certificate ( ee -- )
1169 \ Obtain the total certificate length.
1170 addr-cert_length get32
1172 \ Open the outer SEQUENCE.
1180 \ First element may be an explicit version. We accept only
1181 \ versions 0 to 2 (certificates v1 to v3).
1182 read-tag dup 0x20 = if
1183 drop check-constructed read-length-open-elt
1185 0x02 check-tag-primitive
1186 read-small-int-value
1187 2 > if ERR_X509_UNSUPPORTED fail then
1192 \ Serial number. We just check that the tag is correct.
1193 0x02 check-tag-primitive
1196 \ Signature algorithm. This structure is redundant with the one
1197 \ on the outside; we just skip it.
1198 read-sequence-open skip-close-elt
1200 \ Issuer name: hashed, then copied into next_dn_hash[].
1202 addr-next_dn_hash addr-current_dn_hash dn-hash-length blobcopy
1206 read-date get-system-date after if ERR_X509_EXPIRED fail then
1207 read-date get-system-date before if ERR_X509_EXPIRED fail then
1212 \ For the EE, we must check whether the Common Name, if
1213 \ any, matches the expected server name.
1214 read-DN-EE { eename }
1216 \ For a non-EE certificate, the hashed subject DN must match
1217 \ the saved hashed issuer DN from the previous certificate.
1219 addr-current_dn_hash addr-saved_dn_hash dn-hash-length eqblob
1220 ifnot ERR_X509_DN_MISMATCH fail then
1222 \ Move the hashed issuer DN for this certificate into the
1223 \ saved_dn_hash[] array.
1224 addr-saved_dn_hash addr-next_dn_hash dn-hash-length blobcopy
1228 \ Algorithm Identifier. Right now we are only interested in the
1229 \ OID, since we only support RSA keys.
1231 read-OID ifnot ERR_X509_UNSUPPORTED fail then
1235 rsaEncryption eqOID uf
1237 \ Public key itself: the BIT STRING contains bytes
1238 \ (no partial byte) and these bytes encode the
1241 \ RSA public key is a SEQUENCE of two
1242 \ INTEGER. We get both INTEGER values into
1243 \ the pkey_data[] buffer, if they fit.
1246 read-integer { nlen }
1247 addr-len-pkey_data swap nlen + swap nlen -
1248 read-integer { elen }
1251 \ Check that the public key fits our minimal
1252 \ size requirements. Note that the integer
1253 \ decoder already skipped the leading bytes
1254 \ of value 0, so we are working on the true
1255 \ modulus length here.
1256 addr-min_rsa_size get16 128 + nlen > if
1257 ERR_X509_WEAK_PUBLIC_KEY fail
1260 KEYTYPE_RSA >pkey-type
1264 id-ecPublicKey eqOID uf
1265 \ We support only named curves, for which the
1266 \ "parameters" field in the AlgorithmIdentifier
1267 \ field should be an OID.
1268 read-OID ifnot ERR_X509_UNSUPPORTED fail then
1270 ansix9p256r1 eqOID uf 23 enduf
1271 ansix9p384r1 eqOID uf 24 enduf
1272 ansix9p521r1 eqOID uf 25 enduf
1273 ERR_X509_UNSUPPORTED fail
1279 dup addr-len-pkey_data rot < if
1280 ERR_X509_LIMIT_EXCEEDED fail
1283 KEYTYPE_EC >pkey-type
1286 \ Not a recognised public key type.
1287 ERR_X509_UNSUPPORTED fail
1291 \ Process public key.
1293 \ For the EE certificate, copy the key data to the
1296 KEYTYPE_RSA of nlen elen copy-ee-rsa-pkey endof
1297 KEYTYPE_EC of curve qlen copy-ee-ec-pkey endof
1298 ERR_X509_UNSUPPORTED fail
1301 \ Verify signature on previous certificate. We invoke
1302 \ the RSA implementation.
1304 KEYTYPE_RSA of nlen elen do-rsa-vrfy endof
1305 KEYTYPE_EC of curve qlen do-ecdsa-vrfy endof
1306 ERR_X509_UNSUPPORTED fail
1312 \ This flag will be set to true if the Basic Constraints extension
1316 \ Skip issuerUniqueID and subjectUniqueID, and process extensions
1317 \ if present. Extensions are an explicit context tag of value 3
1318 \ around a SEQUENCE OF extensions. Each extension is a SEQUENCE
1319 \ with an OID, an optional boolean, and a value; the value is
1326 check-constructed read-length-open-elt
1332 read-tag dup 0x01 = if
1333 read-boolean >critical
1336 0x04 check-tag-primitive read-length-open-elt
1338 \ Extensions with specific processing.
1339 basicConstraints eqOID uf
1343 process-basicConstraints
1350 subjectAltName eqOID uf
1359 \ We don't implement full processing of
1360 \ policies. The call below mostly checks
1361 \ that the contents of the Certificate
1362 \ Policies extension can be safely ignored.
1363 certificatePolicies eqOID uf
1365 process-certPolicies
1371 \ Extensions which are always ignored,
1373 authorityKeyIdentifier eqOID uf
1376 subjectKeyIdentifier eqOID uf
1379 issuerAltName eqOID uf
1382 subjectDirectoryAttributes eqOID uf
1385 crlDistributionPoints eqOID uf
1388 freshestCRL eqOID uf
1391 authorityInfoAccess eqOID uf
1394 subjectInfoAccess eqOID uf
1398 \ Unrecognized extensions trigger a failure
1399 \ if critical; otherwise, they are just
1402 ERR_X509_CRITICAL_EXTENSION fail
1412 -1 = ifnot ERR_X509_UNEXPECTED fail then
1417 \ Terminate hashing.
1420 \ For the EE certificate, verify that the intended server name
1423 eename zero-server-name or ifnot
1424 ERR_X509_BAD_SERVER_NAME fail
1428 \ If this is the EE certificate, then direct trust may apply.
1429 \ Note: we do this at this point, not immediately after decoding
1430 \ the public key, because even in case of direct trust we still
1431 \ want to check the server name with regards to the SAN extension.
1432 \ However, we want to check direct trust before trying to decode
1433 \ the signature algorithm, because it should work even if that
1434 \ algorithm is not supported.
1435 ee if check-direct-trust then
1437 \ Non-EE certificates MUST have a Basic Constraints extension
1438 \ (that marks them as being CA).
1439 ee seenBC or ifnot ERR_X509_NOT_CA fail then
1441 \ signature algorithm
1442 read-tag check-sequence read-length-open-elt
1443 \ Read and understand the OID. Right now, we support only
1444 \ RSA with PKCS#1 v1.5 padding, and hash functions SHA-1,
1445 \ SHA-224, SHA-256, SHA-384 and SHA-512. We purposely do NOT
1447 \ TODO: add support for RSA/PSS
1449 \ Based on the signature OID, we get:
1450 \ -- the signing key type
1451 \ -- the hash function numeric identifier
1452 \ -- the hash function OID
1454 sha1WithRSAEncryption eqOID
1455 uf 2 KEYTYPE_RSA id-sha1 enduf
1456 sha224WithRSAEncryption eqOID
1457 uf 3 KEYTYPE_RSA id-sha224 enduf
1458 sha256WithRSAEncryption eqOID
1459 uf 4 KEYTYPE_RSA id-sha256 enduf
1460 sha384WithRSAEncryption eqOID
1461 uf 5 KEYTYPE_RSA id-sha384 enduf
1462 sha512WithRSAEncryption eqOID
1463 uf 6 KEYTYPE_RSA id-sha512 enduf
1465 ecdsa-with-SHA1 eqOID
1466 uf 2 KEYTYPE_EC id-sha1 enduf
1467 ecdsa-with-SHA224 eqOID
1468 uf 3 KEYTYPE_EC id-sha224 enduf
1469 ecdsa-with-SHA256 eqOID
1470 uf 4 KEYTYPE_EC id-sha256 enduf
1471 ecdsa-with-SHA384 eqOID
1472 uf 5 KEYTYPE_EC id-sha384 enduf
1473 ecdsa-with-SHA512 eqOID
1474 uf 6 KEYTYPE_EC id-sha512 enduf
1475 ERR_X509_UNSUPPORTED fail
1477 addr-cert_sig_hash_oid set16
1478 addr-cert_signer_key_type set8
1480 \ Compute the TBS hash into tbs_hash.
1482 dup ifnot ERR_X509_UNSUPPORTED fail then
1483 addr-cert_sig_hash_len set8
1485 ERR_X509_UNSUPPORTED fail
1487 \ We ignore the parameters, whether they are present or not,
1488 \ because we got all the information from the OID.
1493 dup CX 0 8191 { BR_X509_BUFSIZE_SIG } > if
1494 ERR_X509_LIMIT_EXCEEDED fail
1496 dup addr-cert_sig_len set16
1497 addr-cert_sig read-blob
1499 \ Close the outer SEQUENCE.
1502 \ Close the advertised total certificate length. This checks that
1503 \ there is no trailing garbage after the certificate.
1506 \ Flag the certificate as fully processed.
1507 0 addr-cert_length set32
1509 \ Check whether the issuer for the current certificate is known
1510 \ as a trusted CA; in which case, verify the signature.
1511 check-trust-anchor-CA ;
1514 \ Unless restricted by a Key Usage extension, all usages are
1516 0x30 addr-key_usages set8
1517 -1 decode-certificate
1520 0 decode-certificate co