]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Fix Suite B 192-bit AKM to use proper PMK length
authorJouni Malinen <jouni@qca.qualcomm.com>
Tue, 13 Oct 2015 22:18:11 +0000 (01:18 +0300)
committerJouni Malinen <j@w1.fi>
Wed, 14 Oct 2015 15:43:26 +0000 (18:43 +0300)
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>
src/ap/ieee802_1x.c
src/ap/pmksa_cache_auth.c
src/ap/pmksa_cache_auth.h
src/ap/wpa_auth.c
src/ap/wpa_auth.h
src/ap/wpa_auth_i.h
src/common/wpa_common.h
src/rsn_supp/pmksa_cache.c
src/rsn_supp/pmksa_cache.h
src/rsn_supp/wpa.c
src/rsn_supp/wpa_i.h

index 0c4d6aecd816280c60779bbc71972773e74f016f..68fdb72b192854f174ea614b3d6968ae4bc62352 100644 (file)
@@ -2575,7 +2575,7 @@ static void ieee802_1x_finished(struct hostapd_data *hapd,
                session_timeout = dot11RSNAConfigPMKLifetime;
        if (success && key && len >= PMK_LEN && !sta->remediation &&
            !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) {
                hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
                               HOSTAPD_LEVEL_DEBUG,
index 877affe4eadcc2c0c8f59ec3184edbaf8e58ba21..83e4bdabdce9d1e8f81fd6150cab3b6920fec6c3 100644 (file)
@@ -258,7 +258,7 @@ pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
        struct rsn_pmksa_cache_entry *entry, *pos;
        struct os_reltime now;
 
-       if (pmk_len > PMK_LEN)
+       if (pmk_len > PMK_LEN_MAX)
                return NULL;
 
        if (wpa_key_mgmt_suite_b(akmp) && !kck)
index 8b7be1291b53a7dda2e023659409b518386071d1..b2da379bc34821a2c1980933dbd0840c9c882ac7 100644 (file)
@@ -17,7 +17,7 @@
 struct rsn_pmksa_cache_entry {
        struct rsn_pmksa_cache_entry *next, *hnext;
        u8 pmkid[PMKID_LEN];
-       u8 pmk[PMK_LEN];
+       u8 pmk[PMK_LEN_MAX];
        size_t pmk_len;
        os_time_t expiration;
        int akmp; /* WPA_KEY_MGMT_* */
index 9c136efec2dabe4f0100390ffa3dd7b98f9763a8..c2c5693c51e63ded681b6f68b87a6702387c53ea 100644 (file)
@@ -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,
                                       struct wpa_group *group);
 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,
                           struct wpa_group *group);
 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;
        int ok = 0;
        const u8 *pmk = NULL;
+       unsigned int pmk_len;
 
        for (;;) {
                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);
                        if (pmk == NULL)
                                break;
-               } else
+                       pmk_len = PMK_LEN;
+               } else {
                        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)
                    == 0) {
@@ -1904,11 +1909,27 @@ SM_STATE(WPA_PTK, INITPMK)
 #endif /* CONFIG_IEEE80211R */
        if (sm->pmksa) {
                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) {
+               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 "
-                          "(len=%lu)", (unsigned long) len);
-               os_memcpy(sm->PMK, msk, PMK_LEN);
+                          "(MSK len=%lu PMK len=%u)", (unsigned long) 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
                if (len >= 2 * 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);
        if (psk) {
                os_memcpy(sm->PMK, psk, PMK_LEN);
+               sm->pmk_len = PMK_LEN;
 #ifdef CONFIG_IEEE80211R
                os_memcpy(sm->xxkey, psk, PMK_LEN);
                sm->xxkey_len = PMK_LEN;
@@ -1994,7 +2016,7 @@ SM_STATE(WPA_PTK, PTKSTART)
                         * Calculate PMKID since no PMKSA cache entry was
                         * 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],
                                  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,
-                         const u8 *pmk, struct wpa_ptk *ptk)
+                         const u8 *pmk, unsigned int pmk_len,
+                         struct wpa_ptk *ptk)
 {
 #ifdef CONFIG_IEEE80211R
        if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
                return wpa_auth_derive_ptk_ft(sm, pmk, ptk);
 #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,
                              ptk, sm->wpa_key_mgmt, sm->pairwise);
 }
