15b9c547cSRui Paulo /* 25b9c547cSRui Paulo * WPA Supplicant - Mesh RSN routines 35b9c547cSRui Paulo * Copyright (c) 2013-2014, cozybit, Inc. All rights reserved. 45b9c547cSRui Paulo * 55b9c547cSRui Paulo * This software may be distributed under the terms of the BSD license. 65b9c547cSRui Paulo * See README for more details. 75b9c547cSRui Paulo */ 85b9c547cSRui Paulo 95b9c547cSRui Paulo #include "utils/includes.h" 105b9c547cSRui Paulo 115b9c547cSRui Paulo #include "utils/common.h" 125b9c547cSRui Paulo #include "utils/eloop.h" 135b9c547cSRui Paulo #include "crypto/sha256.h" 145b9c547cSRui Paulo #include "crypto/random.h" 155b9c547cSRui Paulo #include "crypto/aes.h" 165b9c547cSRui Paulo #include "crypto/aes_siv.h" 175b9c547cSRui Paulo #include "rsn_supp/wpa.h" 185b9c547cSRui Paulo #include "ap/hostapd.h" 195b9c547cSRui Paulo #include "ap/wpa_auth.h" 205b9c547cSRui Paulo #include "ap/sta_info.h" 215b9c547cSRui Paulo #include "ap/ieee802_11.h" 225b9c547cSRui Paulo #include "wpa_supplicant_i.h" 235b9c547cSRui Paulo #include "driver_i.h" 245b9c547cSRui Paulo #include "wpas_glue.h" 255b9c547cSRui Paulo #include "mesh_mpm.h" 265b9c547cSRui Paulo #include "mesh_rsn.h" 275b9c547cSRui Paulo 285b9c547cSRui Paulo #define MESH_AUTH_TIMEOUT 10 295b9c547cSRui Paulo #define MESH_AUTH_RETRY 3 305b9c547cSRui Paulo 315b9c547cSRui Paulo void mesh_auth_timer(void *eloop_ctx, void *user_data) 325b9c547cSRui Paulo { 335b9c547cSRui Paulo struct wpa_supplicant *wpa_s = eloop_ctx; 345b9c547cSRui Paulo struct sta_info *sta = user_data; 35*780fb4a2SCy Schubert struct hostapd_data *hapd; 365b9c547cSRui Paulo 375b9c547cSRui Paulo if (sta->sae->state != SAE_ACCEPTED) { 385b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "AUTH: Re-authenticate with " MACSTR 395b9c547cSRui Paulo " (attempt %d) ", 405b9c547cSRui Paulo MAC2STR(sta->addr), sta->sae_auth_retry); 415b9c547cSRui Paulo wpa_msg(wpa_s, MSG_INFO, MESH_SAE_AUTH_FAILURE "addr=" MACSTR, 425b9c547cSRui Paulo MAC2STR(sta->addr)); 435b9c547cSRui Paulo if (sta->sae_auth_retry < MESH_AUTH_RETRY) { 445b9c547cSRui Paulo mesh_rsn_auth_sae_sta(wpa_s, sta); 455b9c547cSRui Paulo } else { 46*780fb4a2SCy Schubert hapd = wpa_s->ifmsh->bss[0]; 47*780fb4a2SCy Schubert 485b9c547cSRui Paulo if (sta->sae_auth_retry > MESH_AUTH_RETRY) { 49*780fb4a2SCy Schubert ap_free_sta(hapd, sta); 505b9c547cSRui Paulo return; 515b9c547cSRui Paulo } 525b9c547cSRui Paulo 535b9c547cSRui Paulo /* block the STA if exceeded the number of attempts */ 545b9c547cSRui Paulo wpa_mesh_set_plink_state(wpa_s, sta, PLINK_BLOCKED); 555b9c547cSRui Paulo sta->sae->state = SAE_NOTHING; 565b9c547cSRui Paulo wpa_msg(wpa_s, MSG_INFO, MESH_SAE_AUTH_BLOCKED "addr=" 575b9c547cSRui Paulo MACSTR " duration=%d", 585b9c547cSRui Paulo MAC2STR(sta->addr), 59*780fb4a2SCy Schubert hapd->conf->ap_max_inactivity); 605b9c547cSRui Paulo } 615b9c547cSRui Paulo sta->sae_auth_retry++; 625b9c547cSRui Paulo } 635b9c547cSRui Paulo } 645b9c547cSRui Paulo 655b9c547cSRui Paulo 665b9c547cSRui Paulo static void auth_logger(void *ctx, const u8 *addr, logger_level level, 675b9c547cSRui Paulo const char *txt) 685b9c547cSRui Paulo { 695b9c547cSRui Paulo if (addr) 705b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " - %s", 715b9c547cSRui Paulo MAC2STR(addr), txt); 725b9c547cSRui Paulo else 735b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "AUTH: %s", txt); 745b9c547cSRui Paulo } 755b9c547cSRui Paulo 765b9c547cSRui Paulo 775b9c547cSRui Paulo static const u8 *auth_get_psk(void *ctx, const u8 *addr, 785b9c547cSRui Paulo const u8 *p2p_dev_addr, const u8 *prev_psk) 795b9c547cSRui Paulo { 805b9c547cSRui Paulo struct mesh_rsn *mesh_rsn = ctx; 815b9c547cSRui Paulo struct hostapd_data *hapd = mesh_rsn->wpa_s->ifmsh->bss[0]; 825b9c547cSRui Paulo struct sta_info *sta = ap_get_sta(hapd, addr); 835b9c547cSRui Paulo 845b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)", 855b9c547cSRui Paulo __func__, MAC2STR(addr), prev_psk); 865b9c547cSRui Paulo 875b9c547cSRui Paulo if (sta && sta->auth_alg == WLAN_AUTH_SAE) { 885b9c547cSRui Paulo if (!sta->sae || prev_psk) 895b9c547cSRui Paulo return NULL; 905b9c547cSRui Paulo return sta->sae->pmk; 915b9c547cSRui Paulo } 925b9c547cSRui Paulo 935b9c547cSRui Paulo return NULL; 945b9c547cSRui Paulo } 955b9c547cSRui Paulo 965b9c547cSRui Paulo 975b9c547cSRui Paulo static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg, 985b9c547cSRui Paulo const u8 *addr, int idx, u8 *key, size_t key_len) 995b9c547cSRui Paulo { 1005b9c547cSRui Paulo struct mesh_rsn *mesh_rsn = ctx; 1015b9c547cSRui Paulo u8 seq[6]; 1025b9c547cSRui Paulo 1035b9c547cSRui Paulo os_memset(seq, 0, sizeof(seq)); 1045b9c547cSRui Paulo 1055b9c547cSRui Paulo if (addr) { 1065b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "AUTH: %s(alg=%d addr=" MACSTR 1075b9c547cSRui Paulo " key_idx=%d)", 1085b9c547cSRui Paulo __func__, alg, MAC2STR(addr), idx); 1095b9c547cSRui Paulo } else { 1105b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "AUTH: %s(alg=%d key_idx=%d)", 1115b9c547cSRui Paulo __func__, alg, idx); 1125b9c547cSRui Paulo } 1135b9c547cSRui Paulo wpa_hexdump_key(MSG_DEBUG, "AUTH: set_key - key", key, key_len); 1145b9c547cSRui Paulo 1155b9c547cSRui Paulo return wpa_drv_set_key(mesh_rsn->wpa_s, alg, addr, idx, 1165b9c547cSRui Paulo 1, seq, 6, key, key_len); 1175b9c547cSRui Paulo } 1185b9c547cSRui Paulo 1195b9c547cSRui Paulo 1205b9c547cSRui Paulo static int auth_start_ampe(void *ctx, const u8 *addr) 1215b9c547cSRui Paulo { 1225b9c547cSRui Paulo struct mesh_rsn *mesh_rsn = ctx; 1235b9c547cSRui Paulo struct hostapd_data *hapd; 1245b9c547cSRui Paulo struct sta_info *sta; 1255b9c547cSRui Paulo 1265b9c547cSRui Paulo if (mesh_rsn->wpa_s->current_ssid->mode != WPAS_MODE_MESH) 1275b9c547cSRui Paulo return -1; 1285b9c547cSRui Paulo 1295b9c547cSRui Paulo hapd = mesh_rsn->wpa_s->ifmsh->bss[0]; 1305b9c547cSRui Paulo sta = ap_get_sta(hapd, addr); 1315b9c547cSRui Paulo if (sta) 1325b9c547cSRui Paulo eloop_cancel_timeout(mesh_auth_timer, mesh_rsn->wpa_s, sta); 1335b9c547cSRui Paulo 1345b9c547cSRui Paulo mesh_mpm_auth_peer(mesh_rsn->wpa_s, addr); 1355b9c547cSRui Paulo return 0; 1365b9c547cSRui Paulo } 1375b9c547cSRui Paulo 1385b9c547cSRui Paulo 139*780fb4a2SCy Schubert static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr, 140*780fb4a2SCy Schubert enum mfp_options ieee80211w) 1415b9c547cSRui Paulo { 1425b9c547cSRui Paulo struct wpa_auth_config conf; 1435b9c547cSRui Paulo struct wpa_auth_callbacks cb; 1445b9c547cSRui Paulo u8 seq[6] = {}; 1455b9c547cSRui Paulo 1465b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine"); 1475b9c547cSRui Paulo 1485b9c547cSRui Paulo os_memset(&conf, 0, sizeof(conf)); 149*780fb4a2SCy Schubert conf.wpa = WPA_PROTO_RSN; 1505b9c547cSRui Paulo conf.wpa_key_mgmt = WPA_KEY_MGMT_SAE; 151*780fb4a2SCy Schubert conf.wpa_pairwise = rsn->pairwise_cipher; 152*780fb4a2SCy Schubert conf.rsn_pairwise = rsn->pairwise_cipher; 153*780fb4a2SCy Schubert conf.wpa_group = rsn->group_cipher; 1545b9c547cSRui Paulo conf.eapol_version = 0; 1555b9c547cSRui Paulo conf.wpa_group_rekey = -1; 156*780fb4a2SCy Schubert #ifdef CONFIG_IEEE80211W 157*780fb4a2SCy Schubert conf.ieee80211w = ieee80211w; 158*780fb4a2SCy Schubert if (ieee80211w != NO_MGMT_FRAME_PROTECTION) 159*780fb4a2SCy Schubert conf.group_mgmt_cipher = rsn->mgmt_group_cipher; 160*780fb4a2SCy Schubert #endif /* CONFIG_IEEE80211W */ 1615b9c547cSRui Paulo 1625b9c547cSRui Paulo os_memset(&cb, 0, sizeof(cb)); 1635b9c547cSRui Paulo cb.ctx = rsn; 1645b9c547cSRui Paulo cb.logger = auth_logger; 1655b9c547cSRui Paulo cb.get_psk = auth_get_psk; 1665b9c547cSRui Paulo cb.set_key = auth_set_key; 1675b9c547cSRui Paulo cb.start_ampe = auth_start_ampe; 1685b9c547cSRui Paulo 1695b9c547cSRui Paulo rsn->auth = wpa_init(addr, &conf, &cb); 1705b9c547cSRui Paulo if (rsn->auth == NULL) { 1715b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed"); 1725b9c547cSRui Paulo return -1; 1735b9c547cSRui Paulo } 1745b9c547cSRui Paulo 1755b9c547cSRui Paulo /* TODO: support rekeying */ 176*780fb4a2SCy Schubert rsn->mgtk_len = wpa_cipher_key_len(conf.wpa_group); 177*780fb4a2SCy Schubert if (random_get_bytes(rsn->mgtk, rsn->mgtk_len) < 0) 1785b9c547cSRui Paulo return -1; 179*780fb4a2SCy Schubert rsn->mgtk_key_id = 1; 180*780fb4a2SCy Schubert 181*780fb4a2SCy Schubert #ifdef CONFIG_IEEE80211W 182*780fb4a2SCy Schubert if (ieee80211w != NO_MGMT_FRAME_PROTECTION) { 183*780fb4a2SCy Schubert rsn->igtk_len = wpa_cipher_key_len(conf.group_mgmt_cipher); 184*780fb4a2SCy Schubert if (random_get_bytes(rsn->igtk, rsn->igtk_len) < 0) 185*780fb4a2SCy Schubert return -1; 186*780fb4a2SCy Schubert rsn->igtk_key_id = 4; 1875b9c547cSRui Paulo 1885b9c547cSRui Paulo /* group mgmt */ 189*780fb4a2SCy Schubert wpa_hexdump_key(MSG_DEBUG, "mesh: Own TX IGTK", 190*780fb4a2SCy Schubert rsn->igtk, rsn->igtk_len); 191*780fb4a2SCy Schubert wpa_drv_set_key(rsn->wpa_s, 192*780fb4a2SCy Schubert wpa_cipher_to_alg(rsn->mgmt_group_cipher), NULL, 193*780fb4a2SCy Schubert rsn->igtk_key_id, 1, 194*780fb4a2SCy Schubert seq, sizeof(seq), rsn->igtk, rsn->igtk_len); 195*780fb4a2SCy Schubert } 196*780fb4a2SCy Schubert #endif /* CONFIG_IEEE80211W */ 1975b9c547cSRui Paulo 1985b9c547cSRui Paulo /* group privacy / data frames */ 199*780fb4a2SCy Schubert wpa_hexdump_key(MSG_DEBUG, "mesh: Own TX MGTK", 200*780fb4a2SCy Schubert rsn->mgtk, rsn->mgtk_len); 201*780fb4a2SCy Schubert wpa_drv_set_key(rsn->wpa_s, wpa_cipher_to_alg(rsn->group_cipher), NULL, 202*780fb4a2SCy Schubert rsn->mgtk_key_id, 1, seq, sizeof(seq), 203*780fb4a2SCy Schubert rsn->mgtk, rsn->mgtk_len); 2045b9c547cSRui Paulo 2055b9c547cSRui Paulo return 0; 2065b9c547cSRui Paulo } 2075b9c547cSRui Paulo 2085b9c547cSRui Paulo 2095b9c547cSRui Paulo static void mesh_rsn_deinit(struct mesh_rsn *rsn) 2105b9c547cSRui Paulo { 2115b9c547cSRui Paulo os_memset(rsn->mgtk, 0, sizeof(rsn->mgtk)); 212*780fb4a2SCy Schubert rsn->mgtk_len = 0; 213*780fb4a2SCy Schubert os_memset(rsn->igtk, 0, sizeof(rsn->igtk)); 214*780fb4a2SCy Schubert rsn->igtk_len = 0; 215325151a3SRui Paulo if (rsn->auth) 2165b9c547cSRui Paulo wpa_deinit(rsn->auth); 2175b9c547cSRui Paulo } 2185b9c547cSRui Paulo 2195b9c547cSRui Paulo 2205b9c547cSRui Paulo struct mesh_rsn *mesh_rsn_auth_init(struct wpa_supplicant *wpa_s, 2215b9c547cSRui Paulo struct mesh_conf *conf) 2225b9c547cSRui Paulo { 2235b9c547cSRui Paulo struct mesh_rsn *mesh_rsn; 2245b9c547cSRui Paulo struct hostapd_data *bss = wpa_s->ifmsh->bss[0]; 2255b9c547cSRui Paulo const u8 *ie; 2265b9c547cSRui Paulo size_t ie_len; 2275b9c547cSRui Paulo 2285b9c547cSRui Paulo mesh_rsn = os_zalloc(sizeof(*mesh_rsn)); 2295b9c547cSRui Paulo if (mesh_rsn == NULL) 2305b9c547cSRui Paulo return NULL; 2315b9c547cSRui Paulo mesh_rsn->wpa_s = wpa_s; 232*780fb4a2SCy Schubert mesh_rsn->pairwise_cipher = conf->pairwise_cipher; 233*780fb4a2SCy Schubert mesh_rsn->group_cipher = conf->group_cipher; 234*780fb4a2SCy Schubert mesh_rsn->mgmt_group_cipher = conf->mgmt_group_cipher; 2355b9c547cSRui Paulo 236*780fb4a2SCy Schubert if (__mesh_rsn_auth_init(mesh_rsn, wpa_s->own_addr, 237*780fb4a2SCy Schubert conf->ieee80211w) < 0) { 2385b9c547cSRui Paulo mesh_rsn_deinit(mesh_rsn); 239325151a3SRui Paulo os_free(mesh_rsn); 2405b9c547cSRui Paulo return NULL; 2415b9c547cSRui Paulo } 2425b9c547cSRui Paulo 2435b9c547cSRui Paulo bss->wpa_auth = mesh_rsn->auth; 2445b9c547cSRui Paulo 2455b9c547cSRui Paulo ie = wpa_auth_get_wpa_ie(mesh_rsn->auth, &ie_len); 246325151a3SRui Paulo conf->rsn_ie = (u8 *) ie; 247325151a3SRui Paulo conf->rsn_ie_len = ie_len; 2485b9c547cSRui Paulo 2495b9c547cSRui Paulo wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid); 2505b9c547cSRui Paulo 2515b9c547cSRui Paulo return mesh_rsn; 2525b9c547cSRui Paulo } 2535b9c547cSRui Paulo 2545b9c547cSRui Paulo 2555b9c547cSRui Paulo static int index_within_array(const int *array, int idx) 2565b9c547cSRui Paulo { 2575b9c547cSRui Paulo int i; 2585b9c547cSRui Paulo 2595b9c547cSRui Paulo for (i = 0; i < idx; i++) { 2605b9c547cSRui Paulo if (array[i] == -1) 2615b9c547cSRui Paulo return 0; 2625b9c547cSRui Paulo } 2635b9c547cSRui Paulo 2645b9c547cSRui Paulo return 1; 2655b9c547cSRui Paulo } 2665b9c547cSRui Paulo 2675b9c547cSRui Paulo 2685b9c547cSRui Paulo static int mesh_rsn_sae_group(struct wpa_supplicant *wpa_s, 2695b9c547cSRui Paulo struct sae_data *sae) 2705b9c547cSRui Paulo { 2715b9c547cSRui Paulo int *groups = wpa_s->ifmsh->bss[0]->conf->sae_groups; 2725b9c547cSRui Paulo 2735b9c547cSRui Paulo /* Configuration may have changed, so validate current index */ 2745b9c547cSRui Paulo if (!index_within_array(groups, wpa_s->mesh_rsn->sae_group_index)) 2755b9c547cSRui Paulo return -1; 2765b9c547cSRui Paulo 2775b9c547cSRui Paulo for (;;) { 2785b9c547cSRui Paulo int group = groups[wpa_s->mesh_rsn->sae_group_index]; 2795b9c547cSRui Paulo 2805b9c547cSRui Paulo if (group <= 0) 2815b9c547cSRui Paulo break; 2825b9c547cSRui Paulo if (sae_set_group(sae, group) == 0) { 2835b9c547cSRui Paulo wpa_dbg(wpa_s, MSG_DEBUG, "SME: Selected SAE group %d", 2845b9c547cSRui Paulo sae->group); 2855b9c547cSRui Paulo return 0; 2865b9c547cSRui Paulo } 2875b9c547cSRui Paulo wpa_s->mesh_rsn->sae_group_index++; 2885b9c547cSRui Paulo } 2895b9c547cSRui Paulo 2905b9c547cSRui Paulo return -1; 2915b9c547cSRui Paulo } 2925b9c547cSRui Paulo 2935b9c547cSRui Paulo 2945b9c547cSRui Paulo static int mesh_rsn_build_sae_commit(struct wpa_supplicant *wpa_s, 2955b9c547cSRui Paulo struct wpa_ssid *ssid, 2965b9c547cSRui Paulo struct sta_info *sta) 2975b9c547cSRui Paulo { 2985b9c547cSRui Paulo if (ssid->passphrase == NULL) { 2995b9c547cSRui Paulo wpa_msg(wpa_s, MSG_DEBUG, "SAE: No password available"); 3005b9c547cSRui Paulo return -1; 3015b9c547cSRui Paulo } 3025b9c547cSRui Paulo 3035b9c547cSRui Paulo if (mesh_rsn_sae_group(wpa_s, sta->sae) < 0) { 3045b9c547cSRui Paulo wpa_msg(wpa_s, MSG_DEBUG, "SAE: Failed to select group"); 3055b9c547cSRui Paulo return -1; 3065b9c547cSRui Paulo } 3075b9c547cSRui Paulo 3085b9c547cSRui Paulo return sae_prepare_commit(wpa_s->own_addr, sta->addr, 3095b9c547cSRui Paulo (u8 *) ssid->passphrase, 3105b9c547cSRui Paulo os_strlen(ssid->passphrase), sta->sae); 3115b9c547cSRui Paulo } 3125b9c547cSRui Paulo 3135b9c547cSRui Paulo 3145b9c547cSRui Paulo /* initiate new SAE authentication with sta */ 3155b9c547cSRui Paulo int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s, 3165b9c547cSRui Paulo struct sta_info *sta) 3175b9c547cSRui Paulo { 3185b9c547cSRui Paulo struct hostapd_data *hapd = wpa_s->ifmsh->bss[0]; 3195b9c547cSRui Paulo struct wpa_ssid *ssid = wpa_s->current_ssid; 320*780fb4a2SCy Schubert struct rsn_pmksa_cache_entry *pmksa; 3215b9c547cSRui Paulo unsigned int rnd; 3225b9c547cSRui Paulo int ret; 3235b9c547cSRui Paulo 3245b9c547cSRui Paulo if (!ssid) { 3255b9c547cSRui Paulo wpa_msg(wpa_s, MSG_DEBUG, 3265b9c547cSRui Paulo "AUTH: No current_ssid known to initiate new SAE"); 3275b9c547cSRui Paulo return -1; 3285b9c547cSRui Paulo } 3295b9c547cSRui Paulo 3305b9c547cSRui Paulo if (!sta->sae) { 3315b9c547cSRui Paulo sta->sae = os_zalloc(sizeof(*sta->sae)); 3325b9c547cSRui Paulo if (sta->sae == NULL) 3335b9c547cSRui Paulo return -1; 3345b9c547cSRui Paulo } 3355b9c547cSRui Paulo 336*780fb4a2SCy Schubert pmksa = wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr); 337*780fb4a2SCy Schubert if (pmksa) { 338*780fb4a2SCy Schubert if (!sta->wpa_sm) 339*780fb4a2SCy Schubert sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, 340*780fb4a2SCy Schubert sta->addr, NULL); 341*780fb4a2SCy Schubert if (!sta->wpa_sm) { 342*780fb4a2SCy Schubert wpa_printf(MSG_ERROR, 343*780fb4a2SCy Schubert "mesh: Failed to initialize RSN state machine"); 344*780fb4a2SCy Schubert return -1; 345*780fb4a2SCy Schubert } 346*780fb4a2SCy Schubert 347*780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, 348*780fb4a2SCy Schubert "AUTH: Mesh PMKSA cache entry found for " MACSTR 349*780fb4a2SCy Schubert " - try to use PMKSA caching instead of new SAE authentication", 350*780fb4a2SCy Schubert MAC2STR(sta->addr)); 351*780fb4a2SCy Schubert wpa_auth_pmksa_set_to_sm(pmksa, sta->wpa_sm, hapd->wpa_auth, 352*780fb4a2SCy Schubert sta->sae->pmkid, sta->sae->pmk); 353*780fb4a2SCy Schubert sae_accept_sta(hapd, sta); 354*780fb4a2SCy Schubert sta->mesh_sae_pmksa_caching = 1; 355*780fb4a2SCy Schubert return 0; 356*780fb4a2SCy Schubert } 357*780fb4a2SCy Schubert sta->mesh_sae_pmksa_caching = 0; 358*780fb4a2SCy Schubert 3595b9c547cSRui Paulo if (mesh_rsn_build_sae_commit(wpa_s, ssid, sta)) 3605b9c547cSRui Paulo return -1; 3615b9c547cSRui Paulo 3625b9c547cSRui Paulo wpa_msg(wpa_s, MSG_DEBUG, 3635b9c547cSRui Paulo "AUTH: started authentication with SAE peer: " MACSTR, 3645b9c547cSRui Paulo MAC2STR(sta->addr)); 3655b9c547cSRui Paulo 3665b9c547cSRui Paulo ret = auth_sae_init_committed(hapd, sta); 3675b9c547cSRui Paulo if (ret) 3685b9c547cSRui Paulo return ret; 3695b9c547cSRui Paulo 3705b9c547cSRui Paulo eloop_cancel_timeout(mesh_auth_timer, wpa_s, sta); 3715b9c547cSRui Paulo rnd = rand() % MESH_AUTH_TIMEOUT; 3725b9c547cSRui Paulo eloop_register_timeout(MESH_AUTH_TIMEOUT + rnd, 0, mesh_auth_timer, 3735b9c547cSRui Paulo wpa_s, sta); 3745b9c547cSRui Paulo return 0; 3755b9c547cSRui Paulo } 3765b9c547cSRui Paulo 3775b9c547cSRui Paulo 3785b9c547cSRui Paulo void mesh_rsn_get_pmkid(struct mesh_rsn *rsn, struct sta_info *sta, u8 *pmkid) 3795b9c547cSRui Paulo { 380*780fb4a2SCy Schubert os_memcpy(pmkid, sta->sae->pmkid, SAE_PMKID_LEN); 3815b9c547cSRui Paulo } 3825b9c547cSRui Paulo 3835b9c547cSRui Paulo 3845b9c547cSRui Paulo static void 3855b9c547cSRui Paulo mesh_rsn_derive_aek(struct mesh_rsn *rsn, struct sta_info *sta) 3865b9c547cSRui Paulo { 3875b9c547cSRui Paulo u8 *myaddr = rsn->wpa_s->own_addr; 3885b9c547cSRui Paulo u8 *peer = sta->addr; 389*780fb4a2SCy Schubert u8 *addr1, *addr2; 390*780fb4a2SCy Schubert u8 context[RSN_SELECTOR_LEN + 2 * ETH_ALEN], *ptr = context; 3915b9c547cSRui Paulo 392*780fb4a2SCy Schubert /* 393*780fb4a2SCy Schubert * AEK = KDF-Hash-256(PMK, "AEK Derivation", Selected AKM Suite || 394*780fb4a2SCy Schubert * min(localMAC, peerMAC) || max(localMAC, peerMAC)) 395*780fb4a2SCy Schubert */ 396*780fb4a2SCy Schubert /* Selected AKM Suite: SAE */ 397*780fb4a2SCy Schubert RSN_SELECTOR_PUT(ptr, RSN_AUTH_KEY_MGMT_SAE); 398*780fb4a2SCy Schubert ptr += RSN_SELECTOR_LEN; 3995b9c547cSRui Paulo 4005b9c547cSRui Paulo if (os_memcmp(myaddr, peer, ETH_ALEN) < 0) { 4015b9c547cSRui Paulo addr1 = myaddr; 4025b9c547cSRui Paulo addr2 = peer; 403*780fb4a2SCy Schubert } else { 404*780fb4a2SCy Schubert addr1 = peer; 405*780fb4a2SCy Schubert addr2 = myaddr; 4065b9c547cSRui Paulo } 407*780fb4a2SCy Schubert os_memcpy(ptr, addr1, ETH_ALEN); 408*780fb4a2SCy Schubert ptr += ETH_ALEN; 409*780fb4a2SCy Schubert os_memcpy(ptr, addr2, ETH_ALEN); 4105b9c547cSRui Paulo 4115b9c547cSRui Paulo sha256_prf(sta->sae->pmk, sizeof(sta->sae->pmk), "AEK Derivation", 4125b9c547cSRui Paulo context, sizeof(context), sta->aek, sizeof(sta->aek)); 4135b9c547cSRui Paulo } 4145b9c547cSRui Paulo 4155b9c547cSRui Paulo 4165b9c547cSRui Paulo /* derive mesh temporal key from pmk */ 4175b9c547cSRui Paulo int mesh_rsn_derive_mtk(struct wpa_supplicant *wpa_s, struct sta_info *sta) 4185b9c547cSRui Paulo { 4195b9c547cSRui Paulo u8 *ptr; 4205b9c547cSRui Paulo u8 *min, *max; 4215b9c547cSRui Paulo u8 *myaddr = wpa_s->own_addr; 4225b9c547cSRui Paulo u8 *peer = sta->addr; 423*780fb4a2SCy Schubert u8 context[2 * WPA_NONCE_LEN + 2 * 2 + RSN_SELECTOR_LEN + 2 * ETH_ALEN]; 4245b9c547cSRui Paulo 425*780fb4a2SCy Schubert /* 426*780fb4a2SCy Schubert * MTK = KDF-Hash-Length(PMK, "Temporal Key Derivation", min(localNonce, 427*780fb4a2SCy Schubert * peerNonce) || max(localNonce, peerNonce) || min(localLinkID, 428*780fb4a2SCy Schubert * peerLinkID) || max(localLinkID, peerLinkID) || Selected AKM Suite || 429*780fb4a2SCy Schubert * min(localMAC, peerMAC) || max(localMAC, peerMAC)) 430*780fb4a2SCy Schubert */ 4315b9c547cSRui Paulo ptr = context; 432*780fb4a2SCy Schubert if (os_memcmp(sta->my_nonce, sta->peer_nonce, WPA_NONCE_LEN) < 0) { 4335b9c547cSRui Paulo min = sta->my_nonce; 4345b9c547cSRui Paulo max = sta->peer_nonce; 4355b9c547cSRui Paulo } else { 4365b9c547cSRui Paulo min = sta->peer_nonce; 4375b9c547cSRui Paulo max = sta->my_nonce; 4385b9c547cSRui Paulo } 439*780fb4a2SCy Schubert os_memcpy(ptr, min, WPA_NONCE_LEN); 440*780fb4a2SCy Schubert ptr += WPA_NONCE_LEN; 441*780fb4a2SCy Schubert os_memcpy(ptr, max, WPA_NONCE_LEN); 442*780fb4a2SCy Schubert ptr += WPA_NONCE_LEN; 4435b9c547cSRui Paulo 4445b9c547cSRui Paulo if (sta->my_lid < sta->peer_lid) { 445*780fb4a2SCy Schubert WPA_PUT_LE16(ptr, sta->my_lid); 446*780fb4a2SCy Schubert ptr += 2; 447*780fb4a2SCy Schubert WPA_PUT_LE16(ptr, sta->peer_lid); 448*780fb4a2SCy Schubert ptr += 2; 4495b9c547cSRui Paulo } else { 450*780fb4a2SCy Schubert WPA_PUT_LE16(ptr, sta->peer_lid); 451*780fb4a2SCy Schubert ptr += 2; 452*780fb4a2SCy Schubert WPA_PUT_LE16(ptr, sta->my_lid); 453*780fb4a2SCy Schubert ptr += 2; 4545b9c547cSRui Paulo } 4555b9c547cSRui Paulo 456*780fb4a2SCy Schubert /* Selected AKM Suite: SAE */ 457*780fb4a2SCy Schubert RSN_SELECTOR_PUT(ptr, RSN_AUTH_KEY_MGMT_SAE); 458*780fb4a2SCy Schubert ptr += RSN_SELECTOR_LEN; 4595b9c547cSRui Paulo 4605b9c547cSRui Paulo if (os_memcmp(myaddr, peer, ETH_ALEN) < 0) { 4615b9c547cSRui Paulo min = myaddr; 4625b9c547cSRui Paulo max = peer; 4635b9c547cSRui Paulo } else { 4645b9c547cSRui Paulo min = peer; 4655b9c547cSRui Paulo max = myaddr; 4665b9c547cSRui Paulo } 4675b9c547cSRui Paulo os_memcpy(ptr, min, ETH_ALEN); 468*780fb4a2SCy Schubert ptr += ETH_ALEN; 469*780fb4a2SCy Schubert os_memcpy(ptr, max, ETH_ALEN); 4705b9c547cSRui Paulo 471*780fb4a2SCy Schubert sta->mtk_len = wpa_cipher_key_len(wpa_s->mesh_rsn->pairwise_cipher); 472*780fb4a2SCy Schubert sha256_prf(sta->sae->pmk, SAE_PMK_LEN, 4735b9c547cSRui Paulo "Temporal Key Derivation", context, sizeof(context), 474*780fb4a2SCy Schubert sta->mtk, sta->mtk_len); 4755b9c547cSRui Paulo return 0; 4765b9c547cSRui Paulo } 4775b9c547cSRui Paulo 4785b9c547cSRui Paulo 4795b9c547cSRui Paulo void mesh_rsn_init_ampe_sta(struct wpa_supplicant *wpa_s, struct sta_info *sta) 4805b9c547cSRui Paulo { 481*780fb4a2SCy Schubert if (random_get_bytes(sta->my_nonce, WPA_NONCE_LEN) < 0) { 4825b9c547cSRui Paulo wpa_printf(MSG_INFO, "mesh: Failed to derive random nonce"); 4835b9c547cSRui Paulo /* TODO: How to handle this more cleanly? */ 4845b9c547cSRui Paulo } 485*780fb4a2SCy Schubert os_memset(sta->peer_nonce, 0, WPA_NONCE_LEN); 4865b9c547cSRui Paulo mesh_rsn_derive_aek(wpa_s->mesh_rsn, sta); 4875b9c547cSRui Paulo } 4885b9c547cSRui Paulo 4895b9c547cSRui Paulo 4905b9c547cSRui Paulo /* insert AMPE and encrypted MIC at @ie. 4915b9c547cSRui Paulo * @mesh_rsn: mesh RSN context 4925b9c547cSRui Paulo * @sta: STA we're sending to 4935b9c547cSRui Paulo * @cat: pointer to category code in frame header. 4945b9c547cSRui Paulo * @buf: wpabuf to add encrypted AMPE and MIC to. 4955b9c547cSRui Paulo * */ 4965b9c547cSRui Paulo int mesh_rsn_protect_frame(struct mesh_rsn *rsn, struct sta_info *sta, 4975b9c547cSRui Paulo const u8 *cat, struct wpabuf *buf) 4985b9c547cSRui Paulo { 4995b9c547cSRui Paulo struct ieee80211_ampe_ie *ampe; 5005b9c547cSRui Paulo u8 const *ie = wpabuf_head_u8(buf) + wpabuf_len(buf); 501*780fb4a2SCy Schubert u8 *ampe_ie, *pos, *mic_payload; 5025b9c547cSRui Paulo const u8 *aad[] = { rsn->wpa_s->own_addr, sta->addr, cat }; 5035b9c547cSRui Paulo const size_t aad_len[] = { ETH_ALEN, ETH_ALEN, ie - cat }; 5045b9c547cSRui Paulo int ret = 0; 505*780fb4a2SCy Schubert size_t len; 5065b9c547cSRui Paulo 507*780fb4a2SCy Schubert len = sizeof(*ampe); 508*780fb4a2SCy Schubert if (cat[1] == PLINK_OPEN) 509*780fb4a2SCy Schubert len += rsn->mgtk_len + WPA_KEY_RSC_LEN + 4; 510*780fb4a2SCy Schubert #ifdef CONFIG_IEEE80211W 511*780fb4a2SCy Schubert if (cat[1] == PLINK_OPEN && rsn->igtk_len) 512*780fb4a2SCy Schubert len += 2 + 6 + rsn->igtk_len; 513*780fb4a2SCy Schubert #endif /* CONFIG_IEEE80211W */ 514*780fb4a2SCy Schubert 515*780fb4a2SCy Schubert if (2 + AES_BLOCK_SIZE + 2 + len > wpabuf_tailroom(buf)) { 5165b9c547cSRui Paulo wpa_printf(MSG_ERROR, "protect frame: buffer too small"); 5175b9c547cSRui Paulo return -EINVAL; 5185b9c547cSRui Paulo } 5195b9c547cSRui Paulo 520*780fb4a2SCy Schubert ampe_ie = os_zalloc(2 + len); 5215b9c547cSRui Paulo if (!ampe_ie) { 5225b9c547cSRui Paulo wpa_printf(MSG_ERROR, "protect frame: out of memory"); 5235b9c547cSRui Paulo return -ENOMEM; 5245b9c547cSRui Paulo } 5255b9c547cSRui Paulo 5265b9c547cSRui Paulo /* IE: AMPE */ 5275b9c547cSRui Paulo ampe_ie[0] = WLAN_EID_AMPE; 528*780fb4a2SCy Schubert ampe_ie[1] = len; 5295b9c547cSRui Paulo ampe = (struct ieee80211_ampe_ie *) (ampe_ie + 2); 5305b9c547cSRui Paulo 5315b9c547cSRui Paulo RSN_SELECTOR_PUT(ampe->selected_pairwise_suite, 532*780fb4a2SCy Schubert RSN_CIPHER_SUITE_CCMP); 533*780fb4a2SCy Schubert os_memcpy(ampe->local_nonce, sta->my_nonce, WPA_NONCE_LEN); 534*780fb4a2SCy Schubert os_memcpy(ampe->peer_nonce, sta->peer_nonce, WPA_NONCE_LEN); 535*780fb4a2SCy Schubert 536*780fb4a2SCy Schubert pos = (u8 *) (ampe + 1); 537*780fb4a2SCy Schubert if (cat[1] != PLINK_OPEN) 538*780fb4a2SCy Schubert goto skip_keys; 539*780fb4a2SCy Schubert 540*780fb4a2SCy Schubert /* TODO: Key Replay Counter[8] optionally for 541*780fb4a2SCy Schubert * Mesh Group Key Inform/Acknowledge frames */ 542*780fb4a2SCy Schubert 5435b9c547cSRui Paulo /* TODO: static mgtk for now since we don't support rekeying! */ 544*780fb4a2SCy Schubert /* 545*780fb4a2SCy Schubert * GTKdata[variable]: 546*780fb4a2SCy Schubert * MGTK[variable] || Key RSC[8] || GTKExpirationTime[4] 547*780fb4a2SCy Schubert */ 548*780fb4a2SCy Schubert os_memcpy(pos, rsn->mgtk, rsn->mgtk_len); 549*780fb4a2SCy Schubert pos += rsn->mgtk_len; 550*780fb4a2SCy Schubert wpa_drv_get_seqnum(rsn->wpa_s, NULL, rsn->mgtk_key_id, pos); 551*780fb4a2SCy Schubert pos += WPA_KEY_RSC_LEN; 552*780fb4a2SCy Schubert /* Use fixed GTKExpirationTime for now */ 553*780fb4a2SCy Schubert WPA_PUT_LE32(pos, 0xffffffff); 554*780fb4a2SCy Schubert pos += 4; 555*780fb4a2SCy Schubert 556*780fb4a2SCy Schubert #ifdef CONFIG_IEEE80211W 557*780fb4a2SCy Schubert /* 558*780fb4a2SCy Schubert * IGTKdata[variable]: 559*780fb4a2SCy Schubert * Key ID[2], IPN[6], IGTK[variable] 560*780fb4a2SCy Schubert */ 561*780fb4a2SCy Schubert if (rsn->igtk_len) { 562*780fb4a2SCy Schubert WPA_PUT_LE16(pos, rsn->igtk_key_id); 563*780fb4a2SCy Schubert pos += 2; 564*780fb4a2SCy Schubert wpa_drv_get_seqnum(rsn->wpa_s, NULL, rsn->igtk_key_id, pos); 565*780fb4a2SCy Schubert pos += 6; 566*780fb4a2SCy Schubert os_memcpy(pos, rsn->igtk, rsn->igtk_len); 567*780fb4a2SCy Schubert } 568*780fb4a2SCy Schubert #endif /* CONFIG_IEEE80211W */ 569*780fb4a2SCy Schubert 570*780fb4a2SCy Schubert skip_keys: 571*780fb4a2SCy Schubert wpa_hexdump_key(MSG_DEBUG, "mesh: Plaintext AMPE element", 572*780fb4a2SCy Schubert ampe_ie, 2 + len); 5735b9c547cSRui Paulo 5745b9c547cSRui Paulo /* IE: MIC */ 575*780fb4a2SCy Schubert wpabuf_put_u8(buf, WLAN_EID_MIC); 576*780fb4a2SCy Schubert wpabuf_put_u8(buf, AES_BLOCK_SIZE); 5775b9c547cSRui Paulo /* MIC field is output ciphertext */ 5785b9c547cSRui Paulo 5795b9c547cSRui Paulo /* encrypt after MIC */ 580*780fb4a2SCy Schubert mic_payload = wpabuf_put(buf, 2 + len + AES_BLOCK_SIZE); 5815b9c547cSRui Paulo 582*780fb4a2SCy Schubert if (aes_siv_encrypt(sta->aek, ampe_ie, 2 + len, 3, 5835b9c547cSRui Paulo aad, aad_len, mic_payload)) { 5845b9c547cSRui Paulo wpa_printf(MSG_ERROR, "protect frame: failed to encrypt"); 5855b9c547cSRui Paulo ret = -ENOMEM; 5865b9c547cSRui Paulo } 5875b9c547cSRui Paulo 5885b9c547cSRui Paulo os_free(ampe_ie); 5895b9c547cSRui Paulo 5905b9c547cSRui Paulo return ret; 5915b9c547cSRui Paulo } 5925b9c547cSRui Paulo 5935b9c547cSRui Paulo 5945b9c547cSRui Paulo int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta, 5955b9c547cSRui Paulo struct ieee802_11_elems *elems, const u8 *cat, 596*780fb4a2SCy Schubert const u8 *chosen_pmk, 5975b9c547cSRui Paulo const u8 *start, size_t elems_len) 5985b9c547cSRui Paulo { 5995b9c547cSRui Paulo int ret = 0; 6005b9c547cSRui Paulo struct ieee80211_ampe_ie *ampe; 601*780fb4a2SCy Schubert u8 null_nonce[WPA_NONCE_LEN] = {}; 6025b9c547cSRui Paulo u8 ampe_eid; 6035b9c547cSRui Paulo u8 ampe_ie_len; 604*780fb4a2SCy Schubert u8 *ampe_buf, *crypt = NULL, *pos, *end; 6055b9c547cSRui Paulo size_t crypt_len; 6065b9c547cSRui Paulo const u8 *aad[] = { sta->addr, wpa_s->own_addr, cat }; 6075b9c547cSRui Paulo const size_t aad_len[] = { ETH_ALEN, ETH_ALEN, 6085b9c547cSRui Paulo (elems->mic - 2) - cat }; 609*780fb4a2SCy Schubert size_t key_len; 610*780fb4a2SCy Schubert 611*780fb4a2SCy Schubert if (!sta->sae) { 612*780fb4a2SCy Schubert struct hostapd_data *hapd = wpa_s->ifmsh->bss[0]; 613*780fb4a2SCy Schubert 614*780fb4a2SCy Schubert if (!wpa_auth_pmksa_get(hapd->wpa_auth, sta->addr)) { 615*780fb4a2SCy Schubert wpa_printf(MSG_INFO, 616*780fb4a2SCy Schubert "Mesh RSN: SAE is not prepared yet"); 617*780fb4a2SCy Schubert return -1; 618*780fb4a2SCy Schubert } 619*780fb4a2SCy Schubert mesh_rsn_auth_sae_sta(wpa_s, sta); 620*780fb4a2SCy Schubert } 621*780fb4a2SCy Schubert 622*780fb4a2SCy Schubert if (chosen_pmk && os_memcmp(chosen_pmk, sta->sae->pmkid, PMKID_LEN)) { 623*780fb4a2SCy Schubert wpa_msg(wpa_s, MSG_DEBUG, 624*780fb4a2SCy Schubert "Mesh RSN: Invalid PMKID (Chosen PMK did not match calculated PMKID)"); 625*780fb4a2SCy Schubert return -1; 626*780fb4a2SCy Schubert } 6275b9c547cSRui Paulo 6285b9c547cSRui Paulo if (!elems->mic || elems->mic_len < AES_BLOCK_SIZE) { 6295b9c547cSRui Paulo wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: missing mic ie"); 6305b9c547cSRui Paulo return -1; 6315b9c547cSRui Paulo } 6325b9c547cSRui Paulo 6335b9c547cSRui Paulo ampe_buf = (u8 *) elems->mic + elems->mic_len; 6345b9c547cSRui Paulo if ((int) elems_len < ampe_buf - start) 6355b9c547cSRui Paulo return -1; 6365b9c547cSRui Paulo 6375b9c547cSRui Paulo crypt_len = elems_len - (elems->mic - start); 638*780fb4a2SCy Schubert if (crypt_len < 2 + AES_BLOCK_SIZE) { 6395b9c547cSRui Paulo wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: missing ampe ie"); 6405b9c547cSRui Paulo return -1; 6415b9c547cSRui Paulo } 6425b9c547cSRui Paulo 6435b9c547cSRui Paulo /* crypt is modified by siv_decrypt */ 6445b9c547cSRui Paulo crypt = os_zalloc(crypt_len); 6455b9c547cSRui Paulo if (!crypt) { 6465b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Mesh RSN: out of memory"); 6475b9c547cSRui Paulo ret = -ENOMEM; 6485b9c547cSRui Paulo goto free; 6495b9c547cSRui Paulo } 6505b9c547cSRui Paulo 6515b9c547cSRui Paulo os_memcpy(crypt, elems->mic, crypt_len); 6525b9c547cSRui Paulo 6535b9c547cSRui Paulo if (aes_siv_decrypt(sta->aek, crypt, crypt_len, 3, 6545b9c547cSRui Paulo aad, aad_len, ampe_buf)) { 6555b9c547cSRui Paulo wpa_printf(MSG_ERROR, "Mesh RSN: frame verification failed!"); 656*780fb4a2SCy Schubert ret = -2; 6575b9c547cSRui Paulo goto free; 6585b9c547cSRui Paulo } 6595b9c547cSRui Paulo 660*780fb4a2SCy Schubert crypt_len -= AES_BLOCK_SIZE; 661*780fb4a2SCy Schubert wpa_hexdump_key(MSG_DEBUG, "mesh: Decrypted AMPE element", 662*780fb4a2SCy Schubert ampe_buf, crypt_len); 663*780fb4a2SCy Schubert 6645b9c547cSRui Paulo ampe_eid = *ampe_buf++; 6655b9c547cSRui Paulo ampe_ie_len = *ampe_buf++; 6665b9c547cSRui Paulo 6675b9c547cSRui Paulo if (ampe_eid != WLAN_EID_AMPE || 668*780fb4a2SCy Schubert (size_t) 2 + ampe_ie_len > crypt_len || 6695b9c547cSRui Paulo ampe_ie_len < sizeof(struct ieee80211_ampe_ie)) { 6705b9c547cSRui Paulo wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: invalid ampe ie"); 6715b9c547cSRui Paulo ret = -1; 6725b9c547cSRui Paulo goto free; 6735b9c547cSRui Paulo } 6745b9c547cSRui Paulo 6755b9c547cSRui Paulo ampe = (struct ieee80211_ampe_ie *) ampe_buf; 676*780fb4a2SCy Schubert pos = (u8 *) (ampe + 1); 677*780fb4a2SCy Schubert end = ampe_buf + ampe_ie_len; 678*780fb4a2SCy Schubert if (os_memcmp(ampe->peer_nonce, null_nonce, WPA_NONCE_LEN) != 0 && 679*780fb4a2SCy Schubert os_memcmp(ampe->peer_nonce, sta->my_nonce, WPA_NONCE_LEN) != 0) { 6805b9c547cSRui Paulo wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: invalid peer nonce"); 6815b9c547cSRui Paulo ret = -1; 6825b9c547cSRui Paulo goto free; 6835b9c547cSRui Paulo } 6845b9c547cSRui Paulo os_memcpy(sta->peer_nonce, ampe->local_nonce, 6855b9c547cSRui Paulo sizeof(ampe->local_nonce)); 6865b9c547cSRui Paulo 687*780fb4a2SCy Schubert /* TODO: Key Replay Counter[8] in Mesh Group Key Inform/Acknowledge 688*780fb4a2SCy Schubert * frames */ 689*780fb4a2SCy Schubert 690*780fb4a2SCy Schubert /* 691*780fb4a2SCy Schubert * GTKdata shall not be included in Mesh Peering Confirm. While the 692*780fb4a2SCy Schubert * standard does not state the same about IGTKdata, that same constraint 693*780fb4a2SCy Schubert * needs to apply for it. It makes no sense to include the keys in Mesh 694*780fb4a2SCy Schubert * Peering Close frames either, so while the standard does not seem to 695*780fb4a2SCy Schubert * have a shall statement for these, they are described without 696*780fb4a2SCy Schubert * mentioning GTKdata. 697*780fb4a2SCy Schubert * 698*780fb4a2SCy Schubert * An earlier implementation used to add GTKdata to both Mesh Peering 699*780fb4a2SCy Schubert * Open and Mesh Peering Confirm frames, so ignore the possibly present 700*780fb4a2SCy Schubert * GTKdata frame without rejecting the frame as a backwards 701*780fb4a2SCy Schubert * compatibility mechanism. 702*780fb4a2SCy Schubert */ 703*780fb4a2SCy Schubert if (cat[1] != PLINK_OPEN) { 704*780fb4a2SCy Schubert if (end > pos) { 705*780fb4a2SCy Schubert wpa_hexdump_key(MSG_DEBUG, 706*780fb4a2SCy Schubert "mesh: Ignore unexpected GTKdata(etc.) fields in the end of AMPE element in Mesh Peering Confirm/Close", 707*780fb4a2SCy Schubert pos, end - pos); 708*780fb4a2SCy Schubert } 709*780fb4a2SCy Schubert goto free; 710*780fb4a2SCy Schubert } 711*780fb4a2SCy Schubert 712*780fb4a2SCy Schubert /* 713*780fb4a2SCy Schubert * GTKdata[variable]: 714*780fb4a2SCy Schubert * MGTK[variable] || Key RSC[8] || GTKExpirationTime[4] 715*780fb4a2SCy Schubert */ 716*780fb4a2SCy Schubert sta->mgtk_key_id = 1; /* FIX: Where to get Key ID? */ 717*780fb4a2SCy Schubert key_len = wpa_cipher_key_len(wpa_s->mesh_rsn->group_cipher); 718*780fb4a2SCy Schubert if ((int) key_len + WPA_KEY_RSC_LEN + 4 > end - pos) { 719*780fb4a2SCy Schubert wpa_dbg(wpa_s, MSG_DEBUG, "mesh: Truncated AMPE element"); 720*780fb4a2SCy Schubert ret = -1; 721*780fb4a2SCy Schubert goto free; 722*780fb4a2SCy Schubert } 723*780fb4a2SCy Schubert sta->mgtk_len = key_len; 724*780fb4a2SCy Schubert os_memcpy(sta->mgtk, pos, sta->mgtk_len); 725*780fb4a2SCy Schubert wpa_hexdump_key(MSG_DEBUG, "mesh: GTKdata - MGTK", 726*780fb4a2SCy Schubert sta->mgtk, sta->mgtk_len); 727*780fb4a2SCy Schubert pos += sta->mgtk_len; 728*780fb4a2SCy Schubert wpa_hexdump(MSG_DEBUG, "mesh: GTKdata - MGTK - Key RSC", 729*780fb4a2SCy Schubert pos, WPA_KEY_RSC_LEN); 730*780fb4a2SCy Schubert os_memcpy(sta->mgtk_rsc, pos, sizeof(sta->mgtk_rsc)); 731*780fb4a2SCy Schubert pos += WPA_KEY_RSC_LEN; 732*780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, 733*780fb4a2SCy Schubert "mesh: GTKdata - MGTK - GTKExpirationTime: %u seconds", 734*780fb4a2SCy Schubert WPA_GET_LE32(pos)); 735*780fb4a2SCy Schubert pos += 4; 736*780fb4a2SCy Schubert 737*780fb4a2SCy Schubert #ifdef CONFIG_IEEE80211W 738*780fb4a2SCy Schubert /* 739*780fb4a2SCy Schubert * IGTKdata[variable]: 740*780fb4a2SCy Schubert * Key ID[2], IPN[6], IGTK[variable] 741*780fb4a2SCy Schubert */ 742*780fb4a2SCy Schubert key_len = wpa_cipher_key_len(wpa_s->mesh_rsn->mgmt_group_cipher); 743*780fb4a2SCy Schubert if (end - pos >= (int) (2 + 6 + key_len)) { 744*780fb4a2SCy Schubert sta->igtk_key_id = WPA_GET_LE16(pos); 745*780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, "mesh: IGTKdata - Key ID %u", 746*780fb4a2SCy Schubert sta->igtk_key_id); 747*780fb4a2SCy Schubert pos += 2; 748*780fb4a2SCy Schubert os_memcpy(sta->igtk_rsc, pos, sizeof(sta->igtk_rsc)); 749*780fb4a2SCy Schubert wpa_hexdump(MSG_DEBUG, "mesh: IGTKdata - IPN", 750*780fb4a2SCy Schubert sta->igtk_rsc, sizeof(sta->igtk_rsc)); 751*780fb4a2SCy Schubert pos += 6; 752*780fb4a2SCy Schubert os_memcpy(sta->igtk, pos, key_len); 753*780fb4a2SCy Schubert sta->igtk_len = key_len; 754*780fb4a2SCy Schubert wpa_hexdump_key(MSG_DEBUG, "mesh: IGTKdata - IGTK", 755*780fb4a2SCy Schubert sta->igtk, sta->igtk_len); 756*780fb4a2SCy Schubert } 757*780fb4a2SCy Schubert #endif /* CONFIG_IEEE80211W */ 758*780fb4a2SCy Schubert 7595b9c547cSRui Paulo free: 7605b9c547cSRui Paulo os_free(crypt); 7615b9c547cSRui Paulo return ret; 7625b9c547cSRui Paulo } 763