Fix SHA-256-based KDF when using CCMP as the pairwise cipher

IEEE 802.11r KDF uses key length in the derivation and as such, the PTK
length must be specified correctly. The previous version was deriving
using 512-bit PTK regardless of the negotiated cipher suite; this works
for TKIP, but not for CCMP. Update the code to use proper PTK length
based on the pairwise cipher.

This fixed PTK derivation for both IEEE 802.11r and IEEE 802.11w (when
using AKMP that specifies SHA-256-based key derivation). The fixed
version does not interoperate with the previous versions. [Bug 307]
This commit is contained in:
Jouni Malinen 2009-04-01 12:04:36 +03:00 committed by Jouni Malinen
parent d61f48ba1d
commit c0a6190815
8 changed files with 28 additions and 18 deletions

View file

@ -15,6 +15,9 @@ ChangeLog for hostapd
* fixed TNC with EAP-TTLS * fixed TNC with EAP-TTLS
* fixed IEEE 802.11r key derivation function to match with the standard * fixed IEEE 802.11r key derivation function to match with the standard
(note: this breaks interoperability with previous version) [Bug 303] (note: this breaks interoperability with previous version) [Bug 303]
* fixed SHA-256 based key derivation function to match with the
standard when using CCMP (for IEEE 802.11r and IEEE 802.11w)
(note: this breaks interoperability with previous version) [Bug 307]
2009-01-06 - v0.6.7 2009-01-06 - v0.6.7
* added support for Wi-Fi Protected Setup (WPS) * added support for Wi-Fi Protected Setup (WPS)

View file

@ -1405,14 +1405,15 @@ SM_STATE(WPA_PTK, PTKSTART)
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *pmk, static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *pmk,
struct wpa_ptk *ptk) struct wpa_ptk *ptk)
{ {
size_t ptk_len = sm->pairwise == WPA_CIPHER_CCMP ? 48 : 64;
#ifdef CONFIG_IEEE80211R #ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
return wpa_auth_derive_ptk_ft(sm, pmk, ptk); return wpa_auth_derive_ptk_ft(sm, pmk, ptk, ptk_len);
#endif /* CONFIG_IEEE80211R */ #endif /* CONFIG_IEEE80211R */
wpa_pmk_to_ptk(pmk, PMK_LEN, "Pairwise key expansion", wpa_pmk_to_ptk(pmk, PMK_LEN, "Pairwise key expansion",
sm->wpa_auth->addr, sm->addr, sm->ANonce, sm->SNonce, sm->wpa_auth->addr, sm->addr, sm->ANonce, sm->SNonce,
(u8 *) ptk, sizeof(*ptk), (u8 *) ptk, ptk_len,
wpa_key_mgmt_sha256(sm->wpa_key_mgmt)); wpa_key_mgmt_sha256(sm->wpa_key_mgmt));
return 0; return 0;

View file

@ -213,7 +213,7 @@ void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
#ifdef CONFIG_IEEE80211R #ifdef CONFIG_IEEE80211R
int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len); int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len);
int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk, int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
struct wpa_ptk *ptk); struct wpa_ptk *ptk, size_t ptk_len);
struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void); struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void);
void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache); void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache);
#endif /* CONFIG_IEEE80211R */ #endif /* CONFIG_IEEE80211R */

View file

@ -344,7 +344,7 @@ static int wpa_ft_pull_pmk_r1(struct wpa_authenticator *wpa_auth,
int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk, int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
struct wpa_ptk *ptk) struct wpa_ptk *ptk, size_t ptk_len)
{ {
u8 pmk_r0[PMK_LEN], pmk_r0_name[WPA_PMK_NAME_LEN]; u8 pmk_r0[PMK_LEN], pmk_r0_name[WPA_PMK_NAME_LEN];
u8 pmk_r1[PMK_LEN], pmk_r1_name[WPA_PMK_NAME_LEN]; u8 pmk_r1[PMK_LEN], pmk_r1_name[WPA_PMK_NAME_LEN];
@ -377,8 +377,8 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr, wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
sm->wpa_auth->addr, pmk_r1_name, sm->wpa_auth->addr, pmk_r1_name,
(u8 *) ptk, sizeof(*ptk), ptk_name); (u8 *) ptk, ptk_len, ptk_name);
wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, sizeof(*ptk)); wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len);
wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN); wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
return 0; return 0;
@ -889,7 +889,7 @@ static u16 wpa_ft_process_auth_req(struct wpa_state_machine *sm,
u8 ptk_name[WPA_PMK_NAME_LEN]; u8 ptk_name[WPA_PMK_NAME_LEN];
struct wpa_auth_config *conf; struct wpa_auth_config *conf;
struct wpa_ft_ies parse; struct wpa_ft_ies parse;
size_t buflen; size_t buflen, ptk_len;
int ret; int ret;
u8 *pos, *end; u8 *pos, *end;
@ -979,11 +979,12 @@ static u16 wpa_ft_process_auth_req(struct wpa_state_machine *sm,
wpa_hexdump(MSG_DEBUG, "FT: Generated ANonce", wpa_hexdump(MSG_DEBUG, "FT: Generated ANonce",
sm->ANonce, WPA_NONCE_LEN); sm->ANonce, WPA_NONCE_LEN);
ptk_len = sm->pairwise == WPA_CIPHER_CCMP ? 48 : 64;
wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr, wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
sm->wpa_auth->addr, pmk_r1_name, sm->wpa_auth->addr, pmk_r1_name,
(u8 *) &sm->PTK, sizeof(sm->PTK), ptk_name); (u8 *) &sm->PTK, ptk_len, ptk_name);
wpa_hexdump_key(MSG_DEBUG, "FT: PTK", wpa_hexdump_key(MSG_DEBUG, "FT: PTK",
(u8 *) &sm->PTK, sizeof(sm->PTK)); (u8 *) &sm->PTK, ptk_len);
wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN); wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
wpa_ft_install_ptk(sm); wpa_ft_install_ptk(sm);

