xref: /freebsd/contrib/bearssl/src/x509/x509_minimal.t0 (revision cc9e6590773dba57440750c124173ed531349a06)
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