OSDN Git Service

Accumulative patch from commit dc013f1e37df3462085cf01a13f0c432f146ad7a
[android-x86/external-wpa_supplicant_8.git] / src / ap / wpa_auth.c
index 1d942a4..fa4b1cb 100644 (file)
@@ -54,11 +54,12 @@ static const int dot11RSNAConfigPMKReauthThreshold = 70;
 static const int dot11RSNAConfigSATimeout = 60;
 
 
-static inline void wpa_auth_mic_failure_report(
+static inline int wpa_auth_mic_failure_report(
        struct wpa_authenticator *wpa_auth, const u8 *addr)
 {
        if (wpa_auth->cb.mic_failure_report)
-               wpa_auth->cb.mic_failure_report(wpa_auth->cb.ctx, addr);
+               return wpa_auth->cb.mic_failure_report(wpa_auth->cb.ctx, addr);
+       return 0;
 }
 
 
@@ -278,30 +279,12 @@ static void wpa_auth_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry,
 }
 
 
-static void wpa_group_set_key_len(struct wpa_group *group, int cipher)
-{
-       switch (cipher) {
-       case WPA_CIPHER_CCMP:
-               group->GTK_len = 16;
-               break;
-       case WPA_CIPHER_TKIP:
-               group->GTK_len = 32;
-               break;
-       case WPA_CIPHER_WEP104:
-               group->GTK_len = 13;
-               break;
-       case WPA_CIPHER_WEP40:
-               group->GTK_len = 5;
-               break;
-       }
-}
-
-
 static int wpa_group_init_gmk_and_counter(struct wpa_authenticator *wpa_auth,
                                          struct wpa_group *group)
 {
-       u8 buf[ETH_ALEN + 8 + sizeof(group)];
+       u8 buf[ETH_ALEN + 8 + sizeof(unsigned long)];
        u8 rkey[32];
+       unsigned long ptr;
 
        if (random_get_bytes(group->GMK, WPA_GMK_LEN) < 0)
                return -1;
@@ -313,7 +296,8 @@ static int wpa_group_init_gmk_and_counter(struct wpa_authenticator *wpa_auth,
         */
        os_memcpy(buf, wpa_auth->addr, ETH_ALEN);
        wpa_get_ntp_timestamp(buf + ETH_ALEN);
-       os_memcpy(buf + ETH_ALEN + 8, &group, sizeof(group));
+       ptr = (unsigned long) group;
+       os_memcpy(buf + ETH_ALEN + 8, &ptr, sizeof(ptr));
        if (random_get_bytes(rkey, sizeof(rkey)) < 0)
                return -1;
 
@@ -338,8 +322,7 @@ static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
 
        group->GTKAuthenticator = TRUE;
        group->vlan_id = vlan_id;
-
-       wpa_group_set_key_len(group, wpa_auth->conf.wpa_group);
+       group->GTK_len = wpa_cipher_key_len(wpa_auth->conf.wpa_group);
 
        if (random_pool_ready() != 1) {
                wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool "
@@ -514,7 +497,7 @@ int wpa_reconfig(struct wpa_authenticator *wpa_auth,
         * configuration.
         */
        group = wpa_auth->group;
-       wpa_group_set_key_len(group, wpa_auth->conf.wpa_group);
+       group->GTK_len = wpa_cipher_key_len(wpa_auth->conf.wpa_group);
        group->GInit = TRUE;
        wpa_group_sm_step(wpa_auth, group);
        group->GInit = FALSE;
@@ -720,8 +703,8 @@ static int ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth,
 #endif /* CONFIG_IEEE80211R */
 
 
-static void wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
-                                    struct wpa_state_machine *sm, int group)
+static int wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
+                                   struct wpa_state_machine *sm, int group)
 {
        /* Supplicant reported a Michael MIC error */
        wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
@@ -738,7 +721,8 @@ static void wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
                                "ignore Michael MIC failure report since "
                                "pairwise cipher is not TKIP");
        } else {
-               wpa_auth_mic_failure_report(wpa_auth, sm->addr);
+               if (wpa_auth_mic_failure_report(wpa_auth, sm->addr) > 0)
+                       return 1; /* STA entry was removed */
                sm->dot11RSNAStatsTKIPRemoteMICFailures++;
                wpa_auth->dot11RSNAStatsTKIPRemoteMICFailures++;
        }
@@ -748,6 +732,7 @@ static void wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
         * Authenticator may do it, let's change the keys now anyway.
         */
        wpa_request_new_ptk(sm);
+       return 0;
 }
 
 
