Suite B: PMKID derivation for AKM 00-0F-AC:11

The new AKM uses a different mechanism of deriving the PMKID based on
KCK instead of PMK. hostapd was already doing this after the KCK had
been derived, but wpa_supplicant functionality needs to be moved from
processing of EAPOL-Key frame 1/4 to 3/4 to have the KCK available.

Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
Jouni Malinen 2014-11-16 13:22:46 +02:00
parent 666497c8e6
commit 087a1f4efd
13 changed files with 117 additions and 8 deletions

View file

@ -203,6 +203,12 @@ ifdef CONFIG_HS20
NEED_AES_OMAC1=y
endif
ifdef CONFIG_SUITEB
L_CFLAGS += -DCONFIG_SUITEB
NEED_SHA256=y
NEED_AES_OMAC1=y
endif
ifdef CONFIG_IEEE80211W
L_CFLAGS += -DCONFIG_IEEE80211W
NEED_SHA256=y

View file

@ -195,6 +195,12 @@ ifdef CONFIG_PROXYARP
CONFIG_L2_PACKET=y
endif
ifdef CONFIG_SUITEB
CFLAGS += -DCONFIG_SUITEB
NEED_SHA256=y
NEED_AES_OMAC1=y
endif
ifdef CONFIG_IEEE80211W
CFLAGS += -DCONFIG_IEEE80211W
NEED_SHA256=y

View file

@ -233,6 +233,8 @@ static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
* @pmk: The new pairwise master key
* @pmk_len: PMK length in bytes, usually PMK_LEN (32)
* @kck: Key confirmation key or %NULL if not yet derived
* @kck_len: KCK length in bytes
* @aa: Authenticator address
* @spa: Supplicant address
* @session_timeout: Session timeout
@ -248,8 +250,9 @@ static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
struct rsn_pmksa_cache_entry *
pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
const u8 *pmk, size_t pmk_len,
const u8 *aa, const u8 *spa, int session_timeout,
struct eapol_state_machine *eapol, int akmp)
const u8 *kck, size_t kck_len,
const u8 *aa, const u8 *spa, int session_timeout,
struct eapol_state_machine *eapol, int akmp)
{
struct rsn_pmksa_cache_entry *entry, *pos;
struct os_reltime now;
@ -257,13 +260,19 @@ pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
if (pmk_len > PMK_LEN)
return NULL;
if (wpa_key_mgmt_suite_b(akmp) && !kck)
return NULL;
entry = os_zalloc(sizeof(*entry));
if (entry == NULL)
return NULL;
os_memcpy(entry->pmk, pmk, pmk_len);
entry->pmk_len = pmk_len;
rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
wpa_key_mgmt_sha256(akmp));
if (wpa_key_mgmt_suite_b(akmp))
rsn_pmkid_suite_b(kck, kck_len, aa, spa, entry->pmkid);
else
rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
wpa_key_mgmt_sha256(akmp));
os_get_reltime(&now);
entry->expiration = now.sec;
if (session_timeout > 0)

View file

@ -50,6 +50,7 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
struct rsn_pmksa_cache_entry *
pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
const u8 *pmk, size_t pmk_len,
const u8 *kck, size_t kck_len,
const u8 *aa, const u8 *spa, int session_timeout,
struct eapol_state_machine *eapol, int akmp);
struct rsn_pmksa_cache_entry *

View file

@ -3057,6 +3057,7 @@ int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
return -1;
if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, PMK_LEN,
sm->PTK.kck, sizeof(sm->PTK.kck),
sm->wpa_auth->addr, sm->addr, session_timeout,
eapol, sm->wpa_key_mgmt))
return 0;
@ -3073,7 +3074,9 @@ int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
if (wpa_auth == NULL)
return -1;
if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, len, wpa_auth->addr,
if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, len,
NULL, 0,
wpa_auth->addr,
sta_addr, session_timeout, eapol,
WPA_KEY_MGMT_IEEE8021X))
return 0;
@ -3089,6 +3092,7 @@ int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr,
return -1;
if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, PMK_LEN,
NULL, 0,
wpa_auth->addr, addr, 0, NULL,
WPA_KEY_MGMT_SAE))
return 0;

