Suite B: PMKID derivation for AKM 00-0F-AC:11
[mech_eap.git] / src / rsn_supp / wpa.c
index acb4ee6..9c840c6 100644 (file)
@@ -138,6 +138,24 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
 }
 
 
+static void wpa_supplicant_key_mgmt_set_pmk(struct wpa_sm *sm)
+{
+#ifdef CONFIG_IEEE80211R
+       if (sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
+               if (wpa_sm_key_mgmt_set_pmk(sm, sm->xxkey, sm->xxkey_len))
+                       wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+                               "RSN: Cannot set low order 256 bits of MSK for key management offload");
+       } else {
+#endif /* CONFIG_IEEE80211R */
+               if (wpa_sm_key_mgmt_set_pmk(sm, sm->pmk, sm->pmk_len))
+                       wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+                               "RSN: Cannot set PMK for key management offload");
+#ifdef CONFIG_IEEE80211R
+       }
+#endif /* CONFIG_IEEE80211R */
+}
+
+
 static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
                                  const unsigned char *src_addr,
                                  const u8 *pmkid)
@@ -162,7 +180,7 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
        }
 
        if (pmkid && sm->cur_pmksa &&
-           os_memcmp(pmkid, sm->cur_pmksa->pmkid, PMKID_LEN) == 0) {
+           os_memcmp_const(pmkid, sm->cur_pmksa->pmkid, PMKID_LEN) == 0) {
                wpa_hexdump(MSG_DEBUG, "RSN: matched PMKID", pmkid, PMKID_LEN);
                wpa_sm_set_pmk_from_pmksa(sm);
                wpa_hexdump_key(MSG_DEBUG, "RSN: PMK from PMKSA cache",
@@ -198,10 +216,13 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
                        wpa_hexdump_key(MSG_DEBUG, "WPA: PMK from EAPOL state "
                                        "machines", sm->pmk, pmk_len);
                        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);
@@ -235,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. */
@@ -906,7 +928,8 @@ static int ft_validate_rsnie(struct wpa_sm *sm,
                return -1;
        }
 
-       if (os_memcmp(rsn.pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0) {
+       if (os_memcmp_const(rsn.pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0)
+       {
                wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
                        "FT: PMKR1Name mismatch in "
                        "FT 4-way handshake message 3/4");
@@ -1177,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:
@@ -1294,7 +1328,8 @@ static int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm,
                                (unsigned long) maxkeylen);
                        return -1;
                }
-               if (aes_unwrap(sm->ptk.kek, maxkeylen / 8, key_data, gd->gtk)) {
+               if (aes_unwrap(sm->ptk.kek, 16, maxkeylen / 8, key_data,
+                              gd->gtk)) {
                        wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
                                "WPA: AES unwrap failed - could not decrypt "
                                "GTK");
@@ -1418,7 +1453,7 @@ static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,
                os_memset(key->key_mic, 0, 16);
                wpa_eapol_key_mic(sm->tptk.kck, ver, buf, len,
                                  key->key_mic);
-               if (os_memcmp(mic, key->key_mic, 16) != 0) {
+               if (os_memcmp_const(mic, key->key_mic, 16) != 0) {
                        wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
                                "WPA: Invalid EAPOL-Key MIC "
                                "when using TPTK - ignoring TPTK");
@@ -1435,7 +1470,7 @@ static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,
                os_memset(key->key_mic, 0, 16);
                wpa_eapol_key_mic(sm->ptk.kck, ver, buf, len,
                                  key->key_mic);
-               if (os_memcmp(mic, key->key_mic, 16) != 0) {
+               if (os_memcmp_const(mic, key->key_mic, 16) != 0) {
                        wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
                                "WPA: Invalid EAPOL-Key MIC - "
                                "dropping packet");
@@ -1502,7 +1537,7 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,
                                "WPA: No memory for AES-UNWRAP buffer");
                        return -1;
                }
-               if (aes_unwrap(sm->ptk.kek, *key_data_len / 8,
+               if (aes_unwrap(sm->ptk.kek, 16, *key_data_len / 8,
                               key_data, buf)) {
                        os_free(buf);
                        wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
@@ -1735,6 +1770,9 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
                        wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
                                "WPA: Backwards compatibility: allow invalid "
                                "version for non-CCMP group keys");
+               } else if (ver == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+                       wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+                               "WPA: Interoperability workaround: allow incorrect (should have been HMAC-SHA1), but stronger (is AES-128-CMAC), descriptor version to be used");
                } else
                        goto out;
        } else if (sm->pairwise_cipher == WPA_CIPHER_GCMP &&
@@ -1901,6 +1939,8 @@ static u32 wpa_key_mgmt_suite(struct wpa_sm *sm)
                        WPA_AUTH_KEY_MGMT_CCKM);
        case WPA_KEY_MGMT_WPA_NONE:
                return WPA_AUTH_KEY_MGMT_NONE;
+       case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
+               return RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
        default:
                return 0;
        }
@@ -2179,10 +2219,12 @@ void wpa_sm_notify_disassoc(struct wpa_sm *sm)
  * @sm: Pointer to WPA state machine data from wpa_sm_init()
  * @pmk: The new PMK
  * @pmk_len: The length of the new PMK in bytes
+ * @bssid: AA to add into PMKSA cache or %NULL to not cache the PMK
  *
  * Configure the PMK for WPA state machine.
  */
-void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len)
+void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
+                   const u8 *bssid)
 {
        if (sm == NULL)
                return;
@@ -2195,6 +2237,12 @@ void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len)
        sm->xxkey_len = pmk_len;
        os_memcpy(sm->xxkey, pmk, pmk_len);
 #endif /* CONFIG_IEEE80211R */
+
+       if (bssid) {
+               pmksa_cache_add(sm->pmksa, pmk, pmk_len, NULL, 0,
+                               bssid, sm->own_addr,
+                               sm->network_ctx, sm->key_mgmt);
+       }
 }
 
 
@@ -2778,3 +2826,30 @@ int wpa_sm_get_p2p_ip_addr(struct wpa_sm *sm, u8 *buf)
 }
 
 #endif /* CONFIG_P2P */
+
+
+void wpa_sm_set_rx_replay_ctr(struct wpa_sm *sm, const u8 *rx_replay_counter)
+{
+       if (rx_replay_counter == NULL)
+               return;
+
+       os_memcpy(sm->rx_replay_counter, rx_replay_counter,
+                 WPA_REPLAY_COUNTER_LEN);
+       sm->rx_replay_counter_set = 1;
+       wpa_printf(MSG_DEBUG, "Updated key replay counter");
+}
+
+
+void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm, const u8 *ptk_kck,
+                           const u8 *ptk_kek)
+{
+       if (ptk_kck) {
+               os_memcpy(sm->ptk.kck, ptk_kck, 16);
+               wpa_printf(MSG_DEBUG, "Updated PTK KCK");
+       }
+       if (ptk_kek) {
+               os_memcpy(sm->ptk.kek, ptk_kek, 16);
+               wpa_printf(MSG_DEBUG, "Updated PTK KEK");
+       }
+       sm->ptk_set = 1;
+}