385972b4c89ff77da5563b39014d693d3f928c3c
[BearSSL] / src / x509 / x509_minimal.t0
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
23 preamble {
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 legnth 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 #ifndef BR_USE_UNIX_TIME
153 #if defined __unix__ || defined __linux__ \
154 || defined _POSIX_SOURCE || defined _POSIX_C_SOURCE \
155 || (defined __APPLE__ && defined __MACH__)
156 #define BR_USE_UNIX_TIME 1
157 #endif
158 #endif
159
160 #ifndef BR_USE_WIN32_TIME
161 #if defined _WIN32 || defined _WIN64
162 #define BR_USE_WIN32_TIME 1
163 #endif
164 #endif
165
166 #if BR_USE_UNIX_TIME
167 #include <time.h>
168 #endif
169
170 #if BR_USE_WIN32_TIME
171 #include <windows.h>
172 #endif
173
174 void br_x509_minimal_init_main(void *ctx);
175 void br_x509_minimal_run(void *ctx);
176
177 /* see bearssl_x509.h */
178 void
179 br_x509_minimal_init(br_x509_minimal_context *ctx,
180 const br_hash_class *dn_hash_impl,
181 const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num)
182 {
183 memset(ctx, 0, sizeof *ctx);
184 ctx->vtable = &br_x509_minimal_vtable;
185 ctx->dn_hash_impl = dn_hash_impl;
186 ctx->trust_anchors = trust_anchors;
187 ctx->trust_anchors_num = trust_anchors_num;
188 }
189
190 static void
191 xm_start_chain(const br_x509_class **ctx, const char *server_name)
192 {
193 br_x509_minimal_context *cc;
194
195 cc = (br_x509_minimal_context *)ctx;
196 memset(&cc->pkey, 0, sizeof cc->pkey);
197 cc->num_certs = 0;
198 cc->err = 0;
199 cc->cpu.dp = cc->dp_stack;
200 cc->cpu.rp = cc->rp_stack;
201 br_x509_minimal_init_main(&cc->cpu);
202 if (server_name == NULL || *server_name == 0) {
203 cc->server_name = NULL;
204 } else {
205 cc->server_name = server_name;
206 }
207 }
208
209 static void
210 xm_start_cert(const br_x509_class **ctx, uint32_t length)
211 {
212 br_x509_minimal_context *cc;
213
214 cc = (br_x509_minimal_context *)ctx;
215 if (cc->err != 0) {
216 return;
217 }
218 if (length == 0) {
219 cc->err = BR_ERR_X509_TRUNCATED;
220 return;
221 }
222 cc->cert_length = length;
223 }
224
225 static void
226 xm_append(const br_x509_class **ctx, const unsigned char *buf, size_t len)
227 {
228 br_x509_minimal_context *cc;
229
230 cc = (br_x509_minimal_context *)ctx;
231 if (cc->err != 0) {
232 return;
233 }
234 cc->hbuf = buf;
235 cc->hlen = len;
236 br_x509_minimal_run(&cc->cpu);
237 }
238
239 static void
240 xm_end_cert(const br_x509_class **ctx)
241 {
242 br_x509_minimal_context *cc;
243
244 cc = (br_x509_minimal_context *)ctx;
245 if (cc->err == 0 && cc->cert_length != 0) {
246 cc->err = BR_ERR_X509_TRUNCATED;
247 }
248 cc->num_certs ++;
249 }
250
251 static unsigned
252 xm_end_chain(const br_x509_class **ctx)
253 {
254 br_x509_minimal_context *cc;
255
256 cc = (br_x509_minimal_context *)ctx;
257 if (cc->err == 0) {
258 if (cc->num_certs == 0) {
259 cc->err = BR_ERR_X509_EMPTY_CHAIN;
260 } else {
261 cc->err = BR_ERR_X509_NOT_TRUSTED;
262 }
263 } else if (cc->err == BR_ERR_X509_OK) {
264 return 0;
265 }
266 return (unsigned)cc->err;
267 }
268
269 static const br_x509_pkey *
270 xm_get_pkey(const br_x509_class *const *ctx, unsigned *usages)
271 {
272 br_x509_minimal_context *cc;
273
274 cc = (br_x509_minimal_context *)ctx;
275 if (cc->err == BR_ERR_X509_OK
276 || cc->err == BR_ERR_X509_NOT_TRUSTED)
277 {
278 if (usages != NULL) {
279 *usages = cc->key_usages;
280 }
281 return &((br_x509_minimal_context *)ctx)->pkey;
282 } else {
283 return NULL;
284 }
285 }
286
287 /* see bearssl_x509.h */
288 const br_x509_class br_x509_minimal_vtable = {
289 sizeof(br_x509_minimal_context),
290 xm_start_chain,
291 xm_start_cert,
292 xm_append,
293 xm_end_cert,
294 xm_end_chain,
295 xm_get_pkey
296 };
297
298 #define CTX ((br_x509_minimal_context *)((unsigned char *)t0ctx - offsetof(br_x509_minimal_context, cpu)))
299 #define CONTEXT_NAME br_x509_minimal_context
300
301 #define DNHASH_LEN ((CTX->dn_hash_impl->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK)
302
303 /*
304 * Hash a DN (from a trust anchor) into the provided buffer. This uses the
305 * DN hash implementation and context structure from the X.509 engine
306 * context.
307 */
308 static void
309 hash_dn(br_x509_minimal_context *ctx, const void *dn, size_t len,
310 unsigned char *out)
311 {
312 ctx->dn_hash_impl->init(&ctx->dn_hash.vtable);
313 ctx->dn_hash_impl->update(&ctx->dn_hash.vtable, dn, len);
314 ctx->dn_hash_impl->out(&ctx->dn_hash.vtable, out);
315 }
316
317 /*
318 * Compare two big integers for equality. The integers use unsigned big-endian
319 * encoding; extra leading bytes (of value 0) are allowed.
320 */
321 static int
322 eqbigint(const unsigned char *b1, size_t len1,
323 const unsigned char *b2, size_t len2)
324 {
325 while (len1 > 0 && *b1 == 0) {
326 b1 ++;
327 len1 --;
328 }
329 while (len2 > 0 && *b2 == 0) {
330 b2 ++;
331 len2 --;
332 }
333 if (len1 != len2) {
334 return 0;
335 }
336 return memcmp(b1, b2, len1) == 0;
337 }
338
339 /*
340 * Verify the signature on the certificate with the provided public key.
341 * This function checks the public key type with regards to the expected
342 * type. Returned value is either 0 on success, or a non-zero error code.
343 */
344 static int
345 verify_signature(br_x509_minimal_context *ctx, const br_x509_pkey *pk)
346 {
347 int kt;
348
349 kt = ctx->cert_signer_key_type;
350 if ((pk->key_type & 0x0F) != kt) {
351 return BR_ERR_X509_WRONG_KEY_TYPE;
352 }
353 switch (kt) {
354 unsigned char tmp[64];
355
356 case BR_KEYTYPE_RSA:
357 if (ctx->irsa == 0) {
358 return BR_ERR_X509_UNSUPPORTED;
359 }
360 if (!ctx->irsa(ctx->cert_sig, ctx->cert_sig_len,
361 &t0_datablock[ctx->cert_sig_hash_oid],
362 ctx->cert_sig_hash_len, &pk->key.rsa, tmp))
363 {
364 return BR_ERR_X509_BAD_SIGNATURE;
365 }
366 if (memcmp(ctx->tbs_hash, tmp, ctx->cert_sig_hash_len) != 0) {
367 return BR_ERR_X509_BAD_SIGNATURE;
368 }
369 return 0;
370
371 case BR_KEYTYPE_EC:
372 if (ctx->iecdsa == 0) {
373 return BR_ERR_X509_UNSUPPORTED;
374 }
375 if (!ctx->iecdsa(ctx->iec, ctx->tbs_hash,
376 ctx->cert_sig_hash_len, &pk->key.ec,
377 ctx->cert_sig, ctx->cert_sig_len))
378 {
379 return BR_ERR_X509_BAD_SIGNATURE;
380 }
381 return 0;
382
383 default:
384 return BR_ERR_X509_UNSUPPORTED;
385 }
386 }
387
388 /*
389 * Compare two strings for equality, in a case-insensitive way. This
390 * function handles casing only for ASCII letters.
391 */
392 static int
393 eqnocase(const void *s1, const void *s2, size_t len)
394 {
395 const unsigned char *buf1, *buf2;
396
397 buf1 = s1;
398 buf2 = s2;
399 while (len -- > 0) {
400 int x1, x2;
401
402 x1 = *buf1 ++;
403 x2 = *buf2 ++;
404 if (x1 >= 'A' && x1 <= 'Z') {
405 x1 += 'a' - 'A';
406 }
407 if (x2 >= 'A' && x2 <= 'Z') {
408 x2 += 'a' - 'A';
409 }
410 if (x1 != x2) {
411 return 0;
412 }
413 }
414 return 1;
415 }
416
417 }
418
419 cc: read8-low ( -- x ) {
420 if (CTX->hlen == 0) {
421 T0_PUSHi(-1);
422 } else {
423 unsigned char x = *CTX->hbuf ++;
424 if (CTX->do_mhash) {
425 br_multihash_update(&CTX->mhash, &x, 1);
426 }
427 if (CTX->do_dn_hash) {
428 CTX->dn_hash_impl->update(&CTX->dn_hash.vtable, &x, 1);
429 }
430 CTX->hlen --;
431 T0_PUSH(x);
432 }
433 }
434
435 addr: cert_length
436 addr: num_certs
437
438 cc: read-blob-inner ( addr len -- addr len ) {
439 uint32_t len = T0_POP();
440 uint32_t addr = T0_POP();
441 size_t clen = CTX->hlen;
442 if (clen > len) {
443 clen = (size_t)len;
444 }
445 if (addr != 0) {
446 memcpy((unsigned char *)CTX + addr, CTX->hbuf, clen);
447 }
448 if (CTX->do_mhash) {
449 br_multihash_update(&CTX->mhash, CTX->hbuf, clen);
450 }
451 if (CTX->do_dn_hash) {
452 CTX->dn_hash_impl->update(
453 &CTX->dn_hash.vtable, CTX->hbuf, clen);
454 }
455 CTX->hbuf += clen;
456 CTX->hlen -= clen;
457 T0_PUSH(addr + clen);
458 T0_PUSH(len - clen);
459 }
460
461 \ Compute the TBS hash, using the provided hash ID. The hash value is
462 \ written in the tbs_hash[] array, and the hash length is returned. If
463 \ the requested hash function is not supported, then 0 is returned.
464 cc: compute-tbs-hash ( id -- hashlen ) {
465 int id = T0_POPi();
466 size_t len;
467 len = br_multihash_out(&CTX->mhash, id, CTX->tbs_hash);
468 T0_PUSH(len);
469 }
470
471 \ Push true (-1) if no server name is expected in the EE certificate.
472 cc: zero-server-name ( -- bool ) {
473 T0_PUSHi(-(CTX->server_name == NULL));
474 }
475
476 addr: key_usages
477 addr: cert_sig
478 addr: cert_sig_len
479 addr: cert_signer_key_type
480 addr: cert_sig_hash_oid
481 addr: cert_sig_hash_len
482 addr: tbs_hash
483 addr: min_rsa_size
484
485 \ Start TBS hash computation. The hash functions are reinitialised.
486 cc: start-tbs-hash ( -- ) {
487 br_multihash_init(&CTX->mhash);
488 CTX->do_mhash = 1;
489 }
490
491 \ Stop TBS hash computation.
492 cc: stop-tbs-hash ( -- ) {
493 CTX->do_mhash = 0;
494 }
495
496 \ Start DN hash computation.
497 cc: start-dn-hash ( -- ) {
498 CTX->dn_hash_impl->init(&CTX->dn_hash.vtable);
499 CTX->do_dn_hash = 1;
500 }
501
502 \ Terminate DN hash computation and write the DN hash into the
503 \ current_dn_hash buffer.
504 cc: compute-dn-hash ( -- ) {
505 CTX->dn_hash_impl->out(&CTX->dn_hash.vtable, CTX->current_dn_hash);
506 CTX->do_dn_hash = 0;
507 }
508
509 \ Get the length of hash values obtained with the DN hasher.
510 cc: dn-hash-length ( -- len ) {
511 T0_PUSH(DNHASH_LEN);
512 }
513
514 \ Copy data between two areas in the context.
515 cc: blobcopy ( addr-dst addr-src len -- ) {
516 size_t len = T0_POP();
517 unsigned char *src = (unsigned char *)CTX + T0_POP();
518 unsigned char *dst = (unsigned char *)CTX + T0_POP();
519 memcpy(dst, src, len);
520 }
521
522 addr: current_dn_hash
523 addr: next_dn_hash
524 addr: saved_dn_hash
525
526 \ Read a DN. The normalized DN hash is computed and stored in the
527 \ current_dn_hash. The Common Name is also extracted to the pad, if
528 \ it is present and small enough (255 bytes at most); the CN length is
529 \ then written in pad[0]. If these conditions are not met, then pad[0]
530 \ is set to 0.
531 : read-DN ( lim -- lim )
532 \ Activate DN hashing.
533 start-dn-hash
534
535 \ Prepare pad.
536 0 addr-pad set8
537
538 \ Parse the DN structure: it is a SEQUENCE of SET of
539 \ AttributeTypeAndValue. Each AttributeTypeAndValue is a
540 \ SEQUENCE { OBJECT IDENTIFIER, ANY }.
541 read-sequence-open
542 begin
543 dup while
544
545 read-tag 0x11 check-tag-constructed read-length-open-elt
546 dup ifnot ERR_X509_BAD_DN fail then
547 begin
548 dup while
549
550 read-sequence-open
551 \ We want to recognize the OID for Common Name,
552 \ but we don't want to use read-OID because we
553 \ need to preserve the pad contents. Instead, we
554 \ use the fact that the encoding for the value of
555 \ id-at-commonName is 55 04 03 (three bytes).
556 read-tag 0x06 check-tag-primitive read-length-open-elt
557 dup 3 = if
558 read8 16 << { tmp }
559 read8 8 << tmp + >tmp
560 read8 tmp +
561 0x550403 = { isCN }
562 then
563 skip-close-elt
564
565 \ If this is a Common Name, then we want to copy
566 \ it to the pad, but only if it uses a mono-byte
567 \ encoding (Printable, Teletex or UTF-8).
568 isCN if
569 read-tag
570 dup dup 0x0C = swap 0x13 = or swap 0x14 = or if
571 check-primitive
572 read-small-value drop
573 close-elt
574 else
575 drop
576 0 addr-pad set8
577 skip-close-elt
578 then
579 else
580 skip-close-elt
581 then
582 repeat
583 close-elt
584 repeat
585 close-elt
586
587 \ Compute DN hash and deactivate DN hashing.
588 compute-dn-hash ;
589
590 \ Get the validation date and time from the context or system.
591 cc: get-system-date ( -- days seconds ) {
592 if (CTX->days == 0 && CTX->seconds == 0) {
593 #if BR_USE_UNIX_TIME
594 time_t x = time(NULL);
595
596 T0_PUSH((uint32_t)(x / 86400) + 719528);
597 T0_PUSH((uint32_t)(x % 86400));
598 #elif BR_USE_WIN32_TIME
599 FILETIME ft;
600 uint64_t x;
601
602 GetSystemTimeAsFileTime(&ft);
603 x = ((uint64_t)ft.dwHighDateTime << 32)
604 + (uint64_t)ft.dwLowDateTime;
605 x = (x / 10000000);
606 T0_PUSH((uint32_t)(x / 86400) + 584754);
607 T0_PUSH((uint32_t)(x % 86400));
608 #else
609 CTX->err = BR_ERR_X509_TIME_UNKNOWN;
610 T0_CO();
611 #endif
612 } else {
613 T0_PUSH(CTX->days);
614 T0_PUSH(CTX->seconds);
615 }
616 }
617
618 \ Compare two dates (days+seconds) together.
619 : before ( days1 seconds1 days2 seconds2 -- bool )
620 { d1 s1 d2 s2 }
621 d1 d2 = if s1 s2 < else d1 d2 < then ;
622
623 : after ( days1 seconds1 days2 seconds2 -- bool )
624 swap2 before ;
625
626 \ Swap the top two elements with the two elements immediately below.
627 : swap2 ( a b c d -- c d a b )
628 3 roll 3 roll ;
629
630 \ Match the name in the pad with the expected server name. Returned value
631 \ is true (-1) on match, false (0) otherwise. If there is no expected
632 \ server name, then 0 is returned.
633 \ Match conditions: either an exact match (case insensitive), or a
634 \ wildcard match, if the found name starts with "*.". We only match a
635 \ starting wildcard, and only against a complete DN name component.
636 cc: match-server-name ( -- bool ) {
637 size_t n1, n2;
638
639 if (CTX->server_name == NULL) {
640 T0_PUSH(0);
641 T0_RET();
642 }
643 n1 = strlen(CTX->server_name);
644 n2 = CTX->pad[0];
645 if (n1 == n2 && eqnocase(&CTX->pad[1], CTX->server_name, n1)) {
646 T0_PUSHi(-1);
647 T0_RET();
648 }
649 if (n2 >= 2 && CTX->pad[1] == '*' && CTX->pad[2] == '.') {
650 size_t u;
651
652 u = 0;
653 while (u < n1 && CTX->server_name[u] != '.') {
654 u ++;
655 }
656 u ++;
657 n1 -= u;
658 if ((n2 - 2) == n1
659 && eqnocase(&CTX->pad[3], CTX->server_name + u, n1))
660 {
661 T0_PUSHi(-1);
662 T0_RET();
663 }
664 }
665 T0_PUSH(0);
666 }
667
668 \ Get the address and length for the pkey_data buffer.
669 : addr-len-pkey_data ( -- addr len )
670 CX 0 8191 { offsetof(br_x509_minimal_context, pkey_data) }
671 CX 0 8191 { BR_X509_BUFSIZE_KEY } ;
672
673 \ Copy the EE public key to the permanent buffer (RSA).
674 cc: copy-ee-rsa-pkey ( nlen elen -- ) {
675 size_t elen = T0_POP();
676 size_t nlen = T0_POP();
677 memcpy(CTX->ee_pkey_data, CTX->pkey_data, nlen + elen);
678 CTX->pkey.key_type = BR_KEYTYPE_RSA;
679 CTX->pkey.key.rsa.n = CTX->ee_pkey_data;
680 CTX->pkey.key.rsa.nlen = nlen;
681 CTX->pkey.key.rsa.e = CTX->ee_pkey_data + nlen;
682 CTX->pkey.key.rsa.elen = elen;
683 }
684
685 \ Copy the EE public key to the permanent buffer (EC).
686 cc: copy-ee-ec-pkey ( curve qlen -- ) {
687 size_t qlen = T0_POP();
688 uint32_t curve = T0_POP();
689 memcpy(CTX->ee_pkey_data, CTX->pkey_data, qlen);
690 CTX->pkey.key_type = BR_KEYTYPE_EC;
691 CTX->pkey.key.ec.curve = curve;
692 CTX->pkey.key.ec.q = CTX->ee_pkey_data;
693 CTX->pkey.key.ec.qlen = qlen;
694 }
695
696 \ Check whether the current certificate (EE) is directly trusted.
697 cc: check-direct-trust ( -- ) {
698 size_t u;
699
700 for (u = 0; u < CTX->trust_anchors_num; u ++) {
701 const br_x509_trust_anchor *ta;
702 unsigned char hashed_DN[64];
703 int kt;
704
705 ta = &CTX->trust_anchors[u];
706 if (ta->flags & BR_X509_TA_CA) {
707 continue;
708 }
709 hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN);
710 if (memcmp(hashed_DN, CTX->current_dn_hash, DNHASH_LEN)) {
711 continue;
712 }
713 kt = CTX->pkey.key_type;
714 if ((ta->pkey.key_type & 0x0F) != kt) {
715 continue;
716 }
717 switch (kt) {
718
719 case BR_KEYTYPE_RSA:
720 if (!eqbigint(CTX->pkey.key.rsa.n,
721 CTX->pkey.key.rsa.nlen,
722 ta->pkey.key.rsa.n,
723 ta->pkey.key.rsa.nlen)
724 || !eqbigint(CTX->pkey.key.rsa.e,
725 CTX->pkey.key.rsa.elen,
726 ta->pkey.key.rsa.e,
727 ta->pkey.key.rsa.elen))
728 {
729 continue;
730 }
731 break;
732
733 case BR_KEYTYPE_EC:
734 if (CTX->pkey.key.ec.curve != ta->pkey.key.ec.curve
735 || CTX->pkey.key.ec.qlen != ta->pkey.key.ec.qlen
736 || memcmp(CTX->pkey.key.ec.q,
737 ta->pkey.key.ec.q,
738 ta->pkey.key.ec.qlen) != 0)
739 {
740 continue;
741 }
742 break;
743
744 default:
745 continue;
746 }
747
748 /*
749 * Direct trust match!
750 */
751 CTX->err = BR_ERR_X509_OK;
752 T0_CO();
753 }
754 }
755
756 \ Check the signature on the certificate with regards to all trusted CA.
757 \ We use the issuer hash (in saved_dn_hash[]) as CA identifier.
758 cc: check-trust-anchor-CA ( -- ) {
759 size_t u;
760
761 for (u = 0; u < CTX->trust_anchors_num; u ++) {
762 const br_x509_trust_anchor *ta;
763 unsigned char hashed_DN[64];
764
765 ta = &CTX->trust_anchors[u];
766 if (!(ta->flags & BR_X509_TA_CA)) {
767 continue;
768 }
769 hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN);
770 if (memcmp(hashed_DN, CTX->saved_dn_hash, DNHASH_LEN)) {
771 continue;
772 }
773 if (verify_signature(CTX, &ta->pkey) == 0) {
774 CTX->err = BR_ERR_X509_OK;
775 T0_CO();
776 }
777 }
778 }
779
780 \ Verify RSA signature. This uses the public key that was just decoded
781 \ into CTX->pkey_data; the modulus and exponent length are provided as
782 \ parameters. The resulting hash value is compared with the one in
783 \ tbs_hash. Returned value is 0 on success, or a non-zero error code.
784 cc: do-rsa-vrfy ( nlen elen -- err ) {
785 size_t elen = T0_POP();
786 size_t nlen = T0_POP();
787 br_x509_pkey pk;
788
789 pk.key_type = BR_KEYTYPE_RSA;
790 pk.key.rsa.n = CTX->pkey_data;
791 pk.key.rsa.nlen = nlen;
792 pk.key.rsa.e = CTX->pkey_data + nlen;
793 pk.key.rsa.elen = elen;
794 T0_PUSH(verify_signature(CTX, &pk));
795 }
796
797 \ Verify ECDSA signature. This uses the public key that was just decoded
798 \ into CTX->pkey_dayta; the curve ID and public point length are provided
799 \ as parameters. The hash value in tbs_hash is used. Returned value is 0
800 \ on success, or non-zero error code.
801 cc: do-ecdsa-vrfy ( curve qlen -- err ) {
802 size_t qlen = T0_POP();
803 int curve = T0_POP();
804 br_x509_pkey pk;
805
806 pk.key_type = BR_KEYTYPE_EC;
807 pk.key.ec.curve = curve;
808 pk.key.ec.q = CTX->pkey_data;
809 pk.key.ec.qlen = qlen;
810 T0_PUSH(verify_signature(CTX, &pk));
811 }
812
813 cc: print-bytes ( addr len -- ) {
814 extern int printf(const char *fmt, ...);
815 size_t len = T0_POP();
816 unsigned char *buf = (unsigned char *)CTX + T0_POP();
817 size_t u;
818
819 for (u = 0; u < len; u ++) {
820 printf("%02X", buf[u]);
821 }
822 }
823
824 cc: printOID ( -- ) {
825 extern int printf(const char *fmt, ...);
826 size_t u, len;
827
828 len = CTX->pad[0];
829 if (len == 0) {
830 printf("*");
831 T0_RET();
832 }
833 printf("%u.%u", CTX->pad[1] / 40, CTX->pad[1] % 40);
834 u = 2;
835 while (u <= len) {
836 unsigned long ul;
837
838 ul = 0;
839 for (;;) {
840 int x;
841
842 if (u > len) {
843 printf("BAD");
844 T0_RET();
845 }
846 x = CTX->pad[u ++];
847 ul = (ul << 7) + (x & 0x7F);
848 if (!(x & 0x80)) {
849 break;
850 }
851 }
852 printf(".%lu", ul);
853 }
854 }
855
856 \ Extensions with specific processing.
857 OID: basicConstraints 2.5.29.19
858 OID: keyUsage 2.5.29.15
859 OID: subjectAltName 2.5.29.17
860
861 \ Extensions which are ignored when encountered, even if critical.
862 OID: authorityKeyIdentifier 2.5.29.35
863 OID: subjectKeyIdentifier 2.5.29.14
864 OID: issuerAltName 2.5.29.18
865 OID: subjectDirectoryAttributes 2.5.29.9
866 OID: crlDistributionPoints 2.5.29.31
867 OID: freshestCRL 2.5.29.46
868 OID: authorityInfoAccess 1.3.6.1.5.5.7.1.1
869 OID: subjectInfoAccess 1.3.6.1.5.5.7.1.11
870
871 \ Process a Basic Constraints extension. This should be called only if
872 \ the certificate is not the EE. We check that the extension contains
873 \ the "CA" flag, and that the path length, if specified, is compatible
874 \ with the current chain length.
875 : process-basicConstraints ( lim -- lim )
876 read-sequence-open
877 read-tag-or-end
878 dup 0x01 = if
879 read-boolean ifnot ERR_X509_NOT_CA fail then
880 read-tag-or-end
881 else
882 ERR_X509_NOT_CA fail
883 then
884 dup 0x02 = if
885 drop check-primitive read-small-int-value
886 addr-num_certs get32 1- < if ERR_X509_NOT_CA fail then
887 read-tag-or-end
888 then
889 -1 <> if ERR_X509_UNEXPECTED fail then
890 drop
891 close-elt
892 ;
893
894 \ Process a Key Usage extension.
895 \ For the EE certificate:
896 \ -- if the key usage contains keyEncipherment (2), dataEncipherment (3)
897 \ or keyAgreement (4), then the "key exchange" usage is allowed;
898 \ -- if the key usage contains digitalSignature (0) or nonRepudiation (1),
899 \ then the "signature" usage is allowed.
900 \ For CA certificates, the extension must contain keyCertSign (5).
901 : process-keyUsage ( lim ee -- lim )
902 { ee }
903
904 \ Read tag for the BIT STRING and open it.
905 read-tag 0x03 check-tag-primitive
906 read-length-open-elt
907 \ First byte indicates number of ignored bits in the last byte. It
908 \ must be between 0 and 7.
909 read8 { ign }
910 ign 7 > if ERR_X509_UNEXPECTED fail then
911 \ Depending on length, we have either 0, 1 or more bytes to read.
912 dup case
913 0 of ERR_X509_FORBIDDEN_KEY_USAGE fail endof
914 1 of read8 ign >> ign << endof
915 drop read8 0
916 endcase
917
918 \ Check bits.
919 ee if
920 \ EE: get usages.
921 0
922 over 0x38 and if 0x10 or then
923 swap 0xC0 and if 0x20 or then
924 addr-key_usages set8
925 else
926 \ Not EE: keyCertSign must be set.
927 0x04 and ifnot ERR_X509_FORBIDDEN_KEY_USAGE fail then
928 then
929
930 \ We don't care about subsequent bytes.
931 skip-close-elt ;
932
933 \ Process a Subject Alt Name extension. Returned value is a boolean set
934 \ to true if the expected server name was matched against a dNSName in
935 \ the extension.
936 : process-SAN ( lim -- lim bool )
937 0 { m }
938 read-sequence-open
939 begin dup while
940 \ We check only names of type dNSName; they use IA5String,
941 \ which is basically ASCII.
942 read-tag 0x22 = if
943 check-primitive
944 read-small-value drop
945 match-server-name m or >m
946 else
947 drop read-length-skip
948 then
949 repeat
950 close-elt
951 m ;
952
953 \ Decode a certificate. The "ee" boolean must be true for the EE.
954 : decode-certificate ( ee -- )
955 { ee }
956
957 \ Obtain the total certificate length.
958 addr-cert_length get32
959
960 \ Open the outer SEQUENCE.
961 read-sequence-open
962
963 \ TBS
964 \ Activate hashing.
965 start-tbs-hash
966 read-sequence-open
967
968 \ First element may be an explicit version. We accept only
969 \ versions 0 to 2 (certificates v1 to v3).
970 read-tag dup 0x20 = if
971 drop check-constructed read-length-open-elt
972 read-tag
973 0x02 check-tag-primitive
974 read-small-int-value
975 2 > if ERR_X509_UNSUPPORTED fail then
976 close-elt
977 read-tag
978 then
979
980 \ Serial number. We just check that the tag is correct.
981 0x02 check-tag-primitive
982 read-length-skip
983
984 \ Signature algorithm. This structure is redundant with the one
985 \ on the outside; we just skip it.
986 read-sequence-open skip-close-elt
987
988 \ Issuer name: hashed, then copied into next_dn_hash[].
989 read-DN
990 addr-next_dn_hash addr-current_dn_hash dn-hash-length blobcopy
991
992 \ Validity dates.
993 read-sequence-open
994 read-date get-system-date after if ERR_X509_EXPIRED fail then
995 read-date get-system-date before if ERR_X509_EXPIRED fail then
996 close-elt
997
998 \ Subject name.
999 read-DN
1000 ee if
1001 \ For the EE, we must check whether the Common Name, if
1002 \ any, matches the expected server name.
1003 match-server-name { eename }
1004 else
1005 \ For a non-EE certificate, the hashed subject DN must match
1006 \ the saved hashed issuer DN from the previous certificate.
1007 addr-current_dn_hash addr-saved_dn_hash dn-hash-length eqblob
1008 ifnot ERR_X509_DN_MISMATCH fail then
1009 then
1010 \ Move the hashed issuer DN for this certificate into the
1011 \ saved_dn_hash[] array.
1012 addr-saved_dn_hash addr-next_dn_hash dn-hash-length blobcopy
1013
1014 \ Public Key.
1015 read-sequence-open
1016 \ Algorithm Identifier. Right now we are only interested in the
1017 \ OID, since we only support RSA keys.
1018 read-sequence-open
1019 read-OID ifnot ERR_X509_UNSUPPORTED fail then
1020 { ; pkey-type }
1021 choice
1022 \ RSA public key.
1023 rsaEncryption eqOID uf
1024 skip-close-elt
1025 \ Public key itself: the BIT STRING contains bytes
1026 \ (no partial byte) and these bytes encode the
1027 \ actual value.
1028 read-bits-open
1029 \ RSA public key is a SEQUENCE of two
1030 \ INTEGER. We get both INTEGER values into
1031 \ the pkey_data[] buffer, if they fit.
1032 read-sequence-open
1033 addr-len-pkey_data
1034 read-integer { nlen }
1035 addr-len-pkey_data swap nlen + swap nlen -
1036 read-integer { elen }
1037 close-elt
1038
1039 \ Check that the public key fits our minimal
1040 \ size requirements. Note that the integer
1041 \ decoder already skipped the leading bytes
1042 \ of value 0, so we are working on the true
1043 \ modulus length here.
1044 addr-min_rsa_size get16 128 + nlen > if
1045 ERR_X509_WEAK_PUBLIC_KEY fail
1046 then
1047 close-elt
1048 KEYTYPE_RSA >pkey-type
1049 enduf
1050
1051 \ EC public key.
1052 id-ecPublicKey eqOID uf
1053 \ We support only named curves, for which the
1054 \ "parameters" field in the AlgorithmIdentifier
1055 \ field should be an OID.
1056 read-OID ifnot ERR_X509_UNSUPPORTED fail then
1057 choice
1058 ansix9p256r1 eqOID uf 23 enduf
1059 ansix9p384r1 eqOID uf 24 enduf
1060 ansix9p521r1 eqOID uf 25 enduf
1061 ERR_X509_UNSUPPORTED fail
1062 endchoice
1063 { curve }
1064 close-elt
1065 read-bits-open
1066 dup { qlen }
1067 dup addr-len-pkey_data rot < if
1068 ERR_X509_LIMIT_EXCEEDED fail
1069 then
1070 read-blob
1071 KEYTYPE_EC >pkey-type
1072 enduf
1073
1074 \ Not a recognised public key type.
1075 ERR_X509_UNSUPPORTED fail
1076 endchoice
1077 close-elt
1078
1079 \ Process public key.
1080 ee if
1081 \ For the EE certificate, copy the key data to the
1082 \ relevant buffer.
1083 pkey-type case
1084 KEYTYPE_RSA of nlen elen copy-ee-rsa-pkey endof
1085 KEYTYPE_EC of curve qlen copy-ee-ec-pkey endof
1086 ERR_X509_UNSUPPORTED fail
1087 endcase
1088 else
1089 \ Verify signature on previous certificate. We invoke
1090 \ the RSA implementation.
1091 pkey-type case
1092 KEYTYPE_RSA of nlen elen do-rsa-vrfy endof
1093 KEYTYPE_EC of curve qlen do-ecdsa-vrfy endof
1094 ERR_X509_UNSUPPORTED fail
1095 endcase
1096 dup if fail then
1097 drop
1098 then
1099
1100 \ This flag will be set to true if the Basic Constraints extension
1101 \ is encountered.
1102 0 { seenBC }
1103
1104 \ Skip issuerUniqueID and subjectUniqueID, and process extensions
1105 \ if present. Extensions are an explicit context tag of value 3
1106 \ around a SEQUENCE OF extensions. Each extension is a SEQUENCE
1107 \ with an OID, an optional boolean, and a value; the value is
1108 \ an OCTET STRING.
1109 read-tag-or-end
1110 0x21 iftag-skip
1111 0x22 iftag-skip
1112 dup 0x23 = if
1113 drop
1114 check-constructed read-length-open-elt
1115 read-sequence-open
1116 begin dup while
1117 0 { critical }
1118 read-sequence-open
1119 read-OID drop
1120 read-tag dup 0x01 = if
1121 read-boolean >critical
1122 read-tag
1123 then
1124 0x04 check-tag-primitive read-length-open-elt
1125 choice
1126 \ Extensions with specific processing.
1127 basicConstraints eqOID uf
1128 ee if
1129 skip-remaining
1130 else
1131 process-basicConstraints
1132 -1 >seenBC
1133 then
1134 enduf
1135 keyUsage eqOID uf
1136 ee process-keyUsage
1137 enduf
1138 subjectAltName eqOID uf
1139 ee if
1140 0 >eename
1141 process-SAN >eename
1142 else
1143 skip-remaining
1144 then
1145 enduf
1146
1147 \ Extensions which are always ignored,
1148 \ even if critical.
1149 authorityKeyIdentifier eqOID uf
1150 skip-remaining
1151 enduf
1152 subjectKeyIdentifier eqOID uf
1153 skip-remaining
1154 enduf
1155 issuerAltName eqOID uf
1156 skip-remaining
1157 enduf
1158 subjectDirectoryAttributes eqOID uf
1159 skip-remaining
1160 enduf
1161 crlDistributionPoints eqOID uf
1162 skip-remaining
1163 enduf
1164 freshestCRL eqOID uf
1165 skip-remaining
1166 enduf
1167 authorityInfoAccess eqOID uf
1168 skip-remaining
1169 enduf
1170 subjectInfoAccess eqOID uf
1171 skip-remaining
1172 enduf
1173
1174 \ Unrecognized extensions trigger a failure
1175 \ if critical; otherwise, they are just
1176 \ ignored.
1177 critical if
1178 ERR_X509_CRITICAL_EXTENSION fail
1179 then
1180 skip-remaining
1181 endchoice
1182 close-elt
1183 close-elt
1184 repeat
1185 close-elt
1186 close-elt
1187 else
1188 -1 = ifnot ERR_X509_UNEXPECTED fail then
1189 drop
1190 then
1191
1192 close-elt
1193 \ Terminate hashing.
1194 stop-tbs-hash
1195
1196 \ For the EE certificate, verify that the intended server name
1197 \ was matched.
1198 ee if
1199 eename zero-server-name or ifnot
1200 ERR_X509_BAD_SERVER_NAME fail
1201 then
1202 then
1203
1204 \ If this is the EE certificate, then direct trust may apply.
1205 \ Note: we do this at this point, not immediately after decoding
1206 \ the public key, because even in case of direct trust we still
1207 \ want to check the server name with regards to the SAN extension.
1208 \ However, we want to check direct trust before trying to decode
1209 \ the signature algorithm, because it should work even if that
1210 \ algorithm is not supported.
1211 ee if check-direct-trust then
1212
1213 \ Non-EE certificates MUST have a Basic Constraints extension
1214 \ (that marks them as being CA).
1215 ee seenBC or ifnot ERR_X509_NOT_CA fail then
1216
1217 \ signature algorithm
1218 read-tag check-sequence read-length-open-elt
1219 \ Read and understand the OID. Right now, we support only
1220 \ RSA with PKCS#1 v1.5 padding, and hash functions SHA-1,
1221 \ SHA-224, SHA-256, SHA-384 and SHA-512. We purposely do NOT
1222 \ support MD5 here.
1223 \ TODO: add support for RSA/PSS
1224 read-OID if
1225 \ Based on the signature OID, we get:
1226 \ -- the signing key type
1227 \ -- the hash function numeric identifier
1228 \ -- the hash function OID
1229 choice
1230 sha1WithRSAEncryption eqOID
1231 uf 2 KEYTYPE_RSA id-sha1 enduf
1232 sha224WithRSAEncryption eqOID
1233 uf 3 KEYTYPE_RSA id-sha224 enduf
1234 sha256WithRSAEncryption eqOID
1235 uf 4 KEYTYPE_RSA id-sha256 enduf
1236 sha384WithRSAEncryption eqOID
1237 uf 5 KEYTYPE_RSA id-sha384 enduf
1238 sha512WithRSAEncryption eqOID
1239 uf 6 KEYTYPE_RSA id-sha512 enduf
1240
1241 ecdsa-with-SHA1 eqOID
1242 uf 2 KEYTYPE_EC id-sha1 enduf
1243 ecdsa-with-SHA224 eqOID
1244 uf 3 KEYTYPE_EC id-sha224 enduf
1245 ecdsa-with-SHA256 eqOID
1246 uf 4 KEYTYPE_EC id-sha256 enduf
1247 ecdsa-with-SHA384 eqOID
1248 uf 5 KEYTYPE_EC id-sha384 enduf
1249 ecdsa-with-SHA512 eqOID
1250 uf 6 KEYTYPE_EC id-sha512 enduf
1251 ERR_X509_UNSUPPORTED fail
1252 endchoice
1253 addr-cert_sig_hash_oid set16
1254 addr-cert_signer_key_type set8
1255
1256 \ Compute the TBS hash into tbs_hash.
1257 compute-tbs-hash
1258 dup ifnot ERR_X509_UNSUPPORTED fail then
1259 addr-cert_sig_hash_len set8
1260 else
1261 ERR_X509_UNSUPPORTED fail
1262 then
1263 \ We ignore the parameters, whether they are present or not,
1264 \ because we got all the information from the OID.
1265 skip-close-elt
1266
1267 \ signature value
1268 read-bits-open
1269 dup CX 0 8191 { BR_X509_BUFSIZE_SIG } > if
1270 ERR_X509_LIMIT_EXCEEDED fail
1271 then
1272 dup addr-cert_sig_len set16
1273 addr-cert_sig read-blob
1274
1275 \ Close the outer SEQUENCE.
1276 close-elt
1277
1278 \ Close the advertised total certificate length. This checks that
1279 \ there is no trailing garbage after the certificate.
1280 close-elt
1281
1282 \ Flag the certificate as fully processed.
1283 0 addr-cert_length set32
1284
1285 \ Check whether the issuer for the current certificate is known
1286 \ as a trusted CA; in which case, verify the signature.
1287 check-trust-anchor-CA ;
1288
1289 : main
1290 \ Unless restricted by a Key Usage extension, all usages are
1291 \ deemed allowed.
1292 0x30 addr-key_usages set8
1293 -1 decode-certificate
1294 co
1295 begin
1296 0 decode-certificate co
1297 again
1298 ;