eapol: Only send EAPOL-Start on step 1/4 if really needed

Currently we'd send EAPOL-Start whenever EAP was configured and we
received an EAPOL-Key before EAP negotiation.  Instead only do that if
we know we can't respond to the 4-Way handshake because we don't have
a PMK yet or the PMKID doesn't match.  Require a PMKID in step 1/4 if
we'd sent a list of PMKIDs in our RSNE.
This commit is contained in:
Andrew Zaborowski 2017-04-21 19:09:53 +02:00 committed by Denis Kenzior
parent f53cb22b7e
commit 48966f57e8
1 changed files with 57 additions and 9 deletions

View File

@ -843,10 +843,57 @@ static void eapol_handle_ptk_1_of_4(struct eapol_sm *sm,
uint8_t *ies;
size_t ies_len;
const uint8_t *own_ie = sm->handshake->own_ie;
const uint8_t *pmkid;
struct ie_rsn_info rsn_info;
if (!eapol_verify_ptk_1_of_4(ek))
goto error_unspecified;
pmkid = handshake_util_find_pmkid_kde(ek->key_data,
L_BE16_TO_CPU(ek->key_data_len));
/*
* Require the PMKID KDE whenever we've sent a list of PMKIDs in
* our RSNE, otherwise treat it as optional and only validate it
* against our PMK. Some 802.11-2012 sections show message 1/4
* without a PMKID KDE and there are APs that send no PMKID KDE.
*/
if (!sm->handshake->wpa_ie &&
ie_parse_rsne_from_data(own_ie, own_ie[1] + 2,
&rsn_info) >= 0 &&
rsn_info.num_pmkids) {
bool found = false;
int i;
if (!pmkid)
goto error_unspecified;
for (i = 0; i < rsn_info.num_pmkids; i++)
if (!memcmp(rsn_info.pmkids + i * 16, pmkid, 16)) {
found = true;
break;
}
if (!found)
goto error_unspecified;
} else if (pmkid) {
uint8_t own_pmkid[16];
if (handshake_state_get_pmkid(sm->handshake, own_pmkid) &&
memcmp(pmkid, own_pmkid, 16)) {
/*
* If the AP has a different PMKSA from ours and we
* have means to create a new PMKSA through EAP then
* try that, otherwise give up.
*/
if (sm->eap) {
send_eapol_start(NULL, sm);
return;
} else
goto error_unspecified;
}
}
handshake_state_new_snonce(sm->handshake);
handshake_state_set_anonce(sm->handshake, ek->key_nonce);
@ -858,7 +905,6 @@ static void eapol_handle_ptk_1_of_4(struct eapol_sm *sm,
(IE_RSN_AKM_SUITE_FT_OVER_8021X |
IE_RSN_AKM_SUITE_FT_USING_PSK |
IE_RSN_AKM_SUITE_FT_OVER_SAE_SHA256)) {
struct ie_rsn_info rsn_info;
const uint8_t *mde = sm->handshake->mde;
const uint8_t *fte = sm->handshake->fte;
@ -868,10 +914,6 @@ static void eapol_handle_ptk_1_of_4(struct eapol_sm *sm,
*/
ies = alloca(512);
if (ie_parse_rsne_from_data(own_ie, own_ie[1] + 2,
&rsn_info) < 0)
goto error_unspecified;
rsn_info.num_pmkids = 1;
rsn_info.pmkids = sm->handshake->pmk_r1_name;
@ -1533,6 +1575,12 @@ static void eapol_rx_packet(struct eapol_sm *sm,
if (!sm->protocol_version)
sm->protocol_version = eh->protocol_version;
/* Only EAPOL-EAP packets allowed in preauthentication */
if (sm->preauth && eh->packet_type != 0) {
handshake_failed(sm, MPDU_REASON_CODE_UNSPECIFIED);
return;
}
switch (eh->packet_type) {
case 0: /* EAPOL-EAP */
l_timeout_remove(sm->eapol_start_timeout);
@ -1556,7 +1604,10 @@ static void eapol_rx_packet(struct eapol_sm *sm,
break;
case 3: /* EAPOL-Key */
if (sm->eap) {
if (!sm->handshake->have_pmk) {
if (!sm->eap)
return;
/*
* Either this is an error (EAP negotiation in
* progress) or the server is giving us a chance to
@ -1569,9 +1620,6 @@ static void eapol_rx_packet(struct eapol_sm *sm,
return;
}
if (!sm->handshake->have_pmk)
return;
eapol_key_handle(sm, frame, len);
break;