@@ -849,7 +834,8 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
        if (msg == REQUEST || msg == PAIRWISE_2 || msg == PAIRWISE_4 ||
            msg == GROUP_2) {
                u16 ver = key_info & WPA_KEY_INFO_TYPE_MASK;
-               if (sm->pairwise == WPA_CIPHER_CCMP) {
+               if (sm->pairwise == WPA_CIPHER_CCMP ||
+                   sm->pairwise == WPA_CIPHER_GCMP) {
                        if (wpa_use_aes_cmac(sm) &&
                            ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
                                wpa_auth_logger(wpa_auth, sm->addr,
@@ -865,7 +851,7 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
                                wpa_auth_logger(wpa_auth, sm->addr,
                                                LOGGER_WARNING,
                                                "did not use HMAC-SHA1-AES "
-                                               "with CCMP");
+                                               "with CCMP/GCMP");
                                return;
                        }
                }
@@ -1100,9 +1086,10 @@ continue_processing:
 #endif /* CONFIG_PEERKEY */
                        return;
                } else if (key_info & WPA_KEY_INFO_ERROR) {
-                       wpa_receive_error_report(
-                               wpa_auth, sm,
-                               !(key_info & WPA_KEY_INFO_KEY_TYPE));
+                       if (wpa_receive_error_report(
+                                   wpa_auth, sm,
+                                   !(key_info & WPA_KEY_INFO_KEY_TYPE)) > 0)
+                               return; /* STA entry was removed */
                } else if (key_info & WPA_KEY_INFO_KEY_TYPE) {
                        wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
                                        "received EAPOL-Key Request for new "
@@ -1240,7 +1227,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
                version = force_version;
        else if (wpa_use_aes_cmac(sm))
                version = WPA_KEY_INFO_TYPE_AES_128_CMAC;
-       else if (sm->pairwise == WPA_CIPHER_CCMP)
+       else if (sm->pairwise != WPA_CIPHER_TKIP)
                version = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
        else
                version = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
@@ -1287,20 +1274,7 @@ void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
        WPA_PUT_BE16(key->key_info, key_info);
 
        alg = pairwise ? sm->pairwise : wpa_auth->conf.wpa_group;
-       switch (alg) {
-       case WPA_CIPHER_CCMP:
-               WPA_PUT_BE16(key->key_length, 16);
-               break;
-       case WPA_CIPHER_TKIP:
-               WPA_PUT_BE16(key->key_length, 32);
-               break;
-       case WPA_CIPHER_WEP40:
-               WPA_PUT_BE16(key->key_length, 5);
-               break;
-       case WPA_CIPHER_WEP104:
-               WPA_PUT_BE16(key->key_length, 13);
-               break;
-       }
+       WPA_PUT_BE16(key->key_length, wpa_cipher_key_len(alg));
        if (key_info & WPA_KEY_INFO_SMK_MESSAGE)
                WPA_PUT_BE16(key->key_length, 0);
 
@@ -1533,22 +1507,6 @@ int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event)
 }
 
 
-static enum wpa_alg wpa_alg_enum(int alg)
-{
-       switch (alg) {
-       case WPA_CIPHER_CCMP:
-               return WPA_ALG_CCMP;
-       case WPA_CIPHER_TKIP:
-               return WPA_ALG_TKIP;
-       case WPA_CIPHER_WEP104:
-       case WPA_CIPHER_WEP40:
-               return WPA_ALG_WEP;
-       default:
-               return WPA_ALG_NONE;
-       }
-}
-
-
 SM_STATE(WPA_PTK, INITIALIZE)
 {
        SM_ENTRY_MA(WPA_PTK, INITIALIZE, wpa_ptk);
@@ -1773,7 +1731,7 @@ SM_STATE(WPA_PTK, PTKSTART)
 static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *pmk,
                          struct wpa_ptk *ptk)
 {
-       size_t ptk_len = sm->pairwise == WPA_CIPHER_CCMP ? 48 : 64;
+       size_t ptk_len = sm->pairwise != WPA_CIPHER_TKIP ? 48 : 64;
 #ifdef CONFIG_IEEE80211R
        if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
                return wpa_auth_derive_ptk_ft(sm, pmk, ptk, ptk_len);
@@ -1898,6 +1856,14 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
            wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, igtk.pn) < 0)
                os_memset(igtk.pn, 0, sizeof(igtk.pn));
        os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
