Suite B: PMKID derivation for AKM 00-0F-AC:11
authorJouni Malinen <j@w1.fi>
Sun, 16 Nov 2014 11:22:46 +0000 (13:22 +0200)
committerJouni Malinen <j@w1.fi>
Sun, 16 Nov 2014 15:09:11 +0000 (17:09 +0200)
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>
13 files changed:
hostapd/Android.mk
hostapd/Makefile
src/ap/pmksa_cache_auth.c
src/ap/pmksa_cache_auth.h
src/ap/wpa_auth.c
src/common/wpa_common.c
src/common/wpa_common.h
src/rsn_supp/pmksa_cache.c
src/rsn_supp/pmksa_cache.h
src/rsn_supp/preauth.c
src/rsn_supp/wpa.c
wpa_supplicant/Android.mk
wpa_supplicant/Makefile

index 84a8778..a6cb8d0 100644 (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
index 86b6ea5..06cd6c7 100644 (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
index 44c4a0d..4270382 100644 (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)
index b2d4e9d..519555f 100644 (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 *
index 102845b..562801a 100644 (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;
index 897f726..f87e791 100644 (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)
index 0ef5a9d..3bacbdc 100644 (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);
index 885291a..5f29627 100644 (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)
index 6cbf89a..f8e040e 100644 (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;
index e392125..13a6cad 100644 (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);
index 47e3607..9c840c6 100644 (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);
        }
 }
index bfe5215..b09e1d6 100644 (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
index 7e19cf8..1547ec5 100644 (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