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

Generated by: LCOV version 1.10