View file

@ -929,6 +929,39 @@ void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
}
#ifdef CONFIG_SUITEB
/**
* rsn_pmkid_suite_b - Calculate PMK identifier for Suite B AKM
* @kck: Key confirmation key
* @kck_len: Length of kck in bytes
* @aa: Authenticator address
* @spa: Supplicant address
* @pmkid: Buffer for PMKID
* Returns: 0 on success, -1 on failure
*
* IEEE Std 802.11ac-2013 - 11.6.1.3 Pairwise key hierarchy
* PMKID = Truncate(HMAC-SHA-256(KCK, "PMK Name" || AA || SPA))
*/
int rsn_pmkid_suite_b(const u8 *kck, size_t kck_len, const u8 *aa,
const u8 *spa, u8 *pmkid)
{
char *title = "PMK Name";
const u8 *addr[3];
const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
unsigned char hash[SHA256_MAC_LEN];
addr[0] = (u8 *) title;
addr[1] = aa;
addr[2] = spa;
if (hmac_sha256_vector(kck, kck_len, 3, addr, len, hash) < 0)
return -1;
os_memcpy(pmkid, hash, PMKID_LEN);
return 0;
}
#endif /* CONFIG_SUITEB */
/**
* wpa_cipher_txt - Convert cipher suite to a text string
* @cipher: Cipher suite (WPA_CIPHER_* enum)

View file

@ -374,6 +374,16 @@ int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
u8 *pmkid, int use_sha256);
#ifdef CONFIG_SUITEB
int rsn_pmkid_suite_b(const u8 *kck, size_t kck_len, const u8 *aa,
const u8 *spa, u8 *pmkid);
#else /* CONFIG_SUITEB */
static inline int rsn_pmkid_suite_b(const u8 *kck, size_t kck_len, const u8 *aa,
const u8 *spa, u8 *pmkid)
{
return -1;
}
#endif /* CONFIG_SUITEB */
const char * wpa_cipher_txt(int cipher);
const char * wpa_key_mgmt_txt(int key_mgmt, int proto);

View file

@ -109,6 +109,8 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
* @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
* @pmk: The new pairwise master key
* @pmk_len: PMK length in bytes, usually PMK_LEN (32)
* @kck: Key confirmation key or %NULL if not yet derived
* @kck_len: KCK length in bytes
* @aa: Authenticator address
* @spa: Supplicant address
* @network_ctx: Network configuration context for this PMK
@ -122,6 +124,7 @@ static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
*/
struct rsn_pmksa_cache_entry *
pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
const u8 *kck, size_t kck_len,
const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
{
struct rsn_pmksa_cache_entry *entry, *pos, *prev;
@ -130,13 +133,19 @@ pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
if (pmk_len > PMK_LEN)
return NULL;
if (wpa_key_mgmt_suite_b(akmp) && !kck)
return NULL;
entry = os_zalloc(sizeof(*entry));
if (entry == NULL)
return NULL;
os_memcpy(entry->pmk, pmk, pmk_len);
entry->pmk_len = pmk_len;
rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
wpa_key_mgmt_sha256(akmp));
if (wpa_key_mgmt_suite_b(akmp))
rsn_pmkid_suite_b(kck, kck_len, aa, spa, entry->pmkid);
else
rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
wpa_key_mgmt_sha256(akmp));
os_get_reltime(&now);
entry->expiration = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime;
entry->reauth_time = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime *
@ -333,6 +342,7 @@ pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa,
struct rsn_pmksa_cache_entry *new_entry;
new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len,
NULL, 0,
aa, pmksa->sm->own_addr,
old_entry->network_ctx, old_entry->akmp);
if (new_entry == NULL)

