]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
TLS: Add support for extKeyUsage X.509v3 extension
authorJouni Malinen <j@w1.fi>
Sun, 29 Nov 2015 19:53:23 +0000 (21:53 +0200)
committerJouni Malinen <j@w1.fi>
Sun, 29 Nov 2015 19:53:23 +0000 (21:53 +0200)
If the server/client certificate includes the extKeyUsage extension,
verify that the listed key purposes include either the
anyExtendedKeyUsage wildcard or id-kp-serverAuth/id-kp-clientAuth,
respectively.

Signed-off-by: Jouni Malinen <j@w1.fi>
src/tls/tlsv1_client_read.c
src/tls/tlsv1_server_read.c
src/tls/x509v3.c
src/tls/x509v3.h

index 5830e7acadd0261a15b381491616312e9fb74ec8..40c6a46ff23e9ae54257a792ff6efffbdf48d1b1 100644 (file)
@@ -548,6 +548,19 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
                return -1;
        }
 
+       if (conn->cred && !conn->cred->server_cert_only && chain &&
+           (chain->extensions_present & X509_EXT_EXT_KEY_USAGE) &&
+           !(chain->ext_key_usage &
+             (X509_EXT_KEY_USAGE_ANY | X509_EXT_KEY_USAGE_SERVER_AUTH))) {
+               tls_cert_chain_failure_event(
+                       conn, 0, chain, TLS_FAIL_BAD_CERTIFICATE,
+                       "certificate not allowed for server authentication");
+               tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                         TLS_ALERT_BAD_CERTIFICATE);
+               x509_certificate_chain_free(chain);
+               return -1;
+       }
+
        x509_certificate_chain_free(chain);
 
        *in_len = end - in_data;
index 0f237baff9db6d8c0dd3ad2ef9207037d65ee2b2..8347d7accd6d8a41e35404ae280540efd8e9227d 100644 (file)
@@ -471,6 +471,15 @@ static int tls_process_certificate(struct tlsv1_server *conn, u8 ct,
                return -1;
        }
 
+       if (chain && (chain->extensions_present & X509_EXT_EXT_KEY_USAGE) &&
+           !(chain->ext_key_usage &
+             (X509_EXT_KEY_USAGE_ANY | X509_EXT_KEY_USAGE_CLIENT_AUTH))) {
+               tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+                                  TLS_ALERT_BAD_CERTIFICATE);
+               x509_certificate_chain_free(chain);
+               return -1;
+       }
+
        x509_certificate_chain_free(chain);
 
        *in_len = end - in_data;
index 38b49e22a92dfe3de8bf532745efa1bd80daed6d..75e328556b1c1477c49e2ed8a89adcd9cf1287d7 100644 (file)
@@ -720,6 +720,15 @@ static int x509_id_ce_oid(struct asn1_oid *oid)
 }
 
 