@@ -2024,6 +2047,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
        struct wpa_ptk PTK;
        int ok = 0, psk_found = 0;
        const u8 *pmk = NULL;
+       unsigned int pmk_len;
 
        SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
        sm->EAPOLKeyReceived = FALSE;
@@ -2039,10 +2063,13 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
                        if (pmk == NULL)
                                break;
                        psk_found = 1;
-               } else
+                       pmk_len = PMK_LEN;
+               } else {
                        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,
                                       sm->last_rx_eapol_key,
@@ -2092,6 +2119,7 @@ SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
                 * state machine data based on whatever PSK was selected here.
                 */
                os_memcpy(sm->PMK, pmk, PMK_LEN);
+               sm->pmk_len = PMK_LEN;
        }
 
        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,
+                      unsigned int pmk_len,
                       int session_timeout, struct eapol_state_machine *eapol)
 {
        if (sm == NULL || sm->wpa != WPA_VERSION_WPA2 ||
            sm->wpa_auth->conf.disable_pmksa_caching)
                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->wpa_auth->addr, sm->addr, session_timeout,
                                 eapol, sm->wpa_key_mgmt))
index 7d432efc1662e09fd423df144e180ae53baef695..75b73f024ab032b7ad301efbf0780458087f000e 100644 (file)
@@ -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,
                               size_t *len);
 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 wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
                               const u8 *pmk, size_t len, const u8 *sta_addr,
index 409efb9be0021fa035a308e0f7ed21d1a7f63608..72b7eb37a3a7a5a5a06fd7d72b1322c72ecc8b76 100644 (file)
@@ -60,7 +60,8 @@ struct wpa_state_machine {
        u8 SNonce[WPA_NONCE_LEN];
        u8 alt_SNonce[WPA_NONCE_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;
        Boolean PTK_valid;
        Boolean pairwise_set;
index c08f6514ab5732df723270aac27af5c267cca777..ee71bfc092e0c12ab1a8c796640f0d8d38cd3f83 100644 (file)
@@ -12,6 +12,8 @@
 /* IEEE 802.11i */
 #define PMKID_LEN 16
 #define PMK_LEN 32
+#define PMK_LEN_SUITE_B_192 48
+#define PMK_LEN_MAX 48
 #define WPA_REPLAY_COUNTER_LEN 8
 #define WPA_NONCE_LEN 32
 #define WPA_KEY_RSC_LEN 8
index ef7b6838647651f66f030d09ee0f220d12809cb1..b221e1242de2a07e8d0b53aebc1d34f4d520a289 100644 (file)
@@ -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 os_reltime now;
 
-       if (pmk_len > PMK_LEN)
+       if (pmk_len > PMK_LEN_MAX)
                return NULL;
 
        if (wpa_key_mgmt_suite_b(akmp) && !kck)
index f8e040e067d95da9305197f434be126def199789..7ec09ea329209cd438dca4ddae6c9ce702a85d39 100644 (file)
@@ -15,7 +15,7 @@
 struct rsn_pmksa_cache_entry {
        struct rsn_pmksa_cache_entry *next;
        u8 pmkid[PMKID_LEN];
-       u8 pmk[PMK_LEN];
+       u8 pmk[PMK_LEN_MAX];
        size_t pmk_len;
        os_time_t expiration;
        int akmp; /* WPA_KEY_MGMT_* */
index f1f65c61ab27b1f640e92844d3c0702bdf17bd5c..3968f4b29a0f8a6a4f05d0740ba1741da746cfa2 100644 (file)
@@ -206,15 +206,21 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
 #endif /* CONFIG_IEEE80211R */
        } else if (wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) && sm->eapol) {
                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) {
-                       /*
-                        * 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;
+                       if (pmk_len == PMK_LEN) {
+                               /*
+                                * 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;
+                       }
                } else {
 #ifdef CONFIG_IEEE80211R
                        u8 buf[2 * PMK_LEN];
index 939e0a9902e682d40b8781fe3e99672ad3207258..af2d8c0c31b66e996024b9d0646cf5cbe624f0d2 100644 (file)
@@ -19,7 +19,7 @@ struct wpa_eapol_key;
  * struct wpa_sm - Internal WPA state machine data
  */
 struct wpa_sm {
-       u8 pmk[PMK_LEN];
+       u8 pmk[PMK_LEN_MAX];
        size_t pmk_len;
        struct wpa_ptk ptk, tptk;
        int ptk_set, tptk_set;