mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2025-01-05 12:52:37 +01:00
eapol: Sanity check 2nd RSNE
If the second (optional) RSN element is included in Step 3/4 of the 4-way handshake, parse it and perform basic sanity checks
This commit is contained in:
parent
3b3ed6defe
commit
12551b52ff
74
src/eapol.c
74
src/eapol.c
@ -821,9 +821,11 @@ static const uint8_t *eapol_find_gtk_kde(const uint8_t *data, size_t data_len,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const uint8_t *eapol_find_rsne(const uint8_t *data, size_t data_len)
|
static const uint8_t *eapol_find_rsne(const uint8_t *data, size_t data_len,
|
||||||
|
const uint8_t **optional)
|
||||||
{
|
{
|
||||||
struct ie_tlv_iter iter;
|
struct ie_tlv_iter iter;
|
||||||
|
const uint8_t *first = NULL;
|
||||||
|
|
||||||
ie_tlv_iter_init(&iter, data, data_len);
|
ie_tlv_iter_init(&iter, data, data_len);
|
||||||
|
|
||||||
@ -831,10 +833,18 @@ static const uint8_t *eapol_find_rsne(const uint8_t *data, size_t data_len)
|
|||||||
if (ie_tlv_iter_get_tag(&iter) != IE_TYPE_RSN)
|
if (ie_tlv_iter_get_tag(&iter) != IE_TYPE_RSN)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
return ie_tlv_iter_get_data(&iter) - 2;
|
if (!first) {
|
||||||
|
first = ie_tlv_iter_get_data(&iter) - 2;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optional)
|
||||||
|
*optional = ie_tlv_iter_get_data(&iter) - 2;
|
||||||
|
|
||||||
|
return first;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return first;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const uint8_t *eapol_find_wpa_ie(const uint8_t *data, size_t data_len)
|
static const uint8_t *eapol_find_wpa_ie(const uint8_t *data, size_t data_len)
|
||||||
@ -960,6 +970,7 @@ static void eapol_handle_ptk_3_of_4(uint32_t ifindex,
|
|||||||
const uint8_t *gtk;
|
const uint8_t *gtk;
|
||||||
size_t gtk_len;
|
size_t gtk_len;
|
||||||
const uint8_t *rsne;
|
const uint8_t *rsne;
|
||||||
|
const uint8_t *optional_rsne = NULL;
|
||||||
uint8_t gtk_key_index;
|
uint8_t gtk_key_index;
|
||||||
|
|
||||||
if (!eapol_verify_ptk_3_of_4(ek, sm->wpa_ie)) {
|
if (!eapol_verify_ptk_3_of_4(ek, sm->wpa_ie)) {
|
||||||
@ -983,7 +994,8 @@ static void eapol_handle_ptk_3_of_4(uint32_t ifindex,
|
|||||||
*/
|
*/
|
||||||
if (!sm->wpa_ie)
|
if (!sm->wpa_ie)
|
||||||
rsne = eapol_find_rsne(decrypted_key_data,
|
rsne = eapol_find_rsne(decrypted_key_data,
|
||||||
decrypted_key_data_size);
|
decrypted_key_data_size,
|
||||||
|
&optional_rsne);
|
||||||
else
|
else
|
||||||
rsne = eapol_find_wpa_ie(decrypted_key_data,
|
rsne = eapol_find_wpa_ie(decrypted_key_data,
|
||||||
decrypted_key_data_size);
|
decrypted_key_data_size);
|
||||||
@ -1004,6 +1016,60 @@ static void eapol_handle_ptk_3_of_4(uint32_t ifindex,
|
|||||||
* Supplicant uses the pairwise cipher suite specified in the second
|
* Supplicant uses the pairwise cipher suite specified in the second
|
||||||
* RSNE or deauthenticates."
|
* RSNE or deauthenticates."
|
||||||
*/
|
*/
|
||||||
|
if (optional_rsne) {
|
||||||
|
struct ie_rsn_info info1;
|
||||||
|
struct ie_rsn_info info2;
|
||||||
|
uint16_t override;
|
||||||
|
|
||||||
|
if (ie_parse_rsne_from_data(rsne, rsne[1] + 2, &info1) < 0) {
|
||||||
|
handshake_failed(ifindex, sm,
|
||||||
|
MPDU_REASON_CODE_IE_DIFFERENT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ie_parse_rsne_from_data(optional_rsne, optional_rsne[1] + 2,
|
||||||
|
&info2) < 0) {
|
||||||
|
handshake_failed(ifindex, sm,
|
||||||
|
MPDU_REASON_CODE_IE_DIFFERENT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 11.6.2:
|
||||||
|
* It may happen, for example, that a Supplicant selects a
|
||||||
|
* pairwise cipher suite which is advertised by an AP, but
|
||||||
|
* which policy disallows for this particular STA. An
|
||||||
|
* Authenticator may, therefore, insert a second RSNE to
|
||||||
|
* overrule the STA’s selection. An Authenticator’s SME shall
|
||||||
|
* insert the second RSNE, after the first RSNE, only for this
|
||||||
|
* purpose. The pairwise cipher suite in the second RSNE
|
||||||
|
* included shall be one of the ciphers advertised by the
|
||||||
|
* Authenticator. All other fields in the second RSNE shall be
|
||||||
|
* identical to the first RSNE.
|
||||||
|
*
|
||||||
|
* - Check that akm_suites and group_cipher are the same
|
||||||
|
* between rsne1 and rsne2
|
||||||
|
* - Check that pairwise_ciphers is not the same between rsne1
|
||||||
|
* and rsne2
|
||||||
|
* - Check that rsne2 pairwise_ciphers is a subset of rsne
|
||||||
|
*/
|
||||||
|
if (info1.akm_suites != info2.akm_suites ||
|
||||||
|
info1.group_cipher != info2.group_cipher) {
|
||||||
|
handshake_failed(ifindex, sm,
|
||||||
|
MPDU_REASON_CODE_IE_DIFFERENT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
override = info2.pairwise_ciphers;
|
||||||
|
|
||||||
|
if (override == info1.pairwise_ciphers ||
|
||||||
|
!(info1.pairwise_ciphers & override) ||
|
||||||
|
__builtin_popcount(override) != 1) {
|
||||||
|
handshake_failed(ifindex, sm,
|
||||||
|
MPDU_REASON_CODE_INVALID_PAIRWISE_CIPHER);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO: Handle IE_RSN_CIPHER_SUITE_NO_GROUP_TRAFFIC case
|
* TODO: Handle IE_RSN_CIPHER_SUITE_NO_GROUP_TRAFFIC case
|
||||||
|
Loading…
Reference in New Issue
Block a user