+static int x509_any_ext_key_usage_oid(struct asn1_oid *oid)
+{
+       return oid->len == 6 &&
+               x509_id_ce_oid(oid) &&
+               oid->oid[3] == 37 /* extKeyUsage */ &&
+               oid->oid[4] == 0 /* anyExtendedKeyUsage */;
+}
+
+
 static int x509_parse_ext_key_usage(struct x509_certificate *cert,
                                    const u8 *pos, size_t len)
 {
@@ -1073,6 +1082,100 @@ static int x509_parse_ext_issuer_alt_name(struct x509_certificate *cert,
 }
 
 
+static int x509_id_pkix_oid(struct asn1_oid *oid)
+{
+       return oid->len >= 7 &&
+               oid->oid[0] == 1 /* iso */ &&
+               oid->oid[1] == 3 /* identified-organization */ &&
+               oid->oid[2] == 6 /* dod */ &&
+               oid->oid[3] == 1 /* internet */ &&
+               oid->oid[4] == 5 /* security */ &&
+               oid->oid[5] == 5 /* mechanisms */ &&
+               oid->oid[6] == 7 /* id-pkix */;
+}
+
+
+static int x509_id_kp_oid(struct asn1_oid *oid)
+{
+       /* id-kp */
+       return oid->len >= 8 &&
+               x509_id_pkix_oid(oid) &&
+               oid->oid[7] == 3 /* id-kp */;
+}
+
+
+static int x509_id_kp_server_auth_oid(struct asn1_oid *oid)
+{
+       /* id-kp */
+       return oid->len == 9 &&
+               x509_id_kp_oid(oid) &&
+               oid->oid[8] == 1 /* id-kp-serverAuth */;
+}
+
+
+static int x509_id_kp_client_auth_oid(struct asn1_oid *oid)
+{
+       /* id-kp */
+       return oid->len == 9 &&
+               x509_id_kp_oid(oid) &&
+               oid->oid[8] == 2 /* id-kp-clientAuth */;
+}
+
+
+static int x509_parse_ext_ext_key_usage(struct x509_certificate *cert,
+                                       const u8 *pos, size_t len)
+{
+       struct asn1_hdr hdr;
+       const u8 *end;
+       struct asn1_oid oid;
+
+       /*
+        * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
+        *
+        * KeyPurposeId ::= OBJECT IDENTIFIER
+        */
+
+       if (asn1_get_next(pos, len, &hdr) < 0 ||
+           hdr.class != ASN1_CLASS_UNIVERSAL ||
+           hdr.tag != ASN1_TAG_SEQUENCE) {
+               wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
+                          "(ExtKeyUsageSyntax) - found class %d tag 0x%x",
+                          hdr.class, hdr.tag);
+               return -1;
+       }
+       if (hdr.length > pos + len - hdr.payload)
+               return -1;
+       pos = hdr.payload;
+       end = pos + hdr.length;
+
+       wpa_hexdump(MSG_MSGDUMP, "X509: ExtKeyUsageSyntax", pos, end - pos);
+
+       while (pos < end) {
+               char buf[80];
+
+               if (asn1_get_oid(pos, end - pos, &oid, &pos))
+                       return -1;
+               if (x509_any_ext_key_usage_oid(&oid)) {
+                       os_strlcpy(buf, "anyExtendedKeyUsage", sizeof(buf));
+                       cert->ext_key_usage |= X509_EXT_KEY_USAGE_ANY;
+               } else if (x509_id_kp_server_auth_oid(&oid)) {
+                       os_strlcpy(buf, "id-kp-serverAuth", sizeof(buf));
+                       cert->ext_key_usage |= X509_EXT_KEY_USAGE_SERVER_AUTH;
+               } else if (x509_id_kp_client_auth_oid(&oid)) {
+                       os_strlcpy(buf, "id-kp-clientAuth", sizeof(buf));
+                       cert->ext_key_usage |= X509_EXT_KEY_USAGE_CLIENT_AUTH;
+               } else {
+                       asn1_oid_to_str(&oid, buf, sizeof(buf));
+               }
+               wpa_printf(MSG_DEBUG, "ExtKeyUsage KeyPurposeId: %s", buf);
+       }
+
+       cert->extensions_present |= X509_EXT_EXT_KEY_USAGE;
+
+       return 0;
+}
+
+
 static int x509_parse_extension_data(struct x509_certificate *cert,
                                     struct asn1_oid *oid,
                                     const u8 *pos, size_t len)
@@ -1084,7 +1187,6 @@ static int x509_parse_extension_data(struct x509_certificate *cert,
         * certificate policies (section 4.2.1.5)
         * name constraints (section 4.2.1.11)
         * policy constraints (section 4.2.1.12)
-        * extended key usage (section 4.2.1.13)
         * inhibit any-policy (section 4.2.1.15)
         */
        switch (oid->oid[3]) {
@@ -1096,6 +1198,8 @@ static int x509_parse_extension_data(struct x509_certificate *cert,
                return x509_parse_ext_issuer_alt_name(cert, pos, len);
        case 19: /* id-ce-basicConstraints */
                return x509_parse_ext_basic_constraints(cert, pos, len);
+       case 37: /* id-ce-extKeyUsage */
+               return x509_parse_ext_ext_key_usage(cert, pos, len);
        default:
                return 1;
        }
index 91a35baf92b1892cc7645507124991c5df9c1afd..12ef86eeae81dfd8e09847c07da14f70275f39c2 100644 (file)
@@ -68,6 +68,7 @@ struct x509_certificate {
 #define X509_EXT_KEY_USAGE                     (1 << 2)
 #define X509_EXT_SUBJECT_ALT_NAME              (1 << 3)
 #define X509_EXT_ISSUER_ALT_NAME               (1 << 4)
+#define X509_EXT_EXT_KEY_USAGE                 (1 << 5)
 
        /* BasicConstraints */
        int ca; /* cA */
@@ -85,6 +86,12 @@ struct x509_certificate {
 #define X509_KEY_USAGE_ENCIPHER_ONLY           (1 << 7)
 #define X509_KEY_USAGE_DECIPHER_ONLY           (1 << 8)
 
+       /* ExtKeyUsage */
+       unsigned long ext_key_usage;
+#define X509_EXT_KEY_USAGE_ANY                 (1 << 0)
+#define X509_EXT_KEY_USAGE_SERVER_AUTH         (1 << 1)
+#define X509_EXT_KEY_USAGE_CLIENT_AUTH         (1 << 2)
+
        /*
         * The DER format certificate follows struct x509_certificate. These
         * pointers point to that buffer.