Cumulative patch from commit 324ade51e168f28430f4429849becd0f08d507c0 (DO NOT MERGE)
324ade5 TLS: Make tls_cert_chain_failure_event() more robust
c6231b5 TLS: Remove storing of never-read value
15a6813 Remove unnecessary cleanup assignment in SHA1Final()
ef3866a nl80211: Don't call linux_iface_up() for a dedicated P2P Device
c2ed779 mesh: Document Mesh Peering Management element structure in more detail
b2817cd mesh: Check PMKID in AMPE Action frames
6c33eed mesh: Fix PMKID to match the standard
ede7770 wpa_supplicant: Do not wait for monitor on P2P Device interface
1c94570 Do not wait for monitor to attach if no control interface
f98674a Clone default LIBS value to LIBS_* for other tools
7d2f674 Add "GET_CAPABILITY acs" to allow ACS build option to be detected
d990971 wpa_supplicant: Enable Automatic Channel Selection support for AP mode
96bc508 Handle survey event properly in wpa_supplicant
d39f796 EAP-TNC peer: Remove dead code related to fragmentation
662512e P2PS: Remove dead code
abbbaa4 TNC: Print received IF-TNCCS message as debug ASCII hexdump
d745f02 EAP-TNC peer: Allow fragment_size to be configured
a67e7e5 RADIUS: Add EACCES to list of recognized send() errno values
5bd9be4 Fix RADIUS Called-Station-Id to not escape SSID
0764dd6 TLS client: Multi-OCSP check to cover intermediate CAs
d6b536f Add ocsp=3 configuration parameter for multi-OCSP
0268383 TLS: Move variable declaration to the beginning of the block
b567775 TLS client: OCSP stapling with ocsp_multi option (RFC 6961)
8ea6a27 TLS server: OCSP stapling with ocsp_multi option (RFC 6961)
5addb0d Server configuration for OCSP stapling with ocsp_multi (RFC 6961)
bca0872 TLS server: OCSP stapling
9532bd2 GnuTLS: OCSP stapling on the server side
6241766 Use wpa_msg() for the "RSN: PMKID mismatch" message
e161451 EAP-EKE: Merge identical error return paths
13cb0a6 EAP-EKE: Reject too long Prot() data when building a frame
0ab0de8 Document previously missing key_mgmt values
Change-Id: I9ac7d0da03d8baf4542e276ab20cb56e44bfa33c
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/hostapd/Makefile b/hostapd/Makefile
index fa5435d..45afedf 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -6,6 +6,21 @@
CFLAGS = -MMD -O2 -Wall -g
endif
+ifdef LIBS
+# If LIBS is set with some global build system defaults, clone those for
+# LIBS_c, LIBS_h, and LIBS_n to cover hostapd_cli, hlr_auc_gw, and
+# nt_password_hash as well.
+ifndef LIBS_c
+LIBS_c := $(LIBS)
+endif
+ifndef LIBS_h
+LIBS_h := $(LIBS)
+endif
+ifndef LIBS_n
+LIBS_n := $(LIBS)
+endif
+endif
+
CFLAGS += $(EXTRA_CFLAGS)
CFLAGS += -I$(abspath ../src)
CFLAGS += -I$(abspath ../src/utils)
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index f2163b8..503d479 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -2132,6 +2132,9 @@
} else if (os_strcmp(buf, "ocsp_stapling_response") == 0) {
os_free(bss->ocsp_stapling_response);
bss->ocsp_stapling_response = os_strdup(pos);
+ } else if (os_strcmp(buf, "ocsp_stapling_response_multi") == 0) {
+ os_free(bss->ocsp_stapling_response_multi);
+ bss->ocsp_stapling_response_multi = os_strdup(pos);
} else if (os_strcmp(buf, "dh_file") == 0) {
os_free(bss->dh_file);
bss->dh_file = os_strdup(pos);
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 4f51140..ecd4328 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -795,6 +795,11 @@
# -respout /tmp/ocsp-cache.der
#ocsp_stapling_response=/tmp/ocsp-cache.der
+# Cached OCSP stapling response list (DER encoded OCSPResponseList)
+# This is similar to ocsp_stapling_response, but the extended version defined in
+# RFC 6961 to allow multiple OCSP responses to be provided.
+#ocsp_stapling_response_multi=/tmp/ocsp-multi-cache.der
+
# dh_file: File path to DH/DSA parameters file (in PEM format)
# This is an optional configuration file for setting parameters for an
# ephemeral DH key exchange. In most cases, the default RSA authentication does
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index cf9b2ce..88074f2 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -471,6 +471,7 @@
os_free(conf->private_key);
os_free(conf->private_key_passwd);
os_free(conf->ocsp_stapling_response);
+ os_free(conf->ocsp_stapling_response_multi);
os_free(conf->dh_file);
os_free(conf->openssl_ciphers);
os_free(conf->pac_opaque_encr_key);
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index ff9dcb0..44bcccc 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -341,6 +341,7 @@
int check_crl;
unsigned int tls_session_lifetime;
char *ocsp_stapling_response;
+ char *ocsp_stapling_response_multi;
char *dh_file;
char *openssl_ciphers;
u8 *pac_opaque_encr_key;
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index c9111f6..cdb49cd 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -173,6 +173,8 @@
params.openssl_ciphers = hapd->conf->openssl_ciphers;
params.ocsp_stapling_response =
hapd->conf->ocsp_stapling_response;
+ params.ocsp_stapling_response_multi =
+ hapd->conf->ocsp_stapling_response_multi;
if (tls_global_set_params(hapd->ssl_ctx, ¶ms)) {
wpa_printf(MSG_ERROR, "Failed to set TLS parameters");
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index fd07201..aad0d81 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -549,8 +549,8 @@
#ifdef CONFIG_ACS
-static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
- struct acs_selected_channels *acs_res)
+void hostapd_acs_channel_selected(struct hostapd_data *hapd,
+ struct acs_selected_channels *acs_res)
{
int ret, i;
@@ -945,6 +945,8 @@
ieee802_1x_receive(hapd, src, data, data_len);
}
+#endif /* HOSTAPD */
+
static struct hostapd_channel_data * hostapd_get_mode_channel(
struct hostapd_iface *iface, unsigned int freq)
@@ -1019,10 +1021,9 @@
}
-static void hostapd_event_get_survey(struct hostapd_data *hapd,
- struct survey_results *survey_results)
+void hostapd_event_get_survey(struct hostapd_iface *iface,
+ struct survey_results *survey_results)
{
- struct hostapd_iface *iface = hapd->iface;
struct freq_survey *survey, *tmp;
struct hostapd_channel_data *chan;
@@ -1054,6 +1055,7 @@
}
+#ifdef HOSTAPD
#ifdef NEED_AP_MLME
static void hostapd_event_iface_unavailable(struct hostapd_data *hapd)
@@ -1261,7 +1263,7 @@
data->connect_failed_reason.code);
break;
case EVENT_SURVEY:
- hostapd_event_get_survey(hapd, &data->survey_results);
+ hostapd_event_get_survey(hapd->iface, &data->survey_results);
break;
#ifdef NEED_AP_MLME
case EVENT_INTERFACE_UNAVAILABLE:
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 8161a59..7b59f80 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -493,6 +493,11 @@
int ssi_signal);
void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
int offset, int width, int cf1, int cf2);
+struct survey_results;
+void hostapd_event_get_survey(struct hostapd_iface *iface,
+ struct survey_results *survey_results);
+void hostapd_acs_channel_selected(struct hostapd_data *hapd,
+ struct acs_selected_channels *acs_res);
const struct hostapd_eap_user *
hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index f566603..e3b3d94 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -475,6 +475,7 @@
{
char buf[128];
struct hostapd_radius_attr *attr;
+ int len;
if (!hostapd_config_get_radius_attr(req_attr,
RADIUS_ATTR_NAS_IP_ADDRESS) &&
@@ -506,15 +507,15 @@
return -1;
}
- os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
- MAC2STR(hapd->own_addr),
- wpa_ssid_txt(hapd->conf->ssid.ssid,
- hapd->conf->ssid.ssid_len));
- buf[sizeof(buf) - 1] = '\0';
+ len = os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":",
+ MAC2STR(hapd->own_addr));
+ os_memcpy(&buf[len], hapd->conf->ssid.ssid,
+ hapd->conf->ssid.ssid_len);
+ len += hapd->conf->ssid.ssid_len;
if (!hostapd_config_get_radius_attr(req_attr,
RADIUS_ATTR_CALLED_STATION_ID) &&
!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
- (u8 *) buf, os_strlen(buf))) {
+ (u8 *) buf, len)) {
wpa_printf(MSG_ERROR, "Could not add Called-Station-Id");
return -1;
}
diff --git a/src/common/sae.c b/src/common/sae.c
index b962ea2..6c00a7e 100644
--- a/src/common/sae.c
+++ b/src/common/sae.c
@@ -816,6 +816,7 @@
os_memset(keyseed, 0, sizeof(keyseed));
os_memcpy(sae->tmp->kck, keys, SAE_KCK_LEN);
os_memcpy(sae->pmk, keys + SAE_KCK_LEN, SAE_PMK_LEN);
+ os_memcpy(sae->pmkid, val, SAE_PMKID_LEN);
os_memset(keys, 0, sizeof(keys));
wpa_hexdump_key(MSG_DEBUG, "SAE: KCK", sae->tmp->kck, SAE_KCK_LEN);
wpa_hexdump_key(MSG_DEBUG, "SAE: PMK", sae->pmk, SAE_PMK_LEN);
diff --git a/src/common/sae.h b/src/common/sae.h
index c07026c..a4270bc 100644
--- a/src/common/sae.h
+++ b/src/common/sae.h
@@ -45,6 +45,7 @@
enum { SAE_NOTHING, SAE_COMMITTED, SAE_CONFIRMED, SAE_ACCEPTED } state;
u16 send_confirm;
u8 pmk[SAE_PMK_LEN];
+ u8 pmkid[SAE_PMKID_LEN];
struct crypto_bignum *peer_commit_scalar;
int group;
int sync;
diff --git a/src/crypto/sha1-internal.c b/src/crypto/sha1-internal.c
index f6658e6..ffcba66 100644
--- a/src/crypto/sha1-internal.c
+++ b/src/crypto/sha1-internal.c
@@ -297,7 +297,6 @@
255);
}
/* Wipe variables */
- i = 0;
os_memset(context->buffer, 0, 64);
os_memset(context->state, 0, 20);
os_memset(context->count, 0, 8);
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index bca94d6..453b4de 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -96,6 +96,7 @@
#define TLS_CONN_EAP_FAST BIT(7)
#define TLS_CONN_DISABLE_TLSv1_0 BIT(8)
#define TLS_CONN_EXT_CERT_CHECK BIT(9)
+#define TLS_CONN_REQUIRE_OCSP_ALL BIT(10)
/**
* struct tls_connection_params - Parameters for TLS connection
@@ -140,6 +141,9 @@
* @flags: Parameter options (TLS_CONN_*)
* @ocsp_stapling_response: DER encoded file with cached OCSP stapling response
* or %NULL if OCSP is not enabled
+ * @ocsp_stapling_response_multi: DER encoded file with cached OCSP stapling
+ * response list (OCSPResponseList for ocsp_multi in RFC 6961) or %NULL if
+ * ocsp_multi is not enabled
*
* TLS connection parameters to be configured with tls_connection_set_params()
* and tls_global_set_params().
@@ -180,6 +184,7 @@
unsigned int flags;
const char *ocsp_stapling_response;
+ const char *ocsp_stapling_response_multi;
};
diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c
index b1bec4a..c4cd3c1 100644
--- a/src/crypto/tls_gnutls.c
+++ b/src/crypto/tls_gnutls.c
@@ -37,6 +37,8 @@
union tls_event_data *data);
void *cb_ctx;
int cert_in_cb;
+
+ char *ocsp_stapling_response;
};
struct tls_connection {
@@ -133,6 +135,7 @@
if (global->params_set)
gnutls_certificate_free_credentials(global->xcred);
os_free(global->session_data);
+ os_free(global->ocsp_stapling_response);
os_free(global);
}
@@ -347,6 +350,12 @@
if (conn == NULL || params == NULL)
return -1;
+ if (params->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
+ wpa_printf(MSG_INFO,
+ "GnuTLS: ocsp=3 not supported");
+ return -1;
+ }
+
if (params->flags & TLS_CONN_EXT_CERT_CHECK) {
wpa_printf(MSG_INFO,
"GnuTLS: tls_ext_cert_check=1 not supported");
@@ -602,6 +611,44 @@
}
+#if GNUTLS_VERSION_NUMBER >= 0x030103
+static int server_ocsp_status_req(gnutls_session_t session, void *ptr,
+ gnutls_datum_t *resp)
+{
+ struct tls_global *global = ptr;
+ char *cached;
+ size_t len;
+
+ if (!global->ocsp_stapling_response) {
+ wpa_printf(MSG_DEBUG, "GnuTLS: OCSP status callback - no response configured");
+ return GNUTLS_E_NO_CERTIFICATE_STATUS;
+ }
+
+ cached = os_readfile(global->ocsp_stapling_response, &len);
+ if (!cached) {
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: OCSP status callback - could not read response file (%s)",
+ global->ocsp_stapling_response);
+ return GNUTLS_E_NO_CERTIFICATE_STATUS;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "GnuTLS: OCSP status callback - send cached response");
+ resp->data = gnutls_malloc(len);
+ if (!resp->data) {
+ os_free(resp);
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ os_memcpy(resp->data, cached, len);
+ resp->size = len;
+ os_free(cached);
+
+ return GNUTLS_E_SUCCESS;
+}
+#endif /* 3.1.3 */
+
+
int tls_global_set_params(void *tls_ctx,
const struct tls_connection_params *params)
{
@@ -696,6 +743,17 @@
}
}
+#if GNUTLS_VERSION_NUMBER >= 0x030103
+ os_free(global->ocsp_stapling_response);
+ if (params->ocsp_stapling_response)
+ global->ocsp_stapling_response =
+ os_strdup(params->ocsp_stapling_response);
+ else
+ global->ocsp_stapling_response = NULL;
+ gnutls_certificate_set_ocsp_status_request_function(
+ global->xcred, server_ocsp_status_req, global);
+#endif /* 3.1.3 */
+
global->params_set = 1;
return 0;
diff --git a/src/crypto/tls_internal.c b/src/crypto/tls_internal.c
index 8b90d56..01a7c97 100644
--- a/src/crypto/tls_internal.c
+++ b/src/crypto/tls_internal.c
@@ -331,6 +331,13 @@
return -1;
}
+ if (params->ocsp_stapling_response)
+ cred->ocsp_stapling_response =
+ os_strdup(params->ocsp_stapling_response);
+ if (params->ocsp_stapling_response_multi)
+ cred->ocsp_stapling_response_multi =
+ os_strdup(params->ocsp_stapling_response_multi);
+
return 0;
#else /* CONFIG_TLS_INTERNAL_SERVER */
return -1;
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 1d75ba7..62277c4 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -3890,6 +3890,12 @@
if (conn == NULL)
return -1;
+ if (params->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: ocsp=3 not supported");
+ return -1;
+ }
+
/*
* If the engine isn't explicitly configured, and any of the
* cert/key fields are actually PKCS#11 URIs, then automatically
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index ed5e4a8..cdd1504 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -1735,9 +1735,6 @@
if (nl80211_init_bss(bss))
goto failed;
- if (linux_iface_up(drv->global->ioctl_sock, ifname) > 0)
- drv->start_iface_up = 1;
-
if (wpa_driver_nl80211_finish_drv_init(drv, set_addr, 1, driver_params))
goto failed;
@@ -2240,6 +2237,11 @@
if (!bss->if_dynamic && nl80211_get_ifmode(bss) == NL80211_IFTYPE_AP)
bss->static_ap = 1;
+ if (first &&
+ nl80211_get_ifmode(bss) != NL80211_IFTYPE_P2P_DEVICE &&
+ linux_iface_up(drv->global->ioctl_sock, bss->ifname) > 0)
+ drv->start_iface_up = 1;
+
if (wpa_driver_nl80211_capa(drv))
return -1;
diff --git a/src/eap_common/eap_eke_common.c b/src/eap_common/eap_eke_common.c
index 4dfdb3f..6217468 100644
--- a/src/eap_common/eap_eke_common.c
+++ b/src/eap_common/eap_eke_common.c
@@ -44,9 +44,7 @@
int dhlen;
dhlen = eap_eke_dh_len(dhgroup);
- if (dhlen < 0)
- return -1;
- if (encr != EAP_EKE_ENCR_AES128_CBC)
+ if (dhlen < 0 || encr != EAP_EKE_ENCR_AES128_CBC)
return -1;
return AES_BLOCK_SIZE + dhlen;
}
@@ -166,14 +164,11 @@
size_t pub_len, i;
generator = eap_eke_dh_generator(group);
- if (generator < 0 || generator > 255)
+ dh = eap_eke_dh_group(group);
+ if (generator < 0 || generator > 255 || !dh)
return -1;
gen = generator;
- dh = eap_eke_dh_group(group);
- if (dh == NULL)
- return -1;
-
/* x = random number 2 .. p-1 */
if (random_get_bytes(ret_priv, dh->prime_len))
return -1;
@@ -411,11 +406,8 @@
size_t len;
const struct dh_group *dh;
- if (sess->encr != EAP_EKE_ENCR_AES128_CBC)
- return -1;
-
dh = eap_eke_dh_group(sess->dhgroup);
- if (dh == NULL)
+ if (sess->encr != EAP_EKE_ENCR_AES128_CBC || !dh)
return -1;
/* Decrypt peer DHComponent */
@@ -635,6 +627,7 @@
if (*prot_len < block_size + data_len + pad + icv_len) {
wpa_printf(MSG_INFO, "EAP-EKE: Not enough room for Prot() data");
+ return -1;
}
pos = prot;
@@ -653,10 +646,8 @@
pos += pad;
}
- if (aes_128_cbc_encrypt(sess->ke, iv, e, data_len + pad) < 0)
- return -1;
-
- if (eap_eke_mac(sess->mac, sess->ki, e, data_len + pad, pos) < 0)
+ if (aes_128_cbc_encrypt(sess->ke, iv, e, data_len + pad) < 0 ||
+ eap_eke_mac(sess->mac, sess->ki, e, data_len + pad, pos) < 0)
return -1;
pos += icv_len;
@@ -684,9 +675,8 @@
else
return -1;
- if (prot_len < 2 * block_size + icv_len)
- return -1;
- if ((prot_len - icv_len) % block_size)
+ if (prot_len < 2 * block_size + icv_len ||
+ (prot_len - icv_len) % block_size)
return -1;
if (eap_eke_mac(sess->mac, sess->ki, prot + block_size,
@@ -737,22 +727,14 @@
sess->mac = mac;
sess->prf_len = eap_eke_prf_len(prf);
- if (sess->prf_len < 0)
- return -1;
sess->nonce_len = eap_eke_nonce_len(prf);
- if (sess->nonce_len < 0)
- return -1;
sess->auth_len = eap_eke_auth_len(prf);
- if (sess->auth_len < 0)
- return -1;
sess->dhcomp_len = eap_eke_dhcomp_len(sess->dhgroup, sess->encr);
- if (sess->dhcomp_len < 0)
- return -1;
sess->pnonce_len = eap_eke_pnonce_len(sess->mac);
- if (sess->pnonce_len < 0)
- return -1;
sess->pnonce_ps_len = eap_eke_pnonce_ps_len(sess->mac);
- if (sess->pnonce_ps_len < 0)
+ if (sess->prf_len < 0 || sess->nonce_len < 0 || sess->auth_len < 0 ||
+ sess->dhcomp_len < 0 || sess->pnonce_len < 0 ||
+ sess->pnonce_ps_len < 0)
return -1;
return 0;
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index c270832..406c162 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -196,8 +196,10 @@
if (config->ocsp)
params->flags |= TLS_CONN_REQUEST_OCSP;
- if (config->ocsp == 2)
+ if (config->ocsp >= 2)
params->flags |= TLS_CONN_REQUIRE_OCSP;
+ if (config->ocsp == 3)
+ params->flags |= TLS_CONN_REQUIRE_OCSP_ALL;
data->conn = tls_connection_init(data->ssl_ctx);
if (data->conn == NULL) {
wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
diff --git a/src/eap_peer/eap_tnc.c b/src/eap_peer/eap_tnc.c
index 25b9f12..e4294bb 100644
--- a/src/eap_peer/eap_tnc.c
+++ b/src/eap_peer/eap_tnc.c
@@ -10,6 +10,7 @@
#include "common.h"
#include "eap_i.h"
+#include "eap_config.h"
#include "tncc.h"
@@ -35,12 +36,16 @@
static void * eap_tnc_init(struct eap_sm *sm)
{
struct eap_tnc_data *data;
+ struct eap_peer_config *config = eap_get_config(sm);
data = os_zalloc(sizeof(*data));
if (data == NULL)
return NULL;
data->state = WAIT_START;
- data->fragment_size = 1300;
+ if (config && config->fragment_size)
+ data->fragment_size = config->fragment_size;
+ else
+ data->fragment_size = 1300;
data->tncc = tncc_init();
if (data->tncc == NULL) {
os_free(data);
@@ -345,11 +350,6 @@
ret->decision = DECISION_UNCOND_SUCC;
ret->allowNotifications = TRUE;
- if (data->out_buf) {
- data->state = PROC_MSG;
- return eap_tnc_build_msg(data, ret, id);
- }
-
if (tncs_done) {
resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1,
EAP_CODE_RESPONSE, eap_get_id(reqData));
diff --git a/src/eap_peer/tncc.c b/src/eap_peer/tncc.c
index 7ca956e..9965513 100644
--- a/src/eap_peer/tncc.c
+++ b/src/eap_peer/tncc.c
@@ -694,6 +694,8 @@
enum tncc_process_res res = TNCCS_PROCESS_OK_NO_RECOMMENDATION;
int recommendation_msg = 0;
+ wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Received IF-TNCCS message",
+ msg, len);
buf = dup_binstr(msg, len);
if (buf == NULL)
return TNCCS_PROCESS_ERROR;
diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c
index 0bcdb45..b24bbf8 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -308,7 +308,7 @@
int _errno = errno;
wpa_printf(MSG_INFO, "send[RADIUS,s=%d]: %s", s, strerror(errno));
if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
- _errno == EBADF || _errno == ENETUNREACH) {
+ _errno == EBADF || _errno == ENETUNREACH || _errno == EACCES) {
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
"Send failed - maybe interface status changed -"
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 669f658..64ef933 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -270,7 +270,7 @@
* much we can do here without knowing what
* exactly caused the server to misbehave.
*/
- wpa_dbg(sm->ctx->msg_ctx, MSG_INFO,
+ wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
"RSN: PMKID mismatch - authentication server may have derived different MSK?!");
return -1;
}
diff --git a/src/tls/tlsv1_client.c b/src/tls/tlsv1_client.c
index cc404c1..9bc0d21 100644
--- a/src/tls/tlsv1_client.c
+++ b/src/tls/tlsv1_client.c
@@ -111,7 +111,6 @@
pos += conn->rl.iv_size;
/* server_write_IV */
os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size);
- pos += conn->rl.iv_size;
} else {
/*
* Use IV field to set the mask value for TLS v1.1. A fixed
diff --git a/src/tls/tlsv1_client_ocsp.c b/src/tls/tlsv1_client_ocsp.c
index 2d5cdb9..1d7b68c 100644
--- a/src/tls/tlsv1_client_ocsp.c
+++ b/src/tls/tlsv1_client_ocsp.c
@@ -316,6 +316,7 @@
static enum tls_ocsp_result
tls_process_ocsp_responses(struct tlsv1_client *conn,
+ struct x509_certificate *cert,
struct x509_certificate *issuer, const u8 *resp,
size_t len)
{
@@ -335,8 +336,7 @@
hdr.class, hdr.tag);
return TLS_OCSP_INVALID;
}
- if (tls_process_ocsp_single_response(conn, conn->server_cert,
- issuer,
+ if (tls_process_ocsp_single_response(conn, cert, issuer,
hdr.payload, hdr.length,
&res) == 0)
return res;
@@ -350,8 +350,9 @@
static enum tls_ocsp_result
-tls_process_basic_ocsp_response(struct tlsv1_client *conn, const u8 *resp,
- size_t len)
+tls_process_basic_ocsp_response(struct tlsv1_client *conn,
+ struct x509_certificate *srv_cert,
+ const u8 *resp, size_t len)
{
struct asn1_hdr hdr;
const u8 *pos, *end;
@@ -365,6 +366,7 @@
struct x509_name name; /* used if key_hash == NULL */
char buf[100];
os_time_t produced_at;
+ enum tls_ocsp_result res;
wpa_hexdump(MSG_MSGDUMP, "OCSP: BasicOCSPResponse", resp, len);
@@ -594,20 +596,20 @@
/* Ignore for now. */
}
- if (!conn->server_cert) {
+ if (!srv_cert) {
wpa_printf(MSG_DEBUG,
"OCSP: Server certificate not known - cannot check OCSP response");
goto no_resp;
}
- if (conn->server_cert->next) {
+ if (srv_cert->next) {
/* Issuer has already been verified in the chain */
- issuer = conn->server_cert->next;
+ issuer = srv_cert->next;
} else {
/* Find issuer from the set of trusted certificates */
for (issuer = conn->cred ? conn->cred->trusted_certs : NULL;
issuer; issuer = issuer->next) {
- if (x509_name_compare(&conn->server_cert->issuer,
+ if (x509_name_compare(&srv_cert->issuer,
&issuer->subject) == 0)
break;
}
@@ -625,7 +627,7 @@
} else {
for (signer = certs; signer; signer = signer->next) {
if (!ocsp_responder_id_match(signer, &name, key_hash) ||
- x509_name_compare(&conn->server_cert->issuer,
+ x509_name_compare(&srv_cert->issuer,
&issuer->subject) != 0 ||
!(signer->ext_key_usage &
X509_EXT_KEY_USAGE_OCSP) ||
@@ -654,8 +656,13 @@
return TLS_OCSP_INVALID;
}
- return tls_process_ocsp_responses(conn, issuer, responses,
- responses_len);
+ res = tls_process_ocsp_responses(conn, srv_cert, issuer,
+ responses, responses_len);
+ if (res == TLS_OCSP_REVOKED)
+ srv_cert->ocsp_revoked = 1;
+ else if (res == TLS_OCSP_GOOD)
+ srv_cert->ocsp_good = 1;
+ return res;
no_resp:
x509_free_name(&name);
@@ -677,6 +684,9 @@
u8 resp_status;
struct asn1_oid oid;
char obuf[80];
+ struct x509_certificate *cert;
+ enum tls_ocsp_result res = TLS_OCSP_NO_RESPONSE;
+ enum tls_ocsp_result res_first = res;
wpa_hexdump(MSG_MSGDUMP, "TLSv1: OCSPResponse", resp, len);
@@ -769,5 +779,25 @@
return TLS_OCSP_INVALID;
}
- return tls_process_basic_ocsp_response(conn, hdr.payload, hdr.length);
+ cert = conn->server_cert;
+ while (cert) {
+ if (!cert->ocsp_good && !cert->ocsp_revoked) {
+ char sbuf[128];
+
+ x509_name_string(&cert->subject, sbuf, sizeof(sbuf));
+ wpa_printf(MSG_DEBUG,
+ "OCSP: Trying to find certificate status for %s",
+ sbuf);
+
+ res = tls_process_basic_ocsp_response(conn, cert,
+ hdr.payload,
+ hdr.length);
+ if (cert == conn->server_cert)
+ res_first = res;
+ }
+ if (res == TLS_OCSP_REVOKED || cert->issuer_trusted)
+ break;
+ cert = cert->next;
+ }
+ return res == TLS_OCSP_REVOKED ? res : res_first;
}
diff --git a/src/tls/tlsv1_client_read.c b/src/tls/tlsv1_client_read.c
index ff12452..244c3cb 100644
--- a/src/tls/tlsv1_client_read.c
+++ b/src/tls/tlsv1_client_read.c
@@ -326,7 +326,7 @@
union tls_event_data ev;
char subject[128];
- if (!conn->event_cb)
+ if (!conn->event_cb || !cert)
return;
os_memset(&ev, 0, sizeof(ev));
@@ -790,14 +790,40 @@
}
+static enum tls_ocsp_result
+tls_process_certificate_status_ocsp_response(struct tlsv1_client *conn,
+ const u8 *pos, size_t len)
+{
+ const u8 *end = pos + len;
+ u32 ocsp_resp_len;
+
+ /* 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 TLS_OCSP_INVALID;
+ }
+ 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 TLS_OCSP_INVALID;
+ }
+
+ return tls_process_ocsp_response(conn, pos, ocsp_resp_len);
+}
+
+
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;
+ struct x509_certificate *cert;
+ int depth;
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
wpa_printf(MSG_DEBUG,
@@ -850,6 +876,7 @@
* CertificateStatusType status_type;
* select (status_type) {
* case ocsp: OCSPResponse;
+ * case ocsp_multi: OCSPResponseList;
* } response;
* } CertificateStatus;
*/
@@ -862,32 +889,110 @@
wpa_printf(MSG_DEBUG, "TLSv1: CertificateStatus status_type %u",
status_type);
- if (status_type != 1 /* ocsp */) {
+ if (status_type == 1 /* ocsp */) {
+ res = tls_process_certificate_status_ocsp_response(
+ conn, pos, end - pos);
+ } else if (status_type == 2 /* ocsp_multi */) {
+ int good = 0, revoked = 0;
+ u32 resp_len;
+
+ res = TLS_OCSP_NO_RESPONSE;
+
+ /*
+ * opaque OCSPResponse<0..2^24-1>;
+ *
+ * struct {
+ * OCSPResponse ocsp_response_list<1..2^24-1>;
+ * } OCSPResponseList;
+ */
+ if (end - pos < 3) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Truncated OCSPResponseList");
+ res = TLS_OCSP_INVALID;
+ goto done;
+ }
+ resp_len = WPA_GET_BE24(pos);
+ pos += 3;
+ if (end - pos < resp_len) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Truncated OCSPResponseList(len=%u)",
+ resp_len);
+ res = TLS_OCSP_INVALID;
+ goto done;
+ }
+ end = pos + resp_len;
+
+ while (end - pos >= 3) {
+ resp_len = WPA_GET_BE24(pos);
+ pos += 3;
+ if (resp_len > end - pos) {
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Truncated OCSPResponse(len=%u; left=%d) in ocsp_multi",
+ resp_len, (int) (end - pos));
+ res = TLS_OCSP_INVALID;
+ break;
+ }
+ if (!resp_len)
+ continue; /* Skip an empty response */
+ res = tls_process_certificate_status_ocsp_response(
+ conn, pos - 3, resp_len + 3);
+ if (res == TLS_OCSP_REVOKED)
+ revoked++;
+ else if (res == TLS_OCSP_GOOD)
+ good++;
+ pos += resp_len;
+ }
+
+ if (revoked)
+ res = TLS_OCSP_REVOKED;
+ else if (good)
+ res = TLS_OCSP_GOOD;
+ } else {
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);
+done:
+ if (res == TLS_OCSP_REVOKED) {
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_CERTIFICATE_REVOKED);
+ for (cert = conn->server_cert, depth = 0; cert;
+ cert = cert->next, depth++) {
+ if (cert->ocsp_revoked) {
+ tls_cert_chain_failure_event(
+ conn, depth, cert, TLS_FAIL_REVOKED,
+ "certificate revoked");
+ }
+ }
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;
+ if (conn->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
+ /*
+ * Verify that each certificate on the chain that is not part
+ * of the trusted certificates has a good status. If not,
+ * terminate handshake.
+ */
+ for (cert = conn->server_cert, depth = 0; cert;
+ cert = cert->next, depth++) {
+ if (!cert->ocsp_good) {
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE);
+ tls_cert_chain_failure_event(
+ conn, depth, cert,
+ TLS_FAIL_UNSPECIFIED,
+ "bad certificate status response");
+ return -1;
+ }
+ if (cert->issuer_trusted)
+ break;
+ }
+ }
+
+ if ((conn->flags & TLS_CONN_REQUIRE_OCSP) && res != TLS_OCSP_GOOD) {
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ res == TLS_OCSP_INVALID ? TLS_ALERT_DECODE_ERROR :
TLS_ALERT_BAD_CERTIFICATE_STATUS_RESPONSE);
if (conn->server_cert)
tls_cert_chain_failure_event(
@@ -895,28 +1000,8 @@
TLS_FAIL_UNSPECIFIED,
"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);
- if (conn->server_cert)
- tls_cert_chain_failure_event(
- conn, 0, conn->server_cert,
- TLS_FAIL_UNSPECIFIED,
- "bad certificate status response");
- 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:
diff --git a/src/tls/tlsv1_client_write.c b/src/tls/tlsv1_client_write.c
index 8e8cb5e..04d895e 100644
--- a/src/tls/tlsv1_client_write.c
+++ b/src/tls/tlsv1_client_write.c
@@ -192,6 +192,46 @@
pos += 2;
WPA_PUT_BE16(pos, 0); /* request_extensions(empty) */
pos += 2;
+
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Add status_request_v2 extension for OCSP stapling");
+ /* ExtensionsType extension_type = status_request_v2(17) */
+ WPA_PUT_BE16(pos, TLS_EXT_STATUS_REQUEST_V2);
+ pos += 2;
+ /* opaque extension_data<0..2^16-1> length */
+ WPA_PUT_BE16(pos, 7);
+ pos += 2;
+
+ /*
+ * RFC 6961, 2.2:
+ * struct {
+ * CertificateStatusType status_type;
+ * uint16 request_length;
+ * select (status_type) {
+ * case ocsp: OCSPStatusRequest;
+ * case ocsp_multi: OCSPStatusRequest;
+ * } request;
+ * } CertificateStatusRequestItemV2;
+ *
+ * enum { ocsp(1), ocsp_multi(2), (255) } CertificateStatusType;
+ *
+ * struct {
+ * CertificateStatusRequestItemV2
+ * certificate_status_req_list<1..2^16-1>;
+ * } CertificateStatusRequestListV2;
+ */
+
+ /* certificate_status_req_list<1..2^16-1> */
+ WPA_PUT_BE16(pos, 5);
+ pos += 2;
+
+ /* CertificateStatusRequestItemV2 */
+ *pos++ = 2; /* status_type = ocsp_multi(2) */
+ /* OCSPStatusRequest as shown above for v1 */
+ 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)
diff --git a/src/tls/tlsv1_common.h b/src/tls/tlsv1_common.h
index 7a252fe..e30b15a 100644
--- a/src/tls/tlsv1_common.h
+++ b/src/tls/tlsv1_common.h
@@ -170,6 +170,7 @@
#define TLS_EXT_TRUNCATED_HMAC 4 /* RFC 4366 */
#define TLS_EXT_STATUS_REQUEST 5 /* RFC 4366 */
#define TLS_EXT_SIGNATURE_ALGORITHMS 13 /* RFC 5246 */
+#define TLS_EXT_STATUS_REQUEST_V2 17 /* RFC 6961 */
#define TLS_EXT_SESSION_TICKET 35 /* RFC 4507 */
#define TLS_EXT_PAC_OPAQUE TLS_EXT_SESSION_TICKET /* EAP-FAST terminology */
diff --git a/src/tls/tlsv1_cred.c b/src/tls/tlsv1_cred.c
index 92f97c7..52c1ae0 100644
--- a/src/tls/tlsv1_cred.c
+++ b/src/tls/tlsv1_cred.c
@@ -36,6 +36,8 @@
crypto_private_key_free(cred->key);
os_free(cred->dh_p);
os_free(cred->dh_g);
+ os_free(cred->ocsp_stapling_response);
+ os_free(cred->ocsp_stapling_response_multi);
os_free(cred);
}
diff --git a/src/tls/tlsv1_cred.h b/src/tls/tlsv1_cred.h
index b4bfe38..716e93c 100644
--- a/src/tls/tlsv1_cred.h
+++ b/src/tls/tlsv1_cred.h
@@ -24,6 +24,9 @@
size_t dh_p_len;
u8 *dh_g; /* generator */
size_t dh_g_len;
+
+ char *ocsp_stapling_response;
+ char *ocsp_stapling_response_multi;
};
diff --git a/src/tls/tlsv1_server_i.h b/src/tls/tlsv1_server_i.h
index 96d79b3..29c6678 100644
--- a/src/tls/tlsv1_server_i.h
+++ b/src/tls/tlsv1_server_i.h
@@ -55,6 +55,9 @@
void *log_cb_ctx;
int use_session_ticket;
+ unsigned int status_request:1;
+ unsigned int status_request_v2:1;
+ unsigned int status_request_multi:1;
u8 *dh_secret;
size_t dh_secret_len;
diff --git a/src/tls/tlsv1_server_read.c b/src/tls/tlsv1_server_read.c
index 8347d7a..4aa8a01 100644
--- a/src/tls/tlsv1_server_read.c
+++ b/src/tls/tlsv1_server_read.c
@@ -46,6 +46,78 @@
}
+static void tls_process_status_request_item(struct tlsv1_server *conn,
+ const u8 *req, size_t req_len)
+{
+ const u8 *pos, *end;
+ u8 status_type;
+
+ pos = req;
+ end = req + req_len;
+
+ /*
+ * RFC 6961, 2.2:
+ * struct {
+ * CertificateStatusType status_type;
+ * uint16 request_length;
+ * select (status_type) {
+ * case ocsp: OCSPStatusRequest;
+ * case ocsp_multi: OCSPStatusRequest;
+ * } request;
+ * } CertificateStatusRequestItemV2;
+ *
+ * enum { ocsp(1), ocsp_multi(2), (255) } CertificateStatusType;
+ */
+
+ if (end - pos < 1)
+ return; /* Truncated data */
+
+ status_type = *pos++;
+ wpa_printf(MSG_DEBUG, "TLSv1: CertificateStatusType %u", status_type);
+ if (status_type != 1 && status_type != 2)
+ return; /* Unsupported status type */
+ /*
+ * For now, only OCSP stapling is supported, so ignore the specific
+ * request, if any.
+ */
+ wpa_hexdump(MSG_DEBUG, "TLSv1: OCSPStatusRequest", pos, end - pos);
+
+ if (status_type == 2)
+ conn->status_request_multi = 1;
+}
+
+
+static void tls_process_status_request_v2(struct tlsv1_server *conn,
+ const u8 *ext, size_t ext_len)
+{
+ const u8 *pos, *end;
+
+ conn->status_request_v2 = 1;
+
+ pos = ext;
+ end = ext + ext_len;
+
+ /*
+ * RFC 6961, 2.2:
+ * struct {
+ * CertificateStatusRequestItemV2
+ * certificate_status_req_list<1..2^16-1>;
+ * } CertificateStatusRequestListV2;
+ */
+
+ while (end - pos >= 2) {
+ u16 len;
+
+ len = WPA_GET_BE16(pos);
+ pos += 2;
+ if (len > end - pos)
+ break; /* Truncated data */
+ tls_process_status_request_item(conn, pos, len);
+ pos += len;
+ }
+}
+
+
static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
const u8 *in_data, size_t *in_len)
{
@@ -267,6 +339,11 @@
ext_len);
conn->session_ticket_len = ext_len;
}
+ } else if (ext_type == TLS_EXT_STATUS_REQUEST) {
+ conn->status_request = 1;
+ } else if (ext_type == TLS_EXT_STATUS_REQUEST_V2) {
+ tls_process_status_request_v2(conn, pos,
+ ext_len);
}
pos += ext_len;
diff --git a/src/tls/tlsv1_server_write.c b/src/tls/tlsv1_server_write.c
index e7c5e22..bdc6c11 100644
--- a/src/tls/tlsv1_server_write.c
+++ b/src/tls/tlsv1_server_write.c
@@ -42,7 +42,7 @@
static int tls_write_server_hello(struct tlsv1_server *conn,
u8 **msgpos, u8 *end)
{
- u8 *pos, *rhdr, *hs_start, *hs_length;
+ u8 *pos, *rhdr, *hs_start, *hs_length, *ext_start;
struct os_time now;
size_t rlen;
@@ -97,6 +97,32 @@
/* CompressionMethod compression_method */
*pos++ = TLS_COMPRESSION_NULL;
+ /* Extension */
+ ext_start = pos;
+ pos += 2;
+
+ if (conn->status_request) {
+ /* Add a status_request extension with empty extension_data */
+ /* 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, 0);
+ pos += 2;
+ }
+
+ if (conn->status_request_v2) {
+ /*
+ Add a status_request_v2 extension with empty extension_data
+ */
+ /* ExtensionsType extension_type = status_request_v2(17) */
+ WPA_PUT_BE16(pos, TLS_EXT_STATUS_REQUEST_V2);
+ pos += 2;
+ /* opaque extension_data<0..2^16-1> length */
+ WPA_PUT_BE16(pos, 0);
+ pos += 2;
+ }
+
if (conn->session_ticket && conn->session_ticket_cb) {
int res = conn->session_ticket_cb(
conn->session_ticket_cb_ctx,
@@ -133,6 +159,11 @@
*/
}
+ if (pos == ext_start + 2)
+ pos -= 2; /* no extensions */
+ else
+ WPA_PUT_BE16(ext_start, pos - ext_start - 2);
+
WPA_PUT_BE24(hs_length, pos - hs_length - 3);
tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
@@ -244,6 +275,93 @@
}
+static int tls_write_server_certificate_status(struct tlsv1_server *conn,
+ u8 **msgpos, u8 *end,
+ int ocsp_multi,
+ char *ocsp_resp,
+ size_t ocsp_resp_len)
+{
+ u8 *pos, *rhdr, *hs_start, *hs_length;
+ size_t rlen;
+
+ if (!ocsp_resp) {
+ /*
+ * Client did not request certificate status or there is no
+ * matching response cached.
+ */
+ return 0;
+ }
+
+ pos = *msgpos;
+ if (TLS_RECORD_HEADER_LEN + 1 + 3 + 1 + 3 + ocsp_resp_len >
+ (unsigned int) (end - pos)) {
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ tlsv1_server_log(conn, "Send CertificateStatus (multi=%d)", ocsp_multi);
+ rhdr = pos;
+ pos += TLS_RECORD_HEADER_LEN;
+
+ /* opaque fragment[TLSPlaintext.length] */
+
+ /* Handshake */
+ hs_start = pos;
+ /* HandshakeType msg_type */
+ *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_STATUS;
+ /* uint24 length (to be filled) */
+ hs_length = pos;
+ pos += 3;
+
+ /* body - CertificateStatus
+ *
+ * struct {
+ * CertificateStatusType status_type;
+ * select (status_type) {
+ * case ocsp: OCSPResponse;
+ * case ocsp_multi: OCSPResponseList;
+ * } response;
+ * } CertificateStatus;
+ *
+ * opaque OCSPResponse<1..2^24-1>;
+ *
+ * struct {
+ * OCSPResponse ocsp_response_list<1..2^24-1>;
+ * } OCSPResponseList;
+ */
+
+ /* CertificateStatusType status_type */
+ if (ocsp_multi)
+ *pos++ = 2; /* ocsp_multi(2) */
+ else
+ *pos++ = 1; /* ocsp(1) */
+ /* uint24 length of OCSPResponse */
+ WPA_PUT_BE24(pos, ocsp_resp_len);
+ pos += 3;
+ os_memcpy(pos, ocsp_resp, ocsp_resp_len);
+ pos += ocsp_resp_len;
+
+ WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+
+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+ rhdr, end - rhdr, hs_start, pos - hs_start,
+ &rlen) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
+ tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ pos = rhdr + rlen;
+
+ tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+
+ *msgpos = pos;
+
+ return 0;
+}
+
+
static int tls_write_server_key_exchange(struct tlsv1_server *conn,
u8 **msgpos, u8 *end)
{
@@ -810,24 +928,46 @@
{
u8 *msg, *end, *pos;
size_t msglen;
+ int ocsp_multi = 0;
+ char *ocsp_resp = NULL;
+ size_t ocsp_resp_len = 0;
*out_len = 0;
- msglen = 1000 + tls_server_cert_chain_der_len(conn);
+ if (conn->status_request_multi &&
+ conn->cred->ocsp_stapling_response_multi) {
+ ocsp_resp = os_readfile(
+ conn->cred->ocsp_stapling_response_multi,
+ &ocsp_resp_len);
+ ocsp_multi = 1;
+ } else if ((conn->status_request || conn->status_request_v2) &&
+ conn->cred->ocsp_stapling_response) {
+ ocsp_resp = os_readfile(conn->cred->ocsp_stapling_response,
+ &ocsp_resp_len);
+ }
+ if (!ocsp_resp)
+ ocsp_resp_len = 0;
+
+ msglen = 1000 + tls_server_cert_chain_der_len(conn) + ocsp_resp_len;
msg = os_malloc(msglen);
- if (msg == NULL)
+ if (msg == NULL) {
+ os_free(ocsp_resp);
return NULL;
+ }
pos = msg;
end = msg + msglen;
if (tls_write_server_hello(conn, &pos, end) < 0) {
os_free(msg);
+ os_free(ocsp_resp);
return NULL;
}
if (conn->use_session_ticket) {
+ os_free(ocsp_resp);
+
/* Abbreviated handshake using session ticket; RFC 4507 */
if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 ||
tls_write_server_finished(conn, &pos, end) < 0) {
@@ -844,12 +984,16 @@
/* Full handshake */
if (tls_write_server_certificate(conn, &pos, end) < 0 ||
+ tls_write_server_certificate_status(conn, &pos, end, ocsp_multi,
+ ocsp_resp, ocsp_resp_len) < 0 ||
tls_write_server_key_exchange(conn, &pos, end) < 0 ||
tls_write_server_certificate_request(conn, &pos, end) < 0 ||
tls_write_server_hello_done(conn, &pos, end) < 0) {
os_free(msg);
+ os_free(ocsp_resp);
return NULL;
}
+ os_free(ocsp_resp);
*out_len = pos - msg;
diff --git a/src/tls/x509v3.c b/src/tls/x509v3.c
index 5521390..75f222c 100644
--- a/src/tls/x509v3.c
+++ b/src/tls/x509v3.c
@@ -1339,6 +1339,7 @@
size_t left;
char sbuf[128];
unsigned long value;
+ const u8 *subject_dn;
/* tbsCertificate TBSCertificate ::= SEQUENCE */
if (asn1_get_next(buf, len, &hdr) < 0 ||
@@ -1436,7 +1437,6 @@
return -1;
/* subject Name */
- const u8 *subject_dn;
subject_dn = pos;
if (x509_parse_name(pos, end - pos, &cert->subject, &pos))
return -1;
@@ -2038,6 +2038,7 @@
os_get_time(&now);
for (cert = chain, idx = 0; cert; cert = cert->next, idx++) {
+ cert->issuer_trusted = 0;
x509_name_string(&cert->subject, buf, sizeof(buf));
wpa_printf(MSG_DEBUG, "X509: %lu: %s", idx, buf);
@@ -2123,6 +2124,7 @@
wpa_printf(MSG_DEBUG, "X509: Trusted certificate "
"found to complete the chain");
+ cert->issuer_trusted = 1;
chain_trusted = 1;
}
}
diff --git a/src/tls/x509v3.h b/src/tls/x509v3.h
index dcdb4a3..7df8e2a 100644
--- a/src/tls/x509v3.h
+++ b/src/tls/x509v3.h
@@ -106,6 +106,11 @@
size_t cert_len;
const u8 *tbs_cert_start;
size_t tbs_cert_len;
+
+ /* Meta data used for certificate validation */
+ unsigned int ocsp_good:1;
+ unsigned int ocsp_revoked:1;
+ unsigned int issuer_trusted:1;
};
enum {
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index f62b30a..95690bf 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -856,6 +856,12 @@
endif
endif
+ifdef CONFIG_ACS
+L_CFLAGS += -DCONFIG_ACS
+OBJS += src/ap/acs.c
+LIBS += -lm
+endif
+
ifdef CONFIG_PCSC
# PC/SC interface for smartcards (USIM, GSM SIM)
L_CFLAGS += -DPCSC_FUNCS -I/usr/include/PCSC
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 6bab7d1..8fa35e5 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -6,6 +6,17 @@
CFLAGS = -MMD -O2 -Wall -g
endif
+ifdef LIBS
+# If LIBS is set with some global build system defaults, clone those for
+# LIBS_c and LIBS_p to cover wpa_passphrase and wpa_cli as well.
+ifndef LIBS_c
+LIBS_c := $(LIBS)
+endif
+ifndef LIBS_p
+LIBS_p := $(LIBS)
+endif
+endif
+
export LIBDIR ?= /usr/local/lib/
export INCDIR ?= /usr/local/include/
export BINDIR ?= /usr/local/sbin/
@@ -884,6 +895,12 @@
endif
endif
+ifdef CONFIG_ACS
+CFLAGS += -DCONFIG_ACS
+OBJS += ../src/ap/acs.o
+LIBS += -lm
+endif
+
ifdef CONFIG_PCSC
# PC/SC interface for smartcards (USIM, GSM SIM)
CFLAGS += -DPCSC_FUNCS -I/usr/include/PCSC
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 27fa2a9..105fb1c 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -213,6 +213,14 @@
if (wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf))
return -1;
+#ifdef CONFIG_ACS
+ if (ssid->acs) {
+ /* Setting channel to 0 in order to enable ACS */
+ conf->channel = 0;
+ wpa_printf(MSG_DEBUG, "Use automatic channel selection");
+ }
+#endif /* CONFIG_ACS */
+
if (ieee80211_is_dfs(ssid->frequency) && wpa_s->conf->country[0]) {
conf->ieee80211h = 1;
conf->ieee80211d = 1;
@@ -558,6 +566,11 @@
{
struct wpa_supplicant *wpa_s = ctx;
+#ifdef CONFIG_ACS
+ if (wpa_s->current_ssid && wpa_s->current_ssid->acs)
+ wpa_s->assoc_freq = wpa_s->ap_iface->freq;
+#endif /* CONFIG_ACS */
+
wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
if (wpa_s->ap_configured_cb)
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index f2ae4fd..85717e9 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1920,6 +1920,9 @@
{ INT_RANGE(mixed_cell, 0, 1) },
{ INT_RANGE(frequency, 0, 65000) },
{ INT_RANGE(fixed_freq, 0, 1) },
+#ifdef CONFIG_ACS
+ { INT_RANGE(acs, 0, 1) },
+#endif /* CONFIG_ACS */
#ifdef CONFIG_MESH
{ FUNC(mesh_basic_rates) },
{ INT(dot11MeshMaxRetries) },
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 80e3e56..6ea113e 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -747,6 +747,9 @@
INT(no_auto_peer);
INT(frequency);
INT(fixed_freq);
+#ifdef CONFIG_ACS
+ INT(acs);
+#endif /* CONFIG_ACS */
write_int(f, "proactive_key_caching", ssid->proactive_key_caching, -1);
INT(disabled);
INT(peerkey);
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index de8157a..b296826 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -431,6 +431,18 @@
*/
int fixed_freq;
+#ifdef CONFIG_ACS
+ /**
+ * ACS - Automatic Channel Selection for AP mode
+ *
+ * If present, it will be handled together with frequency.
+ * frequency will be used to determine hardware mode only, when it is
+ * used for both hardware mode and channel when used alone. This will
+ * force the channel to be set to 0, thus enabling ACS.
+ */
+ int acs;
+#endif /* CONFIG_ACS */
+
/**
* mesh_basic_rates - BSS Basic rate set for mesh network
*
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index d1274f6..ecf8d2d 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -3937,6 +3937,15 @@
}
#endif /* CONFIG_FIPS */
+#ifdef CONFIG_ACS
+ if (os_strcmp(field, "acs") == 0) {
+ res = os_snprintf(buf, buflen, "ACS");
+ if (os_snprintf_error(buflen, res))
+ return -1;
+ return res;
+ }
+#endif /* CONFIG_ACS */
+
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
field);
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index 2c71b2d..7b36751 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -1058,6 +1058,9 @@
struct sockaddr_un from;
socklen_t fromlen = sizeof(from);
+ if (priv->sock == -1)
+ return;
+
for (;;) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor to "
"attach", priv->wpa_s->ifname);
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index e2e4bdc..8b1d121 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -513,3 +513,29 @@
# OS X builds. This is only for building eapol_test.
#CONFIG_OSX=y
+
+# Automatic Channel Selection
+# This will allow wpa_supplicant to pick the channel automatically when channel
+# is set to "0".
+#
+# TODO: Extend parser to be able to parse "channel=acs_survey" as an alternative
+# to "channel=0". This would enable us to eventually add other ACS algorithms in
+# similar way.
+#
+# Automatic selection is currently only done through initialization, later on
+# we hope to do background checks to keep us moving to more ideal channels as
+# time goes by. ACS is currently only supported through the nl80211 driver and
+# your driver must have survey dump capability that is filled by the driver
+# during scanning.
+#
+# TODO: In analogy to hostapd be able to customize the ACS survey algorithm with
+# a newly to create wpa_supplicant.conf variable acs_num_scans.
+#
+# Supported ACS drivers:
+# * ath9k
+# * ath5k
+# * ath10k
+#
+# For more details refer to:
+# http://wireless.kernel.org/en/users/Documentation/acs
+#CONFIG_ACS=y
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 1ac177e..3c60cc1 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -3942,6 +3942,22 @@
data->mesh_peer.ie_len);
#endif /* CONFIG_MESH */
break;
+ case EVENT_SURVEY:
+#ifdef CONFIG_AP
+ if (!wpa_s->ap_iface)
+ break;
+ hostapd_event_get_survey(wpa_s->ap_iface,
+ &data->survey_results);
+#endif /* CONFIG_AP */
+ break;
+ case EVENT_ACS_CHANNEL_SELECTED:
+#ifdef CONFIG_ACS
+ if (!wpa_s->ap_iface)
+ break;
+ hostapd_acs_channel_selected(wpa_s->ap_iface->bss[0],
+ &data->acs_selected_channels);
+#endif /* CONFIG_ACS */
+ break;
default:
wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
break;
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
index 7ebd4d2..4caa55c 100644
--- a/wpa_supplicant/mesh_mpm.c
+++ b/wpa_supplicant/mesh_mpm.c
@@ -20,11 +20,11 @@
#include "mesh_rsn.h"
struct mesh_peer_mgmt_ie {
- const u8 *proto_id;
- const u8 *llid;
- const u8 *plid;
- const u8 *reason;
- const u8 *pmk;
+ const u8 *proto_id; /* Mesh Peering Protocol Identifier (2 octets) */
+ const u8 *llid; /* Local Link ID (2 octets) */
+ const u8 *plid; /* Peer Link ID (conditional, 2 octets) */
+ const u8 *reason; /* Reason Code (conditional, 2 octets) */
+ const u8 *chosen_pmk; /* Chosen PMK (optional, 16 octets) */
};
static void plink_timer(void *eloop_ctx, void *user_data);
@@ -72,10 +72,10 @@
{
os_memset(mpm_ie, 0, sizeof(*mpm_ie));
- /* remove optional PMK at end */
- if (len >= 16) {
- len -= 16;
- mpm_ie->pmk = ie + len - 16;
+ /* Remove optional Chosen PMK field at end */
+ if (len >= SAE_PMKID_LEN) {
+ mpm_ie->chosen_pmk = ie + len - SAE_PMKID_LEN;
+ len -= SAE_PMKID_LEN;
}
if ((action_field == PLINK_OPEN && len != 4) ||
@@ -101,8 +101,8 @@
len -= 2;
}
- /* plid, present for confirm, and possibly close */
- if (len)
+ /* Peer Link ID, present for confirm, and possibly close */
+ if (len >= 2)
mpm_ie->plid = ie;
return 0;
@@ -1014,6 +1014,7 @@
if ((mconf->security & MESH_CONF_SEC_AMPE) &&
mesh_rsn_process_ampe(wpa_s, sta, &elems,
&mgmt->u.action.category,
+ peer_mgmt_ie.chosen_pmk,
ies, ie_len)) {
wpa_printf(MSG_DEBUG, "MPM: RSN process rejected frame");
return;
diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c
index 747f1ae..5d88274 100644
--- a/wpa_supplicant/mesh_rsn.c
+++ b/wpa_supplicant/mesh_rsn.c
@@ -328,10 +328,7 @@
void mesh_rsn_get_pmkid(struct mesh_rsn *rsn, struct sta_info *sta, u8 *pmkid)
{
- /* don't expect wpa auth to cache the pmkid for now */
- rsn_pmkid(sta->sae->pmk, PMK_LEN, rsn->wpa_s->own_addr,
- sta->addr, pmkid,
- wpa_key_mgmt_sha256(wpa_auth_sta_key_mgmt(sta->wpa_sm)));
+ os_memcpy(pmkid, sta->sae->pmkid, SAE_PMKID_LEN);
}
@@ -503,6 +500,7 @@
int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta,
struct ieee802_11_elems *elems, const u8 *cat,
+ const u8 *chosen_pmk,
const u8 *start, size_t elems_len)
{
int ret = 0;
@@ -516,6 +514,12 @@
const size_t aad_len[] = { ETH_ALEN, ETH_ALEN,
(elems->mic - 2) - cat };
+ if (chosen_pmk && os_memcmp(chosen_pmk, sta->sae->pmkid, PMKID_LEN)) {
+ wpa_msg(wpa_s, MSG_DEBUG,
+ "Mesh RSN: Invalid PMKID (Chosen PMK did not match calculated PMKID)");
+ return -1;
+ }
+
if (!elems->mic || elems->mic_len < AES_BLOCK_SIZE) {
wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: missing mic ie");
return -1;
diff --git a/wpa_supplicant/mesh_rsn.h b/wpa_supplicant/mesh_rsn.h
index b1471b2..89601d4 100644
--- a/wpa_supplicant/mesh_rsn.h
+++ b/wpa_supplicant/mesh_rsn.h
@@ -30,6 +30,7 @@
const u8 *cat, struct wpabuf *buf);
int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta,
struct ieee802_11_elems *elems, const u8 *cat,
+ const u8 *chosen_pmk,
const u8 *start, size_t elems_len);
void mesh_auth_timer(void *eloop_ctx, void *user_data);
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 45dae50..d6acbd0 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -774,13 +774,6 @@
case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_NEW:
case P2PS_SETUP_GROUP_OWNER | P2PS_SETUP_CLIENT:
- /*
- * Peer has an active GO, so if the role allows it and
- * we do not have any active roles, become client.
- */
- if ((role & P2PS_SETUP_CLIENT) && !go_wpa_s && !cli_wpa_s)
- return P2PS_SETUP_CLIENT;
-
if (cli_wpa_s)
conncap = P2PS_SETUP_GROUP_OWNER;
else {
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 29683bc..e588992 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -5227,7 +5227,7 @@
if (global->params.wait_for_monitor) {
for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
- if (wpa_s->ctrl_iface)
+ if (wpa_s->ctrl_iface && !wpa_s->p2p_mgmt)
wpa_supplicant_ctrl_iface_wait(
wpa_s->ctrl_iface);
}
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index e33b720..e204061 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -586,6 +586,8 @@
# 0 = do not use OCSP stapling (TLS certificate status extension)
# 1 = try to use OCSP stapling, but not require response
# 2 = require valid OCSP stapling response
+# 3 = require valid OCSP stapling response for all not-trusted
+# certificates in the server certificate chain
#
# sim_num: Identifier for which SIM to use in multi-SIM devices
#
@@ -748,8 +750,18 @@
# IEEE8021X = IEEE 802.1X using EAP authentication and (optionally) dynamically
# generated WEP keys
# NONE = WPA is not used; plaintext or static WEP could be used
+# WPA-NONE = WPA-None for IBSS (deprecated; use proto=RSN key_mgmt=WPA-PSK
+# instead)
+# FT-PSK = Fast BSS Transition (IEEE 802.11r) with pre-shared key
+# FT-EAP = Fast BSS Transition (IEEE 802.11r) with EAP authentication
# WPA-PSK-SHA256 = Like WPA-PSK but using stronger SHA256-based algorithms
# WPA-EAP-SHA256 = Like WPA-EAP but using stronger SHA256-based algorithms
+# SAE = Simultaneous authentication of equals; pre-shared key/password -based
+# authentication with stronger security than WPA-PSK especially when using
+# not that strong password
+# FT-SAE = SAE with FT
+# WPA-EAP-SUITE-B = Suite B 128-bit level
+# WPA-EAP-SUITE-B-192 = Suite B 192-bit level
# If not set, this defaults to: WPA-PSK WPA-EAP
#
# ieee80211w: whether management frame protection is enabled
@@ -1074,6 +1086,8 @@
# 0 = do not use OCSP stapling (TLS certificate status extension)
# 1 = try to use OCSP stapling, but not require response
# 2 = require valid OCSP stapling response
+# 3 = require valid OCSP stapling response for all not-trusted
+# certificates in the server certificate chain
#
# openssl_ciphers: OpenSSL specific cipher configuration
# This can be used to override the global openssl_ciphers configuration