+       if (sm->wpa_auth->conf.disable_gtk) {
+               /*
+                * Provide unique random IGTK to each STA to prevent use of
+                * IGTK in the BSS.
+                */
+               if (random_get_bytes(igtk.igtk, WPA_IGTK_LEN) < 0)
+                       return pos;
+       }
        pos = wpa_add_kde(pos, RSN_KEY_DATA_IGTK,
                          (const u8 *) &igtk, sizeof(igtk), NULL, 0);
 
@@ -1922,7 +1888,7 @@ static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
 
 SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
 {
-       u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos;
+       u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos, dummy_gtk[32];
        size_t gtk_len, kde_len;
        struct wpa_group *gsm = sm->group;
        u8 *wpa_ie;
@@ -1960,6 +1926,15 @@ SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
                secure = 1;
                gtk = gsm->GTK[gsm->GN - 1];
                gtk_len = gsm->GTK_len;
+               if (sm->wpa_auth->conf.disable_gtk) {
+                       /*
+                        * Provide unique random GTK to each STA to prevent use
+                        * of GTK in the BSS.
+                        */
+                       if (random_get_bytes(dummy_gtk, gtk_len) < 0)
+                               return;
+                       gtk = dummy_gtk;
+               }
                keyidx = gsm->GN;
                _rsc = rsc;
                encr = 1;
@@ -2071,15 +2046,8 @@ SM_STATE(WPA_PTK, PTKINITDONE)
        SM_ENTRY_MA(WPA_PTK, PTKINITDONE, wpa_ptk);
        sm->EAPOLKeyReceived = FALSE;
        if (sm->Pair) {
-               enum wpa_alg alg;
-               int klen;
-               if (sm->pairwise == WPA_CIPHER_TKIP) {
-                       alg = WPA_ALG_TKIP;
-                       klen = 32;
-               } else {
-                       alg = WPA_ALG_CCMP;
-                       klen = 16;
-               }
+               enum wpa_alg alg = wpa_cipher_to_alg(sm->pairwise);
+               int klen = wpa_cipher_key_len(sm->pairwise);
                if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
                                     sm->PTK.tk1, klen)) {
                        wpa_sta_disconnect(sm->wpa_auth, sm->addr);
@@ -2256,6 +2224,7 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
        struct wpa_group *gsm = sm->group;
        u8 *kde, *pos, hdr[2];
        size_t kde_len;
+       u8 *gtk, dummy_gtk[32];
 
        SM_ENTRY_MA(WPA_PTK_GROUP, REKEYNEGOTIATING, wpa_ptk_group);
 
@@ -2276,6 +2245,16 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
        wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
                        "sending 1/2 msg of Group Key Handshake");
 
+       gtk = gsm->GTK[gsm->GN - 1];
+       if (sm->wpa_auth->conf.disable_gtk) {
+               /*
+                * Provide unique random GTK to each STA to prevent use
+                * of GTK in the BSS.
+                */
+               if (random_get_bytes(dummy_gtk, gsm->GTK_len) < 0)
+                       return;
+               gtk = dummy_gtk;
+       }
        if (sm->wpa == WPA_VERSION_WPA2) {
                kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
                        ieee80211w_kde_len(sm);
@@ -2287,10 +2266,10 @@ SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
                hdr[0] = gsm->GN & 0x03;
                hdr[1] = 0;
                pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
-                                 gsm->GTK[gsm->GN - 1], gsm->GTK_len);
+                                 gtk, gsm->GTK_len);
                pos = ieee80211w_kde_add(sm, pos);
        } else {
-               kde = gsm->GTK[gsm->GN - 1];
+               kde = gtk;
                pos = kde + gsm->GTK_len;
        }
 
