xref: /freebsd/contrib/bearssl/src/x509/x509_minimal.t0 (revision 7fdf597e96a02165cfe22ff357b857d5fa15ed8a)
1\ Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
2\
3\ Permission is hereby granted, free of charge, to any person obtaining
4\ a copy of this software and associated documentation files (the
5\ "Software"), to deal in the Software without restriction, including
6\ without limitation the rights to use, copy, modify, merge, publish,
7\ distribute, sublicense, and/or sell copies of the Software, and to
8\ permit persons to whom the Software is furnished to do so, subject to
9\ the following conditions:
10\
11\ The above copyright notice and this permission notice shall be
12\ included in all copies or substantial portions of the Software.
13\
14\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
18\ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
19\ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20\ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21\ SOFTWARE.
22
23preamble {
24
25#include "inner.h"
26
27/*
28 * Implementation Notes
29 * --------------------
30 *
31 * The C code pushes the data by chunks; all decoding is done in the
32 * T0 code. The cert_length value is set to the certificate length when
33 * a new certificate is started; the T0 code picks it up as outer limit,
34 * and decoding functions use it to ensure that no attempt is made at
35 * reading past it. The T0 code also checks that once the certificate is
36 * decoded, there are no trailing bytes.
37 *
38 * The T0 code sets cert_length to 0 when the certificate is fully
39 * decoded.
40 *
41 * The C code must still perform two checks:
42 *
43 *  -- If the certificate length is 0, then the T0 code will not be
44 *  invoked at all. This invalid condition must thus be reported by the
45 *  C code.
46 *
47 *  -- When reaching the end of certificate, the C code must verify that
48 *  the certificate length has been set to 0, thereby signaling that
49 *  the T0 code properly decoded a certificate.
50 *
51 * Processing of a chain works in the following way:
52 *
53 *  -- The error flag is set to a non-zero value when validation is
54 *  finished. The value is either BR_ERR_X509_OK (validation is
55 *  successful) or another non-zero error code. When a non-zero error
56 *  code is obtained, the remaining bytes in the current certificate and
57 *  the subsequent certificates (if any) are completely ignored.
58 *
59 *  -- Each certificate is decoded in due course, with the following
60 *  "interesting points":
61 *
62 *     -- Start of the TBS: the multihash engine is reset and activated.
63 *
64 *     -- Start of the issuer DN: the secondary hash engine is started,
65 *     to process the encoded issuer DN.
66 *
67 *     -- End of the issuer DN: the secondary hash engine is stopped. The
68 *     resulting hash value is computed and then copied into the
69 *     next_dn_hash[] buffer.
70 *
71 *     -- Start of the subject DN: the secondary hash engine is started,
72 *     to process the encoded subject DN.
73 *
74 *     -- For the EE certificate only: the Common Name, if any, is matched
75 *     against the expected server name.
76 *
77 *     -- End of the subject DN: the secondary hash engine is stopped. The
78 *     resulting hash value is computed into the pad. It is then processed:
79 *
80 *        -- If this is the EE certificate, then the hash is ignored
81 *        (except for direct trust processing, see later; the hash is
82 *        simply left in current_dn_hash[]).
83 *
84 *        -- Otherwise, the hashed subject DN is compared with the saved
85 *        hash value (in saved_dn_hash[]). They must match.
86 *
87 *     Either way, the next_dn_hash[] value is then copied into the
88 *     saved_dn_hash[] value. Thus, at that point, saved_dn_hash[]
89 *     contains the hash of the issuer DN for the current certificate,
90 *     and current_dn_hash[] contains the hash of the subject DN for the
91 *     current certificate.
92 *
93 *     -- Public key: it is decoded into the cert_pkey[] buffer. Unknown
94 *     key types are reported at that point.
95 *
96 *        -- If this is the EE certificate, then the key type is compared
97 *        with the expected key type (initialization parameter). The public
98 *        key data is copied to ee_pkey_data[]. The key and hashed subject
99 *        DN are also compared with the "direct trust" keys; if the key
100 *        and DN are matched, then validation ends with a success.
101 *
102 *        -- Otherwise, the saved signature (cert_sig[]) is verified
103 *        against the saved TBS hash (tbs_hash[]) and that freshly
104 *        decoded public key. Failure here ends validation with an error.
105 *
106 *     -- Extensions: extension values are processed in due order.
107 *
108 *        -- Basic Constraints: for all certificates except EE, must be
109 *        present, indicate a CA, and have a path length compatible with
110 *        the chain length so far.
111 *
112 *        -- Key Usage: for the EE, if present, must allow signatures
113 *        or encryption/key exchange, as required for the cipher suite.
114 *        For non-EE, if present, must have the "certificate sign" bit.
115 *
116 *        -- Subject Alt Name: for the EE, dNSName names are matched
117 *        against the server name. Ignored for non-EE.
118 *
119 *        -- Authority Key Identifier, Subject Key Identifier, Issuer
120 *        Alt Name, Subject Directory Attributes, CRL Distribution Points
121 *        Freshest CRL, Authority Info Access and Subject Info Access
122 *        extensions are always ignored: they either contain only
123 *        informative data, or they relate to revocation processing, which
124 *        we explicitly do not support.
125 *
126 *        -- All other extensions are ignored if non-critical. If a
127 *        critical extension other than the ones above is encountered,
128 *        then a failure is reported.
129 *
130 *     -- End of the TBS: the multihash engine is stopped.
131 *
132 *     -- Signature algorithm: the signature algorithm on the
133 *     certificate is decoded. A failure is reported if that algorithm
134 *     is unknown. The hashed TBS corresponding to the signature hash
135 *     function is computed and stored in tbs_hash[] (if not supported,
136 *     then a failure is reported). The hash OID and length are stored
137 *     in cert_sig_hash_oid and cert_sig_hash_len.
138 *
139 *     -- Signature value: the signature value is copied into the
140 *     cert_sig[] array.
141 *
142 *     -- Certificate end: the hashed issuer DN (saved_dn_hash[]) is
143 *     looked up in the trust store (CA trust anchors only); for all
144 *     that match, the signature (cert_sig[]) is verified against the
145 *     anchor public key (hashed TBS is in tbs_hash[]). If one of these
146 *     signatures is valid, then validation ends with a success.
147 *
148 *  -- If the chain end is reached without obtaining a validation success,
149 *  then validation is reported as failed.
150 */
151
152#if BR_USE_UNIX_TIME
153#include <time.h>
154#endif
155
156#if BR_USE_WIN32_TIME
157#include <windows.h>
158#endif
159
160/*
161 * The T0 compiler will produce these prototypes declarations in the
162 * header.
163 *
164void br_x509_minimal_init_main(void *ctx);
165void br_x509_minimal_run(void *ctx);
166 */
167
168/* see bearssl_x509.h */
169void
170br_x509_minimal_init(br_x509_minimal_context *ctx,
171	const br_hash_class *dn_hash_impl,
172	const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num)
173{
174	memset(ctx, 0, sizeof *ctx);
175	ctx->vtable = &br_x509_minimal_vtable;
176	ctx->dn_hash_impl = dn_hash_impl;
177	ctx->trust_anchors = trust_anchors;
178	ctx->trust_anchors_num = trust_anchors_num;
179}
180
181static void
182xm_start_chain(const br_x509_class **ctx, const char *server_name)
183{
184	br_x509_minimal_context *cc;
185	size_t u;
186
187	cc = (br_x509_minimal_context *)(void *)ctx;
188	for (u = 0; u < cc->num_name_elts; u ++) {
189		cc->name_elts[u].status = 0;
190		cc->name_elts[u].buf[0] = 0;
191	}
192	memset(&cc->pkey, 0, sizeof cc->pkey);
193	cc->num_certs = 0;
194	cc->err = 0;
195	cc->cpu.dp = cc->dp_stack;
196	cc->cpu.rp = cc->rp_stack;
197	br_x509_minimal_init_main(&cc->cpu);
198	if (server_name == NULL || *server_name == 0) {
199		cc->server_name = NULL;
200	} else {
201		cc->server_name = server_name;
202	}
203}
204
205static void
206xm_start_cert(const br_x509_class **ctx, uint32_t length)
207{
208	br_x509_minimal_context *cc;
209
210	cc = (br_x509_minimal_context *)(void *)ctx;
211	if (cc->err != 0) {
212		return;
213	}
214	if (length == 0) {
215		cc->err = BR_ERR_X509_TRUNCATED;
216		return;
217	}
218	cc->cert_length = length;
219}
220
221static void
222xm_append(const br_x509_class **ctx, const unsigned char *buf, size_t len)
223{
224	br_x509_minimal_context *cc;
225
226	cc = (br_x509_minimal_context *)(void *)ctx;
227	if (cc->err != 0) {
228		return;
229	}
230	cc->hbuf = buf;
231	cc->hlen = len;
232	br_x509_minimal_run(&cc->cpu);
233}
234
235static void
236xm_end_cert(const br_x509_class **ctx)
237{
238	br_x509_minimal_context *cc;
239
240	cc = (br_x509_minimal_context *)(void *)ctx;
241	if (cc->err == 0 && cc->cert_length != 0) {
242		cc->err = BR_ERR_X509_TRUNCATED;
243	}
244	cc->num_certs ++;
245}
246
247static unsigned
248xm_end_chain(const br_x509_class **ctx)
249{
250	br_x509_minimal_context *cc;
251
252	cc = (br_x509_minimal_context *)(void *)ctx;
253	if (cc->err == 0) {
254		if (cc->num_certs == 0) {
255			cc->err = BR_ERR_X509_EMPTY_CHAIN;
256		} else {
257			cc->err = BR_ERR_X509_NOT_TRUSTED;
258		}
259	} else if (cc->err == BR_ERR_X509_OK) {
260		return 0;
261	}
262	return (unsigned)cc->err;
263}
264
265static const br_x509_pkey *
266xm_get_pkey(const br_x509_class *const *ctx, unsigned *usages)
267{
268	br_x509_minimal_context *cc;
269
270	cc = (br_x509_minimal_context *)(void *)ctx;
271	if (cc->err == BR_ERR_X509_OK
272		|| cc->err == BR_ERR_X509_NOT_TRUSTED)
273	{
274		if (usages != NULL) {
275			*usages = cc->key_usages;
276		}
277		return &((br_x509_minimal_context *)(void *)ctx)->pkey;
278	} else {
279		return NULL;
280	}
281}
282
283/* see bearssl_x509.h */
284const br_x509_class br_x509_minimal_vtable = {
285	sizeof(br_x509_minimal_context),
286	xm_start_chain,
287	xm_start_cert,
288	xm_append,
289	xm_end_cert,
290	xm_end_chain,
291	xm_get_pkey
292};
293
294#define CTX   ((br_x509_minimal_context *)(void *)((unsigned char *)t0ctx - offsetof(br_x509_minimal_context, cpu)))
295#define CONTEXT_NAME   br_x509_minimal_context
296
297#define DNHASH_LEN   ((CTX->dn_hash_impl->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK)
298
299/*
300 * Hash a DN (from a trust anchor) into the provided buffer. This uses the
301 * DN hash implementation and context structure from the X.509 engine
302 * context.
303 */
304static void
305hash_dn(br_x509_minimal_context *ctx, const void *dn, size_t len,
306	unsigned char *out)
307{
308	ctx->dn_hash_impl->init(&ctx->dn_hash.vtable);
309	ctx->dn_hash_impl->update(&ctx->dn_hash.vtable, dn, len);
310	ctx->dn_hash_impl->out(&ctx->dn_hash.vtable, out);
311}
312
313/*
314 * Compare two big integers for equality. The integers use unsigned big-endian
315 * encoding; extra leading bytes (of value 0) are allowed.
316 */
317static int
318eqbigint(const unsigned char *b1, size_t len1,
319	const unsigned char *b2, size_t len2)
320{
321	while (len1 > 0 && *b1 == 0) {
322		b1 ++;
323		len1 --;
324	}
325	while (len2 > 0 && *b2 == 0) {
326		b2 ++;
327		len2 --;
328	}
329	if (len1 != len2) {
330		return 0;
331	}
332	return memcmp(b1, b2, len1) == 0;
333}
334
335/*
336 * Compare two strings for equality, in a case-insensitive way. This
337 * function handles casing only for ASCII letters.
338 */
339static int
340eqnocase(const void *s1, const void *s2, size_t len)
341{
342	const unsigned char *buf1, *buf2;
343
344	buf1 = s1;
345	buf2 = s2;
346	while (len -- > 0) {
347		int x1, x2;
348
349		x1 = *buf1 ++;
350		x2 = *buf2 ++;
351		if (x1 >= 'A' && x1 <= 'Z') {
352			x1 += 'a' - 'A';
353		}
354		if (x2 >= 'A' && x2 <= 'Z') {
355			x2 += 'a' - 'A';
356		}
357		if (x1 != x2) {
358			return 0;
359		}
360	}
361	return 1;
362}
363
364static int verify_signature(br_x509_minimal_context *ctx,
365	const br_x509_pkey *pk);
366
367}
368
369postamble {
370
371/*
372 * Verify the signature on the certificate with the provided public key.
373 * This function checks the public key type with regards to the expected
374 * type. Returned value is either 0 on success, or a non-zero error code.
375 */
376static int
377verify_signature(br_x509_minimal_context *ctx, const br_x509_pkey *pk)
378{
379	int kt;
380
381	kt = ctx->cert_signer_key_type;
382	if ((pk->key_type & 0x0F) != kt) {
383		return BR_ERR_X509_WRONG_KEY_TYPE;
384	}
385	switch (kt) {
386		unsigned char tmp[64];
387
388	case BR_KEYTYPE_RSA:
389		if (ctx->irsa == 0) {
390			return BR_ERR_X509_UNSUPPORTED;
391		}
392		if (!ctx->irsa(ctx->cert_sig, ctx->cert_sig_len,
393			&t0_datablock[ctx->cert_sig_hash_oid],
394			ctx->cert_sig_hash_len, &pk->key.rsa, tmp))
395		{
396			return BR_ERR_X509_BAD_SIGNATURE;
397		}
398		if (memcmp(ctx->tbs_hash, tmp, ctx->cert_sig_hash_len) != 0) {
399			return BR_ERR_X509_BAD_SIGNATURE;
400		}
401		return 0;
402
403	case BR_KEYTYPE_EC:
404		if (ctx->iecdsa == 0) {
405			return BR_ERR_X509_UNSUPPORTED;
406		}
407		if (!ctx->iecdsa(ctx->iec, ctx->tbs_hash,
408			ctx->cert_sig_hash_len, &pk->key.ec,
409			ctx->cert_sig, ctx->cert_sig_len))
410		{
411			return BR_ERR_X509_BAD_SIGNATURE;
412		}
413		return 0;
414
415	default:
416		return BR_ERR_X509_UNSUPPORTED;
417	}
418}
419
420}
421
422cc: read8-low ( -- x ) {
423	if (CTX->hlen == 0) {
424		T0_PUSHi(-1);
425	} else {
426		unsigned char x = *CTX->hbuf ++;
427		if (CTX->do_mhash) {
428			br_multihash_update(&CTX->mhash, &x, 1);
429		}
430		if (CTX->do_dn_hash) {
431			CTX->dn_hash_impl->update(&CTX->dn_hash.vtable, &x, 1);
432		}
433		CTX->hlen --;
434		T0_PUSH(x);
435	}
436}
437
438addr: cert_length
439addr: num_certs
440
441cc: read-blob-inner ( addr len -- addr len ) {
442	uint32_t len = T0_POP();
443	uint32_t addr = T0_POP();
444	size_t clen = CTX->hlen;
445	if (clen > len) {
446		clen = (size_t)len;
447	}
448	if (addr != 0) {
449		memcpy((unsigned char *)CTX + addr, CTX->hbuf, clen);
450	}
451	if (CTX->do_mhash) {
452		br_multihash_update(&CTX->mhash, CTX->hbuf, clen);
453	}
454	if (CTX->do_dn_hash) {
455		CTX->dn_hash_impl->update(
456			&CTX->dn_hash.vtable, CTX->hbuf, clen);
457	}
458	CTX->hbuf += clen;
459	CTX->hlen -= clen;
460	T0_PUSH(addr + clen);
461	T0_PUSH(len - clen);
462}
463
464\ Compute the TBS hash, using the provided hash ID. The hash value is
465\ written in the tbs_hash[] array, and the hash length is returned. If
466\ the requested hash function is not supported, then 0 is returned.
467cc: compute-tbs-hash ( id -- hashlen ) {
468	int id = T0_POPi();
469	size_t len;
470	len = br_multihash_out(&CTX->mhash, id, CTX->tbs_hash);
471	T0_PUSH(len);
472}
473
474\ Push true (-1) if no server name is expected in the EE certificate.
475cc: zero-server-name ( -- bool ) {
476	T0_PUSHi(-(CTX->server_name == NULL));
477}
478
479addr: key_usages
480addr: cert_sig
481addr: cert_sig_len
482addr: cert_signer_key_type
483addr: cert_sig_hash_oid
484addr: cert_sig_hash_len
485addr: tbs_hash
486addr: min_rsa_size
487
488\ Start TBS hash computation. The hash functions are reinitialised.
489cc: start-tbs-hash ( -- ) {
490	br_multihash_init(&CTX->mhash);
491	CTX->do_mhash = 1;
492}
493
494\ Stop TBS hash computation.
495cc: stop-tbs-hash ( -- ) {
496	CTX->do_mhash = 0;
497}
498
499\ Start DN hash computation.
500cc: start-dn-hash ( -- ) {
501	CTX->dn_hash_impl->init(&CTX->dn_hash.vtable);
502	CTX->do_dn_hash = 1;
503}
504
505\ Terminate DN hash computation and write the DN hash into the
506\ current_dn_hash buffer.
507cc: compute-dn-hash ( -- ) {
508	CTX->dn_hash_impl->out(&CTX->dn_hash.vtable, CTX->current_dn_hash);
509	CTX->do_dn_hash = 0;
510}
511
512\ Get the length of hash values obtained with the DN hasher.
513cc: dn-hash-length ( -- len ) {
514	T0_PUSH(DNHASH_LEN);
515}
516
517\ Copy data between two areas in the context.
518cc: blobcopy ( addr-dst addr-src len -- ) {
519	size_t len = T0_POP();
520	unsigned char *src = (unsigned char *)CTX + T0_POP();
521	unsigned char *dst = (unsigned char *)CTX + T0_POP();
522	memcpy(dst, src, len);
523}
524
525addr: current_dn_hash
526addr: next_dn_hash
527addr: saved_dn_hash
528
529\ Read a DN, hashing it into current_dn_hash. The DN contents are not
530\ inspected (only the outer tag, for SEQUENCE, is checked).
531: read-DN ( lim -- lim )
532	start-dn-hash
533	read-sequence-open skip-close-elt
534	compute-dn-hash ;
535
536cc: offset-name-element ( san -- n ) {
537	unsigned san = T0_POP();
538	size_t u;
539
540	for (u = 0; u < CTX->num_name_elts; u ++) {
541		if (CTX->name_elts[u].status == 0) {
542			const unsigned char *oid;
543			size_t len, off;
544
545			oid = CTX->name_elts[u].oid;
546			if (san) {
547				if (oid[0] != 0 || oid[1] != 0) {
548					continue;
549				}
550				off = 2;
551			} else {
552				off = 0;
553			}
554			len = oid[off];
555			if (len != 0 && len == CTX->pad[0]
556				&& memcmp(oid + off + 1,
557					CTX->pad + 1, len) == 0)
558			{
559				T0_PUSH(u);
560				T0_RET();
561			}
562		}
563	}
564	T0_PUSHi(-1);
565}
566
567cc: copy-name-element ( bool offbuf -- ) {
568	size_t len;
569	int32_t off = T0_POPi();
570	int ok = T0_POPi();
571
572	if (off >= 0) {
573		br_name_element *ne = &CTX->name_elts[off];
574
575		if (ok) {
576			len = CTX->pad[0];
577			if (len < ne->len) {
578				memcpy(ne->buf, CTX->pad + 1, len);
579				ne->buf[len] = 0;
580				ne->status = 1;
581			} else {
582				ne->status = -1;
583			}
584		} else {
585			ne->status = -1;
586		}
587	}
588}
589
590cc: copy-name-SAN ( bool tag -- ) {
591	unsigned tag = T0_POP();
592	unsigned ok = T0_POP();
593	size_t u, len;
594
595	len = CTX->pad[0];
596	for (u = 0; u < CTX->num_name_elts; u ++) {
597		br_name_element *ne;
598
599		ne = &CTX->name_elts[u];
600		if (ne->status == 0 && ne->oid[0] == 0 && ne->oid[1] == tag) {
601			if (ok && ne->len > len) {
602				memcpy(ne->buf, CTX->pad + 1, len);
603				ne->buf[len] = 0;
604				ne->status = 1;
605			} else {
606				ne->status = -1;
607			}
608			break;
609		}
610	}
611}
612
613\ Read a value, decoding string types. If the string type is recognised
614\ and the value could be converted to UTF-8 into the pad, then true (-1)
615\ is returned; in all other cases, false (0) is returned. Either way, the
616\ object is consumed.
617: read-string ( lim -- lim bool )
618	read-tag case
619		\ UTF8String
620		12 of check-primitive read-value-UTF8 endof
621		\ NumericString
622		18 of check-primitive read-value-latin1 endof
623		\ PrintableString
624		19 of check-primitive read-value-latin1 endof
625		\ TeletexString
626		20 of check-primitive read-value-latin1 endof
627		\ IA5String
628		22 of check-primitive read-value-latin1 endof
629		\ BMPString
630		30 of check-primitive read-value-UTF16 endof
631		2drop read-length-skip 0 0
632	endcase ;
633
634\ Read a DN for the EE. The normalized DN hash is computed and stored in the
635\ current_dn_hash.
636\ Name elements are gathered. Also, the Common Name is matched against the
637\ intended server name.
638\ Returned value is true (-1) if the CN matches the intended server name,
639\ false (0) otherwise.
640: read-DN-EE ( lim -- lim bool )
641	\ Flag will be set to true if there is a CN and it matches the
642	\ intended server name.
643	0 { eename-matches }
644
645	\ Activate DN hashing.
646	start-dn-hash
647
648	\ Parse the DN structure: it is a SEQUENCE of SET of
649	\ AttributeTypeAndValue. Each AttributeTypeAndValue is a
650	\ SEQUENCE { OBJECT IDENTIFIER, ANY }.
651	read-sequence-open
652	begin
653		dup while
654
655		read-tag 0x11 check-tag-constructed read-length-open-elt
656		dup ifnot ERR_X509_BAD_DN fail then
657		begin
658			dup while
659
660			read-sequence-open
661
662			\ Read the OID. If the OID could not be read (too
663			\ long) then the first pad byte will be 0.
664			read-OID drop
665
666			\ If it is the Common Name then we'll need to
667			\ match it against the intended server name (if
668			\ applicable).
669			id-at-commonName eqOID { isCN }
670
671			\ Get offset for reception buffer for that element
672			\ (or -1).
673			0 offset-name-element { offbuf }
674
675			\ Try to read the value as a string.
676			read-string
677
678			\ If the value could be decoded as a string,
679			\ copy it and/or match it, as appropriate.
680			dup isCN and if
681				match-server-name if
682					-1 >eename-matches
683				then
684			then
685			offbuf copy-name-element
686
687			\ Close the SEQUENCE
688			close-elt
689
690		repeat
691		close-elt
692	repeat
693	close-elt
694
695	\ Compute DN hash and deactivate DN hashing.
696	compute-dn-hash
697
698	\ Return the CN match flag.
699	eename-matches ;
700
701\ Check the provided validity range against the current (or configured)
702\ date and time ("na" = notAfter, "nb = notBefore). Returned value:
703\   -1   current date/time is before the notBefore date
704\    0   current date/time is within the allowed range
705\   +1   current date/time is after the notAfter range
706\ If the current date/time is not available, then this function triggers a
707\ failure and does not return.
708cc: check-validity-range ( na-days na-seconds nb-days nb-seconds -- int ) {
709	uint32_t nbs = T0_POP();
710	uint32_t nbd = T0_POP();
711	uint32_t nas = T0_POP();
712	uint32_t nad = T0_POP();
713	int r;
714	if (CTX->itime != 0) {
715		r = CTX->itime(CTX->itime_ctx, nbd, nbs, nad, nas);
716		if (r < -1 || r > 1) {
717			CTX->err = BR_ERR_X509_TIME_UNKNOWN;
718			T0_CO();
719		}
720	} else {
721		uint32_t vd = CTX->days;
722		uint32_t vs = CTX->seconds;
723		if (vd == 0 && vs == 0) {
724#if BR_USE_UNIX_TIME
725			time_t x = time(NULL);
726
727			vd = (uint32_t)(x / 86400) + 719528;
728			vs = (uint32_t)(x % 86400);
729#elif BR_USE_WIN32_TIME
730			FILETIME ft;
731			uint64_t x;
732
733			GetSystemTimeAsFileTime(&ft);
734			x = ((uint64_t)ft.dwHighDateTime << 32)
735				+ (uint64_t)ft.dwLowDateTime;
736			x = (x / 10000000);
737			vd = (uint32_t)(x / 86400) + 584754;
738			vs = (uint32_t)(x % 86400);
739#else
740			CTX->err = BR_ERR_X509_TIME_UNKNOWN;
741			T0_CO();
742#endif
743		}
744		if (vd < nbd || (vd == nbd && vs < nbs)) {
745			r = -1;
746		} else if (vd > nad || (vd == nad && vs > nas)) {
747			r = 1;
748		} else {
749			r = 0;
750		}
751	}
752	T0_PUSHi(r);
753}
754
755\ Swap the top two elements with the two elements immediately below.
756: swap2 ( a b c d -- c d a b )
757	3 roll 3 roll ;
758
759\ Match the name in the pad with the expected server name. Returned value
760\ is true (-1) on match, false (0) otherwise. If there is no expected
761\ server name, then 0 is returned.
762\ Match conditions: either an exact match (case insensitive), or a
763\ wildcard match, if the found name starts with "*.". We only match a
764\ starting wildcard, and only against a complete DN name component.
765cc: match-server-name ( -- bool ) {
766	size_t n1, n2;
767
768	if (CTX->server_name == NULL) {
769		T0_PUSH(0);
770		T0_RET();
771	}
772	n1 = strlen(CTX->server_name);
773	n2 = CTX->pad[0];
774	if (n1 == n2 && eqnocase(&CTX->pad[1], CTX->server_name, n1)) {
775		T0_PUSHi(-1);
776		T0_RET();
777	}
778	if (n2 >= 2 && CTX->pad[1] == '*' && CTX->pad[2] == '.') {
779		size_t u;
780
781		u = 0;
782		while (u < n1 && CTX->server_name[u] != '.') {
783			u ++;
784		}
785		u ++;
786		n1 -= u;
787		if ((n2 - 2) == n1
788			&& eqnocase(&CTX->pad[3], CTX->server_name + u, n1))
789		{
790			T0_PUSHi(-1);
791			T0_RET();
792		}
793	}
794	T0_PUSH(0);
795}
796
797\ Get the address and length for the pkey_data buffer.
798: addr-len-pkey_data ( -- addr len )
799	CX 0 8191 { offsetof(br_x509_minimal_context, pkey_data) }
800	CX 0 8191 { BR_X509_BUFSIZE_KEY } ;
801
802\ Copy the EE public key to the permanent buffer (RSA).
803cc: copy-ee-rsa-pkey ( nlen elen -- ) {
804	size_t elen = T0_POP();
805	size_t nlen = T0_POP();
806	memcpy(CTX->ee_pkey_data, CTX->pkey_data, nlen + elen);
807	CTX->pkey.key_type = BR_KEYTYPE_RSA;
808	CTX->pkey.key.rsa.n = CTX->ee_pkey_data;
809	CTX->pkey.key.rsa.nlen = nlen;
810	CTX->pkey.key.rsa.e = CTX->ee_pkey_data + nlen;
811	CTX->pkey.key.rsa.elen = elen;
812}
813
814\ Copy the EE public key to the permanent buffer (EC).
815cc: copy-ee-ec-pkey ( curve qlen -- ) {
816	size_t qlen = T0_POP();
817	uint32_t curve = T0_POP();
818	memcpy(CTX->ee_pkey_data, CTX->pkey_data, qlen);
819	CTX->pkey.key_type = BR_KEYTYPE_EC;
820	CTX->pkey.key.ec.curve = curve;
821	CTX->pkey.key.ec.q = CTX->ee_pkey_data;
822	CTX->pkey.key.ec.qlen = qlen;
823}
824
825\ Check whether the current certificate (EE) is directly trusted.
826cc: check-direct-trust ( -- ) {
827	size_t u;
828
829	for (u = 0; u < CTX->trust_anchors_num; u ++) {
830		const br_x509_trust_anchor *ta;
831		unsigned char hashed_DN[64];
832		int kt;
833
834		ta = &CTX->trust_anchors[u];
835		if (ta->flags & BR_X509_TA_CA) {
836			continue;
837		}
838		hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN);
839		if (memcmp(hashed_DN, CTX->current_dn_hash, DNHASH_LEN)) {
840			continue;
841		}
842		kt = CTX->pkey.key_type;
843		if ((ta->pkey.key_type & 0x0F) != kt) {
844			continue;
845		}
846		switch (kt) {
847
848		case BR_KEYTYPE_RSA:
849			if (!eqbigint(CTX->pkey.key.rsa.n,
850				CTX->pkey.key.rsa.nlen,
851				ta->pkey.key.rsa.n,
852				ta->pkey.key.rsa.nlen)
853				|| !eqbigint(CTX->pkey.key.rsa.e,
854				CTX->pkey.key.rsa.elen,
855				ta->pkey.key.rsa.e,
856				ta->pkey.key.rsa.elen))
857			{
858				continue;
859			}
860			break;
861
862		case BR_KEYTYPE_EC:
863			if (CTX->pkey.key.ec.curve != ta->pkey.key.ec.curve
864				|| CTX->pkey.key.ec.qlen != ta->pkey.key.ec.qlen
865				|| memcmp(CTX->pkey.key.ec.q,
866					ta->pkey.key.ec.q,
867					ta->pkey.key.ec.qlen) != 0)
868			{
869				continue;
870			}
871			break;
872
873		default:
874			continue;
875		}
876
877		/*
878		 * Direct trust match!
879		 */
880		CTX->err = BR_ERR_X509_OK;
881		T0_CO();
882	}
883}
884
885\ Check the signature on the certificate with regards to all trusted CA.
886\ We use the issuer hash (in saved_dn_hash[]) as CA identifier.
887cc: check-trust-anchor-CA ( -- ) {
888	size_t u;
889
890	for (u = 0; u < CTX->trust_anchors_num; u ++) {
891		const br_x509_trust_anchor *ta;
892		unsigned char hashed_DN[64];
893
894		ta = &CTX->trust_anchors[u];
895		if (!(ta->flags & BR_X509_TA_CA)) {
896			continue;
897		}
898		hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN);
899		if (memcmp(hashed_DN, CTX->saved_dn_hash, DNHASH_LEN)) {
900			continue;
901		}
902		if (verify_signature(CTX, &ta->pkey) == 0) {
903			CTX->err = BR_ERR_X509_OK;
904			T0_CO();
905		}
906	}
907}
908
909\ Verify RSA signature. This uses the public key that was just decoded
910\ into CTX->pkey_data; the modulus and exponent length are provided as
911\ parameters. The resulting hash value is compared with the one in
912\ tbs_hash. Returned value is 0 on success, or a non-zero error code.
913cc: do-rsa-vrfy ( nlen elen -- err ) {
914	size_t elen = T0_POP();
915	size_t nlen = T0_POP();
916	br_x509_pkey pk;
917
918	pk.key_type = BR_KEYTYPE_RSA;
919	pk.key.rsa.n = CTX->pkey_data;
920	pk.key.rsa.nlen = nlen;
921	pk.key.rsa.e = CTX->pkey_data + nlen;
922	pk.key.rsa.elen = elen;
923	T0_PUSH(verify_signature(CTX, &pk));
924}
925
926\ Verify ECDSA signature. This uses the public key that was just decoded
927\ into CTX->pkey_dayta; the curve ID and public point length are provided
928\ as parameters. The hash value in tbs_hash is used. Returned value is 0
929\ on success, or non-zero error code.
930cc: do-ecdsa-vrfy ( curve qlen -- err ) {
931	size_t qlen = T0_POP();
932	int curve = T0_POP();
933	br_x509_pkey pk;
934
935	pk.key_type = BR_KEYTYPE_EC;
936	pk.key.ec.curve = curve;
937	pk.key.ec.q = CTX->pkey_data;
938	pk.key.ec.qlen = qlen;
939	T0_PUSH(verify_signature(CTX, &pk));
940}
941
942cc: print-bytes ( addr len -- ) {
943	extern int printf(const char *fmt, ...);
944	size_t len = T0_POP();
945	unsigned char *buf = (unsigned char *)CTX + T0_POP();
946	size_t u;
947
948	for (u = 0; u < len; u ++) {
949		printf("%02X", buf[u]);
950	}
951}
952
953cc: printOID ( -- ) {
954	extern int printf(const char *fmt, ...);
955	size_t u, len;
956
957	len = CTX->pad[0];
958	if (len == 0) {
959		printf("*");
960		T0_RET();
961	}
962	printf("%u.%u", CTX->pad[1] / 40, CTX->pad[1] % 40);
963	u = 2;
964	while (u <= len) {
965		unsigned long ul;
966
967		ul = 0;
968		for (;;) {
969			int x;
970
971			if (u > len) {
972				printf("BAD");
973				T0_RET();
974			}
975			x = CTX->pad[u ++];
976			ul = (ul << 7) + (x & 0x7F);
977			if (!(x & 0x80)) {
978				break;
979			}
980		}
981		printf(".%lu", ul);
982	}
983}
984
985\ Extensions with specific processing.
986OID: basicConstraints      2.5.29.19
987OID: keyUsage              2.5.29.15
988OID: subjectAltName        2.5.29.17
989OID: certificatePolicies   2.5.29.32
990
991\ Policy qualifier "pointer to CPS"
992OID: id-qt-cps             1.3.6.1.5.5.7.2.1
993
994\ Extensions which are ignored when encountered, even if critical.
995OID: authorityKeyIdentifier        2.5.29.35
996OID: subjectKeyIdentifier          2.5.29.14
997OID: issuerAltName                 2.5.29.18
998OID: subjectDirectoryAttributes    2.5.29.9
999OID: crlDistributionPoints         2.5.29.31
1000OID: freshestCRL                   2.5.29.46
1001OID: authorityInfoAccess           1.3.6.1.5.5.7.1.1
1002OID: subjectInfoAccess             1.3.6.1.5.5.7.1.11
1003
1004\ Process a Basic Constraints extension. This should be called only if
1005\ the certificate is not the EE. We check that the extension contains
1006\ the "CA" flag, and that the path length, if specified, is compatible
1007\ with the current chain length.
1008: process-basicConstraints ( lim -- lim )
1009	read-sequence-open
1010	read-tag-or-end
1011	dup 0x01 = if
1012		read-boolean ifnot ERR_X509_NOT_CA fail then
1013		read-tag-or-end
1014	else
1015		ERR_X509_NOT_CA fail
1016	then
1017	dup 0x02 = if
1018		drop check-primitive read-small-int-value
1019		addr-num_certs get32 1- < if ERR_X509_NOT_CA fail then
1020		read-tag-or-end
1021	then
1022	-1 <> if ERR_X509_UNEXPECTED fail then
1023	drop
1024	close-elt
1025	;
1026
1027\ Process a Key Usage extension.
1028\ For the EE certificate:
1029\   -- if the key usage contains keyEncipherment (2), dataEncipherment (3)
1030\      or keyAgreement (4), then the "key exchange" usage is allowed;
1031\   -- if the key usage contains digitalSignature (0) or nonRepudiation (1),
1032\      then the "signature" usage is allowed.
1033\ For CA certificates, the extension must contain keyCertSign (5).
1034: process-keyUsage ( lim ee -- lim )
1035	{ ee }
1036
1037	\ Read tag for the BIT STRING and open it.
1038	read-tag 0x03 check-tag-primitive
1039	read-length-open-elt
1040	\ First byte indicates number of ignored bits in the last byte. It
1041	\ must be between 0 and 7.
1042	read8 { ign }
1043	ign 7 > if ERR_X509_UNEXPECTED fail then
1044	\ Depending on length, we have either 0, 1 or more bytes to read.
1045	dup case
1046		0 of ERR_X509_FORBIDDEN_KEY_USAGE fail endof
1047		1 of read8 ign >> ign << endof
1048		drop read8 0
1049	endcase
1050
1051	\ Check bits.
1052	ee if
1053		\ EE: get usages.
1054		0
1055		over 0x38 and if 0x10 or then
1056		swap 0xC0 and if 0x20 or then
1057		addr-key_usages set8
1058	else
1059		\ Not EE: keyCertSign must be set.
1060		0x04 and ifnot ERR_X509_FORBIDDEN_KEY_USAGE fail then
1061	then
1062
1063	\ We don't care about subsequent bytes.
1064	skip-close-elt ;
1065
1066\ Process a Certificate Policies extension.
1067\
1068\ Since we don't actually support full policies processing, this function
1069\ only checks that the extension contents can be safely ignored. Indeed,
1070\ we don't validate against a specific set of policies (in RFC 5280
1071\ terminology, user-initial-policy-set only contains the special value
1072\ any-policy). Moreover, we don't support policy constraints (if a
1073\ critical Policy Constraints extension is encountered, the validation
1074\ will fail). Therefore, we can safely ignore the contents of this
1075\ extension, except if it is critical AND one of the policy OID has a
1076\ qualifier which is distinct from id-qt-cps (because id-qt-cps is
1077\ specially designated by RFC 5280 has having no mandated action).
1078\
1079\ This function is called only if the extension is critical.
1080: process-certPolicies ( lim -- lim )
1081	\ Extension value is a SEQUENCE OF PolicyInformation.
1082	read-sequence-open
1083	begin dup while
1084		\ PolicyInformation ::= SEQUENCE {
1085		\    policyIdentifier  OBJECT IDENTIFIER,
1086		\    policyQualifiers  SEQUENCE OF PolicyQualifierInfo OPTIONAL
1087		\ }
1088		read-sequence-open
1089		read-OID drop
1090		dup if
1091			read-sequence-open
1092			begin dup while
1093				\ PolicyQualifierInfo ::= SEQUENCE {
1094				\    policyQualifierId  OBJECT IDENTIFIER,
1095				\    qualifier          ANY
1096				\ }
1097				read-sequence-open
1098				read-OID drop id-qt-cps eqOID ifnot
1099					ERR_X509_CRITICAL_EXTENSION fail
1100				then
1101				skip-close-elt
1102			repeat
1103			close-elt
1104		then
1105		close-elt
1106	repeat
1107	close-elt ;
1108
1109\ Process a Subject Alt Name extension. Returned value is a boolean set
1110\ to true if the expected server name was matched against a dNSName in
1111\ the extension.
1112: process-SAN ( lim -- lim bool )
1113	0 { m }
1114	read-sequence-open
1115	begin dup while
1116		\ Read the tag. If the tag is context-0, then parse an
1117		\ 'otherName'. If the tag is context-2, then parse a
1118		\ dNSName. If the tag is context-1 or context-6,
1119		\ parse
1120		read-tag case
1121			\ OtherName
1122			0x20 of
1123				\ OtherName ::= SEQUENCE {
1124				\     type-id   OBJECT IDENTIFIER,
1125				\     value     [0] EXPLICIT ANY
1126				\ }
1127				check-constructed read-length-open-elt
1128				read-OID drop
1129				-1 offset-name-element { offbuf }
1130				read-tag 0x20 check-tag-constructed
1131				read-length-open-elt
1132				read-string offbuf copy-name-element
1133				close-elt
1134				close-elt
1135			endof
1136			\ rfc822Name (IA5String)
1137			0x21 of
1138				check-primitive
1139				read-value-UTF8 1 copy-name-SAN
1140			endof
1141			\ dNSName (IA5String)
1142			0x22 of
1143				check-primitive
1144				read-value-UTF8
1145				dup if match-server-name m or >m then
1146				2 copy-name-SAN
1147			endof
1148			\ uniformResourceIdentifier (IA5String)
1149			0x26 of
1150				check-primitive
1151				read-value-UTF8 6 copy-name-SAN
1152			endof
1153			2drop read-length-skip 0
1154		endcase
1155
1156		\ We check only names of type dNSName; they use IA5String,
1157		\ which is basically ASCII.
1158		\ read-tag 0x22 = if
1159		\ 	check-primitive
1160		\ 	read-small-value drop
1161		\ 	match-server-name m or >m
1162		\ else
1163		\ 	drop read-length-skip
1164		\ then
1165	repeat
1166	close-elt
1167	m ;
1168
1169\ Decode a certificate. The "ee" boolean must be true for the EE.
1170: decode-certificate ( ee -- )
1171	{ ee }
1172
1173	\ Obtain the total certificate length.
1174	addr-cert_length get32
1175
1176	\ Open the outer SEQUENCE.
1177	read-sequence-open
1178
1179	\ TBS
1180	\ Activate hashing.
1181	start-tbs-hash
1182	read-sequence-open
1183
1184	\ First element may be an explicit version. We accept only
1185	\ versions 0 to 2 (certificates v1 to v3).
1186	read-tag dup 0x20 = if
1187		drop check-constructed read-length-open-elt
1188		read-tag
1189		0x02 check-tag-primitive
1190		read-small-int-value
1191		2 > if ERR_X509_UNSUPPORTED fail then
1192		close-elt
1193		read-tag
1194	then
1195
1196	\ Serial number. We just check that the tag is correct.
1197	0x02 check-tag-primitive
1198	read-length-skip
1199
1200	\ Signature algorithm. This structure is redundant with the one
1201	\ on the outside; we just skip it.
1202	read-sequence-open skip-close-elt
1203
1204	\ Issuer name: hashed, then copied into next_dn_hash[].
1205	read-DN
1206	addr-next_dn_hash addr-current_dn_hash dn-hash-length blobcopy
1207
1208	\ Validity dates.
1209	read-sequence-open
1210	read-date { nbd nbs } read-date nbd nbs check-validity-range
1211	if ERR_X509_EXPIRED fail then
1212	close-elt
1213
1214	\ Subject name.
1215	ee if
1216		\ For the EE, we must check whether the Common Name, if
1217		\ any, matches the expected server name.
1218		read-DN-EE { eename }
1219	else
1220		\ For a non-EE certificate, the hashed subject DN must match
1221		\ the saved hashed issuer DN from the previous certificate.
1222		read-DN
1223		addr-current_dn_hash addr-saved_dn_hash dn-hash-length eqblob
1224		ifnot ERR_X509_DN_MISMATCH fail then
1225	then
1226	\ Move the hashed issuer DN for this certificate into the
1227	\ saved_dn_hash[] array.
1228	addr-saved_dn_hash addr-next_dn_hash dn-hash-length blobcopy
1229
1230	\ Public Key.
1231	read-sequence-open
1232	\ Algorithm Identifier. Right now we are only interested in the
1233	\ OID, since we only support RSA keys.
1234	read-sequence-open
1235	read-OID ifnot ERR_X509_UNSUPPORTED fail then
1236	{ ; pkey-type }
1237	choice
1238		\ RSA public key.
1239		rsaEncryption eqOID uf
1240			skip-close-elt
1241			\ Public key itself: the BIT STRING contains bytes
1242			\ (no partial byte) and these bytes encode the
1243			\ actual value.
1244			read-bits-open
1245				\ RSA public key is a SEQUENCE of two
1246				\ INTEGER. We get both INTEGER values into
1247				\ the pkey_data[] buffer, if they fit.
1248				read-sequence-open
1249				addr-len-pkey_data
1250				read-integer { nlen }
1251				addr-len-pkey_data swap nlen + swap nlen -
1252				read-integer { elen }
1253				close-elt
1254
1255				\ Check that the public key fits our minimal
1256				\ size requirements. Note that the integer
1257				\ decoder already skipped the leading bytes
1258				\ of value 0, so we are working on the true
1259				\ modulus length here.
1260				addr-min_rsa_size get16 128 + nlen > if
1261					ERR_X509_WEAK_PUBLIC_KEY fail
1262				then
1263			close-elt
1264			KEYTYPE_RSA >pkey-type
1265		enduf
1266
1267		\ EC public key.
1268		id-ecPublicKey eqOID uf
1269			\ We support only named curves, for which the
1270			\ "parameters" field in the AlgorithmIdentifier
1271			\ field should be an OID.
1272			read-OID ifnot ERR_X509_UNSUPPORTED fail then
1273			choice
1274				ansix9p256r1 eqOID uf 23 enduf
1275				ansix9p384r1 eqOID uf 24 enduf
1276				ansix9p521r1 eqOID uf 25 enduf
1277				ERR_X509_UNSUPPORTED fail
1278			endchoice
1279			{ curve }
1280			close-elt
1281			read-bits-open
1282			dup { qlen }
1283			dup addr-len-pkey_data rot < if
1284				ERR_X509_LIMIT_EXCEEDED fail
1285			then
1286			read-blob
1287			KEYTYPE_EC >pkey-type
1288		enduf
1289
1290		\ Not a recognised public key type.
1291		ERR_X509_UNSUPPORTED fail
1292	endchoice
1293	close-elt
1294
1295	\ Process public key.
1296	ee if
1297		\ For the EE certificate, copy the key data to the
1298		\ relevant buffer.
1299		pkey-type case
1300			KEYTYPE_RSA of nlen elen copy-ee-rsa-pkey endof
1301			KEYTYPE_EC of curve qlen copy-ee-ec-pkey endof
1302			ERR_X509_UNSUPPORTED fail
1303		endcase
1304	else
1305		\ Verify signature on previous certificate. We invoke
1306		\ the RSA implementation.
1307		pkey-type case
1308			KEYTYPE_RSA of nlen elen do-rsa-vrfy endof
1309			KEYTYPE_EC of curve qlen do-ecdsa-vrfy endof
1310			ERR_X509_UNSUPPORTED fail
1311		endcase
1312		dup if fail then
1313		drop
1314	then
1315
1316	\ This flag will be set to true if the Basic Constraints extension
1317	\ is encountered.
1318	0 { seenBC }
1319
1320	\ Skip issuerUniqueID and subjectUniqueID, and process extensions
1321	\ if present. Extensions are an explicit context tag of value 3
1322	\ around a SEQUENCE OF extensions. Each extension is a SEQUENCE
1323	\ with an OID, an optional boolean, and a value; the value is
1324	\ an OCTET STRING.
1325	read-tag-or-end
1326	0x21 iftag-skip
1327	0x22 iftag-skip
1328	dup 0x23 = if
1329		drop
1330		check-constructed read-length-open-elt
1331		read-sequence-open
1332		begin dup while
1333			0 { critical }
1334			read-sequence-open
1335			read-OID drop
1336			read-tag dup 0x01 = if
1337				read-boolean >critical
1338				read-tag
1339			then
1340			0x04 check-tag-primitive read-length-open-elt
1341			choice
1342				\ Extensions with specific processing.
1343				basicConstraints eqOID uf
1344					ee if
1345						skip-remaining
1346					else
1347						process-basicConstraints
1348						-1 >seenBC
1349					then
1350				enduf
1351				keyUsage         eqOID uf
1352					ee process-keyUsage
1353				enduf
1354				subjectAltName   eqOID uf
1355					ee if
1356						0 >eename
1357						process-SAN >eename
1358					else
1359						skip-remaining
1360					then
1361				enduf
1362
1363				\ We don't implement full processing of
1364				\ policies. The call below mostly checks
1365				\ that the contents of the Certificate
1366				\ Policies extension can be safely ignored.
1367				certificatePolicies eqOID uf
1368					critical if
1369						process-certPolicies
1370					else
1371						skip-remaining
1372					then
1373				enduf
1374
1375				\ Extensions which are always ignored,
1376				\ even if critical.
1377				authorityKeyIdentifier     eqOID uf
1378					skip-remaining
1379				enduf
1380				subjectKeyIdentifier       eqOID uf
1381					skip-remaining
1382				enduf
1383				issuerAltName              eqOID uf
1384					skip-remaining
1385				enduf
1386				subjectDirectoryAttributes eqOID uf
1387					skip-remaining
1388				enduf
1389				crlDistributionPoints      eqOID uf
1390					skip-remaining
1391				enduf
1392				freshestCRL                eqOID uf
1393					skip-remaining
1394				enduf
1395				authorityInfoAccess        eqOID uf
1396					skip-remaining
1397				enduf
1398				subjectInfoAccess          eqOID uf
1399					skip-remaining
1400				enduf
1401
1402				\ Unrecognized extensions trigger a failure
1403				\ if critical; otherwise, they are just
1404				\ ignored.
1405				critical if
1406					ERR_X509_CRITICAL_EXTENSION fail
1407				then
1408				skip-remaining
1409			endchoice
1410			close-elt
1411			close-elt
1412		repeat
1413		close-elt
1414		close-elt
1415	else
1416		-1 = ifnot ERR_X509_UNEXPECTED fail then
1417		drop
1418	then
1419
1420	close-elt
1421	\ Terminate hashing.
1422	stop-tbs-hash
1423
1424	\ For the EE certificate, verify that the intended server name
1425	\ was matched.
1426	ee if
1427		eename zero-server-name or ifnot
1428			ERR_X509_BAD_SERVER_NAME fail
1429		then
1430	then
1431
1432	\ If this is the EE certificate, then direct trust may apply.
1433	\ Note: we do this at this point, not immediately after decoding
1434	\ the public key, because even in case of direct trust we still
1435	\ want to check the server name with regards to the SAN extension.
1436	\ However, we want to check direct trust before trying to decode
1437	\ the signature algorithm, because it should work even if that
1438	\ algorithm is not supported.
1439	ee if check-direct-trust then
1440
1441	\ Non-EE certificates MUST have a Basic Constraints extension
1442	\ (that marks them as being CA).
1443	ee seenBC or ifnot ERR_X509_NOT_CA fail then
1444
1445	\ signature algorithm
1446	read-tag check-sequence read-length-open-elt
1447	\ Read and understand the OID. Right now, we support only
1448	\ RSA with PKCS#1 v1.5 padding, and hash functions SHA-1,
1449	\ SHA-224, SHA-256, SHA-384 and SHA-512. We purposely do NOT
1450	\ support MD5 here.
1451	\ TODO: add support for RSA/PSS
1452	read-OID if
1453		\ Based on the signature OID, we get:
1454		\ -- the signing key type
1455		\ -- the hash function numeric identifier
1456		\ -- the hash function OID
1457		choice
1458			sha1WithRSAEncryption   eqOID
1459				uf 2 KEYTYPE_RSA id-sha1   enduf
1460			sha224WithRSAEncryption eqOID
1461				uf 3 KEYTYPE_RSA id-sha224 enduf
1462			sha256WithRSAEncryption eqOID
1463				uf 4 KEYTYPE_RSA id-sha256 enduf
1464			sha384WithRSAEncryption eqOID
1465				uf 5 KEYTYPE_RSA id-sha384 enduf
1466			sha512WithRSAEncryption eqOID
1467				uf 6 KEYTYPE_RSA id-sha512 enduf
1468
1469			ecdsa-with-SHA1   eqOID
1470				uf 2 KEYTYPE_EC id-sha1 enduf
1471			ecdsa-with-SHA224 eqOID
1472				uf 3 KEYTYPE_EC id-sha224 enduf
1473			ecdsa-with-SHA256 eqOID
1474				uf 4 KEYTYPE_EC id-sha256 enduf
1475			ecdsa-with-SHA384 eqOID
1476				uf 5 KEYTYPE_EC id-sha384 enduf
1477			ecdsa-with-SHA512 eqOID
1478				uf 6 KEYTYPE_EC id-sha512 enduf
1479			ERR_X509_UNSUPPORTED fail
1480		endchoice
1481		addr-cert_sig_hash_oid set16
1482		addr-cert_signer_key_type set8
1483
1484		\ Compute the TBS hash into tbs_hash.
1485		compute-tbs-hash
1486		dup ifnot ERR_X509_UNSUPPORTED fail then
1487		addr-cert_sig_hash_len set8
1488	else
1489		ERR_X509_UNSUPPORTED fail
1490	then
1491	\ We ignore the parameters, whether they are present or not,
1492	\ because we got all the information from the OID.
1493	skip-close-elt
1494
1495	\ signature value
1496	read-bits-open
1497	dup CX 0 8191 { BR_X509_BUFSIZE_SIG } > if
1498		ERR_X509_LIMIT_EXCEEDED fail
1499	then
1500	dup addr-cert_sig_len set16
1501	addr-cert_sig read-blob
1502
1503	\ Close the outer SEQUENCE.
1504	close-elt
1505
1506	\ Close the advertised total certificate length. This checks that
1507	\ there is no trailing garbage after the certificate.
1508	close-elt
1509
1510	\ Flag the certificate as fully processed.
1511	0 addr-cert_length set32
1512
1513	\ Check whether the issuer for the current certificate is known
1514	\ as a trusted CA; in which case, verify the signature.
1515	check-trust-anchor-CA ;
1516
1517: main
1518	\ Unless restricted by a Key Usage extension, all usages are
1519	\ deemed allowed.
1520	0x30 addr-key_usages set8
1521	-1 decode-certificate
1522	co
1523	begin
1524		0 decode-certificate co
1525	again
1526	;
1527