diff options
| author | Dmitry Shmidt <dimitrysh@google.com> | 2015-01-21 13:19:05 -0800 |
|---|---|---|
| committer | Dmitry Shmidt <dimitrysh@google.com> | 2015-01-21 13:26:50 -0800 |
| commit | 2f74e36e84064ffa32f82f3decf36b653c7e4fad (patch) | |
| tree | 184eb654d7eeb89fbca4b8735baf64c07c1c721d /src/crypto | |
| parent | ff787d557db719adea0fdf2679667500c65cf74d (diff) | |
| download | android_external_wpa_supplicant_8-2f74e36e84064ffa32f82f3decf36b653c7e4fad.tar.gz android_external_wpa_supplicant_8-2f74e36e84064ffa32f82f3decf36b653c7e4fad.tar.bz2 android_external_wpa_supplicant_8-2f74e36e84064ffa32f82f3decf36b653c7e4fad.zip | |
Cumulative patch from commit fb09ed338919db09f3990196171fa73b37e7a17f (DO NOT MERGE)
fb09ed3 Interworking: Notify the ANQP parsing status
d10b01d HS20: Provide appropriate permission to the OSU related files
73f1ee0 HS20: Fix TrustRoot path for PolicyUpdate node in PPS MO
54a0ac0 HS20: Return result of cmd_sub_rem in hs20-osu-client
b62b0cb WNM: Fix possible memory leak by free buf
9bd0273 EAP: Fix possible memory leak in eap_ttls_process_decrypted()
b760e64 eap_server: Avoid NULL pointer dereference in eap_fast_encrypt_phase2()
948d3a8 hostapd: Remove unused variable from hostapd_get_hw_features
dd09e42 Fix memory leak in wpa_supplicant global bgscan configuration
30f459c wpa_cli: Fix NULL dereference on printf string argument
414f23d Avoid NULL string in printf on EAP method names in authenticator
b72b2ad P2P: Stop p2p_listen/find on wpas_p2p_invite
7b7b444 nl80211: Fix reading of the extended capabilities mask
7e608d1 P2P: Use the correct wpa_s interface to handle P2P state flush
fd83335 AP: Enable HT Tx STBC for AP/GO if supported by driver
d90bfa9 Move external_scan_running to wpa_radio
0c5f01f Clear reattach flag in fast associate flow
8ad8bc5 NFC: Redirect NFC commands on global control interface
57ae1f5 P2P: Fix P2P invitation with NFC
07565ab WNM: Fix the length of WNM_BSS_QUERY control interface command
2d9c99e Retry scan-for-connect if driver trigger fails
911942e Add a test framework for various wpa_supplicant failure cases
6b46bfa WPS: Re-fix an interoperability issue with mixed mode and AP Settings
1648cc6 ACS: Allow subset of channels to be configured
95ff306 nl80211: Allow HT/VHT to be disabled for IBSS
7451a21 mesh: Return negative value on join failed
5a2a6de mesh: Make inactivity timer configurable
b9749ba AP: Expire STA without entry in kernel
a114c72 AP: Remove redundant condition for STA expiration
0d787f0 Fix RADIUS client with out-of-memory and missing shared secret
0efcad2 Print in debug log whether attached monitor is for global interface
8266e6c HS 2.0: Try to use same BSS entry for storing GAS results
6c69991 Make wpa_supplicant FLUSH command more likely to clear all BSS entries
2dbe63a Write reason for scan only_new_results into debug log
242b83a eapol_test: Fix cert_cb() function arguments
a8826b1 Interworking: Avoid busy loop in scan result mismatch corner cases
edd5939 Interworking: Start ANQP fetch from eloop callback
cbc210d RADIUS DAS: Allow PMKSA cache entry to be removed without association
4e871ed RADIUS DAS: Support Acct-Multi-Session-Id as a session identifier
b52c0d4 Add authMultiSessionId into hostapd STA info
861beb7 RADIUS DAS: Check for single session match for Disconnect-Request
783b2a9 Interworking: Fix INTERWORKING_CONNECT with zero-length SSID BSS entry
1fef85c nl80211: Fix AP-scan-in-STA-mode error path behavior
cebee30 Add domain_match network profile parameter
d07d3fb Add peer certificate alt subject name information to EAP events
98a4cd4 D-Bus: Clear cached EAP data on network profile changes
483dd6a Include peer certificate always in EAP events
dd5f902 Get rid of a compiler warning
d29fa3a Extend VENDOR_ELEM parameters to cover non-P2P Association Request
e7d0e97 hostapd: Add vendor specific VHT extension for the 2.4 GHz band
Change-Id: I45436c49986cd6bddbd869db3f474871a29ce1dc
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
Diffstat (limited to 'src/crypto')
| -rw-r--r-- | src/crypto/tls.h | 15 | ||||
| -rw-r--r-- | src/crypto/tls_gnutls.c | 36 | ||||
| -rw-r--r-- | src/crypto/tls_internal.c | 5 | ||||
| -rw-r--r-- | src/crypto/tls_openssl.c | 104 | ||||
| -rw-r--r-- | src/crypto/tls_schannel.c | 5 |
5 files changed, 149 insertions, 16 deletions
diff --git a/src/crypto/tls.h b/src/crypto/tls.h index a4f954c7..9ae95a66 100644 --- a/src/crypto/tls.h +++ b/src/crypto/tls.h @@ -41,9 +41,13 @@ enum tls_fail_reason { 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, }; + +#define TLS_MAX_ALT_SUBJECT 10 + union tls_event_data { struct { int depth; @@ -59,6 +63,8 @@ union tls_event_data { const struct wpabuf *cert; const u8 *hash; size_t hash_len; + const char *altsubject[TLS_MAX_ALT_SUBJECT]; + int num_altsubject; } peer_cert; struct { @@ -102,7 +108,11 @@ struct tls_config { * @altsubject_match: String to match in the alternative subject of the peer * 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 + * certificate or %NULL to allow all domain names. This may allow subdomains an + * wildcard certificates. Each domain name label must have a full match. + * @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 @@ -146,6 +156,7 @@ struct tls_connection_params { 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; diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c index f2eacb5d..65db6fcc 100644 --- a/src/crypto/tls_gnutls.c +++ b/src/crypto/tls_gnutls.c @@ -58,6 +58,7 @@ struct tls_connection { gnutls_certificate_credentials_t xcred; char *suffix_match; + char *domain_match; unsigned int flags; }; @@ -280,6 +281,7 @@ void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn) wpabuf_free(conn->push_buf); wpabuf_free(conn->pull_buf); os_free(conn->suffix_match); + os_free(conn->domain_match); os_free(conn); } @@ -363,6 +365,21 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, return -1; } +#if GNUTLS_VERSION_NUMBER >= 0x030300 + os_free(conn->domain_match); + conn->domain_match = NULL; + if (params->domain_match) { + conn->domain_match = os_strdup(params->domain_match); + if (conn->domain_match == NULL) + return -1; + } +#else /* < 3.3.0 */ + if (params->domain_match) { + wpa_printf(MSG_INFO, "GnuTLS: domain_match not supported"); + return -1; + } +#endif /* >= 3.3.0 */ + conn->flags = params->flags; if (params->openssl_ciphers) { @@ -1111,6 +1128,25 @@ static int tls_connection_verify_peer(gnutls_session_t session) goto out; } +#if GNUTLS_VERSION_NUMBER >= 0x030300 + if (conn->domain_match && + !gnutls_x509_crt_check_hostname2( + cert, conn->domain_match, + GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS)) { + wpa_printf(MSG_WARNING, + "TLS: Domain match '%s' not found", + conn->domain_match); + gnutls_tls_fail_event( + conn, &certs[i], i, buf, + "Domain mismatch", + TLS_FAIL_DOMAIN_MISMATCH); + err = GNUTLS_A_BAD_CERTIFICATE; + gnutls_x509_crt_deinit(cert); + os_free(buf); + goto out; + } +#endif /* >= 3.3.0 */ + /* TODO: validate altsubject_match. * For now, any such configuration is rejected in * tls_connection_set_params() */ diff --git a/src/crypto/tls_internal.c b/src/crypto/tls_internal.c index 86375d11..0c955da2 100644 --- a/src/crypto/tls_internal.c +++ b/src/crypto/tls_internal.c @@ -205,6 +205,11 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, return -1; } + if (params->domain_match) { + wpa_printf(MSG_INFO, "TLS: domain_match not supported"); + return -1; + } + if (params->openssl_ciphers) { wpa_printf(MSG_INFO, "GnuTLS: openssl_ciphers not supported"); return -1; diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c index 5433ebb2..e3ca0682 100644 --- a/src/crypto/tls_openssl.c +++ b/src/crypto/tls_openssl.c @@ -96,7 +96,7 @@ struct tls_connection { 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; @@ -1098,6 +1098,7 @@ void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn) 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); } @@ -1190,7 +1191,8 @@ static int tls_match_altsubject(X509 *cert, const char *match) #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; @@ -1203,7 +1205,7 @@ static int domain_suffix_match(const u8 *val, size_t len, const char *match) } 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, @@ -1222,7 +1224,7 @@ static int domain_suffix_match(const u8 *val, size_t len, const char *match) #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 */ @@ -1235,7 +1237,8 @@ static int tls_match_suffix(X509 *cert, const char *match) 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); @@ -1248,8 +1251,10 @@ static int tls_match_suffix(X509 *cert, const char *match) 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; } } @@ -1276,13 +1281,16 @@ static int tls_match_suffix(X509 *cert, const char *match) 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"); + 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 */ } @@ -1377,6 +1385,11 @@ static void openssl_tls_cert_event(struct tls_connection *conn, struct wpabuf *cert = NULL; union tls_event_data ev; struct tls_context *context = conn->context; + char *altsubject[TLS_MAX_ALT_SUBJECT]; + int alt, num_altsubject = 0; + GENERAL_NAME *gen; + void *ext; + stack_index_t i; #ifdef CONFIG_SHA256 u8 hash[32]; #endif /* CONFIG_SHA256 */ @@ -1403,8 +1416,52 @@ static void openssl_tls_cert_event(struct tls_connection *conn, #endif /* CONFIG_SHA256 */ ev.peer_cert.depth = depth; ev.peer_cert.subject = subject; + + ext = X509_get_ext_d2i(err_cert, NID_subject_alt_name, NULL, NULL); + for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) { + char *pos; + + if (num_altsubject == TLS_MAX_ALT_SUBJECT) + break; + gen = sk_GENERAL_NAME_value(ext, i); + if (gen->type != GEN_EMAIL && + gen->type != GEN_DNS && + gen->type != GEN_URI) + continue; + + pos = os_malloc(10 + gen->d.ia5->length + 1); + if (pos == NULL) + break; + altsubject[num_altsubject++] = pos; + + switch (gen->type) { + case GEN_EMAIL: + os_memcpy(pos, "EMAIL:", 6); + pos += 6; + break; + case GEN_DNS: + os_memcpy(pos, "DNS:", 4); + pos += 4; + break; + case GEN_URI: + os_memcpy(pos, "URI:", 4); + pos += 4; + break; + } + + os_memcpy(pos, gen->d.ia5->data, gen->d.ia5->length); + pos += gen->d.ia5->length; + *pos = '\0'; + } + + for (alt = 0; alt < num_altsubject; alt++) + ev.peer_cert.altsubject[alt] = altsubject[alt]; + ev.peer_cert.num_altsubject = num_altsubject; + context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev); wpabuf_free(cert); + for (alt = 0; alt < num_altsubject; alt++) + os_free(altsubject[alt]); } @@ -1416,7 +1473,7 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx) 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); @@ -1444,6 +1501,7 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx) 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; @@ -1513,13 +1571,21 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx) "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); @@ -1783,7 +1849,8 @@ int tls_global_set_verify(void *ssl_ctx, int check_crl) 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; @@ -1809,6 +1876,14 @@ static int tls_connection_set_subject_match(struct tls_connection *conn, 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; } @@ -3273,7 +3348,8 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, 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 (engine_id && ca_cert_id) { diff --git a/src/crypto/tls_schannel.c b/src/crypto/tls_schannel.c index a43b4874..31a2c946 100644 --- a/src/crypto/tls_schannel.c +++ b/src/crypto/tls_schannel.c @@ -707,6 +707,11 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, return -1; } + if (params->domain_match) { + wpa_printf(MSG_INFO, "TLS: domain_match not supported"); + return -1; + } + if (params->openssl_ciphers) { wpa_printf(MSG_INFO, "GnuTLS: openssl_ciphers not supported"); return -1; |