@@ -2416,6 +2395,9 @@ static void wpa_group_gtk_init(struct wpa_authenticator *wpa_auth,
 
 static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
 {
+       if (ctx != NULL && ctx != sm->group)
+               return 0;
+
        if (sm->wpa_ptk_state != WPA_PTK_PTKINITDONE) {
                wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
                                "Not in PTKINITDONE; skip Group Key update");
@@ -2433,6 +2415,10 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
                                "marking station for GTK rekeying");
        }
 
+       /* Do not rekey GTK/IGTK when STA is in WNM-Sleep Mode */
+       if (sm->is_wnmsleep)
+               return 0;
+
        sm->group->GKeyDoneStations++;
        sm->GUpdateStationKeys = TRUE;
 
@@ -2441,6 +2427,86 @@ static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
 }
 
 
+#ifdef CONFIG_WNM
+/* update GTK when exiting WNM-Sleep Mode */
+void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm)
+{
+       if (sm->is_wnmsleep)
+               return;
+
+       wpa_group_update_sta(sm, NULL);
+}
+
+
+void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag)
+{
+       sm->is_wnmsleep = !!flag;
+}
+
+
+int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos)
+{
+       struct wpa_group *gsm = sm->group;
+       u8 *start = pos;
+
+       /*
+        * GTK subelement:
+        * Sub-elem ID[1] | Length[1] | Key Info[2] | Key Length[1] | RSC[8] |
+        * Key[5..32]
+        */
+       *pos++ = WNM_SLEEP_SUBELEM_GTK;
+       *pos++ = 11 + gsm->GTK_len;
+       /* Key ID in B0-B1 of Key Info */
+       WPA_PUT_LE16(pos, gsm->GN & 0x03);
+       pos += 2;
+       *pos++ = gsm->GTK_len;
+       if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, pos) != 0)
+               return 0;
+       pos += 8;
+       os_memcpy(pos, gsm->GTK[gsm->GN - 1], gsm->GTK_len);
+       pos += gsm->GTK_len;
+
+       wpa_printf(MSG_DEBUG, "WNM: GTK Key ID %u in WNM-Sleep Mode exit",
+                  gsm->GN);
+       wpa_hexdump_key(MSG_DEBUG, "WNM: GTK in WNM-Sleep Mode exit",
+                       gsm->GTK[gsm->GN - 1], gsm->GTK_len);
+
+       return pos - start;
+}
+
+
+#ifdef CONFIG_IEEE80211W
+int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
+{
+       struct wpa_group *gsm = sm->group;
+       u8 *start = pos;
+
+       /*
+        * IGTK subelement:
+        * Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] | Key[16]
+        */
+       *pos++ = WNM_SLEEP_SUBELEM_IGTK;
+       *pos++ = 2 + 6 + WPA_IGTK_LEN;
+       WPA_PUT_LE16(pos, gsm->GN_igtk);
+       pos += 2;
+       if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos) != 0)
+               return 0;
+       pos += 6;
+
+       os_memcpy(pos, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
+       pos += WPA_IGTK_LEN;
+
+       wpa_printf(MSG_DEBUG, "WNM: IGTK Key ID %u in WNM-Sleep Mode exit",
+                  gsm->GN_igtk);
+       wpa_hexdump_key(MSG_DEBUG, "WNM: IGTK in WNM-Sleep Mode exit",
+                       gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
+
+       return pos - start;
+}
+#endif /* CONFIG_IEEE80211W */
+#endif /* CONFIG_WNM */
+
+
 static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
                              struct wpa_group *group)
 {
@@ -2470,7 +2536,7 @@ static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
                           group->GKeyDoneStations);
                group->GKeyDoneStations = 0;
        }
-       wpa_auth_for_each_sta(wpa_auth, wpa_group_update_sta, NULL);
+       wpa_auth_for_each_sta(wpa_auth, wpa_group_update_sta, group);
        wpa_printf(MSG_DEBUG, "wpa_group_setkeys: GKeyDoneStations=%d",
                   group->GKeyDoneStations);
 }
