1189251Ssam/* 2189251Ssam * WPA Supplicant - PeerKey for Direct Link Setup (DLS) 3189251Ssam * Copyright (c) 2006-2008, Jouni Malinen <j@w1.fi> 4189251Ssam * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7189251Ssam */ 8189251Ssam 9189251Ssam#include "includes.h" 10189251Ssam 11189251Ssam#ifdef CONFIG_PEERKEY 12189251Ssam 13189251Ssam#include "common.h" 14189251Ssam#include "eloop.h" 15214734Srpaulo#include "crypto/sha1.h" 16214734Srpaulo#include "crypto/sha256.h" 17252726Srpaulo#include "crypto/random.h" 18214734Srpaulo#include "common/ieee802_11_defs.h" 19189251Ssam#include "wpa.h" 20189251Ssam#include "wpa_i.h" 21189251Ssam#include "wpa_ie.h" 22189251Ssam#include "peerkey.h" 23189251Ssam 24189251Ssam 25189251Ssamstatic u8 * wpa_add_ie(u8 *pos, const u8 *ie, size_t ie_len) 26189251Ssam{ 27189251Ssam os_memcpy(pos, ie, ie_len); 28189251Ssam return pos + ie_len; 29189251Ssam} 30189251Ssam 31189251Ssam 32189251Ssamstatic u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len) 33189251Ssam{ 34189251Ssam *pos++ = WLAN_EID_VENDOR_SPECIFIC; 35189251Ssam *pos++ = RSN_SELECTOR_LEN + data_len; 36189251Ssam RSN_SELECTOR_PUT(pos, kde); 37189251Ssam pos += RSN_SELECTOR_LEN; 38189251Ssam os_memcpy(pos, data, data_len); 39189251Ssam pos += data_len; 40189251Ssam return pos; 41189251Ssam} 42189251Ssam 43189251Ssam 44189251Ssamstatic void wpa_supplicant_smk_timeout(void *eloop_ctx, void *timeout_ctx) 45189251Ssam{ 46189251Ssam#if 0 47189251Ssam struct wpa_sm *sm = eloop_ctx; 48189251Ssam struct wpa_peerkey *peerkey = timeout_ctx; 49189251Ssam#endif 50189251Ssam /* TODO: time out SMK and any STK that was generated using this SMK */ 51189251Ssam} 52189251Ssam 53189251Ssam 54189251Ssamstatic void wpa_supplicant_peerkey_free(struct wpa_sm *sm, 55189251Ssam struct wpa_peerkey *peerkey) 56189251Ssam{ 57189251Ssam eloop_cancel_timeout(wpa_supplicant_smk_timeout, sm, peerkey); 58189251Ssam os_free(peerkey); 59189251Ssam} 60189251Ssam 61189251Ssam 62189251Ssamstatic int wpa_supplicant_send_smk_error(struct wpa_sm *sm, const u8 *dst, 63189251Ssam const u8 *peer, 64189251Ssam u16 mui, u16 error_type, int ver) 65189251Ssam{ 66189251Ssam size_t rlen; 67189251Ssam struct wpa_eapol_key *err; 68189251Ssam struct rsn_error_kde error; 69189251Ssam u8 *rbuf, *pos; 70189251Ssam size_t kde_len; 71189251Ssam u16 key_info; 72189251Ssam 73189251Ssam kde_len = 2 + RSN_SELECTOR_LEN + sizeof(error); 74189251Ssam if (peer) 75189251Ssam kde_len += 2 + RSN_SELECTOR_LEN + ETH_ALEN; 76189251Ssam 77189251Ssam rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, 78189251Ssam NULL, sizeof(*err) + kde_len, &rlen, 79189251Ssam (void *) &err); 80189251Ssam if (rbuf == NULL) 81189251Ssam return -1; 82189251Ssam 83189251Ssam err->type = EAPOL_KEY_TYPE_RSN; 84189251Ssam key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC | 85189251Ssam WPA_KEY_INFO_SECURE | WPA_KEY_INFO_ERROR | 86189251Ssam WPA_KEY_INFO_REQUEST; 87189251Ssam WPA_PUT_BE16(err->key_info, key_info); 88189251Ssam WPA_PUT_BE16(err->key_length, 0); 89189251Ssam os_memcpy(err->replay_counter, sm->request_counter, 90189251Ssam WPA_REPLAY_COUNTER_LEN); 91189251Ssam inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN); 92189251Ssam 93189251Ssam WPA_PUT_BE16(err->key_data_length, (u16) kde_len); 94189251Ssam pos = (u8 *) (err + 1); 95189251Ssam 96189251Ssam if (peer) { 97189251Ssam /* Peer MAC Address KDE */ 98189251Ssam pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN); 99189251Ssam } 100189251Ssam 101189251Ssam /* Error KDE */ 102189251Ssam error.mui = host_to_be16(mui); 103189251Ssam error.error_type = host_to_be16(error_type); 104189251Ssam wpa_add_kde(pos, RSN_KEY_DATA_ERROR, (u8 *) &error, sizeof(error)); 105189251Ssam 106189251Ssam if (peer) { 107189251Ssam wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK Error (peer " 108189251Ssam MACSTR " mui %d error_type %d)", 109189251Ssam MAC2STR(peer), mui, error_type); 110189251Ssam } else { 111189251Ssam wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK Error " 112189251Ssam "(mui %d error_type %d)", mui, error_type); 113189251Ssam } 114189251Ssam 115189251Ssam wpa_eapol_key_send(sm, sm->ptk.kck, ver, dst, ETH_P_EAPOL, 116189251Ssam rbuf, rlen, err->key_mic); 117189251Ssam 118189251Ssam return 0; 119189251Ssam} 120189251Ssam 121189251Ssam 122189251Ssamstatic int wpa_supplicant_send_smk_m3(struct wpa_sm *sm, 123189251Ssam const unsigned char *src_addr, 124189251Ssam const struct wpa_eapol_key *key, 125189251Ssam int ver, struct wpa_peerkey *peerkey) 126189251Ssam{ 127189251Ssam size_t rlen; 128189251Ssam struct wpa_eapol_key *reply; 129189251Ssam u8 *rbuf, *pos; 130189251Ssam size_t kde_len; 131189251Ssam u16 key_info; 132189251Ssam 133189251Ssam /* KDEs: Peer RSN IE, Initiator MAC Address, Initiator Nonce */ 134189251Ssam kde_len = peerkey->rsnie_p_len + 135189251Ssam 2 + RSN_SELECTOR_LEN + ETH_ALEN + 136189251Ssam 2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN; 137189251Ssam 138189251Ssam rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, 139189251Ssam NULL, sizeof(*reply) + kde_len, &rlen, 140189251Ssam (void *) &reply); 141189251Ssam if (rbuf == NULL) 142189251Ssam return -1; 143189251Ssam 144189251Ssam reply->type = EAPOL_KEY_TYPE_RSN; 145189251Ssam key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC | 146189251Ssam WPA_KEY_INFO_SECURE; 147189251Ssam WPA_PUT_BE16(reply->key_info, key_info); 148189251Ssam WPA_PUT_BE16(reply->key_length, 0); 149189251Ssam os_memcpy(reply->replay_counter, key->replay_counter, 150189251Ssam WPA_REPLAY_COUNTER_LEN); 151189251Ssam 152189251Ssam os_memcpy(reply->key_nonce, peerkey->pnonce, WPA_NONCE_LEN); 153189251Ssam 154189251Ssam WPA_PUT_BE16(reply->key_data_length, (u16) kde_len); 155189251Ssam pos = (u8 *) (reply + 1); 156189251Ssam 157189251Ssam /* Peer RSN IE */ 158189251Ssam pos = wpa_add_ie(pos, peerkey->rsnie_p, peerkey->rsnie_p_len); 159189251Ssam 160189251Ssam /* Initiator MAC Address KDE */ 161189251Ssam pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peerkey->addr, ETH_ALEN); 162189251Ssam 163189251Ssam /* Initiator Nonce */ 164189251Ssam wpa_add_kde(pos, RSN_KEY_DATA_NONCE, peerkey->inonce, WPA_NONCE_LEN); 165189251Ssam 166189251Ssam wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK M3"); 167189251Ssam wpa_eapol_key_send(sm, sm->ptk.kck, ver, src_addr, ETH_P_EAPOL, 168189251Ssam rbuf, rlen, reply->key_mic); 169189251Ssam 170189251Ssam return 0; 171189251Ssam} 172189251Ssam 173189251Ssam 174189251Ssamstatic int wpa_supplicant_process_smk_m2( 175189251Ssam struct wpa_sm *sm, const unsigned char *src_addr, 176189251Ssam const struct wpa_eapol_key *key, size_t extra_len, int ver) 177189251Ssam{ 178189251Ssam struct wpa_peerkey *peerkey; 179189251Ssam struct wpa_eapol_ie_parse kde; 180189251Ssam struct wpa_ie_data ie; 181189251Ssam int cipher; 182189251Ssam struct rsn_ie_hdr *hdr; 183189251Ssam u8 *pos; 184189251Ssam 185189251Ssam wpa_printf(MSG_DEBUG, "RSN: Received SMK M2"); 186189251Ssam 187189251Ssam if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) { 188189251Ssam wpa_printf(MSG_INFO, "RSN: SMK handshake not allowed for " 189189251Ssam "the current network"); 190189251Ssam return -1; 191189251Ssam } 192189251Ssam 193189251Ssam if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) < 194189251Ssam 0) { 195189251Ssam wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M2"); 196189251Ssam return -1; 197189251Ssam } 198189251Ssam 199189251Ssam if (kde.rsn_ie == NULL || kde.mac_addr == NULL || 200189251Ssam kde.mac_addr_len < ETH_ALEN) { 201189251Ssam wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in " 202189251Ssam "SMK M2"); 203189251Ssam return -1; 204189251Ssam } 205189251Ssam 206189251Ssam wpa_printf(MSG_DEBUG, "RSN: SMK M2 - SMK initiator " MACSTR, 207189251Ssam MAC2STR(kde.mac_addr)); 208189251Ssam 209189251Ssam if (kde.rsn_ie_len > PEERKEY_MAX_IE_LEN) { 210189251Ssam wpa_printf(MSG_INFO, "RSN: Too long Initiator RSN IE in SMK " 211189251Ssam "M2"); 212189251Ssam return -1; 213189251Ssam } 214189251Ssam 215189251Ssam if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) { 216189251Ssam wpa_printf(MSG_INFO, "RSN: Failed to parse RSN IE in SMK M2"); 217189251Ssam return -1; 218189251Ssam } 219189251Ssam 220189251Ssam cipher = ie.pairwise_cipher & sm->allowed_pairwise_cipher; 221189251Ssam if (cipher & WPA_CIPHER_CCMP) { 222189251Ssam wpa_printf(MSG_DEBUG, "RSN: Using CCMP for PeerKey"); 223189251Ssam cipher = WPA_CIPHER_CCMP; 224252726Srpaulo } else if (cipher & WPA_CIPHER_GCMP) { 225252726Srpaulo wpa_printf(MSG_DEBUG, "RSN: Using GCMP for PeerKey"); 226252726Srpaulo cipher = WPA_CIPHER_GCMP; 227189251Ssam } else if (cipher & WPA_CIPHER_TKIP) { 228189251Ssam wpa_printf(MSG_DEBUG, "RSN: Using TKIP for PeerKey"); 229189251Ssam cipher = WPA_CIPHER_TKIP; 230189251Ssam } else { 231189251Ssam wpa_printf(MSG_INFO, "RSN: No acceptable cipher in SMK M2"); 232189251Ssam wpa_supplicant_send_smk_error(sm, src_addr, kde.mac_addr, 233189251Ssam STK_MUI_SMK, STK_ERR_CPHR_NS, 234189251Ssam ver); 235189251Ssam return -1; 236189251Ssam } 237189251Ssam 238189251Ssam /* TODO: find existing entry and if found, use that instead of adding 239189251Ssam * a new one; how to handle the case where both ends initiate at the 240189251Ssam * same time? */ 241189251Ssam peerkey = os_zalloc(sizeof(*peerkey)); 242189251Ssam if (peerkey == NULL) 243189251Ssam return -1; 244189251Ssam os_memcpy(peerkey->addr, kde.mac_addr, ETH_ALEN); 245189251Ssam os_memcpy(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN); 246189251Ssam os_memcpy(peerkey->rsnie_i, kde.rsn_ie, kde.rsn_ie_len); 247189251Ssam peerkey->rsnie_i_len = kde.rsn_ie_len; 248189251Ssam peerkey->cipher = cipher; 249189251Ssam#ifdef CONFIG_IEEE80211W 250189251Ssam if (ie.key_mgmt & (WPA_KEY_MGMT_IEEE8021X_SHA256 | 251189251Ssam WPA_KEY_MGMT_PSK_SHA256)) 252189251Ssam peerkey->use_sha256 = 1; 253189251Ssam#endif /* CONFIG_IEEE80211W */ 254189251Ssam 255252726Srpaulo if (random_get_bytes(peerkey->pnonce, WPA_NONCE_LEN)) { 256214734Srpaulo wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, 257189251Ssam "WPA: Failed to get random data for PNonce"); 258189251Ssam wpa_supplicant_peerkey_free(sm, peerkey); 259189251Ssam return -1; 260189251Ssam } 261189251Ssam 262189251Ssam hdr = (struct rsn_ie_hdr *) peerkey->rsnie_p; 263189251Ssam hdr->elem_id = WLAN_EID_RSN; 264189251Ssam WPA_PUT_LE16(hdr->version, RSN_VERSION); 265189251Ssam pos = (u8 *) (hdr + 1); 266189251Ssam /* Group Suite can be anything for SMK RSN IE; receiver will just 267189251Ssam * ignore it. */ 268189251Ssam RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); 269189251Ssam pos += RSN_SELECTOR_LEN; 270189251Ssam /* Include only the selected cipher in pairwise cipher suite */ 271189251Ssam WPA_PUT_LE16(pos, 1); 272189251Ssam pos += 2; 273252726Srpaulo RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN, cipher)); 274189251Ssam pos += RSN_SELECTOR_LEN; 275189251Ssam 276189251Ssam hdr->len = (pos - peerkey->rsnie_p) - 2; 277189251Ssam peerkey->rsnie_p_len = pos - peerkey->rsnie_p; 278189251Ssam wpa_hexdump(MSG_DEBUG, "WPA: RSN IE for SMK handshake", 279189251Ssam peerkey->rsnie_p, peerkey->rsnie_p_len); 280189251Ssam 281189251Ssam wpa_supplicant_send_smk_m3(sm, src_addr, key, ver, peerkey); 282189251Ssam 283189251Ssam peerkey->next = sm->peerkey; 284189251Ssam sm->peerkey = peerkey; 285189251Ssam 286189251Ssam return 0; 287189251Ssam} 288189251Ssam 289189251Ssam 290189251Ssam/** 291189251Ssam * rsn_smkid - Derive SMK identifier 292189251Ssam * @smk: Station master key (32 bytes) 293189251Ssam * @pnonce: Peer Nonce 294189251Ssam * @mac_p: Peer MAC address 295189251Ssam * @inonce: Initiator Nonce 296189251Ssam * @mac_i: Initiator MAC address 297189251Ssam * @use_sha256: Whether to use SHA256-based KDF 298189251Ssam * 299189251Ssam * 8.5.1.4 Station to station (STK) key hierarchy 300189251Ssam * SMKID = HMAC-SHA1-128(SMK, "SMK Name" || PNonce || MAC_P || INonce || MAC_I) 301189251Ssam */ 302189251Ssamstatic void rsn_smkid(const u8 *smk, const u8 *pnonce, const u8 *mac_p, 303189251Ssam const u8 *inonce, const u8 *mac_i, u8 *smkid, 304189251Ssam int use_sha256) 305189251Ssam{ 306189251Ssam char *title = "SMK Name"; 307189251Ssam const u8 *addr[5]; 308189251Ssam const size_t len[5] = { 8, WPA_NONCE_LEN, ETH_ALEN, WPA_NONCE_LEN, 309189251Ssam ETH_ALEN }; 310189251Ssam unsigned char hash[SHA256_MAC_LEN]; 311189251Ssam 312189251Ssam addr[0] = (u8 *) title; 313189251Ssam addr[1] = pnonce; 314189251Ssam addr[2] = mac_p; 315189251Ssam addr[3] = inonce; 316189251Ssam addr[4] = mac_i; 317189251Ssam 318189251Ssam#ifdef CONFIG_IEEE80211W 319189251Ssam if (use_sha256) 320189251Ssam hmac_sha256_vector(smk, PMK_LEN, 5, addr, len, hash); 321189251Ssam else 322189251Ssam#endif /* CONFIG_IEEE80211W */ 323189251Ssam hmac_sha1_vector(smk, PMK_LEN, 5, addr, len, hash); 324189251Ssam os_memcpy(smkid, hash, PMKID_LEN); 325189251Ssam} 326189251Ssam 327189251Ssam 328189251Ssamstatic void wpa_supplicant_send_stk_1_of_4(struct wpa_sm *sm, 329189251Ssam struct wpa_peerkey *peerkey) 330189251Ssam{ 331189251Ssam size_t mlen; 332189251Ssam struct wpa_eapol_key *msg; 333189251Ssam u8 *mbuf; 334189251Ssam size_t kde_len; 335189251Ssam u16 key_info, ver; 336189251Ssam 337189251Ssam kde_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN; 338189251Ssam 339189251Ssam mbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, 340189251Ssam sizeof(*msg) + kde_len, &mlen, 341189251Ssam (void *) &msg); 342189251Ssam if (mbuf == NULL) 343189251Ssam return; 344189251Ssam 345189251Ssam msg->type = EAPOL_KEY_TYPE_RSN; 346189251Ssam 347252726Srpaulo if (peerkey->cipher != WPA_CIPHER_TKIP) 348189251Ssam ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES; 349189251Ssam else 350189251Ssam ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4; 351189251Ssam 352189251Ssam key_info = ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_ACK; 353189251Ssam WPA_PUT_BE16(msg->key_info, key_info); 354189251Ssam 355252726Srpaulo if (peerkey->cipher != WPA_CIPHER_TKIP) 356189251Ssam WPA_PUT_BE16(msg->key_length, 16); 357189251Ssam else 358189251Ssam WPA_PUT_BE16(msg->key_length, 32); 359189251Ssam 360189251Ssam os_memcpy(msg->replay_counter, peerkey->replay_counter, 361189251Ssam WPA_REPLAY_COUNTER_LEN); 362189251Ssam inc_byte_array(peerkey->replay_counter, WPA_REPLAY_COUNTER_LEN); 363189251Ssam 364189251Ssam WPA_PUT_BE16(msg->key_data_length, kde_len); 365189251Ssam wpa_add_kde((u8 *) (msg + 1), RSN_KEY_DATA_PMKID, 366189251Ssam peerkey->smkid, PMKID_LEN); 367189251Ssam 368252726Srpaulo if (random_get_bytes(peerkey->inonce, WPA_NONCE_LEN)) { 369214734Srpaulo wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, 370189251Ssam "RSN: Failed to get random data for INonce (STK)"); 371189251Ssam os_free(mbuf); 372189251Ssam return; 373189251Ssam } 374189251Ssam wpa_hexdump(MSG_DEBUG, "RSN: INonce for STK 4-Way Handshake", 375189251Ssam peerkey->inonce, WPA_NONCE_LEN); 376189251Ssam os_memcpy(msg->key_nonce, peerkey->inonce, WPA_NONCE_LEN); 377189251Ssam 378189251Ssam wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 1/4 to " MACSTR, 379189251Ssam MAC2STR(peerkey->addr)); 380189251Ssam wpa_eapol_key_send(sm, NULL, ver, peerkey->addr, ETH_P_EAPOL, 381189251Ssam mbuf, mlen, NULL); 382189251Ssam} 383189251Ssam 384189251Ssam 385189251Ssamstatic void wpa_supplicant_send_stk_3_of_4(struct wpa_sm *sm, 386189251Ssam struct wpa_peerkey *peerkey) 387189251Ssam{ 388189251Ssam size_t mlen; 389189251Ssam struct wpa_eapol_key *msg; 390189251Ssam u8 *mbuf, *pos; 391189251Ssam size_t kde_len; 392189251Ssam u16 key_info, ver; 393189251Ssam be32 lifetime; 394189251Ssam 395189251Ssam kde_len = peerkey->rsnie_i_len + 396189251Ssam 2 + RSN_SELECTOR_LEN + sizeof(lifetime); 397189251Ssam 398189251Ssam mbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, 399189251Ssam sizeof(*msg) + kde_len, &mlen, 400189251Ssam (void *) &msg); 401189251Ssam if (mbuf == NULL) 402189251Ssam return; 403189251Ssam 404189251Ssam msg->type = EAPOL_KEY_TYPE_RSN; 405189251Ssam 406252726Srpaulo if (peerkey->cipher != WPA_CIPHER_TKIP) 407189251Ssam ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES; 408189251Ssam else 409189251Ssam ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4; 410189251Ssam 411189251Ssam key_info = ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_ACK | 412189251Ssam WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE; 413189251Ssam WPA_PUT_BE16(msg->key_info, key_info); 414189251Ssam 415252726Srpaulo if (peerkey->cipher != WPA_CIPHER_TKIP) 416189251Ssam WPA_PUT_BE16(msg->key_length, 16); 417189251Ssam else 418189251Ssam WPA_PUT_BE16(msg->key_length, 32); 419189251Ssam 420189251Ssam os_memcpy(msg->replay_counter, peerkey->replay_counter, 421189251Ssam WPA_REPLAY_COUNTER_LEN); 422189251Ssam inc_byte_array(peerkey->replay_counter, WPA_REPLAY_COUNTER_LEN); 423189251Ssam 424189251Ssam WPA_PUT_BE16(msg->key_data_length, kde_len); 425189251Ssam pos = (u8 *) (msg + 1); 426189251Ssam pos = wpa_add_ie(pos, peerkey->rsnie_i, peerkey->rsnie_i_len); 427189251Ssam lifetime = host_to_be32(peerkey->lifetime); 428189251Ssam wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME, 429189251Ssam (u8 *) &lifetime, sizeof(lifetime)); 430189251Ssam 431189251Ssam os_memcpy(msg->key_nonce, peerkey->inonce, WPA_NONCE_LEN); 432189251Ssam 433189251Ssam wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 3/4 to " MACSTR, 434189251Ssam MAC2STR(peerkey->addr)); 435189251Ssam wpa_eapol_key_send(sm, peerkey->stk.kck, ver, peerkey->addr, 436189251Ssam ETH_P_EAPOL, mbuf, mlen, msg->key_mic); 437189251Ssam} 438189251Ssam 439189251Ssam 440189251Ssamstatic int wpa_supplicant_process_smk_m4(struct wpa_peerkey *peerkey, 441189251Ssam struct wpa_eapol_ie_parse *kde) 442189251Ssam{ 443189251Ssam wpa_printf(MSG_DEBUG, "RSN: Received SMK M4 (Initiator " MACSTR ")", 444189251Ssam MAC2STR(kde->mac_addr)); 445189251Ssam 446189251Ssam if (os_memcmp(kde->smk + PMK_LEN, peerkey->pnonce, WPA_NONCE_LEN) != 0) 447189251Ssam { 448189251Ssam wpa_printf(MSG_INFO, "RSN: PNonce in SMK KDE does not " 449189251Ssam "match with the one used in SMK M3"); 450189251Ssam return -1; 451189251Ssam } 452189251Ssam 453189251Ssam if (os_memcmp(kde->nonce, peerkey->inonce, WPA_NONCE_LEN) != 0) { 454189251Ssam wpa_printf(MSG_INFO, "RSN: INonce in SMK M4 did not " 455189251Ssam "match with the one received in SMK M2"); 456189251Ssam return -1; 457189251Ssam } 458189251Ssam 459189251Ssam return 0; 460189251Ssam} 461189251Ssam 462189251Ssam 463189251Ssamstatic int wpa_supplicant_process_smk_m5(struct wpa_sm *sm, 464189251Ssam const unsigned char *src_addr, 465189251Ssam const struct wpa_eapol_key *key, 466189251Ssam int ver, 467189251Ssam struct wpa_peerkey *peerkey, 468189251Ssam struct wpa_eapol_ie_parse *kde) 469189251Ssam{ 470189251Ssam int cipher; 471189251Ssam struct wpa_ie_data ie; 472189251Ssam 473189251Ssam wpa_printf(MSG_DEBUG, "RSN: Received SMK M5 (Peer " MACSTR ")", 474189251Ssam MAC2STR(kde->mac_addr)); 475189251Ssam if (kde->rsn_ie == NULL || kde->rsn_ie_len > PEERKEY_MAX_IE_LEN || 476189251Ssam wpa_parse_wpa_ie_rsn(kde->rsn_ie, kde->rsn_ie_len, &ie) < 0) { 477189251Ssam wpa_printf(MSG_INFO, "RSN: No RSN IE in SMK M5"); 478189251Ssam /* TODO: abort negotiation */ 479189251Ssam return -1; 480189251Ssam } 481189251Ssam 482189251Ssam if (os_memcmp(key->key_nonce, peerkey->inonce, WPA_NONCE_LEN) != 0) { 483189251Ssam wpa_printf(MSG_INFO, "RSN: Key Nonce in SMK M5 does " 484189251Ssam "not match with INonce used in SMK M1"); 485189251Ssam return -1; 486189251Ssam } 487189251Ssam 488189251Ssam if (os_memcmp(kde->smk + PMK_LEN, peerkey->inonce, WPA_NONCE_LEN) != 0) 489189251Ssam { 490189251Ssam wpa_printf(MSG_INFO, "RSN: INonce in SMK KDE does not " 491189251Ssam "match with the one used in SMK M1"); 492189251Ssam return -1; 493189251Ssam } 494189251Ssam 495189251Ssam os_memcpy(peerkey->rsnie_p, kde->rsn_ie, kde->rsn_ie_len); 496189251Ssam peerkey->rsnie_p_len = kde->rsn_ie_len; 497189251Ssam os_memcpy(peerkey->pnonce, kde->nonce, WPA_NONCE_LEN); 498189251Ssam 499189251Ssam cipher = ie.pairwise_cipher & sm->allowed_pairwise_cipher; 500189251Ssam if (cipher & WPA_CIPHER_CCMP) { 501189251Ssam wpa_printf(MSG_DEBUG, "RSN: Using CCMP for PeerKey"); 502189251Ssam peerkey->cipher = WPA_CIPHER_CCMP; 503252726Srpaulo } else if (cipher & WPA_CIPHER_GCMP) { 504252726Srpaulo wpa_printf(MSG_DEBUG, "RSN: Using GCMP for PeerKey"); 505252726Srpaulo peerkey->cipher = WPA_CIPHER_GCMP; 506189251Ssam } else if (cipher & WPA_CIPHER_TKIP) { 507189251Ssam wpa_printf(MSG_DEBUG, "RSN: Using TKIP for PeerKey"); 508189251Ssam peerkey->cipher = WPA_CIPHER_TKIP; 509189251Ssam } else { 510189251Ssam wpa_printf(MSG_INFO, "RSN: SMK Peer STA " MACSTR " selected " 511189251Ssam "unacceptable cipher", MAC2STR(kde->mac_addr)); 512189251Ssam wpa_supplicant_send_smk_error(sm, src_addr, kde->mac_addr, 513189251Ssam STK_MUI_SMK, STK_ERR_CPHR_NS, 514189251Ssam ver); 515189251Ssam /* TODO: abort negotiation */ 516189251Ssam return -1; 517189251Ssam } 518189251Ssam 519189251Ssam return 0; 520189251Ssam} 521189251Ssam 522189251Ssam 523189251Ssamstatic int wpa_supplicant_process_smk_m45( 524189251Ssam struct wpa_sm *sm, const unsigned char *src_addr, 525189251Ssam const struct wpa_eapol_key *key, size_t extra_len, int ver) 526189251Ssam{ 527189251Ssam struct wpa_peerkey *peerkey; 528189251Ssam struct wpa_eapol_ie_parse kde; 529189251Ssam u32 lifetime; 530189251Ssam struct os_time now; 531189251Ssam 532189251Ssam if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) { 533189251Ssam wpa_printf(MSG_DEBUG, "RSN: SMK handshake not allowed for " 534189251Ssam "the current network"); 535189251Ssam return -1; 536189251Ssam } 537189251Ssam 538189251Ssam if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) < 539189251Ssam 0) { 540189251Ssam wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M4/M5"); 541189251Ssam return -1; 542189251Ssam } 543189251Ssam 544189251Ssam if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN || 545189251Ssam kde.nonce == NULL || kde.nonce_len < WPA_NONCE_LEN || 546189251Ssam kde.smk == NULL || kde.smk_len < PMK_LEN + WPA_NONCE_LEN || 547189251Ssam kde.lifetime == NULL || kde.lifetime_len < 4) { 548189251Ssam wpa_printf(MSG_INFO, "RSN: No MAC Address, Nonce, SMK, or " 549189251Ssam "Lifetime KDE in SMK M4/M5"); 550189251Ssam return -1; 551189251Ssam } 552189251Ssam 553189251Ssam for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) { 554189251Ssam if (os_memcmp(peerkey->addr, kde.mac_addr, ETH_ALEN) == 0 && 555189251Ssam os_memcmp(peerkey->initiator ? peerkey->inonce : 556189251Ssam peerkey->pnonce, 557189251Ssam key->key_nonce, WPA_NONCE_LEN) == 0) 558189251Ssam break; 559189251Ssam } 560189251Ssam if (peerkey == NULL) { 561189251Ssam wpa_printf(MSG_INFO, "RSN: No matching SMK handshake found " 562189251Ssam "for SMK M4/M5: peer " MACSTR, 563189251Ssam MAC2STR(kde.mac_addr)); 564189251Ssam return -1; 565189251Ssam } 566189251Ssam 567189251Ssam if (peerkey->initiator) { 568189251Ssam if (wpa_supplicant_process_smk_m5(sm, src_addr, key, ver, 569189251Ssam peerkey, &kde) < 0) 570189251Ssam return -1; 571189251Ssam } else { 572189251Ssam if (wpa_supplicant_process_smk_m4(peerkey, &kde) < 0) 573189251Ssam return -1; 574189251Ssam } 575189251Ssam 576189251Ssam os_memcpy(peerkey->smk, kde.smk, PMK_LEN); 577189251Ssam peerkey->smk_complete = 1; 578189251Ssam wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", peerkey->smk, PMK_LEN); 579189251Ssam lifetime = WPA_GET_BE32(kde.lifetime); 580189251Ssam wpa_printf(MSG_DEBUG, "RSN: SMK lifetime %u seconds", lifetime); 581189251Ssam if (lifetime > 1000000000) 582189251Ssam lifetime = 1000000000; /* avoid overflowing expiration time */ 583189251Ssam peerkey->lifetime = lifetime; 584189251Ssam os_get_time(&now); 585189251Ssam peerkey->expiration = now.sec + lifetime; 586189251Ssam eloop_register_timeout(lifetime, 0, wpa_supplicant_smk_timeout, 587189251Ssam sm, peerkey); 588189251Ssam 589189251Ssam if (peerkey->initiator) { 590189251Ssam rsn_smkid(peerkey->smk, peerkey->pnonce, peerkey->addr, 591189251Ssam peerkey->inonce, sm->own_addr, peerkey->smkid, 592189251Ssam peerkey->use_sha256); 593189251Ssam wpa_supplicant_send_stk_1_of_4(sm, peerkey); 594189251Ssam } else { 595189251Ssam rsn_smkid(peerkey->smk, peerkey->pnonce, sm->own_addr, 596189251Ssam peerkey->inonce, peerkey->addr, peerkey->smkid, 597189251Ssam peerkey->use_sha256); 598189251Ssam } 599189251Ssam wpa_hexdump(MSG_DEBUG, "RSN: SMKID", peerkey->smkid, PMKID_LEN); 600189251Ssam 601189251Ssam return 0; 602189251Ssam} 603189251Ssam 604189251Ssam 605189251Ssamstatic int wpa_supplicant_process_smk_error( 606189251Ssam struct wpa_sm *sm, const unsigned char *src_addr, 607189251Ssam const struct wpa_eapol_key *key, size_t extra_len) 608189251Ssam{ 609189251Ssam struct wpa_eapol_ie_parse kde; 610189251Ssam struct rsn_error_kde error; 611189251Ssam u8 peer[ETH_ALEN]; 612189251Ssam u16 error_type; 613189251Ssam 614189251Ssam wpa_printf(MSG_DEBUG, "RSN: Received SMK Error"); 615189251Ssam 616189251Ssam if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) { 617189251Ssam wpa_printf(MSG_DEBUG, "RSN: SMK handshake not allowed for " 618189251Ssam "the current network"); 619189251Ssam return -1; 620189251Ssam } 621189251Ssam 622189251Ssam if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) < 623189251Ssam 0) { 624189251Ssam wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error"); 625189251Ssam return -1; 626189251Ssam } 627189251Ssam 628189251Ssam if (kde.error == NULL || kde.error_len < sizeof(error)) { 629189251Ssam wpa_printf(MSG_INFO, "RSN: No Error KDE in SMK Error"); 630189251Ssam return -1; 631189251Ssam } 632189251Ssam 633189251Ssam if (kde.mac_addr && kde.mac_addr_len >= ETH_ALEN) 634189251Ssam os_memcpy(peer, kde.mac_addr, ETH_ALEN); 635214734Srpaulo else 636214734Srpaulo os_memset(peer, 0, ETH_ALEN); 637189251Ssam os_memcpy(&error, kde.error, sizeof(error)); 638189251Ssam error_type = be_to_host16(error.error_type); 639214734Srpaulo wpa_msg(sm->ctx->msg_ctx, MSG_INFO, 640189251Ssam "RSN: SMK Error KDE received: MUI %d error_type %d peer " 641189251Ssam MACSTR, 642189251Ssam be_to_host16(error.mui), error_type, 643189251Ssam MAC2STR(peer)); 644189251Ssam 645189251Ssam if (kde.mac_addr && 646189251Ssam (error_type == STK_ERR_STA_NR || error_type == STK_ERR_STA_NRSN || 647189251Ssam error_type == STK_ERR_CPHR_NS)) { 648189251Ssam struct wpa_peerkey *peerkey; 649189251Ssam 650189251Ssam for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) { 651189251Ssam if (os_memcmp(peerkey->addr, kde.mac_addr, ETH_ALEN) == 652189251Ssam 0) 653189251Ssam break; 654189251Ssam } 655189251Ssam if (peerkey == NULL) { 656189251Ssam wpa_printf(MSG_DEBUG, "RSN: No matching SMK handshake " 657189251Ssam "found for SMK Error"); 658189251Ssam return -1; 659189251Ssam } 660189251Ssam /* TODO: abort SMK/STK handshake and remove all related keys */ 661189251Ssam } 662189251Ssam 663189251Ssam return 0; 664189251Ssam} 665189251Ssam 666189251Ssam 667189251Ssamstatic void wpa_supplicant_process_stk_1_of_4(struct wpa_sm *sm, 668189251Ssam struct wpa_peerkey *peerkey, 669189251Ssam const struct wpa_eapol_key *key, 670189251Ssam u16 ver) 671189251Ssam{ 672189251Ssam struct wpa_eapol_ie_parse ie; 673189251Ssam const u8 *kde; 674189251Ssam size_t len, kde_buf_len; 675189251Ssam struct wpa_ptk *stk; 676189251Ssam u8 buf[8], *kde_buf, *pos; 677189251Ssam be32 lifetime; 678189251Ssam 679189251Ssam wpa_printf(MSG_DEBUG, "RSN: RX message 1 of STK 4-Way Handshake from " 680189251Ssam MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver); 681189251Ssam 682189251Ssam os_memset(&ie, 0, sizeof(ie)); 683189251Ssam 684189251Ssam /* RSN: msg 1/4 should contain SMKID for the selected SMK */ 685189251Ssam kde = (const u8 *) (key + 1); 686189251Ssam len = WPA_GET_BE16(key->key_data_length); 687189251Ssam wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", kde, len); 688189251Ssam if (wpa_supplicant_parse_ies(kde, len, &ie) < 0 || ie.pmkid == NULL) { 689189251Ssam wpa_printf(MSG_DEBUG, "RSN: No SMKID in STK 1/4"); 690189251Ssam return; 691189251Ssam } 692189251Ssam if (os_memcmp(ie.pmkid, peerkey->smkid, PMKID_LEN) != 0) { 693189251Ssam wpa_hexdump(MSG_DEBUG, "RSN: Unknown SMKID in STK 1/4", 694189251Ssam ie.pmkid, PMKID_LEN); 695189251Ssam return; 696189251Ssam } 697189251Ssam 698252726Srpaulo if (random_get_bytes(peerkey->pnonce, WPA_NONCE_LEN)) { 699214734Srpaulo wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, 700189251Ssam "RSN: Failed to get random data for PNonce"); 701189251Ssam return; 702189251Ssam } 703189251Ssam wpa_hexdump(MSG_DEBUG, "WPA: Renewed PNonce", 704189251Ssam peerkey->pnonce, WPA_NONCE_LEN); 705189251Ssam 706189251Ssam /* Calculate STK which will be stored as a temporary STK until it has 707189251Ssam * been verified when processing message 3/4. */ 708189251Ssam stk = &peerkey->tstk; 709189251Ssam wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion", 710189251Ssam sm->own_addr, peerkey->addr, 711189251Ssam peerkey->pnonce, key->key_nonce, 712189251Ssam (u8 *) stk, sizeof(*stk), 713189251Ssam peerkey->use_sha256); 714189251Ssam /* Supplicant: swap tx/rx Mic keys */ 715189251Ssam os_memcpy(buf, stk->u.auth.tx_mic_key, 8); 716189251Ssam os_memcpy(stk->u.auth.tx_mic_key, stk->u.auth.rx_mic_key, 8); 717189251Ssam os_memcpy(stk->u.auth.rx_mic_key, buf, 8); 718189251Ssam peerkey->tstk_set = 1; 719189251Ssam 720189251Ssam kde_buf_len = peerkey->rsnie_p_len + 721189251Ssam 2 + RSN_SELECTOR_LEN + sizeof(lifetime) + 722189251Ssam 2 + RSN_SELECTOR_LEN + PMKID_LEN; 723189251Ssam kde_buf = os_malloc(kde_buf_len); 724189251Ssam if (kde_buf == NULL) 725189251Ssam return; 726189251Ssam pos = kde_buf; 727189251Ssam pos = wpa_add_ie(pos, peerkey->rsnie_p, peerkey->rsnie_p_len); 728189251Ssam lifetime = host_to_be32(peerkey->lifetime); 729189251Ssam pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME, 730189251Ssam (u8 *) &lifetime, sizeof(lifetime)); 731189251Ssam wpa_add_kde(pos, RSN_KEY_DATA_PMKID, peerkey->smkid, PMKID_LEN); 732189251Ssam 733189251Ssam if (wpa_supplicant_send_2_of_4(sm, peerkey->addr, key, ver, 734189251Ssam peerkey->pnonce, kde_buf, kde_buf_len, 735189251Ssam stk)) { 736189251Ssam os_free(kde_buf); 737189251Ssam return; 738189251Ssam } 739189251Ssam os_free(kde_buf); 740189251Ssam 741189251Ssam os_memcpy(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN); 742189251Ssam} 743189251Ssam 744189251Ssam 745189251Ssamstatic void wpa_supplicant_update_smk_lifetime(struct wpa_sm *sm, 746189251Ssam struct wpa_peerkey *peerkey, 747189251Ssam struct wpa_eapol_ie_parse *kde) 748189251Ssam{ 749189251Ssam u32 lifetime; 750189251Ssam struct os_time now; 751189251Ssam 752189251Ssam if (kde->lifetime == NULL || kde->lifetime_len < sizeof(lifetime)) 753189251Ssam return; 754189251Ssam 755189251Ssam lifetime = WPA_GET_BE32(kde->lifetime); 756189251Ssam 757189251Ssam if (lifetime >= peerkey->lifetime) { 758189251Ssam wpa_printf(MSG_DEBUG, "RSN: Peer used SMK lifetime %u seconds " 759189251Ssam "which is larger than or equal to own value %u " 760189251Ssam "seconds - ignored", lifetime, peerkey->lifetime); 761189251Ssam return; 762189251Ssam } 763189251Ssam 764189251Ssam wpa_printf(MSG_DEBUG, "RSN: Peer used shorter SMK lifetime %u seconds " 765189251Ssam "(own was %u seconds) - updated", 766189251Ssam lifetime, peerkey->lifetime); 767189251Ssam peerkey->lifetime = lifetime; 768189251Ssam 769189251Ssam os_get_time(&now); 770189251Ssam peerkey->expiration = now.sec + lifetime; 771189251Ssam eloop_cancel_timeout(wpa_supplicant_smk_timeout, sm, peerkey); 772189251Ssam eloop_register_timeout(lifetime, 0, wpa_supplicant_smk_timeout, 773189251Ssam sm, peerkey); 774189251Ssam} 775189251Ssam 776189251Ssam 777189251Ssamstatic void wpa_supplicant_process_stk_2_of_4(struct wpa_sm *sm, 778189251Ssam struct wpa_peerkey *peerkey, 779189251Ssam const struct wpa_eapol_key *key, 780189251Ssam u16 ver) 781189251Ssam{ 782189251Ssam struct wpa_eapol_ie_parse kde; 783189251Ssam const u8 *keydata; 784189251Ssam size_t len; 785189251Ssam 786189251Ssam wpa_printf(MSG_DEBUG, "RSN: RX message 2 of STK 4-Way Handshake from " 787189251Ssam MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver); 788189251Ssam 789189251Ssam os_memset(&kde, 0, sizeof(kde)); 790189251Ssam 791189251Ssam /* RSN: msg 2/4 should contain SMKID for the selected SMK and RSN IE 792189251Ssam * from the peer. It may also include Lifetime KDE. */ 793189251Ssam keydata = (const u8 *) (key + 1); 794189251Ssam len = WPA_GET_BE16(key->key_data_length); 795189251Ssam wpa_hexdump(MSG_DEBUG, "RSN: msg 2/4 key data", keydata, len); 796189251Ssam if (wpa_supplicant_parse_ies(keydata, len, &kde) < 0 || 797189251Ssam kde.pmkid == NULL || kde.rsn_ie == NULL) { 798189251Ssam wpa_printf(MSG_DEBUG, "RSN: No SMKID or RSN IE in STK 2/4"); 799189251Ssam return; 800189251Ssam } 801189251Ssam 802189251Ssam if (os_memcmp(kde.pmkid, peerkey->smkid, PMKID_LEN) != 0) { 803189251Ssam wpa_hexdump(MSG_DEBUG, "RSN: Unknown SMKID in STK 2/4", 804189251Ssam kde.pmkid, PMKID_LEN); 805189251Ssam return; 806189251Ssam } 807189251Ssam 808189251Ssam if (kde.rsn_ie_len != peerkey->rsnie_p_len || 809189251Ssam os_memcmp(kde.rsn_ie, peerkey->rsnie_p, kde.rsn_ie_len) != 0) { 810189251Ssam wpa_printf(MSG_INFO, "RSN: Peer RSN IE in SMK and STK " 811189251Ssam "handshakes did not match"); 812189251Ssam wpa_hexdump(MSG_DEBUG, "RSN: Peer RSN IE in SMK handshake", 813189251Ssam peerkey->rsnie_p, peerkey->rsnie_p_len); 814189251Ssam wpa_hexdump(MSG_DEBUG, "RSN: Peer RSN IE in STK handshake", 815189251Ssam kde.rsn_ie, kde.rsn_ie_len); 816189251Ssam return; 817189251Ssam } 818189251Ssam 819189251Ssam wpa_supplicant_update_smk_lifetime(sm, peerkey, &kde); 820189251Ssam 821189251Ssam wpa_supplicant_send_stk_3_of_4(sm, peerkey); 822189251Ssam os_memcpy(peerkey->pnonce, key->key_nonce, WPA_NONCE_LEN); 823189251Ssam} 824189251Ssam 825189251Ssam 826189251Ssamstatic void wpa_supplicant_process_stk_3_of_4(struct wpa_sm *sm, 827189251Ssam struct wpa_peerkey *peerkey, 828189251Ssam const struct wpa_eapol_key *key, 829189251Ssam u16 ver) 830189251Ssam{ 831189251Ssam struct wpa_eapol_ie_parse kde; 832189251Ssam const u8 *keydata; 833189251Ssam size_t len, key_len; 834189251Ssam const u8 *_key; 835189251Ssam u8 key_buf[32], rsc[6]; 836189251Ssam 837189251Ssam wpa_printf(MSG_DEBUG, "RSN: RX message 3 of STK 4-Way Handshake from " 838189251Ssam MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver); 839189251Ssam 840189251Ssam os_memset(&kde, 0, sizeof(kde)); 841189251Ssam 842189251Ssam /* RSN: msg 3/4 should contain Initiator RSN IE. It may also include 843189251Ssam * Lifetime KDE. */ 844189251Ssam keydata = (const u8 *) (key + 1); 845189251Ssam len = WPA_GET_BE16(key->key_data_length); 846189251Ssam wpa_hexdump(MSG_DEBUG, "RSN: msg 3/4 key data", keydata, len); 847189251Ssam if (wpa_supplicant_parse_ies(keydata, len, &kde) < 0) { 848189251Ssam wpa_printf(MSG_DEBUG, "RSN: Failed to parse key data in " 849189251Ssam "STK 3/4"); 850189251Ssam return; 851189251Ssam } 852189251Ssam 853189251Ssam if (kde.rsn_ie_len != peerkey->rsnie_i_len || 854189251Ssam os_memcmp(kde.rsn_ie, peerkey->rsnie_i, kde.rsn_ie_len) != 0) { 855189251Ssam wpa_printf(MSG_INFO, "RSN: Initiator RSN IE in SMK and STK " 856189251Ssam "handshakes did not match"); 857189251Ssam wpa_hexdump(MSG_DEBUG, "RSN: Initiator RSN IE in SMK " 858189251Ssam "handshake", 859189251Ssam peerkey->rsnie_i, peerkey->rsnie_i_len); 860189251Ssam wpa_hexdump(MSG_DEBUG, "RSN: Initiator RSN IE in STK " 861189251Ssam "handshake", 862189251Ssam kde.rsn_ie, kde.rsn_ie_len); 863189251Ssam return; 864189251Ssam } 865189251Ssam 866189251Ssam if (os_memcmp(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN) != 0) { 867189251Ssam wpa_printf(MSG_WARNING, "RSN: INonce from message 1 of STK " 868189251Ssam "4-Way Handshake differs from 3 of STK 4-Way " 869189251Ssam "Handshake - drop packet (src=" MACSTR ")", 870189251Ssam MAC2STR(peerkey->addr)); 871189251Ssam return; 872189251Ssam } 873189251Ssam 874189251Ssam wpa_supplicant_update_smk_lifetime(sm, peerkey, &kde); 875189251Ssam 876189251Ssam if (wpa_supplicant_send_4_of_4(sm, peerkey->addr, key, ver, 877189251Ssam WPA_GET_BE16(key->key_info), 878189251Ssam NULL, 0, &peerkey->stk)) 879189251Ssam return; 880189251Ssam 881189251Ssam _key = (u8 *) peerkey->stk.tk1; 882189251Ssam if (peerkey->cipher == WPA_CIPHER_TKIP) { 883189251Ssam /* Swap Tx/Rx keys for Michael MIC */ 884189251Ssam os_memcpy(key_buf, _key, 16); 885189251Ssam os_memcpy(key_buf + 16, peerkey->stk.u.auth.rx_mic_key, 8); 886189251Ssam os_memcpy(key_buf + 24, peerkey->stk.u.auth.tx_mic_key, 8); 887189251Ssam _key = key_buf; 888189251Ssam key_len = 32; 889189251Ssam } else 890189251Ssam key_len = 16; 891189251Ssam 892189251Ssam os_memset(rsc, 0, 6); 893189251Ssam if (wpa_sm_set_key(sm, peerkey->cipher, peerkey->addr, 0, 1, 894189251Ssam rsc, sizeof(rsc), _key, key_len) < 0) { 895189251Ssam wpa_printf(MSG_WARNING, "RSN: Failed to set STK to the " 896189251Ssam "driver."); 897189251Ssam return; 898189251Ssam } 899189251Ssam} 900189251Ssam 901189251Ssam 902189251Ssamstatic void wpa_supplicant_process_stk_4_of_4(struct wpa_sm *sm, 903189251Ssam struct wpa_peerkey *peerkey, 904189251Ssam const struct wpa_eapol_key *key, 905189251Ssam u16 ver) 906189251Ssam{ 907189251Ssam u8 rsc[6]; 908189251Ssam 909189251Ssam wpa_printf(MSG_DEBUG, "RSN: RX message 4 of STK 4-Way Handshake from " 910189251Ssam MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver); 911189251Ssam 912189251Ssam os_memset(rsc, 0, 6); 913189251Ssam if (wpa_sm_set_key(sm, peerkey->cipher, peerkey->addr, 0, 1, 914189251Ssam rsc, sizeof(rsc), (u8 *) peerkey->stk.tk1, 915189251Ssam peerkey->cipher == WPA_CIPHER_TKIP ? 32 : 16) < 0) { 916189251Ssam wpa_printf(MSG_WARNING, "RSN: Failed to set STK to the " 917189251Ssam "driver."); 918189251Ssam return; 919189251Ssam } 920189251Ssam} 921189251Ssam 922189251Ssam 923189251Ssam/** 924189251Ssam * peerkey_verify_eapol_key_mic - Verify PeerKey MIC 925189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init() 926189251Ssam * @peerkey: Pointer to the PeerKey data for the peer 927189251Ssam * @key: Pointer to the EAPOL-Key frame header 928189251Ssam * @ver: Version bits from EAPOL-Key Key Info 929189251Ssam * @buf: Pointer to the beginning of EAPOL-Key frame 930189251Ssam * @len: Length of the EAPOL-Key frame 931189251Ssam * Returns: 0 on success, -1 on failure 932189251Ssam */ 933189251Ssamint peerkey_verify_eapol_key_mic(struct wpa_sm *sm, 934189251Ssam struct wpa_peerkey *peerkey, 935189251Ssam struct wpa_eapol_key *key, u16 ver, 936189251Ssam const u8 *buf, size_t len) 937189251Ssam{ 938189251Ssam u8 mic[16]; 939189251Ssam int ok = 0; 940189251Ssam 941189251Ssam if (peerkey->initiator && !peerkey->stk_set) { 942189251Ssam wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion", 943189251Ssam sm->own_addr, peerkey->addr, 944189251Ssam peerkey->inonce, key->key_nonce, 945189251Ssam (u8 *) &peerkey->stk, sizeof(peerkey->stk), 946189251Ssam peerkey->use_sha256); 947189251Ssam peerkey->stk_set = 1; 948189251Ssam } 949189251Ssam 950189251Ssam os_memcpy(mic, key->key_mic, 16); 951189251Ssam if (peerkey->tstk_set) { 952189251Ssam os_memset(key->key_mic, 0, 16); 953189251Ssam wpa_eapol_key_mic(peerkey->tstk.kck, ver, buf, len, 954189251Ssam key->key_mic); 955189251Ssam if (os_memcmp(mic, key->key_mic, 16) != 0) { 956189251Ssam wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC " 957189251Ssam "when using TSTK - ignoring TSTK"); 958189251Ssam } else { 959189251Ssam ok = 1; 960189251Ssam peerkey->tstk_set = 0; 961189251Ssam peerkey->stk_set = 1; 962189251Ssam os_memcpy(&peerkey->stk, &peerkey->tstk, 963189251Ssam sizeof(peerkey->stk)); 964189251Ssam } 965189251Ssam } 966189251Ssam 967189251Ssam if (!ok && peerkey->stk_set) { 968189251Ssam os_memset(key->key_mic, 0, 16); 969189251Ssam wpa_eapol_key_mic(peerkey->stk.kck, ver, buf, len, 970189251Ssam key->key_mic); 971189251Ssam if (os_memcmp(mic, key->key_mic, 16) != 0) { 972189251Ssam wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC " 973189251Ssam "- dropping packet"); 974189251Ssam return -1; 975189251Ssam } 976189251Ssam ok = 1; 977189251Ssam } 978189251Ssam 979189251Ssam if (!ok) { 980189251Ssam wpa_printf(MSG_WARNING, "RSN: Could not verify EAPOL-Key MIC " 981189251Ssam "- dropping packet"); 982189251Ssam return -1; 983189251Ssam } 984189251Ssam 985189251Ssam os_memcpy(peerkey->replay_counter, key->replay_counter, 986189251Ssam WPA_REPLAY_COUNTER_LEN); 987189251Ssam peerkey->replay_counter_set = 1; 988189251Ssam return 0; 989189251Ssam} 990189251Ssam 991189251Ssam 992189251Ssam/** 993189251Ssam * wpa_sm_stkstart - Send EAPOL-Key Request for STK handshake (STK M1) 994189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init() 995189251Ssam * @peer: MAC address of the peer STA 996189251Ssam * Returns: 0 on success, or -1 on failure 997189251Ssam * 998189251Ssam * Send an EAPOL-Key Request to the current authenticator to start STK 999189251Ssam * handshake with the peer. 1000189251Ssam */ 1001189251Ssamint wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer) 1002189251Ssam{ 1003189251Ssam size_t rlen, kde_len; 1004189251Ssam struct wpa_eapol_key *req; 1005189251Ssam int key_info, ver; 1006189251Ssam u8 bssid[ETH_ALEN], *rbuf, *pos, *count_pos; 1007189251Ssam u16 count; 1008189251Ssam struct rsn_ie_hdr *hdr; 1009189251Ssam struct wpa_peerkey *peerkey; 1010189251Ssam struct wpa_ie_data ie; 1011189251Ssam 1012189251Ssam if (sm->proto != WPA_PROTO_RSN || !sm->ptk_set || !sm->peerkey_enabled) 1013189251Ssam return -1; 1014189251Ssam 1015189251Ssam if (sm->ap_rsn_ie && 1016189251Ssam wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &ie) == 0 && 1017189251Ssam !(ie.capabilities & WPA_CAPABILITY_PEERKEY_ENABLED)) { 1018189251Ssam wpa_printf(MSG_DEBUG, "RSN: Current AP does not support STK"); 1019189251Ssam return -1; 1020189251Ssam } 1021189251Ssam 1022252726Srpaulo if (sm->pairwise_cipher != WPA_CIPHER_TKIP) 1023189251Ssam ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES; 1024189251Ssam else 1025189251Ssam ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4; 1026189251Ssam 1027189251Ssam if (wpa_sm_get_bssid(sm, bssid) < 0) { 1028189251Ssam wpa_printf(MSG_WARNING, "Failed to read BSSID for EAPOL-Key " 1029189251Ssam "SMK M1"); 1030189251Ssam return -1; 1031189251Ssam } 1032189251Ssam 1033189251Ssam /* TODO: find existing entry and if found, use that instead of adding 1034189251Ssam * a new one */ 1035189251Ssam peerkey = os_zalloc(sizeof(*peerkey)); 1036189251Ssam if (peerkey == NULL) 1037189251Ssam return -1; 1038189251Ssam peerkey->initiator = 1; 1039189251Ssam os_memcpy(peerkey->addr, peer, ETH_ALEN); 1040189251Ssam#ifdef CONFIG_IEEE80211W 1041189251Ssam if (wpa_key_mgmt_sha256(sm->key_mgmt)) 1042189251Ssam peerkey->use_sha256 = 1; 1043189251Ssam#endif /* CONFIG_IEEE80211W */ 1044189251Ssam 1045189251Ssam /* SMK M1: 1046189251Ssam * EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce, 1047189251Ssam * MIC=MIC, DataKDs=(RSNIE_I, MAC_P KDE)) 1048189251Ssam */ 1049189251Ssam 1050189251Ssam hdr = (struct rsn_ie_hdr *) peerkey->rsnie_i; 1051189251Ssam hdr->elem_id = WLAN_EID_RSN; 1052189251Ssam WPA_PUT_LE16(hdr->version, RSN_VERSION); 1053189251Ssam pos = (u8 *) (hdr + 1); 1054189251Ssam /* Group Suite can be anything for SMK RSN IE; receiver will just 1055189251Ssam * ignore it. */ 1056189251Ssam RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP); 1057189251Ssam pos += RSN_SELECTOR_LEN; 1058189251Ssam count_pos = pos; 1059189251Ssam pos += 2; 1060189251Ssam 1061252726Srpaulo count = rsn_cipher_put_suites(pos, sm->allowed_pairwise_cipher); 1062252726Srpaulo pos += count * RSN_SELECTOR_LEN; 1063189251Ssam WPA_PUT_LE16(count_pos, count); 1064189251Ssam 1065189251Ssam hdr->len = (pos - peerkey->rsnie_i) - 2; 1066189251Ssam peerkey->rsnie_i_len = pos - peerkey->rsnie_i; 1067189251Ssam wpa_hexdump(MSG_DEBUG, "WPA: RSN IE for SMK handshake", 1068189251Ssam peerkey->rsnie_i, peerkey->rsnie_i_len); 1069189251Ssam 1070189251Ssam kde_len = peerkey->rsnie_i_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN; 1071189251Ssam 1072189251Ssam rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL, 1073189251Ssam sizeof(*req) + kde_len, &rlen, 1074189251Ssam (void *) &req); 1075189251Ssam if (rbuf == NULL) { 1076189251Ssam wpa_supplicant_peerkey_free(sm, peerkey); 1077189251Ssam return -1; 1078189251Ssam } 1079189251Ssam 1080189251Ssam req->type = EAPOL_KEY_TYPE_RSN; 1081189251Ssam key_info = WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC | 1082189251Ssam WPA_KEY_INFO_SECURE | WPA_KEY_INFO_REQUEST | ver; 1083189251Ssam WPA_PUT_BE16(req->key_info, key_info); 1084189251Ssam WPA_PUT_BE16(req->key_length, 0); 1085189251Ssam os_memcpy(req->replay_counter, sm->request_counter, 1086189251Ssam WPA_REPLAY_COUNTER_LEN); 1087189251Ssam inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN); 1088189251Ssam 1089252726Srpaulo if (random_get_bytes(peerkey->inonce, WPA_NONCE_LEN)) { 1090214734Srpaulo wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, 1091189251Ssam "WPA: Failed to get random data for INonce"); 1092189251Ssam os_free(rbuf); 1093189251Ssam wpa_supplicant_peerkey_free(sm, peerkey); 1094189251Ssam return -1; 1095189251Ssam } 1096189251Ssam os_memcpy(req->key_nonce, peerkey->inonce, WPA_NONCE_LEN); 1097189251Ssam wpa_hexdump(MSG_DEBUG, "WPA: INonce for SMK handshake", 1098189251Ssam req->key_nonce, WPA_NONCE_LEN); 1099189251Ssam 1100189251Ssam WPA_PUT_BE16(req->key_data_length, (u16) kde_len); 1101189251Ssam pos = (u8 *) (req + 1); 1102189251Ssam 1103189251Ssam /* Initiator RSN IE */ 1104189251Ssam pos = wpa_add_ie(pos, peerkey->rsnie_i, peerkey->rsnie_i_len); 1105189251Ssam /* Peer MAC address KDE */ 1106189251Ssam wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN); 1107189251Ssam 1108189251Ssam wpa_printf(MSG_INFO, "RSN: Sending EAPOL-Key SMK M1 Request (peer " 1109189251Ssam MACSTR ")", MAC2STR(peer)); 1110189251Ssam wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL, 1111189251Ssam rbuf, rlen, req->key_mic); 1112189251Ssam 1113189251Ssam peerkey->next = sm->peerkey; 1114189251Ssam sm->peerkey = peerkey; 1115189251Ssam 1116189251Ssam return 0; 1117189251Ssam} 1118189251Ssam 1119189251Ssam 1120189251Ssam/** 1121189251Ssam * peerkey_deinit - Free PeerKey values 1122189251Ssam * @sm: Pointer to WPA state machine data from wpa_sm_init() 1123189251Ssam */ 1124189251Ssamvoid peerkey_deinit(struct wpa_sm *sm) 1125189251Ssam{ 1126189251Ssam struct wpa_peerkey *prev, *peerkey = sm->peerkey; 1127189251Ssam while (peerkey) { 1128189251Ssam prev = peerkey; 1129189251Ssam peerkey = peerkey->next; 1130189251Ssam os_free(prev); 1131189251Ssam } 1132252726Srpaulo sm->peerkey = NULL; 1133189251Ssam} 1134189251Ssam 1135189251Ssam 1136189251Ssamvoid peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey, 1137189251Ssam struct wpa_eapol_key *key, u16 key_info, u16 ver) 1138189251Ssam{ 1139189251Ssam if ((key_info & (WPA_KEY_INFO_MIC | WPA_KEY_INFO_ACK)) == 1140189251Ssam (WPA_KEY_INFO_MIC | WPA_KEY_INFO_ACK)) { 1141189251Ssam /* 3/4 STK 4-Way Handshake */ 1142189251Ssam wpa_supplicant_process_stk_3_of_4(sm, peerkey, key, ver); 1143189251Ssam } else if (key_info & WPA_KEY_INFO_ACK) { 1144189251Ssam /* 1/4 STK 4-Way Handshake */ 1145189251Ssam wpa_supplicant_process_stk_1_of_4(sm, peerkey, key, ver); 1146189251Ssam } else if (key_info & WPA_KEY_INFO_SECURE) { 1147189251Ssam /* 4/4 STK 4-Way Handshake */ 1148189251Ssam wpa_supplicant_process_stk_4_of_4(sm, peerkey, key, ver); 1149189251Ssam } else { 1150189251Ssam /* 2/4 STK 4-Way Handshake */ 1151189251Ssam wpa_supplicant_process_stk_2_of_4(sm, peerkey, key, ver); 1152189251Ssam } 1153189251Ssam} 1154189251Ssam 1155189251Ssam 1156189251Ssamvoid peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr, 1157189251Ssam struct wpa_eapol_key *key, size_t extra_len, 1158189251Ssam u16 key_info, u16 ver) 1159189251Ssam{ 1160189251Ssam if (key_info & WPA_KEY_INFO_ERROR) { 1161189251Ssam /* SMK Error */ 1162189251Ssam wpa_supplicant_process_smk_error(sm, src_addr, key, extra_len); 1163189251Ssam } else if (key_info & WPA_KEY_INFO_ACK) { 1164189251Ssam /* SMK M2 */ 1165189251Ssam wpa_supplicant_process_smk_m2(sm, src_addr, key, extra_len, 1166189251Ssam ver); 1167189251Ssam } else { 1168189251Ssam /* SMK M4 or M5 */ 1169189251Ssam wpa_supplicant_process_smk_m45(sm, src_addr, key, extra_len, 1170189251Ssam ver); 1171189251Ssam } 1172189251Ssam} 1173189251Ssam 1174189251Ssam#endif /* CONFIG_PEERKEY */ 1175