Fix Suite B 192-bit AKM to use proper PMK length
In addition to the PTK length increasing, the length of the PMK was increased (from 256 to 384 bits) for the 00-0f-ac:12 AKM. This part was missing from the initial implementation and a fixed length (256-bit) PMK was used for all AKMs. Fix this by adding more complete support for variable length PMK and use 384 bits from MSK instead of 256 bits when using this AKM. This is not backwards compatible with the earlier implementations. Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
parent
ae7d9fbd3d
commit
207976f053
11 changed files with 73 additions and 27 deletions
|
@ -2575,7 +2575,7 @@ static void ieee802_1x_finished(struct hostapd_data *hapd,
|
||||||
session_timeout = dot11RSNAConfigPMKLifetime;
|
session_timeout = dot11RSNAConfigPMKLifetime;
|
||||||
if (success && key && len >= PMK_LEN && !sta->remediation &&
|
if (success && key && len >= PMK_LEN && !sta->remediation &&
|
||||||
!sta->hs20_deauth_requested &&
|
!sta->hs20_deauth_requested &&
|
||||||
wpa_auth_pmksa_add(sta->wpa_sm, key, session_timeout,
|
wpa_auth_pmksa_add(sta->wpa_sm, key, len, session_timeout,
|
||||||
sta->eapol_sm) == 0) {
|
sta->eapol_sm) == 0) {
|
||||||
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
|
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
|
||||||
HOSTAPD_LEVEL_DEBUG,
|
HOSTAPD_LEVEL_DEBUG,
|
||||||
|
|
|
@ -258,7 +258,7 @@ pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
|
||||||
struct rsn_pmksa_cache_entry *entry, *pos;
|
struct rsn_pmksa_cache_entry *entry, *pos;
|
||||||
struct os_reltime now;
|
struct os_reltime now;
|
||||||
|
|
||||||
if (pmk_len > PMK_LEN)
|
if (pmk_len > PMK_LEN_MAX)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (wpa_key_mgmt_suite_b(akmp) && !kck)
|
if (wpa_key_mgmt_suite_b(akmp) && !kck)
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
struct rsn_pmksa_cache_entry {
|
struct rsn_pmksa_cache_entry {
|
||||||
struct rsn_pmksa_cache_entry *next, *hnext;
|
struct rsn_pmksa_cache_entry *next, *hnext;
|
||||||
u8 pmkid[PMKID_LEN];
|
u8 pmkid[PMKID_LEN];
|
||||||
u8 pmk[PMK_LEN];
|
u8 pmk[PMK_LEN_MAX];
|
||||||
size_t pmk_len;
|
size_t pmk_len;
|
||||||
os_time_t expiration;
|
os_time_t expiration;
|
||||||
int akmp; /* WPA_KEY_MGMT_* */
|
int akmp; /* WPA_KEY_MGMT_* */
|
||||||
|
|
|
@ -44,7 +44,8 @@ static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
|
||||||
static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
|
static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
|
||||||
struct wpa_group *group);
|
struct wpa_group *group);
|
||||||
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
|
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
|
||||||
const u8 *pmk, struct wpa_ptk *ptk);
|
const u8 *pmk, unsigned int pmk_len,
|
||||||
|
struct wpa_ptk *ptk);
|
||||||
static void wpa_group_free(struct wpa_authenticator *wpa_auth,
|
static void wpa_group_free(struct wpa_authenticator *wpa_auth,
|
||||||
struct wpa_group *group);
|
struct wpa_group *group);
|
||||||
static void wpa_group_get(struct wpa_authenticator *wpa_auth,
|
static void wpa_group_get(struct wpa_authenticator *wpa_auth,
|
||||||
|
@ -827,6 +828,7 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
|
||||||
struct wpa_ptk PTK;
|
struct wpa_ptk PTK;
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
const u8 *pmk = NULL;
|
const u8 *pmk = NULL;
|
||||||
|
unsigned int pmk_len;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
|
if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
|
||||||
|
@ -834,10 +836,13 @@ static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
|
||||||
sm->p2p_dev_addr, pmk);
|
sm->p2p_dev_addr, pmk);
|
||||||
if (pmk == NULL)
|
if (pmk == NULL)
|
||||||
break;
|
break;
|
||||||
} else
|
pmk_len = PMK_LEN;
|
||||||
|
} else {
|
||||||
pmk = sm->PMK;
|
pmk = sm->PMK;
|
||||||
|
pmk_len = sm->pmk_len;
|
||||||
|
}
|
||||||
|
|
||||||
wpa_derive_ptk(sm, sm->alt_SNonce, pmk, &PTK);
|
wpa_derive_ptk(sm, sm->alt_SNonce, pmk, pmk_len, &PTK);
|
||||||
|
|
||||||
if (wpa_verify_key_mic(sm->wpa_key_mgmt, &PTK, data, data_len)
|
if (wpa_verify_key_mic(sm->wpa_key_mgmt, &PTK, data, data_len)
|
||||||
== 0) {
|
== 0) {
|
||||||
|
@ -1904,11 +1909,27 @@ SM_STATE(WPA_PTK, INITPMK)
|
||||||
#endif /* CONFIG_IEEE80211R */
|
#endif /* CONFIG_IEEE80211R */
|
||||||
if (sm->pmksa) {
|
if (sm->pmksa) {
|
||||||
wpa_printf(MSG_DEBUG, "WPA: PMK from PMKSA cache");
|
wpa_printf(MSG_DEBUG, "WPA: PMK from PMKSA cache");
|
||||||
os_memcpy(sm->PMK, sm->pmksa->pmk, PMK_LEN);
|
os_memcpy(sm->PMK, sm->pmksa->pmk, sm->pmksa->pmk_len);
|
||||||
|
sm->pmk_len = sm->pmksa->pmk_len;
|
||||||
} else if (wpa_auth_get_msk(sm->wpa_auth, sm->addr, msk, &len) == 0) {
|
} else if (wpa_auth_get_msk(sm->wpa_auth, sm->addr, msk, &len) == 0) {
|
||||||
|
unsigned int pmk_len;
|
||||||
|
|
||||||
|
if (sm->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
|
||||||
|
pmk_len = PMK_LEN_SUITE_B_192;
|
||||||
|
else
|
||||||
|
pmk_len = PMK_LEN;
|
||||||
wpa_printf(MSG_DEBUG, "WPA: PMK from EAPOL state machine "
|
wpa_printf(MSG_DEBUG, "WPA: PMK from EAPOL state machine "
|
||||||
"(len=%lu)", (unsigned long) len);
|
"(MSK len=%lu PMK len=%u)", (unsigned long) len,
|
||||||
os_memcpy(sm->PMK, msk, PMK_LEN);
|
pmk_len);
|
||||||
|
if (len < pmk_len) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"WPA: MSK not long enough (%u) to create PMK (%u)",
|
||||||
|
(unsigned int) len, (unsigned int) pmk_len);
|
||||||
|
sm->Disconnect = TRUE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
os_memcpy(sm->PMK, msk, pmk_len);
|
||||||
|
sm->pmk_len = pmk_len;
|
||||||
#ifdef CONFIG_IEEE80211R
|
#ifdef CONFIG_IEEE80211R
|
||||||
if (len >= 2 * PMK_LEN) {
|
if (len >= 2 * PMK_LEN) {
|
||||||
os_memcpy(sm->xxkey, msk + PMK_LEN, PMK_LEN);
|
os_memcpy(sm->xxkey, msk + PMK_LEN, PMK_LEN);
|
||||||
|
@ -1943,6 +1964,7 @@ SM_STATE(WPA_PTK, INITPSK)
|
||||||
psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr, NULL);
|
psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, sm->p2p_dev_addr, NULL);
|
||||||
if (psk) {
|
if (psk) {
|
||||||
os_memcpy(sm->PMK, psk, PMK_LEN);
|
os_memcpy(sm->PMK, psk, PMK_LEN);
|
||||||
|
sm->pmk_len = PMK_LEN;
|
||||||
#ifdef CONFIG_IEEE80211R
|
#ifdef CONFIG_IEEE80211R
|
||||||
os_memcpy(sm->xxkey, psk, PMK_LEN);
|
os_memcpy(sm->xxkey, psk, PMK_LEN);
|
||||||
sm->xxkey_len = PMK_LEN;
|
sm->xxkey_len = PMK_LEN;
|
||||||
|
@ -1994,7 +2016,7 @@ SM_STATE(WPA_PTK, PTKSTART)
|
||||||
* Calculate PMKID since no PMKSA cache entry was
|
* Calculate PMKID since no PMKSA cache entry was
|
||||||
* available with pre-calculated PMKID.
|
* available with pre-calculated PMKID.
|
||||||
*/
|
*/
|
||||||
rsn_pmkid(sm->PMK, PMK_LEN, sm->wpa_auth->addr,
|
rsn_pmkid(sm->PMK, sm->pmk_len, sm->wpa_auth->addr,
|
||||||
sm->addr, &pmkid[2 + RSN_SELECTOR_LEN],
|
sm->addr, &pmkid[2 + RSN_SELECTOR_LEN],
|
||||||
wpa_key_mgmt_sha256(sm->wpa_key_mgmt));
|
wpa_key_mgmt_sha256(sm->wpa_key_mgmt));
|
||||||
}
|
}
|
||||||
|
@ -2006,14 +2028,15 @@ SM_STATE(WPA_PTK, PTKSTART)
|
||||||
|
|
||||||
|
|
||||||
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
|
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
|
||||||
const u8 *pmk, struct wpa_ptk *ptk)
|
const u8 *pmk, unsigned int pmk_len,
|
||||||
|
struct wpa_ptk *ptk)
|
||||||
{
|
{
|
||||||
#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);
|
||||||
#endif /* CONFIG_IEEE80211R */
|
#endif /* CONFIG_IEEE80211R */
|
||||||
|
|
||||||
return wpa_pmk_to_ptk(pmk, PMK_LEN, "Pairwise key expansion",
|
return wpa_pmk_to_ptk(pmk, pmk_len, "Pairwise key expansion",
|
||||||
sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce,
|
sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce,
|
||||||
ptk, sm->wpa_key_mgmt, sm->pairwise);
|
ptk, sm->wpa_key_mgmt, sm->pairwise);
|
||||||
}
|
}
|
||||||
|
@ -2024,6 +2047,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
|
||||||
struct wpa_ptk PTK;
|
struct wpa_ptk PTK;
|
||||||
int ok = 0, psk_found = 0;
|
int ok = 0, psk_found = 0;
|
||||||
const u8 *pmk = NULL;
|
const u8 *pmk = NULL;
|
||||||
|
unsigned int pmk_len;
|
||||||
|
|
||||||
SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
|
SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
|
||||||
sm->EAPOLKeyReceived = FALSE;
|
sm->EAPOLKeyReceived = FALSE;
|
||||||
|
@ -2039,10 +2063,13 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
|
||||||
if (pmk == NULL)
|
if (pmk == NULL)
|
||||||
break;
|
break;
|
||||||
psk_found = 1;
|
psk_found = 1;
|
||||||
} else
|
pmk_len = PMK_LEN;
|
||||||
|
} else {
|
||||||
pmk = sm->PMK;
|
pmk = sm->PMK;
|
||||||
|
pmk_len = sm->pmk_len;
|
||||||
|
}
|
||||||
|
|
||||||
wpa_derive_ptk(sm, sm->SNonce, pmk, &PTK);
|
wpa_derive_ptk(sm, sm->SNonce, pmk, pmk_len, &PTK);
|
||||||
|
|
||||||
if (wpa_verify_key_mic(sm->wpa_key_mgmt, &PTK,
|
if (wpa_verify_key_mic(sm->wpa_key_mgmt, &PTK,
|
||||||
sm->last_rx_eapol_key,
|
sm->last_rx_eapol_key,
|
||||||
|
@ -2092,6 +2119,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
|
||||||
* state machine data based on whatever PSK was selected here.
|
* state machine data based on whatever PSK was selected here.
|
||||||
*/
|
*/
|
||||||
os_memcpy(sm->PMK, pmk, PMK_LEN);
|
os_memcpy(sm->PMK, pmk, PMK_LEN);
|
||||||
|
sm->pmk_len = PMK_LEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
sm->MICVerified = TRUE;
|
sm->MICVerified = TRUE;
|
||||||
|
@ -3243,13 +3271,21 @@ const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth, size_t *len)
|
||||||
|
|
||||||
|
|
||||||
int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
|
int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
|
||||||
|
unsigned int pmk_len,
|
||||||
int session_timeout, struct eapol_state_machine *eapol)
|
int session_timeout, struct eapol_state_machine *eapol)
|
||||||
{
|
{
|
||||||
if (sm == NULL || sm->wpa != WPA_VERSION_WPA2 ||
|
if (sm == NULL || sm->wpa != WPA_VERSION_WPA2 ||
|
||||||
sm->wpa_auth->conf.disable_pmksa_caching)
|
sm->wpa_auth->conf.disable_pmksa_caching)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, PMK_LEN,
|
if (sm->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
|
||||||
|
if (pmk_len > PMK_LEN_SUITE_B_192)
|
||||||
|
pmk_len = PMK_LEN_SUITE_B_192;
|
||||||
|
} else if (pmk_len > PMK_LEN) {
|
||||||
|
pmk_len = PMK_LEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, pmk_len,
|
||||||
sm->PTK.kck, sm->PTK.kck_len,
|
sm->PTK.kck, sm->PTK.kck_len,
|
||||||
sm->wpa_auth->addr, sm->addr, session_timeout,
|
sm->wpa_auth->addr, sm->addr, session_timeout,
|
||||||
eapol, sm->wpa_key_mgmt))
|
eapol, sm->wpa_key_mgmt))
|
||||||
|
|
|
@ -279,6 +279,7 @@ void wpa_auth_sta_local_mic_failure_report(struct wpa_state_machine *sm);
|
||||||
const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth,
|
const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth,
|
||||||
size_t *len);
|
size_t *len);
|
||||||
int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
|
int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
|
||||||
|
unsigned int pmk_len,
|
||||||
int session_timeout, struct eapol_state_machine *eapol);
|
int session_timeout, struct eapol_state_machine *eapol);
|
||||||
int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
|
int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
|
||||||
const u8 *pmk, size_t len, const u8 *sta_addr,
|
const u8 *pmk, size_t len, const u8 *sta_addr,
|
||||||
|
|
|
@ -60,7 +60,8 @@ struct wpa_state_machine {
|
||||||
u8 SNonce[WPA_NONCE_LEN];
|
u8 SNonce[WPA_NONCE_LEN];
|
||||||
u8 alt_SNonce[WPA_NONCE_LEN];
|
u8 alt_SNonce[WPA_NONCE_LEN];
|
||||||
u8 alt_replay_counter[WPA_REPLAY_COUNTER_LEN];
|
u8 alt_replay_counter[WPA_REPLAY_COUNTER_LEN];
|
||||||
u8 PMK[PMK_LEN];
|
u8 PMK[PMK_LEN_MAX];
|
||||||
|
unsigned int pmk_len;
|
||||||
struct wpa_ptk PTK;
|
struct wpa_ptk PTK;
|
||||||
Boolean PTK_valid;
|
Boolean PTK_valid;
|
||||||
Boolean pairwise_set;
|
Boolean pairwise_set;
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
/* IEEE 802.11i */
|
/* IEEE 802.11i */
|
||||||
#define PMKID_LEN 16
|
#define PMKID_LEN 16
|
||||||
#define PMK_LEN 32
|
#define PMK_LEN 32
|
||||||
|
#define PMK_LEN_SUITE_B_192 48
|
||||||
|
#define PMK_LEN_MAX 48
|
||||||
#define WPA_REPLAY_COUNTER_LEN 8
|
#define WPA_REPLAY_COUNTER_LEN 8
|
||||||
#define WPA_NONCE_LEN 32
|
#define WPA_NONCE_LEN 32
|
||||||
#define WPA_KEY_RSC_LEN 8
|
#define WPA_KEY_RSC_LEN 8
|
||||||
|
|
|
@ -130,7 +130,7 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
|
||||||
struct rsn_pmksa_cache_entry *entry, *pos, *prev;
|
struct rsn_pmksa_cache_entry *entry, *pos, *prev;
|
||||||
struct os_reltime now;
|
struct os_reltime now;
|
||||||
|
|
||||||
if (pmk_len > PMK_LEN)
|
if (pmk_len > PMK_LEN_MAX)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (wpa_key_mgmt_suite_b(akmp) && !kck)
|
if (wpa_key_mgmt_suite_b(akmp) && !kck)
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
struct rsn_pmksa_cache_entry {
|
struct rsn_pmksa_cache_entry {
|
||||||
struct rsn_pmksa_cache_entry *next;
|
struct rsn_pmksa_cache_entry *next;
|
||||||
u8 pmkid[PMKID_LEN];
|
u8 pmkid[PMKID_LEN];
|
||||||
u8 pmk[PMK_LEN];
|
u8 pmk[PMK_LEN_MAX];
|
||||||
size_t pmk_len;
|
size_t pmk_len;
|
||||||
os_time_t expiration;
|
os_time_t expiration;
|
||||||
int akmp; /* WPA_KEY_MGMT_* */
|
int akmp; /* WPA_KEY_MGMT_* */
|
||||||
|
|
|
@ -206,15 +206,21 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
|
||||||
#endif /* CONFIG_IEEE80211R */
|
#endif /* CONFIG_IEEE80211R */
|
||||||
} else if (wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) && sm->eapol) {
|
} else if (wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) && sm->eapol) {
|
||||||
int res, pmk_len;
|
int res, pmk_len;
|
||||||
pmk_len = PMK_LEN;
|
|
||||||
res = eapol_sm_get_key(sm->eapol, sm->pmk, PMK_LEN);
|
if (sm->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
|
||||||
|
pmk_len = PMK_LEN_SUITE_B_192;
|
||||||
|
else
|
||||||
|
pmk_len = PMK_LEN;
|
||||||
|
res = eapol_sm_get_key(sm->eapol, sm->pmk, pmk_len);
|
||||||
if (res) {
|
if (res) {
|
||||||
/*
|
if (pmk_len == PMK_LEN) {
|
||||||
* EAP-LEAP is an exception from other EAP methods: it
|
/*
|
||||||
* uses only 16-byte PMK.
|
* EAP-LEAP is an exception from other EAP
|
||||||
*/
|
* methods: it uses only 16-byte PMK.
|
||||||
res = eapol_sm_get_key(sm->eapol, sm->pmk, 16);
|
*/
|
||||||
pmk_len = 16;
|
res = eapol_sm_get_key(sm->eapol, sm->pmk, 16);
|
||||||
|
pmk_len = 16;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
#ifdef CONFIG_IEEE80211R
|
#ifdef CONFIG_IEEE80211R
|
||||||
u8 buf[2 * PMK_LEN];
|
u8 buf[2 * PMK_LEN];
|
||||||
|
|
|
@ -19,7 +19,7 @@ struct wpa_eapol_key;
|
||||||
* struct wpa_sm - Internal WPA state machine data
|
* struct wpa_sm - Internal WPA state machine data
|
||||||
*/
|
*/
|
||||||
struct wpa_sm {
|
struct wpa_sm {
|
||||||
u8 pmk[PMK_LEN];
|
u8 pmk[PMK_LEN_MAX];
|
||||||
size_t pmk_len;
|
size_t pmk_len;
|
||||||
struct wpa_ptk ptk, tptk;
|
struct wpa_ptk ptk, tptk;
|
||||||
int ptk_set, tptk_set;
|
int ptk_set, tptk_set;
|
||||||
|
|
Loading…
Reference in a new issue