diff --git a/src/device.c b/src/device.c index 1b4603ed..a63add93 100644 --- a/src/device.c +++ b/src/device.c @@ -731,7 +731,8 @@ static struct handshake_state *device_handshake_setup(struct device *device, } if (security == SECURITY_PSK) - handshake_state_set_pmk(hs, network_get_psk(network)); + handshake_state_set_pmk(hs, network_get_psk(network), + 32); else handshake_state_set_8021x_config(hs, network_get_settings(network)); @@ -898,7 +899,7 @@ static void device_preauthenticate_cb(struct netdev *netdev, uint8_t rsne_buf[300]; struct ie_rsn_info rsn_info; - handshake_state_set_pmk(new_hs, pmk); + handshake_state_set_pmk(new_hs, pmk, 32); handshake_state_set_authenticator_address(new_hs, device->preauth_bssid); handshake_state_set_supplicant_address(new_hs, diff --git a/src/eapol.c b/src/eapol.c index c3ece5bc..5989bfcb 100644 --- a/src/eapol.c +++ b/src/eapol.c @@ -1624,8 +1624,6 @@ static void eapol_eap_results_cb(const uint8_t *msk_data, size_t msk_len, void *user_data) { struct eapol_sm *sm = user_data; - ssize_t pmk_len; - const uint8_t *pmk_data; l_debug("EAP key material received"); @@ -1634,34 +1632,35 @@ static void eapol_eap_results_cb(const uint8_t *msk_data, size_t msk_len, * "When not using a PSK, the PMK is derived from the AAA key. * The PMK shall be computed as the first 256 bits (bits 0–255) * of the AAA key: PMK ← L(PTK, 0, 256)." - * 802.11 11.6.1.3: + * 802.11-2016 12.7.1.3: * "When not using a PSK, the PMK is derived from the MSK. - * The PMK shall be computed as the first 256 bits (bits 0–255) - * of the MSK: PMK ← L(MSK, 0, 256)." + * The PMK shall be computed as the first PMK_bits bits + * (bits 0 to PMK_bits–1) of the MSK: PMK = L(MSK, 0, PMK_bits)." * RFC5247 explains AAA-Key refers to the MSK and confirms the * first 32 bytes of the MSK are used. MSK is at least 64 octets * long per RFC3748. Note WEP derives the PTK from MSK differently. * * In a Fast Transition initial mobility domain association the PMK - * maps to the XXKey except with EAP: - * 802.11 11.6.1.7.3: - * "If the AKM negotiated is 00-0F-AC:3, then XXKey shall be the - * second 256 bits of the MSK (which is derived from the IEEE + * maps to the XXKey, except with EAP: + * 802.11-2016 12.7.1.7.3: + * "If the AKM negotiated is 00-0F-AC:3, then [...] XXKey shall be + * the second 256 bits of the MSK (which is derived from the IEEE * 802.1X authentication), i.e., XXKey = L(MSK, 256, 256)." + * So we need to save the first 64 bytes at minimum. */ if (sm->handshake->akm_suite == IE_RSN_AKM_SUITE_FT_OVER_8021X) { - pmk_len = (ssize_t) msk_len - 32; - pmk_data = msk_data + 32; + if (msk_len < 64) + goto msk_short; } else { - pmk_len = msk_len; - pmk_data = msk_data; + if (msk_len < 32) + goto msk_short; } - if (pmk_len < 32) - goto msk_short; + if (msk_len > sizeof(sm->handshake->pmk)) + msk_len = sizeof(sm->handshake->pmk); - handshake_state_set_pmk(sm->handshake, pmk_data); + handshake_state_set_pmk(sm->handshake, msk_data, msk_len); return; diff --git a/src/handshake.c b/src/handshake.c index 6dd4a0d4..479a05dc 100644 --- a/src/handshake.c +++ b/src/handshake.c @@ -103,9 +103,10 @@ void handshake_state_set_authenticator_address(struct handshake_state *s, memcpy(s->aa, aa, sizeof(s->aa)); } -void handshake_state_set_pmk(struct handshake_state *s, const uint8_t *pmk) +void handshake_state_set_pmk(struct handshake_state *s, const uint8_t *pmk, + size_t pmk_len) { - memcpy(s->pmk, pmk, sizeof(s->pmk)); + memcpy(s->pmk, pmk, pmk_len); s->have_pmk = true; } @@ -278,11 +279,24 @@ bool handshake_state_derive_ptk(struct handshake_state *s) IE_RSN_AKM_SUITE_FT_OVER_SAE_SHA256)) { uint16_t mdid; uint8_t ptk_name[16]; + const uint8_t *xxkey = s->pmk; + + /* + * In a Fast Transition initial mobility domain association + * the PMK maps to the XXKey, except with EAP: + * 802.11-2016 12.7.1.7.3: + * "If the AKM negotiated is 00-0F-AC:3, then [...] XXKey + * shall be the second 256 bits of the MSK (which is + * derived from the IEEE 802.1X authentication), i.e., + * XXKey = L(MSK, 256, 256)." + */ + if (s->akm_suite == IE_RSN_AKM_SUITE_FT_OVER_8021X) + xxkey = s->pmk + 32; ie_parse_mobility_domain_from_data(s->mde, s->mde[1] + 2, &mdid, NULL, NULL); - if (!crypto_derive_pmk_r0(s->pmk, s->ssid, s->ssid_len, mdid, + if (!crypto_derive_pmk_r0(xxkey, s->ssid, s->ssid_len, mdid, s->r0khid, s->r0khid_len, s->spa, s->pmk_r0, s->pmk_r0_name)) diff --git a/src/handshake.h b/src/handshake.h index 5d4ac3de..0d255fef 100644 --- a/src/handshake.h +++ b/src/handshake.h @@ -72,7 +72,7 @@ struct handshake_state { enum ie_rsn_cipher_suite group_cipher; enum ie_rsn_cipher_suite group_management_cipher; enum ie_rsn_akm_suite akm_suite; - uint8_t pmk[32]; + uint8_t pmk[64]; uint8_t snonce[32]; uint8_t anonce[32]; uint8_t ptk[64]; @@ -102,7 +102,8 @@ void handshake_state_set_supplicant_address(struct handshake_state *s, void handshake_state_set_authenticator_address(struct handshake_state *s, const uint8_t *aa); void handshake_state_set_user_data(struct handshake_state *s, void *user_data); -void handshake_state_set_pmk(struct handshake_state *s, const uint8_t *pmk); +void handshake_state_set_pmk(struct handshake_state *s, const uint8_t *pmk, + size_t pmk_len); void handshake_state_set_8021x_config(struct handshake_state *s, struct l_settings *settings); struct l_settings *handshake_state_get_8021x_config(struct handshake_state *s);