10957b409SSimon J. Gerraty\ Copyright (c) 2016 Thomas Pornin <pornin@bolet.org> 20957b409SSimon J. Gerraty\ 30957b409SSimon J. Gerraty\ Permission is hereby granted, free of charge, to any person obtaining 40957b409SSimon J. Gerraty\ a copy of this software and associated documentation files (the 50957b409SSimon J. Gerraty\ "Software"), to deal in the Software without restriction, including 60957b409SSimon J. Gerraty\ without limitation the rights to use, copy, modify, merge, publish, 70957b409SSimon J. Gerraty\ distribute, sublicense, and/or sell copies of the Software, and to 80957b409SSimon J. Gerraty\ permit persons to whom the Software is furnished to do so, subject to 90957b409SSimon J. Gerraty\ the following conditions: 100957b409SSimon J. Gerraty\ 110957b409SSimon J. Gerraty\ The above copyright notice and this permission notice shall be 120957b409SSimon J. Gerraty\ included in all copies or substantial portions of the Software. 130957b409SSimon J. Gerraty\ 140957b409SSimon J. Gerraty\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 150957b409SSimon J. Gerraty\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 160957b409SSimon J. Gerraty\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 170957b409SSimon J. Gerraty\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 180957b409SSimon J. Gerraty\ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 190957b409SSimon J. Gerraty\ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 200957b409SSimon J. Gerraty\ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 210957b409SSimon J. Gerraty\ SOFTWARE. 220957b409SSimon J. Gerraty 230957b409SSimon J. Gerratypreamble { 240957b409SSimon J. Gerraty 250957b409SSimon J. Gerraty#include "inner.h" 260957b409SSimon J. Gerraty 270957b409SSimon J. Gerraty/* 280957b409SSimon J. Gerraty * Implementation Notes 290957b409SSimon J. Gerraty * -------------------- 300957b409SSimon J. Gerraty * 310957b409SSimon J. Gerraty * The C code pushes the data by chunks; all decoding is done in the 320957b409SSimon J. Gerraty * T0 code. The cert_length value is set to the certificate length when 330957b409SSimon J. Gerraty * a new certificate is started; the T0 code picks it up as outer limit, 340957b409SSimon J. Gerraty * and decoding functions use it to ensure that no attempt is made at 350957b409SSimon J. Gerraty * reading past it. The T0 code also checks that once the certificate is 360957b409SSimon J. Gerraty * decoded, there are no trailing bytes. 370957b409SSimon J. Gerraty * 380957b409SSimon J. Gerraty * The T0 code sets cert_length to 0 when the certificate is fully 390957b409SSimon J. Gerraty * decoded. 400957b409SSimon J. Gerraty * 410957b409SSimon J. Gerraty * The C code must still perform two checks: 420957b409SSimon J. Gerraty * 430957b409SSimon J. Gerraty * -- If the certificate length is 0, then the T0 code will not be 440957b409SSimon J. Gerraty * invoked at all. This invalid condition must thus be reported by the 450957b409SSimon J. Gerraty * C code. 460957b409SSimon J. Gerraty * 470957b409SSimon J. Gerraty * -- When reaching the end of certificate, the C code must verify that 480957b409SSimon J. Gerraty * the certificate length has been set to 0, thereby signaling that 490957b409SSimon J. Gerraty * the T0 code properly decoded a certificate. 500957b409SSimon J. Gerraty * 510957b409SSimon J. Gerraty * Processing of a chain works in the following way: 520957b409SSimon J. Gerraty * 530957b409SSimon J. Gerraty * -- The error flag is set to a non-zero value when validation is 540957b409SSimon J. Gerraty * finished. The value is either BR_ERR_X509_OK (validation is 550957b409SSimon J. Gerraty * successful) or another non-zero error code. When a non-zero error 560957b409SSimon J. Gerraty * code is obtained, the remaining bytes in the current certificate and 570957b409SSimon J. Gerraty * the subsequent certificates (if any) are completely ignored. 580957b409SSimon J. Gerraty * 590957b409SSimon J. Gerraty * -- Each certificate is decoded in due course, with the following 600957b409SSimon J. Gerraty * "interesting points": 610957b409SSimon J. Gerraty * 620957b409SSimon J. Gerraty * -- Start of the TBS: the multihash engine is reset and activated. 630957b409SSimon J. Gerraty * 640957b409SSimon J. Gerraty * -- Start of the issuer DN: the secondary hash engine is started, 650957b409SSimon J. Gerraty * to process the encoded issuer DN. 660957b409SSimon J. Gerraty * 670957b409SSimon J. Gerraty * -- End of the issuer DN: the secondary hash engine is stopped. The 680957b409SSimon J. Gerraty * resulting hash value is computed and then copied into the 690957b409SSimon J. Gerraty * next_dn_hash[] buffer. 700957b409SSimon J. Gerraty * 710957b409SSimon J. Gerraty * -- Start of the subject DN: the secondary hash engine is started, 720957b409SSimon J. Gerraty * to process the encoded subject DN. 730957b409SSimon J. Gerraty * 740957b409SSimon J. Gerraty * -- For the EE certificate only: the Common Name, if any, is matched 750957b409SSimon J. Gerraty * against the expected server name. 760957b409SSimon J. Gerraty * 770957b409SSimon J. Gerraty * -- End of the subject DN: the secondary hash engine is stopped. The 780957b409SSimon J. Gerraty * resulting hash value is computed into the pad. It is then processed: 790957b409SSimon J. Gerraty * 800957b409SSimon J. Gerraty * -- If this is the EE certificate, then the hash is ignored 810957b409SSimon J. Gerraty * (except for direct trust processing, see later; the hash is 820957b409SSimon J. Gerraty * simply left in current_dn_hash[]). 830957b409SSimon J. Gerraty * 840957b409SSimon J. Gerraty * -- Otherwise, the hashed subject DN is compared with the saved 850957b409SSimon J. Gerraty * hash value (in saved_dn_hash[]). They must match. 860957b409SSimon J. Gerraty * 870957b409SSimon J. Gerraty * Either way, the next_dn_hash[] value is then copied into the 880957b409SSimon J. Gerraty * saved_dn_hash[] value. Thus, at that point, saved_dn_hash[] 890957b409SSimon J. Gerraty * contains the hash of the issuer DN for the current certificate, 900957b409SSimon J. Gerraty * and current_dn_hash[] contains the hash of the subject DN for the 910957b409SSimon J. Gerraty * current certificate. 920957b409SSimon J. Gerraty * 930957b409SSimon J. Gerraty * -- Public key: it is decoded into the cert_pkey[] buffer. Unknown 940957b409SSimon J. Gerraty * key types are reported at that point. 950957b409SSimon J. Gerraty * 960957b409SSimon J. Gerraty * -- If this is the EE certificate, then the key type is compared 970957b409SSimon J. Gerraty * with the expected key type (initialization parameter). The public 980957b409SSimon J. Gerraty * key data is copied to ee_pkey_data[]. The key and hashed subject 990957b409SSimon J. Gerraty * DN are also compared with the "direct trust" keys; if the key 1000957b409SSimon J. Gerraty * and DN are matched, then validation ends with a success. 1010957b409SSimon J. Gerraty * 1020957b409SSimon J. Gerraty * -- Otherwise, the saved signature (cert_sig[]) is verified 1030957b409SSimon J. Gerraty * against the saved TBS hash (tbs_hash[]) and that freshly 1040957b409SSimon J. Gerraty * decoded public key. Failure here ends validation with an error. 1050957b409SSimon J. Gerraty * 1060957b409SSimon J. Gerraty * -- Extensions: extension values are processed in due order. 1070957b409SSimon J. Gerraty * 1080957b409SSimon J. Gerraty * -- Basic Constraints: for all certificates except EE, must be 109*cc9e6590SSimon J. Gerraty * present, indicate a CA, and have a path length compatible with 1100957b409SSimon J. Gerraty * the chain length so far. 1110957b409SSimon J. Gerraty * 1120957b409SSimon J. Gerraty * -- Key Usage: for the EE, if present, must allow signatures 1130957b409SSimon J. Gerraty * or encryption/key exchange, as required for the cipher suite. 1140957b409SSimon J. Gerraty * For non-EE, if present, must have the "certificate sign" bit. 1150957b409SSimon J. Gerraty * 1160957b409SSimon J. Gerraty * -- Subject Alt Name: for the EE, dNSName names are matched 1170957b409SSimon J. Gerraty * against the server name. Ignored for non-EE. 1180957b409SSimon J. Gerraty * 1190957b409SSimon J. Gerraty * -- Authority Key Identifier, Subject Key Identifier, Issuer 1200957b409SSimon J. Gerraty * Alt Name, Subject Directory Attributes, CRL Distribution Points 1210957b409SSimon J. Gerraty * Freshest CRL, Authority Info Access and Subject Info Access 1220957b409SSimon J. Gerraty * extensions are always ignored: they either contain only 1230957b409SSimon J. Gerraty * informative data, or they relate to revocation processing, which 1240957b409SSimon J. Gerraty * we explicitly do not support. 1250957b409SSimon J. Gerraty * 1260957b409SSimon J. Gerraty * -- All other extensions are ignored if non-critical. If a 1270957b409SSimon J. Gerraty * critical extension other than the ones above is encountered, 1280957b409SSimon J. Gerraty * then a failure is reported. 1290957b409SSimon J. Gerraty * 1300957b409SSimon J. Gerraty * -- End of the TBS: the multihash engine is stopped. 1310957b409SSimon J. Gerraty * 1320957b409SSimon J. Gerraty * -- Signature algorithm: the signature algorithm on the 1330957b409SSimon J. Gerraty * certificate is decoded. A failure is reported if that algorithm 1340957b409SSimon J. Gerraty * is unknown. The hashed TBS corresponding to the signature hash 1350957b409SSimon J. Gerraty * function is computed and stored in tbs_hash[] (if not supported, 1360957b409SSimon J. Gerraty * then a failure is reported). The hash OID and length are stored 1370957b409SSimon J. Gerraty * in cert_sig_hash_oid and cert_sig_hash_len. 1380957b409SSimon J. Gerraty * 1390957b409SSimon J. Gerraty * -- Signature value: the signature value is copied into the 1400957b409SSimon J. Gerraty * cert_sig[] array. 1410957b409SSimon J. Gerraty * 1420957b409SSimon J. Gerraty * -- Certificate end: the hashed issuer DN (saved_dn_hash[]) is 1430957b409SSimon J. Gerraty * looked up in the trust store (CA trust anchors only); for all 1440957b409SSimon J. Gerraty * that match, the signature (cert_sig[]) is verified against the 1450957b409SSimon J. Gerraty * anchor public key (hashed TBS is in tbs_hash[]). If one of these 1460957b409SSimon J. Gerraty * signatures is valid, then validation ends with a success. 1470957b409SSimon J. Gerraty * 1480957b409SSimon J. Gerraty * -- If the chain end is reached without obtaining a validation success, 1490957b409SSimon J. Gerraty * then validation is reported as failed. 1500957b409SSimon J. Gerraty */ 1510957b409SSimon J. Gerraty 1520957b409SSimon J. Gerraty#if BR_USE_UNIX_TIME 1530957b409SSimon J. Gerraty#include <time.h> 1540957b409SSimon J. Gerraty#endif 1550957b409SSimon J. Gerraty 1560957b409SSimon J. Gerraty#if BR_USE_WIN32_TIME 1570957b409SSimon J. Gerraty#include <windows.h> 1580957b409SSimon J. Gerraty#endif 1590957b409SSimon J. Gerraty 1600957b409SSimon J. Gerraty/* 1610957b409SSimon J. Gerraty * The T0 compiler will produce these prototypes declarations in the 1620957b409SSimon J. Gerraty * header. 1630957b409SSimon J. Gerraty * 1640957b409SSimon J. Gerratyvoid br_x509_minimal_init_main(void *ctx); 1650957b409SSimon J. Gerratyvoid br_x509_minimal_run(void *ctx); 1660957b409SSimon J. Gerraty */ 1670957b409SSimon J. Gerraty 1680957b409SSimon J. Gerraty/* see bearssl_x509.h */ 1690957b409SSimon J. Gerratyvoid 1700957b409SSimon J. Gerratybr_x509_minimal_init(br_x509_minimal_context *ctx, 1710957b409SSimon J. Gerraty const br_hash_class *dn_hash_impl, 1720957b409SSimon J. Gerraty const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num) 1730957b409SSimon J. Gerraty{ 1740957b409SSimon J. Gerraty memset(ctx, 0, sizeof *ctx); 1750957b409SSimon J. Gerraty ctx->vtable = &br_x509_minimal_vtable; 1760957b409SSimon J. Gerraty ctx->dn_hash_impl = dn_hash_impl; 1770957b409SSimon J. Gerraty ctx->trust_anchors = trust_anchors; 1780957b409SSimon J. Gerraty ctx->trust_anchors_num = trust_anchors_num; 1790957b409SSimon J. Gerraty} 1800957b409SSimon J. Gerraty 1810957b409SSimon J. Gerratystatic void 1820957b409SSimon J. Gerratyxm_start_chain(const br_x509_class **ctx, const char *server_name) 1830957b409SSimon J. Gerraty{ 1840957b409SSimon J. Gerraty br_x509_minimal_context *cc; 1850957b409SSimon J. Gerraty size_t u; 1860957b409SSimon J. Gerraty 1870957b409SSimon J. Gerraty cc = (br_x509_minimal_context *)(void *)ctx; 1880957b409SSimon J. Gerraty for (u = 0; u < cc->num_name_elts; u ++) { 1890957b409SSimon J. Gerraty cc->name_elts[u].status = 0; 1900957b409SSimon J. Gerraty cc->name_elts[u].buf[0] = 0; 1910957b409SSimon J. Gerraty } 1920957b409SSimon J. Gerraty memset(&cc->pkey, 0, sizeof cc->pkey); 1930957b409SSimon J. Gerraty cc->num_certs = 0; 1940957b409SSimon J. Gerraty cc->err = 0; 1950957b409SSimon J. Gerraty cc->cpu.dp = cc->dp_stack; 1960957b409SSimon J. Gerraty cc->cpu.rp = cc->rp_stack; 1970957b409SSimon J. Gerraty br_x509_minimal_init_main(&cc->cpu); 1980957b409SSimon J. Gerraty if (server_name == NULL || *server_name == 0) { 1990957b409SSimon J. Gerraty cc->server_name = NULL; 2000957b409SSimon J. Gerraty } else { 2010957b409SSimon J. Gerraty cc->server_name = server_name; 2020957b409SSimon J. Gerraty } 2030957b409SSimon J. Gerraty} 2040957b409SSimon J. Gerraty 2050957b409SSimon J. Gerratystatic void 2060957b409SSimon J. Gerratyxm_start_cert(const br_x509_class **ctx, uint32_t length) 2070957b409SSimon J. Gerraty{ 2080957b409SSimon J. Gerraty br_x509_minimal_context *cc; 2090957b409SSimon J. Gerraty 2100957b409SSimon J. Gerraty cc = (br_x509_minimal_context *)(void *)ctx; 2110957b409SSimon J. Gerraty if (cc->err != 0) { 2120957b409SSimon J. Gerraty return; 2130957b409SSimon J. Gerraty } 2140957b409SSimon J. Gerraty if (length == 0) { 2150957b409SSimon J. Gerraty cc->err = BR_ERR_X509_TRUNCATED; 2160957b409SSimon J. Gerraty return; 2170957b409SSimon J. Gerraty } 2180957b409SSimon J. Gerraty cc->cert_length = length; 2190957b409SSimon J. Gerraty} 2200957b409SSimon J. Gerraty 2210957b409SSimon J. Gerratystatic void 2220957b409SSimon J. Gerratyxm_append(const br_x509_class **ctx, const unsigned char *buf, size_t len) 2230957b409SSimon J. Gerraty{ 2240957b409SSimon J. Gerraty br_x509_minimal_context *cc; 2250957b409SSimon J. Gerraty 2260957b409SSimon J. Gerraty cc = (br_x509_minimal_context *)(void *)ctx; 2270957b409SSimon J. Gerraty if (cc->err != 0) { 2280957b409SSimon J. Gerraty return; 2290957b409SSimon J. Gerraty } 2300957b409SSimon J. Gerraty cc->hbuf = buf; 2310957b409SSimon J. Gerraty cc->hlen = len; 2320957b409SSimon J. Gerraty br_x509_minimal_run(&cc->cpu); 2330957b409SSimon J. Gerraty} 2340957b409SSimon J. Gerraty 2350957b409SSimon J. Gerratystatic void 2360957b409SSimon J. Gerratyxm_end_cert(const br_x509_class **ctx) 2370957b409SSimon J. Gerraty{ 2380957b409SSimon J. Gerraty br_x509_minimal_context *cc; 2390957b409SSimon J. Gerraty 2400957b409SSimon J. Gerraty cc = (br_x509_minimal_context *)(void *)ctx; 2410957b409SSimon J. Gerraty if (cc->err == 0 && cc->cert_length != 0) { 2420957b409SSimon J. Gerraty cc->err = BR_ERR_X509_TRUNCATED; 2430957b409SSimon J. Gerraty } 2440957b409SSimon J. Gerraty cc->num_certs ++; 2450957b409SSimon J. Gerraty} 2460957b409SSimon J. Gerraty 2470957b409SSimon J. Gerratystatic unsigned 2480957b409SSimon J. Gerratyxm_end_chain(const br_x509_class **ctx) 2490957b409SSimon J. Gerraty{ 2500957b409SSimon J. Gerraty br_x509_minimal_context *cc; 2510957b409SSimon J. Gerraty 2520957b409SSimon J. Gerraty cc = (br_x509_minimal_context *)(void *)ctx; 2530957b409SSimon J. Gerraty if (cc->err == 0) { 2540957b409SSimon J. Gerraty if (cc->num_certs == 0) { 2550957b409SSimon J. Gerraty cc->err = BR_ERR_X509_EMPTY_CHAIN; 2560957b409SSimon J. Gerraty } else { 2570957b409SSimon J. Gerraty cc->err = BR_ERR_X509_NOT_TRUSTED; 2580957b409SSimon J. Gerraty } 2590957b409SSimon J. Gerraty } else if (cc->err == BR_ERR_X509_OK) { 2600957b409SSimon J. Gerraty return 0; 2610957b409SSimon J. Gerraty } 2620957b409SSimon J. Gerraty return (unsigned)cc->err; 2630957b409SSimon J. Gerraty} 2640957b409SSimon J. Gerraty 2650957b409SSimon J. Gerratystatic const br_x509_pkey * 2660957b409SSimon J. Gerratyxm_get_pkey(const br_x509_class *const *ctx, unsigned *usages) 2670957b409SSimon J. Gerraty{ 2680957b409SSimon J. Gerraty br_x509_minimal_context *cc; 2690957b409SSimon J. Gerraty 2700957b409SSimon J. Gerraty cc = (br_x509_minimal_context *)(void *)ctx; 2710957b409SSimon J. Gerraty if (cc->err == BR_ERR_X509_OK 2720957b409SSimon J. Gerraty || cc->err == BR_ERR_X509_NOT_TRUSTED) 2730957b409SSimon J. Gerraty { 2740957b409SSimon J. Gerraty if (usages != NULL) { 2750957b409SSimon J. Gerraty *usages = cc->key_usages; 2760957b409SSimon J. Gerraty } 2770957b409SSimon J. Gerraty return &((br_x509_minimal_context *)(void *)ctx)->pkey; 2780957b409SSimon J. Gerraty } else { 2790957b409SSimon J. Gerraty return NULL; 2800957b409SSimon J. Gerraty } 2810957b409SSimon J. Gerraty} 2820957b409SSimon J. Gerraty 2830957b409SSimon J. Gerraty/* see bearssl_x509.h */ 2840957b409SSimon J. Gerratyconst br_x509_class br_x509_minimal_vtable = { 2850957b409SSimon J. Gerraty sizeof(br_x509_minimal_context), 2860957b409SSimon J. Gerraty xm_start_chain, 2870957b409SSimon J. Gerraty xm_start_cert, 2880957b409SSimon J. Gerraty xm_append, 2890957b409SSimon J. Gerraty xm_end_cert, 2900957b409SSimon J. Gerraty xm_end_chain, 2910957b409SSimon J. Gerraty xm_get_pkey 2920957b409SSimon J. Gerraty}; 2930957b409SSimon J. Gerraty 2940957b409SSimon J. Gerraty#define CTX ((br_x509_minimal_context *)(void *)((unsigned char *)t0ctx - offsetof(br_x509_minimal_context, cpu))) 2950957b409SSimon J. Gerraty#define CONTEXT_NAME br_x509_minimal_context 2960957b409SSimon J. Gerraty 2970957b409SSimon J. Gerraty#define DNHASH_LEN ((CTX->dn_hash_impl->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK) 2980957b409SSimon J. Gerraty 2990957b409SSimon J. Gerraty/* 3000957b409SSimon J. Gerraty * Hash a DN (from a trust anchor) into the provided buffer. This uses the 3010957b409SSimon J. Gerraty * DN hash implementation and context structure from the X.509 engine 3020957b409SSimon J. Gerraty * context. 3030957b409SSimon J. Gerraty */ 3040957b409SSimon J. Gerratystatic void 3050957b409SSimon J. Gerratyhash_dn(br_x509_minimal_context *ctx, const void *dn, size_t len, 3060957b409SSimon J. Gerraty unsigned char *out) 3070957b409SSimon J. Gerraty{ 3080957b409SSimon J. Gerraty ctx->dn_hash_impl->init(&ctx->dn_hash.vtable); 3090957b409SSimon J. Gerraty ctx->dn_hash_impl->update(&ctx->dn_hash.vtable, dn, len); 3100957b409SSimon J. Gerraty ctx->dn_hash_impl->out(&ctx->dn_hash.vtable, out); 3110957b409SSimon J. Gerraty} 3120957b409SSimon J. Gerraty 3130957b409SSimon J. Gerraty/* 3140957b409SSimon J. Gerraty * Compare two big integers for equality. The integers use unsigned big-endian 3150957b409SSimon J. Gerraty * encoding; extra leading bytes (of value 0) are allowed. 3160957b409SSimon J. Gerraty */ 3170957b409SSimon J. Gerratystatic int 3180957b409SSimon J. Gerratyeqbigint(const unsigned char *b1, size_t len1, 3190957b409SSimon J. Gerraty const unsigned char *b2, size_t len2) 3200957b409SSimon J. Gerraty{ 3210957b409SSimon J. Gerraty while (len1 > 0 && *b1 == 0) { 3220957b409SSimon J. Gerraty b1 ++; 3230957b409SSimon J. Gerraty len1 --; 3240957b409SSimon J. Gerraty } 3250957b409SSimon J. Gerraty while (len2 > 0 && *b2 == 0) { 3260957b409SSimon J. Gerraty b2 ++; 3270957b409SSimon J. Gerraty len2 --; 3280957b409SSimon J. Gerraty } 3290957b409SSimon J. Gerraty if (len1 != len2) { 3300957b409SSimon J. Gerraty return 0; 3310957b409SSimon J. Gerraty } 3320957b409SSimon J. Gerraty return memcmp(b1, b2, len1) == 0; 3330957b409SSimon J. Gerraty} 3340957b409SSimon J. Gerraty 3350957b409SSimon J. Gerraty/* 3360957b409SSimon J. Gerraty * Compare two strings for equality, in a case-insensitive way. This 3370957b409SSimon J. Gerraty * function handles casing only for ASCII letters. 3380957b409SSimon J. Gerraty */ 3390957b409SSimon J. Gerratystatic int 3400957b409SSimon J. Gerratyeqnocase(const void *s1, const void *s2, size_t len) 3410957b409SSimon J. Gerraty{ 3420957b409SSimon J. Gerraty const unsigned char *buf1, *buf2; 3430957b409SSimon J. Gerraty 3440957b409SSimon J. Gerraty buf1 = s1; 3450957b409SSimon J. Gerraty buf2 = s2; 3460957b409SSimon J. Gerraty while (len -- > 0) { 3470957b409SSimon J. Gerraty int x1, x2; 3480957b409SSimon J. Gerraty 3490957b409SSimon J. Gerraty x1 = *buf1 ++; 3500957b409SSimon J. Gerraty x2 = *buf2 ++; 3510957b409SSimon J. Gerraty if (x1 >= 'A' && x1 <= 'Z') { 3520957b409SSimon J. Gerraty x1 += 'a' - 'A'; 3530957b409SSimon J. Gerraty } 3540957b409SSimon J. Gerraty if (x2 >= 'A' && x2 <= 'Z') { 3550957b409SSimon J. Gerraty x2 += 'a' - 'A'; 3560957b409SSimon J. Gerraty } 3570957b409SSimon J. Gerraty if (x1 != x2) { 3580957b409SSimon J. Gerraty return 0; 3590957b409SSimon J. Gerraty } 3600957b409SSimon J. Gerraty } 3610957b409SSimon J. Gerraty return 1; 3620957b409SSimon J. Gerraty} 3630957b409SSimon J. Gerraty 3640957b409SSimon J. Gerratystatic int verify_signature(br_x509_minimal_context *ctx, 3650957b409SSimon J. Gerraty const br_x509_pkey *pk); 3660957b409SSimon J. Gerraty 3670957b409SSimon J. Gerraty} 3680957b409SSimon J. Gerraty 3690957b409SSimon J. Gerratypostamble { 3700957b409SSimon J. Gerraty 3710957b409SSimon J. Gerraty/* 3720957b409SSimon J. Gerraty * Verify the signature on the certificate with the provided public key. 3730957b409SSimon J. Gerraty * This function checks the public key type with regards to the expected 3740957b409SSimon J. Gerraty * type. Returned value is either 0 on success, or a non-zero error code. 3750957b409SSimon J. Gerraty */ 3760957b409SSimon J. Gerratystatic int 3770957b409SSimon J. Gerratyverify_signature(br_x509_minimal_context *ctx, const br_x509_pkey *pk) 3780957b409SSimon J. Gerraty{ 3790957b409SSimon J. Gerraty int kt; 3800957b409SSimon J. Gerraty 3810957b409SSimon J. Gerraty kt = ctx->cert_signer_key_type; 3820957b409SSimon J. Gerraty if ((pk->key_type & 0x0F) != kt) { 3830957b409SSimon J. Gerraty return BR_ERR_X509_WRONG_KEY_TYPE; 3840957b409SSimon J. Gerraty } 3850957b409SSimon J. Gerraty switch (kt) { 3860957b409SSimon J. Gerraty unsigned char tmp[64]; 3870957b409SSimon J. Gerraty 3880957b409SSimon J. Gerraty case BR_KEYTYPE_RSA: 3890957b409SSimon J. Gerraty if (ctx->irsa == 0) { 3900957b409SSimon J. Gerraty return BR_ERR_X509_UNSUPPORTED; 3910957b409SSimon J. Gerraty } 3920957b409SSimon J. Gerraty if (!ctx->irsa(ctx->cert_sig, ctx->cert_sig_len, 3930957b409SSimon J. Gerraty &t0_datablock[ctx->cert_sig_hash_oid], 3940957b409SSimon J. Gerraty ctx->cert_sig_hash_len, &pk->key.rsa, tmp)) 3950957b409SSimon J. Gerraty { 3960957b409SSimon J. Gerraty return BR_ERR_X509_BAD_SIGNATURE; 3970957b409SSimon J. Gerraty } 3980957b409SSimon J. Gerraty if (memcmp(ctx->tbs_hash, tmp, ctx->cert_sig_hash_len) != 0) { 3990957b409SSimon J. Gerraty return BR_ERR_X509_BAD_SIGNATURE; 4000957b409SSimon J. Gerraty } 4010957b409SSimon J. Gerraty return 0; 4020957b409SSimon J. Gerraty 4030957b409SSimon J. Gerraty case BR_KEYTYPE_EC: 4040957b409SSimon J. Gerraty if (ctx->iecdsa == 0) { 4050957b409SSimon J. Gerraty return BR_ERR_X509_UNSUPPORTED; 4060957b409SSimon J. Gerraty } 4070957b409SSimon J. Gerraty if (!ctx->iecdsa(ctx->iec, ctx->tbs_hash, 4080957b409SSimon J. Gerraty ctx->cert_sig_hash_len, &pk->key.ec, 4090957b409SSimon J. Gerraty ctx->cert_sig, ctx->cert_sig_len)) 4100957b409SSimon J. Gerraty { 4110957b409SSimon J. Gerraty return BR_ERR_X509_BAD_SIGNATURE; 4120957b409SSimon J. Gerraty } 4130957b409SSimon J. Gerraty return 0; 4140957b409SSimon J. Gerraty 4150957b409SSimon J. Gerraty default: 4160957b409SSimon J. Gerraty return BR_ERR_X509_UNSUPPORTED; 4170957b409SSimon J. Gerraty } 4180957b409SSimon J. Gerraty} 4190957b409SSimon J. Gerraty 4200957b409SSimon J. Gerraty} 4210957b409SSimon J. Gerraty 4220957b409SSimon J. Gerratycc: read8-low ( -- x ) { 4230957b409SSimon J. Gerraty if (CTX->hlen == 0) { 4240957b409SSimon J. Gerraty T0_PUSHi(-1); 4250957b409SSimon J. Gerraty } else { 4260957b409SSimon J. Gerraty unsigned char x = *CTX->hbuf ++; 4270957b409SSimon J. Gerraty if (CTX->do_mhash) { 4280957b409SSimon J. Gerraty br_multihash_update(&CTX->mhash, &x, 1); 4290957b409SSimon J. Gerraty } 4300957b409SSimon J. Gerraty if (CTX->do_dn_hash) { 4310957b409SSimon J. Gerraty CTX->dn_hash_impl->update(&CTX->dn_hash.vtable, &x, 1); 4320957b409SSimon J. Gerraty } 4330957b409SSimon J. Gerraty CTX->hlen --; 4340957b409SSimon J. Gerraty T0_PUSH(x); 4350957b409SSimon J. Gerraty } 4360957b409SSimon J. Gerraty} 4370957b409SSimon J. Gerraty 4380957b409SSimon J. Gerratyaddr: cert_length 4390957b409SSimon J. Gerratyaddr: num_certs 4400957b409SSimon J. Gerraty 4410957b409SSimon J. Gerratycc: read-blob-inner ( addr len -- addr len ) { 4420957b409SSimon J. Gerraty uint32_t len = T0_POP(); 4430957b409SSimon J. Gerraty uint32_t addr = T0_POP(); 4440957b409SSimon J. Gerraty size_t clen = CTX->hlen; 4450957b409SSimon J. Gerraty if (clen > len) { 4460957b409SSimon J. Gerraty clen = (size_t)len; 4470957b409SSimon J. Gerraty } 4480957b409SSimon J. Gerraty if (addr != 0) { 4490957b409SSimon J. Gerraty memcpy((unsigned char *)CTX + addr, CTX->hbuf, clen); 4500957b409SSimon J. Gerraty } 4510957b409SSimon J. Gerraty if (CTX->do_mhash) { 4520957b409SSimon J. Gerraty br_multihash_update(&CTX->mhash, CTX->hbuf, clen); 4530957b409SSimon J. Gerraty } 4540957b409SSimon J. Gerraty if (CTX->do_dn_hash) { 4550957b409SSimon J. Gerraty CTX->dn_hash_impl->update( 4560957b409SSimon J. Gerraty &CTX->dn_hash.vtable, CTX->hbuf, clen); 4570957b409SSimon J. Gerraty } 4580957b409SSimon J. Gerraty CTX->hbuf += clen; 4590957b409SSimon J. Gerraty CTX->hlen -= clen; 4600957b409SSimon J. Gerraty T0_PUSH(addr + clen); 4610957b409SSimon J. Gerraty T0_PUSH(len - clen); 4620957b409SSimon J. Gerraty} 4630957b409SSimon J. Gerraty 4640957b409SSimon J. Gerraty\ Compute the TBS hash, using the provided hash ID. The hash value is 4650957b409SSimon J. Gerraty\ written in the tbs_hash[] array, and the hash length is returned. If 4660957b409SSimon J. Gerraty\ the requested hash function is not supported, then 0 is returned. 4670957b409SSimon J. Gerratycc: compute-tbs-hash ( id -- hashlen ) { 4680957b409SSimon J. Gerraty int id = T0_POPi(); 4690957b409SSimon J. Gerraty size_t len; 4700957b409SSimon J. Gerraty len = br_multihash_out(&CTX->mhash, id, CTX->tbs_hash); 4710957b409SSimon J. Gerraty T0_PUSH(len); 4720957b409SSimon J. Gerraty} 4730957b409SSimon J. Gerraty 4740957b409SSimon J. Gerraty\ Push true (-1) if no server name is expected in the EE certificate. 4750957b409SSimon J. Gerratycc: zero-server-name ( -- bool ) { 4760957b409SSimon J. Gerraty T0_PUSHi(-(CTX->server_name == NULL)); 4770957b409SSimon J. Gerraty} 4780957b409SSimon J. Gerraty 4790957b409SSimon J. Gerratyaddr: key_usages 4800957b409SSimon J. Gerratyaddr: cert_sig 4810957b409SSimon J. Gerratyaddr: cert_sig_len 4820957b409SSimon J. Gerratyaddr: cert_signer_key_type 4830957b409SSimon J. Gerratyaddr: cert_sig_hash_oid 4840957b409SSimon J. Gerratyaddr: cert_sig_hash_len 4850957b409SSimon J. Gerratyaddr: tbs_hash 4860957b409SSimon J. Gerratyaddr: min_rsa_size 4870957b409SSimon J. Gerraty 4880957b409SSimon J. Gerraty\ Start TBS hash computation. The hash functions are reinitialised. 4890957b409SSimon J. Gerratycc: start-tbs-hash ( -- ) { 4900957b409SSimon J. Gerraty br_multihash_init(&CTX->mhash); 4910957b409SSimon J. Gerraty CTX->do_mhash = 1; 4920957b409SSimon J. Gerraty} 4930957b409SSimon J. Gerraty 4940957b409SSimon J. Gerraty\ Stop TBS hash computation. 4950957b409SSimon J. Gerratycc: stop-tbs-hash ( -- ) { 4960957b409SSimon J. Gerraty CTX->do_mhash = 0; 4970957b409SSimon J. Gerraty} 4980957b409SSimon J. Gerraty 4990957b409SSimon J. Gerraty\ Start DN hash computation. 5000957b409SSimon J. Gerratycc: start-dn-hash ( -- ) { 5010957b409SSimon J. Gerraty CTX->dn_hash_impl->init(&CTX->dn_hash.vtable); 5020957b409SSimon J. Gerraty CTX->do_dn_hash = 1; 5030957b409SSimon J. Gerraty} 5040957b409SSimon J. Gerraty 5050957b409SSimon J. Gerraty\ Terminate DN hash computation and write the DN hash into the 5060957b409SSimon J. Gerraty\ current_dn_hash buffer. 5070957b409SSimon J. Gerratycc: compute-dn-hash ( -- ) { 5080957b409SSimon J. Gerraty CTX->dn_hash_impl->out(&CTX->dn_hash.vtable, CTX->current_dn_hash); 5090957b409SSimon J. Gerraty CTX->do_dn_hash = 0; 5100957b409SSimon J. Gerraty} 5110957b409SSimon J. Gerraty 5120957b409SSimon J. Gerraty\ Get the length of hash values obtained with the DN hasher. 5130957b409SSimon J. Gerratycc: dn-hash-length ( -- len ) { 5140957b409SSimon J. Gerraty T0_PUSH(DNHASH_LEN); 5150957b409SSimon J. Gerraty} 5160957b409SSimon J. Gerraty 5170957b409SSimon J. Gerraty\ Copy data between two areas in the context. 5180957b409SSimon J. Gerratycc: blobcopy ( addr-dst addr-src len -- ) { 5190957b409SSimon J. Gerraty size_t len = T0_POP(); 5200957b409SSimon J. Gerraty unsigned char *src = (unsigned char *)CTX + T0_POP(); 5210957b409SSimon J. Gerraty unsigned char *dst = (unsigned char *)CTX + T0_POP(); 5220957b409SSimon J. Gerraty memcpy(dst, src, len); 5230957b409SSimon J. Gerraty} 5240957b409SSimon J. Gerraty 5250957b409SSimon J. Gerratyaddr: current_dn_hash 5260957b409SSimon J. Gerratyaddr: next_dn_hash 5270957b409SSimon J. Gerratyaddr: saved_dn_hash 5280957b409SSimon J. Gerraty 5290957b409SSimon J. Gerraty\ Read a DN, hashing it into current_dn_hash. The DN contents are not 5300957b409SSimon J. Gerraty\ inspected (only the outer tag, for SEQUENCE, is checked). 5310957b409SSimon J. Gerraty: read-DN ( lim -- lim ) 5320957b409SSimon J. Gerraty start-dn-hash 5330957b409SSimon J. Gerraty read-sequence-open skip-close-elt 5340957b409SSimon J. Gerraty compute-dn-hash ; 5350957b409SSimon J. Gerraty 5360957b409SSimon J. Gerratycc: offset-name-element ( san -- n ) { 5370957b409SSimon J. Gerraty unsigned san = T0_POP(); 5380957b409SSimon J. Gerraty size_t u; 5390957b409SSimon J. Gerraty 5400957b409SSimon J. Gerraty for (u = 0; u < CTX->num_name_elts; u ++) { 5410957b409SSimon J. Gerraty if (CTX->name_elts[u].status == 0) { 5420957b409SSimon J. Gerraty const unsigned char *oid; 5430957b409SSimon J. Gerraty size_t len, off; 5440957b409SSimon J. Gerraty 5450957b409SSimon J. Gerraty oid = CTX->name_elts[u].oid; 5460957b409SSimon J. Gerraty if (san) { 5470957b409SSimon J. Gerraty if (oid[0] != 0 || oid[1] != 0) { 5480957b409SSimon J. Gerraty continue; 5490957b409SSimon J. Gerraty } 5500957b409SSimon J. Gerraty off = 2; 5510957b409SSimon J. Gerraty } else { 5520957b409SSimon J. Gerraty off = 0; 5530957b409SSimon J. Gerraty } 5540957b409SSimon J. Gerraty len = oid[off]; 5550957b409SSimon J. Gerraty if (len != 0 && len == CTX->pad[0] 5560957b409SSimon J. Gerraty && memcmp(oid + off + 1, 5570957b409SSimon J. Gerraty CTX->pad + 1, len) == 0) 5580957b409SSimon J. Gerraty { 5590957b409SSimon J. Gerraty T0_PUSH(u); 5600957b409SSimon J. Gerraty T0_RET(); 5610957b409SSimon J. Gerraty } 5620957b409SSimon J. Gerraty } 5630957b409SSimon J. Gerraty } 5640957b409SSimon J. Gerraty T0_PUSHi(-1); 5650957b409SSimon J. Gerraty} 5660957b409SSimon J. Gerraty 5670957b409SSimon J. Gerratycc: copy-name-element ( bool offbuf -- ) { 5680957b409SSimon J. Gerraty size_t len; 5690957b409SSimon J. Gerraty int32_t off = T0_POPi(); 5700957b409SSimon J. Gerraty int ok = T0_POPi(); 5710957b409SSimon J. Gerraty 5720957b409SSimon J. Gerraty if (off >= 0) { 5730957b409SSimon J. Gerraty br_name_element *ne = &CTX->name_elts[off]; 5740957b409SSimon J. Gerraty 5750957b409SSimon J. Gerraty if (ok) { 5760957b409SSimon J. Gerraty len = CTX->pad[0]; 5770957b409SSimon J. Gerraty if (len < ne->len) { 5780957b409SSimon J. Gerraty memcpy(ne->buf, CTX->pad + 1, len); 5790957b409SSimon J. Gerraty ne->buf[len] = 0; 5800957b409SSimon J. Gerraty ne->status = 1; 5810957b409SSimon J. Gerraty } else { 5820957b409SSimon J. Gerraty ne->status = -1; 5830957b409SSimon J. Gerraty } 5840957b409SSimon J. Gerraty } else { 5850957b409SSimon J. Gerraty ne->status = -1; 5860957b409SSimon J. Gerraty } 5870957b409SSimon J. Gerraty } 5880957b409SSimon J. Gerraty} 5890957b409SSimon J. Gerraty 5900957b409SSimon J. Gerratycc: copy-name-SAN ( bool tag -- ) { 5910957b409SSimon J. Gerraty unsigned tag = T0_POP(); 5920957b409SSimon J. Gerraty unsigned ok = T0_POP(); 5930957b409SSimon J. Gerraty size_t u, len; 5940957b409SSimon J. Gerraty 5950957b409SSimon J. Gerraty len = CTX->pad[0]; 5960957b409SSimon J. Gerraty for (u = 0; u < CTX->num_name_elts; u ++) { 5970957b409SSimon J. Gerraty br_name_element *ne; 5980957b409SSimon J. Gerraty 5990957b409SSimon J. Gerraty ne = &CTX->name_elts[u]; 6000957b409SSimon J. Gerraty if (ne->status == 0 && ne->oid[0] == 0 && ne->oid[1] == tag) { 6010957b409SSimon J. Gerraty if (ok && ne->len > len) { 6020957b409SSimon J. Gerraty memcpy(ne->buf, CTX->pad + 1, len); 6030957b409SSimon J. Gerraty ne->buf[len] = 0; 6040957b409SSimon J. Gerraty ne->status = 1; 6050957b409SSimon J. Gerraty } else { 6060957b409SSimon J. Gerraty ne->status = -1; 6070957b409SSimon J. Gerraty } 6080957b409SSimon J. Gerraty break; 6090957b409SSimon J. Gerraty } 6100957b409SSimon J. Gerraty } 6110957b409SSimon J. Gerraty} 6120957b409SSimon J. Gerraty 6130957b409SSimon J. Gerraty\ Read a value, decoding string types. If the string type is recognised 6140957b409SSimon J. Gerraty\ and the value could be converted to UTF-8 into the pad, then true (-1) 6150957b409SSimon J. Gerraty\ is returned; in all other cases, false (0) is returned. Either way, the 6160957b409SSimon J. Gerraty\ object is consumed. 6170957b409SSimon J. Gerraty: read-string ( lim -- lim bool ) 6180957b409SSimon J. Gerraty read-tag case 6190957b409SSimon J. Gerraty \ UTF8String 6200957b409SSimon J. Gerraty 12 of check-primitive read-value-UTF8 endof 6210957b409SSimon J. Gerraty \ NumericString 6220957b409SSimon J. Gerraty 18 of check-primitive read-value-latin1 endof 6230957b409SSimon J. Gerraty \ PrintableString 6240957b409SSimon J. Gerraty 19 of check-primitive read-value-latin1 endof 6250957b409SSimon J. Gerraty \ TeletexString 6260957b409SSimon J. Gerraty 20 of check-primitive read-value-latin1 endof 6270957b409SSimon J. Gerraty \ IA5String 6280957b409SSimon J. Gerraty 22 of check-primitive read-value-latin1 endof 6290957b409SSimon J. Gerraty \ BMPString 6300957b409SSimon J. Gerraty 30 of check-primitive read-value-UTF16 endof 6310957b409SSimon J. Gerraty 2drop read-length-skip 0 0 6320957b409SSimon J. Gerraty endcase ; 6330957b409SSimon J. Gerraty 6340957b409SSimon J. Gerraty\ Read a DN for the EE. The normalized DN hash is computed and stored in the 6350957b409SSimon J. Gerraty\ current_dn_hash. 6360957b409SSimon J. Gerraty\ Name elements are gathered. Also, the Common Name is matched against the 6370957b409SSimon J. Gerraty\ intended server name. 6380957b409SSimon J. Gerraty\ Returned value is true (-1) if the CN matches the intended server name, 6390957b409SSimon J. Gerraty\ false (0) otherwise. 6400957b409SSimon J. Gerraty: read-DN-EE ( lim -- lim bool ) 6410957b409SSimon J. Gerraty \ Flag will be set to true if there is a CN and it matches the 6420957b409SSimon J. Gerraty \ intended server name. 6430957b409SSimon J. Gerraty 0 { eename-matches } 6440957b409SSimon J. Gerraty 6450957b409SSimon J. Gerraty \ Activate DN hashing. 6460957b409SSimon J. Gerraty start-dn-hash 6470957b409SSimon J. Gerraty 6480957b409SSimon J. Gerraty \ Parse the DN structure: it is a SEQUENCE of SET of 6490957b409SSimon J. Gerraty \ AttributeTypeAndValue. Each AttributeTypeAndValue is a 6500957b409SSimon J. Gerraty \ SEQUENCE { OBJECT IDENTIFIER, ANY }. 6510957b409SSimon J. Gerraty read-sequence-open 6520957b409SSimon J. Gerraty begin 6530957b409SSimon J. Gerraty dup while 6540957b409SSimon J. Gerraty 6550957b409SSimon J. Gerraty read-tag 0x11 check-tag-constructed read-length-open-elt 6560957b409SSimon J. Gerraty dup ifnot ERR_X509_BAD_DN fail then 6570957b409SSimon J. Gerraty begin 6580957b409SSimon J. Gerraty dup while 6590957b409SSimon J. Gerraty 6600957b409SSimon J. Gerraty read-sequence-open 6610957b409SSimon J. Gerraty 6620957b409SSimon J. Gerraty \ Read the OID. If the OID could not be read (too 6630957b409SSimon J. Gerraty \ long) then the first pad byte will be 0. 6640957b409SSimon J. Gerraty read-OID drop 6650957b409SSimon J. Gerraty 6660957b409SSimon J. Gerraty \ If it is the Common Name then we'll need to 6670957b409SSimon J. Gerraty \ match it against the intended server name (if 6680957b409SSimon J. Gerraty \ applicable). 6690957b409SSimon J. Gerraty id-at-commonName eqOID { isCN } 6700957b409SSimon J. Gerraty 6710957b409SSimon J. Gerraty \ Get offset for reception buffer for that element 6720957b409SSimon J. Gerraty \ (or -1). 6730957b409SSimon J. Gerraty 0 offset-name-element { offbuf } 6740957b409SSimon J. Gerraty 6750957b409SSimon J. Gerraty \ Try to read the value as a string. 6760957b409SSimon J. Gerraty read-string 6770957b409SSimon J. Gerraty 6780957b409SSimon J. Gerraty \ If the value could be decoded as a string, 6790957b409SSimon J. Gerraty \ copy it and/or match it, as appropriate. 6800957b409SSimon J. Gerraty dup isCN and if 6810957b409SSimon J. Gerraty match-server-name if 6820957b409SSimon J. Gerraty -1 >eename-matches 6830957b409SSimon J. Gerraty then 6840957b409SSimon J. Gerraty then 6850957b409SSimon J. Gerraty offbuf copy-name-element 6860957b409SSimon J. Gerraty 6870957b409SSimon J. Gerraty \ Close the SEQUENCE 6880957b409SSimon J. Gerraty close-elt 6890957b409SSimon J. Gerraty 6900957b409SSimon J. Gerraty repeat 6910957b409SSimon J. Gerraty close-elt 6920957b409SSimon J. Gerraty repeat 6930957b409SSimon J. Gerraty close-elt 6940957b409SSimon J. Gerraty 6950957b409SSimon J. Gerraty \ Compute DN hash and deactivate DN hashing. 6960957b409SSimon J. Gerraty compute-dn-hash 6970957b409SSimon J. Gerraty 6980957b409SSimon J. Gerraty \ Return the CN match flag. 6990957b409SSimon J. Gerraty eename-matches ; 7000957b409SSimon J. Gerraty 701*cc9e6590SSimon J. Gerraty\ Check the provided validity range against the current (or configured) 702*cc9e6590SSimon J. Gerraty\ date and time ("na" = notAfter, "nb = notBefore). Returned value: 703*cc9e6590SSimon J. Gerraty\ -1 current date/time is before the notBefore date 704*cc9e6590SSimon J. Gerraty\ 0 current date/time is within the allowed range 705*cc9e6590SSimon J. Gerraty\ +1 current date/time is after the notAfter range 706*cc9e6590SSimon J. Gerraty\ If the current date/time is not available, then this function triggers a 707*cc9e6590SSimon J. Gerraty\ failure and does not return. 708*cc9e6590SSimon J. Gerratycc: check-validity-range ( na-days na-seconds nb-days nb-seconds -- int ) { 709*cc9e6590SSimon J. Gerraty uint32_t nbs = T0_POP(); 710*cc9e6590SSimon J. Gerraty uint32_t nbd = T0_POP(); 711*cc9e6590SSimon J. Gerraty uint32_t nas = T0_POP(); 712*cc9e6590SSimon J. Gerraty uint32_t nad = T0_POP(); 713*cc9e6590SSimon J. Gerraty int r; 714*cc9e6590SSimon J. Gerraty if (CTX->itime != 0) { 715*cc9e6590SSimon J. Gerraty r = CTX->itime(CTX->itime_ctx, nbd, nbs, nad, nas); 716*cc9e6590SSimon J. Gerraty if (r < -1 || r > 1) { 717*cc9e6590SSimon J. Gerraty CTX->err = BR_ERR_X509_TIME_UNKNOWN; 718*cc9e6590SSimon J. Gerraty T0_CO(); 719*cc9e6590SSimon J. Gerraty } 720*cc9e6590SSimon J. Gerraty } else { 721*cc9e6590SSimon J. Gerraty uint32_t vd = CTX->days; 722*cc9e6590SSimon J. Gerraty uint32_t vs = CTX->seconds; 723*cc9e6590SSimon J. Gerraty if (vd == 0 && vs == 0) { 7240957b409SSimon J. Gerraty#if BR_USE_UNIX_TIME 7250957b409SSimon J. Gerraty time_t x = time(NULL); 7260957b409SSimon J. Gerraty 727*cc9e6590SSimon J. Gerraty vd = (uint32_t)(x / 86400) + 719528; 728*cc9e6590SSimon J. Gerraty vs = (uint32_t)(x % 86400); 7290957b409SSimon J. Gerraty#elif BR_USE_WIN32_TIME 7300957b409SSimon J. Gerraty FILETIME ft; 7310957b409SSimon J. Gerraty uint64_t x; 7320957b409SSimon J. Gerraty 7330957b409SSimon J. Gerraty GetSystemTimeAsFileTime(&ft); 7340957b409SSimon J. Gerraty x = ((uint64_t)ft.dwHighDateTime << 32) 7350957b409SSimon J. Gerraty + (uint64_t)ft.dwLowDateTime; 7360957b409SSimon J. Gerraty x = (x / 10000000); 737*cc9e6590SSimon J. Gerraty vd = (uint32_t)(x / 86400) + 584754; 738*cc9e6590SSimon J. Gerraty vs = (uint32_t)(x % 86400); 7390957b409SSimon J. Gerraty#else 7400957b409SSimon J. Gerraty CTX->err = BR_ERR_X509_TIME_UNKNOWN; 7410957b409SSimon J. Gerraty T0_CO(); 7420957b409SSimon J. Gerraty#endif 743*cc9e6590SSimon J. Gerraty } 744*cc9e6590SSimon J. Gerraty if (vd < nbd || (vd == nbd && vs < nbs)) { 745*cc9e6590SSimon J. Gerraty r = -1; 746*cc9e6590SSimon J. Gerraty } else if (vd > nad || (vd == nad && vs > nas)) { 747*cc9e6590SSimon J. Gerraty r = 1; 7480957b409SSimon J. Gerraty } else { 749*cc9e6590SSimon J. Gerraty r = 0; 7500957b409SSimon J. Gerraty } 7510957b409SSimon J. Gerraty } 752*cc9e6590SSimon J. Gerraty T0_PUSHi(r); 753*cc9e6590SSimon J. Gerraty} 7540957b409SSimon J. Gerraty 7550957b409SSimon J. Gerraty\ Swap the top two elements with the two elements immediately below. 7560957b409SSimon J. Gerraty: swap2 ( a b c d -- c d a b ) 7570957b409SSimon J. Gerraty 3 roll 3 roll ; 7580957b409SSimon J. Gerraty 7590957b409SSimon J. Gerraty\ Match the name in the pad with the expected server name. Returned value 7600957b409SSimon J. Gerraty\ is true (-1) on match, false (0) otherwise. If there is no expected 7610957b409SSimon J. Gerraty\ server name, then 0 is returned. 7620957b409SSimon J. Gerraty\ Match conditions: either an exact match (case insensitive), or a 7630957b409SSimon J. Gerraty\ wildcard match, if the found name starts with "*.". We only match a 7640957b409SSimon J. Gerraty\ starting wildcard, and only against a complete DN name component. 7650957b409SSimon J. Gerratycc: match-server-name ( -- bool ) { 7660957b409SSimon J. Gerraty size_t n1, n2; 7670957b409SSimon J. Gerraty 7680957b409SSimon J. Gerraty if (CTX->server_name == NULL) { 7690957b409SSimon J. Gerraty T0_PUSH(0); 7700957b409SSimon J. Gerraty T0_RET(); 7710957b409SSimon J. Gerraty } 7720957b409SSimon J. Gerraty n1 = strlen(CTX->server_name); 7730957b409SSimon J. Gerraty n2 = CTX->pad[0]; 7740957b409SSimon J. Gerraty if (n1 == n2 && eqnocase(&CTX->pad[1], CTX->server_name, n1)) { 7750957b409SSimon J. Gerraty T0_PUSHi(-1); 7760957b409SSimon J. Gerraty T0_RET(); 7770957b409SSimon J. Gerraty } 7780957b409SSimon J. Gerraty if (n2 >= 2 && CTX->pad[1] == '*' && CTX->pad[2] == '.') { 7790957b409SSimon J. Gerraty size_t u; 7800957b409SSimon J. Gerraty 7810957b409SSimon J. Gerraty u = 0; 7820957b409SSimon J. Gerraty while (u < n1 && CTX->server_name[u] != '.') { 7830957b409SSimon J. Gerraty u ++; 7840957b409SSimon J. Gerraty } 7850957b409SSimon J. Gerraty u ++; 7860957b409SSimon J. Gerraty n1 -= u; 7870957b409SSimon J. Gerraty if ((n2 - 2) == n1 7880957b409SSimon J. Gerraty && eqnocase(&CTX->pad[3], CTX->server_name + u, n1)) 7890957b409SSimon J. Gerraty { 7900957b409SSimon J. Gerraty T0_PUSHi(-1); 7910957b409SSimon J. Gerraty T0_RET(); 7920957b409SSimon J. Gerraty } 7930957b409SSimon J. Gerraty } 7940957b409SSimon J. Gerraty T0_PUSH(0); 7950957b409SSimon J. Gerraty} 7960957b409SSimon J. Gerraty 7970957b409SSimon J. Gerraty\ Get the address and length for the pkey_data buffer. 7980957b409SSimon J. Gerraty: addr-len-pkey_data ( -- addr len ) 7990957b409SSimon J. Gerraty CX 0 8191 { offsetof(br_x509_minimal_context, pkey_data) } 8000957b409SSimon J. Gerraty CX 0 8191 { BR_X509_BUFSIZE_KEY } ; 8010957b409SSimon J. Gerraty 8020957b409SSimon J. Gerraty\ Copy the EE public key to the permanent buffer (RSA). 8030957b409SSimon J. Gerratycc: copy-ee-rsa-pkey ( nlen elen -- ) { 8040957b409SSimon J. Gerraty size_t elen = T0_POP(); 8050957b409SSimon J. Gerraty size_t nlen = T0_POP(); 8060957b409SSimon J. Gerraty memcpy(CTX->ee_pkey_data, CTX->pkey_data, nlen + elen); 8070957b409SSimon J. Gerraty CTX->pkey.key_type = BR_KEYTYPE_RSA; 8080957b409SSimon J. Gerraty CTX->pkey.key.rsa.n = CTX->ee_pkey_data; 8090957b409SSimon J. Gerraty CTX->pkey.key.rsa.nlen = nlen; 8100957b409SSimon J. Gerraty CTX->pkey.key.rsa.e = CTX->ee_pkey_data + nlen; 8110957b409SSimon J. Gerraty CTX->pkey.key.rsa.elen = elen; 8120957b409SSimon J. Gerraty} 8130957b409SSimon J. Gerraty 8140957b409SSimon J. Gerraty\ Copy the EE public key to the permanent buffer (EC). 8150957b409SSimon J. Gerratycc: copy-ee-ec-pkey ( curve qlen -- ) { 8160957b409SSimon J. Gerraty size_t qlen = T0_POP(); 8170957b409SSimon J. Gerraty uint32_t curve = T0_POP(); 8180957b409SSimon J. Gerraty memcpy(CTX->ee_pkey_data, CTX->pkey_data, qlen); 8190957b409SSimon J. Gerraty CTX->pkey.key_type = BR_KEYTYPE_EC; 8200957b409SSimon J. Gerraty CTX->pkey.key.ec.curve = curve; 8210957b409SSimon J. Gerraty CTX->pkey.key.ec.q = CTX->ee_pkey_data; 8220957b409SSimon J. Gerraty CTX->pkey.key.ec.qlen = qlen; 8230957b409SSimon J. Gerraty} 8240957b409SSimon J. Gerraty 8250957b409SSimon J. Gerraty\ Check whether the current certificate (EE) is directly trusted. 8260957b409SSimon J. Gerratycc: check-direct-trust ( -- ) { 8270957b409SSimon J. Gerraty size_t u; 8280957b409SSimon J. Gerraty 8290957b409SSimon J. Gerraty for (u = 0; u < CTX->trust_anchors_num; u ++) { 8300957b409SSimon J. Gerraty const br_x509_trust_anchor *ta; 8310957b409SSimon J. Gerraty unsigned char hashed_DN[64]; 8320957b409SSimon J. Gerraty int kt; 8330957b409SSimon J. Gerraty 8340957b409SSimon J. Gerraty ta = &CTX->trust_anchors[u]; 8350957b409SSimon J. Gerraty if (ta->flags & BR_X509_TA_CA) { 8360957b409SSimon J. Gerraty continue; 8370957b409SSimon J. Gerraty } 8380957b409SSimon J. Gerraty hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN); 8390957b409SSimon J. Gerraty if (memcmp(hashed_DN, CTX->current_dn_hash, DNHASH_LEN)) { 8400957b409SSimon J. Gerraty continue; 8410957b409SSimon J. Gerraty } 8420957b409SSimon J. Gerraty kt = CTX->pkey.key_type; 8430957b409SSimon J. Gerraty if ((ta->pkey.key_type & 0x0F) != kt) { 8440957b409SSimon J. Gerraty continue; 8450957b409SSimon J. Gerraty } 8460957b409SSimon J. Gerraty switch (kt) { 8470957b409SSimon J. Gerraty 8480957b409SSimon J. Gerraty case BR_KEYTYPE_RSA: 8490957b409SSimon J. Gerraty if (!eqbigint(CTX->pkey.key.rsa.n, 8500957b409SSimon J. Gerraty CTX->pkey.key.rsa.nlen, 8510957b409SSimon J. Gerraty ta->pkey.key.rsa.n, 8520957b409SSimon J. Gerraty ta->pkey.key.rsa.nlen) 8530957b409SSimon J. Gerraty || !eqbigint(CTX->pkey.key.rsa.e, 8540957b409SSimon J. Gerraty CTX->pkey.key.rsa.elen, 8550957b409SSimon J. Gerraty ta->pkey.key.rsa.e, 8560957b409SSimon J. Gerraty ta->pkey.key.rsa.elen)) 8570957b409SSimon J. Gerraty { 8580957b409SSimon J. Gerraty continue; 8590957b409SSimon J. Gerraty } 8600957b409SSimon J. Gerraty break; 8610957b409SSimon J. Gerraty 8620957b409SSimon J. Gerraty case BR_KEYTYPE_EC: 8630957b409SSimon J. Gerraty if (CTX->pkey.key.ec.curve != ta->pkey.key.ec.curve 8640957b409SSimon J. Gerraty || CTX->pkey.key.ec.qlen != ta->pkey.key.ec.qlen 8650957b409SSimon J. Gerraty || memcmp(CTX->pkey.key.ec.q, 8660957b409SSimon J. Gerraty ta->pkey.key.ec.q, 8670957b409SSimon J. Gerraty ta->pkey.key.ec.qlen) != 0) 8680957b409SSimon J. Gerraty { 8690957b409SSimon J. Gerraty continue; 8700957b409SSimon J. Gerraty } 8710957b409SSimon J. Gerraty break; 8720957b409SSimon J. Gerraty 8730957b409SSimon J. Gerraty default: 8740957b409SSimon J. Gerraty continue; 8750957b409SSimon J. Gerraty } 8760957b409SSimon J. Gerraty 8770957b409SSimon J. Gerraty /* 8780957b409SSimon J. Gerraty * Direct trust match! 8790957b409SSimon J. Gerraty */ 8800957b409SSimon J. Gerraty CTX->err = BR_ERR_X509_OK; 8810957b409SSimon J. Gerraty T0_CO(); 8820957b409SSimon J. Gerraty } 8830957b409SSimon J. Gerraty} 8840957b409SSimon J. Gerraty 8850957b409SSimon J. Gerraty\ Check the signature on the certificate with regards to all trusted CA. 8860957b409SSimon J. Gerraty\ We use the issuer hash (in saved_dn_hash[]) as CA identifier. 8870957b409SSimon J. Gerratycc: check-trust-anchor-CA ( -- ) { 8880957b409SSimon J. Gerraty size_t u; 8890957b409SSimon J. Gerraty 8900957b409SSimon J. Gerraty for (u = 0; u < CTX->trust_anchors_num; u ++) { 8910957b409SSimon J. Gerraty const br_x509_trust_anchor *ta; 8920957b409SSimon J. Gerraty unsigned char hashed_DN[64]; 8930957b409SSimon J. Gerraty 8940957b409SSimon J. Gerraty ta = &CTX->trust_anchors[u]; 8950957b409SSimon J. Gerraty if (!(ta->flags & BR_X509_TA_CA)) { 8960957b409SSimon J. Gerraty continue; 8970957b409SSimon J. Gerraty } 8980957b409SSimon J. Gerraty hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN); 8990957b409SSimon J. Gerraty if (memcmp(hashed_DN, CTX->saved_dn_hash, DNHASH_LEN)) { 9000957b409SSimon J. Gerraty continue; 9010957b409SSimon J. Gerraty } 9020957b409SSimon J. Gerraty if (verify_signature(CTX, &ta->pkey) == 0) { 9030957b409SSimon J. Gerraty CTX->err = BR_ERR_X509_OK; 9040957b409SSimon J. Gerraty T0_CO(); 9050957b409SSimon J. Gerraty } 9060957b409SSimon J. Gerraty } 9070957b409SSimon J. Gerraty} 9080957b409SSimon J. Gerraty 9090957b409SSimon J. Gerraty\ Verify RSA signature. This uses the public key that was just decoded 9100957b409SSimon J. Gerraty\ into CTX->pkey_data; the modulus and exponent length are provided as 9110957b409SSimon J. Gerraty\ parameters. The resulting hash value is compared with the one in 9120957b409SSimon J. Gerraty\ tbs_hash. Returned value is 0 on success, or a non-zero error code. 9130957b409SSimon J. Gerratycc: do-rsa-vrfy ( nlen elen -- err ) { 9140957b409SSimon J. Gerraty size_t elen = T0_POP(); 9150957b409SSimon J. Gerraty size_t nlen = T0_POP(); 9160957b409SSimon J. Gerraty br_x509_pkey pk; 9170957b409SSimon J. Gerraty 9180957b409SSimon J. Gerraty pk.key_type = BR_KEYTYPE_RSA; 9190957b409SSimon J. Gerraty pk.key.rsa.n = CTX->pkey_data; 9200957b409SSimon J. Gerraty pk.key.rsa.nlen = nlen; 9210957b409SSimon J. Gerraty pk.key.rsa.e = CTX->pkey_data + nlen; 9220957b409SSimon J. Gerraty pk.key.rsa.elen = elen; 9230957b409SSimon J. Gerraty T0_PUSH(verify_signature(CTX, &pk)); 9240957b409SSimon J. Gerraty} 9250957b409SSimon J. Gerraty 9260957b409SSimon J. Gerraty\ Verify ECDSA signature. This uses the public key that was just decoded 9270957b409SSimon J. Gerraty\ into CTX->pkey_dayta; the curve ID and public point length are provided 9280957b409SSimon J. Gerraty\ as parameters. The hash value in tbs_hash is used. Returned value is 0 9290957b409SSimon J. Gerraty\ on success, or non-zero error code. 9300957b409SSimon J. Gerratycc: do-ecdsa-vrfy ( curve qlen -- err ) { 9310957b409SSimon J. Gerraty size_t qlen = T0_POP(); 9320957b409SSimon J. Gerraty int curve = T0_POP(); 9330957b409SSimon J. Gerraty br_x509_pkey pk; 9340957b409SSimon J. Gerraty 9350957b409SSimon J. Gerraty pk.key_type = BR_KEYTYPE_EC; 9360957b409SSimon J. Gerraty pk.key.ec.curve = curve; 9370957b409SSimon J. Gerraty pk.key.ec.q = CTX->pkey_data; 9380957b409SSimon J. Gerraty pk.key.ec.qlen = qlen; 9390957b409SSimon J. Gerraty T0_PUSH(verify_signature(CTX, &pk)); 9400957b409SSimon J. Gerraty} 9410957b409SSimon J. Gerraty 9420957b409SSimon J. Gerratycc: print-bytes ( addr len -- ) { 9430957b409SSimon J. Gerraty extern int printf(const char *fmt, ...); 9440957b409SSimon J. Gerraty size_t len = T0_POP(); 9450957b409SSimon J. Gerraty unsigned char *buf = (unsigned char *)CTX + T0_POP(); 9460957b409SSimon J. Gerraty size_t u; 9470957b409SSimon J. Gerraty 9480957b409SSimon J. Gerraty for (u = 0; u < len; u ++) { 9490957b409SSimon J. Gerraty printf("%02X", buf[u]); 9500957b409SSimon J. Gerraty } 9510957b409SSimon J. Gerraty} 9520957b409SSimon J. Gerraty 9530957b409SSimon J. Gerratycc: printOID ( -- ) { 9540957b409SSimon J. Gerraty extern int printf(const char *fmt, ...); 9550957b409SSimon J. Gerraty size_t u, len; 9560957b409SSimon J. Gerraty 9570957b409SSimon J. Gerraty len = CTX->pad[0]; 9580957b409SSimon J. Gerraty if (len == 0) { 9590957b409SSimon J. Gerraty printf("*"); 9600957b409SSimon J. Gerraty T0_RET(); 9610957b409SSimon J. Gerraty } 9620957b409SSimon J. Gerraty printf("%u.%u", CTX->pad[1] / 40, CTX->pad[1] % 40); 9630957b409SSimon J. Gerraty u = 2; 9640957b409SSimon J. Gerraty while (u <= len) { 9650957b409SSimon J. Gerraty unsigned long ul; 9660957b409SSimon J. Gerraty 9670957b409SSimon J. Gerraty ul = 0; 9680957b409SSimon J. Gerraty for (;;) { 9690957b409SSimon J. Gerraty int x; 9700957b409SSimon J. Gerraty 9710957b409SSimon J. Gerraty if (u > len) { 9720957b409SSimon J. Gerraty printf("BAD"); 9730957b409SSimon J. Gerraty T0_RET(); 9740957b409SSimon J. Gerraty } 9750957b409SSimon J. Gerraty x = CTX->pad[u ++]; 9760957b409SSimon J. Gerraty ul = (ul << 7) + (x & 0x7F); 9770957b409SSimon J. Gerraty if (!(x & 0x80)) { 9780957b409SSimon J. Gerraty break; 9790957b409SSimon J. Gerraty } 9800957b409SSimon J. Gerraty } 9810957b409SSimon J. Gerraty printf(".%lu", ul); 9820957b409SSimon J. Gerraty } 9830957b409SSimon J. Gerraty} 9840957b409SSimon J. Gerraty 9850957b409SSimon J. Gerraty\ Extensions with specific processing. 9860957b409SSimon J. GerratyOID: basicConstraints 2.5.29.19 9870957b409SSimon J. GerratyOID: keyUsage 2.5.29.15 9880957b409SSimon J. GerratyOID: subjectAltName 2.5.29.17 9890957b409SSimon J. GerratyOID: certificatePolicies 2.5.29.32 9900957b409SSimon J. Gerraty 9910957b409SSimon J. Gerraty\ Policy qualifier "pointer to CPS" 9920957b409SSimon J. GerratyOID: id-qt-cps 1.3.6.1.5.5.7.2.1 9930957b409SSimon J. Gerraty 9940957b409SSimon J. Gerraty\ Extensions which are ignored when encountered, even if critical. 9950957b409SSimon J. GerratyOID: authorityKeyIdentifier 2.5.29.35 9960957b409SSimon J. GerratyOID: subjectKeyIdentifier 2.5.29.14 9970957b409SSimon J. GerratyOID: issuerAltName 2.5.29.18 9980957b409SSimon J. GerratyOID: subjectDirectoryAttributes 2.5.29.9 9990957b409SSimon J. GerratyOID: crlDistributionPoints 2.5.29.31 10000957b409SSimon J. GerratyOID: freshestCRL 2.5.29.46 10010957b409SSimon J. GerratyOID: authorityInfoAccess 1.3.6.1.5.5.7.1.1 10020957b409SSimon J. GerratyOID: subjectInfoAccess 1.3.6.1.5.5.7.1.11 10030957b409SSimon J. Gerraty 10040957b409SSimon J. Gerraty\ Process a Basic Constraints extension. This should be called only if 10050957b409SSimon J. Gerraty\ the certificate is not the EE. We check that the extension contains 10060957b409SSimon J. Gerraty\ the "CA" flag, and that the path length, if specified, is compatible 10070957b409SSimon J. Gerraty\ with the current chain length. 10080957b409SSimon J. Gerraty: process-basicConstraints ( lim -- lim ) 10090957b409SSimon J. Gerraty read-sequence-open 10100957b409SSimon J. Gerraty read-tag-or-end 10110957b409SSimon J. Gerraty dup 0x01 = if 10120957b409SSimon J. Gerraty read-boolean ifnot ERR_X509_NOT_CA fail then 10130957b409SSimon J. Gerraty read-tag-or-end 10140957b409SSimon J. Gerraty else 10150957b409SSimon J. Gerraty ERR_X509_NOT_CA fail 10160957b409SSimon J. Gerraty then 10170957b409SSimon J. Gerraty dup 0x02 = if 10180957b409SSimon J. Gerraty drop check-primitive read-small-int-value 10190957b409SSimon J. Gerraty addr-num_certs get32 1- < if ERR_X509_NOT_CA fail then 10200957b409SSimon J. Gerraty read-tag-or-end 10210957b409SSimon J. Gerraty then 10220957b409SSimon J. Gerraty -1 <> if ERR_X509_UNEXPECTED fail then 10230957b409SSimon J. Gerraty drop 10240957b409SSimon J. Gerraty close-elt 10250957b409SSimon J. Gerraty ; 10260957b409SSimon J. Gerraty 10270957b409SSimon J. Gerraty\ Process a Key Usage extension. 10280957b409SSimon J. Gerraty\ For the EE certificate: 10290957b409SSimon J. Gerraty\ -- if the key usage contains keyEncipherment (2), dataEncipherment (3) 10300957b409SSimon J. Gerraty\ or keyAgreement (4), then the "key exchange" usage is allowed; 10310957b409SSimon J. Gerraty\ -- if the key usage contains digitalSignature (0) or nonRepudiation (1), 10320957b409SSimon J. Gerraty\ then the "signature" usage is allowed. 10330957b409SSimon J. Gerraty\ For CA certificates, the extension must contain keyCertSign (5). 10340957b409SSimon J. Gerraty: process-keyUsage ( lim ee -- lim ) 10350957b409SSimon J. Gerraty { ee } 10360957b409SSimon J. Gerraty 10370957b409SSimon J. Gerraty \ Read tag for the BIT STRING and open it. 10380957b409SSimon J. Gerraty read-tag 0x03 check-tag-primitive 10390957b409SSimon J. Gerraty read-length-open-elt 10400957b409SSimon J. Gerraty \ First byte indicates number of ignored bits in the last byte. It 10410957b409SSimon J. Gerraty \ must be between 0 and 7. 10420957b409SSimon J. Gerraty read8 { ign } 10430957b409SSimon J. Gerraty ign 7 > if ERR_X509_UNEXPECTED fail then 10440957b409SSimon J. Gerraty \ Depending on length, we have either 0, 1 or more bytes to read. 10450957b409SSimon J. Gerraty dup case 10460957b409SSimon J. Gerraty 0 of ERR_X509_FORBIDDEN_KEY_USAGE fail endof 10470957b409SSimon J. Gerraty 1 of read8 ign >> ign << endof 10480957b409SSimon J. Gerraty drop read8 0 10490957b409SSimon J. Gerraty endcase 10500957b409SSimon J. Gerraty 10510957b409SSimon J. Gerraty \ Check bits. 10520957b409SSimon J. Gerraty ee if 10530957b409SSimon J. Gerraty \ EE: get usages. 10540957b409SSimon J. Gerraty 0 10550957b409SSimon J. Gerraty over 0x38 and if 0x10 or then 10560957b409SSimon J. Gerraty swap 0xC0 and if 0x20 or then 10570957b409SSimon J. Gerraty addr-key_usages set8 10580957b409SSimon J. Gerraty else 10590957b409SSimon J. Gerraty \ Not EE: keyCertSign must be set. 10600957b409SSimon J. Gerraty 0x04 and ifnot ERR_X509_FORBIDDEN_KEY_USAGE fail then 10610957b409SSimon J. Gerraty then 10620957b409SSimon J. Gerraty 10630957b409SSimon J. Gerraty \ We don't care about subsequent bytes. 10640957b409SSimon J. Gerraty skip-close-elt ; 10650957b409SSimon J. Gerraty 10660957b409SSimon J. Gerraty\ Process a Certificate Policies extension. 10670957b409SSimon J. Gerraty\ 10680957b409SSimon J. Gerraty\ Since we don't actually support full policies processing, this function 10690957b409SSimon J. Gerraty\ only checks that the extension contents can be safely ignored. Indeed, 10700957b409SSimon J. Gerraty\ we don't validate against a specific set of policies (in RFC 5280 10710957b409SSimon J. Gerraty\ terminology, user-initial-policy-set only contains the special value 10720957b409SSimon J. Gerraty\ any-policy). Moreover, we don't support policy constraints (if a 10730957b409SSimon J. Gerraty\ critical Policy Constraints extension is encountered, the validation 10740957b409SSimon J. Gerraty\ will fail). Therefore, we can safely ignore the contents of this 10750957b409SSimon J. Gerraty\ extension, except if it is critical AND one of the policy OID has a 10760957b409SSimon J. Gerraty\ qualifier which is distinct from id-qt-cps (because id-qt-cps is 10770957b409SSimon J. Gerraty\ specially designated by RFC 5280 has having no mandated action). 10780957b409SSimon J. Gerraty\ 10790957b409SSimon J. Gerraty\ This function is called only if the extension is critical. 10800957b409SSimon J. Gerraty: process-certPolicies ( lim -- lim ) 10810957b409SSimon J. Gerraty \ Extension value is a SEQUENCE OF PolicyInformation. 10820957b409SSimon J. Gerraty read-sequence-open 10830957b409SSimon J. Gerraty begin dup while 10840957b409SSimon J. Gerraty \ PolicyInformation ::= SEQUENCE { 10850957b409SSimon J. Gerraty \ policyIdentifier OBJECT IDENTIFIER, 10860957b409SSimon J. Gerraty \ policyQualifiers SEQUENCE OF PolicyQualifierInfo OPTIONAL 10870957b409SSimon J. Gerraty \ } 10880957b409SSimon J. Gerraty read-sequence-open 10890957b409SSimon J. Gerraty read-OID drop 10900957b409SSimon J. Gerraty dup if 10910957b409SSimon J. Gerraty read-sequence-open 10920957b409SSimon J. Gerraty begin dup while 10930957b409SSimon J. Gerraty \ PolicyQualifierInfo ::= SEQUENCE { 10940957b409SSimon J. Gerraty \ policyQualifierId OBJECT IDENTIFIER, 10950957b409SSimon J. Gerraty \ qualifier ANY 10960957b409SSimon J. Gerraty \ } 10970957b409SSimon J. Gerraty read-sequence-open 10980957b409SSimon J. Gerraty read-OID drop id-qt-cps eqOID ifnot 10990957b409SSimon J. Gerraty ERR_X509_CRITICAL_EXTENSION fail 11000957b409SSimon J. Gerraty then 11010957b409SSimon J. Gerraty skip-close-elt 11020957b409SSimon J. Gerraty repeat 11030957b409SSimon J. Gerraty close-elt 11040957b409SSimon J. Gerraty then 11050957b409SSimon J. Gerraty close-elt 11060957b409SSimon J. Gerraty repeat 11070957b409SSimon J. Gerraty close-elt ; 11080957b409SSimon J. Gerraty 11090957b409SSimon J. Gerraty\ Process a Subject Alt Name extension. Returned value is a boolean set 11100957b409SSimon J. Gerraty\ to true if the expected server name was matched against a dNSName in 11110957b409SSimon J. Gerraty\ the extension. 11120957b409SSimon J. Gerraty: process-SAN ( lim -- lim bool ) 11130957b409SSimon J. Gerraty 0 { m } 11140957b409SSimon J. Gerraty read-sequence-open 11150957b409SSimon J. Gerraty begin dup while 11160957b409SSimon J. Gerraty \ Read the tag. If the tag is context-0, then parse an 11170957b409SSimon J. Gerraty \ 'otherName'. If the tag is context-2, then parse a 11180957b409SSimon J. Gerraty \ dNSName. If the tag is context-1 or context-6, 11190957b409SSimon J. Gerraty \ parse 11200957b409SSimon J. Gerraty read-tag case 11210957b409SSimon J. Gerraty \ OtherName 11220957b409SSimon J. Gerraty 0x20 of 11230957b409SSimon J. Gerraty \ OtherName ::= SEQUENCE { 11240957b409SSimon J. Gerraty \ type-id OBJECT IDENTIFIER, 11250957b409SSimon J. Gerraty \ value [0] EXPLICIT ANY 11260957b409SSimon J. Gerraty \ } 11270957b409SSimon J. Gerraty check-constructed read-length-open-elt 11280957b409SSimon J. Gerraty read-OID drop 11290957b409SSimon J. Gerraty -1 offset-name-element { offbuf } 11300957b409SSimon J. Gerraty read-tag 0x20 check-tag-constructed 11310957b409SSimon J. Gerraty read-length-open-elt 11320957b409SSimon J. Gerraty read-string offbuf copy-name-element 11330957b409SSimon J. Gerraty close-elt 11340957b409SSimon J. Gerraty close-elt 11350957b409SSimon J. Gerraty endof 11360957b409SSimon J. Gerraty \ rfc822Name (IA5String) 11370957b409SSimon J. Gerraty 0x21 of 11380957b409SSimon J. Gerraty check-primitive 11390957b409SSimon J. Gerraty read-value-UTF8 1 copy-name-SAN 11400957b409SSimon J. Gerraty endof 11410957b409SSimon J. Gerraty \ dNSName (IA5String) 11420957b409SSimon J. Gerraty 0x22 of 11430957b409SSimon J. Gerraty check-primitive 11440957b409SSimon J. Gerraty read-value-UTF8 11450957b409SSimon J. Gerraty dup if match-server-name m or >m then 11460957b409SSimon J. Gerraty 2 copy-name-SAN 11470957b409SSimon J. Gerraty endof 11480957b409SSimon J. Gerraty \ uniformResourceIdentifier (IA5String) 11490957b409SSimon J. Gerraty 0x26 of 11500957b409SSimon J. Gerraty check-primitive 11510957b409SSimon J. Gerraty read-value-UTF8 6 copy-name-SAN 11520957b409SSimon J. Gerraty endof 11530957b409SSimon J. Gerraty 2drop read-length-skip 0 11540957b409SSimon J. Gerraty endcase 11550957b409SSimon J. Gerraty 11560957b409SSimon J. Gerraty \ We check only names of type dNSName; they use IA5String, 11570957b409SSimon J. Gerraty \ which is basically ASCII. 11580957b409SSimon J. Gerraty \ read-tag 0x22 = if 11590957b409SSimon J. Gerraty \ check-primitive 11600957b409SSimon J. Gerraty \ read-small-value drop 11610957b409SSimon J. Gerraty \ match-server-name m or >m 11620957b409SSimon J. Gerraty \ else 11630957b409SSimon J. Gerraty \ drop read-length-skip 11640957b409SSimon J. Gerraty \ then 11650957b409SSimon J. Gerraty repeat 11660957b409SSimon J. Gerraty close-elt 11670957b409SSimon J. Gerraty m ; 11680957b409SSimon J. Gerraty 11690957b409SSimon J. Gerraty\ Decode a certificate. The "ee" boolean must be true for the EE. 11700957b409SSimon J. Gerraty: decode-certificate ( ee -- ) 11710957b409SSimon J. Gerraty { ee } 11720957b409SSimon J. Gerraty 11730957b409SSimon J. Gerraty \ Obtain the total certificate length. 11740957b409SSimon J. Gerraty addr-cert_length get32 11750957b409SSimon J. Gerraty 11760957b409SSimon J. Gerraty \ Open the outer SEQUENCE. 11770957b409SSimon J. Gerraty read-sequence-open 11780957b409SSimon J. Gerraty 11790957b409SSimon J. Gerraty \ TBS 11800957b409SSimon J. Gerraty \ Activate hashing. 11810957b409SSimon J. Gerraty start-tbs-hash 11820957b409SSimon J. Gerraty read-sequence-open 11830957b409SSimon J. Gerraty 11840957b409SSimon J. Gerraty \ First element may be an explicit version. We accept only 11850957b409SSimon J. Gerraty \ versions 0 to 2 (certificates v1 to v3). 11860957b409SSimon J. Gerraty read-tag dup 0x20 = if 11870957b409SSimon J. Gerraty drop check-constructed read-length-open-elt 11880957b409SSimon J. Gerraty read-tag 11890957b409SSimon J. Gerraty 0x02 check-tag-primitive 11900957b409SSimon J. Gerraty read-small-int-value 11910957b409SSimon J. Gerraty 2 > if ERR_X509_UNSUPPORTED fail then 11920957b409SSimon J. Gerraty close-elt 11930957b409SSimon J. Gerraty read-tag 11940957b409SSimon J. Gerraty then 11950957b409SSimon J. Gerraty 11960957b409SSimon J. Gerraty \ Serial number. We just check that the tag is correct. 11970957b409SSimon J. Gerraty 0x02 check-tag-primitive 11980957b409SSimon J. Gerraty read-length-skip 11990957b409SSimon J. Gerraty 12000957b409SSimon J. Gerraty \ Signature algorithm. This structure is redundant with the one 12010957b409SSimon J. Gerraty \ on the outside; we just skip it. 12020957b409SSimon J. Gerraty read-sequence-open skip-close-elt 12030957b409SSimon J. Gerraty 12040957b409SSimon J. Gerraty \ Issuer name: hashed, then copied into next_dn_hash[]. 12050957b409SSimon J. Gerraty read-DN 12060957b409SSimon J. Gerraty addr-next_dn_hash addr-current_dn_hash dn-hash-length blobcopy 12070957b409SSimon J. Gerraty 12080957b409SSimon J. Gerraty \ Validity dates. 12090957b409SSimon J. Gerraty read-sequence-open 1210*cc9e6590SSimon J. Gerraty read-date { nbd nbs } read-date nbd nbs check-validity-range 1211*cc9e6590SSimon J. Gerraty if ERR_X509_EXPIRED fail then 12120957b409SSimon J. Gerraty close-elt 12130957b409SSimon J. Gerraty 12140957b409SSimon J. Gerraty \ Subject name. 12150957b409SSimon J. Gerraty ee if 12160957b409SSimon J. Gerraty \ For the EE, we must check whether the Common Name, if 12170957b409SSimon J. Gerraty \ any, matches the expected server name. 12180957b409SSimon J. Gerraty read-DN-EE { eename } 12190957b409SSimon J. Gerraty else 12200957b409SSimon J. Gerraty \ For a non-EE certificate, the hashed subject DN must match 12210957b409SSimon J. Gerraty \ the saved hashed issuer DN from the previous certificate. 12220957b409SSimon J. Gerraty read-DN 12230957b409SSimon J. Gerraty addr-current_dn_hash addr-saved_dn_hash dn-hash-length eqblob 12240957b409SSimon J. Gerraty ifnot ERR_X509_DN_MISMATCH fail then 12250957b409SSimon J. Gerraty then 12260957b409SSimon J. Gerraty \ Move the hashed issuer DN for this certificate into the 12270957b409SSimon J. Gerraty \ saved_dn_hash[] array. 12280957b409SSimon J. Gerraty addr-saved_dn_hash addr-next_dn_hash dn-hash-length blobcopy 12290957b409SSimon J. Gerraty 12300957b409SSimon J. Gerraty \ Public Key. 12310957b409SSimon J. Gerraty read-sequence-open 12320957b409SSimon J. Gerraty \ Algorithm Identifier. Right now we are only interested in the 12330957b409SSimon J. Gerraty \ OID, since we only support RSA keys. 12340957b409SSimon J. Gerraty read-sequence-open 12350957b409SSimon J. Gerraty read-OID ifnot ERR_X509_UNSUPPORTED fail then 12360957b409SSimon J. Gerraty { ; pkey-type } 12370957b409SSimon J. Gerraty choice 12380957b409SSimon J. Gerraty \ RSA public key. 12390957b409SSimon J. Gerraty rsaEncryption eqOID uf 12400957b409SSimon J. Gerraty skip-close-elt 12410957b409SSimon J. Gerraty \ Public key itself: the BIT STRING contains bytes 12420957b409SSimon J. Gerraty \ (no partial byte) and these bytes encode the 12430957b409SSimon J. Gerraty \ actual value. 12440957b409SSimon J. Gerraty read-bits-open 12450957b409SSimon J. Gerraty \ RSA public key is a SEQUENCE of two 12460957b409SSimon J. Gerraty \ INTEGER. We get both INTEGER values into 12470957b409SSimon J. Gerraty \ the pkey_data[] buffer, if they fit. 12480957b409SSimon J. Gerraty read-sequence-open 12490957b409SSimon J. Gerraty addr-len-pkey_data 12500957b409SSimon J. Gerraty read-integer { nlen } 12510957b409SSimon J. Gerraty addr-len-pkey_data swap nlen + swap nlen - 12520957b409SSimon J. Gerraty read-integer { elen } 12530957b409SSimon J. Gerraty close-elt 12540957b409SSimon J. Gerraty 12550957b409SSimon J. Gerraty \ Check that the public key fits our minimal 12560957b409SSimon J. Gerraty \ size requirements. Note that the integer 12570957b409SSimon J. Gerraty \ decoder already skipped the leading bytes 12580957b409SSimon J. Gerraty \ of value 0, so we are working on the true 12590957b409SSimon J. Gerraty \ modulus length here. 12600957b409SSimon J. Gerraty addr-min_rsa_size get16 128 + nlen > if 12610957b409SSimon J. Gerraty ERR_X509_WEAK_PUBLIC_KEY fail 12620957b409SSimon J. Gerraty then 12630957b409SSimon J. Gerraty close-elt 12640957b409SSimon J. Gerraty KEYTYPE_RSA >pkey-type 12650957b409SSimon J. Gerraty enduf 12660957b409SSimon J. Gerraty 12670957b409SSimon J. Gerraty \ EC public key. 12680957b409SSimon J. Gerraty id-ecPublicKey eqOID uf 12690957b409SSimon J. Gerraty \ We support only named curves, for which the 12700957b409SSimon J. Gerraty \ "parameters" field in the AlgorithmIdentifier 12710957b409SSimon J. Gerraty \ field should be an OID. 12720957b409SSimon J. Gerraty read-OID ifnot ERR_X509_UNSUPPORTED fail then 12730957b409SSimon J. Gerraty choice 12740957b409SSimon J. Gerraty ansix9p256r1 eqOID uf 23 enduf 12750957b409SSimon J. Gerraty ansix9p384r1 eqOID uf 24 enduf 12760957b409SSimon J. Gerraty ansix9p521r1 eqOID uf 25 enduf 12770957b409SSimon J. Gerraty ERR_X509_UNSUPPORTED fail 12780957b409SSimon J. Gerraty endchoice 12790957b409SSimon J. Gerraty { curve } 12800957b409SSimon J. Gerraty close-elt 12810957b409SSimon J. Gerraty read-bits-open 12820957b409SSimon J. Gerraty dup { qlen } 12830957b409SSimon J. Gerraty dup addr-len-pkey_data rot < if 12840957b409SSimon J. Gerraty ERR_X509_LIMIT_EXCEEDED fail 12850957b409SSimon J. Gerraty then 12860957b409SSimon J. Gerraty read-blob 12870957b409SSimon J. Gerraty KEYTYPE_EC >pkey-type 12880957b409SSimon J. Gerraty enduf 12890957b409SSimon J. Gerraty 12900957b409SSimon J. Gerraty \ Not a recognised public key type. 12910957b409SSimon J. Gerraty ERR_X509_UNSUPPORTED fail 12920957b409SSimon J. Gerraty endchoice 12930957b409SSimon J. Gerraty close-elt 12940957b409SSimon J. Gerraty 12950957b409SSimon J. Gerraty \ Process public key. 12960957b409SSimon J. Gerraty ee if 12970957b409SSimon J. Gerraty \ For the EE certificate, copy the key data to the 12980957b409SSimon J. Gerraty \ relevant buffer. 12990957b409SSimon J. Gerraty pkey-type case 13000957b409SSimon J. Gerraty KEYTYPE_RSA of nlen elen copy-ee-rsa-pkey endof 13010957b409SSimon J. Gerraty KEYTYPE_EC of curve qlen copy-ee-ec-pkey endof 13020957b409SSimon J. Gerraty ERR_X509_UNSUPPORTED fail 13030957b409SSimon J. Gerraty endcase 13040957b409SSimon J. Gerraty else 13050957b409SSimon J. Gerraty \ Verify signature on previous certificate. We invoke 13060957b409SSimon J. Gerraty \ the RSA implementation. 13070957b409SSimon J. Gerraty pkey-type case 13080957b409SSimon J. Gerraty KEYTYPE_RSA of nlen elen do-rsa-vrfy endof 13090957b409SSimon J. Gerraty KEYTYPE_EC of curve qlen do-ecdsa-vrfy endof 13100957b409SSimon J. Gerraty ERR_X509_UNSUPPORTED fail 13110957b409SSimon J. Gerraty endcase 13120957b409SSimon J. Gerraty dup if fail then 13130957b409SSimon J. Gerraty drop 13140957b409SSimon J. Gerraty then 13150957b409SSimon J. Gerraty 13160957b409SSimon J. Gerraty \ This flag will be set to true if the Basic Constraints extension 13170957b409SSimon J. Gerraty \ is encountered. 13180957b409SSimon J. Gerraty 0 { seenBC } 13190957b409SSimon J. Gerraty 13200957b409SSimon J. Gerraty \ Skip issuerUniqueID and subjectUniqueID, and process extensions 13210957b409SSimon J. Gerraty \ if present. Extensions are an explicit context tag of value 3 13220957b409SSimon J. Gerraty \ around a SEQUENCE OF extensions. Each extension is a SEQUENCE 13230957b409SSimon J. Gerraty \ with an OID, an optional boolean, and a value; the value is 13240957b409SSimon J. Gerraty \ an OCTET STRING. 13250957b409SSimon J. Gerraty read-tag-or-end 13260957b409SSimon J. Gerraty 0x21 iftag-skip 13270957b409SSimon J. Gerraty 0x22 iftag-skip 13280957b409SSimon J. Gerraty dup 0x23 = if 13290957b409SSimon J. Gerraty drop 13300957b409SSimon J. Gerraty check-constructed read-length-open-elt 13310957b409SSimon J. Gerraty read-sequence-open 13320957b409SSimon J. Gerraty begin dup while 13330957b409SSimon J. Gerraty 0 { critical } 13340957b409SSimon J. Gerraty read-sequence-open 13350957b409SSimon J. Gerraty read-OID drop 13360957b409SSimon J. Gerraty read-tag dup 0x01 = if 13370957b409SSimon J. Gerraty read-boolean >critical 13380957b409SSimon J. Gerraty read-tag 13390957b409SSimon J. Gerraty then 13400957b409SSimon J. Gerraty 0x04 check-tag-primitive read-length-open-elt 13410957b409SSimon J. Gerraty choice 13420957b409SSimon J. Gerraty \ Extensions with specific processing. 13430957b409SSimon J. Gerraty basicConstraints eqOID uf 13440957b409SSimon J. Gerraty ee if 13450957b409SSimon J. Gerraty skip-remaining 13460957b409SSimon J. Gerraty else 13470957b409SSimon J. Gerraty process-basicConstraints 13480957b409SSimon J. Gerraty -1 >seenBC 13490957b409SSimon J. Gerraty then 13500957b409SSimon J. Gerraty enduf 13510957b409SSimon J. Gerraty keyUsage eqOID uf 13520957b409SSimon J. Gerraty ee process-keyUsage 13530957b409SSimon J. Gerraty enduf 13540957b409SSimon J. Gerraty subjectAltName eqOID uf 13550957b409SSimon J. Gerraty ee if 13560957b409SSimon J. Gerraty 0 >eename 13570957b409SSimon J. Gerraty process-SAN >eename 13580957b409SSimon J. Gerraty else 13590957b409SSimon J. Gerraty skip-remaining 13600957b409SSimon J. Gerraty then 13610957b409SSimon J. Gerraty enduf 13620957b409SSimon J. Gerraty 13630957b409SSimon J. Gerraty \ We don't implement full processing of 13640957b409SSimon J. Gerraty \ policies. The call below mostly checks 13650957b409SSimon J. Gerraty \ that the contents of the Certificate 13660957b409SSimon J. Gerraty \ Policies extension can be safely ignored. 13670957b409SSimon J. Gerraty certificatePolicies eqOID uf 13680957b409SSimon J. Gerraty critical if 13690957b409SSimon J. Gerraty process-certPolicies 13700957b409SSimon J. Gerraty else 13710957b409SSimon J. Gerraty skip-remaining 13720957b409SSimon J. Gerraty then 13730957b409SSimon J. Gerraty enduf 13740957b409SSimon J. Gerraty 13750957b409SSimon J. Gerraty \ Extensions which are always ignored, 13760957b409SSimon J. Gerraty \ even if critical. 13770957b409SSimon J. Gerraty authorityKeyIdentifier eqOID uf 13780957b409SSimon J. Gerraty skip-remaining 13790957b409SSimon J. Gerraty enduf 13800957b409SSimon J. Gerraty subjectKeyIdentifier eqOID uf 13810957b409SSimon J. Gerraty skip-remaining 13820957b409SSimon J. Gerraty enduf 13830957b409SSimon J. Gerraty issuerAltName eqOID uf 13840957b409SSimon J. Gerraty skip-remaining 13850957b409SSimon J. Gerraty enduf 13860957b409SSimon J. Gerraty subjectDirectoryAttributes eqOID uf 13870957b409SSimon J. Gerraty skip-remaining 13880957b409SSimon J. Gerraty enduf 13890957b409SSimon J. Gerraty crlDistributionPoints eqOID uf 13900957b409SSimon J. Gerraty skip-remaining 13910957b409SSimon J. Gerraty enduf 13920957b409SSimon J. Gerraty freshestCRL eqOID uf 13930957b409SSimon J. Gerraty skip-remaining 13940957b409SSimon J. Gerraty enduf 13950957b409SSimon J. Gerraty authorityInfoAccess eqOID uf 13960957b409SSimon J. Gerraty skip-remaining 13970957b409SSimon J. Gerraty enduf 13980957b409SSimon J. Gerraty subjectInfoAccess eqOID uf 13990957b409SSimon J. Gerraty skip-remaining 14000957b409SSimon J. Gerraty enduf 14010957b409SSimon J. Gerraty 14020957b409SSimon J. Gerraty \ Unrecognized extensions trigger a failure 14030957b409SSimon J. Gerraty \ if critical; otherwise, they are just 14040957b409SSimon J. Gerraty \ ignored. 14050957b409SSimon J. Gerraty critical if 14060957b409SSimon J. Gerraty ERR_X509_CRITICAL_EXTENSION fail 14070957b409SSimon J. Gerraty then 14080957b409SSimon J. Gerraty skip-remaining 14090957b409SSimon J. Gerraty endchoice 14100957b409SSimon J. Gerraty close-elt 14110957b409SSimon J. Gerraty close-elt 14120957b409SSimon J. Gerraty repeat 14130957b409SSimon J. Gerraty close-elt 14140957b409SSimon J. Gerraty close-elt 14150957b409SSimon J. Gerraty else 14160957b409SSimon J. Gerraty -1 = ifnot ERR_X509_UNEXPECTED fail then 14170957b409SSimon J. Gerraty drop 14180957b409SSimon J. Gerraty then 14190957b409SSimon J. Gerraty 14200957b409SSimon J. Gerraty close-elt 14210957b409SSimon J. Gerraty \ Terminate hashing. 14220957b409SSimon J. Gerraty stop-tbs-hash 14230957b409SSimon J. Gerraty 14240957b409SSimon J. Gerraty \ For the EE certificate, verify that the intended server name 14250957b409SSimon J. Gerraty \ was matched. 14260957b409SSimon J. Gerraty ee if 14270957b409SSimon J. Gerraty eename zero-server-name or ifnot 14280957b409SSimon J. Gerraty ERR_X509_BAD_SERVER_NAME fail 14290957b409SSimon J. Gerraty then 14300957b409SSimon J. Gerraty then 14310957b409SSimon J. Gerraty 14320957b409SSimon J. Gerraty \ If this is the EE certificate, then direct trust may apply. 14330957b409SSimon J. Gerraty \ Note: we do this at this point, not immediately after decoding 14340957b409SSimon J. Gerraty \ the public key, because even in case of direct trust we still 14350957b409SSimon J. Gerraty \ want to check the server name with regards to the SAN extension. 14360957b409SSimon J. Gerraty \ However, we want to check direct trust before trying to decode 14370957b409SSimon J. Gerraty \ the signature algorithm, because it should work even if that 14380957b409SSimon J. Gerraty \ algorithm is not supported. 14390957b409SSimon J. Gerraty ee if check-direct-trust then 14400957b409SSimon J. Gerraty 14410957b409SSimon J. Gerraty \ Non-EE certificates MUST have a Basic Constraints extension 14420957b409SSimon J. Gerraty \ (that marks them as being CA). 14430957b409SSimon J. Gerraty ee seenBC or ifnot ERR_X509_NOT_CA fail then 14440957b409SSimon J. Gerraty 14450957b409SSimon J. Gerraty \ signature algorithm 14460957b409SSimon J. Gerraty read-tag check-sequence read-length-open-elt 14470957b409SSimon J. Gerraty \ Read and understand the OID. Right now, we support only 14480957b409SSimon J. Gerraty \ RSA with PKCS#1 v1.5 padding, and hash functions SHA-1, 14490957b409SSimon J. Gerraty \ SHA-224, SHA-256, SHA-384 and SHA-512. We purposely do NOT 14500957b409SSimon J. Gerraty \ support MD5 here. 14510957b409SSimon J. Gerraty \ TODO: add support for RSA/PSS 14520957b409SSimon J. Gerraty read-OID if 14530957b409SSimon J. Gerraty \ Based on the signature OID, we get: 14540957b409SSimon J. Gerraty \ -- the signing key type 14550957b409SSimon J. Gerraty \ -- the hash function numeric identifier 14560957b409SSimon J. Gerraty \ -- the hash function OID 14570957b409SSimon J. Gerraty choice 14580957b409SSimon J. Gerraty sha1WithRSAEncryption eqOID 14590957b409SSimon J. Gerraty uf 2 KEYTYPE_RSA id-sha1 enduf 14600957b409SSimon J. Gerraty sha224WithRSAEncryption eqOID 14610957b409SSimon J. Gerraty uf 3 KEYTYPE_RSA id-sha224 enduf 14620957b409SSimon J. Gerraty sha256WithRSAEncryption eqOID 14630957b409SSimon J. Gerraty uf 4 KEYTYPE_RSA id-sha256 enduf 14640957b409SSimon J. Gerraty sha384WithRSAEncryption eqOID 14650957b409SSimon J. Gerraty uf 5 KEYTYPE_RSA id-sha384 enduf 14660957b409SSimon J. Gerraty sha512WithRSAEncryption eqOID 14670957b409SSimon J. Gerraty uf 6 KEYTYPE_RSA id-sha512 enduf 14680957b409SSimon J. Gerraty 14690957b409SSimon J. Gerraty ecdsa-with-SHA1 eqOID 14700957b409SSimon J. Gerraty uf 2 KEYTYPE_EC id-sha1 enduf 14710957b409SSimon J. Gerraty ecdsa-with-SHA224 eqOID 14720957b409SSimon J. Gerraty uf 3 KEYTYPE_EC id-sha224 enduf 14730957b409SSimon J. Gerraty ecdsa-with-SHA256 eqOID 14740957b409SSimon J. Gerraty uf 4 KEYTYPE_EC id-sha256 enduf 14750957b409SSimon J. Gerraty ecdsa-with-SHA384 eqOID 14760957b409SSimon J. Gerraty uf 5 KEYTYPE_EC id-sha384 enduf 14770957b409SSimon J. Gerraty ecdsa-with-SHA512 eqOID 14780957b409SSimon J. Gerraty uf 6 KEYTYPE_EC id-sha512 enduf 14790957b409SSimon J. Gerraty ERR_X509_UNSUPPORTED fail 14800957b409SSimon J. Gerraty endchoice 14810957b409SSimon J. Gerraty addr-cert_sig_hash_oid set16 14820957b409SSimon J. Gerraty addr-cert_signer_key_type set8 14830957b409SSimon J. Gerraty 14840957b409SSimon J. Gerraty \ Compute the TBS hash into tbs_hash. 14850957b409SSimon J. Gerraty compute-tbs-hash 14860957b409SSimon J. Gerraty dup ifnot ERR_X509_UNSUPPORTED fail then 14870957b409SSimon J. Gerraty addr-cert_sig_hash_len set8 14880957b409SSimon J. Gerraty else 14890957b409SSimon J. Gerraty ERR_X509_UNSUPPORTED fail 14900957b409SSimon J. Gerraty then 14910957b409SSimon J. Gerraty \ We ignore the parameters, whether they are present or not, 14920957b409SSimon J. Gerraty \ because we got all the information from the OID. 14930957b409SSimon J. Gerraty skip-close-elt 14940957b409SSimon J. Gerraty 14950957b409SSimon J. Gerraty \ signature value 14960957b409SSimon J. Gerraty read-bits-open 14970957b409SSimon J. Gerraty dup CX 0 8191 { BR_X509_BUFSIZE_SIG } > if 14980957b409SSimon J. Gerraty ERR_X509_LIMIT_EXCEEDED fail 14990957b409SSimon J. Gerraty then 15000957b409SSimon J. Gerraty dup addr-cert_sig_len set16 15010957b409SSimon J. Gerraty addr-cert_sig read-blob 15020957b409SSimon J. Gerraty 15030957b409SSimon J. Gerraty \ Close the outer SEQUENCE. 15040957b409SSimon J. Gerraty close-elt 15050957b409SSimon J. Gerraty 15060957b409SSimon J. Gerraty \ Close the advertised total certificate length. This checks that 15070957b409SSimon J. Gerraty \ there is no trailing garbage after the certificate. 15080957b409SSimon J. Gerraty close-elt 15090957b409SSimon J. Gerraty 15100957b409SSimon J. Gerraty \ Flag the certificate as fully processed. 15110957b409SSimon J. Gerraty 0 addr-cert_length set32 15120957b409SSimon J. Gerraty 15130957b409SSimon J. Gerraty \ Check whether the issuer for the current certificate is known 15140957b409SSimon J. Gerraty \ as a trusted CA; in which case, verify the signature. 15150957b409SSimon J. Gerraty check-trust-anchor-CA ; 15160957b409SSimon J. Gerraty 15170957b409SSimon J. Gerraty: main 15180957b409SSimon J. Gerraty \ Unless restricted by a Key Usage extension, all usages are 15190957b409SSimon J. Gerraty \ deemed allowed. 15200957b409SSimon J. Gerraty 0x30 addr-key_usages set8 15210957b409SSimon J. Gerraty -1 decode-certificate 15220957b409SSimon J. Gerraty co 15230957b409SSimon J. Gerraty begin 15240957b409SSimon J. Gerraty 0 decode-certificate co 15250957b409SSimon J. Gerraty again 15260957b409SSimon J. Gerraty ; 1527