1214501Srpaulo/* 2214501Srpaulo * hostapd - PeerKey for Direct Link Setup (DLS) 3214501Srpaulo * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi> 4214501Srpaulo * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7214501Srpaulo */ 8214501Srpaulo 9214501Srpaulo#include "utils/includes.h" 10214501Srpaulo 11214501Srpaulo#include "utils/common.h" 12214501Srpaulo#include "utils/eloop.h" 13214501Srpaulo#include "crypto/sha1.h" 14214501Srpaulo#include "crypto/sha256.h" 15252726Srpaulo#include "crypto/random.h" 16214501Srpaulo#include "wpa_auth.h" 17214501Srpaulo#include "wpa_auth_i.h" 18214501Srpaulo#include "wpa_auth_ie.h" 19214501Srpaulo 20214501Srpaulo#ifdef CONFIG_PEERKEY 21214501Srpaulo 22214501Srpaulostatic void wpa_stsl_step(void *eloop_ctx, void *timeout_ctx) 23214501Srpaulo{ 24214501Srpaulo#if 0 25214501Srpaulo struct wpa_authenticator *wpa_auth = eloop_ctx; 26214501Srpaulo struct wpa_stsl_negotiation *neg = timeout_ctx; 27214501Srpaulo#endif 28214501Srpaulo 29214501Srpaulo /* TODO: ? */ 30214501Srpaulo} 31214501Srpaulo 32214501Srpaulo 33214501Srpaulostruct wpa_stsl_search { 34214501Srpaulo const u8 *addr; 35214501Srpaulo struct wpa_state_machine *sm; 36214501Srpaulo}; 37214501Srpaulo 38214501Srpaulo 39214501Srpaulostatic int wpa_stsl_select_sta(struct wpa_state_machine *sm, void *ctx) 40214501Srpaulo{ 41214501Srpaulo struct wpa_stsl_search *search = ctx; 42214501Srpaulo if (os_memcmp(search->addr, sm->addr, ETH_ALEN) == 0) { 43214501Srpaulo search->sm = sm; 44214501Srpaulo return 1; 45214501Srpaulo } 46214501Srpaulo return 0; 47214501Srpaulo} 48214501Srpaulo 49214501Srpaulo 50214501Srpaulostatic void wpa_smk_send_error(struct wpa_authenticator *wpa_auth, 51214501Srpaulo struct wpa_state_machine *sm, const u8 *peer, 52214501Srpaulo u16 mui, u16 error_type) 53214501Srpaulo{ 54214501Srpaulo u8 kde[2 + RSN_SELECTOR_LEN + ETH_ALEN + 55214501Srpaulo 2 + RSN_SELECTOR_LEN + sizeof(struct rsn_error_kde)]; 56214501Srpaulo u8 *pos; 57214501Srpaulo struct rsn_error_kde error; 58214501Srpaulo 59214501Srpaulo wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, 60214501Srpaulo "Sending SMK Error"); 61214501Srpaulo 62214501Srpaulo pos = kde; 63214501Srpaulo 64214501Srpaulo if (peer) { 65214501Srpaulo pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN, 66214501Srpaulo NULL, 0); 67214501Srpaulo } 68214501Srpaulo 69214501Srpaulo error.mui = host_to_be16(mui); 70214501Srpaulo error.error_type = host_to_be16(error_type); 71214501Srpaulo pos = wpa_add_kde(pos, RSN_KEY_DATA_ERROR, 72214501Srpaulo (u8 *) &error, sizeof(error), NULL, 0); 73214501Srpaulo 74214501Srpaulo __wpa_send_eapol(wpa_auth, sm, 75214501Srpaulo WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC | 76214501Srpaulo WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_ERROR, 77214501Srpaulo NULL, NULL, kde, pos - kde, 0, 0, 0); 78214501Srpaulo} 79214501Srpaulo 80214501Srpaulo 81214501Srpaulovoid wpa_smk_m1(struct wpa_authenticator *wpa_auth, 82214501Srpaulo struct wpa_state_machine *sm, struct wpa_eapol_key *key) 83214501Srpaulo{ 84214501Srpaulo struct wpa_eapol_ie_parse kde; 85214501Srpaulo struct wpa_stsl_search search; 86214501Srpaulo u8 *buf, *pos; 87214501Srpaulo size_t buf_len; 88214501Srpaulo 89214501Srpaulo if (wpa_parse_kde_ies((const u8 *) (key + 1), 90214501Srpaulo WPA_GET_BE16(key->key_data_length), &kde) < 0) { 91214501Srpaulo wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M1"); 92214501Srpaulo return; 93214501Srpaulo } 94214501Srpaulo 95214501Srpaulo if (kde.rsn_ie == NULL || kde.mac_addr == NULL || 96214501Srpaulo kde.mac_addr_len < ETH_ALEN) { 97214501Srpaulo wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in " 98214501Srpaulo "SMK M1"); 99214501Srpaulo return; 100214501Srpaulo } 101214501Srpaulo 102214501Srpaulo /* Initiator = sm->addr; Peer = kde.mac_addr */ 103214501Srpaulo 104214501Srpaulo search.addr = kde.mac_addr; 105214501Srpaulo search.sm = NULL; 106214501Srpaulo if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) == 107214501Srpaulo 0 || search.sm == NULL) { 108214501Srpaulo wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR 109214501Srpaulo " aborted - STA not associated anymore", 110214501Srpaulo MAC2STR(kde.mac_addr)); 111214501Srpaulo wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK, 112214501Srpaulo STK_ERR_STA_NR); 113214501Srpaulo /* FIX: wpa_stsl_remove(wpa_auth, neg); */ 114214501Srpaulo return; 115214501Srpaulo } 116214501Srpaulo 117214501Srpaulo buf_len = kde.rsn_ie_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN; 118214501Srpaulo buf = os_malloc(buf_len); 119214501Srpaulo if (buf == NULL) 120214501Srpaulo return; 121214501Srpaulo /* Initiator RSN IE */ 122214501Srpaulo os_memcpy(buf, kde.rsn_ie, kde.rsn_ie_len); 123214501Srpaulo pos = buf + kde.rsn_ie_len; 124214501Srpaulo /* Initiator MAC Address */ 125214501Srpaulo pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, sm->addr, ETH_ALEN, 126214501Srpaulo NULL, 0); 127214501Srpaulo 128214501Srpaulo /* SMK M2: 129214501Srpaulo * EAPOL-Key(S=1, M=1, A=1, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce, 130214501Srpaulo * MIC=MIC, DataKDs=(RSNIE_I, MAC_I KDE) 131214501Srpaulo */ 132214501Srpaulo 133214501Srpaulo wpa_auth_logger(wpa_auth, search.sm->addr, LOGGER_DEBUG, 134214501Srpaulo "Sending SMK M2"); 135214501Srpaulo 136214501Srpaulo __wpa_send_eapol(wpa_auth, search.sm, 137214501Srpaulo WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC | 138214501Srpaulo WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE, 139214501Srpaulo NULL, key->key_nonce, buf, pos - buf, 0, 0, 0); 140214501Srpaulo 141214501Srpaulo os_free(buf); 142214501Srpaulo} 143214501Srpaulo 144214501Srpaulo 145214501Srpaulostatic void wpa_send_smk_m4(struct wpa_authenticator *wpa_auth, 146214501Srpaulo struct wpa_state_machine *sm, 147214501Srpaulo struct wpa_eapol_key *key, 148214501Srpaulo struct wpa_eapol_ie_parse *kde, 149214501Srpaulo const u8 *smk) 150214501Srpaulo{ 151214501Srpaulo u8 *buf, *pos; 152214501Srpaulo size_t buf_len; 153214501Srpaulo u32 lifetime; 154214501Srpaulo 155214501Srpaulo /* SMK M4: 156214501Srpaulo * EAPOL-Key(S=1, M=1, A=0, I=1, K=0, SM=1, KeyRSC=0, Nonce=PNonce, 157214501Srpaulo * MIC=MIC, DataKDs=(MAC_I KDE, INonce KDE, SMK KDE, 158214501Srpaulo * Lifetime KDE) 159214501Srpaulo */ 160214501Srpaulo 161214501Srpaulo buf_len = 2 + RSN_SELECTOR_LEN + ETH_ALEN + 162214501Srpaulo 2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN + 163214501Srpaulo 2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN + 164214501Srpaulo 2 + RSN_SELECTOR_LEN + sizeof(lifetime); 165214501Srpaulo pos = buf = os_malloc(buf_len); 166214501Srpaulo if (buf == NULL) 167214501Srpaulo return; 168214501Srpaulo 169214501Srpaulo /* Initiator MAC Address */ 170214501Srpaulo pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, kde->mac_addr, ETH_ALEN, 171214501Srpaulo NULL, 0); 172214501Srpaulo 173214501Srpaulo /* Initiator Nonce */ 174214501Srpaulo pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, kde->nonce, WPA_NONCE_LEN, 175214501Srpaulo NULL, 0); 176214501Srpaulo 177214501Srpaulo /* SMK with PNonce */ 178214501Srpaulo pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN, 179214501Srpaulo key->key_nonce, WPA_NONCE_LEN); 180214501Srpaulo 181214501Srpaulo /* Lifetime */ 182214501Srpaulo lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */ 183214501Srpaulo pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME, 184214501Srpaulo (u8 *) &lifetime, sizeof(lifetime), NULL, 0); 185214501Srpaulo 186214501Srpaulo wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, 187214501Srpaulo "Sending SMK M4"); 188214501Srpaulo 189214501Srpaulo __wpa_send_eapol(wpa_auth, sm, 190214501Srpaulo WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC | 191214501Srpaulo WPA_KEY_INFO_INSTALL | WPA_KEY_INFO_SMK_MESSAGE, 192214501Srpaulo NULL, key->key_nonce, buf, pos - buf, 0, 1, 0); 193214501Srpaulo 194214501Srpaulo os_free(buf); 195214501Srpaulo} 196214501Srpaulo 197214501Srpaulo 198214501Srpaulostatic void wpa_send_smk_m5(struct wpa_authenticator *wpa_auth, 199214501Srpaulo struct wpa_state_machine *sm, 200214501Srpaulo struct wpa_eapol_key *key, 201214501Srpaulo struct wpa_eapol_ie_parse *kde, 202214501Srpaulo const u8 *smk, const u8 *peer) 203214501Srpaulo{ 204214501Srpaulo u8 *buf, *pos; 205214501Srpaulo size_t buf_len; 206214501Srpaulo u32 lifetime; 207214501Srpaulo 208214501Srpaulo /* SMK M5: 209214501Srpaulo * EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce, 210214501Srpaulo * MIC=MIC, DataKDs=(RSNIE_P, MAC_P KDE, PNonce, SMK KDE, 211214501Srpaulo * Lifetime KDE)) 212214501Srpaulo */ 213214501Srpaulo 214214501Srpaulo buf_len = kde->rsn_ie_len + 215214501Srpaulo 2 + RSN_SELECTOR_LEN + ETH_ALEN + 216214501Srpaulo 2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN + 217214501Srpaulo 2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN + 218214501Srpaulo 2 + RSN_SELECTOR_LEN + sizeof(lifetime); 219214501Srpaulo pos = buf = os_malloc(buf_len); 220214501Srpaulo if (buf == NULL) 221214501Srpaulo return; 222214501Srpaulo 223214501Srpaulo /* Peer RSN IE */ 224214501Srpaulo os_memcpy(buf, kde->rsn_ie, kde->rsn_ie_len); 225214501Srpaulo pos = buf + kde->rsn_ie_len; 226214501Srpaulo 227214501Srpaulo /* Peer MAC Address */ 228214501Srpaulo pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN, NULL, 0); 229214501Srpaulo 230214501Srpaulo /* PNonce */ 231214501Srpaulo pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, key->key_nonce, 232214501Srpaulo WPA_NONCE_LEN, NULL, 0); 233214501Srpaulo 234214501Srpaulo /* SMK and INonce */ 235214501Srpaulo pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN, 236214501Srpaulo kde->nonce, WPA_NONCE_LEN); 237214501Srpaulo 238214501Srpaulo /* Lifetime */ 239214501Srpaulo lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */ 240214501Srpaulo pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME, 241214501Srpaulo (u8 *) &lifetime, sizeof(lifetime), NULL, 0); 242214501Srpaulo 243214501Srpaulo wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG, 244214501Srpaulo "Sending SMK M5"); 245214501Srpaulo 246214501Srpaulo __wpa_send_eapol(wpa_auth, sm, 247214501Srpaulo WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC | 248214501Srpaulo WPA_KEY_INFO_SMK_MESSAGE, 249214501Srpaulo NULL, kde->nonce, buf, pos - buf, 0, 1, 0); 250214501Srpaulo 251214501Srpaulo os_free(buf); 252214501Srpaulo} 253214501Srpaulo 254214501Srpaulo 255214501Srpaulovoid wpa_smk_m3(struct wpa_authenticator *wpa_auth, 256214501Srpaulo struct wpa_state_machine *sm, struct wpa_eapol_key *key) 257214501Srpaulo{ 258214501Srpaulo struct wpa_eapol_ie_parse kde; 259214501Srpaulo struct wpa_stsl_search search; 260214501Srpaulo u8 smk[32], buf[ETH_ALEN + 8 + 2 * WPA_NONCE_LEN], *pos; 261214501Srpaulo 262214501Srpaulo if (wpa_parse_kde_ies((const u8 *) (key + 1), 263214501Srpaulo WPA_GET_BE16(key->key_data_length), &kde) < 0) { 264214501Srpaulo wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M3"); 265214501Srpaulo return; 266214501Srpaulo } 267214501Srpaulo 268214501Srpaulo if (kde.rsn_ie == NULL || 269214501Srpaulo kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN || 270214501Srpaulo kde.nonce == NULL || kde.nonce_len < WPA_NONCE_LEN) { 271214501Srpaulo wpa_printf(MSG_INFO, "RSN: No RSN IE, MAC address KDE, or " 272214501Srpaulo "Nonce KDE in SMK M3"); 273214501Srpaulo return; 274214501Srpaulo } 275214501Srpaulo 276214501Srpaulo /* Peer = sm->addr; Initiator = kde.mac_addr; 277214501Srpaulo * Peer Nonce = key->key_nonce; Initiator Nonce = kde.nonce */ 278214501Srpaulo 279214501Srpaulo search.addr = kde.mac_addr; 280214501Srpaulo search.sm = NULL; 281214501Srpaulo if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) == 282214501Srpaulo 0 || search.sm == NULL) { 283214501Srpaulo wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR 284214501Srpaulo " aborted - STA not associated anymore", 285214501Srpaulo MAC2STR(kde.mac_addr)); 286214501Srpaulo wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK, 287214501Srpaulo STK_ERR_STA_NR); 288214501Srpaulo /* FIX: wpa_stsl_remove(wpa_auth, neg); */ 289214501Srpaulo return; 290214501Srpaulo } 291214501Srpaulo 292252726Srpaulo if (random_get_bytes(smk, PMK_LEN)) { 293214501Srpaulo wpa_printf(MSG_DEBUG, "RSN: Failed to generate SMK"); 294214501Srpaulo return; 295214501Srpaulo } 296214501Srpaulo 297214501Srpaulo /* SMK = PRF-256(Random number, "SMK Derivation", 298214501Srpaulo * AA || Time || INonce || PNonce) 299214501Srpaulo */ 300214501Srpaulo os_memcpy(buf, wpa_auth->addr, ETH_ALEN); 301214501Srpaulo pos = buf + ETH_ALEN; 302214501Srpaulo wpa_get_ntp_timestamp(pos); 303214501Srpaulo pos += 8; 304214501Srpaulo os_memcpy(pos, kde.nonce, WPA_NONCE_LEN); 305214501Srpaulo pos += WPA_NONCE_LEN; 306214501Srpaulo os_memcpy(pos, key->key_nonce, WPA_NONCE_LEN); 307214501Srpaulo#ifdef CONFIG_IEEE80211W 308214501Srpaulo sha256_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf), 309214501Srpaulo smk, PMK_LEN); 310214501Srpaulo#else /* CONFIG_IEEE80211W */ 311214501Srpaulo sha1_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf), 312214501Srpaulo smk, PMK_LEN); 313214501Srpaulo#endif /* CONFIG_IEEE80211W */ 314214501Srpaulo 315214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", smk, PMK_LEN); 316214501Srpaulo 317214501Srpaulo wpa_send_smk_m4(wpa_auth, sm, key, &kde, smk); 318214501Srpaulo wpa_send_smk_m5(wpa_auth, search.sm, key, &kde, smk, sm->addr); 319214501Srpaulo 320214501Srpaulo /* Authenticator does not need SMK anymore and it is required to forget 321214501Srpaulo * it. */ 322214501Srpaulo os_memset(smk, 0, sizeof(*smk)); 323214501Srpaulo} 324214501Srpaulo 325214501Srpaulo 326214501Srpaulovoid wpa_smk_error(struct wpa_authenticator *wpa_auth, 327214501Srpaulo struct wpa_state_machine *sm, struct wpa_eapol_key *key) 328214501Srpaulo{ 329214501Srpaulo struct wpa_eapol_ie_parse kde; 330214501Srpaulo struct wpa_stsl_search search; 331214501Srpaulo struct rsn_error_kde error; 332214501Srpaulo u16 mui, error_type; 333214501Srpaulo 334214501Srpaulo if (wpa_parse_kde_ies((const u8 *) (key + 1), 335214501Srpaulo WPA_GET_BE16(key->key_data_length), &kde) < 0) { 336214501Srpaulo wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error"); 337214501Srpaulo return; 338214501Srpaulo } 339214501Srpaulo 340214501Srpaulo if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN || 341214501Srpaulo kde.error == NULL || kde.error_len < sizeof(error)) { 342214501Srpaulo wpa_printf(MSG_INFO, "RSN: No MAC address or Error KDE in " 343214501Srpaulo "SMK Error"); 344214501Srpaulo return; 345214501Srpaulo } 346214501Srpaulo 347214501Srpaulo search.addr = kde.mac_addr; 348214501Srpaulo search.sm = NULL; 349214501Srpaulo if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) == 350214501Srpaulo 0 || search.sm == NULL) { 351214501Srpaulo wpa_printf(MSG_DEBUG, "RSN: Peer STA " MACSTR " not " 352214501Srpaulo "associated for SMK Error message from " MACSTR, 353214501Srpaulo MAC2STR(kde.mac_addr), MAC2STR(sm->addr)); 354214501Srpaulo return; 355214501Srpaulo } 356214501Srpaulo 357214501Srpaulo os_memcpy(&error, kde.error, sizeof(error)); 358214501Srpaulo mui = be_to_host16(error.mui); 359214501Srpaulo error_type = be_to_host16(error.error_type); 360214501Srpaulo wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO, 361214501Srpaulo "STA reported SMK Error: Peer " MACSTR 362214501Srpaulo " MUI %d Error Type %d", 363214501Srpaulo MAC2STR(kde.mac_addr), mui, error_type); 364214501Srpaulo 365214501Srpaulo wpa_smk_send_error(wpa_auth, search.sm, sm->addr, mui, error_type); 366214501Srpaulo} 367214501Srpaulo 368214501Srpaulo 369214501Srpauloint wpa_stsl_remove(struct wpa_authenticator *wpa_auth, 370214501Srpaulo struct wpa_stsl_negotiation *neg) 371214501Srpaulo{ 372214501Srpaulo struct wpa_stsl_negotiation *pos, *prev; 373214501Srpaulo 374214501Srpaulo if (wpa_auth == NULL) 375214501Srpaulo return -1; 376214501Srpaulo pos = wpa_auth->stsl_negotiations; 377214501Srpaulo prev = NULL; 378214501Srpaulo while (pos) { 379214501Srpaulo if (pos == neg) { 380214501Srpaulo if (prev) 381214501Srpaulo prev->next = pos->next; 382214501Srpaulo else 383214501Srpaulo wpa_auth->stsl_negotiations = pos->next; 384214501Srpaulo 385214501Srpaulo eloop_cancel_timeout(wpa_stsl_step, wpa_auth, pos); 386214501Srpaulo os_free(pos); 387214501Srpaulo return 0; 388214501Srpaulo } 389214501Srpaulo prev = pos; 390214501Srpaulo pos = pos->next; 391214501Srpaulo } 392214501Srpaulo 393214501Srpaulo return -1; 394214501Srpaulo} 395214501Srpaulo 396214501Srpaulo#endif /* CONFIG_PEERKEY */ 397