aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJouni Malinen <jouni@codeaurora.org>2019-10-17 13:54:05 (GMT)
committerJouni Malinen <j@w1.fi>2019-10-17 13:54:05 (GMT)
commit6d6c887751bf6cb9a30a64640766478e7b45b6c4 (patch)
treeda3aaca581c38bdde327ec9c68da2b0e2ba2938a
parent8401cdc8d4b6e31764431683a1fc553e0f347c8e (diff)
downloadhostap-6d6c887751bf6cb9a30a64640766478e7b45b6c4.zip
hostap-6d6c887751bf6cb9a30a64640766478e7b45b6c4.tar.gz
hostap-6d6c887751bf6cb9a30a64640766478e7b45b6c4.tar.bz2
SAE: Add RSNXE in Association Request and EAPOL-Key msg 2/4
Add the new RSNXE into (Re)Association Request frames and EAPOL-Key msg 2/4 when using SAE with hash-to-element mechanism enabled. This allows the AP to verify that there was no downgrade attack when both PWE derivation mechanisms are enabled. Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
-rw-r--r--src/rsn_supp/wpa.c131
-rw-r--r--src/rsn_supp/wpa.h6
-rw-r--r--src/rsn_supp/wpa_i.h3
-rw-r--r--src/rsn_supp/wpa_ie.c22
-rw-r--r--src/rsn_supp/wpa_ie.h1
-rw-r--r--wpa_supplicant/events.c21
-rw-r--r--wpa_supplicant/sme.c15
-rw-r--r--wpa_supplicant/wpa_supplicant.c18
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h3
9 files changed, 187 insertions, 33 deletions
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index f5231c1..504feaf 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -655,51 +655,51 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
kde = sm->assoc_wpa_ie;
kde_len = sm->assoc_wpa_ie_len;
+ kde_buf = os_malloc(kde_len +
+ 2 + RSN_SELECTOR_LEN + 3 +
+ sm->assoc_rsnxe_len +
+ 2 + RSN_SELECTOR_LEN + 1);
+ if (!kde_buf)
+ goto failed;
+ os_memcpy(kde_buf, kde, kde_len);
+ kde = kde_buf;
#ifdef CONFIG_OCV
if (wpa_sm_ocv_enabled(sm)) {
struct wpa_channel_info ci;
u8 *pos;
+ pos = kde + kde_len;
if (wpa_sm_channel_info(sm, &ci) != 0) {
wpa_printf(MSG_WARNING,
"Failed to get channel info for OCI element in EAPOL-Key 2/4");
goto failed;
}
- kde_buf = os_malloc(kde_len + 2 + RSN_SELECTOR_LEN + 3);
- if (!kde_buf) {
- wpa_printf(MSG_WARNING,
- "Failed to allocate memory for KDE with OCI in EAPOL-Key 2/4");
- goto failed;
- }
-
- os_memcpy(kde_buf, kde, kde_len);
- kde = kde_buf;
- pos = kde + kde_len;
if (ocv_insert_oci_kde(&ci, &pos) < 0)
goto failed;
kde_len = pos - kde;
}
#endif /* CONFIG_OCV */
+ if (sm->assoc_rsnxe && sm->assoc_rsnxe_len) {
+ os_memcpy(kde + kde_len, sm->assoc_rsnxe, sm->assoc_rsnxe_len);
+ kde_len += sm->assoc_rsnxe_len;
+ }
+
#ifdef CONFIG_P2P
if (sm->p2p) {
- kde_buf = os_malloc(kde_len + 2 + RSN_SELECTOR_LEN + 1);
- if (kde_buf) {
- u8 *pos;
- wpa_printf(MSG_DEBUG, "P2P: Add IP Address Request KDE "
- "into EAPOL-Key 2/4");
- os_memcpy(kde_buf, kde, kde_len);
- kde = kde_buf;
- pos = kde + kde_len;
- *pos++ = WLAN_EID_VENDOR_SPECIFIC;
- *pos++ = RSN_SELECTOR_LEN + 1;
- RSN_SELECTOR_PUT(pos, WFA_KEY_DATA_IP_ADDR_REQ);
- pos += RSN_SELECTOR_LEN;
- *pos++ = 0x01;
- kde_len = pos - kde;
- }
+ u8 *pos;
+
+ wpa_printf(MSG_DEBUG,
+ "P2P: Add IP Address Request KDE into EAPOL-Key 2/4");
+ pos = kde + kde_len;
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = RSN_SELECTOR_LEN + 1;
+ RSN_SELECTOR_PUT(pos, WFA_KEY_DATA_IP_ADDR_REQ);
+ pos += RSN_SELECTOR_LEN;
+ *pos++ = 0x01;
+ kde_len = pos - kde;
}
#endif /* CONFIG_P2P */
@@ -2672,6 +2672,7 @@ void wpa_sm_deinit(struct wpa_sm *sm)
eloop_cancel_timeout(wpa_sm_start_preauth, sm, NULL);
eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
os_free(sm->assoc_wpa_ie);
+ os_free(sm->assoc_rsnxe);
os_free(sm->ap_wpa_ie);
os_free(sm->ap_rsn_ie);
os_free(sm->ap_rsnxe);
@@ -3049,6 +3050,9 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
case WPA_PARAM_OCV:
sm->ocv = value;
break;
+ case WPA_PARAM_SAE_PWE:
+ sm->sae_pwe = value;
+ break;
default:
break;
}
@@ -3227,6 +3231,83 @@ int wpa_sm_set_assoc_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
/**
+ * wpa_sm_set_assoc_rsnxe_default - Generate own RSNXE from configuration
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @rsnxe: Pointer to buffer for RSNXE
+ * @rsnxe_len: Pointer to the length of the rsne buffer
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_sm_set_assoc_rsnxe_default(struct wpa_sm *sm, u8 *rsnxe,
+ size_t *rsnxe_len)
+{
+ int res;
+
+ if (!sm)
+ return -1;
+
+ res = wpa_gen_rsnxe(sm, rsnxe, *rsnxe_len);
+ if (res < 0)
+ return -1;
+ *rsnxe_len = res;
+
+ wpa_hexdump(MSG_DEBUG, "RSN: Set own RSNXE default", rsnxe, *rsnxe_len);
+
+ if (sm->assoc_rsnxe) {
+ wpa_hexdump(MSG_DEBUG,
+ "RSN: Leave previously set RSNXE default",
+ sm->assoc_rsnxe, sm->assoc_rsnxe_len);
+ } else if (*rsnxe_len > 0) {
+ /*
+ * Make a copy of the RSNXE so that 4-Way Handshake gets the
+ * correct version of the IE even if it gets changed.
+ */
+ sm->assoc_rsnxe = os_memdup(rsnxe, *rsnxe_len);
+ if (!sm->assoc_rsnxe)
+ return -1;
+
+ sm->assoc_rsnxe_len = *rsnxe_len;
+ }
+
+ return 0;
+}
+
+
+/**
+ * wpa_sm_set_assoc_rsnxe - Set own RSNXE from (Re)AssocReq
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @ie: Pointer to IE data (starting from id)
+ * @len: IE length
+ * Returns: 0 on success, -1 on failure
+ *
+ * Inform WPA state machine about the RSNXE used in (Re)Association Request
+ * frame. The IE will be used to override the default value generated
+ * with wpa_sm_set_assoc_rsnxe_default().
+ */
+int wpa_sm_set_assoc_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len)
+{
+ if (!sm)
+ return -1;
+
+ os_free(sm->assoc_rsnxe);
+ if (!ie || len == 0) {
+ wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+ "RSN: clearing own RSNXE");
+ sm->assoc_rsnxe = NULL;
+ sm->assoc_rsnxe_len = 0;
+ } else {
+ wpa_hexdump(MSG_DEBUG, "RSN: set own RSNXE", ie, len);
+ sm->assoc_rsnxe = os_memdup(ie, len);
+ if (!sm->assoc_rsnxe)
+ return -1;
+
+ sm->assoc_rsnxe_len = len;
+ }
+
+ return 0;
+}
+
+
+/**
* wpa_sm_set_ap_wpa_ie - Set AP WPA IE from Beacon/ProbeResp
* @sm: Pointer to WPA state machine data from wpa_sm_init()
* @ie: Pointer to IE data (starting from id)
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 125d359..f1fbb1b 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -98,7 +98,8 @@ enum wpa_sm_conf_params {
WPA_PARAM_MGMT_GROUP,
WPA_PARAM_RSN_ENABLED,
WPA_PARAM_MFP,
- WPA_PARAM_OCV
+ WPA_PARAM_OCV,
+ WPA_PARAM_SAE_PWE,
};
struct rsn_supp_config {
@@ -134,6 +135,9 @@ void wpa_sm_set_eapol(struct wpa_sm *sm, struct eapol_sm *eapol);
int wpa_sm_set_assoc_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, u8 *wpa_ie,
size_t *wpa_ie_len);
+int wpa_sm_set_assoc_rsnxe_default(struct wpa_sm *sm, u8 *rsnxe,
+ size_t *rsnxe_len);
+int wpa_sm_set_assoc_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_set_ap_rsnxe(struct wpa_sm *sm, const u8 *ie, size_t len);
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 16224c9..2a43342 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -85,9 +85,12 @@ struct wpa_sm {
int rsn_enabled; /* Whether RSN is enabled in configuration */
int mfp; /* 0 = disabled, 1 = optional, 2 = mandatory */
int ocv; /* Operating Channel Validation */
+ int sae_pwe; /* SAE PWE generation options */
u8 *assoc_wpa_ie; /* Own WPA/RSN IE from (Re)AssocReq */
size_t assoc_wpa_ie_len;
+ u8 *assoc_rsnxe; /* Own RSNXE from (Re)AssocReq */
+ size_t assoc_rsnxe_len;
u8 *ap_wpa_ie, *ap_rsn_ie, *ap_rsnxe;
size_t ap_wpa_ie_len, ap_rsn_ie_len, ap_rsnxe_len;
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index e6af6c1..f4ac25c 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -342,6 +342,28 @@ int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)
}
+int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len)
+{
+ u8 *pos = rsnxe;
+
+ if (!wpa_key_mgmt_sae(sm->key_mgmt))
+ return 0; /* SAE not in use */
+ if (sm->sae_pwe != 1 && sm->sae_pwe != 2)
+ return 0; /* no supported extended RSN capabilities */
+
+ if (rsnxe_len < 3)
+ return -1;
+
+ *pos++ = WLAN_EID_RSNX;
+ *pos++ = 1;
+ /* bits 0-3 = 0 since only one octet of Extended RSN Capabilities is
+ * used for now */
+ *pos++ = BIT(WLAN_RSNX_CAPAB_SAE_H2E);
+
+ return pos - rsnxe;
+}
+
+
/**
* wpa_parse_vendor_specific - Parse Vendor Specific IEs
* @pos: Pointer to the IE header
diff --git a/src/rsn_supp/wpa_ie.h b/src/rsn_supp/wpa_ie.h
index 6f18bbe..fa7d0a3 100644
--- a/src/rsn_supp/wpa_ie.h
+++ b/src/rsn_supp/wpa_ie.h
@@ -62,5 +62,6 @@ struct wpa_eapol_ie_parse {
int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
struct wpa_eapol_ie_parse *ie);
int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len);
+int wpa_gen_rsnxe(struct wpa_sm *sm, u8 *rsnxe, size_t rsnxe_len);
#endif /* WPA_IE_H */
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 9ab5ebc..ac4274c 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -2411,7 +2411,7 @@ static int wpas_fst_update_mbie(struct wpa_supplicant *wpa_s,
static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
- int l, len, found = 0, wpa_found, rsn_found;
+ int l, len, found = 0, found_x = 0, wpa_found, rsn_found;
const u8 *p;
#if defined(CONFIG_IEEE80211R) || defined(CONFIG_OWE)
u8 bssid[ETH_ALEN];
@@ -2483,22 +2483,29 @@ static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
p, l);
break;
}
- if ((p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
- (os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) ||
- (p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 4 &&
- (os_memcmp(&p[2], "\x50\x6F\x9A\x12", 4) == 0)) ||
- (p[0] == WLAN_EID_RSN && p[1] >= 2)) {
+ if (!found &&
+ ((p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
+ (os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) ||
+ (p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 4 &&
+ (os_memcmp(&p[2], "\x50\x6F\x9A\x12", 4) == 0)) ||
+ (p[0] == WLAN_EID_RSN && p[1] >= 2))) {
if (wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, p, len))
break;
found = 1;
wpa_find_assoc_pmkid(wpa_s);
- break;
+ }
+ if (!found_x && p[0] == WLAN_EID_RSNX) {
+ if (wpa_sm_set_assoc_rsnxe(wpa_s->wpa, p, len))
+ break;
+ found_x = 1;
}
l -= len;
p += len;
}
if (!found && data->assoc_info.req_ies)
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+ if (!found_x && data->assoc_info.req_ies)
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
#ifdef CONFIG_FILS
#ifdef CONFIG_SME
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index fbec896..c8a5d4b 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -591,6 +591,14 @@ static void sme_send_authentication(struct wpa_supplicant *wpa_s,
os_memcpy(pos, ext_capab, ext_capab_len);
}
+ if (wpa_s->rsnxe_len > 0 &&
+ wpa_s->rsnxe_len <=
+ sizeof(wpa_s->sme.assoc_req_ie) - wpa_s->sme.assoc_req_ie_len) {
+ os_memcpy(wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len,
+ wpa_s->rsnxe, wpa_s->rsnxe_len);
+ wpa_s->sme.assoc_req_ie_len += wpa_s->rsnxe_len;
+ }
+
#ifdef CONFIG_HS20
if (is_hs20_network(wpa_s, ssid, bss)) {
struct wpabuf *hs20;
@@ -884,6 +892,8 @@ static void sme_auth_start_cb(struct wpa_radio_work *work, int deinit)
/* Starting new connection, so clear the possibly used WPA IE from the
* previous association. */
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
+ wpa_s->rsnxe_len = 0;
sme_send_authentication(wpa_s, cwork->bss, cwork->ssid, 1);
}
@@ -1899,6 +1909,11 @@ pfs_fail:
elems.osen_len + 2);
} else
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+ if (elems.rsnxe)
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, elems.rsnxe - 2,
+ elems.rsnxe_len + 2);
+ else
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
if (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group)
params.p2p = 1;
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 29f4820..6688d71 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -404,6 +404,8 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
wpa_sm_set_ap_rsnxe(wpa_s->wpa, NULL, 0);
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
+ wpa_s->rsnxe_len = 0;
wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
wpa_s->group_cipher = WPA_CIPHER_NONE;
wpa_s->mgmt_group_cipher = 0;
@@ -1578,12 +1580,20 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
#ifdef CONFIG_OCV
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_OCV, ssid->ocv);
#endif /* CONFIG_OCV */
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_SAE_PWE, wpa_s->conf->sae_pwe);
if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to generate WPA IE");
return -1;
}
+ wpa_s->rsnxe_len = sizeof(wpa_s->rsnxe);
+ if (wpa_sm_set_assoc_rsnxe_default(wpa_s->wpa, wpa_s->rsnxe,
+ &wpa_s->rsnxe_len)) {
+ wpa_msg(wpa_s, MSG_WARNING, "RSN: Failed to generate RSNXE");
+ return -1;
+ }
+
if (0) {
#ifdef CONFIG_DPP
} else if (wpa_s->key_mgmt == WPA_KEY_MGMT_DPP) {
@@ -2995,6 +3005,12 @@ pfs_fail:
}
#endif /* CONFIG_IEEE80211R */
+ if (wpa_s->rsnxe_len > 0 &&
+ wpa_s->rsnxe_len <= max_wpa_ie_len - wpa_ie_len) {
+ os_memcpy(wpa_ie + wpa_ie_len, wpa_s->rsnxe, wpa_s->rsnxe_len);
+ wpa_ie_len += wpa_s->rsnxe_len;
+ }
+
if (ssid->multi_ap_backhaul_sta) {
size_t multi_ap_ie_len;
@@ -3305,6 +3321,8 @@ static void wpas_start_assoc_cb(struct wpa_radio_work *work, int deinit)
/* Starting new association, so clear the possibly used WPA IE from the
* previous association. */
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_assoc_rsnxe(wpa_s->wpa, NULL, 0);
+ wpa_s->rsnxe_len = 0;
wpa_ie = wpas_populate_assoc_ies(wpa_s, bss, ssid, &params, NULL);
if (!wpa_ie) {
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 1b29617..8c5defc 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -614,6 +614,9 @@ struct wpa_supplicant {
int eapol_received; /* number of EAPOL packets received after the
* previous association event */
+ u8 rsnxe[20];
+ size_t rsnxe_len;
+
struct scard_data *scard;
char imsi[20];
int mnc_len;