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 1393793999 Lines: 291 425 68.5 %
Date: 2014-03-02 Functions: 12 12 100.0 %
Branches: 121 200 60.5 %

           Branch data     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                 :          8 : 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                 :          8 :         const u8 *anonce = key->key_nonce;
      27                 :            : 
      28         [ -  + ]:          8 :         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                 :          8 :         wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, sm->ssid,
      35                 :          8 :                           sm->ssid_len, sm->mobility_domain,
      36                 :         16 :                           sm->r0kh_id, sm->r0kh_id_len, sm->own_addr,
      37                 :          8 :                           sm->pmk_r0, sm->pmk_r0_name);
      38                 :          8 :         wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", sm->pmk_r0, PMK_LEN);
      39                 :          8 :         wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name",
      40                 :          8 :                     sm->pmk_r0_name, WPA_PMK_NAME_LEN);
      41                 :          8 :         wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_name, sm->r1kh_id,
      42                 :          8 :                           sm->own_addr, sm->pmk_r1, sm->pmk_r1_name);
      43                 :          8 :         wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN);
      44                 :          8 :         wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
      45                 :            :                     WPA_PMK_NAME_LEN);
      46                 :          8 :         wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, anonce, sm->own_addr,
      47                 :          8 :                           sm->bssid, sm->pmk_r1_name,
      48                 :            :                           (u8 *) ptk, ptk_len, ptk_name);
      49                 :          8 :         wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len);
      50                 :          8 :         wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
      51                 :            : 
      52                 :          8 :         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                 :       1374 : 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         [ -  + ]:       1374 :         if (sm == NULL)
      68                 :          0 :                 return 0;
      69                 :            : 
      70         [ -  + ]:       1374 :         if (wpa_ft_parse_ies(ies, ies_len, &ft) < 0)
      71                 :          0 :                 return -1;
      72                 :            : 
      73 [ +  + ][ -  + ]:       1374 :         if (ft.mdie && ft.mdie_len < MOBILITY_DOMAIN_ID_LEN + 1)
      74                 :          0 :                 return -1;
      75                 :            : 
      76         [ +  + ]:       1374 :         if (ft.mdie) {
      77                 :         44 :                 wpa_hexdump(MSG_DEBUG, "FT: Mobility domain",
      78                 :         44 :                             ft.mdie, MOBILITY_DOMAIN_ID_LEN);
      79                 :         44 :                 os_memcpy(sm->mobility_domain, ft.mdie,
      80                 :            :                           MOBILITY_DOMAIN_ID_LEN);
      81                 :         44 :                 sm->mdie_ft_capab = ft.mdie[MOBILITY_DOMAIN_ID_LEN];
      82                 :         44 :                 wpa_printf(MSG_DEBUG, "FT: Capability and Policy: 0x%02x",
      83                 :         44 :                            sm->mdie_ft_capab);
      84                 :            :         } else
      85                 :       1330 :                 os_memset(sm->mobility_domain, 0, MOBILITY_DOMAIN_ID_LEN);
      86                 :            : 
      87         [ +  + ]:       1374 :         if (ft.r0kh_id) {
      88                 :         24 :                 wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID",
      89                 :         24 :                             ft.r0kh_id, ft.r0kh_id_len);
      90                 :         24 :                 os_memcpy(sm->r0kh_id, ft.r0kh_id, ft.r0kh_id_len);
      91                 :         24 :                 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         [ +  + ]:       1374 :         if (ft.r1kh_id) {
     102                 :         24 :                 wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID",
     103                 :         24 :                             ft.r1kh_id, FT_R1KH_ID_LEN);
     104                 :         24 :                 os_memcpy(sm->r1kh_id, ft.r1kh_id, FT_R1KH_ID_LEN);
     105                 :            :         } else
     106                 :       1350 :                 os_memset(sm->r1kh_id, 0, FT_R1KH_ID_LEN);
     107                 :            : 
     108                 :       1374 :         os_free(sm->assoc_resp_ies);
     109                 :       1374 :         sm->assoc_resp_ies = os_malloc(ft.mdie_len + 2 + ft.ftie_len + 2);
     110         [ +  - ]:       1374 :         if (sm->assoc_resp_ies) {
     111                 :       1374 :                 u8 *pos = sm->assoc_resp_ies;
     112         [ +  + ]:       1374 :                 if (ft.mdie) {
     113                 :         44 :                         os_memcpy(pos, ft.mdie - 2, ft.mdie_len + 2);
     114                 :         44 :                         pos += ft.mdie_len + 2;
     115                 :            :                 }
     116         [ +  + ]:       1374 :                 if (ft.ftie) {
     117                 :         24 :                         os_memcpy(pos, ft.ftie - 2, ft.ftie_len + 2);
     118                 :         24 :                         pos += ft.ftie_len + 2;
     119                 :            :                 }
     120                 :       1374 :                 sm->assoc_resp_ies_len = pos - sm->assoc_resp_ies;
     121                 :       1374 :                 wpa_hexdump(MSG_DEBUG, "FT: Stored MDIE and FTIE from "
     122                 :            :                             "(Re)Association Response",
     123                 :       1374 :                             sm->assoc_resp_ies, sm->assoc_resp_ies_len);
     124                 :            :         }
     125                 :            : 
     126                 :       1374 :         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                 :         82 : 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                 :         82 :         sm->ft_completed = 0;
     159                 :            : 
     160                 :         82 :         buf_len = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
     161                 :         82 :                 2 + sm->r0kh_id_len + ric_ies_len + 100;
     162                 :         82 :         buf = os_zalloc(buf_len);
     163         [ -  + ]:         82 :         if (buf == NULL)
     164                 :          0 :                 return NULL;
     165                 :         82 :         pos = buf;
     166                 :            : 
     167                 :            :         /* RSNIE[PMKR0Name/PMKR1Name] */
     168                 :         82 :         rsnie = (struct rsn_ie_hdr *) pos;
     169                 :         82 :         rsnie->elem_id = WLAN_EID_RSN;
     170                 :         82 :         WPA_PUT_LE16(rsnie->version, RSN_VERSION);
     171                 :         82 :         pos = (u8 *) (rsnie + 1);
     172                 :            : 
     173                 :            :         /* Group Suite Selector */
     174 [ +  + ][ +  - ]:         82 :         if (sm->group_cipher != WPA_CIPHER_CCMP &&
     175         [ -  + ]:         10 :             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                 :         82 :         RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN,
     183                 :            :                                                   sm->group_cipher));
     184                 :         82 :         pos += RSN_SELECTOR_LEN;
     185                 :            : 
     186                 :            :         /* Pairwise Suite Count */
     187                 :         82 :         WPA_PUT_LE16(pos, 1);
     188                 :         82 :         pos += 2;
     189                 :            : 
     190                 :            :         /* Pairwise Suite List */
     191         [ -  + ]:         82 :         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                 :         82 :         RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN,
     198                 :            :                                                   sm->pairwise_cipher));
     199                 :         82 :         pos += RSN_SELECTOR_LEN;
     200                 :            : 
     201                 :            :         /* Authenticated Key Management Suite Count */
     202                 :         82 :         WPA_PUT_LE16(pos, 1);
     203                 :         82 :         pos += 2;
     204                 :            : 
     205                 :            :         /* Authenticated Key Management Suite List */
     206         [ +  + ]:         82 :         if (sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X)
     207                 :         10 :                 RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
     208         [ +  + ]:         72 :         else if (sm->key_mgmt == WPA_KEY_MGMT_FT_PSK)
     209                 :         50 :                 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                 :         82 :         pos += RSN_SELECTOR_LEN;
     219                 :            : 
     220                 :            :         /* RSN Capabilities */
     221                 :         82 :         capab = 0;
     222                 :            : #ifdef CONFIG_IEEE80211W
     223         [ +  + ]:         82 :         if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC)
     224                 :         20 :                 capab |= WPA_CAPABILITY_MFPC;
     225                 :            : #endif /* CONFIG_IEEE80211W */
     226                 :         82 :         WPA_PUT_LE16(pos, capab);
     227                 :         82 :         pos += 2;
     228                 :            : 
     229                 :            :         /* PMKID Count */
     230                 :         82 :         WPA_PUT_LE16(pos, 1);
     231                 :         82 :         pos += 2;
     232                 :            : 
     233                 :            :         /* PMKID List [PMKR0Name/PMKR1Name] */
     234                 :         82 :         os_memcpy(pos, pmk_name, WPA_PMK_NAME_LEN);
     235                 :         82 :         pos += WPA_PMK_NAME_LEN;
     236                 :            : 
     237                 :            : #ifdef CONFIG_IEEE80211W
     238         [ +  + ]:         82 :         if (sm->mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
     239                 :            :                 /* Management Group Cipher Suite */
     240                 :         20 :                 RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
     241                 :         20 :                 pos += RSN_SELECTOR_LEN;
     242                 :            :         }
     243                 :            : #endif /* CONFIG_IEEE80211W */
     244                 :            : 
     245                 :         82 :         rsnie->len = (pos - (u8 *) rsnie) - 2;
     246                 :            : 
     247                 :            :         /* MDIE */
     248                 :         82 :         *pos++ = WLAN_EID_MOBILITY_DOMAIN;
     249                 :         82 :         *pos++ = sizeof(*mdie);
     250                 :         82 :         mdie = (struct rsn_mdie *) pos;
     251                 :         82 :         pos += sizeof(*mdie);
     252                 :         82 :         os_memcpy(mdie->mobility_domain, sm->mobility_domain,
     253                 :            :                   MOBILITY_DOMAIN_ID_LEN);
     254 [ +  + ][ +  - ]:         82 :         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                 :         82 :         ftie_pos = pos;
     259                 :         82 :         *pos++ = WLAN_EID_FAST_BSS_TRANSITION;
     260                 :         82 :         ftie_len = pos++;
     261                 :         82 :         ftie = (struct rsn_ftie *) pos;
     262                 :         82 :         pos += sizeof(*ftie);
     263                 :         82 :         os_memcpy(ftie->snonce, sm->snonce, WPA_NONCE_LEN);
     264         [ +  + ]:         82 :         if (anonce)
     265                 :         16 :                 os_memcpy(ftie->anonce, anonce, WPA_NONCE_LEN);
     266         [ +  + ]:         82 :         if (kck) {
     267                 :            :                 /* R1KH-ID sub-element in third FT message */
     268                 :         16 :                 *pos++ = FTIE_SUBELEM_R1KH_ID;
     269                 :         16 :                 *pos++ = FT_R1KH_ID_LEN;
     270                 :         16 :                 os_memcpy(pos, sm->r1kh_id, FT_R1KH_ID_LEN);
     271                 :         16 :                 pos += FT_R1KH_ID_LEN;
     272                 :            :         }
     273                 :            :         /* R0KH-ID sub-element */
     274                 :         82 :         *pos++ = FTIE_SUBELEM_R0KH_ID;
     275                 :         82 :         *pos++ = sm->r0kh_id_len;
     276                 :         82 :         os_memcpy(pos, sm->r0kh_id, sm->r0kh_id_len);
     277                 :         82 :         pos += sm->r0kh_id_len;
     278                 :         82 :         *ftie_len = pos - ftie_len - 1;
     279                 :            : 
     280         [ -  + ]:         82 :         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         [ +  + ]:         82 :         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                 :         16 :                 ftie->mic_control[1] = 3 + ieee802_11_ie_count(ric_ies,
     300                 :            :                                                                ric_ies_len);
     301         [ -  + ]:         16 :                 if (wpa_ft_mic(kck, sm->own_addr, target_ap, 5,
     302                 :            :                                ((u8 *) mdie) - 2, 2 + sizeof(*mdie),
     303                 :         16 :                                ftie_pos, 2 + *ftie_len,
     304                 :         16 :                                (u8 *) rsnie, 2 + rsnie->len, ric_ies,
     305                 :         16 :                                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                 :         82 :         *len = pos - buf;
     313                 :            : 
     314                 :         82 :         return buf;
     315                 :            : }
     316                 :            : 
     317                 :            : 
     318                 :         32 : static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid)
     319                 :            : {
     320                 :            :         int keylen;
     321                 :            :         enum wpa_alg alg;
     322                 :         32 :         u8 null_rsc[6] = { 0, 0, 0, 0, 0, 0 };
     323                 :            : 
     324                 :         32 :         wpa_printf(MSG_DEBUG, "FT: Installing PTK to the driver.");
     325                 :            : 
     326         [ -  + ]:         32 :         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                 :         32 :         alg = wpa_cipher_to_alg(sm->pairwise_cipher);
     333                 :         32 :         keylen = wpa_cipher_key_len(sm->pairwise_cipher);
     334                 :            : 
     335         [ +  + ]:         32 :         if (wpa_sm_set_key(sm, alg, bssid, 0, 1, null_rsc,
     336                 :         32 :                            sizeof(null_rsc), (u8 *) sm->ptk.tk1, keylen) < 0) {
     337                 :         16 :                 wpa_printf(MSG_WARNING, "FT: Failed to set PTK to the driver");
     338                 :         16 :                 return -1;
     339                 :            :         }
     340                 :            : 
     341                 :         32 :         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                 :         60 : 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         [ -  + ]:         60 :         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                 :         60 :         ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name,
     363                 :         60 :                                     NULL, sm->bssid, NULL, 0, mdie);
     364         [ +  - ]:         60 :         if (ft_ies) {
     365                 :         60 :                 wpa_sm_update_ft_ies(sm, sm->mobility_domain,
     366                 :            :                                      ft_ies, ft_ies_len);
     367                 :         60 :                 os_free(ft_ies);
     368                 :            :         }
     369                 :            : 
     370                 :         60 :         return 0;
     371                 :            : }
     372                 :            : 
     373                 :            : 
     374                 :         16 : 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                 :         16 :         wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
     388                 :         16 :         wpa_hexdump(MSG_DEBUG, "FT: RIC IEs", ric_ies, ric_ies_len);
     389                 :            : 
     390         [ +  + ]:         16 :         if (ft_action) {
     391         [ -  + ]:          6 :                 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         [ -  + ]:          6 :                 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         [ -  + ]:         16 :         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         [ -  + ]:         16 :         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                 :         16 :         mdie = (struct rsn_mdie *) parse.mdie;
     417 [ +  - ][ +  - ]:         16 :         if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
                 [ -  + ]
     418                 :         16 :             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                 :         16 :         ftie = (struct rsn_ftie *) parse.ftie;
     425 [ +  - ][ -  + ]:         16 :         if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
     426                 :          0 :                 wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
     427                 :          0 :                 return -1;
     428                 :            :         }
     429                 :            : 
     430         [ -  + ]:         16 :         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         [ -  + ]:         16 :         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 [ +  - ][ -  + ]:         16 :         if (parse.r0kh_id_len != sm->r0kh_id_len ||
     445                 :         16 :             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         [ -  + ]:         16 :         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 [ +  - ][ -  + ]:         16 :         if (parse.rsn_pmkid == NULL ||
     461                 :         16 :             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                 :         16 :         os_memcpy(sm->r1kh_id, parse.r1kh_id, FT_R1KH_ID_LEN);
     468                 :         16 :         wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID", sm->r1kh_id, FT_R1KH_ID_LEN);
     469                 :         16 :         wpa_hexdump(MSG_DEBUG, "FT: SNonce", sm->snonce, WPA_NONCE_LEN);
     470                 :         16 :         wpa_hexdump(MSG_DEBUG, "FT: ANonce", ftie->anonce, WPA_NONCE_LEN);
     471                 :         16 :         os_memcpy(sm->anonce, ftie->anonce, WPA_NONCE_LEN);
     472                 :         16 :         wpa_derive_pmk_r1(sm->pmk_r0, sm->pmk_r0_name, sm->r1kh_id,
     473                 :         16 :                           sm->own_addr, sm->pmk_r1, sm->pmk_r1_name);
     474                 :         16 :         wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", sm->pmk_r1, PMK_LEN);
     475                 :         16 :         wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name",
     476                 :         16 :                     sm->pmk_r1_name, WPA_PMK_NAME_LEN);
     477                 :            : 
     478                 :         16 :         bssid = target_ap;
     479         [ +  - ]:         16 :         ptk_len = sm->pairwise_cipher != WPA_CIPHER_TKIP ? 48 : 64;
     480                 :         16 :         wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, ftie->anonce, sm->own_addr,
     481                 :         16 :                           bssid, sm->pmk_r1_name,
     482                 :         16 :                           (u8 *) &sm->ptk, ptk_len, ptk_name);
     483                 :         16 :         wpa_hexdump_key(MSG_DEBUG, "FT: PTK",
     484                 :         16 :                         (u8 *) &sm->ptk, ptk_len);
     485                 :         16 :         wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
     486                 :            : 
     487         [ +  - ]:         16 :         ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, ftie->anonce,
     488                 :         16 :                                     sm->pmk_r1_name, sm->ptk.kck, bssid,
     489                 :            :                                     ric_ies, ric_ies_len,
     490                 :         32 :                                     parse.mdie ? parse.mdie - 2 : NULL);
     491         [ +  - ]:         16 :         if (ft_ies) {
     492                 :         16 :                 wpa_sm_update_ft_ies(sm, sm->mobility_domain,
     493                 :            :                                      ft_ies, ft_ies_len);
     494                 :         16 :                 os_free(ft_ies);
     495                 :            :         }
     496                 :            : 
     497                 :         16 :         wpa_sm_mark_authenticated(sm, bssid);
     498                 :         16 :         ret = wpa_ft_install_ptk(sm, bssid);
     499         [ +  - ]:         16 :         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                 :         16 :                 wpa_printf(MSG_DEBUG, "FT: Failed to set PTK prior to "
     507                 :            :                            "association - try again after reassociation");
     508                 :         16 :                 sm->set_ptk_after_assoc = 1;
     509                 :            :         } else
     510                 :          0 :                 sm->set_ptk_after_assoc = 0;
     511                 :            : 
     512                 :         16 :         sm->ft_completed = 1;
     513         [ +  + ]:         16 :         if (ft_action) {
     514                 :            :                 /*
     515                 :            :                  * The caller is expected trigger re-association with the
     516                 :            :                  * Target AP.
     517                 :            :                  */
     518                 :          6 :                 os_memcpy(sm->bssid, target_ap, ETH_ALEN);
     519                 :            :         }
     520                 :            : 
     521                 :         16 :         return 0;
     522                 :            : }
     523                 :            : 
     524                 :            : 
     525                 :       1376 : int wpa_ft_is_completed(struct wpa_sm *sm)
     526                 :            : {
     527         [ -  + ]:       1376 :         if (sm == NULL)
     528                 :          0 :                 return 0;
     529                 :            : 
     530         [ +  + ]:       1376 :         if (!wpa_key_mgmt_ft(sm->key_mgmt))
     531                 :       1328 :                 return 0;
     532                 :            : 
     533                 :       1376 :         return sm->ft_completed;
     534                 :            : }
     535                 :            : 
     536                 :            : 
     537                 :       1267 : void wpa_reset_ft_completed(struct wpa_sm *sm)
     538                 :            : {
     539         [ +  - ]:       1267 :         if (sm != NULL)
     540                 :       1267 :                 sm->ft_completed = 0;
     541                 :       1267 : }
     542                 :            : 
     543                 :            : 
     544                 :         16 : 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         [ -  + ]:         16 :         if (gtk_elem == NULL) {
     553                 :          0 :                 wpa_printf(MSG_DEBUG, "FT: No GTK included in FTIE");
     554                 :          0 :                 return 0;
     555                 :            :         }
     556                 :            : 
     557                 :         16 :         wpa_hexdump_key(MSG_DEBUG, "FT: Received GTK in Reassoc Resp",
     558                 :            :                         gtk_elem, gtk_elem_len);
     559                 :            : 
     560 [ +  - ][ +  - ]:         16 :         if (gtk_elem_len < 11 + 24 || (gtk_elem_len - 11) % 8 ||
                 [ -  + ]
     561                 :         16 :             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                 :         16 :         gtk_len = gtk_elem_len - 19;
     567         [ -  + ]:         16 :         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                 :         16 :         keylen = wpa_cipher_key_len(sm->group_cipher);
     574                 :         16 :         rsc_len = wpa_cipher_rsc_len(sm->group_cipher);
     575                 :         16 :         alg = wpa_cipher_to_alg(sm->group_cipher);
     576         [ -  + ]:         16 :         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         [ -  + ]:         16 :         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                 :         16 :         keyidx = WPA_GET_LE16(gtk_elem) & 0x03;
     590                 :            : 
     591         [ -  + ]:         16 :         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                 :         16 :         wpa_hexdump_key(MSG_DEBUG, "FT: GTK from Reassoc Resp", gtk, keylen);
     599         [ +  + ]:         16 :         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         [ -  + ]:         16 :         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                 :         16 :         return 0;
     614                 :            : }
     615                 :            : 
     616                 :            : 
     617                 :            : #ifdef CONFIG_IEEE80211W
     618                 :         16 : 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         [ +  + ]:         16 :         if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC)
     625                 :         12 :                 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                 :         16 :         return 0;
     666                 :            : }
     667                 :            : #endif /* CONFIG_IEEE80211W */
     668                 :            : 
     669                 :            : 
     670                 :         16 : 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                 :         16 :         wpa_hexdump(MSG_DEBUG, "FT: Response IEs", ies, ies_len);
     680                 :            : 
     681         [ -  + ]:         16 :         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         [ -  + ]:         16 :         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                 :         16 :         mdie = (struct rsn_mdie *) parse.mdie;
     693 [ +  - ][ +  - ]:         16 :         if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
                 [ -  + ]
     694                 :         16 :             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                 :         16 :         ftie = (struct rsn_ftie *) parse.ftie;
     701 [ +  - ][ -  + ]:         16 :         if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
     702                 :          0 :                 wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
     703                 :          0 :                 return -1;
     704                 :            :         }
     705                 :            : 
     706         [ -  + ]:         16 :         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         [ -  + ]:         16 :         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         [ -  + ]:         16 :         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 [ +  - ][ -  + ]:         16 :         if (parse.r0kh_id_len != sm->r0kh_id_len ||
     730                 :         16 :             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         [ -  + ]:         16 :         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         [ -  + ]:         16 :         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 [ +  - ][ -  + ]:         16 :         if (parse.rsn_pmkid == NULL ||
     752                 :         16 :             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                 :         16 :         count = 3;
     759         [ -  + ]:         16 :         if (parse.ric)
     760                 :          0 :                 count += ieee802_11_ie_count(parse.ric, parse.ric_len);
     761         [ -  + ]:         16 :         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         [ -  + ]:         16 :         if (wpa_ft_mic(sm->ptk.kck, sm->own_addr, src_addr, 6,
     769                 :         32 :                        parse.mdie - 2, parse.mdie_len + 2,
     770                 :         32 :                        parse.ftie - 2, parse.ftie_len + 2,
     771                 :         32 :                        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         [ -  + ]:         16 :         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         [ -  + ]:         16 :         if (wpa_ft_process_gtk_subelem(sm, parse.gtk, parse.gtk_len) < 0)
     786                 :          0 :                 return -1;
     787                 :            : 
     788                 :            : #ifdef CONFIG_IEEE80211W
     789         [ -  + ]:         16 :         if (wpa_ft_process_igtk_subelem(sm, parse.igtk, parse.igtk_len) < 0)
     790                 :          0 :                 return -1;
     791                 :            : #endif /* CONFIG_IEEE80211W */
     792                 :            : 
     793         [ +  - ]:         16 :         if (sm->set_ptk_after_assoc) {
     794                 :         16 :                 wpa_printf(MSG_DEBUG, "FT: Try to set PTK again now that we "
     795                 :            :                            "are associated");
     796         [ -  + ]:         16 :                 if (wpa_ft_install_ptk(sm, src_addr) < 0)
     797                 :          0 :                         return -1;
     798                 :         16 :                 sm->set_ptk_after_assoc = 0;
     799                 :            :         }
     800                 :            : 
     801         [ -  + ]:         16 :         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                 :         16 :         wpa_printf(MSG_DEBUG, "FT: Completed successfully");
     809                 :            : 
     810                 :         16 :         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                 :          6 : 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                 :          6 :         wpa_printf(MSG_DEBUG, "FT: Request over-the-DS with " MACSTR,
     828                 :         36 :                    MAC2STR(target_ap));
     829                 :            : 
     830                 :            :         /* Generate a new SNonce */
     831         [ -  + ]:          6 :         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                 :          6 :         ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, NULL, sm->pmk_r0_name,
     837                 :            :                                     NULL, target_ap, NULL, 0, mdie);
     838         [ +  - ]:          6 :         if (ft_ies) {
     839                 :          6 :                 sm->over_the_ds_in_progress = 1;
     840                 :          6 :                 os_memcpy(sm->target_ap, target_ap, ETH_ALEN);
     841                 :          6 :                 wpa_sm_send_ft_action(sm, 1, target_ap, ft_ies, ft_ies_len);
     842                 :          6 :                 os_free(ft_ies);
     843                 :            :         }
     844                 :            : 
     845                 :          6 :         return 0;
     846                 :            : }
     847                 :            : 
     848                 :            : #endif /* CONFIG_IEEE80211R */

Generated by: LCOV version 1.9