@@ -2482,7 +2548,7 @@ static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
        int ret = 0;
 
        if (wpa_auth_set_key(wpa_auth, group->vlan_id,
-                            wpa_alg_enum(wpa_auth->conf.wpa_group),
+                            wpa_cipher_to_alg(wpa_auth->conf.wpa_group),
                             broadcast_ether_addr, group->GN,
                             group->GTK[group->GN - 1], group->GTK_len) < 0)
                ret = -1;
@@ -2622,23 +2688,6 @@ static const char * wpa_bool_txt(int bool)
 }
 
 
-static int wpa_cipher_bits(int cipher)
-{
-       switch (cipher) {
-       case WPA_CIPHER_CCMP:
-               return 128;
-       case WPA_CIPHER_TKIP:
-               return 256;
-       case WPA_CIPHER_WEP104:
-               return 104;
-       case WPA_CIPHER_WEP40:
-               return 40;
-       default:
-               return 0;
-       }
-}
-
-
 #define RSN_SUITE "%02x-%02x-%02x-%d"
 #define RSN_SUITE_ARG(s) \
 ((s) >> 24) & 0xff, ((s) >> 16) & 0xff, ((s) >> 8) & 0xff, (s) & 0xff
@@ -2701,7 +2750,7 @@ int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen)
                !!wpa_auth->conf.wpa_strict_rekey,
                dot11RSNAConfigGroupUpdateCount,
                dot11RSNAConfigPairwiseUpdateCount,
-               wpa_cipher_bits(wpa_auth->conf.wpa_group),
+               wpa_cipher_key_len(wpa_auth->conf.wpa_group) * 8,
                dot11RSNAConfigPMKLifetime,
                dot11RSNAConfigPMKReauthThreshold,
                dot11RSNAConfigSATimeout,
@@ -2744,29 +2793,10 @@ int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen)
 
        /* dot11RSNAStatsEntry */
 
-       if (sm->wpa == WPA_VERSION_WPA) {
-               if (sm->pairwise == WPA_CIPHER_CCMP)
-                       pairwise = WPA_CIPHER_SUITE_CCMP;
-               else if (sm->pairwise == WPA_CIPHER_TKIP)
-                       pairwise = WPA_CIPHER_SUITE_TKIP;
-               else if (sm->pairwise == WPA_CIPHER_WEP104)
-                       pairwise = WPA_CIPHER_SUITE_WEP104;
-               else if (sm->pairwise == WPA_CIPHER_WEP40)
-                       pairwise = WPA_CIPHER_SUITE_WEP40;
-               else if (sm->pairwise == WPA_CIPHER_NONE)
-                       pairwise = WPA_CIPHER_SUITE_NONE;
-       } else if (sm->wpa == WPA_VERSION_WPA2) {
-               if (sm->pairwise == WPA_CIPHER_CCMP)
-                       pairwise = RSN_CIPHER_SUITE_CCMP;
-               else if (sm->pairwise == WPA_CIPHER_TKIP)
-                       pairwise = RSN_CIPHER_SUITE_TKIP;
-               else if (sm->pairwise == WPA_CIPHER_WEP104)
-                       pairwise = RSN_CIPHER_SUITE_WEP104;
-               else if (sm->pairwise == WPA_CIPHER_WEP40)
-                       pairwise = RSN_CIPHER_SUITE_WEP40;
-               else if (sm->pairwise == WPA_CIPHER_NONE)
-                       pairwise = RSN_CIPHER_SUITE_NONE;
-       } else
+       pairwise = wpa_cipher_to_suite(sm->wpa == WPA_VERSION_WPA2 ?
+                                      WPA_PROTO_RSN : WPA_PROTO_WPA,
+                                      sm->pairwise);
+       if (pairwise == 0)
                return 0;
 
        ret = os_snprintf(
@@ -2984,3 +3014,11 @@ void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
                                       wpa_send_eapol_timeout, wpa_auth, sm);
        }
 }
+
+
+int wpa_auth_uses_sae(struct wpa_state_machine *sm)
+{
+       if (sm == NULL)
+               return 0;
+       return wpa_key_mgmt_sae(sm->wpa_key_mgmt);
+}