File 0013-rh1178263-CVE-2015-0210-domain_match.patch of Package wpa_supplicant.5882
Backport of:
commit cebee30f3170b5104a41bd27ac5f98615ed57656
Author: Jouni Malinen <j@w1.fi>
Date: Wed Jan 14 15:31:28 2015 +0200
Add domain_match network profile parameter
This is similar with domain_suffix_match, but required a full match of
the domain name rather than allowing suffix match (subdomains) or
wildcard certificates.
Signed-off-by: Jouni Malinen <j@w1.fi>
================================================================================
--- wpa_supplicant-2.2/src/crypto/tls.h
+++ wpa_supplicant-2.2/src/crypto/tls.h
@@ -41,7 +41,8 @@
TLS_FAIL_ALTSUBJECT_MISMATCH = 6,
TLS_FAIL_BAD_CERTIFICATE = 7,
TLS_FAIL_SERVER_CHAIN_PROBE = 8,
- TLS_FAIL_DOMAIN_SUFFIX_MISMATCH = 9
+ TLS_FAIL_DOMAIN_SUFFIX_MISMATCH = 9,
+ TLS_FAIL_DOMAIN_MISMATCH = 10
};
union tls_event_data {
@@ -101,6 +102,9 @@
* certificate or %NULL to allow all alternative subjects
* @suffix_match: String to suffix match in the dNSName or CN of the peer
* certificate or %NULL to allow all domain names
+ * @domain_match: String to match in the dNSName or CN of the peer
+ * certificate or %NULL to allow all domain names. This requires a full,
+ * case-insensitive match.
* @client_cert: File or reference name for client X.509 certificate in PEM or
* DER format
* @client_cert_blob: client_cert as inlined data or %NULL if not used
@@ -143,6 +147,7 @@
const char *subject_match;
const char *altsubject_match;
const char *suffix_match;
+ const char *domain_match;
const char *client_cert;
const u8 *client_cert_blob;
size_t client_cert_blob_len;
--- wpa_supplicant-2.2/src/crypto/tls_internal.c
+++ wpa_supplicant-2.2/src/crypto/tls_internal.c
@@ -190,6 +190,11 @@
if (cred == NULL)
return -1;
+ if (params->domain_match) {
+ wpa_printf(MSG_INFO, "TLS: domain_match not supported");
+ return -1;
+ }
+
if (tlsv1_set_ca_cert(cred, params->ca_cert,
params->ca_cert_blob, params->ca_cert_blob_len,
params->ca_path)) {
--- wpa_supplicant-2.2/src/crypto/tls_openssl.c
+++ wpa_supplicant-2.2/src/crypto/tls_openssl.c
@@ -92,7 +92,7 @@
ENGINE *engine; /* functional reference to the engine */
EVP_PKEY *private_key; /* the private key if using engine */
#endif /* OPENSSL_NO_ENGINE */
- char *subject_match, *altsubject_match, *suffix_match;
+ char *subject_match, *altsubject_match, *suffix_match, *domain_match;
int read_alerts, write_alerts, failed;
tls_session_ticket_cb session_ticket_cb;
@@ -1072,6 +1072,7 @@
os_free(conn->subject_match);
os_free(conn->altsubject_match);
os_free(conn->suffix_match);
+ os_free(conn->domain_match);
os_free(conn->session_ticket);
os_free(conn);
}
@@ -1163,7 +1164,8 @@
#ifndef CONFIG_NATIVE_WINDOWS
-static int domain_suffix_match(const u8 *val, size_t len, const char *match)
+static int domain_suffix_match(const u8 *val, size_t len, const char *match,
+ int full)
{
size_t i, match_len;
@@ -1176,7 +1178,7 @@
}
match_len = os_strlen(match);
- if (match_len > len)
+ if (match_len > len || (full && match_len != len))
return 0;
if (os_strncasecmp((const char *) val + len - match_len, match,
@@ -1195,7 +1197,7 @@
#endif /* CONFIG_NATIVE_WINDOWS */
-static int tls_match_suffix(X509 *cert, const char *match)
+static int tls_match_suffix(X509 *cert, const char *match, int full)
{
#ifdef CONFIG_NATIVE_WINDOWS
/* wincrypt.h has conflicting X509_NAME definition */
@@ -1204,15 +1206,17 @@
GENERAL_NAME *gen;
void *ext;
int i;
+ int j;
int dns_name = 0;
X509_NAME *name;
- wpa_printf(MSG_DEBUG, "TLS: Match domain against suffix %s", match);
+ wpa_printf(MSG_DEBUG, "TLS: Match domain against %s%s",
+ full ? "": "suffix ", match);
ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
- for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
- gen = sk_GENERAL_NAME_value(ext, i);
+ for (j = 0; ext && j < sk_GENERAL_NAME_num(ext); j++) {
+ gen = sk_GENERAL_NAME_value(ext, j);
if (gen->type != GEN_DNS)
continue;
dns_name++;
@@ -1220,8 +1224,10 @@
gen->d.dNSName->data,
gen->d.dNSName->length);
if (domain_suffix_match(gen->d.dNSName->data,
- gen->d.dNSName->length, match) == 1) {
- wpa_printf(MSG_DEBUG, "TLS: Suffix match in dNSName found");
+ gen->d.dNSName->length, match, full) ==
+ 1) {
+ wpa_printf(MSG_DEBUG, "TLS: %s in dNSName found",
+ full ? "Match" : "Suffix match");
return 1;
}
}
@@ -1248,13 +1254,16 @@
continue;
wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate commonName",
cn->data, cn->length);
- if (domain_suffix_match(cn->data, cn->length, match) == 1) {
- wpa_printf(MSG_DEBUG, "TLS: Suffix match in commonName found");
- return 1;
- }
+ if (domain_suffix_match(cn->data, cn->length, match, full) == 1)
+ {
+ wpa_printf(MSG_DEBUG, "TLS: %s in commonName found",
+ full ? "Match" : "Suffix match");
+ return 1;
+ }
}
- wpa_printf(MSG_DEBUG, "TLS: No CommonName suffix match found");
+ wpa_printf(MSG_DEBUG, "TLS: No CommonName %smatch found",
+ full ? "": "suffix ");
return 0;
#endif /* CONFIG_NATIVE_WINDOWS */
}
@@ -1388,7 +1397,7 @@
SSL *ssl;
struct tls_connection *conn;
struct tls_context *context;
- char *match, *altmatch, *suffix_match;
+ char *match, *altmatch, *suffix_match, *domain_match;
const char *err_str;
err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
@@ -1416,6 +1425,7 @@
match = conn->subject_match;
altmatch = conn->altsubject_match;
suffix_match = conn->suffix_match;
+ domain_match = conn->domain_match;
if (!preverify_ok && !conn->ca_cert_verify)
preverify_ok = 1;
@@ -1485,13 +1495,21 @@
"AltSubject mismatch",
TLS_FAIL_ALTSUBJECT_MISMATCH);
} else if (depth == 0 && suffix_match &&
- !tls_match_suffix(err_cert, suffix_match)) {
+ !tls_match_suffix(err_cert, suffix_match, 0)) {
wpa_printf(MSG_WARNING, "TLS: Domain suffix match '%s' not found",
suffix_match);
preverify_ok = 0;
openssl_tls_fail_event(conn, err_cert, err, depth, buf,
"Domain suffix mismatch",
TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
+ } else if (depth == 0 && domain_match &&
+ !tls_match_suffix(err_cert, domain_match, 1)) {
+ wpa_printf(MSG_WARNING, "TLS: Domain match '%s' not found",
+ domain_match);
+ preverify_ok = 0;
+ openssl_tls_fail_event(conn, err_cert, err, depth, buf,
+ "Domain mismatch",
+ TLS_FAIL_DOMAIN_MISMATCH);
} else
openssl_tls_cert_event(conn, err_cert, depth, buf);
@@ -1755,7 +1773,8 @@
static int tls_connection_set_subject_match(struct tls_connection *conn,
const char *subject_match,
const char *altsubject_match,
- const char *suffix_match)
+ const char *suffix_match,
+ const char *domain_match)
{
os_free(conn->subject_match);
conn->subject_match = NULL;
@@ -1781,6 +1800,14 @@
return -1;
}
+ os_free(conn->domain_match);
+ conn->domain_match = NULL;
+ if (domain_match) {
+ conn->domain_match = os_strdup(domain_match);
+ if (conn->domain_match == NULL)
+ return -1;
+ }
+
return 0;
}
@@ -3207,7 +3234,8 @@
if (tls_connection_set_subject_match(conn,
params->subject_match,
params->altsubject_match,
- params->suffix_match))
+ params->suffix_match,
+ params->domain_match))
return -1;
if (params->engine && params->ca_cert_id) {
--- wpa_supplicant-2.2/src/eap_peer/eap_config.h
+++ wpa_supplicant-2.2/src/eap_peer/eap_config.h
@@ -225,6 +225,21 @@
*/
char *domain_suffix_match;
+ /**
+ * domain_match - Constraint for server domain name
+ *
+ * If set, this FQDN is used as a full match requirement for the
+ * server certificate in SubjectAltName dNSName element(s). If a
+ * matching dNSName is found, this constraint is met. If no dNSName
+ * values are present, this constraint is matched against SubjectName CN
+ * using same full match comparison. This behavior is similar to
+ * domain_suffix_match, but has the requirement of a full match, i.e.,
+ * no subdomains or wildcard matches are allowed. Case-insensitive
+ * comparison is used, so "Example.com" matches "example.com", but would
+ * not match "test.Example.com".
+ */
+ char *domain_match;
+
/**
* ca_cert2 - File path to CA certificate file (PEM/DER) (Phase 2)
*
@@ -329,6 +344,14 @@
char *domain_suffix_match2;
/**
+ * domain_match2 - Constraint for server domain name
+ *
+ * This field is like domain_match, but used for phase 2 (inside
+ * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ */
+ char *domain_match2;
+
+ /**
* eap_methods - Allowed EAP methods
*
* (vendor=EAP_VENDOR_IETF,method=EAP_TYPE_NONE) terminated list of
--- wpa_supplicant-2.2/src/eap_peer/eap_tls_common.c
+++ wpa_supplicant-2.2/src/eap_peer/eap_tls_common.c
@@ -91,6 +91,7 @@
params->subject_match = (char *) config->subject_match;
params->altsubject_match = (char *) config->altsubject_match;
params->suffix_match = config->domain_suffix_match;
+ params->domain_match = config->domain_match;
params->engine = config->engine;
params->engine_id = config->engine_id;
params->pin = config->pin;
@@ -113,6 +114,7 @@
params->subject_match = (char *) config->subject_match2;
params->altsubject_match = (char *) config->altsubject_match2;
params->suffix_match = config->domain_suffix_match2;
+ params->domain_match = config->domain_match2;
params->engine = config->engine2;
params->engine_id = config->engine2_id;
params->pin = config->pin2;
--- wpa_supplicant-2.2/wpa_supplicant/config.c
+++ wpa_supplicant-2.2/wpa_supplicant/config.c
@@ -1641,6 +1641,7 @@
{ STRe(subject_match) },
{ STRe(altsubject_match) },
{ STRe(domain_suffix_match) },
+ { STRe(domain_match) },
{ STRe(ca_cert2) },
{ STRe(ca_path2) },
{ STRe(client_cert2) },
@@ -1650,6 +1651,7 @@
{ STRe(subject_match2) },
{ STRe(altsubject_match2) },
{ STRe(domain_suffix_match2) },
+ { STRe(domain_match2) },
{ STRe(phase1) },
{ STRe(phase2) },
{ STRe(pcsc) },
@@ -1857,6 +1859,7 @@
os_free(eap->subject_match);
os_free(eap->altsubject_match);
os_free(eap->domain_suffix_match);
+ os_free(eap->domain_match);
os_free(eap->ca_cert2);
os_free(eap->ca_path2);
os_free(eap->client_cert2);
@@ -1866,6 +1869,7 @@
os_free(eap->subject_match2);
os_free(eap->altsubject_match2);
os_free(eap->domain_suffix_match2);
+ os_free(eap->domain_match2);
os_free(eap->phase1);
os_free(eap->phase2);
os_free(eap->pcsc);
--- wpa_supplicant-2.2/wpa_supplicant/config_file.c
+++ wpa_supplicant-2.2/wpa_supplicant/config_file.c
@@ -682,6 +682,7 @@
STR(subject_match);
STR(altsubject_match);
STR(domain_suffix_match);
+ STR(domain_match);
STR(ca_cert2);
STR(ca_path2);
STR(client_cert2);
@@ -691,6 +692,7 @@
STR(subject_match2);
STR(altsubject_match2);
STR(domain_suffix_match2);
+ STR(domain_match2);
STR(phase1);
STR(phase2);
STR(pcsc);
--- wpa_supplicant-2.2/wpa_supplicant/wpa_supplicant.conf
+++ wpa_supplicant-2.2/wpa_supplicant/wpa_supplicant.conf
@@ -810,6 +810,10 @@
# sertificate is only accepted if it contains this string in the subject.
# The subject string is in following format:
# /C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as@example.com
+# Note: Since this is a substring match, this cannot be used securily to
+# do a suffix match against a possible domain name in the CN entry. For
+# such a use case, domain_match should be used instead.
+# instead.
# altsubject_match: Semicolon separated string of entries to be matched against
# the alternative subject name of the authentication server certificate.
# If this string is set, the server sertificate is only accepted if it
@@ -818,6 +822,14 @@
# Example: EMAIL:server@example.com
# Example: DNS:server.example.com;DNS:server2.example.com
# Following types are supported: EMAIL, DNS, URI
+# domain_match: Constraint for server domain name
+# If set, this FQDN is used as a full match requirement for the
+# server certificate in SubjectAltName dNSName element(s). If a
+# matching dNSName is found, this constraint is met. If no dNSName
+# values are present, this constraint is matched against SubjectName CN
+# using same full match comparison. No subdomains or wildcard matches
+# are allowed. Case-insensitive comparison is used, so "Example.com"
+# matches "example.com", but would not match "test.Example.com".
# phase1: Phase1 (outer authentication, i.e., TLS tunnel) parameters
# (string with field-value pairs, e.g., "peapver=0" or
# "peapver=1 peaplabel=1")