LCOV - code coverage report
Current view: top level - wpa_supplicant - mesh_rsn.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1475438200 Lines: 355 393 90.3 %
Date: 2016-10-02 Functions: 17 18 94.4 %

          Line data    Source code
       1             : /*
       2             :  * WPA Supplicant - Mesh RSN routines
       3             :  * Copyright (c) 2013-2014, cozybit, Inc.  All rights reserved.
       4             :  *
       5             :  * This software may be distributed under the terms of the BSD license.
       6             :  * See README for more details.
       7             :  */
       8             : 
       9             : #include "utils/includes.h"
      10             : 
      11             : #include "utils/common.h"
      12             : #include "utils/eloop.h"
      13             : #include "crypto/sha256.h"
      14             : #include "crypto/random.h"
      15             : #include "crypto/aes.h"
      16             : #include "crypto/aes_siv.h"
      17             : #include "rsn_supp/wpa.h"
      18             : #include "ap/hostapd.h"
      19             : #include "ap/wpa_auth.h"
      20             : #include "ap/sta_info.h"
      21             : #include "ap/ieee802_11.h"
      22             : #include "wpa_supplicant_i.h"
      23             : #include "driver_i.h"
      24             : #include "wpas_glue.h"
      25             : #include "mesh_mpm.h"
      26             : #include "mesh_rsn.h"
      27             : 
      28             : #define MESH_AUTH_TIMEOUT 10
      29             : #define MESH_AUTH_RETRY 3
      30             : 
      31          12 : void mesh_auth_timer(void *eloop_ctx, void *user_data)
      32             : {
      33          12 :         struct wpa_supplicant *wpa_s = eloop_ctx;
      34          12 :         struct sta_info *sta = user_data;
      35             :         struct hostapd_data *hapd;
      36             : 
      37          12 :         if (sta->sae->state != SAE_ACCEPTED) {
      38          84 :                 wpa_printf(MSG_DEBUG, "AUTH: Re-authenticate with " MACSTR
      39             :                            " (attempt %d) ",
      40          84 :                            MAC2STR(sta->addr), sta->sae_auth_retry);
      41          72 :                 wpa_msg(wpa_s, MSG_INFO, MESH_SAE_AUTH_FAILURE "addr=" MACSTR,
      42          72 :                         MAC2STR(sta->addr));
      43          12 :                 if (sta->sae_auth_retry < MESH_AUTH_RETRY) {
      44          10 :                         mesh_rsn_auth_sae_sta(wpa_s, sta);
      45             :                 } else {
      46           2 :                         hapd = wpa_s->ifmsh->bss[0];
      47             : 
      48           2 :                         if (sta->sae_auth_retry > MESH_AUTH_RETRY) {
      49           0 :                                 ap_free_sta(hapd, sta);
      50          12 :                                 return;
      51             :                         }
      52             : 
      53             :                         /* block the STA if exceeded the number of attempts */
      54           2 :                         wpa_mesh_set_plink_state(wpa_s, sta, PLINK_BLOCKED);
      55           2 :                         sta->sae->state = SAE_NOTHING;
      56          14 :                         wpa_msg(wpa_s, MSG_INFO, MESH_SAE_AUTH_BLOCKED "addr="
      57             :                                 MACSTR " duration=%d",
      58          12 :                                 MAC2STR(sta->addr),
      59           2 :                                 hapd->conf->ap_max_inactivity);
      60             :                 }
      61          12 :                 sta->sae_auth_retry++;
      62             :         }
      63             : }
      64             : 
      65             : 
      66          72 : static void auth_logger(void *ctx, const u8 *addr, logger_level level,
      67             :                         const char *txt)
      68             : {
      69          72 :         if (addr)
      70         432 :                 wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " - %s",
      71         432 :                            MAC2STR(addr), txt);
      72             :         else
      73           0 :                 wpa_printf(MSG_DEBUG, "AUTH: %s", txt);
      74          72 : }
      75             : 
      76             : 
      77           0 : static const u8 *auth_get_psk(void *ctx, const u8 *addr,
      78             :                               const u8 *p2p_dev_addr, const u8 *prev_psk)
      79             : {
      80           0 :         struct mesh_rsn *mesh_rsn = ctx;
      81           0 :         struct hostapd_data *hapd = mesh_rsn->wpa_s->ifmsh->bss[0];
      82           0 :         struct sta_info *sta = ap_get_sta(hapd, addr);
      83             : 
      84           0 :         wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)",
      85           0 :                    __func__, MAC2STR(addr), prev_psk);
      86             : 
      87           0 :         if (sta && sta->auth_alg == WLAN_AUTH_SAE) {
      88           0 :                 if (!sta->sae || prev_psk)
      89           0 :                         return NULL;
      90           0 :                 return sta->sae->pmk;
      91             :         }
      92             : 
      93           0 :         return NULL;
      94             : }
      95             : 
      96             : 
      97          54 : static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
      98             :                         const u8 *addr, int idx, u8 *key, size_t key_len)
      99             : {
     100          54 :         struct mesh_rsn *mesh_rsn = ctx;
     101             :         u8 seq[6];
     102             : 
     103          54 :         os_memset(seq, 0, sizeof(seq));
     104             : 
     105          54 :         if (addr) {
     106         324 :                 wpa_printf(MSG_DEBUG, "AUTH: %s(alg=%d addr=" MACSTR
     107             :                            " key_idx=%d)",
     108         324 :                            __func__, alg, MAC2STR(addr), idx);
     109             :         } else {
     110           0 :                 wpa_printf(MSG_DEBUG, "AUTH: %s(alg=%d key_idx=%d)",
     111             :                            __func__, alg, idx);
     112             :         }
     113          54 :         wpa_hexdump_key(MSG_DEBUG, "AUTH: set_key - key", key, key_len);
     114             : 
     115          54 :         return wpa_drv_set_key(mesh_rsn->wpa_s, alg, addr, idx,
     116             :                                1, seq, 6, key, key_len);
     117             : }
     118             : 
     119             : 
     120          72 : static int auth_start_ampe(void *ctx, const u8 *addr)
     121             : {
     122          72 :         struct mesh_rsn *mesh_rsn = ctx;
     123             :         struct hostapd_data *hapd;
     124             :         struct sta_info *sta;
     125             : 
     126          72 :         if (mesh_rsn->wpa_s->current_ssid->mode != WPAS_MODE_MESH)
     127           0 :                 return -1;
     128             : 
     129          72 :         hapd = mesh_rsn->wpa_s->ifmsh->bss[0];
     130          72 :         sta = ap_get_sta(hapd, addr);
     131          72 :         if (sta)
     132          72 :                 eloop_cancel_timeout(mesh_auth_timer, mesh_rsn->wpa_s, sta);
     133             : 
     134          72 :         mesh_mpm_auth_peer(mesh_rsn->wpa_s, addr);
     135          72 :         return 0;
     136             : }
     137             : 
     138             : 
     139          68 : static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr,
     140             :                                 enum mfp_options ieee80211w)
     141             : {
     142             :         struct wpa_auth_config conf;
     143             :         struct wpa_auth_callbacks cb;
     144          68 :         u8 seq[6] = {};
     145             : 
     146          68 :         wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine");
     147             : 
     148          68 :         os_memset(&conf, 0, sizeof(conf));
     149          68 :         conf.wpa = WPA_PROTO_RSN;
     150          68 :         conf.wpa_key_mgmt = WPA_KEY_MGMT_SAE;
     151          68 :         conf.wpa_pairwise = rsn->pairwise_cipher;
     152          68 :         conf.rsn_pairwise = rsn->pairwise_cipher;
     153          68 :         conf.wpa_group = rsn->group_cipher;
     154          68 :         conf.eapol_version = 0;
     155          68 :         conf.wpa_group_rekey = -1;
     156             : #ifdef CONFIG_IEEE80211W
     157          68 :         conf.ieee80211w = ieee80211w;
     158          68 :         if (ieee80211w != NO_MGMT_FRAME_PROTECTION)
     159           4 :                 conf.group_mgmt_cipher = rsn->mgmt_group_cipher;
     160             : #endif /* CONFIG_IEEE80211W */
     161             : 
     162          68 :         os_memset(&cb, 0, sizeof(cb));
     163          68 :         cb.ctx = rsn;
     164          68 :         cb.logger = auth_logger;
     165          68 :         cb.get_psk = auth_get_psk;
     166          68 :         cb.set_key = auth_set_key;
     167          68 :         cb.start_ampe = auth_start_ampe;
     168             : 
     169          68 :         rsn->auth = wpa_init(addr, &conf, &cb);
     170          68 :         if (rsn->auth == NULL) {
     171           1 :                 wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed");
     172           1 :                 return -1;
     173             :         }
     174             : 
     175             :         /* TODO: support rekeying */
     176          67 :         rsn->mgtk_len = wpa_cipher_key_len(conf.wpa_group);
     177          67 :         if (random_get_bytes(rsn->mgtk, rsn->mgtk_len) < 0)
     178           1 :                 return -1;
     179          66 :         rsn->mgtk_key_id = 1;
     180             : 
     181             : #ifdef CONFIG_IEEE80211W
     182          66 :         if (ieee80211w != NO_MGMT_FRAME_PROTECTION) {
     183           4 :                 rsn->igtk_len = wpa_cipher_key_len(conf.group_mgmt_cipher);
     184           4 :                 if (random_get_bytes(rsn->igtk, rsn->igtk_len) < 0)
     185           0 :                         return -1;
     186           4 :                 rsn->igtk_key_id = 4;
     187             : 
     188             :                 /* group mgmt */
     189           8 :                 wpa_hexdump_key(MSG_DEBUG, "mesh: Own TX IGTK",
     190           4 :                                 rsn->igtk, rsn->igtk_len);
     191          12 :                 wpa_drv_set_key(rsn->wpa_s,
     192           4 :                                 wpa_cipher_to_alg(rsn->mgmt_group_cipher), NULL,
     193           4 :                                 rsn->igtk_key_id, 1,
     194           4 :                                 seq, sizeof(seq), rsn->igtk, rsn->igtk_len);
     195             :         }
     196             : #endif /* CONFIG_IEEE80211W */
     197             : 
     198             :         /* group privacy / data frames */
     199         132 :         wpa_hexdump_key(MSG_DEBUG, "mesh: Own TX MGTK",
     200          66 :                         rsn->mgtk, rsn->mgtk_len);
     201         132 :         wpa_drv_set_key(rsn->wpa_s, wpa_cipher_to_alg(rsn->group_cipher), NULL,
     202          66 :                         rsn->mgtk_key_id, 1, seq, sizeof(seq),
     203          66 :                         rsn->mgtk, rsn->mgtk_len);
     204             : 
     205          66 :         return 0;
     206             : }
     207             : 
     208             : 
     209           2 : static void mesh_rsn_deinit(struct mesh_rsn *rsn)
     210             : {
     211           2 :         os_memset(rsn->mgtk, 0, sizeof(rsn->mgtk));
     212           2 :         rsn->mgtk_len = 0;
     213           2 :         os_memset(rsn->igtk, 0, sizeof(rsn->igtk));
     214           2 :         rsn->igtk_len = 0;
     215           2 :         if (rsn->auth)
     216           1 :                 wpa_deinit(rsn->auth);
     217           2 : }
     218             : 
     219             : 
     220          69 : struct mesh_rsn *mesh_rsn_auth_init(struct wpa_supplicant *wpa_s,
     221             :                                     struct mesh_conf *conf)
     222             : {
     223             :         struct mesh_rsn *mesh_rsn;
     224          69 :         struct hostapd_data *bss = wpa_s->ifmsh->bss[0];
     225             :         const u8 *ie;
     226             :         size_t ie_len;
     227             : 
     228          69 :         mesh_rsn = os_zalloc(sizeof(*mesh_rsn));
     229          69 :         if (mesh_rsn == NULL)
     230           1 :                 return NULL;
     231          68 :         mesh_rsn->wpa_s = wpa_s;
     232          68 :         mesh_rsn->pairwise_cipher = conf->pairwise_cipher;
     233          68 :         mesh_rsn->group_cipher = conf->group_cipher;
     234          68 :         mesh_rsn->mgmt_group_cipher = conf->mgmt_group_cipher;
     235             : 
     236          68 :         if (__mesh_rsn_auth_init(mesh_rsn, wpa_s->own_addr,
     237             :                                  conf->ieee80211w) < 0) {
     238           2 :                 mesh_rsn_deinit(mesh_rsn);
     239           2 :                 os_free(mesh_rsn);
     240           2 :                 return NULL;
     241             :         }
     242             : 
     243          66 :         bss->wpa_auth = mesh_rsn->auth;
     244             : 
     245          66 :         ie = wpa_auth_get_wpa_ie(mesh_rsn->auth, &ie_len);
     246          66 :         conf->rsn_ie = (u8 *) ie;
     247          66 :         conf->rsn_ie_len = ie_len;
     248             : 
     249          66 :         wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
     250             : 
     251          66 :         return mesh_rsn;
     252             : }
     253             : 
     254             : 
     255          83 : static int index_within_array(const int *array, int idx)
     256             : {
     257             :         int i;
     258             : 
     259          86 :         for (i = 0; i < idx; i++) {
     260           3 :                 if (array[i] == -1)
     261           0 :                         return 0;
     262             :         }
     263             : 
     264          83 :         return 1;
     265             : }
     266             : 
     267             : 
     268          83 : static int mesh_rsn_sae_group(struct wpa_supplicant *wpa_s,
     269             :                               struct sae_data *sae)
     270             : {
     271          83 :         int *groups = wpa_s->ifmsh->bss[0]->conf->sae_groups;
     272             : 
     273             :         /* Configuration may have changed, so validate current index */
     274          83 :         if (!index_within_array(groups, wpa_s->mesh_rsn->sae_group_index))
     275           0 :                 return -1;
     276             : 
     277             :         for (;;) {
     278          87 :                 int group = groups[wpa_s->mesh_rsn->sae_group_index];
     279             : 
     280          87 :                 if (group <= 0)
     281           2 :                         break;
     282          85 :                 if (sae_set_group(sae, group) == 0) {
     283          81 :                         wpa_dbg(wpa_s, MSG_DEBUG, "SME: Selected SAE group %d",
     284             :                                 sae->group);
     285          81 :                         return 0;
     286             :                 }
     287           4 :                 wpa_s->mesh_rsn->sae_group_index++;
     288           4 :         }
     289             : 
     290           2 :         return -1;
     291             : }
     292             : 
     293             : 
     294          83 : static int mesh_rsn_build_sae_commit(struct wpa_supplicant *wpa_s,
     295             :                                      struct wpa_ssid *ssid,
     296             :                                      struct sta_info *sta)
     297             : {
     298          83 :         if (ssid->passphrase == NULL) {
     299           0 :                 wpa_msg(wpa_s, MSG_DEBUG, "SAE: No password available");
     300           0 :                 return -1;
     301             :         }
     302             : 
     303          83 :         if (mesh_rsn_sae_group(wpa_s, sta->sae) < 0) {
     304           2 :                 wpa_msg(wpa_s, MSG_DEBUG, "SAE: Failed to select group");
     305           2 :                 return -1;
     306             :         }
     307             : 
     308         243 :         return sae_prepare_commit(wpa_s->own_addr, sta->addr,
     309          81 :                                   (u8 *) ssid->passphrase,
     310          81 :                                   os_strlen(ssid->passphrase), sta->sae);
     311             : }
     312             : 
     313             : 
     314             : /* initiate new SAE authentication with sta */
     315          93 : int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s,
     316             :                           struct sta_info *sta)
     317             : {
     318          93 :         struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
     319          93 :         struct wpa_ssid *ssid = wpa_s->current_ssid;
     320             :         struct rsn_pmksa_cache_entry *pmksa;
     321             :         unsigned int rnd;
     322             :         int ret;
     323             : 
     324          93 :         if (!ssid) {
     325           0 :                 wpa_msg(wpa_s, MSG_DEBUG,
     326             :                         "AUTH: No current_ssid known to initiate new SAE");
     327           0 :                 return -1;
     328             :         }
     329             : 
     330          93 :         if (!sta->sae) {
     331          83 :                 sta->sae = os_zalloc(sizeof(*sta->sae));
     332          83 :                 if (sta->sae == NULL)
     333           1 :                         return -1;
     334             :         }
     335             : 
     336          92 :         pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr);
     337          92 :         if (pmksa) {
     338           9 :                 if (!sta->wpa_sm)
     339           9 :                         sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
     340           9 :                                                         sta->addr, NULL);
     341           9 :                 if (!sta->wpa_sm) {
     342           1 :                         wpa_printf(MSG_ERROR,
     343             :                                    "mesh: Failed to initialize RSN state machine");
     344           1 :                         return -1;
     345             :                 }
     346             : 
     347          48 :                 wpa_printf(MSG_DEBUG,
     348             :                            "AUTH: Mesh PMKSA cache entry found for " MACSTR
     349             :                            " - try to use PMKSA caching instead of new SAE authentication",
     350          48 :                            MAC2STR(sta->addr));
     351           8 :                 wpa_auth_pmksa_set_to_sm(pmksa, sta->wpa_sm, hapd->wpa_auth,
     352           8 :                                          sta->sae->pmkid, sta->sae->pmk);
     353           8 :                 sae_accept_sta(hapd, sta);
     354           8 :                 sta->mesh_sae_pmksa_caching = 1;
     355           8 :                 return 0;
     356             :         }
     357          83 :         sta->mesh_sae_pmksa_caching = 0;
     358             : 
     359          83 :         if (mesh_rsn_build_sae_commit(wpa_s, ssid, sta))
     360           2 :                 return -1;
     361             : 
     362         486 :         wpa_msg(wpa_s, MSG_DEBUG,
     363             :                 "AUTH: started authentication with SAE peer: " MACSTR,
     364         486 :                 MAC2STR(sta->addr));
     365             : 
     366          81 :         ret = auth_sae_init_committed(hapd, sta);
     367          81 :         if (ret)
     368           1 :                 return ret;
     369             : 
     370          80 :         eloop_cancel_timeout(mesh_auth_timer, wpa_s, sta);
     371          80 :         rnd = rand() % MESH_AUTH_TIMEOUT;
     372          80 :         eloop_register_timeout(MESH_AUTH_TIMEOUT + rnd, 0, mesh_auth_timer,
     373             :                                wpa_s, sta);
     374          80 :         return 0;
     375             : }
     376             : 
     377             : 
     378         262 : void mesh_rsn_get_pmkid(struct mesh_rsn *rsn, struct sta_info *sta, u8 *pmkid)
     379             : {
     380         262 :         os_memcpy(pmkid, sta->sae->pmkid, SAE_PMKID_LEN);
     381         262 : }
     382             : 
     383             : 
     384             : static void
     385          72 : mesh_rsn_derive_aek(struct mesh_rsn *rsn, struct sta_info *sta)
     386             : {
     387          72 :         u8 *myaddr = rsn->wpa_s->own_addr;
     388          72 :         u8 *peer = sta->addr;
     389             :         u8 *addr1, *addr2;
     390          72 :         u8 context[RSN_SELECTOR_LEN + 2 * ETH_ALEN], *ptr = context;
     391             : 
     392             :         /*
     393             :          * AEK = KDF-Hash-256(PMK, "AEK Derivation", Selected AKM Suite ||
     394             :          *       min(localMAC, peerMAC) || max(localMAC, peerMAC))
     395             :          */
     396             :         /* Selected AKM Suite: SAE */
     397          72 :         RSN_SELECTOR_PUT(ptr, RSN_AUTH_KEY_MGMT_SAE);
     398          72 :         ptr += RSN_SELECTOR_LEN;
     399             : 
     400          72 :         if (os_memcmp(myaddr, peer, ETH_ALEN) < 0) {
     401          36 :                 addr1 = myaddr;
     402          36 :                 addr2 = peer;
     403             :         } else {
     404          36 :                 addr1 = peer;
     405          36 :                 addr2 = myaddr;
     406             :         }
     407          72 :         os_memcpy(ptr, addr1, ETH_ALEN);
     408          72 :         ptr += ETH_ALEN;
     409          72 :         os_memcpy(ptr, addr2, ETH_ALEN);
     410             : 
     411          72 :         sha256_prf(sta->sae->pmk, sizeof(sta->sae->pmk), "AEK Derivation",
     412          72 :                    context, sizeof(context), sta->aek, sizeof(sta->aek));
     413          72 : }
     414             : 
     415             : 
     416             : /* derive mesh temporal key from pmk */
     417          68 : int mesh_rsn_derive_mtk(struct wpa_supplicant *wpa_s, struct sta_info *sta)
     418             : {
     419             :         u8 *ptr;
     420             :         u8 *min, *max;
     421          68 :         u8 *myaddr = wpa_s->own_addr;
     422          68 :         u8 *peer = sta->addr;
     423             :         u8 context[2 * WPA_NONCE_LEN + 2 * 2 + RSN_SELECTOR_LEN + 2 * ETH_ALEN];
     424             : 
     425             :         /*
     426             :          * MTK = KDF-Hash-Length(PMK, "Temporal Key Derivation", min(localNonce,
     427             :          *  peerNonce) || max(localNonce, peerNonce) || min(localLinkID,
     428             :          *  peerLinkID) || max(localLinkID, peerLinkID) || Selected AKM Suite ||
     429             :          *  min(localMAC, peerMAC) || max(localMAC, peerMAC))
     430             :          */
     431          68 :         ptr = context;
     432          68 :         if (os_memcmp(sta->my_nonce, sta->peer_nonce, WPA_NONCE_LEN) < 0) {
     433          34 :                 min = sta->my_nonce;
     434          34 :                 max = sta->peer_nonce;
     435             :         } else {
     436          34 :                 min = sta->peer_nonce;
     437          34 :                 max = sta->my_nonce;
     438             :         }
     439          68 :         os_memcpy(ptr, min, WPA_NONCE_LEN);
     440          68 :         ptr += WPA_NONCE_LEN;
     441          68 :         os_memcpy(ptr, max, WPA_NONCE_LEN);
     442          68 :         ptr += WPA_NONCE_LEN;
     443             : 
     444          68 :         if (sta->my_lid < sta->peer_lid) {
     445          34 :                 WPA_PUT_LE16(ptr, sta->my_lid);
     446          34 :                 ptr += 2;
     447          34 :                 WPA_PUT_LE16(ptr, sta->peer_lid);
     448          34 :                 ptr += 2;
     449             :         } else {
     450          34 :                 WPA_PUT_LE16(ptr, sta->peer_lid);
     451          34 :                 ptr += 2;
     452          34 :                 WPA_PUT_LE16(ptr, sta->my_lid);
     453          34 :                 ptr += 2;
     454             :         }
     455             : 
     456             :         /* Selected AKM Suite: SAE */
     457          68 :         RSN_SELECTOR_PUT(ptr, RSN_AUTH_KEY_MGMT_SAE);
     458          68 :         ptr += RSN_SELECTOR_LEN;
     459             : 
     460          68 :         if (os_memcmp(myaddr, peer, ETH_ALEN) < 0) {
     461          34 :                 min = myaddr;
     462          34 :                 max = peer;
     463             :         } else {
     464          34 :                 min = peer;
     465          34 :                 max = myaddr;
     466             :         }
     467          68 :         os_memcpy(ptr, min, ETH_ALEN);
     468          68 :         ptr += ETH_ALEN;
     469          68 :         os_memcpy(ptr, max, ETH_ALEN);
     470             : 
     471          68 :         sta->mtk_len = wpa_cipher_key_len(wpa_s->mesh_rsn->pairwise_cipher);
     472         136 :         sha256_prf(sta->sae->pmk, SAE_PMK_LEN,
     473             :                    "Temporal Key Derivation", context, sizeof(context),
     474          68 :                    sta->mtk, sta->mtk_len);
     475          68 :         return 0;
     476             : }
     477             : 
     478             : 
     479          72 : void mesh_rsn_init_ampe_sta(struct wpa_supplicant *wpa_s, struct sta_info *sta)
     480             : {
     481          72 :         if (random_get_bytes(sta->my_nonce, WPA_NONCE_LEN) < 0) {
     482           1 :                 wpa_printf(MSG_INFO, "mesh: Failed to derive random nonce");
     483             :                 /* TODO: How to handle this more cleanly? */
     484             :         }
     485          72 :         os_memset(sta->peer_nonce, 0, WPA_NONCE_LEN);
     486          72 :         mesh_rsn_derive_aek(wpa_s->mesh_rsn, sta);
     487          72 : }
     488             : 
     489             : 
     490             : /* insert AMPE and encrypted MIC at @ie.
     491             :  * @mesh_rsn: mesh RSN context
     492             :  * @sta: STA we're sending to
     493             :  * @cat: pointer to category code in frame header.
     494             :  * @buf: wpabuf to add encrypted AMPE and MIC to.
     495             :  * */
     496         262 : int mesh_rsn_protect_frame(struct mesh_rsn *rsn, struct sta_info *sta,
     497             :                            const u8 *cat, struct wpabuf *buf)
     498             : {
     499             :         struct ieee80211_ampe_ie *ampe;
     500         262 :         u8 const *ie = wpabuf_head_u8(buf) + wpabuf_len(buf);
     501             :         u8 *ampe_ie, *pos, *mic_payload;
     502         262 :         const u8 *aad[] = { rsn->wpa_s->own_addr, sta->addr, cat };
     503         262 :         const size_t aad_len[] = { ETH_ALEN, ETH_ALEN, ie - cat };
     504         262 :         int ret = 0;
     505             :         size_t len;
     506             : 
     507         262 :         len = sizeof(*ampe);
     508         262 :         if (cat[1] == PLINK_OPEN)
     509          81 :                 len += rsn->mgtk_len + WPA_KEY_RSC_LEN + 4;
     510             : #ifdef CONFIG_IEEE80211W
     511         262 :         if (cat[1] == PLINK_OPEN && rsn->igtk_len)
     512           4 :                 len += 2 + 6 + rsn->igtk_len;
     513             : #endif /* CONFIG_IEEE80211W */
     514             : 
     515         262 :         if (2 + AES_BLOCK_SIZE + 2 + len > wpabuf_tailroom(buf)) {
     516           0 :                 wpa_printf(MSG_ERROR, "protect frame: buffer too small");
     517           0 :                 return -EINVAL;
     518             :         }
     519             : 
     520         262 :         ampe_ie = os_zalloc(2 + len);
     521         262 :         if (!ampe_ie) {
     522           2 :                 wpa_printf(MSG_ERROR, "protect frame: out of memory");
     523           2 :                 return -ENOMEM;
     524             :         }
     525             : 
     526             :         /*  IE: AMPE */
     527         260 :         ampe_ie[0] = WLAN_EID_AMPE;
     528         260 :         ampe_ie[1] = len;
     529         260 :         ampe = (struct ieee80211_ampe_ie *) (ampe_ie + 2);
     530             : 
     531         260 :         RSN_SELECTOR_PUT(ampe->selected_pairwise_suite,
     532             :                          RSN_CIPHER_SUITE_CCMP);
     533         260 :         os_memcpy(ampe->local_nonce, sta->my_nonce, WPA_NONCE_LEN);
     534         260 :         os_memcpy(ampe->peer_nonce, sta->peer_nonce, WPA_NONCE_LEN);
     535             : 
     536         260 :         pos = (u8 *) (ampe + 1);
     537         260 :         if (cat[1] != PLINK_OPEN)
     538         180 :                 goto skip_keys;
     539             : 
     540             :         /* TODO: Key Replay Counter[8] optionally for
     541             :          * Mesh Group Key Inform/Acknowledge frames */
     542             : 
     543             :         /* TODO: static mgtk for now since we don't support rekeying! */
     544             :         /*
     545             :          * GTKdata[variable]:
     546             :          * MGTK[variable] || Key RSC[8] || GTKExpirationTime[4]
     547             :          */
     548          80 :         os_memcpy(pos, rsn->mgtk, rsn->mgtk_len);
     549          80 :         pos += rsn->mgtk_len;
     550          80 :         wpa_drv_get_seqnum(rsn->wpa_s, NULL, rsn->mgtk_key_id, pos);
     551          80 :         pos += WPA_KEY_RSC_LEN;
     552             :         /* Use fixed GTKExpirationTime for now */
     553          80 :         WPA_PUT_LE32(pos, 0xffffffff);
     554          80 :         pos += 4;
     555             : 
     556             : #ifdef CONFIG_IEEE80211W
     557             :         /*
     558             :          * IGTKdata[variable]:
     559             :          * Key ID[2], IPN[6], IGTK[variable]
     560             :          */
     561          80 :         if (rsn->igtk_len) {
     562           4 :                 WPA_PUT_LE16(pos, rsn->igtk_key_id);
     563           4 :                 pos += 2;
     564           4 :                 wpa_drv_get_seqnum(rsn->wpa_s, NULL, rsn->igtk_key_id, pos);
     565           4 :                 pos += 6;
     566           4 :                 os_memcpy(pos, rsn->igtk, rsn->igtk_len);
     567             :         }
     568             : #endif /* CONFIG_IEEE80211W */
     569             : 
     570             : skip_keys:
     571         260 :         wpa_hexdump_key(MSG_DEBUG, "mesh: Plaintext AMPE element",
     572             :                         ampe_ie, 2 + len);
     573             : 
     574             :         /* IE: MIC */
     575         260 :         wpabuf_put_u8(buf, WLAN_EID_MIC);
     576         260 :         wpabuf_put_u8(buf, AES_BLOCK_SIZE);
     577             :         /* MIC field is output ciphertext */
     578             : 
     579             :         /* encrypt after MIC */
     580         260 :         mic_payload = wpabuf_put(buf, 2 + len + AES_BLOCK_SIZE);
     581             : 
     582         260 :         if (aes_siv_encrypt(sta->aek, ampe_ie, 2 + len, 3,
     583             :                             aad, aad_len, mic_payload)) {
     584           1 :                 wpa_printf(MSG_ERROR, "protect frame: failed to encrypt");
     585           1 :                 ret = -ENOMEM;
     586             :         }
     587             : 
     588         260 :         os_free(ampe_ie);
     589             : 
     590         260 :         return ret;
     591             : }
     592             : 
     593             : 
     594         187 : int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta,
     595             :                           struct ieee802_11_elems *elems, const u8 *cat,
     596             :                           const u8 *chosen_pmk,
     597             :                           const u8 *start, size_t elems_len)
     598             : {
     599         187 :         int ret = 0;
     600             :         struct ieee80211_ampe_ie *ampe;
     601         187 :         u8 null_nonce[WPA_NONCE_LEN] = {};
     602             :         u8 ampe_eid;
     603             :         u8 ampe_ie_len;
     604         187 :         u8 *ampe_buf, *crypt = NULL, *pos, *end;
     605             :         size_t crypt_len;
     606         187 :         const u8 *aad[] = { sta->addr, wpa_s->own_addr, cat };
     607         374 :         const size_t aad_len[] = { ETH_ALEN, ETH_ALEN,
     608         187 :                                    (elems->mic - 2) - cat };
     609             :         size_t key_len;
     610             : 
     611         187 :         if (!sta->sae) {
     612           7 :                 struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
     613             : 
     614           7 :                 if (!wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr)) {
     615           4 :                         wpa_printf(MSG_INFO,
     616             :                                    "Mesh RSN: SAE is not prepared yet");
     617           4 :                         return -1;
     618             :                 }
     619           3 :                 mesh_rsn_auth_sae_sta(wpa_s, sta);
     620             :         }
     621             : 
     622         183 :         if (chosen_pmk && os_memcmp(chosen_pmk, sta->sae->pmkid, PMKID_LEN)) {
     623           2 :                 wpa_msg(wpa_s, MSG_DEBUG,
     624             :                         "Mesh RSN: Invalid PMKID (Chosen PMK did not match calculated PMKID)");
     625           2 :                 return -1;
     626             :         }
     627             : 
     628         181 :         if (!elems->mic || elems->mic_len < AES_BLOCK_SIZE) {
     629           1 :                 wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: missing mic ie");
     630           1 :                 return -1;
     631             :         }
     632             : 
     633         180 :         ampe_buf = (u8 *) elems->mic + elems->mic_len;
     634         180 :         if ((int) elems_len < ampe_buf - start)
     635           0 :                 return -1;
     636             : 
     637         180 :         crypt_len = elems_len - (elems->mic - start);
     638         180 :         if (crypt_len < 2 + AES_BLOCK_SIZE) {
     639           0 :                 wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: missing ampe ie");
     640           0 :                 return -1;
     641             :         }
     642             : 
     643             :         /* crypt is modified by siv_decrypt */
     644         180 :         crypt = os_zalloc(crypt_len);
     645         180 :         if (!crypt) {
     646           1 :                 wpa_printf(MSG_ERROR, "Mesh RSN: out of memory");
     647           1 :                 ret = -ENOMEM;
     648           1 :                 goto free;
     649             :         }
     650             : 
     651         179 :         os_memcpy(crypt, elems->mic, crypt_len);
     652             : 
     653         179 :         if (aes_siv_decrypt(sta->aek, crypt, crypt_len, 3,
     654             :                             aad, aad_len, ampe_buf)) {
     655           1 :                 wpa_printf(MSG_ERROR, "Mesh RSN: frame verification failed!");
     656           1 :                 ret = -2;
     657           1 :                 goto free;
     658             :         }
     659             : 
     660         178 :         crypt_len -= AES_BLOCK_SIZE;
     661         178 :         wpa_hexdump_key(MSG_DEBUG, "mesh: Decrypted AMPE element",
     662             :                         ampe_buf, crypt_len);
     663             : 
     664         178 :         ampe_eid = *ampe_buf++;
     665         178 :         ampe_ie_len = *ampe_buf++;
     666             : 
     667         356 :         if (ampe_eid != WLAN_EID_AMPE ||
     668         356 :             (size_t) 2 + ampe_ie_len > crypt_len ||
     669             :             ampe_ie_len < sizeof(struct ieee80211_ampe_ie)) {
     670           0 :                 wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: invalid ampe ie");
     671           0 :                 ret = -1;
     672           0 :                 goto free;
     673             :         }
     674             : 
     675         178 :         ampe = (struct ieee80211_ampe_ie *) ampe_buf;
     676         178 :         pos = (u8 *) (ampe + 1);
     677         178 :         end = ampe_buf + ampe_ie_len;
     678         291 :         if (os_memcmp(ampe->peer_nonce, null_nonce, WPA_NONCE_LEN) != 0 &&
     679         113 :             os_memcmp(ampe->peer_nonce, sta->my_nonce, WPA_NONCE_LEN) != 0) {
     680           0 :                 wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: invalid peer nonce");
     681           0 :                 ret = -1;
     682           0 :                 goto free;
     683             :         }
     684         178 :         os_memcpy(sta->peer_nonce, ampe->local_nonce,
     685             :                   sizeof(ampe->local_nonce));
     686             : 
     687             :         /* TODO: Key Replay Counter[8] in Mesh Group Key Inform/Acknowledge
     688             :          * frames */
     689             : 
     690             :         /*
     691             :          * GTKdata shall not be included in Mesh Peering Confirm. While the
     692             :          * standard does not state the same about IGTKdata, that same constraint
     693             :          * needs to apply for it. It makes no sense to include the keys in Mesh
     694             :          * Peering Close frames either, so while the standard does not seem to
     695             :          * have a shall statement for these, they are described without
     696             :          * mentioning GTKdata.
     697             :          *
     698             :          * An earlier implementation used to add GTKdata to both Mesh Peering
     699             :          * Open and Mesh Peering Confirm frames, so ignore the possibly present
     700             :          * GTKdata frame without rejecting the frame as a backwards
     701             :          * compatibility mechanism.
     702             :          */
     703         178 :         if (cat[1] != PLINK_OPEN) {
     704         108 :                 if (end > pos) {
     705           0 :                         wpa_hexdump_key(MSG_DEBUG,
     706             :                                         "mesh: Ignore unexpected GTKdata(etc.) fields in the end of AMPE element in Mesh Peering Confirm/Close",
     707           0 :                                         pos, end - pos);
     708             :                 }
     709         108 :                 goto free;
     710             :         }
     711             : 
     712             :         /*
     713             :          * GTKdata[variable]:
     714             :          * MGTK[variable] || Key RSC[8] || GTKExpirationTime[4]
     715             :          */
     716          70 :         sta->mgtk_key_id = 1; /* FIX: Where to get Key ID? */
     717          70 :         key_len = wpa_cipher_key_len(wpa_s->mesh_rsn->group_cipher);
     718          70 :         if ((int) key_len + WPA_KEY_RSC_LEN + 4 > end - pos) {
     719           0 :                 wpa_dbg(wpa_s, MSG_DEBUG, "mesh: Truncated AMPE element");
     720           0 :                 ret = -1;
     721           0 :                 goto free;
     722             :         }
     723          70 :         sta->mgtk_len = key_len;
     724          70 :         os_memcpy(sta->mgtk, pos, sta->mgtk_len);
     725         140 :         wpa_hexdump_key(MSG_DEBUG, "mesh: GTKdata - MGTK",
     726          70 :                         sta->mgtk, sta->mgtk_len);
     727          70 :         pos += sta->mgtk_len;
     728          70 :         wpa_hexdump(MSG_DEBUG, "mesh: GTKdata - MGTK - Key RSC",
     729             :                     pos, WPA_KEY_RSC_LEN);
     730          70 :         os_memcpy(sta->mgtk_rsc, pos, sizeof(sta->mgtk_rsc));
     731          70 :         pos += WPA_KEY_RSC_LEN;
     732          70 :         wpa_printf(MSG_DEBUG,
     733             :                    "mesh: GTKdata - MGTK - GTKExpirationTime: %u seconds",
     734             :                    WPA_GET_LE32(pos));
     735          70 :         pos += 4;
     736             : 
     737             : #ifdef CONFIG_IEEE80211W
     738             :         /*
     739             :          * IGTKdata[variable]:
     740             :          * Key ID[2], IPN[6], IGTK[variable]
     741             :          */
     742          70 :         key_len = wpa_cipher_key_len(wpa_s->mesh_rsn->mgmt_group_cipher);
     743          70 :         if (end - pos >= (int) (2 + 6 + key_len)) {
     744           4 :                 sta->igtk_key_id = WPA_GET_LE16(pos);
     745           4 :                 wpa_printf(MSG_DEBUG, "mesh: IGTKdata - Key ID %u",
     746           4 :                            sta->igtk_key_id);
     747           4 :                 pos += 2;
     748           4 :                 os_memcpy(sta->igtk_rsc, pos, sizeof(sta->igtk_rsc));
     749           4 :                 wpa_hexdump(MSG_DEBUG, "mesh: IGTKdata - IPN",
     750           4 :                             sta->igtk_rsc, sizeof(sta->igtk_rsc));
     751           4 :                 pos += 6;
     752           4 :                 os_memcpy(sta->igtk, pos, key_len);
     753           4 :                 sta->igtk_len = key_len;
     754           8 :                 wpa_hexdump_key(MSG_DEBUG, "mesh: IGTKdata - IGTK",
     755           4 :                                 sta->igtk, sta->igtk_len);
     756             :         }
     757             : #endif /* CONFIG_IEEE80211W */
     758             : 
     759             : free:
     760         180 :         os_free(crypt);
     761         180 :         return ret;
     762             : }

Generated by: LCOV version 1.10