View file

@ -360,14 +360,15 @@ static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
const struct wpa_eapol_key *key, const struct wpa_eapol_key *key,
struct wpa_ptk *ptk) struct wpa_ptk *ptk)
{ {
size_t ptk_len = sm->pairwise_cipher == WPA_CIPHER_CCMP ? 48 : 64;
#ifdef CONFIG_IEEE80211R #ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->key_mgmt)) if (wpa_key_mgmt_ft(sm->key_mgmt))
return wpa_derive_ptk_ft(sm, src_addr, key, ptk); return wpa_derive_ptk_ft(sm, src_addr, key, ptk, ptk_len);
#endif /* CONFIG_IEEE80211R */ #endif /* CONFIG_IEEE80211R */
wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion", wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion",
sm->own_addr, sm->bssid, sm->snonce, key->key_nonce, sm->own_addr, sm->bssid, sm->snonce, key->key_nonce,
(u8 *) ptk, sizeof(*ptk), (u8 *) ptk, ptk_len,
wpa_key_mgmt_sha256(sm->key_mgmt)); wpa_key_mgmt_sha256(sm->key_mgmt));
return 0; return 0;
} }

View file

@ -26,7 +26,7 @@
int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr, int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
const struct wpa_eapol_key *key, const struct wpa_eapol_key *key,
struct wpa_ptk *ptk) struct wpa_ptk *ptk, size_t ptk_len)
{ {
u8 pmk_r1_name[WPA_PMK_NAME_LEN]; u8 pmk_r1_name[WPA_PMK_NAME_LEN];
u8 ptk_name[WPA_PMK_NAME_LEN]; u8 ptk_name[WPA_PMK_NAME_LEN];
@ -51,8 +51,8 @@ int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN); wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN);
wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, anonce, sm->own_addr, wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, anonce, sm->own_addr,
sm->bssid, pmk_r1_name, sm->bssid, pmk_r1_name,
(u8 *) ptk, sizeof(*ptk), ptk_name); (u8 *) ptk, ptk_len, ptk_name);
wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, sizeof(*ptk)); wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len);
wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN); wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
return 0; return 0;
@ -520,7 +520,7 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
const u8 *ric_ies, size_t ric_ies_len) const u8 *ric_ies, size_t ric_ies_len)
{ {
u8 *ft_ies; u8 *ft_ies;
size_t ft_ies_len; size_t ft_ies_len, ptk_len;
struct wpa_ft_ies parse; struct wpa_ft_ies parse;
struct rsn_mdie *mdie; struct rsn_mdie *mdie;
struct rsn_ftie *ftie; struct rsn_ftie *ftie;
@ -611,11 +611,12 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
sm->pmk_r1_name, WPA_PMK_NAME_LEN); sm->pmk_r1_name, WPA_PMK_NAME_LEN);
bssid = target_ap; bssid = target_ap;
ptk_len = sm->pairwise_cipher == WPA_CIPHER_CCMP ? 48 : 64;
wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, ftie->anonce, sm->own_addr, wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, ftie->anonce, sm->own_addr,
bssid, sm->pmk_r1_name, bssid, sm->pmk_r1_name,
(u8 *) &sm->ptk, sizeof(sm->ptk), ptk_name); (u8 *) &sm->ptk, ptk_len, ptk_name);
wpa_hexdump_key(MSG_DEBUG, "FT: PTK", wpa_hexdump_key(MSG_DEBUG, "FT: PTK",
(u8 *) &sm->ptk, sizeof(sm->ptk)); (u8 *) &sm->ptk, ptk_len);
wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN); wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, ftie->anonce, ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, ftie->anonce,

View file

@ -240,6 +240,6 @@ int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst,
int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr, int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
const struct wpa_eapol_key *key, const struct wpa_eapol_key *key,
struct wpa_ptk *ptk); struct wpa_ptk *ptk, size_t ptk_len);
#endif /* WPA_I_H */ #endif /* WPA_I_H */

View file

@ -22,6 +22,9 @@ ChangeLog for wpa_supplicant
and association commands (e.g., mac80211-based Linux drivers with and association commands (e.g., mac80211-based Linux drivers with
nl80211; SME in wpa_supplicant); this allows over-the-air FT protocol nl80211; SME in wpa_supplicant); this allows over-the-air FT protocol
to be used (IEEE 802.11r) to be used (IEEE 802.11r)
* fixed SHA-256 based key derivation function to match with the
standard when using CCMP (for IEEE 802.11r and IEEE 802.11w)
(note: this breaks interoperability with previous version) [Bug 307]
2009-01-06 - v0.6.7 2009-01-06 - v0.6.7
* added support for Wi-Fi Protected Setup (WPS) * added support for Wi-Fi Protected Setup (WPS)