View file

@ -57,6 +57,7 @@ struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len);
struct rsn_pmksa_cache_entry *
pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
const u8 *kck, size_t kck_len,
const u8 *aa, const u8 *spa, void *network_ctx, int akmp);
struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm);
void pmksa_cache_clear_current(struct wpa_sm *sm);
@ -104,6 +105,7 @@ static inline int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf,
static inline struct rsn_pmksa_cache_entry *
pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
const u8 *kck, size_t kck_len,
const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
{
return NULL;

View file

@ -94,6 +94,7 @@ static void rsn_preauth_eapol_cb(struct eapol_sm *eapol,
pmk, pmk_len);
sm->pmk_len = pmk_len;
pmksa_cache_add(sm->pmksa, pmk, pmk_len,
NULL, 0,
sm->preauth_bssid, sm->own_addr,
sm->network_ctx,
WPA_KEY_MGMT_IEEE8021X);

View file

@ -218,9 +218,11 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
sm->pmk_len = pmk_len;
wpa_supplicant_key_mgmt_set_pmk(sm);
if (sm->proto == WPA_PROTO_RSN &&
!wpa_key_mgmt_suite_b(sm->key_mgmt) &&
!wpa_key_mgmt_ft(sm->key_mgmt)) {
sa = pmksa_cache_add(sm->pmksa,
sm->pmk, pmk_len,
NULL, 0,
src_addr, sm->own_addr,
sm->network_ctx,
sm->key_mgmt);
@ -254,6 +256,7 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
}
if (abort_cached && wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) &&
!wpa_key_mgmt_suite_b(sm->key_mgmt) &&
!wpa_key_mgmt_ft(sm->key_mgmt) && sm->key_mgmt != WPA_KEY_MGMT_OSEN)
{
/* Send EAPOL-Start to trigger full EAP authentication. */
@ -1197,6 +1200,17 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
if (ie.gtk)
wpa_sm_set_rekey_offload(sm);
if (sm->proto == WPA_PROTO_RSN && wpa_key_mgmt_suite_b(sm->key_mgmt)) {
struct rsn_pmksa_cache_entry *sa;
sa = pmksa_cache_add(sm->pmksa, sm->pmk, sm->pmk_len,
sm->ptk.kck, sizeof(sm->ptk.kck),
sm->bssid, sm->own_addr,
sm->network_ctx, sm->key_mgmt);
if (!sm->cur_pmksa)
sm->cur_pmksa = sa;
}
return;
failed:
@ -2225,7 +2239,8 @@ void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
#endif /* CONFIG_IEEE80211R */
if (bssid) {
pmksa_cache_add(sm->pmksa, pmk, pmk_len, bssid, sm->own_addr,
pmksa_cache_add(sm->pmksa, pmk, pmk_len, NULL, 0,
bssid, sm->own_addr,
sm->network_ctx, sm->key_mgmt);
}
}

View file

@ -182,6 +182,12 @@ ifdef CONFIG_NO_SCAN_PROCESSING
L_CFLAGS += -DCONFIG_NO_SCAN_PROCESSING
endif
ifdef CONFIG_SUITEB
L_CFLAGS += -DCONFIG_SUITEB
NEED_SHA256=y
NEED_AES_OMAC1=y
endif
ifdef CONFIG_IEEE80211W
L_CFLAGS += -DCONFIG_IEEE80211W
NEED_SHA256=y

View file

@ -185,6 +185,12 @@ ifdef CONFIG_NO_SCAN_PROCESSING
CFLAGS += -DCONFIG_NO_SCAN_PROCESSING
endif
ifdef CONFIG_SUITEB
CFLAGS += -DCONFIG_SUITEB
NEED_SHA256=y
NEED_AES_OMAC1=y
endif
ifdef CONFIG_IEEE80211W
CFLAGS += -DCONFIG_IEEE80211W
NEED_SHA256=y