From 1adf262144ffae33d85bde6eddcb925f0c84e797 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 29 Nov 2015 21:53:23 +0200 Subject: [PATCH] TLS: Add support for extKeyUsage X.509v3 extension 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 --- src/tls/tlsv1_client_read.c | 13 +++++ src/tls/tlsv1_server_read.c | 9 +++ src/tls/x509v3.c | 106 +++++++++++++++++++++++++++++++++++- src/tls/x509v3.h | 7 +++ 4 files changed, 134 insertions(+), 1 deletion(-) diff --git a/src/tls/tlsv1_client_read.c b/src/tls/tlsv1_client_read.c index 5830e7aca..40c6a46ff 100644 --- a/src/tls/tlsv1_client_read.c +++ b/src/tls/tlsv1_client_read.c @@ -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; diff --git a/src/tls/tlsv1_server_read.c b/src/tls/tlsv1_server_read.c index 0f237baff..8347d7acc 100644 --- a/src/tls/tlsv1_server_read.c +++ b/src/tls/tlsv1_server_read.c @@ -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; diff --git a/src/tls/x509v3.c b/src/tls/x509v3.c index 38b49e22a..75e328556 100644 --- a/src/tls/x509v3.c +++ b/src/tls/x509v3.c @@ -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; } diff --git a/src/tls/x509v3.h b/src/tls/x509v3.h index 91a35baf9..12ef86eea 100644 --- a/src/tls/x509v3.h +++ b/src/tls/x509v3.h @@ -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.