LCOV - code coverage report
Current view: top level - src/rsn_supp - wpa_ft.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1401264779 Lines: 291 425 68.5 %
Date: 2014-05-28 Functions: 12 12 100.0 %

          Line data    Source code
       1             : /*
       2             :  * WPA Supplicant - IEEE 802.11r - Fast BSS Transition
       3             :  * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
       4             :  *
       5             :  * This software may be distributed under the terms of the BSD license.
       6             :  * See README for more details.
       7             :  */
       8             : 
       9             : #include "includes.h"
      10             : 
      11             : #include "common.h"
      12             : #include "crypto/aes_wrap.h"
      13             : #include "crypto/random.h"
      14             : #include "common/ieee802_11_defs.h"
      15             : #include "common/ieee802_11_common.h"
      16             : #include "wpa.h"
      17             : #include "wpa_i.h"
      18             : 
      19             : #ifdef CONFIG_IEEE80211R
      20             : 
      21          16 : int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
      22             :                       const struct wpa_eapol_key *key,
      23             :                       struct wpa_ptk *ptk, size_t ptk_len)
      24             : {
      25             :         u8 ptk_name[WPA_PMK_NAME_LEN];
      26          16 :         const u8 *anonce = key->key_nonce;
      27             : 
      28          16 :         if (sm->xxkey_len == 0) {
      29           0 :                 wpa_printf(MSG_DEBUG, "FT: XXKey not available for key "
      30             :                            "derivation");
      31           0 :                 return -1;
      32             :         }
      33             : 
      34          32 :         wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, sm->ssid,
      35          16 :                           sm->ssid_len, sm->mobility_domain,
      36          32 :                           sm->r0kh_id, sm->r0kh_id_len, sm->own_addr,
      37          16 :                           sm->pmk_r0, sm->pmk_r0_name);
      38          16 :         wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", sm->pmk_r0, PMK_LEN);
      39          16 :         wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name",
      40          16 :                     sm->pmk_r0_name, WPA_PMK_NAME_LEN);
      41          16 :         wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_name, sm->r1kh_id,
      42          16 :                           sm->own_addr, sm->pmk_r1, sm->pmk_r1_name);
      43          16 :         wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN);
      44          16 :         wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
      45             :                     WPA_PMK_NAME_LEN);
      46          16 :         wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, anonce, sm->own_addr,
      47          16 :                           sm->bssid, sm->pmk_r1_name,
      48             :                           (u8 *) ptk, ptk_len, ptk_name);
      49          16 :         wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len);
      50          16 :         wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
      51             : 
      52          16 :         return 0;
      53             : }
      54             : 
      55             : 
      56             : /**
      57             :  * wpa_sm_set_ft_params - Set FT (IEEE 802.11r) parameters
      58             :  * @sm: Pointer to WPA state machine data from wpa_sm_init()
      59             :  * @ies: Association Response IEs or %NULL to clear FT parameters
      60             :  * @ies_len: Length of ies buffer in octets
      61             :  * Returns: 0 on success, -1 on failure
      62             :  */
      63        2102 : int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len)
      64             : {
      65             :         struct wpa_ft_ies ft;
      66             : 
      67        2102 :         if (sm == NULL)
      68           0 :                 return 0;
      69             : 
      70        2102 :         if (wpa_ft_parse_ies(ies, ies_len, &ft) < 0)
      71           0 :                 return -1;
      72             : 
      73        2102 :         if (ft.mdie && ft.mdie_len < MOBILITY_DOMAIN_ID_LEN + 1)
      74           0 :                 return -1;
      75             : 
      76        2102 :         if (ft.mdie) {
      77          66 :                 wpa_hexdump(MSG_DEBUG, "FT: Mobility domain",
      78          66 :                             ft.mdie, MOBILITY_DOMAIN_ID_LEN);
      79          66 :                 os_memcpy(sm->mobility_domain, ft.mdie,
      80             :                           MOBILITY_DOMAIN_ID_LEN);
      81          66 :                 sm->mdie_ft_capab = ft.mdie[MOBILITY_DOMAIN_ID_LEN];
      82          66 :                 wpa_printf(MSG_DEBUG, "FT: Capability and Policy: 0x%02x",
      83          66 :                            sm->mdie_ft_capab);
      84             :         } else
      85        2036 :                 os_memset(sm->mobility_domain, 0, MOBILITY_DOMAIN_ID_LEN);
      86             : 
      87        2102 :         if (ft.r0kh_id) {
      88          72 :                 wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID",
      89          36 :                             ft.r0kh_id, ft.r0kh_id_len);
      90          36 :                 os_memcpy(sm->r0kh_id, ft.r0kh_id, ft.r0kh_id_len);
      91          36 :                 sm->r0kh_id_len = ft.r0kh_id_len;
      92             :         } else {
      93             :                 /* FIX: When should R0KH-ID be cleared? We need to keep the
      94             :                  * old R0KH-ID in order to be able to use this during FT. */
      95             :                 /*
      96             :                  * os_memset(sm->r0kh_id, 0, FT_R0KH_ID_LEN);
      97             :                  * sm->r0kh_id_len = 0;
      98             :                  */
      99             :         }
     100             : 
     101        2102 :         if (ft.r1kh_id) {
     102          36 :                 wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID",
     103          36 :                             ft.r1kh_id, FT_R1KH_ID_LEN);
     104          36 :                 os_memcpy(sm->r1kh_id, ft.r1kh_id, FT_R1KH_ID_LEN);
     105             :         } else
     106        2066 :                 os_memset(sm->r1kh_id, 0, FT_R1KH_ID_LEN);
     107             : 
     108        2102 :         os_free(sm->assoc_resp_ies);
     109        2102 :         sm->assoc_resp_ies = os_malloc(ft.mdie_len + 2 + ft.ftie_len + 2);
     110        2102 :         if (sm->assoc_resp_ies) {
     111        2102 :                 u8 *pos = sm->assoc_resp_ies;
     112        2102 :                 if (ft.mdie) {
     113          66 :                         os_memcpy(pos, ft.mdie - 2, ft.mdie_len + 2);
     114          66 :                         pos += ft.mdie_len + 2;
     115             :                 }
     116        2102 :                 if (ft.ftie) {
     117          36 :                         os_memcpy(pos, ft.ftie - 2, ft.ftie_len + 2);
     118          36 :                         pos += ft.ftie_len + 2;
     119             :                 }
     120        2102 :                 sm->assoc_resp_ies_len = pos - sm->assoc_resp_ies;
     121        4204 :                 wpa_hexdump(MSG_DEBUG, "FT: Stored MDIE and FTIE from "
     122             :                             "(Re)Association Response",
     123        2102 :                             sm->assoc_resp_ies, sm->assoc_resp_ies_len);
     124             :         }
     125             : 
     126        2102 :         return 0;
     127             : }
     128             : 
     129             : 
     130             : /**
     131             :  * wpa_ft_gen_req_ies - Generate FT (IEEE 802.11r) IEs for Auth/ReAssoc Request
     132             :  * @sm: Pointer to WPA state machine data from wpa_sm_init()
     133             :  * @len: Buffer for returning the length of the IEs
     134             :  * @anonce: ANonce or %NULL if not yet available
     135             :  * @pmk_name: PMKR0Name or PMKR1Name to be added into the RSN IE PMKID List
     136             :  * @kck: 128-bit KCK for MIC or %NULL if no MIC is used
     137             :  * @target_ap: Target AP address
     138             :  * @ric_ies: Optional IE(s), e.g., WMM TSPEC(s), for RIC-Request or %NULL
     139             :  * @ric_ies_len: Length of ric_ies buffer in octets
     140             :  * @ap_mdie: Mobility Domain IE from the target AP
     141             :  * Returns: Pointer to buffer with IEs or %NULL on failure
     142             :  *
     143             :  * Caller is responsible for freeing the returned buffer with os_free();
     144             :  */
     145         119 : static u8 * wpa_ft_gen_req_ies(struct wpa_sm *sm, size_t *len,
     146             :                                const u8 *anonce, const u8 *pmk_name,
     147             :                                const u8 *kck, const u8 *target_ap,
     148             :                                const u8 *ric_ies, size_t ric_ies_len,
     149             :                                const u8 *ap_mdie)
     150             : {
     151             :         size_t buf_len;
     152             :         u8 *buf, *pos, *ftie_len, *ftie_pos;
     153             :         struct rsn_mdie *mdie;
     154             :         struct rsn_ftie *ftie;
     155             :         struct rsn_ie_hdr *rsnie;
     156             :         u16 capab;
     157             : 
     158         119 :         sm->ft_completed = 0;
     159             : 
     160         119 :         buf_len = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
     161         119 :                 2 + sm->r0kh_id_len + ric_ies_len + 100;
     162         119 :         buf = os_zalloc(buf_len);
     163         119 :         if (buf == NULL)
     164           0 :                 return NULL;
     165         119 :         pos = buf;
     166             : 
     167             :         /* RSNIE[PMKR0Name/PMKR1Name] */
     168         119 :         rsnie = (struct rsn_ie_hdr *) pos;
     169         119 :         rsnie->elem_id = WLAN_EID_RSN;
     170         119 :         WPA_PUT_LE16(rsnie->version, RSN_VERSION);
     171         119 :         pos = (u8 *) (rsnie + 1);
     172             : 
     173             :         /* Group Suite Selector */
     174         129 :         if (sm->group_cipher != WPA_CIPHER_CCMP &&
     175          20 :             sm->group_cipher != WPA_CIPHER_GCMP &&
     176          10 :             sm->group_cipher != WPA_CIPHER_TKIP) {
     177           0 :                 wpa_printf(MSG_WARNING, "FT: Invalid group cipher (%d)",
     178             :                            sm->group_cipher);
     179           0 :                 os_free(buf);
     180           0 :                 return NULL;
     181             :         }
     182         119 :         RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN,
     183             :                                                   sm->group_cipher));
     184         119 :         pos += RSN_SELECTOR_LEN;
     185             : 
     186             :         /* Pairwise Suite Count */
     187         119 :         WPA_PUT_LE16(pos, 1);
     188         119 :         pos += 2;
     189             : 
     190             :         /* Pairwise Suite List */
     191         119 :         if (!wpa_cipher_valid_pairwise(sm->pairwise_cipher)) {
     192           0 :                 wpa_printf(MSG_WARNING, "FT: Invalid pairwise cipher (%d)",
     193             :                            sm->pairwise_cipher);
     194           0 :                 os_free(buf);
     195           0 :                 return NULL;
     196             :         }
     197         119 :         RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN,
     198             :                                                   sm->pairwise_cipher));
     199         119 :         pos += RSN_SELECTOR_LEN;
     200             : 
     201             :         /* Authenticated Key Management Suite Count */
     202         119 :         WPA_PUT_LE16(pos, 1);
     203         119 :         pos += 2;
     204             : 
     205             :         /* Authenticated Key Management Suite List */
     206         119 :         if (sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X)
     207          22 :                 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
     208          97 :         else if (sm->key_mgmt == WPA_KEY_MGMT_FT_PSK)
     209          75 :                 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
     210          22 :         else if (sm->key_mgmt == WPA_KEY_MGMT_FT_SAE)
     211          22 :                 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
     212             :         else {
     213           0 :                 wpa_printf(MSG_WARNING, "FT: Invalid key management type (%d)",
     214             :                            sm->key_mgmt);
     215           0 :                 os_free(buf);
     216           0 :                 return NULL;
     217             :         }
     218         119 :         pos += RSN_SELECTOR_LEN;
     219             : 
     220             :         /* RSN Capabilities */
     221         119 :         capab = 0;
     222             : #ifdef CONFIG_IEEE80211W
     223         119 :         if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC)
     224          26 :                 capab |= WPA_CAPABILITY_MFPC;
     225             : #endif /* CONFIG_IEEE80211W */
     226         119 :         WPA_PUT_LE16(pos, capab);
     227         119 :         pos += 2;
     228             : 
     229             :         /* PMKID Count */
     230         119 :         WPA_PUT_LE16(pos, 1);
     231         119 :         pos += 2;
     232             : 
     233             :         /* PMKID List [PMKR0Name/PMKR1Name] */
     234         119 :         os_memcpy(pos, pmk_name, WPA_PMK_NAME_LEN);
     235         119 :         pos += WPA_PMK_NAME_LEN;
     236             : 
     237             : #ifdef CONFIG_IEEE80211W
     238         119 :         if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
     239             :                 /* Management Group Cipher Suite */
     240          26 :                 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
     241          26 :                 pos += RSN_SELECTOR_LEN;
     242             :         }
     243             : #endif /* CONFIG_IEEE80211W */
     244             : 
     245         119 :         rsnie->len = (pos - (u8 *) rsnie) - 2;
     246             : 
     247             :         /* MDIE */
     248         119 :         *pos++ = WLAN_EID_MOBILITY_DOMAIN;
     249         119 :         *pos++ = sizeof(*mdie);
     250         119 :         mdie = (struct rsn_mdie *) pos;
     251         119 :         pos += sizeof(*mdie);
     252         119 :         os_memcpy(mdie->mobility_domain, sm->mobility_domain,
     253             :                   MOBILITY_DOMAIN_ID_LEN);
     254         119 :         mdie->ft_capab = ap_mdie && ap_mdie[1] >= 3 ? ap_mdie[4] :
     255             :                 sm->mdie_ft_capab;
     256             : 
     257             :         /* FTIE[SNonce, [R1KH-ID,] R0KH-ID ] */
     258         119 :         ftie_pos = pos;
     259         119 :         *pos++ = WLAN_EID_FAST_BSS_TRANSITION;
     260         119 :         ftie_len = pos++;
     261         119 :         ftie = (struct rsn_ftie *) pos;
     262         119 :         pos += sizeof(*ftie);
     263         119 :         os_memcpy(ftie->snonce, sm->snonce, WPA_NONCE_LEN);
     264         119 :         if (anonce)
     265          20 :                 os_memcpy(ftie->anonce, anonce, WPA_NONCE_LEN);
     266         119 :         if (kck) {
     267             :                 /* R1KH-ID sub-element in third FT message */
     268          20 :                 *pos++ = FTIE_SUBELEM_R1KH_ID;
     269          20 :                 *pos++ = FT_R1KH_ID_LEN;
     270          20 :                 os_memcpy(pos, sm->r1kh_id, FT_R1KH_ID_LEN);
     271          20 :                 pos += FT_R1KH_ID_LEN;
     272             :         }
     273             :         /* R0KH-ID sub-element */
     274         119 :         *pos++ = FTIE_SUBELEM_R0KH_ID;
     275         119 :         *pos++ = sm->r0kh_id_len;
     276         119 :         os_memcpy(pos, sm->r0kh_id, sm->r0kh_id_len);
     277         119 :         pos += sm->r0kh_id_len;
     278         119 :         *ftie_len = pos - ftie_len - 1;
     279             : 
     280         119 :         if (ric_ies) {
     281             :                 /* RIC Request */
     282           0 :                 os_memcpy(pos, ric_ies, ric_ies_len);
     283           0 :                 pos += ric_ies_len;
     284             :         }
     285             : 
     286         119 :         if (kck) {
     287             :                 /*
     288             :                  * IEEE Std 802.11r-2008, 11A.8.4
     289             :                  * MIC shall be calculated over:
     290             :                  * non-AP STA MAC address
     291             :                  * Target AP MAC address
     292             :                  * Transaction seq number (5 for ReassocReq, 3 otherwise)
     293             :                  * RSN IE
     294             :                  * MDIE
     295             :                  * FTIE (with MIC field set to 0)
     296             :                  * RIC-Request (if present)
     297             :                  */
     298             :                 /* Information element count */
     299          20 :                 ftie->mic_control[1] = 3 + ieee802_11_ie_count(ric_ies,
     300             :                                                                ric_ies_len);
     301          40 :                 if (wpa_ft_mic(kck, sm->own_addr, target_ap, 5,
     302             :                                ((u8 *) mdie) - 2, 2 + sizeof(*mdie),
     303          20 :                                ftie_pos, 2 + *ftie_len,
     304          20 :                                (u8 *) rsnie, 2 + rsnie->len, ric_ies,
     305          20 :                                ric_ies_len, ftie->mic) < 0) {
     306           0 :                         wpa_printf(MSG_INFO, "FT: Failed to calculate MIC");
     307           0 :                         os_free(buf);
     308           0 :                         return NULL;
     309             :                 }
     310             :         }
     311             : 
     312         119 :         *len = pos - buf;
     313             : 
     314         119 :         return buf;
     315             : }
     316             : 
     317             : 
     318          40 : static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid)
     319             : {
     320             :         int keylen;
     321             :         enum wpa_alg alg;
     322          40 :         u8 null_rsc[6] = { 0, 0, 0, 0, 0, 0 };
     323             : 
     324          40 :         wpa_printf(MSG_DEBUG, "FT: Installing PTK to the driver.");
     325             : 
     326          40 :         if (!wpa_cipher_valid_pairwise(sm->pairwise_cipher)) {
     327           0 :                 wpa_printf(MSG_WARNING, "FT: Unsupported pairwise cipher %d",
     328             :                            sm->pairwise_cipher);
     329           0 :                 return -1;
     330             :         }
     331             : 
     332          40 :         alg = wpa_cipher_to_alg(sm->pairwise_cipher);
     333          40 :         keylen = wpa_cipher_key_len(sm->pairwise_cipher);
     334             : 
     335          80 :         if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc,
     336          40 :                            sizeof(null_rsc), (u8 *) sm->ptk.tk1, keylen) < 0) {
     337          20 :                 wpa_printf(MSG_WARNING, "FT: Failed to set PTK to the driver");
     338          20 :                 return -1;
     339             :         }
     340             : 
     341          20 :         return 0;
     342             : }
     343             : 
     344             : 
     345             : /**
     346             :  * wpa_ft_prepare_auth_request - Generate over-the-air auth request
     347             :  * @sm: Pointer to WPA state machine data from wpa_sm_init()
     348             :  * @mdie: Target AP MDIE
     349             :  * Returns: 0 on success, -1 on failure
     350             :  */
     351          86 : int wpa_ft_prepare_auth_request(struct wpa_sm *sm, const u8 *mdie)
     352             : {
     353             :         u8 *ft_ies;
     354             :         size_t ft_ies_len;
     355             : 
     356             :         /* Generate a new SNonce */
     357          86 :         if (random_get_bytes(sm->snonce, WPA_NONCE_LEN)) {
     358           0 :                 wpa_printf(MSG_INFO, "FT: Failed to generate a new SNonce");
     359           0 :                 return -1;
     360             :         }
     361             : 
     362          86 :         ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name,
     363          86 :                                     NULL, sm->bssid, NULL, 0, mdie);
     364          86 :         if (ft_ies) {
     365          86 :                 wpa_sm_update_ft_ies(sm, sm->mobility_domain,
     366             :                                      ft_ies, ft_ies_len);
     367          86 :                 os_free(ft_ies);
     368             :         }
     369             : 
     370          86 :         return 0;
     371             : }
     372             : 
     373             : 
     374          20 : int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
     375             :                             int ft_action, const u8 *target_ap,
     376             :                             const u8 *ric_ies, size_t ric_ies_len)
     377             : {
     378             :         u8 *ft_ies;
     379             :         size_t ft_ies_len, ptk_len;
     380             :         struct wpa_ft_ies parse;
     381             :         struct rsn_mdie *mdie;
     382             :         struct rsn_ftie *ftie;
     383             :         u8 ptk_name[WPA_PMK_NAME_LEN];
     384             :         int ret;
     385             :         const u8 *bssid;
     386             : 
     387          20 :         wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
     388          20 :         wpa_hexdump(MSG_DEBUG, "FT: RIC IEs", ric_ies, ric_ies_len);
     389             : 
     390          20 :         if (ft_action) {
     391           8 :                 if (!sm->over_the_ds_in_progress) {
     392           0 :                         wpa_printf(MSG_DEBUG, "FT: No over-the-DS in progress "
     393             :                                    "- drop FT Action Response");
     394           0 :                         return -1;
     395             :                 }
     396             : 
     397           8 :                 if (os_memcmp(target_ap, sm->target_ap, ETH_ALEN) != 0) {
     398           0 :                         wpa_printf(MSG_DEBUG, "FT: No over-the-DS in progress "
     399             :                                    "with this Target AP - drop FT Action "
     400             :                                    "Response");
     401           0 :                         return -1;
     402             :                 }
     403             :         }
     404             : 
     405          20 :         if (!wpa_key_mgmt_ft(sm->key_mgmt)) {
     406           0 :                 wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not "
     407             :                            "enabled for this connection");
     408           0 :                 return -1;
     409             :         }
     410             : 
     411          20 :         if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
     412           0 :                 wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs");
     413           0 :                 return -1;
     414             :         }
     415             : 
     416          20 :         mdie = (struct rsn_mdie *) parse.mdie;
     417          40 :         if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
     418          20 :             os_memcmp(mdie->mobility_domain, sm->mobility_domain,
     419             :                       MOBILITY_DOMAIN_ID_LEN) != 0) {
     420           0 :                 wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
     421           0 :                 return -1;
     422             :         }
     423             : 
     424          20 :         ftie = (struct rsn_ftie *) parse.ftie;
     425          20 :         if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
     426           0 :                 wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
     427           0 :                 return -1;
     428             :         }
     429             : 
     430          20 :         if (os_memcmp(ftie->snonce, sm->snonce, WPA_NONCE_LEN) != 0) {
     431           0 :                 wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE");
     432           0 :                 wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
     433           0 :                             ftie->snonce, WPA_NONCE_LEN);
     434           0 :                 wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce",
     435           0 :                             sm->snonce, WPA_NONCE_LEN);
     436           0 :                 return -1;
     437             :         }
     438             : 
     439          20 :         if (parse.r0kh_id == NULL) {
     440           0 :                 wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE");
     441           0 :                 return -1;
     442             :         }
     443             : 
     444          40 :         if (parse.r0kh_id_len != sm->r0kh_id_len ||
     445          20 :             os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) {
     446           0 :                 wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with "
     447             :                            "the current R0KH-ID");
     448           0 :                 wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE",
     449           0 :                             parse.r0kh_id, parse.r0kh_id_len);
     450           0 :                 wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID",
     451           0 :                             sm->r0kh_id, sm->r0kh_id_len);
     452           0 :                 return -1;
     453             :         }
     454             : 
     455          20 :         if (parse.r1kh_id == NULL) {
     456           0 :                 wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE");
     457           0 :                 return -1;
     458             :         }
     459             : 
     460          40 :         if (parse.rsn_pmkid == NULL ||
     461          20 :             os_memcmp(parse.rsn_pmkid, sm->pmk_r0_name, WPA_PMK_NAME_LEN)) {
     462           0 :                 wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name (PMKID) in "
     463             :                            "RSNIE");
     464           0 :                 return -1;
     465             :         }
     466             : 
     467          20 :         os_memcpy(sm->r1kh_id, parse.r1kh_id, FT_R1KH_ID_LEN);
     468          20 :         wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", sm->r1kh_id, FT_R1KH_ID_LEN);
     469          20 :         wpa_hexdump(MSG_DEBUG, "FT: SNonce", sm->snonce, WPA_NONCE_LEN);
     470          20 :         wpa_hexdump(MSG_DEBUG, "FT: ANonce", ftie->anonce, WPA_NONCE_LEN);
     471          20 :         os_memcpy(sm->anonce, ftie->anonce, WPA_NONCE_LEN);
     472          20 :         wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_name, sm->r1kh_id,
     473          20 :                           sm->own_addr, sm->pmk_r1, sm->pmk_r1_name);
     474          20 :         wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN);
     475          20 :         wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name",
     476          20 :                     sm->pmk_r1_name, WPA_PMK_NAME_LEN);
     477             : 
     478          20 :         bssid = target_ap;
     479          20 :         ptk_len = sm->pairwise_cipher != WPA_CIPHER_TKIP ? 48 : 64;
     480          20 :         wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, ftie->anonce, sm->own_addr,
     481          20 :                           bssid, sm->pmk_r1_name,
     482          20 :                           (u8 *) &sm->ptk, ptk_len, ptk_name);
     483          20 :         wpa_hexdump_key(MSG_DEBUG, "FT: PTK",
     484          20 :                         (u8 *) &sm->ptk, ptk_len);
     485          20 :         wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
     486             : 
     487          60 :         ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, ftie->anonce,
     488          20 :                                     sm->pmk_r1_name, sm->ptk.kck, bssid,
     489             :                                     ric_ies, ric_ies_len,
     490          40 :                                     parse.mdie ? parse.mdie - 2 : NULL);
     491          20 :         if (ft_ies) {
     492          20 :                 wpa_sm_update_ft_ies(sm, sm->mobility_domain,
     493             :                                      ft_ies, ft_ies_len);
     494          20 :                 os_free(ft_ies);
     495             :         }
     496             : 
     497          20 :         wpa_sm_mark_authenticated(sm, bssid);
     498          20 :         ret = wpa_ft_install_ptk(sm, bssid);
     499          20 :         if (ret) {
     500             :                 /*
     501             :                  * Some drivers do not support key configuration when we are
     502             :                  * not associated with the target AP. Work around this by
     503             :                  * trying again after the following reassociation gets
     504             :                  * completed.
     505             :                  */
     506          20 :                 wpa_printf(MSG_DEBUG, "FT: Failed to set PTK prior to "
     507             :                            "association - try again after reassociation");
     508          20 :                 sm->set_ptk_after_assoc = 1;
     509             :         } else
     510           0 :                 sm->set_ptk_after_assoc = 0;
     511             : 
     512          20 :         sm->ft_completed = 1;
     513          20 :         if (ft_action) {
     514             :                 /*
     515             :                  * The caller is expected trigger re-association with the
     516             :                  * Target AP.
     517             :                  */
     518           8 :                 os_memcpy(sm->bssid, target_ap, ETH_ALEN);
     519             :         }
     520             : 
     521          20 :         return 0;
     522             : }
     523             : 
     524             : 
     525        2127 : int wpa_ft_is_completed(struct wpa_sm *sm)
     526             : {
     527        2127 :         if (sm == NULL)
     528           0 :                 return 0;
     529             : 
     530        2127 :         if (!wpa_key_mgmt_ft(sm->key_mgmt))
     531        2055 :                 return 0;
     532             : 
     533          72 :         return sm->ft_completed;
     534             : }
     535             : 
     536             : 
     537        1114 : void wpa_reset_ft_completed(struct wpa_sm *sm)
     538             : {
     539        1114 :         if (sm != NULL)
     540        1114 :                 sm->ft_completed = 0;
     541        1114 : }
     542             : 
     543             : 
     544          20 : static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem,
     545             :                                       size_t gtk_elem_len)
     546             : {
     547             :         u8 gtk[32];
     548             :         int keyidx;
     549             :         enum wpa_alg alg;
     550             :         size_t gtk_len, keylen, rsc_len;
     551             : 
     552          20 :         if (gtk_elem == NULL) {
     553           0 :                 wpa_printf(MSG_DEBUG, "FT: No GTK included in FTIE");
     554           0 :                 return 0;
     555             :         }
     556             : 
     557          20 :         wpa_hexdump_key(MSG_DEBUG, "FT: Received GTK in Reassoc Resp",
     558             :                         gtk_elem, gtk_elem_len);
     559             : 
     560          40 :         if (gtk_elem_len < 11 + 24 || (gtk_elem_len - 11) % 8 ||
     561          20 :             gtk_elem_len - 19 > sizeof(gtk)) {
     562           0 :                 wpa_printf(MSG_DEBUG, "FT: Invalid GTK sub-elem "
     563             :                            "length %lu", (unsigned long) gtk_elem_len);
     564           0 :                 return -1;
     565             :         }
     566          20 :         gtk_len = gtk_elem_len - 19;
     567          20 :         if (aes_unwrap(sm->ptk.kek, gtk_len / 8, gtk_elem + 11, gtk)) {
     568           0 :                 wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not "
     569             :                            "decrypt GTK");
     570           0 :                 return -1;
     571             :         }
     572             : 
     573          20 :         keylen = wpa_cipher_key_len(sm->group_cipher);
     574          20 :         rsc_len = wpa_cipher_rsc_len(sm->group_cipher);
     575          20 :         alg = wpa_cipher_to_alg(sm->group_cipher);
     576          20 :         if (alg == WPA_ALG_NONE) {
     577           0 :                 wpa_printf(MSG_WARNING, "WPA: Unsupported Group Cipher %d",
     578             :                            sm->group_cipher);
     579           0 :                 return -1;
     580             :         }
     581             : 
     582          20 :         if (gtk_len < keylen) {
     583           0 :                 wpa_printf(MSG_DEBUG, "FT: Too short GTK in FTIE");
     584           0 :                 return -1;
     585             :         }
     586             : 
     587             :         /* Key Info[2] | Key Length[1] | RSC[8] | Key[5..32]. */
     588             : 
     589          20 :         keyidx = WPA_GET_LE16(gtk_elem) & 0x03;
     590             : 
     591          20 :         if (gtk_elem[2] != keylen) {
     592           0 :                 wpa_printf(MSG_DEBUG, "FT: GTK length mismatch: received %d "
     593             :                            "negotiated %lu",
     594           0 :                            gtk_elem[2], (unsigned long) keylen);
     595           0 :                 return -1;
     596             :         }
     597             : 
     598          20 :         wpa_hexdump_key(MSG_DEBUG, "FT: GTK from Reassoc Resp", gtk, keylen);
     599          20 :         if (sm->group_cipher == WPA_CIPHER_TKIP) {
     600             :                 /* Swap Tx/Rx keys for Michael MIC */
     601             :                 u8 tmp[8];
     602           2 :                 os_memcpy(tmp, gtk + 16, 8);
     603           2 :                 os_memcpy(gtk + 16, gtk + 24, 8);
     604           2 :                 os_memcpy(gtk + 24, tmp, 8);
     605             :         }
     606          20 :         if (wpa_sm_set_key(sm, alg, broadcast_ether_addr, keyidx, 0,
     607             :                            gtk_elem + 3, rsc_len, gtk, keylen) < 0) {
     608           0 :                 wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the "
     609             :                            "driver.");
     610           0 :                 return -1;
     611             :         }
     612             : 
     613          20 :         return 0;
     614             : }
     615             : 
     616             : 
     617             : #ifdef CONFIG_IEEE80211W
     618          20 : static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem,
     619             :                                        size_t igtk_elem_len)
     620             : {
     621             :         u8 igtk[WPA_IGTK_LEN];
     622             :         u16 keyidx;
     623             : 
     624          20 :         if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC)
     625          16 :                 return 0;
     626             : 
     627           4 :         if (igtk_elem == NULL) {
     628           0 :                 wpa_printf(MSG_DEBUG, "FT: No IGTK included in FTIE");
     629           0 :                 return 0;
     630             :         }
     631             : 
     632           4 :         wpa_hexdump_key(MSG_DEBUG, "FT: Received IGTK in Reassoc Resp",
     633             :                         igtk_elem, igtk_elem_len);
     634             : 
     635           4 :         if (igtk_elem_len != 2 + 6 + 1 + WPA_IGTK_LEN + 8) {
     636           0 :                 wpa_printf(MSG_DEBUG, "FT: Invalid IGTK sub-elem "
     637             :                            "length %lu", (unsigned long) igtk_elem_len);
     638           0 :                 return -1;
     639             :         }
     640           4 :         if (igtk_elem[8] != WPA_IGTK_LEN) {
     641           0 :                 wpa_printf(MSG_DEBUG, "FT: Invalid IGTK sub-elem Key Length "
     642           0 :                            "%d", igtk_elem[8]);
     643           0 :                 return -1;
     644             :         }
     645             : 
     646           4 :         if (aes_unwrap(sm->ptk.kek, WPA_IGTK_LEN / 8, igtk_elem + 9, igtk)) {
     647           0 :                 wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not "
     648             :                            "decrypt IGTK");
     649           0 :                 return -1;
     650             :         }
     651             : 
     652             :         /* KeyID[2] | IPN[6] | Key Length[1] | Key[16+8] */
     653             : 
     654           4 :         keyidx = WPA_GET_LE16(igtk_elem);
     655             : 
     656           4 :         wpa_hexdump_key(MSG_DEBUG, "FT: IGTK from Reassoc Resp", igtk,
     657             :                         WPA_IGTK_LEN);
     658           4 :         if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr, keyidx, 0,
     659             :                            igtk_elem + 2, 6, igtk, WPA_IGTK_LEN) < 0) {
     660           0 :                 wpa_printf(MSG_WARNING, "WPA: Failed to set IGTK to the "
     661             :                            "driver.");
     662           0 :                 return -1;
     663             :         }
     664             : 
     665           4 :         return 0;
     666             : }
     667             : #endif /* CONFIG_IEEE80211W */
     668             : 
     669             : 
     670          20 : int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
     671             :                                  size_t ies_len, const u8 *src_addr)
     672             : {
     673             :         struct wpa_ft_ies parse;
     674             :         struct rsn_mdie *mdie;
     675             :         struct rsn_ftie *ftie;
     676             :         unsigned int count;
     677             :         u8 mic[16];
     678             : 
     679          20 :         wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
     680             : 
     681          20 :         if (!wpa_key_mgmt_ft(sm->key_mgmt)) {
     682           0 :                 wpa_printf(MSG_DEBUG, "FT: Reject FT IEs since FT is not "
     683             :                            "enabled for this connection");
     684           0 :                 return -1;
     685             :         }
     686             : 
     687          20 :         if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
     688           0 :                 wpa_printf(MSG_DEBUG, "FT: Failed to parse IEs");
     689           0 :                 return -1;
     690             :         }
     691             : 
     692          20 :         mdie = (struct rsn_mdie *) parse.mdie;
     693          40 :         if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
     694          20 :             os_memcmp(mdie->mobility_domain, sm->mobility_domain,
     695             :                       MOBILITY_DOMAIN_ID_LEN) != 0) {
     696           0 :                 wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
     697           0 :                 return -1;
     698             :         }
     699             : 
     700          20 :         ftie = (struct rsn_ftie *) parse.ftie;
     701          20 :         if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
     702           0 :                 wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
     703           0 :                 return -1;
     704             :         }
     705             : 
     706          20 :         if (os_memcmp(ftie->snonce, sm->snonce, WPA_NONCE_LEN) != 0) {
     707           0 :                 wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE");
     708           0 :                 wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
     709           0 :                             ftie->snonce, WPA_NONCE_LEN);
     710           0 :                 wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce",
     711           0 :                             sm->snonce, WPA_NONCE_LEN);
     712           0 :                 return -1;
     713             :         }
     714             : 
     715          20 :         if (os_memcmp(ftie->anonce, sm->anonce, WPA_NONCE_LEN) != 0) {
     716           0 :                 wpa_printf(MSG_DEBUG, "FT: ANonce mismatch in FTIE");
     717           0 :                 wpa_hexdump(MSG_DEBUG, "FT: Received ANonce",
     718           0 :                             ftie->anonce, WPA_NONCE_LEN);
     719           0 :                 wpa_hexdump(MSG_DEBUG, "FT: Expected ANonce",
     720           0 :                             sm->anonce, WPA_NONCE_LEN);
     721           0 :                 return -1;
     722             :         }
     723             : 
     724          20 :         if (parse.r0kh_id == NULL) {
     725           0 :                 wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE");
     726           0 :                 return -1;
     727             :         }
     728             : 
     729          40 :         if (parse.r0kh_id_len != sm->r0kh_id_len ||
     730          20 :             os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) {
     731           0 :                 wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with "
     732             :                            "the current R0KH-ID");
     733           0 :                 wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE",
     734           0 :                             parse.r0kh_id, parse.r0kh_id_len);
     735           0 :                 wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID",
     736           0 :                             sm->r0kh_id, sm->r0kh_id_len);
     737           0 :                 return -1;
     738             :         }
     739             : 
     740          20 :         if (parse.r1kh_id == NULL) {
     741           0 :                 wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE");
     742           0 :                 return -1;
     743             :         }
     744             : 
     745          20 :         if (os_memcmp(parse.r1kh_id, sm->r1kh_id, FT_R1KH_ID_LEN) != 0) {
     746           0 :                 wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in "
     747             :                            "ReassocResp");
     748           0 :                 return -1;
     749             :         }
     750             : 
     751          40 :         if (parse.rsn_pmkid == NULL ||
     752          20 :             os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN)) {
     753           0 :                 wpa_printf(MSG_DEBUG, "FT: No matching PMKR1Name (PMKID) in "
     754           0 :                            "RSNIE (pmkid=%d)", !!parse.rsn_pmkid);
     755           0 :                 return -1;
     756             :         }
     757             : 
     758          20 :         count = 3;
     759          20 :         if (parse.ric)
     760           0 :                 count += ieee802_11_ie_count(parse.ric, parse.ric_len);
     761          20 :         if (ftie->mic_control[1] != count) {
     762           0 :                 wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
     763             :                            "Control: received %u expected %u",
     764           0 :                            ftie->mic_control[1], count);
     765           0 :                 return -1;
     766             :         }
     767             : 
     768         140 :         if (wpa_ft_mic(sm->ptk.kck, sm->own_addr, src_addr, 6,
     769          40 :                        parse.mdie - 2, parse.mdie_len + 2,
     770          40 :                        parse.ftie - 2, parse.ftie_len + 2,
     771          40 :                        parse.rsn - 2, parse.rsn_len + 2,
     772             :                        parse.ric, parse.ric_len,
     773             :                        mic) < 0) {
     774           0 :                 wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
     775           0 :                 return -1;
     776             :         }
     777             : 
     778          20 :         if (os_memcmp(mic, ftie->mic, 16) != 0) {
     779           0 :                 wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE");
     780           0 :                 wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", ftie->mic, 16);
     781           0 :                 wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16);
     782           0 :                 return -1;
     783             :         }
     784             : 
     785          20 :         if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0)
     786           0 :                 return -1;
     787             : 
     788             : #ifdef CONFIG_IEEE80211W
     789          20 :         if (wpa_ft_process_igtk_subelem(sm, parse.igtk, parse.igtk_len) < 0)
     790           0 :                 return -1;
     791             : #endif /* CONFIG_IEEE80211W */
     792             : 
     793          20 :         if (sm->set_ptk_after_assoc) {
     794          20 :                 wpa_printf(MSG_DEBUG, "FT: Try to set PTK again now that we "
     795             :                            "are associated");
     796          20 :                 if (wpa_ft_install_ptk(sm, src_addr) < 0)
     797           0 :                         return -1;
     798          20 :                 sm->set_ptk_after_assoc = 0;
     799             :         }
     800             : 
     801          20 :         if (parse.ric) {
     802           0 :                 wpa_hexdump(MSG_MSGDUMP, "FT: RIC Response",
     803           0 :                             parse.ric, parse.ric_len);
     804             :                 /* TODO: parse response and inform driver about results when
     805             :                  * using wpa_supplicant SME */
     806             :         }
     807             : 
     808          20 :         wpa_printf(MSG_DEBUG, "FT: Completed successfully");
     809             : 
     810          20 :         return 0;
     811             : }
     812             : 
     813             : 
     814             : /**
     815             :  * wpa_ft_start_over_ds - Generate over-the-DS auth request
     816             :  * @sm: Pointer to WPA state machine data from wpa_sm_init()
     817             :  * @target_ap: Target AP Address
     818             :  * @mdie: Mobility Domain IE from the target AP
     819             :  * Returns: 0 on success, -1 on failure
     820             :  */
     821          13 : int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap,
     822             :                          const u8 *mdie)
     823             : {
     824             :         u8 *ft_ies;
     825             :         size_t ft_ies_len;
     826             : 
     827          78 :         wpa_printf(MSG_DEBUG, "FT: Request over-the-DS with " MACSTR,
     828          78 :                    MAC2STR(target_ap));
     829             : 
     830             :         /* Generate a new SNonce */
     831          13 :         if (random_get_bytes(sm->snonce, WPA_NONCE_LEN)) {
     832           0 :                 wpa_printf(MSG_INFO, "FT: Failed to generate a new SNonce");
     833           0 :                 return -1;
     834             :         }
     835             : 
     836          13 :         ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name,
     837             :                                     NULL, target_ap, NULL, 0, mdie);
     838          13 :         if (ft_ies) {
     839          13 :                 sm->over_the_ds_in_progress = 1;
     840          13 :                 os_memcpy(sm->target_ap, target_ap, ETH_ALEN);
     841          13 :                 wpa_sm_send_ft_action(sm, 1, target_ap, ft_ies, ft_ies_len);
     842          13 :                 os_free(ft_ies);
     843             :         }
     844             : 
     845          13 :         return 0;
     846             : }
     847             : 
     848             : #endif /* CONFIG_IEEE80211R */

Generated by: LCOV version 1.10