Fixed spurious warning about old-style prototype.
[BearSSL] / src / x509 / x509_minimal.t0
index f8c7f25..80a3701 100644 (file)
@@ -106,7 +106,7 @@ preamble {
  *     -- Extensions: extension values are processed in due order.
  *
  *        -- Basic Constraints: for all certificates except EE, must be
- *        present, indicate a CA, and have a path legnth compatible with
+ *        present, indicate a CA, and have a path length compatible with
  *        the chain length so far.
  *
  *        -- Key Usage: for the EE, if present, must allow signatures
@@ -149,20 +149,6 @@ preamble {
  *  then validation is reported as failed.
  */
 
-#ifndef BR_USE_UNIX_TIME
-#if defined __unix__ || defined __linux__ \
-       || defined _POSIX_SOURCE || defined _POSIX_C_SOURCE \
-       || (defined __APPLE__ && defined __MACH__)
-#define BR_USE_UNIX_TIME   1
-#endif
-#endif
-
-#ifndef BR_USE_WIN32_TIME
-#if defined _WIN32 || defined _WIN64
-#define BR_USE_WIN32_TIME   1
-#endif
-#endif
-
 #if BR_USE_UNIX_TIME
 #include <time.h>
 #endif
@@ -171,8 +157,13 @@ preamble {
 #include <windows.h>
 #endif
 
+/*
+ * The T0 compiler will produce these prototypes declarations in the
+ * header.
+ *
 void br_x509_minimal_init_main(void *ctx);
 void br_x509_minimal_run(void *ctx);
+ */
 
 /* see bearssl_x509.h */
 void
@@ -193,7 +184,7 @@ xm_start_chain(const br_x509_class **ctx, const char *server_name)
        br_x509_minimal_context *cc;
        size_t u;
 
-       cc = (br_x509_minimal_context *)ctx;
+       cc = (br_x509_minimal_context *)(void *)ctx;
        for (u = 0; u < cc->num_name_elts; u ++) {
                cc->name_elts[u].status = 0;
                cc->name_elts[u].buf[0] = 0;
@@ -216,7 +207,7 @@ xm_start_cert(const br_x509_class **ctx, uint32_t length)
 {
        br_x509_minimal_context *cc;
 
-       cc = (br_x509_minimal_context *)ctx;
+       cc = (br_x509_minimal_context *)(void *)ctx;
        if (cc->err != 0) {
                return;
        }
@@ -232,7 +223,7 @@ xm_append(const br_x509_class **ctx, const unsigned char *buf, size_t len)
 {
        br_x509_minimal_context *cc;
 
-       cc = (br_x509_minimal_context *)ctx;
+       cc = (br_x509_minimal_context *)(void *)ctx;
        if (cc->err != 0) {
                return;
        }
@@ -246,7 +237,7 @@ xm_end_cert(const br_x509_class **ctx)
 {
        br_x509_minimal_context *cc;
 
-       cc = (br_x509_minimal_context *)ctx;
+       cc = (br_x509_minimal_context *)(void *)ctx;
        if (cc->err == 0 && cc->cert_length != 0) {
                cc->err = BR_ERR_X509_TRUNCATED;
        }
@@ -258,7 +249,7 @@ xm_end_chain(const br_x509_class **ctx)
 {
        br_x509_minimal_context *cc;
 
-       cc = (br_x509_minimal_context *)ctx;
+       cc = (br_x509_minimal_context *)(void *)ctx;
        if (cc->err == 0) {
                if (cc->num_certs == 0) {
                        cc->err = BR_ERR_X509_EMPTY_CHAIN;
@@ -276,14 +267,14 @@ xm_get_pkey(const br_x509_class *const *ctx, unsigned *usages)
 {
        br_x509_minimal_context *cc;
 
-       cc = (br_x509_minimal_context *)ctx;
+       cc = (br_x509_minimal_context *)(void *)ctx;
        if (cc->err == BR_ERR_X509_OK
                || cc->err == BR_ERR_X509_NOT_TRUSTED)
        {
                if (usages != NULL) {
                        *usages = cc->key_usages;
                }
-               return &((br_x509_minimal_context *)ctx)->pkey;
+               return &((br_x509_minimal_context *)(void *)ctx)->pkey;
        } else {
                return NULL;
        }
@@ -300,7 +291,7 @@ const br_x509_class br_x509_minimal_vtable = {
        xm_get_pkey
 };
 
-#define CTX   ((br_x509_minimal_context *)((unsigned char *)t0ctx - offsetof(br_x509_minimal_context, cpu)))
+#define CTX   ((br_x509_minimal_context *)(void *)((unsigned char *)t0ctx - offsetof(br_x509_minimal_context, cpu)))
 #define CONTEXT_NAME   br_x509_minimal_context
 
 #define DNHASH_LEN   ((CTX->dn_hash_impl->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK)
@@ -341,6 +332,42 @@ eqbigint(const unsigned char *b1, size_t len1,
        return memcmp(b1, b2, len1) == 0;
 }
 
+/*
+ * Compare two strings for equality, in a case-insensitive way. This
+ * function handles casing only for ASCII letters.
+ */
+static int
+eqnocase(const void *s1, const void *s2, size_t len)
+{
+       const unsigned char *buf1, *buf2;
+
+       buf1 = s1;
+       buf2 = s2;
+       while (len -- > 0) {
+               int x1, x2;
+
+               x1 = *buf1 ++;
+               x2 = *buf2 ++;
+               if (x1 >= 'A' && x1 <= 'Z') {
+                       x1 += 'a' - 'A';
+               }
+               if (x2 >= 'A' && x2 <= 'Z') {
+                       x2 += 'a' - 'A';
+               }
+               if (x1 != x2) {
+                       return 0;
+               }
+       }
+       return 1;
+}
+
+static int verify_signature(br_x509_minimal_context *ctx,
+       const br_x509_pkey *pk);
+
+}
+
+postamble {
+
 /*
  * Verify the signature on the certificate with the provided public key.
  * This function checks the public key type with regards to the expected
@@ -390,35 +417,6 @@ verify_signature(br_x509_minimal_context *ctx, const br_x509_pkey *pk)
        }
 }
 
-/*
- * Compare two strings for equality, in a case-insensitive way. This
- * function handles casing only for ASCII letters.
- */
-static int
-eqnocase(const void *s1, const void *s2, size_t len)
-{
-       const unsigned char *buf1, *buf2;
-
-       buf1 = s1;
-       buf2 = s2;
-       while (len -- > 0) {
-               int x1, x2;
-
-               x1 = *buf1 ++;
-               x2 = *buf2 ++;
-               if (x1 >= 'A' && x1 <= 'Z') {
-                       x1 += 'a' - 'A';
-               }
-               if (x2 >= 'A' && x2 <= 'Z') {
-                       x2 += 'a' - 'A';
-               }
-               if (x1 != x2) {
-                       return 0;
-               }
-       }
-       return 1;
-}
-
 }
 
 cc: read8-low ( -- x ) {
@@ -700,42 +698,60 @@ cc: copy-name-SAN ( bool tag -- ) {
        \ Return the CN match flag.
        eename-matches ;
 
-\ Get the validation date and time from the context or system.
-cc: get-system-date ( -- days seconds ) {
-       if (CTX->days == 0 && CTX->seconds == 0) {
+\ Check the provided validity range against the current (or configured)
+\ date and time ("na" = notAfter, "nb = notBefore). Returned value:
+\   -1   current date/time is before the notBefore date
+\    0   current date/time is within the allowed range
+\   +1   current date/time is after the notAfter range
+\ If the current date/time is not available, then this function triggers a
+\ failure and does not return.
+cc: check-validity-range ( na-days na-seconds nb-days nb-seconds -- int ) {
+       uint32_t nbs = T0_POP();
+       uint32_t nbd = T0_POP();
+       uint32_t nas = T0_POP();
+       uint32_t nad = T0_POP();
+       int r;
+       if (CTX->itime != 0) {
+               r = CTX->itime(CTX->itime_ctx, nbd, nbs, nad, nas);
+               if (r < -1 || r > 1) {
+                       CTX->err = BR_ERR_X509_TIME_UNKNOWN;
+                       T0_CO();
+               }
+       } else {
+               uint32_t vd = CTX->days;
+               uint32_t vs = CTX->seconds;
+               if (vd == 0 && vs == 0) {
 #if BR_USE_UNIX_TIME
-               time_t x = time(NULL);
+                       time_t x = time(NULL);
 
-               T0_PUSH((uint32_t)(x / 86400) + 719528);
-               T0_PUSH((uint32_t)(x % 86400));
+                       vd = (uint32_t)(x / 86400) + 719528;
+                       vs = (uint32_t)(x % 86400);
 #elif BR_USE_WIN32_TIME
-               FILETIME ft;
-               uint64_t x;
-
-               GetSystemTimeAsFileTime(&ft);
-               x = ((uint64_t)ft.dwHighDateTime << 32)
-                       + (uint64_t)ft.dwLowDateTime;
-               x = (x / 10000000);
-               T0_PUSH((uint32_t)(x / 86400) + 584754);
-               T0_PUSH((uint32_t)(x % 86400));
+                       FILETIME ft;
+                       uint64_t x;
+
+                       GetSystemTimeAsFileTime(&ft);
+                       x = ((uint64_t)ft.dwHighDateTime << 32)
+                               + (uint64_t)ft.dwLowDateTime;
+                       x = (x / 10000000);
+                       vd = (uint32_t)(x / 86400) + 584754;
+                       vs = (uint32_t)(x % 86400);
 #else
-               CTX->err = BR_ERR_X509_TIME_UNKNOWN;
-               T0_CO();
+                       CTX->err = BR_ERR_X509_TIME_UNKNOWN;
+                       T0_CO();
 #endif
-       } else {
-               T0_PUSH(CTX->days);
-               T0_PUSH(CTX->seconds);
+               }
+               if (vd < nbd || (vd == nbd && vs < nbs)) {
+                       r = -1;
+               } else if (vd > nad || (vd == nad && vs > nas)) {
+                       r = 1;
+               } else {
+                       r = 0;
+               }
        }
+       T0_PUSHi(r);
 }
 
-\ Compare two dates (days+seconds) together.
-: before ( days1 seconds1 days2 seconds2 -- bool )
-       { d1 s1 d2 s2 }
-       d1 d2 = if s1 s2 < else d1 d2 < then ;
-
-: after ( days1 seconds1 days2 seconds2 -- bool )
-       swap2 before ;
-
 \ Swap the top two elements with the two elements immediately below.
 : swap2 ( a b c d -- c d a b )
        3 roll 3 roll ;
@@ -967,9 +983,13 @@ cc: printOID ( -- ) {
 }
 
 \ Extensions with specific processing.
-OID: basicConstraints    2.5.29.19
-OID: keyUsage            2.5.29.15
-OID: subjectAltName      2.5.29.17
+OID: basicConstraints      2.5.29.19
+OID: keyUsage              2.5.29.15
+OID: subjectAltName        2.5.29.17
+OID: certificatePolicies   2.5.29.32
+
+\ Policy qualifier "pointer to CPS"
+OID: id-qt-cps             1.3.6.1.5.5.7.2.1
 
 \ Extensions which are ignored when encountered, even if critical.
 OID: authorityKeyIdentifier        2.5.29.35
@@ -1043,6 +1063,49 @@ OID: subjectInfoAccess             1.3.6.1.5.5.7.1.11
        \ We don't care about subsequent bytes.
        skip-close-elt ;
 
+\ Process a Certificate Policies extension.
+\
+\ Since we don't actually support full policies processing, this function
+\ only checks that the extension contents can be safely ignored. Indeed,
+\ we don't validate against a specific set of policies (in RFC 5280
+\ terminology, user-initial-policy-set only contains the special value
+\ any-policy). Moreover, we don't support policy constraints (if a
+\ critical Policy Constraints extension is encountered, the validation
+\ will fail). Therefore, we can safely ignore the contents of this
+\ extension, except if it is critical AND one of the policy OID has a
+\ qualifier which is distinct from id-qt-cps (because id-qt-cps is
+\ specially designated by RFC 5280 has having no mandated action).
+\
+\ This function is called only if the extension is critical.
+: process-certPolicies ( lim -- lim )
+       \ Extension value is a SEQUENCE OF PolicyInformation.
+       read-sequence-open
+       begin dup while
+               \ PolicyInformation ::= SEQUENCE {
+               \    policyIdentifier  OBJECT IDENTIFIER,
+               \    policyQualifiers  SEQUENCE OF PolicyQualifierInfo OPTIONAL
+               \ }
+               read-sequence-open
+               read-OID drop
+               dup if
+                       read-sequence-open
+                       begin dup while
+                               \ PolicyQualifierInfo ::= SEQUENCE {
+                               \    policyQualifierId  OBJECT IDENTIFIER,
+                               \    qualifier          ANY
+                               \ }
+                               read-sequence-open
+                               read-OID drop id-qt-cps eqOID ifnot
+                                       ERR_X509_CRITICAL_EXTENSION fail
+                               then
+                               skip-close-elt
+                       repeat
+                       close-elt
+               then
+               close-elt
+       repeat
+       close-elt ;
+
 \ Process a Subject Alt Name extension. Returned value is a boolean set
 \ to true if the expected server name was matched against a dNSName in
 \ the extension.
@@ -1144,8 +1207,8 @@ OID: subjectInfoAccess             1.3.6.1.5.5.7.1.11
 
        \ Validity dates.
        read-sequence-open
-       read-date get-system-date after if ERR_X509_EXPIRED fail then
-       read-date get-system-date before if ERR_X509_EXPIRED fail then
+       read-date { nbd nbs } read-date nbd nbs check-validity-range
+       if ERR_X509_EXPIRED fail then
        close-elt
 
        \ Subject name.
@@ -1297,6 +1360,18 @@ OID: subjectInfoAccess             1.3.6.1.5.5.7.1.11
                                        then
                                enduf
 
+                               \ We don't implement full processing of
+                               \ policies. The call below mostly checks
+                               \ that the contents of the Certificate
+                               \ Policies extension can be safely ignored.
+                               certificatePolicies eqOID uf
+                                       critical if
+                                               process-certPolicies
+                                       else
+                                               skip-remaining
+                                       then
+                               enduf
+
                                \ Extensions which are always ignored,
                                \ even if critical.
                                authorityKeyIdentifier     eqOID uf