wlantest: Fix handling of PTK rekeying
Use a temporary PTK buffer during 4-way handshake when rekeying PTK so that the new EAPOL-Key frame MIC values are checked against the new PTK and frames are decrypted using the old PTK. Take the new PTK into use once msg 4/4 is processed and clear RSC counters at that point (including moving of RSC update to avoid setting RSC based on the msg 4/4). In addition, add a workaround to handle supplicant implementations that set Secure bit to one during PTK rekeying 4-way handshake in msg 2/4. This was previously assumed to be msg 4/4, but the key data contents can be used to figure out whether this is msg 2/4 even if the Secure bit is set to one. Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
adc33680e3
commit
d0b251d2e8
3 changed files with 56 additions and 14 deletions
|
@ -342,9 +342,9 @@ skip_replay_det:
|
||||||
const u8 *peer_addr = NULL;
|
const u8 *peer_addr = NULL;
|
||||||
if (!(fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)))
|
if (!(fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)))
|
||||||
peer_addr = hdr->addr1;
|
peer_addr = hdr->addr1;
|
||||||
|
os_memcpy(rsc, pn, 6);
|
||||||
rx_data_process(wt, bss->bssid, sta->addr, dst, src, decrypted,
|
rx_data_process(wt, bss->bssid, sta->addr, dst, src, decrypted,
|
||||||
dlen, 1, peer_addr);
|
dlen, 1, peer_addr);
|
||||||
os_memcpy(rsc, pn, 6);
|
|
||||||
write_pcap_decrypted(wt, (const u8 *) hdr, 24 + (qos ? 2 : 0),
|
write_pcap_decrypted(wt, (const u8 *) hdr, 24 + (qos ? 2 : 0),
|
||||||
decrypted, dlen);
|
decrypted, dlen);
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,6 +112,21 @@ static int try_pmk(struct wlantest_bss *bss, struct wlantest_sta *sta,
|
||||||
wpa_printf(MSG_INFO, "Derived PTK for STA " MACSTR " BSSID " MACSTR,
|
wpa_printf(MSG_INFO, "Derived PTK for STA " MACSTR " BSSID " MACSTR,
|
||||||
MAC2STR(sta->addr), MAC2STR(bss->bssid));
|
MAC2STR(sta->addr), MAC2STR(bss->bssid));
|
||||||
sta->counters[WLANTEST_STA_COUNTER_PTK_LEARNED]++;
|
sta->counters[WLANTEST_STA_COUNTER_PTK_LEARNED]++;
|
||||||
|
if (sta->ptk_set) {
|
||||||
|
/*
|
||||||
|
* Rekeying - use new PTK for EAPOL-Key frames, but continue
|
||||||
|
* using the old PTK for frame decryption.
|
||||||
|
*/
|
||||||
|
os_memcpy(&sta->tptk, &ptk, sizeof(ptk));
|
||||||
|
wpa_hexdump(MSG_DEBUG, "TPTK:KCK", sta->tptk.kck, 16);
|
||||||
|
wpa_hexdump(MSG_DEBUG, "TPTK:KEK", sta->tptk.kek, 16);
|
||||||
|
wpa_hexdump(MSG_DEBUG, "TPTK:TK1", sta->tptk.tk1, 16);
|
||||||
|
if (ptk_len > 48)
|
||||||
|
wpa_hexdump(MSG_DEBUG, "TPTK:TK2", sta->tptk.u.tk2,
|
||||||
|
16);
|
||||||
|
sta->tptk_set = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
os_memcpy(&sta->ptk, &ptk, sizeof(ptk));
|
os_memcpy(&sta->ptk, &ptk, sizeof(ptk));
|
||||||
wpa_hexdump(MSG_DEBUG, "PTK:KCK", sta->ptk.kck, 16);
|
wpa_hexdump(MSG_DEBUG, "PTK:KCK", sta->ptk.kck, 16);
|
||||||
wpa_hexdump(MSG_DEBUG, "PTK:KEK", sta->ptk.kek, 16);
|
wpa_hexdump(MSG_DEBUG, "PTK:KEK", sta->ptk.kek, 16);
|
||||||
|
@ -155,7 +170,7 @@ static void rx_data_eapol_key_2_of_4(struct wlantest *wt, const u8 *dst,
|
||||||
struct wlantest_sta *sta;
|
struct wlantest_sta *sta;
|
||||||
const struct ieee802_1x_hdr *eapol;
|
const struct ieee802_1x_hdr *eapol;
|
||||||
const struct wpa_eapol_key *hdr;
|
const struct wpa_eapol_key *hdr;
|
||||||
const u8 *key_data;
|
const u8 *key_data, *kck;
|
||||||
u16 key_info, key_data_len;
|
u16 key_info, key_data_len;
|
||||||
struct wpa_eapol_ie_parse ie;
|
struct wpa_eapol_ie_parse ie;
|
||||||
|
|
||||||
|
@ -183,13 +198,17 @@ static void rx_data_eapol_key_2_of_4(struct wlantest *wt, const u8 *dst,
|
||||||
key_data_len = WPA_GET_BE16(hdr->key_data_length);
|
key_data_len = WPA_GET_BE16(hdr->key_data_length);
|
||||||
derive_ptk(wt, bss, sta, key_info & WPA_KEY_INFO_TYPE_MASK, data, len);
|
derive_ptk(wt, bss, sta, key_info & WPA_KEY_INFO_TYPE_MASK, data, len);
|
||||||
|
|
||||||
if (!sta->ptk_set) {
|
if (!sta->ptk_set && !sta->tptk_set) {
|
||||||
wpa_printf(MSG_DEBUG, "No PTK known to process EAPOL-Key 2/4");
|
wpa_printf(MSG_DEBUG, "No PTK known to process EAPOL-Key 2/4");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_mic(sta->ptk.kck, key_info & WPA_KEY_INFO_TYPE_MASK,
|
kck = sta->ptk.kck;
|
||||||
data, len) < 0) {
|
if (sta->tptk_set) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Use TPTK for validation EAPOL-Key MIC");
|
||||||
|
kck = sta->tptk.kck;
|
||||||
|
}
|
||||||
|
if (check_mic(kck, key_info & WPA_KEY_INFO_TYPE_MASK, data, len) < 0) {
|
||||||
wpa_printf(MSG_INFO, "Mismatch in EAPOL-Key 2/4 MIC");
|
wpa_printf(MSG_INFO, "Mismatch in EAPOL-Key 2/4 MIC");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -398,7 +417,7 @@ static void rx_data_eapol_key_3_of_4(struct wlantest *wt, const u8 *dst,
|
||||||
struct wlantest_sta *sta;
|
struct wlantest_sta *sta;
|
||||||
const struct ieee802_1x_hdr *eapol;
|
const struct ieee802_1x_hdr *eapol;
|
||||||
const struct wpa_eapol_key *hdr;
|
const struct wpa_eapol_key *hdr;
|
||||||
const u8 *key_data;
|
const u8 *key_data, *kck;
|
||||||
int recalc = 0;
|
int recalc = 0;
|
||||||
u16 key_info, ver;
|
u16 key_info, ver;
|
||||||
u8 *decrypted_buf = NULL;
|
u8 *decrypted_buf = NULL;
|
||||||
|
@ -430,13 +449,17 @@ static void rx_data_eapol_key_3_of_4(struct wlantest *wt, const u8 *dst,
|
||||||
data, len);
|
data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sta->ptk_set) {
|
if (!sta->ptk_set && !sta->tptk_set) {
|
||||||
wpa_printf(MSG_DEBUG, "No PTK known to process EAPOL-Key 3/4");
|
wpa_printf(MSG_DEBUG, "No PTK known to process EAPOL-Key 3/4");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_mic(sta->ptk.kck, key_info & WPA_KEY_INFO_TYPE_MASK,
|
kck = sta->ptk.kck;
|
||||||
data, len) < 0) {
|
if (sta->tptk_set) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Use TPTK for validation EAPOL-Key MIC");
|
||||||
|
kck = sta->tptk.kck;
|
||||||
|
}
|
||||||
|
if (check_mic(kck, key_info & WPA_KEY_INFO_TYPE_MASK, data, len) < 0) {
|
||||||
wpa_printf(MSG_INFO, "Mismatch in EAPOL-Key 3/4 MIC");
|
wpa_printf(MSG_INFO, "Mismatch in EAPOL-Key 3/4 MIC");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -549,6 +572,7 @@ static void rx_data_eapol_key_4_of_4(struct wlantest *wt, const u8 *dst,
|
||||||
const struct ieee802_1x_hdr *eapol;
|
const struct ieee802_1x_hdr *eapol;
|
||||||
const struct wpa_eapol_key *hdr;
|
const struct wpa_eapol_key *hdr;
|
||||||
u16 key_info;
|
u16 key_info;
|
||||||
|
const u8 *kck;
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "EAPOL-Key 4/4 " MACSTR " -> " MACSTR,
|
wpa_printf(MSG_DEBUG, "EAPOL-Key 4/4 " MACSTR " -> " MACSTR,
|
||||||
MAC2STR(src), MAC2STR(dst));
|
MAC2STR(src), MAC2STR(dst));
|
||||||
|
@ -567,18 +591,29 @@ static void rx_data_eapol_key_4_of_4(struct wlantest *wt, const u8 *dst,
|
||||||
}
|
}
|
||||||
key_info = WPA_GET_BE16(hdr->key_info);
|
key_info = WPA_GET_BE16(hdr->key_info);
|
||||||
|
|
||||||
if (!sta->ptk_set) {
|
if (!sta->ptk_set && !sta->tptk_set) {
|
||||||
wpa_printf(MSG_DEBUG, "No PTK known to process EAPOL-Key 4/4");
|
wpa_printf(MSG_DEBUG, "No PTK known to process EAPOL-Key 4/4");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sta->ptk_set &&
|
kck = sta->ptk.kck;
|
||||||
check_mic(sta->ptk.kck, key_info & WPA_KEY_INFO_TYPE_MASK,
|
if (sta->tptk_set) {
|
||||||
data, len) < 0) {
|
wpa_printf(MSG_DEBUG, "Use TPTK for validation EAPOL-Key MIC");
|
||||||
|
kck = sta->tptk.kck;
|
||||||
|
}
|
||||||
|
if (check_mic(kck, key_info & WPA_KEY_INFO_TYPE_MASK, data, len) < 0) {
|
||||||
wpa_printf(MSG_INFO, "Mismatch in EAPOL-Key 4/4 MIC");
|
wpa_printf(MSG_INFO, "Mismatch in EAPOL-Key 4/4 MIC");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
wpa_printf(MSG_DEBUG, "Valid MIC found in EAPOL-Key 4/4");
|
wpa_printf(MSG_DEBUG, "Valid MIC found in EAPOL-Key 4/4");
|
||||||
|
if (sta->tptk_set) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Update PTK (rekeying)");
|
||||||
|
os_memcpy(&sta->ptk, &sta->tptk, sizeof(sta->ptk));
|
||||||
|
sta->ptk_set = 1;
|
||||||
|
sta->tptk_set = 0;
|
||||||
|
os_memset(sta->rsc_tods, 0, sizeof(sta->rsc_tods));
|
||||||
|
os_memset(sta->rsc_fromds, 0, sizeof(sta->rsc_fromds));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -907,7 +942,12 @@ static void rx_data_eapol_key(struct wlantest *wt, const u8 *dst,
|
||||||
rx_data_eapol_key_3_of_4(wt, dst, src, data, len);
|
rx_data_eapol_key_3_of_4(wt, dst, src, data, len);
|
||||||
break;
|
break;
|
||||||
case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC:
|
case WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC:
|
||||||
rx_data_eapol_key_4_of_4(wt, dst, src, data, len);
|
if (key_data_length == 0)
|
||||||
|
rx_data_eapol_key_4_of_4(wt, dst, src, data,
|
||||||
|
len);
|
||||||
|
else
|
||||||
|
rx_data_eapol_key_2_of_4(wt, dst, src, data,
|
||||||
|
len);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
wpa_printf(MSG_DEBUG, "Unsupported EAPOL-Key frame");
|
wpa_printf(MSG_DEBUG, "Unsupported EAPOL-Key frame");
|
||||||
|
|
|
@ -70,6 +70,8 @@ struct wlantest_sta {
|
||||||
u8 snonce[32]; /* SNonce from the previous EAPOL-Key msg 2/4 */
|
u8 snonce[32]; /* SNonce from the previous EAPOL-Key msg 2/4 */
|
||||||
struct wpa_ptk ptk; /* Derived PTK */
|
struct wpa_ptk ptk; /* Derived PTK */
|
||||||
int ptk_set;
|
int ptk_set;
|
||||||
|
struct wpa_ptk tptk; /* Derived PTK during rekeying */
|
||||||
|
int tptk_set;
|
||||||
u8 rsc_tods[16 + 1][6];
|
u8 rsc_tods[16 + 1][6];
|
||||||
u8 rsc_fromds[16 + 1][6];
|
u8 rsc_fromds[16 + 1][6];
|
||||||
u8 ap_sa_query_tr[2];
|
u8 ap_sa_query_tr[2];
|
||||||
|
|
Loading…
Reference in a new issue