aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Shmidt <dimitrysh@google.com>2015-12-14 12:45:46 -0800
committerDmitry Shmidt <dimitrysh@google.com>2015-12-14 16:03:59 -0800
commit55840adb6cd32ca52064f327b72a40e769f70661 (patch)
tree40e19b01486781811b9037aa3cb7a093cf83b921
parentae24cbe9b93567c1ae4d1fd332fab07a04965b33 (diff)
downloadandroid_external_wpa_supplicant_8-55840adb6cd32ca52064f327b72a40e769f70661.tar.gz
android_external_wpa_supplicant_8-55840adb6cd32ca52064f327b72a40e769f70661.tar.bz2
android_external_wpa_supplicant_8-55840adb6cd32ca52064f327b72a40e769f70661.zip
Cumulative patch from commit 06f14421ea8644d12a7b0be6b583114869f9c451 (DO NOT MERGE)
06f1442 TLS: Parse OCSPResponse to extract BasicOCSPResponse d560288 TLS: Parse CertificateStatus message eeba168 TLS: Add status_request ClientHello extension if OCSP is requested 4303d53 TLS: Parse ServerHello extensions 6b7bb42 TLS: Add minimal support for PKCS #12 5ce2941 TLS: Extend PKCS #5 to support PKCS #12 style key decryption f6a62df TLS: Fix and complete ASN.1 tag list 3c108b7 EAP peer: External server certificate chain validation b6e5e14 EAP-FAST peer: Fix PAC parser error messages 5b904b3 EAP-FAST: Check T-PRF result in MSK/EMSK derivation b1d8c5c EAP-FAST peer: Fix error path handling for Session-Id 36478a1 OpenSSL: Support new API for HMAC/EVP_MD_CTX in OpenSSL 1.1.x-pre1 9257610 FT: Fix FTIE generation for EAPOL-Key msg 3/4 e44bd28 FT: Fix sm->assoc_resp_ftie storing on the AP side 59e78c2 FT: Fix FTIE generation for 4-way handshake after FT protocol run b0ecbd3 AP: Use more readable version of management group cipher in error cases 651c6a8 Add TEST_ASSOC_IE for WPA/RSN IE testing on AP side 58059e6 FST: Print debug entry on MB IE update based on EVENT_AUTH af041f9 dbus: Add support for vendor specific elements 5c8acf7 EAP-IKEv2: Check HMAC SHA1/MD5 result 7b991b4 Use proper build config for parsing proxy_arp 4db29e6 TLS: Add support for PKCS #5 v2.0 PBES2 Change-Id: I10b71e4d3573ef60a52ea6ff56afcd3a06a0b7b0 Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
-rw-r--r--hostapd/config_file.c6
-rw-r--r--src/ap/wpa_auth.c25
-rw-r--r--src/ap/wpa_auth_ft.c10
-rw-r--r--src/common/defs.h1
-rw-r--r--src/common/wpa_common.c41
-rw-r--r--src/common/wpa_common.h2
-rw-r--r--src/crypto/crypto_openssl.c92
-rw-r--r--src/crypto/tls.h1
-rw-r--r--src/crypto/tls_gnutls.c6
-rw-r--r--src/crypto/tls_internal.c6
-rw-r--r--src/crypto/tls_openssl.c5
-rw-r--r--src/eap_common/eap_fast_common.c20
-rw-r--r--src/eap_common/eap_fast_common.h4
-rw-r--r--src/eap_common/ikev2_common.c15
-rw-r--r--src/eap_peer/eap.c23
-rw-r--r--src/eap_peer/eap_config.h14
-rw-r--r--src/eap_peer/eap_fast.c49
-rw-r--r--src/eap_peer/eap_fast_pac.c3
-rw-r--r--src/eap_peer/eap_i.h2
-rw-r--r--src/eap_peer/eap_peap.c44
-rw-r--r--src/eap_peer/eap_tls.c42
-rw-r--r--src/eap_peer/eap_tls_common.c6
-rw-r--r--src/eap_peer/eap_ttls.c41
-rw-r--r--src/eap_server/eap_server_fast.c10
-rw-r--r--src/rsn_supp/wpa.c26
-rw-r--r--src/rsn_supp/wpa.h1
-rw-r--r--src/rsn_supp/wpa_i.h4
-rw-r--r--src/tls/Makefile1
-rw-r--r--src/tls/asn1.h4
-rw-r--r--src/tls/pkcs5.c446
-rw-r--r--src/tls/tlsv1_client.c4
-rw-r--r--src/tls/tlsv1_client_i.h10
-rw-r--r--src/tls/tlsv1_client_ocsp.c169
-rw-r--r--src/tls/tlsv1_client_read.c209
-rw-r--r--src/tls/tlsv1_client_write.c40
-rw-r--r--src/tls/tlsv1_cred.c738
-rw-r--r--wpa_supplicant/Android.mk1
-rw-r--r--wpa_supplicant/Makefile1
-rw-r--r--wpa_supplicant/ctrl_iface.c110
-rw-r--r--wpa_supplicant/dbus/dbus_new.c24
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers.c144
-rw-r--r--wpa_supplicant/dbus/dbus_new_handlers.h7
-rw-r--r--wpa_supplicant/events.c5
-rw-r--r--wpa_supplicant/wpa_supplicant.c93
-rw-r--r--wpa_supplicant/wpa_supplicant.conf6
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h6
-rw-r--r--wpa_supplicant/wpas_glue.c8
47 files changed, 2363 insertions, 162 deletions
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index bf424661..f2163b83 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -3206,13 +3206,15 @@ static int hostapd_config_fill(struct hostapd_config *conf,
os_free(bss->dump_msk_file);
bss->dump_msk_file = os_strdup(pos);
#endif /* CONFIG_RADIUS_TEST */
+#ifdef CONFIG_PROXYARP
+ } else if (os_strcmp(buf, "proxy_arp") == 0) {
+ bss->proxy_arp = atoi(pos);
+#endif /* CONFIG_PROXYARP */
#ifdef CONFIG_HS20
} else if (os_strcmp(buf, "hs20") == 0) {
bss->hs20 = atoi(pos);
} else if (os_strcmp(buf, "disable_dgaf") == 0) {
bss->disable_dgaf = atoi(pos);
- } else if (os_strcmp(buf, "proxy_arp") == 0) {
- bss->proxy_arp = atoi(pos);
} else if (os_strcmp(buf, "na_mcast_to_ucast") == 0) {
bss->na_mcast_to_ucast = atoi(pos);
} else if (os_strcmp(buf, "osen") == 0) {
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index c2c5693c..9b2382f3 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -2298,14 +2298,19 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
pos += wpa_ie_len;
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
- int res = wpa_insert_pmkid(kde, pos - kde, sm->pmk_r1_name);
+ int res;
+ size_t elen;
+
+ elen = pos - kde;
+ res = wpa_insert_pmkid(kde, &elen, sm->pmk_r1_name);
if (res < 0) {
wpa_printf(MSG_ERROR, "FT: Failed to insert "
"PMKR1Name into RSN IE in EAPOL-Key data");
os_free(kde);
return;
}
- pos += res;
+ pos -= wpa_ie_len;
+ pos += elen;
}
#endif /* CONFIG_IEEE80211R */
if (gtk) {
@@ -2323,10 +2328,18 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
struct wpa_auth_config *conf;
conf = &sm->wpa_auth->conf;
- res = wpa_write_ftie(conf, conf->r0_key_holder,
- conf->r0_key_holder_len,
- NULL, NULL, pos, kde + kde_len - pos,
- NULL, 0);
+ if (sm->assoc_resp_ftie &&
+ kde + kde_len - pos >= 2 + sm->assoc_resp_ftie[1]) {
+ os_memcpy(pos, sm->assoc_resp_ftie,
+ 2 + sm->assoc_resp_ftie[1]);
+ res = 2 + sm->assoc_resp_ftie[1];
+ } else {
+ res = wpa_write_ftie(conf, conf->r0_key_holder,
+ conf->r0_key_holder_len,
+ NULL, NULL, pos,
+ kde + kde_len - pos,
+ NULL, 0);
+ }
if (res < 0) {
wpa_printf(MSG_ERROR, "FT: Failed to insert FTIE "
"into EAPOL-Key Key Data");
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index eeaffbf6..42242a54 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -720,11 +720,6 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
ftie_len = res;
pos += res;
- os_free(sm->assoc_resp_ftie);
- sm->assoc_resp_ftie = os_malloc(ftie_len);
- if (sm->assoc_resp_ftie)
- os_memcpy(sm->assoc_resp_ftie, ftie, ftie_len);
-
_ftie = (struct rsn_ftie *) (ftie + 2);
if (auth_alg == WLAN_AUTH_FT)
_ftie->mic_control[1] = 3; /* Information element count */
@@ -750,6 +745,11 @@ u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
_ftie->mic) < 0)
wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
+ os_free(sm->assoc_resp_ftie);
+ sm->assoc_resp_ftie = os_malloc(ftie_len);
+ if (sm->assoc_resp_ftie)
+ os_memcpy(sm->assoc_resp_ftie, ftie, ftie_len);
+
return pos;
}
diff --git a/src/common/defs.h b/src/common/defs.h
index 6aea3751..b3ac4e86 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -312,6 +312,7 @@ enum wpa_ctrl_req_type {
WPA_CTRL_REQ_EAP_PASSPHRASE,
WPA_CTRL_REQ_SIM,
WPA_CTRL_REQ_PSK_PASSPHRASE,
+ WPA_CTRL_REQ_EXT_CERT_CHECK,
NUM_WPA_CTRL_REQS
};
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index 4091bed0..b5f57b3e 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -689,9 +689,10 @@ int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
if (left >= 4) {
data->mgmt_group_cipher = rsn_selector_to_bitfield(pos);
if (!wpa_cipher_valid_mgmt_group(data->mgmt_group_cipher)) {
- wpa_printf(MSG_DEBUG, "%s: Unsupported management "
- "group cipher 0x%x", __func__,
- data->mgmt_group_cipher);
+ wpa_printf(MSG_DEBUG,
+ "%s: Unsupported management group cipher 0x%x (%08x)",
+ __func__, data->mgmt_group_cipher,
+ WPA_GET_BE32(pos));
return -10;
}
pos += RSN_SELECTOR_LEN;
@@ -1279,13 +1280,13 @@ int wpa_compare_rsn_ie(int ft_initial_assoc,
#ifdef CONFIG_IEEE80211R
-int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid)
+int wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid)
{
u8 *start, *end, *rpos, *rend;
int added = 0;
start = ies;
- end = ies + ies_len;
+ end = ies + *ies_len;
while (start < end) {
if (*start == WLAN_EID_RSN)
@@ -1338,11 +1339,29 @@ int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid)
added += 2 + PMKID_LEN;
start[1] += 2 + PMKID_LEN;
} else {
- /* PMKID-Count was included; use it */
- if (WPA_GET_LE16(rpos) != 0) {
- wpa_printf(MSG_ERROR, "FT: Unexpected PMKID "
- "in RSN IE in EAPOL-Key data");
+ u16 num_pmkid;
+
+ if (rend - rpos < 2)
return -1;
+ num_pmkid = WPA_GET_LE16(rpos);
+ /* PMKID-Count was included; use it */
+ if (num_pmkid != 0) {
+ u8 *after;
+
+ if (num_pmkid * PMKID_LEN > rend - rpos - 2)
+ return -1;
+ /*
+ * PMKID may have been included in RSN IE in
+ * (Re)Association Request frame, so remove the old
+ * PMKID(s) first before adding the new one.
+ */
+ wpa_printf(MSG_DEBUG,
+ "FT: Remove %u old PMKID(s) from RSN IE",
+ num_pmkid);
+ after = rpos + 2 + num_pmkid * PMKID_LEN;
+ os_memmove(rpos + 2, after, rend - after);
+ start[1] -= num_pmkid * PMKID_LEN;
+ added -= num_pmkid * PMKID_LEN;
}
WPA_PUT_LE16(rpos, 1);
rpos += 2;
@@ -1355,7 +1374,9 @@ int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid)
wpa_hexdump(MSG_DEBUG, "FT: RSN IE after modification "
"(PMKID inserted)", start, 2 + start[1]);
- return added;
+ *ies_len += added;
+
+ return 0;
}
#endif /* CONFIG_IEEE80211R */
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index ee71bfc0..af1d0f0c 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -409,7 +409,7 @@ u32 wpa_akm_to_suite(int akm);
int wpa_compare_rsn_ie(int ft_initial_assoc,
const u8 *ie1, size_t ie1len,
const u8 *ie2, size_t ie2len);
-int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid);
+int wpa_insert_pmkid(u8 *ies, size_t *ies_len, const u8 *pmkid);
struct wpa_ft_ies {
const u8 *mdie;
diff --git a/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index ad2d2d4a..b53bc4a3 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -65,6 +65,42 @@ static BIGNUM * get_group5_prime(void)
static int openssl_digest_vector(const EVP_MD *type, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac)
{
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ EVP_MD_CTX *ctx;
+ size_t i;
+ unsigned int mac_len;
+
+ if (TEST_FAIL())
+ return -1;
+
+ ctx = EVP_MD_CTX_new();
+ if (!ctx)
+ return -1;
+ if (!EVP_DigestInit_ex(ctx, type, NULL)) {
+ wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestInit_ex failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ EVP_MD_CTX_free(ctx);
+ return -1;
+ }
+ for (i = 0; i < num_elem; i++) {
+ if (!EVP_DigestUpdate(ctx, addr[i], len[i])) {
+ wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestUpdate "
+ "failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ EVP_MD_CTX_free(ctx);
+ return -1;
+ }
+ }
+ if (!EVP_DigestFinal(ctx, mac, &mac_len)) {
+ wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestFinal failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ EVP_MD_CTX_free(ctx);
+ return -1;
+ }
+ EVP_MD_CTX_free(ctx);
+
+ return 0;
+#else
EVP_MD_CTX ctx;
size_t i;
unsigned int mac_len;
@@ -93,6 +129,7 @@ static int openssl_digest_vector(const EVP_MD *type, size_t num_elem,
}
return 0;
+#endif
}
@@ -681,7 +718,11 @@ void dh5_free(void *ctx)
struct crypto_hash {
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ HMAC_CTX *ctx;
+#else
HMAC_CTX ctx;
+#endif
};
@@ -716,6 +757,19 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
ctx = os_zalloc(sizeof(*ctx));
if (ctx == NULL)
return NULL;
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ ctx->ctx = HMAC_CTX_new();
+ if (!ctx->ctx) {
+ os_free(ctx);
+ return NULL;
+ }
+
+ if (HMAC_Init_ex(ctx->ctx, key, key_len, md, NULL) != 1) {
+ HMAC_CTX_free(ctx->ctx);
+ bin_clear_free(ctx, sizeof(*ctx));
+ return NULL;
+ }
+#else
HMAC_CTX_init(&ctx->ctx);
#if OPENSSL_VERSION_NUMBER < 0x00909000
@@ -726,6 +780,7 @@ struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
return NULL;
}
#endif /* openssl < 0.9.9 */
+#endif
return ctx;
}
@@ -735,7 +790,11 @@ void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
{
if (ctx == NULL)
return;
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ HMAC_Update(ctx->ctx, data, len);
+#else
HMAC_Update(&ctx->ctx, data, len);
+#endif
}
@@ -748,11 +807,18 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
return -2;
if (mac == NULL || len == NULL) {
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ HMAC_CTX_free(ctx->ctx);
+#endif
bin_clear_free(ctx, sizeof(*ctx));
return 0;
}
mdlen = *len;
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ res = HMAC_Final(ctx->ctx, mac, &mdlen);
+ HMAC_CTX_free(ctx->ctx);
+#else
#if OPENSSL_VERSION_NUMBER < 0x00909000
HMAC_Final(&ctx->ctx, mac, &mdlen);
res = 1;
@@ -760,6 +826,7 @@ int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
res = HMAC_Final(&ctx->ctx, mac, &mdlen);
#endif /* openssl < 0.9.9 */
HMAC_CTX_cleanup(&ctx->ctx);
+#endif
bin_clear_free(ctx, sizeof(*ctx));
if (res == 1) {
@@ -776,6 +843,30 @@ static int openssl_hmac_vector(const EVP_MD *type, const u8 *key,
const u8 *addr[], const size_t *len, u8 *mac,
unsigned int mdlen)
{
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ HMAC_CTX *ctx;
+ size_t i;
+ int res;
+
+ if (TEST_FAIL())
+ return -1;
+
+ ctx = HMAC_CTX_new();
+ if (!ctx)
+ return -1;
+ res = HMAC_Init_ex(ctx, key, key_len, type, NULL);
+ if (res != 1)
+ goto done;
+
+ for (i = 0; i < num_elem; i++)
+ HMAC_Update(ctx, addr[i], len[i]);
+
+ res = HMAC_Final(ctx, mac, &mdlen);
+done:
+ HMAC_CTX_free(ctx);
+
+ return res == 1 ? 0 : -1;
+#else
HMAC_CTX ctx;
size_t i;
int res;
@@ -803,6 +894,7 @@ static int openssl_hmac_vector(const EVP_MD *type, const u8 *key,
HMAC_CTX_cleanup(&ctx);
return res == 1 ? 0 : -1;
+#endif
}
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index 2e562339..bca94d67 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -95,6 +95,7 @@ struct tls_config {
#define TLS_CONN_DISABLE_TLSv1_2 BIT(6)
#define TLS_CONN_EAP_FAST BIT(7)
#define TLS_CONN_DISABLE_TLSv1_0 BIT(8)
+#define TLS_CONN_EXT_CERT_CHECK BIT(9)
/**
* struct tls_connection_params - Parameters for TLS connection
diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c
index f994379b..b1bec4a5 100644
--- a/src/crypto/tls_gnutls.c
+++ b/src/crypto/tls_gnutls.c
@@ -347,6 +347,12 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
if (conn == NULL || params == NULL)
return -1;
+ if (params->flags & TLS_CONN_EXT_CERT_CHECK) {
+ wpa_printf(MSG_INFO,
+ "GnuTLS: tls_ext_cert_check=1 not supported");
+ return -1;
+ }
+
if (params->subject_match) {
wpa_printf(MSG_INFO, "GnuTLS: subject_match not supported");
return -1;
diff --git a/src/crypto/tls_internal.c b/src/crypto/tls_internal.c
index dcbb31d7..8b90d565 100644
--- a/src/crypto/tls_internal.c
+++ b/src/crypto/tls_internal.c
@@ -200,6 +200,12 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
if (conn->client == NULL)
return -1;
+ if (params->flags & TLS_CONN_EXT_CERT_CHECK) {
+ wpa_printf(MSG_INFO,
+ "TLS: tls_ext_cert_check=1 not supported");
+ return -1;
+ }
+
cred = tlsv1_cred_alloc();
if (cred == NULL)
return -1;
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 471ae2b7..1d75ba7a 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -1583,7 +1583,8 @@ static void openssl_tls_cert_event(struct tls_connection *conn,
return;
os_memset(&ev, 0, sizeof(ev));
- if (conn->cert_probe || context->cert_in_cb) {
+ if (conn->cert_probe || (conn->flags & TLS_CONN_EXT_CERT_CHECK) ||
+ context->cert_in_cb) {
cert = get_x509_cert(err_cert);
ev.peer_cert.cert = cert;
}
@@ -1821,7 +1822,7 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
}
#endif /* OPENSSL_IS_BORINGSSL */
- if (preverify_ok && context->event_cb != NULL)
+ if (depth == 0 && preverify_ok && context->event_cb != NULL)
context->event_cb(context->cb_ctx,
TLS_CERT_CHAIN_SUCCESS, NULL);
diff --git a/src/eap_common/eap_fast_common.c b/src/eap_common/eap_fast_common.c
index 151cc785..e8587fda 100644
--- a/src/eap_common/eap_fast_common.c
+++ b/src/eap_common/eap_fast_common.c
@@ -111,22 +111,24 @@ u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn,
}
-void eap_fast_derive_eap_msk(const u8 *simck, u8 *msk)
+int eap_fast_derive_eap_msk(const u8 *simck, u8 *msk)
{
/*
* RFC 4851, Section 5.4: EAP Master Session Key Generation
* MSK = T-PRF(S-IMCK[j], "Session Key Generating Function", 64)
*/
- sha1_t_prf(simck, EAP_FAST_SIMCK_LEN,
- "Session Key Generating Function", (u8 *) "", 0,
- msk, EAP_FAST_KEY_LEN);
+ if (sha1_t_prf(simck, EAP_FAST_SIMCK_LEN,
+ "Session Key Generating Function", (u8 *) "", 0,
+ msk, EAP_FAST_KEY_LEN) < 0)
+ return -1;
wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (MSK)",
msk, EAP_FAST_KEY_LEN);
+ return 0;
}
-void eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk)
+int eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk)
{
/*
* RFC 4851, Section 5.4: EAP Master Session Key Genreration
@@ -134,11 +136,13 @@ void eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk)
* "Extended Session Key Generating Function", 64)
*/
- sha1_t_prf(simck, EAP_FAST_SIMCK_LEN,
- "Extended Session Key Generating Function", (u8 *) "", 0,
- emsk, EAP_EMSK_LEN);
+ if (sha1_t_prf(simck, EAP_FAST_SIMCK_LEN,
+ "Extended Session Key Generating Function", (u8 *) "", 0,
+ emsk, EAP_EMSK_LEN) < 0)
+ return -1;
wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (EMSK)",
emsk, EAP_EMSK_LEN);
+ return 0;
}
diff --git a/src/eap_common/eap_fast_common.h b/src/eap_common/eap_fast_common.h
index d59a8450..6756dd23 100644
--- a/src/eap_common/eap_fast_common.h
+++ b/src/eap_common/eap_fast_common.h
@@ -99,8 +99,8 @@ void eap_fast_derive_master_secret(const u8 *pac_key, const u8 *server_random,
const u8 *client_random, u8 *master_secret);
u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn,
const char *label, size_t len);
-void eap_fast_derive_eap_msk(const u8 *simck, u8 *msk);
-void eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk);
+int eap_fast_derive_eap_msk(const u8 *simck, u8 *msk);
+int eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk);
int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv,
int tlv_type, u8 *pos, size_t len);
diff --git a/src/eap_common/ikev2_common.c b/src/eap_common/ikev2_common.c
index d60358c7..90fb89e2 100644
--- a/src/eap_common/ikev2_common.c
+++ b/src/eap_common/ikev2_common.c
@@ -62,13 +62,15 @@ int ikev2_integ_hash(int alg, const u8 *key, size_t key_len, const u8 *data,
case AUTH_HMAC_SHA1_96:
if (key_len != 20)
return -1;
- hmac_sha1(key, key_len, data, data_len, tmphash);
+ if (hmac_sha1(key, key_len, data, data_len, tmphash) < 0)
+ return -1;
os_memcpy(hash, tmphash, 12);
break;
case AUTH_HMAC_MD5_96:
if (key_len != 16)
return -1;
- hmac_md5(key, key_len, data, data_len, tmphash);
+ if (hmac_md5(key, key_len, data, data_len, tmphash) < 0)
+ return -1;
os_memcpy(hash, tmphash, 12);
break;
default:
@@ -98,16 +100,13 @@ int ikev2_prf_hash(int alg, const u8 *key, size_t key_len,
{
switch (alg) {
case PRF_HMAC_SHA1:
- hmac_sha1_vector(key, key_len, num_elem, addr, len, hash);
- break;
+ return hmac_sha1_vector(key, key_len, num_elem, addr, len,
+ hash);
case PRF_HMAC_MD5:
- hmac_md5_vector(key, key_len, num_elem, addr, len, hash);
- break;
+ return hmac_md5_vector(key, key_len, num_elem, addr, len, hash);
default:
return -1;
}
-
- return 0;
}
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index 28d5116f..5c189786 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -48,6 +48,8 @@ static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req);
static const char * eap_sm_method_state_txt(EapMethodState state);
static const char * eap_sm_decision_txt(EapDecision decision);
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+static void eap_sm_request(struct eap_sm *sm, enum wpa_ctrl_req_type field,
+ const char *msg, size_t msglen);
@@ -320,11 +322,14 @@ SM_STATE(EAP, GET_METHOD)
wpa_printf(MSG_DEBUG, "EAP: Initialize selected EAP method: "
"vendor %u method %u (%s)",
sm->reqVendor, method, sm->m->name);
- if (reinit)
+ if (reinit) {
sm->eap_method_priv = sm->m->init_for_reauth(
sm, sm->eap_method_priv);
- else
+ } else {
+ sm->waiting_ext_cert_check = 0;
+ sm->ext_cert_check = 0;
sm->eap_method_priv = sm->m->init(sm);
+ }
if (sm->eap_method_priv == NULL) {
struct eap_peer_config *config = eap_get_config(sm);
@@ -1858,6 +1863,11 @@ static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev,
case TLS_CERT_CHAIN_SUCCESS:
eap_notify_status(sm, "remote certificate verification",
"success");
+ if (sm->ext_cert_check) {
+ sm->waiting_ext_cert_check = 1;
+ eap_sm_request(sm, WPA_CTRL_REQ_EXT_CERT_CHECK,
+ NULL, 0);
+ }
break;
case TLS_CERT_CHAIN_FAILURE:
wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TLS_CERT_ERROR
@@ -2180,10 +2190,10 @@ int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose)
#endif /* CONFIG_CTRL_IFACE */
-#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
static void eap_sm_request(struct eap_sm *sm, enum wpa_ctrl_req_type field,
const char *msg, size_t msglen)
{
+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
struct eap_peer_config *config;
const char *txt = NULL;
char *tmp;
@@ -2232,16 +2242,17 @@ static void eap_sm_request(struct eap_sm *sm, enum wpa_ctrl_req_type field,
case WPA_CTRL_REQ_SIM:
txt = msg;
break;
+ case WPA_CTRL_REQ_EXT_CERT_CHECK:
+ break;
default:
return;
}
if (sm->eapol_cb->eap_param_needed)
sm->eapol_cb->eap_param_needed(sm->eapol_ctx, field, txt);
-}
-#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
-#define eap_sm_request(sm, type, msg, msglen) do { } while (0)
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+}
+
const char * eap_sm_get_method_name(struct eap_sm *sm)
{
diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h
index 2b1a1d5e..39ddcff6 100644
--- a/src/eap_peer/eap_config.h
+++ b/src/eap_peer/eap_config.h
@@ -739,6 +739,20 @@ struct eap_peer_config {
* erp - Whether EAP Re-authentication Protocol (ERP) is enabled
*/
int erp;
+
+ /**
+ * pending_ext_cert_check - External server certificate check status
+ *
+ * This field should not be set in configuration step. It is only used
+ * internally when control interface is used to request external
+ * validation of server certificate chain.
+ */
+ enum {
+ NO_CHECK = 0,
+ PENDING_CHECK,
+ EXT_CERT_CHECK_GOOD,
+ EXT_CERT_CHECK_BAD,
+ } pending_ext_cert_check;
};
diff --git a/src/eap_peer/eap_fast.c b/src/eap_peer/eap_fast.c
index 833dcb6b..a7f6befa 100644
--- a/src/eap_peer/eap_fast.c
+++ b/src/eap_peer/eap_fast.c
@@ -1,6 +1,6 @@
/*
* EAP peer method: EAP-FAST (RFC 4851)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -67,6 +67,7 @@ struct eap_fast_data {
int simck_idx;
struct wpabuf *pending_phase2_req;
+ struct wpabuf *pending_resp;
};
@@ -254,14 +255,16 @@ static void eap_fast_deinit(struct eap_sm *sm, void *priv)
os_memset(data->emsk, 0, EAP_EMSK_LEN);
os_free(data->session_id);
wpabuf_free(data->pending_phase2_req);
+ wpabuf_free(data->pending_resp);
os_free(data);
}
static int eap_fast_derive_msk(struct eap_fast_data *data)
{
- eap_fast_derive_eap_msk(data->simck, data->key_data);
- eap_fast_derive_eap_emsk(data->simck, data->emsk);
+ if (eap_fast_derive_eap_msk(data->simck, data->key_data) < 0 ||
+ eap_fast_derive_eap_emsk(data->simck, data->emsk) < 0)
+ return -1;
data->success = 1;
return 0;
}
@@ -1567,6 +1570,34 @@ static struct wpabuf * eap_fast_process(struct eap_sm *sm, void *priv,
res = 1;
}
} else {
+ if (sm->waiting_ext_cert_check && data->pending_resp) {
+ struct eap_peer_config *config = eap_get_config(sm);
+
+ if (config->pending_ext_cert_check ==
+ EXT_CERT_CHECK_GOOD) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-FAST: External certificate check succeeded - continue handshake");
+ resp = data->pending_resp;
+ data->pending_resp = NULL;
+ sm->waiting_ext_cert_check = 0;
+ return resp;
+ }
+
+ if (config->pending_ext_cert_check ==
+ EXT_CERT_CHECK_BAD) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-FAST: External certificate check failed - force authentication failure");
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ sm->waiting_ext_cert_check = 0;
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-FAST: Continuing to wait external server certificate validation");
+ return NULL;
+ }
+
/* Continue processing TLS handshake (phase 1). */
res = eap_peer_tls_process_helper(sm, &data->ssl,
EAP_TYPE_FAST,
@@ -1580,6 +1611,14 @@ static struct wpabuf * eap_fast_process(struct eap_sm *sm, void *priv,
return resp;
}
+ if (sm->waiting_ext_cert_check) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-FAST: Waiting external server certificate validation");
+ wpabuf_free(data->pending_resp);
+ data->pending_resp = resp;
+ return NULL;
+ }
+
if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
char cipher[80];
wpa_printf(MSG_DEBUG,
@@ -1644,6 +1683,8 @@ static void eap_fast_deinit_for_reauth(struct eap_sm *sm, void *priv)
data->key_block_p = NULL;
wpabuf_free(data->pending_phase2_req);
data->pending_phase2_req = NULL;
+ wpabuf_free(data->pending_resp);
+ data->pending_resp = NULL;
}
@@ -1721,7 +1762,7 @@ static u8 * eap_fast_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
struct eap_fast_data *data = priv;
u8 *id;
- if (!data->success)
+ if (!data->success || !data->session_id)
return NULL;
id = os_malloc(data->id_len);
diff --git a/src/eap_peer/eap_fast_pac.c b/src/eap_peer/eap_fast_pac.c
index c0986b31..0220caed 100644
--- a/src/eap_peer/eap_fast_pac.c
+++ b/src/eap_peer/eap_fast_pac.c
@@ -455,7 +455,8 @@ int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_pac **pac_root,
}
if (pac) {
- err = "PAC block not terminated with END";
+ if (!err)
+ err = "PAC block not terminated with END";
eap_fast_free_pac(pac);
}
diff --git a/src/eap_peer/eap_i.h b/src/eap_peer/eap_i.h
index 99b44dae..6ab24834 100644
--- a/src/eap_peer/eap_i.h
+++ b/src/eap_peer/eap_i.h
@@ -366,6 +366,8 @@ struct eap_sm {
int external_sim;
unsigned int expected_failure:1;
+ unsigned int ext_cert_check:1;
+ unsigned int waiting_ext_cert_check:1;
struct dl_list erp_keys; /* struct eap_erp_key */
};
diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c
index 98a48a6c..05960989 100644
--- a/src/eap_peer/eap_peap.c
+++ b/src/eap_peer/eap_peap.c
@@ -1,6 +1,6 @@
/*
* EAP peer method: EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -59,6 +59,7 @@ struct eap_peap_data {
size_t id_len;
struct wpabuf *pending_phase2_req;
+ struct wpabuf *pending_resp;
enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
int crypto_binding_used;
u8 binding_nonce[32];
@@ -191,6 +192,7 @@ static void eap_peap_deinit(struct eap_sm *sm, void *priv)
eap_peap_free_key(data);
os_free(data->session_id);
wpabuf_free(data->pending_phase2_req);
+ wpabuf_free(data->pending_resp);
os_free(data);
}
@@ -1006,6 +1008,34 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
!data->resuming) {
res = eap_peap_decrypt(sm, data, ret, req, &msg, &resp);
} else {
+ if (sm->waiting_ext_cert_check && data->pending_resp) {
+ struct eap_peer_config *config = eap_get_config(sm);
+
+ if (config->pending_ext_cert_check ==
+ EXT_CERT_CHECK_GOOD) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-PEAP: External certificate check succeeded - continue handshake");
+ resp = data->pending_resp;
+ data->pending_resp = NULL;
+ sm->waiting_ext_cert_check = 0;
+ return resp;
+ }
+
+ if (config->pending_ext_cert_check ==
+ EXT_CERT_CHECK_BAD) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-PEAP: External certificate check failed - force authentication failure");
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ sm->waiting_ext_cert_check = 0;
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-PEAP: Continuing to wait external server certificate validation");
+ return NULL;
+ }
+
res = eap_peer_tls_process_helper(sm, &data->ssl,
EAP_TYPE_PEAP,
data->peap_version, id, &msg,
@@ -1018,6 +1048,16 @@ static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
ret->decision = DECISION_FAIL;
return resp;
}
+
+
+ if (sm->waiting_ext_cert_check) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-PEAP: Waiting external server certificate validation");
+ wpabuf_free(data->pending_resp);
+ data->pending_resp = resp;
+ return NULL;
+ }
+
if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
char *label;
wpa_printf(MSG_DEBUG,
@@ -1123,6 +1163,8 @@ static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv)
struct eap_peap_data *data = priv;
wpabuf_free(data->pending_phase2_req);
data->pending_phase2_req = NULL;
+ wpabuf_free(data->pending_resp);
+ data->pending_resp = NULL;
data->crypto_binding_used = 0;
}
diff --git a/src/eap_peer/eap_tls.c b/src/eap_peer/eap_tls.c
index 66a027a6..ba8e74b5 100644
--- a/src/eap_peer/eap_tls.c
+++ b/src/eap_peer/eap_tls.c
@@ -1,6 +1,6 @@
/*
* EAP peer method: EAP-TLS (RFC 2716)
- * Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2008, 2012-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -25,6 +25,7 @@ struct eap_tls_data {
size_t id_len;
void *ssl_ctx;
u8 eap_type;
+ struct wpabuf *pending_resp;
};
@@ -142,6 +143,7 @@ static void eap_tls_deinit(struct eap_sm *sm, void *priv)
eap_peer_tls_ssl_deinit(sm, &data->ssl);
eap_tls_free_key(data);
os_free(data->session_id);
+ wpabuf_free(data->pending_resp);
os_free(data);
}
@@ -216,6 +218,32 @@ static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv,
struct eap_tls_data *data = priv;
struct wpabuf msg;
+ if (sm->waiting_ext_cert_check && data->pending_resp) {
+ struct eap_peer_config *config = eap_get_config(sm);
+
+ if (config->pending_ext_cert_check == EXT_CERT_CHECK_GOOD) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TLS: External certificate check succeeded - continue handshake");
+ resp = data->pending_resp;
+ data->pending_resp = NULL;
+ sm->waiting_ext_cert_check = 0;
+ return resp;
+ }
+
+ if (config->pending_ext_cert_check == EXT_CERT_CHECK_BAD) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TLS: External certificate check failed - force authentication failure");
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ sm->waiting_ext_cert_check = 0;
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-TLS: Continuing to wait external server certificate validation");
+ return NULL;
+ }
+
pos = eap_peer_tls_process_init(sm, &data->ssl, data->eap_type, ret,
reqData, &left, &flags);
if (pos == NULL)
@@ -237,6 +265,14 @@ static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv,
return eap_tls_failure(sm, data, ret, res, resp, id);
}
+ if (sm->waiting_ext_cert_check) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TLS: Waiting external server certificate validation");
+ wpabuf_free(data->pending_resp);
+ data->pending_resp = resp;
+ return NULL;
+ }
+
if (tls_connection_established(data->ssl_ctx, data->ssl.conn))
eap_tls_success(sm, data, ret);
@@ -258,6 +294,10 @@ static Boolean eap_tls_has_reauth_data(struct eap_sm *sm, void *priv)
static void eap_tls_deinit_for_reauth(struct eap_sm *sm, void *priv)
{
+ struct eap_tls_data *data = priv;
+
+ wpabuf_free(data->pending_resp);
+ data->pending_resp = NULL;
}
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index af2b7541..4b994fd3 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -80,6 +80,10 @@ static void eap_tls_params_flags(struct tls_connection_params *params,
params->flags |= TLS_CONN_DISABLE_TLSv1_2;
if (os_strstr(txt, "tls_disable_tlsv1_2=0"))
params->flags &= ~TLS_CONN_DISABLE_TLSv1_2;
+ if (os_strstr(txt, "tls_ext_cert_check=1"))
+ params->flags |= TLS_CONN_EXT_CERT_CHECK;
+ if (os_strstr(txt, "tls_ext_cert_check=0"))
+ params->flags &= ~TLS_CONN_EXT_CERT_CHECK;
}
@@ -177,6 +181,8 @@ static int eap_tls_params_from_conf(struct eap_sm *sm,
params->openssl_ciphers = config->openssl_ciphers;
+ sm->ext_cert_check = !!(params->flags & TLS_CONN_EXT_CERT_CHECK);
+
return 0;
}
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index b186c915..9741dede 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -1,6 +1,6 @@
/*
* EAP peer method: EAP-TTLS (RFC 5281)
- * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -58,6 +58,7 @@ struct eap_ttls_data {
size_t id_len;
struct wpabuf *pending_phase2_req;
+ struct wpabuf *pending_resp;
#ifdef EAP_TNC
int ready_for_tnc;
@@ -153,6 +154,7 @@ static void eap_ttls_deinit(struct eap_sm *sm, void *priv)
eap_ttls_free_key(data);
os_free(data->session_id);
wpabuf_free(data->pending_phase2_req);
+ wpabuf_free(data->pending_resp);
os_free(data);
}
@@ -1408,6 +1410,32 @@ static int eap_ttls_process_handshake(struct eap_sm *sm,
{
int res;
+ if (sm->waiting_ext_cert_check && data->pending_resp) {
+ struct eap_peer_config *config = eap_get_config(sm);
+
+ if (config->pending_ext_cert_check == EXT_CERT_CHECK_GOOD) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TTLS: External certificate check succeeded - continue handshake");
+ *out_data = data->pending_resp;
+ data->pending_resp = NULL;
+ sm->waiting_ext_cert_check = 0;
+ return 0;
+ }
+
+ if (config->pending_ext_cert_check == EXT_CERT_CHECK_BAD) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TTLS: External certificate check failed - force authentication failure");
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ sm->waiting_ext_cert_check = 0;
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "EAP-TTLS: Continuing to wait external server certificate validation");
+ return 0;
+ }
+
res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_TTLS,
data->ttls_version, identifier,
in_data, out_data);
@@ -1418,6 +1446,15 @@ static int eap_ttls_process_handshake(struct eap_sm *sm,
return -1;
}
+ if (sm->waiting_ext_cert_check) {
+ wpa_printf(MSG_DEBUG,
+ "EAP-TTLS: Waiting external server certificate validation");
+ wpabuf_free(data->pending_resp);
+ data->pending_resp = *out_data;
+ *out_data = NULL;
+ return 0;
+ }
+
if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS done, proceed to "
"Phase 2");
@@ -1557,6 +1594,8 @@ static void eap_ttls_deinit_for_reauth(struct eap_sm *sm, void *priv)
struct eap_ttls_data *data = priv;
wpabuf_free(data->pending_phase2_req);
data->pending_phase2_req = NULL;
+ wpabuf_free(data->pending_resp);
+ data->pending_resp = NULL;
#ifdef EAP_TNC
data->ready_for_tnc = 0;
data->tnc_started = 0;
diff --git a/src/eap_server/eap_server_fast.c b/src/eap_server/eap_server_fast.c
index 47210e14..e348eb3e 100644
--- a/src/eap_server/eap_server_fast.c
+++ b/src/eap_server/eap_server_fast.c
@@ -1564,7 +1564,10 @@ static u8 * eap_fast_getKey(struct eap_sm *sm, void *priv, size_t *len)
if (eapKeyData == NULL)
return NULL;
- eap_fast_derive_eap_msk(data->simck, eapKeyData);
+ if (eap_fast_derive_eap_msk(data->simck, eapKeyData) < 0) {
+ os_free(eapKeyData);
+ return NULL;
+ }
*len = EAP_FAST_KEY_LEN;
return eapKeyData;
@@ -1583,7 +1586,10 @@ static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
if (eapKeyData == NULL)
return NULL;
- eap_fast_derive_eap_emsk(data->simck, eapKeyData);
+ if (eap_fast_derive_eap_emsk(data->simck, eapKeyData) < 0) {
+ os_free(eapKeyData);
+ return NULL;
+ }
*len = EAP_EMSK_LEN;
return eapKeyData;
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 0b5fe51e..9bde3c81 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -364,13 +364,12 @@ int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
if (rsn_ie_buf == NULL)
return -1;
os_memcpy(rsn_ie_buf, wpa_ie, wpa_ie_len);
- res = wpa_insert_pmkid(rsn_ie_buf, wpa_ie_len,
+ res = wpa_insert_pmkid(rsn_ie_buf, &wpa_ie_len,
sm->pmk_r1_name);
if (res < 0) {
os_free(rsn_ie_buf);
return -1;
}
- wpa_ie_len += res;
if (sm->assoc_resp_ies) {
os_memcpy(rsn_ie_buf + wpa_ie_len, sm->assoc_resp_ies,
@@ -2291,6 +2290,9 @@ void wpa_sm_deinit(struct wpa_sm *sm)
#ifdef CONFIG_IEEE80211R
os_free(sm->assoc_resp_ies);
#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_TESTING_OPTIONS
+ wpabuf_free(sm->test_assoc_ie);
+#endif /* CONFIG_TESTING_OPTIONS */
os_free(sm);
}
@@ -2692,6 +2694,17 @@ int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, u8 *wpa_ie,
if (sm == NULL)
return -1;
+#ifdef CONFIG_TESTING_OPTIONS
+ if (sm->test_assoc_ie) {
+ wpa_printf(MSG_DEBUG,
+ "TESTING: Replace association WPA/RSN IE");
+ if (*wpa_ie_len < wpabuf_len(sm->test_assoc_ie))
+ return -1;
+ os_memcpy(wpa_ie, wpabuf_head(sm->test_assoc_ie),
+ wpabuf_len(sm->test_assoc_ie));
+ res = wpabuf_len(sm->test_assoc_ie);
+ } else
+#endif /* CONFIG_TESTING_OPTIONS */
res = wpa_gen_wpa_ie(sm, wpa_ie, *wpa_ie_len);
if (res < 0)
return -1;
@@ -3031,3 +3044,12 @@ void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm,
}
sm->ptk_set = 1;
}
+
+
+#ifdef CONFIG_TESTING_OPTIONS
+void wpa_sm_set_test_assoc_ie(struct wpa_sm *sm, struct wpabuf *buf)
+{
+ wpabuf_free(sm->test_assoc_ie);
+ sm->test_assoc_ie = buf;
+}
+#endif /* CONFIG_TESTING_OPTIONS */
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 1d274534..f9c89b36 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -419,5 +419,6 @@ int wpa_tdls_enable_chan_switch(struct wpa_sm *sm, const u8 *addr,
int wpa_tdls_disable_chan_switch(struct wpa_sm *sm, const u8 *addr);
int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf);
+void wpa_sm_set_test_assoc_ie(struct wpa_sm *sm, struct wpabuf *buf);
#endif /* WPA_H */
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index dba6b624..f653ba6e 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -134,6 +134,10 @@ struct wpa_sm {
#ifdef CONFIG_P2P
u8 p2p_ip_addr[3 * 4];
#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_TESTING_OPTIONS
+ struct wpabuf *test_assoc_ie;
+#endif /* CONFIG_TESTING_OPTIONS */
};
diff --git a/src/tls/Makefile b/src/tls/Makefile
index 27cdfcaa..52a890a1 100644
--- a/src/tls/Makefile
+++ b/src/tls/Makefile
@@ -24,6 +24,7 @@ LIB_OBJS= \
tlsv1_client.o \
tlsv1_client_read.o \
tlsv1_client_write.o \
+ tlsv1_client_ocsp.o \
tlsv1_common.o \
tlsv1_cred.o \
tlsv1_record.o \
diff --git a/src/tls/asn1.h b/src/tls/asn1.h
index 74750076..6bd7df56 100644
--- a/src/tls/asn1.h
+++ b/src/tls/asn1.h
@@ -20,6 +20,7 @@
#define ASN1_TAG_EXTERNAL 0x08 /* not yet parsed */
#define ASN1_TAG_REAL 0x09 /* not yet parsed */
#define ASN1_TAG_ENUMERATED 0x0A /* not yet parsed */
+#define ASN1_TAG_EMBEDDED_PDV 0x0B /* not yet parsed */
#define ASN1_TAG_UTF8STRING 0x0C /* not yet parsed */
#define ANS1_TAG_RELATIVE_OID 0x0D
#define ASN1_TAG_SEQUENCE 0x10 /* shall be constructed */
@@ -35,7 +36,8 @@
#define ASN1_TAG_VISIBLESTRING 0x1A
#define ASN1_TAG_GENERALSTRING 0x1B /* not yet parsed */
#define ASN1_TAG_UNIVERSALSTRING 0x1C /* not yet parsed */
-#define ASN1_TAG_BMPSTRING 0x1D /* not yet parsed */
+#define ASN1_TAG_CHARACTERSTRING 0x1D /* not yet parsed */
+#define ASN1_TAG_BMPSTRING 0x1E /* not yet parsed */
#define ASN1_CLASS_UNIVERSAL 0
#define ASN1_CLASS_APPLICATION 1
diff --git a/src/tls/pkcs5.c b/src/tls/pkcs5.c
index 8a934837..a2ad83b8 100644
--- a/src/tls/pkcs5.c
+++ b/src/tls/pkcs5.c
@@ -1,6 +1,6 @@
/*
* PKCS #5 (Password-based Encryption)
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -11,6 +11,7 @@
#include "common.h"
#include "crypto/crypto.h"
#include "crypto/md5.h"
+#include "crypto/sha1.h"
#include "asn1.h"
#include "pkcs5.h"
@@ -18,30 +19,261 @@
struct pkcs5_params {
enum pkcs5_alg {
PKCS5_ALG_UNKNOWN,
- PKCS5_ALG_MD5_DES_CBC
+ PKCS5_ALG_MD5_DES_CBC,
+ PKCS5_ALG_PBES2,
+ PKCS5_ALG_SHA1_3DES_CBC,
} alg;
- u8 salt[8];
+ u8 salt[64];
size_t salt_len;
unsigned int iter_count;
+ enum pbes2_enc_alg {
+ PBES2_ENC_ALG_UNKNOWN,
+ PBES2_ENC_ALG_DES_EDE3_CBC,
+ } enc_alg;
+ u8 iv[8];
+ size_t iv_len;
};
+static int oid_is_rsadsi(struct asn1_oid *oid)
+{
+ return oid->len >= 4 &&
+ oid->oid[0] == 1 /* iso */ &&
+ oid->oid[1] == 2 /* member-body */ &&
+ oid->oid[2] == 840 /* us */ &&
+ oid->oid[3] == 113549 /* rsadsi */;
+}
+
+
+static int pkcs5_is_oid(struct asn1_oid *oid, unsigned long alg)
+{
+ return oid->len == 7 &&
+ oid_is_rsadsi(oid) &&
+ oid->oid[4] == 1 /* pkcs */ &&
+ oid->oid[5] == 5 /* pkcs-5 */ &&
+ oid->oid[6] == alg;
+}
+
+
+static int enc_alg_is_oid(struct asn1_oid *oid, unsigned long alg)
+{
+ return oid->len == 6 &&
+ oid_is_rsadsi(oid) &&
+ oid->oid[4] == 3 /* encryptionAlgorithm */ &&
+ oid->oid[5] == alg;
+}
+
+
+static int pkcs12_is_pbe_oid(struct asn1_oid *oid, unsigned long alg)
+{
+ return oid->len == 8 &&
+ oid_is_rsadsi(oid) &&
+ oid->oid[4] == 1 /* pkcs */ &&
+ oid->oid[5] == 12 /* pkcs-12 */ &&
+ oid->oid[6] == 1 /* pkcs-12PbeIds */ &&
+ oid->oid[7] == alg;
+}
+
+
static enum pkcs5_alg pkcs5_get_alg(struct asn1_oid *oid)
{
- if (oid->len == 7 &&
- oid->oid[0] == 1 /* iso */ &&
- oid->oid[1] == 2 /* member-body */ &&
- oid->oid[2] == 840 /* us */ &&
- oid->oid[3] == 113549 /* rsadsi */ &&
- oid->oid[4] == 1 /* pkcs */ &&
- oid->oid[5] == 5 /* pkcs-5 */ &&
- oid->oid[6] == 3 /* pbeWithMD5AndDES-CBC */)
+ if (pkcs5_is_oid(oid, 3)) /* pbeWithMD5AndDES-CBC (PBES1) */
return PKCS5_ALG_MD5_DES_CBC;
-
+ if (pkcs12_is_pbe_oid(oid, 3)) /* pbeWithSHAAnd3-KeyTripleDES-CBC */
+ return PKCS5_ALG_SHA1_3DES_CBC;
+ if (pkcs5_is_oid(oid, 13)) /* id-PBES2 (PBES2) */
+ return PKCS5_ALG_PBES2;
return PKCS5_ALG_UNKNOWN;
}
+static int pkcs5_get_params_pbes2(struct pkcs5_params *params, const u8 *pos,
+ const u8 *enc_alg_end)
+{
+ struct asn1_hdr hdr;
+ const u8 *end, *kdf_end;
+ struct asn1_oid oid;
+ char obuf[80];
+
+ /*
+ * RFC 2898, Ch. A.4
+ *
+ * PBES2-params ::= SEQUENCE {
+ * keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
+ * encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} }
+ *
+ * PBES2-KDFs ALGORITHM-IDENTIFIER ::=
+ * { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ... }
+ */
+
+ if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #5: Expected SEQUENCE (PBES2-params) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ pos = hdr.payload;
+ end = hdr.payload + hdr.length;
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #5: Expected SEQUENCE (keyDerivationFunc) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ pos = hdr.payload;
+ kdf_end = end = hdr.payload + hdr.length;
+
+ if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #5: Failed to parse OID (keyDerivationFunc algorithm)");
+ return -1;
+ }
+
+ asn1_oid_to_str(&oid, obuf, sizeof(obuf));
+ wpa_printf(MSG_DEBUG, "PKCS #5: PBES2 keyDerivationFunc algorithm %s",
+ obuf);
+ if (!pkcs5_is_oid(&oid, 12)) /* id-PBKDF2 */ {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #5: Unsupported PBES2 keyDerivationFunc algorithm %s",
+ obuf);
+ return -1;
+ }
+
+ /*
+ * RFC 2898, C.
+ *
+ * PBKDF2-params ::= SEQUENCE {
+ * salt CHOICE {
+ * specified OCTET STRING,
+ * otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}}
+ * },
+ * iterationCount INTEGER (1..MAX),
+ * keyLength INTEGER (1..MAX) OPTIONAL,
+ * prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT
+ * algid-hmacWithSHA1
+ * }
+ */
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #5: Expected SEQUENCE (PBKDF2-params) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ pos = hdr.payload;
+ end = hdr.payload + hdr.length;
+
+ /* For now, only support the salt CHOICE specified (OCTET STRING) */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_OCTETSTRING ||
+ hdr.length > sizeof(params->salt)) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #5: Expected OCTET STRING (salt.specified) - found class %d tag 0x%x size %d",
+ hdr.class, hdr.tag, hdr.length);
+ return -1;
+ }
+ pos = hdr.payload + hdr.length;
+ os_memcpy(params->salt, hdr.payload, hdr.length);
+ params->salt_len = hdr.length;
+ wpa_hexdump(MSG_DEBUG, "PKCS #5: salt", params->salt, params->salt_len);
+
+ /* iterationCount INTEGER */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #5: Expected INTEGER - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ if (hdr.length == 1) {
+ params->iter_count = *hdr.payload;
+ } else if (hdr.length == 2) {
+ params->iter_count = WPA_GET_BE16(hdr.payload);
+ } else if (hdr.length == 4) {
+ params->iter_count = WPA_GET_BE32(hdr.payload);
+ } else {
+ wpa_hexdump(MSG_DEBUG,
+ "PKCS #5: Unsupported INTEGER value (iterationCount)",
+ hdr.payload, hdr.length);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "PKCS #5: iterationCount=0x%x",
+ params->iter_count);
+ if (params->iter_count == 0 || params->iter_count > 0xffff) {
+ wpa_printf(MSG_INFO, "PKCS #5: Unsupported iterationCount=0x%x",
+ params->iter_count);
+ return -1;
+ }
+
+ /* For now, ignore optional keyLength and prf */
+
+ pos = kdf_end;
+
+ /* encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} */
+
+ if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #5: Expected SEQUENCE (encryptionScheme) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ pos = hdr.payload;
+ end = hdr.payload + hdr.length;
+
+ if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #5: Failed to parse OID (encryptionScheme algorithm)");
+ return -1;
+ }
+
+ asn1_oid_to_str(&oid, obuf, sizeof(obuf));
+ wpa_printf(MSG_DEBUG, "PKCS #5: PBES2 encryptionScheme algorithm %s",
+ obuf);
+ if (enc_alg_is_oid(&oid, 7)) {
+ params->enc_alg = PBES2_ENC_ALG_DES_EDE3_CBC;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #5: Unsupported PBES2 encryptionScheme algorithm %s",
+ obuf);
+ return -1;
+ }
+
+ /*
+ * RFC 2898, B.2.2:
+ * The parameters field associated with this OID in an
+ * AlgorithmIdentifier shall have type OCTET STRING (SIZE(8)),
+ * specifying the initialization vector for CBC mode.
+ */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_OCTETSTRING ||
+ hdr.length != 8) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #5: Expected OCTET STRING (SIZE(8)) (IV) - found class %d tag 0x%x size %d",
+ hdr.class, hdr.tag, hdr.length);
+ return -1;
+ }
+ os_memcpy(params->iv, hdr.payload, hdr.length);
+ params->iv_len = hdr.length;
+ wpa_hexdump(MSG_DEBUG, "PKCS #5: IV", params->iv, params->iv_len);
+
+ return 0;
+}
+
+
static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len,
struct pkcs5_params *params)
{
@@ -71,11 +303,23 @@ static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len,
return -1;
}
+ if (params->alg == PKCS5_ALG_PBES2)
+ return pkcs5_get_params_pbes2(params, pos, enc_alg_end);
+
+ /* PBES1 */
+
/*
* PKCS#5, Section 8
* PBEParameter ::= SEQUENCE {
* salt OCTET STRING SIZE(8),
* iterationCount INTEGER }
+ *
+ * Note: The same implementation can be used to parse the PKCS #12
+ * version described in RFC 7292, C:
+ * pkcs-12PbeParams ::= SEQUENCE {
+ * salt OCTET STRING,
+ * iterations INTEGER
+ * }
*/
if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 ||
@@ -89,11 +333,11 @@ static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len,
pos = hdr.payload;
end = hdr.payload + hdr.length;
- /* salt OCTET STRING SIZE(8) */
+ /* salt OCTET STRING SIZE(8) (PKCS #5) or OCTET STRING (PKCS #12) */
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
hdr.class != ASN1_CLASS_UNIVERSAL ||
hdr.tag != ASN1_TAG_OCTETSTRING ||
- hdr.length != 8) {
+ hdr.length > sizeof(params->salt)) {
wpa_printf(MSG_DEBUG, "PKCS #5: Expected OCTETSTRING SIZE(8) "
"(salt) - found class %d tag 0x%x size %d",
hdr.class, hdr.tag, hdr.length);
@@ -136,6 +380,174 @@ static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len,
}
+static struct crypto_cipher *
+pkcs5_crypto_init_pbes2(struct pkcs5_params *params, const char *passwd)
+{
+ u8 key[24];
+
+ if (params->enc_alg != PBES2_ENC_ALG_DES_EDE3_CBC ||
+ params->iv_len != 8)
+ return NULL;
+
+ wpa_hexdump_ascii_key(MSG_DEBUG, "PKCS #5: PBES2 password for PBKDF2",
+ passwd, os_strlen(passwd));
+ wpa_hexdump(MSG_DEBUG, "PKCS #5: PBES2 salt for PBKDF2",
+ params->salt, params->salt_len);
+ wpa_printf(MSG_DEBUG, "PKCS #5: PBES2 PBKDF2 iterations: %u",
+ params->iter_count);
+ if (pbkdf2_sha1(passwd, params->salt, params->salt_len,
+ params->iter_count, key, sizeof(key)) < 0)
+ return NULL;
+ wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES EDE3 key", key, sizeof(key));
+ wpa_hexdump(MSG_DEBUG, "PKCS #5: DES IV", params->iv, params->iv_len);
+
+ return crypto_cipher_init(CRYPTO_CIPHER_ALG_3DES, params->iv,
+ key, sizeof(key));
+}
+
+
+static void add_byte_array_mod(u8 *a, const u8 *b, size_t len)
+{
+ size_t i;
+ unsigned int carry = 0;
+
+ for (i = len - 1; i < len; i--) {
+ carry = carry + a[i] + b[i];
+ a[i] = carry & 0xff;
+ carry >>= 8;
+ }
+}
+
+
+static int pkcs12_key_gen(const u8 *pw, size_t pw_len, const u8 *salt,
+ size_t salt_len, u8 id, unsigned int iter,
+ size_t out_len, u8 *out)
+{
+ unsigned int u, v, S_len, P_len, i;
+ u8 *D = NULL, *I = NULL, *B = NULL, *pos;
+ int res = -1;
+
+ /* RFC 7292, B.2 */
+ u = SHA1_MAC_LEN;
+ v = 64;
+
+ /* D = copies of ID */
+ D = os_malloc(v);
+ if (!D)
+ goto done;
+ os_memset(D, id, v);
+
+ /* S = copies of salt; P = copies of password, I = S || P */
+ S_len = v * ((salt_len + v - 1) / v);
+ P_len = v * ((pw_len + v - 1) / v);
+ I = os_malloc(S_len + P_len);
+ if (!I)
+ goto done;
+ pos = I;
+ if (salt_len) {
+ for (i = 0; i < S_len; i++)
+ *pos++ = salt[i % salt_len];
+ }
+ if (pw_len) {
+ for (i = 0; i < P_len; i++)
+ *pos++ = pw[i % pw_len];
+ }
+
+ B = os_malloc(v);
+ if (!B)
+ goto done;
+
+ for (;;) {
+ u8 hash[SHA1_MAC_LEN];
+ const u8 *addr[2];
+ size_t len[2];
+
+ addr[0] = D;
+ len[0] = v;
+ addr[1] = I;
+ len[1] = S_len + P_len;
+ if (sha1_vector(2, addr, len, hash) < 0)
+ goto done;
+
+ addr[0] = hash;
+ len[0] = SHA1_MAC_LEN;
+ for (i = 1; i < iter; i++) {
+ if (sha1_vector(1, addr, len, hash) < 0)
+ goto done;
+ }
+
+ if (out_len <= u) {
+ os_memcpy(out, hash, out_len);
+ res = 0;
+ goto done;
+ }
+
+ os_memcpy(out, hash, u);
+ out += u;
+ out_len -= u;
+
+ /* I_j = (I_j + B + 1) mod 2^(v*8) */
+ /* B = copies of Ai (final hash value) */
+ for (i = 0; i < v; i++)
+ B[i] = hash[i % u];
+ inc_byte_array(B, v);
+ for (i = 0; i < S_len + P_len; i += v)
+ add_byte_array_mod(&I[i], B, v);
+ }
+
+done:
+ os_free(B);
+ os_free(I);
+ os_free(D);
+ return res;
+}
+
+
+#define PKCS12_ID_ENC 1
+#define PKCS12_ID_IV 2
+#define PKCS12_ID_MAC 3
+
+static struct crypto_cipher *
+pkcs12_crypto_init_sha1(struct pkcs5_params *params, const char *passwd)
+{
+ unsigned int i;
+ u8 *pw;
+ size_t pw_len;
+ u8 key[24];
+ u8 iv[8];
+
+ if (params->alg != PKCS5_ALG_SHA1_3DES_CBC)
+ return NULL;
+
+ pw_len = passwd ? os_strlen(passwd) : 0;
+ pw = os_malloc(2 * (pw_len + 1));
+ if (!pw)
+ return NULL;
+ if (pw_len) {
+ for (i = 0; i <= pw_len; i++)
+ WPA_PUT_BE16(&pw[2 * i], passwd[i]);
+ pw_len = 2 * (pw_len + 1);
+ }
+
+ if (pkcs12_key_gen(pw, pw_len, params->salt, params->salt_len,
+ PKCS12_ID_ENC, params->iter_count,
+ sizeof(key), key) < 0 ||
+ pkcs12_key_gen(pw, pw_len, params->salt, params->salt_len,
+ PKCS12_ID_IV, params->iter_count,
+ sizeof(iv), iv) < 0) {
+ os_free(pw);
+ return NULL;
+ }
+
+ os_free(pw);
+
+ wpa_hexdump_key(MSG_DEBUG, "PKCS #12: DES key", key, sizeof(key));
+ wpa_hexdump_key(MSG_DEBUG, "PKCS #12: DES IV", iv, sizeof(iv));
+
+ return crypto_cipher_init(CRYPTO_CIPHER_ALG_3DES, iv, key, sizeof(key));
+}
+
+
static struct crypto_cipher * pkcs5_crypto_init(struct pkcs5_params *params,
const char *passwd)
{
@@ -144,6 +556,12 @@ static struct crypto_cipher * pkcs5_crypto_init(struct pkcs5_params *params,
const u8 *addr[2];
size_t len[2];
+ if (params->alg == PKCS5_ALG_PBES2)
+ return pkcs5_crypto_init_pbes2(params, passwd);
+
+ if (params->alg == PKCS5_ALG_SHA1_3DES_CBC)
+ return pkcs12_crypto_init_sha1(params, passwd);
+
if (params->alg != PKCS5_ALG_MD5_DES_CBC)
return NULL;
diff --git a/src/tls/tlsv1_client.c b/src/tls/tlsv1_client.c
index 846d2932..cc404c15 100644
--- a/src/tls/tlsv1_client.c
+++ b/src/tls/tlsv1_client.c
@@ -1,6 +1,6 @@
/*
* TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246)
- * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -11,6 +11,7 @@
#include "common.h"
#include "crypto/sha1.h"
#include "crypto/tls.h"
+#include "x509v3.h"
#include "tlsv1_common.h"
#include "tlsv1_record.h"
#include "tlsv1_client.h"
@@ -494,6 +495,7 @@ void tlsv1_client_deinit(struct tlsv1_client *conn)
tlsv1_client_free_dh(conn);
tlsv1_cred_free(conn->cred);
wpabuf_free(conn->partial_input);
+ x509_certificate_chain_free(conn->server_cert);
os_free(conn);
}
diff --git a/src/tls/tlsv1_client_i.h b/src/tls/tlsv1_client_i.h
index 6c4dbc71..12ec8df6 100644
--- a/src/tls/tlsv1_client_i.h
+++ b/src/tls/tlsv1_client_i.h
@@ -36,6 +36,7 @@ struct tlsv1_client {
unsigned int session_ticket_included:1;
unsigned int use_session_ticket:1;
unsigned int cert_in_cb:1;
+ unsigned int ocsp_resp_received:1;
struct crypto_public_key *server_rsa_key;
@@ -70,6 +71,8 @@ struct tlsv1_client {
void (*event_cb)(void *ctx, enum tls_event ev,
union tls_event_data *data);
void *cb_ctx;
+
+ struct x509_certificate *server_cert;
};
@@ -87,4 +90,11 @@ int tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct,
const u8 *buf, size_t *len,
u8 **out_data, size_t *out_len);
+enum tls_ocsp_result {
+ TLS_OCSP_NO_RESPONSE, TLS_OCSP_INVALID, TLS_OCSP_GOOD, TLS_OCSP_REVOKED
+};
+
+enum tls_ocsp_result tls_process_ocsp_response(struct tlsv1_client *conn,
+ const u8 *resp, size_t len);
+
#endif /* TLSV1_CLIENT_I_H */
diff --git a/src/tls/tlsv1_client_ocsp.c b/src/tls/tlsv1_client_ocsp.c
new file mode 100644
index 00000000..bcc7a860
--- /dev/null
+++ b/src/tls/tlsv1_client_ocsp.c
@@ -0,0 +1,169 @@
+/*
+ * TLSv1 client - OCSP
+ * Copyright (c) 2015, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/tls.h"
+#include "asn1.h"
+#include "tlsv1_common.h"
+#include "tlsv1_record.h"
+#include "tlsv1_client.h"
+#include "tlsv1_client_i.h"
+
+
+/* RFC 6960, 4.2.1: OCSPResponseStatus ::= ENUMERATED */
+enum ocsp_response_status {
+ OCSP_RESP_STATUS_SUCCESSFUL = 0,
+ OCSP_RESP_STATUS_MALFORMED_REQ = 1,
+ OCSP_RESP_STATUS_INT_ERROR = 2,
+ OCSP_RESP_STATUS_TRY_LATER = 3,
+ /* 4 not used */
+ OCSP_RESP_STATUS_SIG_REQUIRED = 5,
+ OCSP_RESP_STATUS_UNAUTHORIZED = 6,
+};
+
+
+static int is_oid_basic_ocsp_resp(struct asn1_oid *oid)
+{
+ return oid->len == 10 &&
+ 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 */ &&
+ oid->oid[7] == 48 /* id-ad */ &&
+ oid->oid[8] == 1 /* id-pkix-ocsp */ &&
+ oid->oid[9] == 1 /* id-pkix-ocsp-basic */;
+}
+
+
+static enum tls_ocsp_result
+tls_process_basic_ocsp_response(struct tlsv1_client *conn, const u8 *resp,
+ size_t len)
+{
+ wpa_hexdump(MSG_MSGDUMP, "OCSP: BasicOCSPResponse", resp, len);
+
+ /*
+ * RFC 6960, 4.2.1:
+ * BasicOCSPResponse ::= SEQUENCE {
+ * tbsResponseData ResponseData,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING,
+ * certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+ */
+
+ /* TODO */
+ return TLS_OCSP_NO_RESPONSE;
+}
+
+
+enum tls_ocsp_result tls_process_ocsp_response(struct tlsv1_client *conn,
+ const u8 *resp, size_t len)
+{
+ struct asn1_hdr hdr;
+ const u8 *pos, *end;
+ u8 resp_status;
+ struct asn1_oid oid;
+ char obuf[80];
+
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: OCSPResponse", resp, len);
+
+ /*
+ * RFC 6960, 4.2.1:
+ * OCSPResponse ::= SEQUENCE {
+ * responseStatus OCSPResponseStatus,
+ * responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
+ */
+
+ if (asn1_get_next(resp, len, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Expected SEQUENCE (OCSPResponse) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return TLS_OCSP_INVALID;
+ }
+ pos = hdr.payload;
+ end = hdr.payload + hdr.length;
+
+ /* OCSPResponseStatus ::= ENUMERATED */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_ENUMERATED ||
+ hdr.length != 1) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Expected ENUMERATED (responseStatus) - found class %d tag 0x%x length %u",
+ hdr.class, hdr.tag, hdr.length);
+ return TLS_OCSP_INVALID;
+ }
+ resp_status = hdr.payload[0];
+ wpa_printf(MSG_DEBUG, "OCSP: responseStatus %u", resp_status);
+ pos = hdr.payload + hdr.length;
+ if (resp_status != OCSP_RESP_STATUS_SUCCESSFUL) {
+ wpa_printf(MSG_DEBUG, "OCSP: No stapling result");
+ return TLS_OCSP_NO_RESPONSE;
+ }
+
+ /* responseBytes [0] EXPLICIT ResponseBytes OPTIONAL */
+ if (pos == end)
+ return TLS_OCSP_NO_RESPONSE;
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC ||
+ hdr.tag != 0) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Expected [0] EXPLICIT (responseBytes) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return TLS_OCSP_INVALID;
+ }
+
+ /*
+ * ResponseBytes ::= SEQUENCE {
+ * responseType OBJECT IDENTIFIER,
+ * response OCTET STRING }
+ */
+
+ if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Expected SEQUENCE (ResponseBytes) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return TLS_OCSP_INVALID;
+ }
+ pos = hdr.payload;
+ end = hdr.payload + hdr.length;
+
+ /* responseType OBJECT IDENTIFIER */
+ if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Failed to parse OID (responseType)");
+ return TLS_OCSP_INVALID;
+ }
+ asn1_oid_to_str(&oid, obuf, sizeof(obuf));
+ wpa_printf(MSG_DEBUG, "OCSP: responseType %s", obuf);
+ if (!is_oid_basic_ocsp_resp(&oid)) {
+ wpa_printf(MSG_DEBUG, "OCSP: Ignore unsupported response type");
+ return TLS_OCSP_NO_RESPONSE;
+ }
+
+ /* response OCTET STRING */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_OCTETSTRING) {
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Expected OCTET STRING (response) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return TLS_OCSP_INVALID;
+ }
+
+ return tls_process_basic_ocsp_response(conn, hdr.payload, hdr.length);
+}
diff --git a/src/tls/tlsv1_client_read.c b/src/tls/tlsv1_client_read.c
index 40c6a46f..b1fa15f4 100644
--- a/src/tls/tlsv1_client_read.c
+++ b/src/tls/tlsv1_client_read.c
@@ -1,6 +1,6 @@
/*
* TLSv1 client - read handshake message
- * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -38,6 +38,43 @@ static int tls_version_disabled(struct tlsv1_client *conn, u16 ver)
}
+static int tls_process_server_hello_extensions(struct tlsv1_client *conn,
+ const u8 *pos, size_t len)
+{
+ const u8 *end = pos + len;
+
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: ServerHello extensions",
+ pos, len);
+ while (pos < end) {
+ u16 ext, elen;
+
+ if (end - pos < 4) {
+ wpa_printf(MSG_INFO, "TLSv1: Truncated ServerHello extension header");
+ return -1;
+ }
+
+ ext = WPA_GET_BE16(pos);
+ pos += 2;
+ elen = WPA_GET_BE16(pos);
+ pos += 2;
+
+ if (elen > end - pos) {
+ wpa_printf(MSG_INFO, "TLSv1: Truncated ServerHello extension");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "TLSv1: ServerHello ExtensionType %u",
+ ext);
+ wpa_hexdump(MSG_DEBUG, "TLSv1: ServerHello extension data",
+ pos, elen);
+
+ pos += elen;
+ }
+
+ return 0;
+}
+
+
static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,
const u8 *in_data, size_t *in_len)
{
@@ -177,8 +214,24 @@ static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,
}
pos++;
+ if (end - pos >= 2) {
+ u16 ext_len;
+
+ ext_len = WPA_GET_BE16(pos);
+ pos += 2;
+ if (end - pos < ext_len) {
+ wpa_printf(MSG_INFO,
+ "TLSv1: Invalid ServerHello extension length: %u (left: %u)",
+ ext_len, (unsigned int) (end - pos));
+ goto decode_error;
+ }
+
+ if (tls_process_server_hello_extensions(conn, pos, ext_len))
+ goto decode_error;
+ pos += ext_len;
+ }
+
if (end != pos) {
- /* TODO: ServerHello extensions */
wpa_hexdump(MSG_DEBUG, "TLSv1: Unexpected extra data in the "
"end of ServerHello", pos, end - pos);
goto decode_error;
@@ -561,7 +614,12 @@ static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
return -1;
}
- x509_certificate_chain_free(chain);
+ if (conn->flags & TLS_CONN_REQUEST_OCSP) {
+ x509_certificate_chain_free(conn->server_cert);
+ conn->server_cert = chain;
+ } else {
+ x509_certificate_chain_free(chain);
+ }
*in_len = end - in_data;
@@ -732,6 +790,134 @@ fail:
}
+static int tls_process_certificate_status(struct tlsv1_client *conn, u8 ct,
+ const u8 *in_data, size_t *in_len)
+{
+ const u8 *pos, *end;
+ size_t left, len;
+ u8 type, status_type;
+ u32 ocsp_resp_len;
+ enum tls_ocsp_result res;
+
+ if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Expected Handshake; received content type 0x%x",
+ ct);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ pos = in_data;
+ left = *in_len;
+
+ if (left < 4) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Too short CertificateStatus (left=%lu)",
+ (unsigned long) left);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ type = *pos++;
+ len = WPA_GET_BE24(pos);
+ pos += 3;
+ left -= 4;
+
+ if (len > left) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Mismatch in CertificateStatus length (len=%lu != left=%lu)",
+ (unsigned long) len, (unsigned long) left);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ end = pos + len;
+
+ if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_STATUS) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Received unexpected handshake message %d (expected CertificateStatus)",
+ type);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateStatus");
+
+ /*
+ * struct {
+ * CertificateStatusType status_type;
+ * select (status_type) {
+ * case ocsp: OCSPResponse;
+ * } response;
+ * } CertificateStatus;
+ */
+ if (end - pos < 1) {
+ wpa_printf(MSG_INFO, "TLSv1: Too short CertificateStatus");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+ status_type = *pos++;
+ wpa_printf(MSG_DEBUG, "TLSv1: CertificateStatus status_type %u",
+ status_type);
+
+ if (status_type != 1 /* ocsp */) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Ignore unsupported CertificateStatus");
+ goto skip;
+ }
+
+ /* opaque OCSPResponse<1..2^24-1>; */
+ if (end - pos < 3) {
+ wpa_printf(MSG_INFO, "TLSv1: Too short OCSPResponse");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+ ocsp_resp_len = WPA_GET_BE24(pos);
+ pos += 3;
+ if (end - pos < ocsp_resp_len) {
+ wpa_printf(MSG_INFO, "TLSv1: Truncated OCSPResponse");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ res = tls_process_ocsp_response(conn, pos, ocsp_resp_len);
+ switch (res) {
+ case TLS_OCSP_NO_RESPONSE:
+ if (!(conn->flags & TLS_CONN_REQUIRE_OCSP))
+ goto skip;
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE);
+ return -1;
+ case TLS_OCSP_INVALID:
+ if (!(conn->flags & TLS_CONN_REQUIRE_OCSP))
+ goto skip; /* ignore - process as if no response */
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ case TLS_OCSP_GOOD:
+ wpa_printf(MSG_DEBUG, "TLSv1: OCSP response good");
+ break;
+ case TLS_OCSP_REVOKED:
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_CERTIFICATE_REVOKED);
+ if (conn->server_cert)
+ tls_cert_chain_failure_event(
+ conn, 0, conn->server_cert, TLS_FAIL_REVOKED,
+ "certificate revoked");
+ return -1;
+ }
+ conn->ocsp_resp_received = 1;
+
+skip:
+ *in_len = end - in_data;
+
+ conn->state = SERVER_KEY_EXCHANGE;
+
+ return 0;
+}
+
+
static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
const u8 *in_data, size_t *in_len)
{
@@ -773,6 +959,10 @@ static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
end = pos + len;
+ if ((conn->flags & TLS_CONN_REQUEST_OCSP) &&
+ type == TLS_HANDSHAKE_TYPE_CERTIFICATE_STATUS)
+ return tls_process_certificate_status(conn, ct, in_data,
+ in_len);
if (type == TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST)
return tls_process_certificate_request(conn, ct, in_data,
in_len);
@@ -782,7 +972,9 @@ static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
if (type != TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE) {
wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
"message %d (expected ServerKeyExchange/"
- "CertificateRequest/ServerHelloDone)", type);
+ "CertificateRequest/ServerHelloDone%s)", type,
+ (conn->flags & TLS_CONN_REQUEST_OCSP) ?
+ "/CertificateStatus" : "");
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
TLS_ALERT_UNEXPECTED_MESSAGE);
return -1;
@@ -936,6 +1128,15 @@ static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct,
wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHelloDone");
+ if ((conn->flags & TLS_CONN_REQUIRE_OCSP) &&
+ !conn->ocsp_resp_received) {
+ wpa_printf(MSG_INFO,
+ "TLSv1: No OCSP response received - reject handshake");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE);
+ return -1;
+ }
+
*in_len = end - in_data;
conn->state = CLIENT_KEY_EXCHANGE;
diff --git a/src/tls/tlsv1_client_write.c b/src/tls/tlsv1_client_write.c
index b1906b21..8e8cb5e4 100644
--- a/src/tls/tlsv1_client_write.c
+++ b/src/tls/tlsv1_client_write.c
@@ -1,6 +1,6 @@
/*
* TLSv1 client - write handshake message
- * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -156,6 +156,44 @@ u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
pos += conn->client_hello_ext_len;
}
+ if (conn->flags & TLS_CONN_REQUEST_OCSP) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Add status_request extension for OCSP stapling");
+ /* ExtensionsType extension_type = status_request(5) */
+ WPA_PUT_BE16(pos, TLS_EXT_STATUS_REQUEST);
+ pos += 2;
+ /* opaque extension_data<0..2^16-1> length */
+ WPA_PUT_BE16(pos, 5);
+ pos += 2;
+
+ /*
+ * RFC 6066, 8:
+ * struct {
+ * CertificateStatusType status_type;
+ * select (status_type) {
+ * case ocsp: OCSPStatusRequest;
+ * } request;
+ * } CertificateStatusRequest;
+ *
+ * enum { ocsp(1), (255) } CertificateStatusType;
+ */
+ *pos++ = 1; /* status_type = ocsp(1) */
+
+ /*
+ * struct {
+ * ResponderID responder_id_list<0..2^16-1>;
+ * Extensions request_extensions;
+ * } OCSPStatusRequest;
+ *
+ * opaque ResponderID<1..2^16-1>;
+ * opaque Extensions<0..2^16-1>;
+ */
+ WPA_PUT_BE16(pos, 0); /* responder_id_list(empty) */
+ pos += 2;
+ WPA_PUT_BE16(pos, 0); /* request_extensions(empty) */
+ pos += 2;
+ }
+
if (pos == ext_start + 2)
pos -= 2; /* no extensions */
else
diff --git a/src/tls/tlsv1_cred.c b/src/tls/tlsv1_cred.c
index 067562b6..92f97c7f 100644
--- a/src/tls/tlsv1_cred.c
+++ b/src/tls/tlsv1_cred.c
@@ -1,6 +1,6 @@
/*
* TLSv1 credentials
- * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -11,6 +11,9 @@
#include "common.h"
#include "base64.h"
#include "crypto/crypto.h"
+#include "crypto/sha1.h"
+#include "pkcs5.h"
+#include "pkcs8.h"
#include "x509v3.h"
#include "tlsv1_cred.h"
@@ -325,6 +328,735 @@ static struct crypto_private_key * tlsv1_set_key_enc_pem(const u8 *key,
}
+#ifdef PKCS12_FUNCS
+
+static int oid_is_rsadsi(struct asn1_oid *oid)
+{
+ return oid->len >= 4 &&
+ oid->oid[0] == 1 /* iso */ &&
+ oid->oid[1] == 2 /* member-body */ &&
+ oid->oid[2] == 840 /* us */ &&
+ oid->oid[3] == 113549 /* rsadsi */;
+}
+
+
+static int pkcs12_is_bagtype_oid(struct asn1_oid *oid, unsigned long type)
+{
+ return oid->len == 9 &&
+ oid_is_rsadsi(oid) &&
+ oid->oid[4] == 1 /* pkcs */ &&
+ oid->oid[5] == 12 /* pkcs-12 */ &&
+ oid->oid[6] == 10 &&
+ oid->oid[7] == 1 /* bagtypes */ &&
+ oid->oid[8] == type;
+}
+
+
+static int is_oid_pkcs7(struct asn1_oid *oid)
+{
+ return oid->len == 7 &&
+ oid->oid[0] == 1 /* iso */ &&
+ oid->oid[1] == 2 /* member-body */ &&
+ oid->oid[2] == 840 /* us */ &&
+ oid->oid[3] == 113549 /* rsadsi */ &&
+ oid->oid[4] == 1 /* pkcs */ &&
+ oid->oid[5] == 7 /* pkcs-7 */;
+}
+
+
+static int is_oid_pkcs7_data(struct asn1_oid *oid)
+{
+ return is_oid_pkcs7(oid) && oid->oid[6] == 1 /* data */;
+}
+
+
+static int is_oid_pkcs7_enc_data(struct asn1_oid *oid)
+{
+ return is_oid_pkcs7(oid) && oid->oid[6] == 6 /* encryptedData */;
+}
+
+
+static int is_oid_pkcs9(struct asn1_oid *oid)
+{
+ return oid->len >= 6 &&
+ oid->oid[0] == 1 /* iso */ &&
+ oid->oid[1] == 2 /* member-body */ &&
+ oid->oid[2] == 840 /* us */ &&
+ oid->oid[3] == 113549 /* rsadsi */ &&
+ oid->oid[4] == 1 /* pkcs */ &&
+ oid->oid[5] == 9 /* pkcs-9 */;
+}
+
+
+static int is_oid_pkcs9_friendly_name(struct asn1_oid *oid)
+{
+ return oid->len == 7 && is_oid_pkcs9(oid) &&
+ oid->oid[6] == 20;
+}
+
+
+static int is_oid_pkcs9_local_key_id(struct asn1_oid *oid)
+{
+ return oid->len == 7 && is_oid_pkcs9(oid) &&
+ oid->oid[6] == 21;
+}
+
+
+static int is_oid_pkcs9_x509_cert(struct asn1_oid *oid)
+{
+ return oid->len == 8 && is_oid_pkcs9(oid) &&
+ oid->oid[6] == 22 /* certTypes */ &&
+ oid->oid[7] == 1 /* x509Certificate */;
+}
+
+
+static int pkcs12_keybag(struct tlsv1_credentials *cred,
+ const u8 *buf, size_t len)
+{
+ /* TODO */
+ return 0;
+}
+
+
+static int pkcs12_pkcs8_keybag(struct tlsv1_credentials *cred,
+ const u8 *buf, size_t len,
+ const char *passwd)
+{
+ struct crypto_private_key *key;
+
+ /* PKCS8ShroudedKeyBag ::= EncryptedPrivateKeyInfo */
+ key = pkcs8_enc_key_import(buf, len, passwd);
+ if (!key)
+ return -1;
+
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Successfully decrypted PKCS8ShroudedKeyBag");
+ crypto_private_key_free(cred->key);
+ cred->key = key;
+
+ return 0;
+}
+
+
+static int pkcs12_certbag(struct tlsv1_credentials *cred,
+ const u8 *buf, size_t len)
+{
+ struct asn1_hdr hdr;
+ struct asn1_oid oid;
+ char obuf[80];
+ const u8 *pos, *end;
+
+ /*
+ * CertBag ::= SEQUENCE {
+ * certId BAG-TYPE.&id ({CertTypes}),
+ * certValue [0] EXPLICIT BAG-TYPE.&Type ({CertTypes}{@certId})
+ * }
+ */
+
+ if (asn1_get_next(buf, len, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected SEQUENCE (CertBag) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ pos = hdr.payload;
+ end = hdr.payload + hdr.length;
+
+ if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Failed to parse OID (certId)");
+ return -1;
+ }
+
+ asn1_oid_to_str(&oid, obuf, sizeof(obuf));
+ wpa_printf(MSG_DEBUG, "PKCS #12: certId %s", obuf);
+
+ if (!is_oid_pkcs9_x509_cert(&oid)) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Ignored unsupported certificate type (certId %s)",
+ obuf);
+ }
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC ||
+ hdr.tag != 0) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected [0] EXPLICIT (certValue) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_OCTETSTRING) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected OCTET STRING (x509Certificate) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "PKCS #12: x509Certificate",
+ hdr.payload, hdr.length);
+ if (cred->cert) {
+ struct x509_certificate *cert;
+
+ wpa_printf(MSG_DEBUG, "PKCS #12: Ignore extra certificate");
+ cert = x509_certificate_parse(hdr.payload, hdr.length);
+ if (!cert) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Failed to parse x509Certificate");
+ return 0;
+ }
+ x509_certificate_chain_free(cert);
+
+ return 0;
+ }
+ return tlsv1_set_cert(cred, NULL, hdr.payload, hdr.length);
+}
+
+
+static int pkcs12_parse_attr_friendly_name(const u8 *pos, const u8 *end)
+{
+ struct asn1_hdr hdr;
+
+ /*
+ * RFC 2985, 5.5.1:
+ * friendlyName ATTRIBUTE ::= {
+ * WITH SYNTAX BMPString (SIZE(1..pkcs-9-ub-friendlyName))
+ * EQUALITY MATCHING RULE caseIgnoreMatch
+ * SINGLE VALUE TRUE
+ * ID pkcs-9-at-friendlyName
+ * }
+ */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_BMPSTRING) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected BMPSTRING (friendlyName) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return 0;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG, "PKCS #12: friendlyName",
+ hdr.payload, hdr.length);
+ return 0;
+}
+
+
+static int pkcs12_parse_attr_local_key_id(const u8 *pos, const u8 *end)
+{
+ struct asn1_hdr hdr;
+
+ /*
+ * RFC 2985, 5.5.2:
+ * localKeyId ATTRIBUTE ::= {
+ * WITH SYNTAX OCTET STRING
+ * EQUALITY MATCHING RULE octetStringMatch
+ * SINGLE VALUE TRUE
+ * ID pkcs-9-at-localKeyId
+ * }
+ */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_OCTETSTRING) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected OCTET STRING (localKeyID) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "PKCS #12: localKeyID",
+ hdr.payload, hdr.length);
+ return 0;
+}
+
+
+static int pkcs12_parse_attr(const u8 *pos, size_t len)
+{
+ const u8 *end = pos + len;
+ struct asn1_hdr hdr;
+ struct asn1_oid a_oid;
+ char obuf[80];
+
+ /*
+ * PKCS12Attribute ::= SEQUENCE {
+ * attrId ATTRIBUTE.&id ({PKCS12AttrSet}),
+ * attrValues SET OF ATTRIBUTE.&Type ({PKCS12AttrSet}{@attrId})
+ * }
+ */
+
+ if (asn1_get_oid(pos, end - pos, &a_oid, &pos)) {
+ wpa_printf(MSG_DEBUG, "PKCS #12: Failed to parse OID (attrId)");
+ return -1;
+ }
+
+ asn1_oid_to_str(&a_oid, obuf, sizeof(obuf));
+ wpa_printf(MSG_DEBUG, "PKCS #12: attrId %s", obuf);
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SET) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected SET (attrValues) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: attrValues",
+ hdr.payload, hdr.length);
+ pos = hdr.payload;
+ end = hdr.payload + hdr.length;
+
+ if (is_oid_pkcs9_friendly_name(&a_oid))
+ return pkcs12_parse_attr_friendly_name(pos, end);
+ if (is_oid_pkcs9_local_key_id(&a_oid))
+ return pkcs12_parse_attr_local_key_id(pos, end);
+
+ wpa_printf(MSG_DEBUG, "PKCS #12: Ignore unknown attribute");
+ return 0;
+}
+
+
+static int pkcs12_safebag(struct tlsv1_credentials *cred,
+ const u8 *buf, size_t len, const char *passwd)
+{
+ struct asn1_hdr hdr;
+ struct asn1_oid oid;
+ char obuf[80];
+ const u8 *pos = buf, *end = buf + len;
+ const u8 *value;
+ size_t value_len;
+
+ wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: SafeBag", buf, len);
+
+ /* BAG-TYPE ::= TYPE-IDENTIFIER */
+ if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Failed to parse OID (BAG-TYPE)");
+ return -1;
+ }
+
+ asn1_oid_to_str(&oid, obuf, sizeof(obuf));
+ wpa_printf(MSG_DEBUG, "PKCS #12: BAG-TYPE %s", obuf);
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC ||
+ hdr.tag != 0) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected [0] EXPLICIT (bagValue) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return 0;
+ }
+ value = hdr.payload;
+ value_len = hdr.length;
+ wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: bagValue", value, value_len);
+ pos = hdr.payload + hdr.length;
+
+ if (pos < end) {
+ /* bagAttributes SET OF PKCS12Attribute OPTIONAL */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SET) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected SET (bagAttributes) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ wpa_hexdump_key(MSG_MSGDUMP, "PKCS #12: bagAttributes",
+ hdr.payload, hdr.length);
+
+ pos = hdr.payload;
+ end = hdr.payload + hdr.length;
+ while (pos < end) {
+ /* PKCS12Attribute ::= SEQUENCE */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected SEQUENCE (PKCS12Attribute) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ if (pkcs12_parse_attr(hdr.payload, hdr.length) < 0)
+ return -1;
+ pos = hdr.payload + hdr.length;
+ }
+ }
+
+ if (pkcs12_is_bagtype_oid(&oid, 1))
+ return pkcs12_keybag(cred, value, value_len);
+ if (pkcs12_is_bagtype_oid(&oid, 2))
+ return pkcs12_pkcs8_keybag(cred, value, value_len, passwd);
+ if (pkcs12_is_bagtype_oid(&oid, 3))
+ return pkcs12_certbag(cred, value, value_len);
+
+ wpa_printf(MSG_DEBUG, "PKCS #12: Ignore unsupported BAG-TYPE");
+ return 0;
+}
+
+
+static int pkcs12_safecontents(struct tlsv1_credentials *cred,
+ const u8 *buf, size_t len,
+ const char *passwd)
+{
+ struct asn1_hdr hdr;
+ const u8 *pos, *end;
+
+ /* SafeContents ::= SEQUENCE OF SafeBag */
+ if (asn1_get_next(buf, len, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected SEQUENCE (SafeContents) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ pos = hdr.payload;
+ end = hdr.payload + hdr.length;
+
+ /*
+ * SafeBag ::= SEQUENCE {
+ * bagId BAG-TYPE.&id ({PKCS12BagSet})
+ * bagValue [0] EXPLICIT BAG-TYPE.&Type({PKCS12BagSet}{@bagId}),
+ * bagAttributes SET OF PKCS12Attribute OPTIONAL
+ * }
+ */
+
+ while (pos < end) {
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected SEQUENCE (SafeBag) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ if (pkcs12_safebag(cred, hdr.payload, hdr.length, passwd) < 0)
+ return -1;
+ pos = hdr.payload + hdr.length;
+ }
+
+ return 0;
+}
+
+
+static int pkcs12_parse_content_data(struct tlsv1_credentials *cred,
+ const u8 *pos, const u8 *end,
+ const char *passwd)
+{
+ struct asn1_hdr hdr;
+
+ /* Data ::= OCTET STRING */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_OCTETSTRING) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected OCTET STRING (Data) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ wpa_hexdump(MSG_MSGDUMP, "PKCS #12: Data", hdr.payload, hdr.length);
+
+ return pkcs12_safecontents(cred, hdr.payload, hdr.length, passwd);
+}
+
+
+static int pkcs12_parse_content_enc_data(struct tlsv1_credentials *cred,
+ const u8 *pos, const u8 *end,
+ const char *passwd)
+{
+ struct asn1_hdr hdr;
+ struct asn1_oid oid;
+ char buf[80];
+ const u8 *enc_alg;
+ u8 *data;
+ size_t enc_alg_len, data_len;
+ int res = -1;
+
+ /*
+ * EncryptedData ::= SEQUENCE {
+ * version Version,
+ * encryptedContentInfo EncryptedContentInfo }
+ */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected SEQUENCE (EncryptedData) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return 0;
+ }
+ pos = hdr.payload;
+
+ /* Version ::= INTEGER */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: No INTEGER tag found for version; class=%d tag=0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ if (hdr.length != 1 || hdr.payload[0] != 0) {
+ wpa_printf(MSG_DEBUG, "PKCS #12: Unrecognized PKCS #7 version");
+ return -1;
+ }
+ pos = hdr.payload + hdr.length;
+
+ wpa_hexdump(MSG_MSGDUMP, "PKCS #12: EncryptedContentInfo",
+ pos, end - pos);
+
+ /*
+ * EncryptedContentInfo ::= SEQUENCE {
+ * contentType ContentType,
+ * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier,
+ * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL }
+ */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected SEQUENCE (EncryptedContentInfo) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ pos = hdr.payload;
+ end = pos + hdr.length;
+
+ /* ContentType ::= OBJECT IDENTIFIER */
+ if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Could not find OBJECT IDENTIFIER (contentType)");
+ return -1;
+ }
+ asn1_oid_to_str(&oid, buf, sizeof(buf));
+ wpa_printf(MSG_DEBUG, "PKCS #12: EncryptedContentInfo::contentType %s",
+ buf);
+
+ if (!is_oid_pkcs7_data(&oid)) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Unsupported EncryptedContentInfo::contentType %s",
+ buf);
+ return 0;
+ }
+
+ /* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG, "PKCS #12: Expected SEQUENCE (ContentEncryptionAlgorithmIdentifier) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ enc_alg = hdr.payload;
+ enc_alg_len = hdr.length;
+ pos = hdr.payload + hdr.length;
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC ||
+ hdr.tag != 0) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected [0] IMPLICIT (encryptedContent) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ /* EncryptedContent ::= OCTET STRING */
+ data = pkcs5_decrypt(enc_alg, enc_alg_len, hdr.payload, hdr.length,
+ passwd, &data_len);
+ if (data) {
+ wpa_hexdump_key(MSG_MSGDUMP,
+ "PKCS #12: Decrypted encryptedContent",
+ data, data_len);
+ res = pkcs12_safecontents(cred, data, data_len, passwd);
+ os_free(data);
+ }
+
+ return res;
+}
+
+
+static int pkcs12_parse_content(struct tlsv1_credentials *cred,
+ const u8 *buf, size_t len,
+ const char *passwd)
+{
+ const u8 *pos = buf;
+ const u8 *end = buf + len;
+ struct asn1_oid oid;
+ char txt[80];
+ struct asn1_hdr hdr;
+
+ wpa_hexdump(MSG_MSGDUMP, "PKCS #12: ContentInfo", buf, len);
+
+ if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Could not find OBJECT IDENTIFIER (contentType)");
+ return 0;
+ }
+
+ asn1_oid_to_str(&oid, txt, sizeof(txt));
+ wpa_printf(MSG_DEBUG, "PKCS #12: contentType %s", txt);
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC ||
+ hdr.tag != 0) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected [0] EXPLICIT (content) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return 0;
+ }
+ pos = hdr.payload;
+
+ if (is_oid_pkcs7_data(&oid))
+ return pkcs12_parse_content_data(cred, pos, end, passwd);
+ if (is_oid_pkcs7_enc_data(&oid))
+ return pkcs12_parse_content_enc_data(cred, pos, end, passwd);
+
+ wpa_printf(MSG_DEBUG, "PKCS #12: Ignored unsupported contentType %s",
+ txt);
+
+ return 0;
+}
+
+
+static int pkcs12_parse(struct tlsv1_credentials *cred,
+ const u8 *key, size_t len, const char *passwd)
+{
+ struct asn1_hdr hdr;
+ const u8 *pos, *end;
+ struct asn1_oid oid;
+ char buf[80];
+
+ /*
+ * PFX ::= SEQUENCE {
+ * version INTEGER {v3(3)}(v3,...),
+ * authSafe ContentInfo,
+ * macData MacData OPTIONAL
+ * }
+ */
+
+ if (asn1_get_next(key, len, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected SEQUENCE (PFX) - found class %d tag 0x%x; assume PKCS #12 not used",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ pos = hdr.payload;
+ end = pos + hdr.length;
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: No INTEGER tag found for version; class=%d tag=0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ if (hdr.length != 1 || hdr.payload[0] != 3) {
+ wpa_printf(MSG_DEBUG, "PKCS #12: Unrecognized version");
+ return -1;
+ }
+ pos = hdr.payload + hdr.length;
+
+ /*
+ * ContentInfo ::= SEQUENCE {
+ * contentType ContentType,
+ * content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
+ */
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected SEQUENCE (authSafe) - found class %d tag 0x%x; assume PKCS #12 not used",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ pos = hdr.payload;
+ end = pos + hdr.length;
+
+ /* ContentType ::= OBJECT IDENTIFIER */
+ if (asn1_get_oid(pos, end - pos, &oid, &pos)) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Could not find OBJECT IDENTIFIER (contentType); assume PKCS #12 not used");
+ return -1;
+ }
+ asn1_oid_to_str(&oid, buf, sizeof(buf));
+ wpa_printf(MSG_DEBUG, "PKCS #12: contentType %s", buf);
+ if (!is_oid_pkcs7_data(&oid)) {
+ wpa_printf(MSG_DEBUG, "PKCS #12: Unsupported contentType %s",
+ buf);
+ return -1;
+ }
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC ||
+ hdr.tag != 0) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected [0] EXPLICIT (content) - found class %d tag 0x%x; assume PKCS #12 not used",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ pos = hdr.payload;
+
+ /* Data ::= OCTET STRING */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_OCTETSTRING) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected OCTET STRING (Data) - found class %d tag 0x%x; assume PKCS #12 not used",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ /*
+ * AuthenticatedSafe ::= SEQUENCE OF ContentInfo
+ * -- Data if unencrypted
+ * -- EncryptedData if password-encrypted
+ * -- EnvelopedData if public key-encrypted
+ */
+ wpa_hexdump(MSG_MSGDUMP, "PKCS #12: Data content",
+ hdr.payload, hdr.length);
+
+ if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected SEQUENCE within Data content - found class %d tag 0x%x; assume PKCS #12 not used",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ pos = hdr.payload;
+ end = pos + hdr.length;
+
+ while (end > pos) {
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG,
+ "PKCS #12: Expected SEQUENCE (ContentInfo) - found class %d tag 0x%x; assume PKCS #12 not used",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ if (pkcs12_parse_content(cred, hdr.payload, hdr.length,
+ passwd) < 0)
+ return -1;
+
+ pos = hdr.payload + hdr.length;
+ }
+
+ return 0;
+}
+
+#endif /* PKCS12_FUNCS */
+
+
static int tlsv1_set_key(struct tlsv1_credentials *cred,
const u8 *key, size_t len, const char *passwd)
{
@@ -333,6 +1065,10 @@ static int tlsv1_set_key(struct tlsv1_credentials *cred,
cred->key = tlsv1_set_key_pem(key, len);
if (cred->key == NULL)
cred->key = tlsv1_set_key_enc_pem(key, len, passwd);
+#ifdef PKCS12_FUNCS
+ if (!cred->key)
+ pkcs12_parse(cred, key, len, passwd);
+#endif /* PKCS12_FUNCS */
if (cred->key == NULL) {
wpa_printf(MSG_INFO, "TLSv1: Failed to parse private key");
return -1;
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index e748785a..f62b30a4 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -980,6 +980,7 @@ OBJS += src/tls/tlsv1_cred.c
OBJS += src/tls/tlsv1_client.c
OBJS += src/tls/tlsv1_client_write.c
OBJS += src/tls/tlsv1_client_read.c
+OBJS += src/tls/tlsv1_client_ocsp.c
OBJS += src/tls/asn1.c
OBJS += src/tls/rsa.c
OBJS += src/tls/x509v3.c
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index e3d3acf1..6bab7d1e 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -1010,6 +1010,7 @@ OBJS += ../src/tls/tlsv1_cred.o
OBJS += ../src/tls/tlsv1_client.o
OBJS += ../src/tls/tlsv1_client_write.o
OBJS += ../src/tls/tlsv1_client_read.o
+OBJS += ../src/tls/tlsv1_client_ocsp.o
OBJS += ../src/tls/asn1.o
OBJS += ../src/tls/rsa.o
OBJS += ../src/tls/x509v3.o
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 7b45a3a7..a3b587fe 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -6952,6 +6952,7 @@ static void wpa_supplicant_ctrl_iface_flush(struct wpa_supplicant *wpa_s)
wpa_s->extra_roc_dur = 0;
wpa_s->test_failure = WPAS_TEST_FAILURE_NONE;
wpa_s->p2p_go_csa_on_inv = 0;
+ wpa_sm_set_test_assoc_ie(wpa_s->wpa, NULL);
#endif /* CONFIG_TESTING_OPTIONS */
wpa_s->disconnected = 0;
@@ -7841,62 +7842,36 @@ static int wpas_ctrl_event_test(struct wpa_supplicant *wpa_s, const char *cmd)
(void *) (intptr_t) count);
}
-#endif /* CONFIG_TESTING_OPTIONS */
-
-static void wpas_ctrl_vendor_elem_update(struct wpa_supplicant *wpa_s)
+static int wpas_ctrl_test_assoc_ie(struct wpa_supplicant *wpa_s,
+ const char *cmd)
{
- unsigned int i;
- char buf[30];
+ struct wpabuf *buf;
+ size_t len;
- wpa_printf(MSG_DEBUG, "Update vendor elements");
+ len = os_strlen(cmd);
+ if (len & 1)
+ return -1;
+ len /= 2;
- for (i = 0; i < NUM_VENDOR_ELEM_FRAMES; i++) {
- if (wpa_s->vendor_elem[i]) {
- int res;
+ if (len == 0) {
+ buf = NULL;
+ } else {
+ buf = wpabuf_alloc(len);
+ if (buf == NULL)
+ return -1;
- res = os_snprintf(buf, sizeof(buf), "frame[%u]", i);
- if (!os_snprintf_error(sizeof(buf), res)) {
- wpa_hexdump_buf(MSG_DEBUG, buf,
- wpa_s->vendor_elem[i]);
- }
+ if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
+ wpabuf_free(buf);
+ return -1;
}
}
-#ifdef CONFIG_P2P
- if (wpa_s->parent == wpa_s &&
- wpa_s->global->p2p &&
- !wpa_s->global->p2p_disabled)
- p2p_set_vendor_elems(wpa_s->global->p2p, wpa_s->vendor_elem);
-#endif /* CONFIG_P2P */
+ wpa_sm_set_test_assoc_ie(wpa_s->wpa, buf);
+ return 0;
}
-
-static struct wpa_supplicant *
-wpas_ctrl_vendor_elem_iface(struct wpa_supplicant *wpa_s,
- enum wpa_vendor_elem_frame frame)
-{
- switch (frame) {
-#ifdef CONFIG_P2P
- case VENDOR_ELEM_PROBE_REQ_P2P:
- case VENDOR_ELEM_PROBE_RESP_P2P:
- case VENDOR_ELEM_PROBE_RESP_P2P_GO:
- case VENDOR_ELEM_BEACON_P2P_GO:
- case VENDOR_ELEM_P2P_PD_REQ:
- case VENDOR_ELEM_P2P_PD_RESP:
- case VENDOR_ELEM_P2P_GO_NEG_REQ:
- case VENDOR_ELEM_P2P_GO_NEG_RESP:
- case VENDOR_ELEM_P2P_GO_NEG_CONF:
- case VENDOR_ELEM_P2P_INV_REQ:
- case VENDOR_ELEM_P2P_INV_RESP:
- case VENDOR_ELEM_P2P_ASSOC_REQ:
- case VENDOR_ELEM_P2P_ASSOC_RESP:
- return wpa_s->parent;
-#endif /* CONFIG_P2P */
- default:
- return wpa_s;
- }
-}
+#endif /* CONFIG_TESTING_OPTIONS */
static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd)
@@ -7910,7 +7885,7 @@ static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd)
frame = atoi(pos);
if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
return -1;
- wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame);
+ wpa_s = wpas_vendor_elem(wpa_s, frame);
pos = os_strchr(pos, ' ');
if (pos == NULL)
@@ -7941,7 +7916,7 @@ static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd)
if (wpa_s->vendor_elem[frame] == NULL) {
wpa_s->vendor_elem[frame] = buf;
- wpas_ctrl_vendor_elem_update(wpa_s);
+ wpas_vendor_elem_update(wpa_s);
return 0;
}
@@ -7952,7 +7927,7 @@ static int wpas_ctrl_vendor_elem_add(struct wpa_supplicant *wpa_s, char *cmd)
wpabuf_put_buf(wpa_s->vendor_elem[frame], buf);
wpabuf_free(buf);
- wpas_ctrl_vendor_elem_update(wpa_s);
+ wpas_vendor_elem_update(wpa_s);
return 0;
}
@@ -7965,7 +7940,7 @@ static int wpas_ctrl_vendor_elem_get(struct wpa_supplicant *wpa_s, char *cmd,
if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
return -1;
- wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame);
+ wpa_s = wpas_vendor_elem(wpa_s, frame);
if (wpa_s->vendor_elem[frame] == NULL)
return 0;
@@ -7983,12 +7958,12 @@ static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd)
size_t len;
u8 *buf;
struct ieee802_11_elems elems;
- u8 *ie, *end;
+ int res;
frame = atoi(pos);
if (frame < 0 || frame >= NUM_VENDOR_ELEM_FRAMES)
return -1;
- wpa_s = wpas_ctrl_vendor_elem_iface(wpa_s, frame);
+ wpa_s = wpas_vendor_elem(wpa_s, frame);
pos = os_strchr(pos, ' ');
if (pos == NULL)
@@ -7998,7 +7973,7 @@ static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd)
if (*pos == '*') {
wpabuf_free(wpa_s->vendor_elem[frame]);
wpa_s->vendor_elem[frame] = NULL;
- wpas_ctrl_vendor_elem_update(wpa_s);
+ wpas_vendor_elem_update(wpa_s);
return 0;
}
@@ -8026,31 +8001,9 @@ static int wpas_ctrl_vendor_elem_remove(struct wpa_supplicant *wpa_s, char *cmd)
return -1;
}
- ie = wpabuf_mhead_u8(wpa_s->vendor_elem[frame]);
- end = ie + wpabuf_len(wpa_s->vendor_elem[frame]);
-
- for (; ie + 1 < end; ie += 2 + ie[1]) {
- if (ie + len > end)
- break;
- if (os_memcmp(ie, buf, len) != 0)
- continue;
-
- if (wpabuf_len(wpa_s->vendor_elem[frame]) == len) {
- wpabuf_free(wpa_s->vendor_elem[frame]);
- wpa_s->vendor_elem[frame] = NULL;
- } else {
- os_memmove(ie, ie + len,
- end - (ie + len));
- wpa_s->vendor_elem[frame]->used -= len;
- }
- os_free(buf);
- wpas_ctrl_vendor_elem_update(wpa_s);
- return 0;
- }
-
+ res = wpas_vendor_elem_remove(wpa_s, frame, buf, len);
os_free(buf);
-
- return -1;
+ return res;
}
@@ -8882,6 +8835,9 @@ char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
} else if (os_strncmp(buf, "EVENT_TEST ", 11) == 0) {
if (wpas_ctrl_event_test(wpa_s, buf + 11) < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "TEST_ASSOC_IE ", 14) == 0) {
+ if (wpas_ctrl_test_assoc_ie(wpa_s, buf + 14) < 0)
+ reply_len = -1;
#endif /* CONFIG_TESTING_OPTIONS */
} else if (os_strncmp(buf, "VENDOR_ELEM_ADD ", 16) == 0) {
if (wpas_ctrl_vendor_elem_add(wpa_s, buf + 16) < 0)
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index 440b8cfc..91a1511a 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -3070,6 +3070,30 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
}
},
#endif /* CONFIG_TDLS */
+ { "VendorElemAdd", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_vendor_elem_add,
+ {
+ { "frame_id", "i", ARG_IN },
+ { "ielems", "ay", ARG_IN },
+ END_ARGS
+ }
+ },
+ { "VendorElemGet", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_vendor_elem_get,
+ {
+ { "frame_id", "i", ARG_IN },
+ { "ielems", "ay", ARG_OUT },
+ END_ARGS
+ }
+ },
+ { "VendorElemRem", WPAS_DBUS_NEW_IFACE_INTERFACE,
+ (WPADBusMethodHandler) wpas_dbus_handler_vendor_elem_remove,
+ {
+ { "frame_id", "i", ARG_IN },
+ { "ielems", "ay", ARG_IN },
+ END_ARGS
+ }
+ },
#ifndef CONFIG_NO_CONFIG_WRITE
{ "SaveConfig", WPAS_DBUS_NEW_IFACE_INTERFACE,
(WPADBusMethodHandler) wpas_dbus_handler_save_config,
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index fbfcdc9a..6b77008a 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -4363,3 +4363,147 @@ out:
}
#endif /* CONFIG_AP */
+
+
+DBusMessage * wpas_dbus_handler_vendor_elem_add(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ u8 *ielems;
+ int len;
+ struct ieee802_11_elems elems;
+ dbus_int32_t frame_id;
+ DBusMessageIter iter, array;
+
+ dbus_message_iter_init(message, &iter);
+ dbus_message_iter_get_basic(&iter, &frame_id);
+ if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) {
+ return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+ "Invalid ID");
+ }
+
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_recurse(&iter, &array);
+ dbus_message_iter_get_fixed_array(&array, &ielems, &len);
+ if (!ielems || len == 0) {
+ return dbus_message_new_error(
+ message, DBUS_ERROR_INVALID_ARGS, "Invalid value");
+ }
+
+ if (ieee802_11_parse_elems(ielems, len, &elems, 0) == ParseFailed) {
+ return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+ "Parse error");
+ }
+
+ wpa_s = wpas_vendor_elem(wpa_s, frame_id);
+ if (!wpa_s->vendor_elem[frame_id]) {
+ wpa_s->vendor_elem[frame_id] = wpabuf_alloc_copy(ielems, len);
+ wpas_vendor_elem_update(wpa_s);
+ return NULL;
+ }
+
+ if (wpabuf_resize(&wpa_s->vendor_elem[frame_id], len) < 0) {
+ return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+ "Resize error");
+ }
+
+ wpabuf_put_data(wpa_s->vendor_elem[frame_id], ielems, len);
+ wpas_vendor_elem_update(wpa_s);
+ return NULL;
+}
+
+
+DBusMessage * wpas_dbus_handler_vendor_elem_get(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ DBusMessage *reply;
+ DBusMessageIter iter, array_iter;
+ dbus_int32_t frame_id;
+ const u8 *elem;
+ size_t elem_len;
+
+ dbus_message_iter_init(message, &iter);
+ dbus_message_iter_get_basic(&iter, &frame_id);
+
+ if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) {
+ return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+ "Invalid ID");
+ }
+
+ wpa_s = wpas_vendor_elem(wpa_s, frame_id);
+ if (!wpa_s->vendor_elem[frame_id]) {
+ return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+ "ID value does not exist");
+ }
+
+ reply = dbus_message_new_method_return(message);
+ if (!reply)
+ return wpas_dbus_error_no_memory(message);
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ elem = wpabuf_head_u8(wpa_s->vendor_elem[frame_id]);
+ elem_len = wpabuf_len(wpa_s->vendor_elem[frame_id]);
+
+ if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BYTE_AS_STRING,
+ &array_iter) ||
+ !dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE,
+ &elem, elem_len) ||
+ !dbus_message_iter_close_container(&iter, &array_iter)) {
+ dbus_message_unref(reply);
+ reply = wpas_dbus_error_no_memory(message);
+ }
+
+ return reply;
+}
+
+
+DBusMessage * wpas_dbus_handler_vendor_elem_remove(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ u8 *ielems;
+ int len;
+ struct ieee802_11_elems elems;
+ DBusMessageIter iter, array;
+ dbus_int32_t frame_id;
+
+ dbus_message_iter_init(message, &iter);
+ dbus_message_iter_get_basic(&iter, &frame_id);
+ if (frame_id < 0 || frame_id >= NUM_VENDOR_ELEM_FRAMES) {
+ return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+ "Invalid ID");
+ }
+
+ dbus_message_iter_next(&iter);
+ dbus_message_iter_recurse(&iter, &array);
+ dbus_message_iter_get_fixed_array(&array, &ielems, &len);
+ if (!ielems || len == 0) {
+ return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+ "Invalid value");
+ }
+
+ wpa_s = wpas_vendor_elem(wpa_s, frame_id);
+
+ if (len == 1 && *ielems == '*') {
+ wpabuf_free(wpa_s->vendor_elem[frame_id]);
+ wpa_s->vendor_elem[frame_id] = NULL;
+ wpas_vendor_elem_update(wpa_s);
+ return NULL;
+ }
+
+ if (!wpa_s->vendor_elem[frame_id]) {
+ return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+ "ID value does not exist");
+ }
+
+ if (ieee802_11_parse_elems(ielems, len, &elems, 0) == ParseFailed) {
+ return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+ "Parse error");
+ }
+
+ if (wpas_vendor_elem_remove(wpa_s, frame_id, ielems, len) == 0)
+ return NULL;
+
+ return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+ "Not found");
+}
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index 86c83597..31b92d19 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -194,6 +194,13 @@ DBusMessage * wpas_dbus_handler_tdls_status(DBusMessage *message,
DBusMessage * wpas_dbus_handler_tdls_teardown(DBusMessage *message,
struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_vendor_elem_add(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_vendor_elem_get(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_handler_vendor_elem_remove(
+ DBusMessage *message, struct wpa_supplicant *wpa_s);
+
DBusMessage * wpas_dbus_handler_save_config(DBusMessage *message,
struct wpa_supplicant *wpa_s);
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 6eb3e888..2675bed1 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -3329,7 +3329,10 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
switch (event) {
case EVENT_AUTH:
#ifdef CONFIG_FST
- wpas_fst_update_mbie(wpa_s, data->auth.ies, data->auth.ies_len);
+ if (!wpas_fst_update_mbie(wpa_s, data->auth.ies,
+ data->auth.ies_len))
+ wpa_printf(MSG_DEBUG,
+ "FST: MB IEs updated from auth IE");
#endif /* CONFIG_FST */
sme_event_auth(wpa_s, data);
break;
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 7e5c07ad..6e2d1807 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -5556,6 +5556,16 @@ int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
if (wpa_s->wpa_state == WPA_SCANNING && !wpa_s->scanning)
wpa_supplicant_req_scan(wpa_s, 0, 0);
break;
+ case WPA_CTRL_REQ_EXT_CERT_CHECK:
+ if (eap->pending_ext_cert_check != PENDING_CHECK)
+ return -1;
+ if (os_strcmp(value, "good") == 0)
+ eap->pending_ext_cert_check = EXT_CERT_CHECK_GOOD;
+ else if (os_strcmp(value, "bad") == 0)
+ eap->pending_ext_cert_check = EXT_CERT_CHECK_BAD;
+ else
+ return -1;
+ break;
default:
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", field);
return -1;
@@ -6143,3 +6153,86 @@ void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s,
}
wpabuf_free(buf);
}
+
+
+struct wpa_supplicant *
+wpas_vendor_elem(struct wpa_supplicant *wpa_s, enum wpa_vendor_elem_frame frame)
+{
+ switch (frame) {
+#ifdef CONFIG_P2P
+ case VENDOR_ELEM_PROBE_REQ_P2P:
+ case VENDOR_ELEM_PROBE_RESP_P2P:
+ case VENDOR_ELEM_PROBE_RESP_P2P_GO:
+ case VENDOR_ELEM_BEACON_P2P_GO:
+ case VENDOR_ELEM_P2P_PD_REQ:
+ case VENDOR_ELEM_P2P_PD_RESP:
+ case VENDOR_ELEM_P2P_GO_NEG_REQ:
+ case VENDOR_ELEM_P2P_GO_NEG_RESP:
+ case VENDOR_ELEM_P2P_GO_NEG_CONF:
+ case VENDOR_ELEM_P2P_INV_REQ:
+ case VENDOR_ELEM_P2P_INV_RESP:
+ case VENDOR_ELEM_P2P_ASSOC_REQ:
+ case VENDOR_ELEM_P2P_ASSOC_RESP:
+ return wpa_s->parent;
+#endif /* CONFIG_P2P */
+ default:
+ return wpa_s;
+ }
+}
+
+
+void wpas_vendor_elem_update(struct wpa_supplicant *wpa_s)
+{
+ unsigned int i;
+ char buf[30];
+
+ wpa_printf(MSG_DEBUG, "Update vendor elements");
+
+ for (i = 0; i < NUM_VENDOR_ELEM_FRAMES; i++) {
+ if (wpa_s->vendor_elem[i]) {
+ int res;
+
+ res = os_snprintf(buf, sizeof(buf), "frame[%u]", i);
+ if (!os_snprintf_error(sizeof(buf), res)) {
+ wpa_hexdump_buf(MSG_DEBUG, buf,
+ wpa_s->vendor_elem[i]);
+ }
+ }
+ }
+
+#ifdef CONFIG_P2P
+ if (wpa_s->parent == wpa_s &&
+ wpa_s->global->p2p &&
+ !wpa_s->global->p2p_disabled)
+ p2p_set_vendor_elems(wpa_s->global->p2p, wpa_s->vendor_elem);
+#endif /* CONFIG_P2P */
+}
+
+
+int wpas_vendor_elem_remove(struct wpa_supplicant *wpa_s, int frame,
+ const u8 *elem, size_t len)
+{
+ u8 *ie, *end;
+
+ ie = wpabuf_mhead_u8(wpa_s->vendor_elem[frame]);
+ end = ie + wpabuf_len(wpa_s->vendor_elem[frame]);
+
+ for (; ie + 1 < end; ie += 2 + ie[1]) {
+ if (ie + len > end)
+ break;
+ if (os_memcmp(ie, elem, len) != 0)
+ continue;
+
+ if (wpabuf_len(wpa_s->vendor_elem[frame]) == len) {
+ wpabuf_free(wpa_s->vendor_elem[frame]);
+ wpa_s->vendor_elem[frame] = NULL;
+ } else {
+ os_memmove(ie, ie + len, end - (ie + len));
+ wpa_s->vendor_elem[frame]->used -= len;
+ }
+ wpas_vendor_elem_update(wpa_s);
+ return 0;
+ }
+
+ return -1;
+}
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 2ce1cc4e..e33b720a 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -1037,6 +1037,12 @@ fast_reauth=1
# that have issues interoperating with updated TLS version)
# tls_disable_tlsv1_2=1 - disable use of TLSv1.2 (a workaround for AAA servers
# that have issues interoperating with updated TLS version)
+# tls_ext_cert_check=0 - No external server certificate validation (default)
+# tls_ext_cert_check=1 - External server certificate validation enabled; this
+# requires an external program doing validation of server certificate
+# chain when receiving CTRL-RSP-EXT_CERT_CHECK event from the control
+# interface and report the result of the validation with
+# CTRL-RSP_EXT_CERT_CHECK.
#
# Following certificate/private key fields are used in inner Phase2
# authentication when using EAP-TTLS or EAP-PEAP.
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index a8b273bc..05a1bc66 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -1179,6 +1179,12 @@ int get_shared_radio_freqs(struct wpa_supplicant *wpa_s,
void wpas_network_reenabled(void *eloop_ctx, void *timeout_ctx);
+void wpas_vendor_elem_update(struct wpa_supplicant *wpa_s);
+struct wpa_supplicant * wpas_vendor_elem(struct wpa_supplicant *wpa_s,
+ enum wpa_vendor_elem_frame frame);
+int wpas_vendor_elem_remove(struct wpa_supplicant *wpa_s, int frame,
+ const u8 *elem, size_t len);
+
#ifdef CONFIG_FST
struct fst_wpa_obj;
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 7986695a..f84c8b90 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -739,6 +739,8 @@ enum wpa_ctrl_req_type wpa_supplicant_ctrl_req_from_string(const char *field)
return WPA_CTRL_REQ_SIM;
else if (os_strcmp(field, "PSK_PASSPHRASE") == 0)
return WPA_CTRL_REQ_PSK_PASSPHRASE;
+ else if (os_strcmp(field, "EXT_CERT_CHECK") == 0)
+ return WPA_CTRL_REQ_EXT_CERT_CHECK;
return WPA_CTRL_REQ_UNKNOWN;
}
@@ -782,6 +784,10 @@ const char * wpa_supplicant_ctrl_req_to_string(enum wpa_ctrl_req_type field,
*txt = "PSK or passphrase";
ret = "PSK_PASSPHRASE";
break;
+ case WPA_CTRL_REQ_EXT_CERT_CHECK:
+ *txt = "External server certificate validation";
+ ret = "EXT_CERT_CHECK";
+ break;
default:
break;
}
@@ -837,6 +843,8 @@ static void wpa_supplicant_eap_param_needed(void *ctx,
if (ssid == NULL)
return;
+ if (field == WPA_CTRL_REQ_EXT_CERT_CHECK)
+ ssid->eap.pending_ext_cert_check = PENDING_CHECK;
wpas_notify_network_request(wpa_s, ssid, field, default_txt);
field_name = wpa_supplicant_ctrl_req_to_string(field, default_txt,