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 1443382998 Lines: 321 419 76.6 %
Date: 2015-09-27 Functions: 12 12 100.0 %

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

Generated by: LCOV version 1.10