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>
This commit is contained in:
Jouni Malinen 2019-10-17 16:54:05 +03:00 committed by Jouni Malinen
parent 8401cdc8d4
commit 6d6c887751
9 changed files with 187 additions and 33 deletions

View file

@ -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;
}
@ -3226,6 +3230,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()

View file

@ -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);

View file

@ -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;

View file

@ -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

View file

@ -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 */