1214501Srpaulo/* 2214501Srpaulo * hostapd / EAP-GPSK (RFC 5433) server 3214501Srpaulo * Copyright (c) 2006-2007, 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 "includes.h" 10214501Srpaulo 11214501Srpaulo#include "common.h" 12252726Srpaulo#include "crypto/random.h" 13214501Srpaulo#include "eap_server/eap_i.h" 14214501Srpaulo#include "eap_common/eap_gpsk_common.h" 15214501Srpaulo 16214501Srpaulo 17214501Srpaulostruct eap_gpsk_data { 18214501Srpaulo enum { GPSK_1, GPSK_3, SUCCESS, FAILURE } state; 19214501Srpaulo u8 rand_server[EAP_GPSK_RAND_LEN]; 20214501Srpaulo u8 rand_peer[EAP_GPSK_RAND_LEN]; 21214501Srpaulo u8 msk[EAP_MSK_LEN]; 22214501Srpaulo u8 emsk[EAP_EMSK_LEN]; 23214501Srpaulo u8 sk[EAP_GPSK_MAX_SK_LEN]; 24214501Srpaulo size_t sk_len; 25214501Srpaulo u8 pk[EAP_GPSK_MAX_PK_LEN]; 26214501Srpaulo size_t pk_len; 27214501Srpaulo u8 *id_peer; 28214501Srpaulo size_t id_peer_len; 29214501Srpaulo u8 *id_server; 30214501Srpaulo size_t id_server_len; 31214501Srpaulo#define MAX_NUM_CSUITES 2 32214501Srpaulo struct eap_gpsk_csuite csuite_list[MAX_NUM_CSUITES]; 33214501Srpaulo size_t csuite_count; 34214501Srpaulo int vendor; /* CSuite/Vendor */ 35214501Srpaulo int specifier; /* CSuite/Specifier */ 36214501Srpaulo}; 37214501Srpaulo 38214501Srpaulo 39214501Srpaulostatic const char * eap_gpsk_state_txt(int state) 40214501Srpaulo{ 41214501Srpaulo switch (state) { 42214501Srpaulo case GPSK_1: 43214501Srpaulo return "GPSK-1"; 44214501Srpaulo case GPSK_3: 45214501Srpaulo return "GPSK-3"; 46214501Srpaulo case SUCCESS: 47214501Srpaulo return "SUCCESS"; 48214501Srpaulo case FAILURE: 49214501Srpaulo return "FAILURE"; 50214501Srpaulo default: 51214501Srpaulo return "?"; 52214501Srpaulo } 53214501Srpaulo} 54214501Srpaulo 55214501Srpaulo 56214501Srpaulostatic void eap_gpsk_state(struct eap_gpsk_data *data, int state) 57214501Srpaulo{ 58214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: %s -> %s", 59214501Srpaulo eap_gpsk_state_txt(data->state), 60214501Srpaulo eap_gpsk_state_txt(state)); 61214501Srpaulo data->state = state; 62214501Srpaulo} 63214501Srpaulo 64214501Srpaulo 65214501Srpaulostatic void * eap_gpsk_init(struct eap_sm *sm) 66214501Srpaulo{ 67214501Srpaulo struct eap_gpsk_data *data; 68214501Srpaulo 69214501Srpaulo data = os_zalloc(sizeof(*data)); 70214501Srpaulo if (data == NULL) 71214501Srpaulo return NULL; 72214501Srpaulo data->state = GPSK_1; 73214501Srpaulo 74214501Srpaulo /* TODO: add support for configuring ID_Server */ 75214501Srpaulo data->id_server = (u8 *) os_strdup("hostapd"); 76214501Srpaulo if (data->id_server) 77214501Srpaulo data->id_server_len = os_strlen((char *) data->id_server); 78214501Srpaulo 79214501Srpaulo data->csuite_count = 0; 80214501Srpaulo if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF, 81214501Srpaulo EAP_GPSK_CIPHER_AES)) { 82214501Srpaulo WPA_PUT_BE32(data->csuite_list[data->csuite_count].vendor, 83214501Srpaulo EAP_GPSK_VENDOR_IETF); 84214501Srpaulo WPA_PUT_BE16(data->csuite_list[data->csuite_count].specifier, 85214501Srpaulo EAP_GPSK_CIPHER_AES); 86214501Srpaulo data->csuite_count++; 87214501Srpaulo } 88214501Srpaulo if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF, 89214501Srpaulo EAP_GPSK_CIPHER_SHA256)) { 90214501Srpaulo WPA_PUT_BE32(data->csuite_list[data->csuite_count].vendor, 91214501Srpaulo EAP_GPSK_VENDOR_IETF); 92214501Srpaulo WPA_PUT_BE16(data->csuite_list[data->csuite_count].specifier, 93214501Srpaulo EAP_GPSK_CIPHER_SHA256); 94214501Srpaulo data->csuite_count++; 95214501Srpaulo } 96214501Srpaulo 97214501Srpaulo return data; 98214501Srpaulo} 99214501Srpaulo 100214501Srpaulo 101214501Srpaulostatic void eap_gpsk_reset(struct eap_sm *sm, void *priv) 102214501Srpaulo{ 103214501Srpaulo struct eap_gpsk_data *data = priv; 104214501Srpaulo os_free(data->id_server); 105214501Srpaulo os_free(data->id_peer); 106214501Srpaulo os_free(data); 107214501Srpaulo} 108214501Srpaulo 109214501Srpaulo 110214501Srpaulostatic struct wpabuf * eap_gpsk_build_gpsk_1(struct eap_sm *sm, 111214501Srpaulo struct eap_gpsk_data *data, u8 id) 112214501Srpaulo{ 113214501Srpaulo size_t len; 114214501Srpaulo struct wpabuf *req; 115214501Srpaulo 116214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-1"); 117214501Srpaulo 118252726Srpaulo if (random_get_bytes(data->rand_server, EAP_GPSK_RAND_LEN)) { 119214501Srpaulo wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to get random data"); 120214501Srpaulo eap_gpsk_state(data, FAILURE); 121214501Srpaulo return NULL; 122214501Srpaulo } 123214501Srpaulo wpa_hexdump(MSG_MSGDUMP, "EAP-GPSK: RAND_Server", 124214501Srpaulo data->rand_server, EAP_GPSK_RAND_LEN); 125214501Srpaulo 126214501Srpaulo len = 1 + 2 + data->id_server_len + EAP_GPSK_RAND_LEN + 2 + 127214501Srpaulo data->csuite_count * sizeof(struct eap_gpsk_csuite); 128214501Srpaulo req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len, 129214501Srpaulo EAP_CODE_REQUEST, id); 130214501Srpaulo if (req == NULL) { 131214501Srpaulo wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to allocate memory " 132214501Srpaulo "for request/GPSK-1"); 133214501Srpaulo eap_gpsk_state(data, FAILURE); 134214501Srpaulo return NULL; 135214501Srpaulo } 136214501Srpaulo 137214501Srpaulo wpabuf_put_u8(req, EAP_GPSK_OPCODE_GPSK_1); 138214501Srpaulo wpabuf_put_be16(req, data->id_server_len); 139214501Srpaulo wpabuf_put_data(req, data->id_server, data->id_server_len); 140214501Srpaulo wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN); 141214501Srpaulo wpabuf_put_be16(req, 142214501Srpaulo data->csuite_count * sizeof(struct eap_gpsk_csuite)); 143214501Srpaulo wpabuf_put_data(req, data->csuite_list, 144214501Srpaulo data->csuite_count * sizeof(struct eap_gpsk_csuite)); 145214501Srpaulo 146214501Srpaulo return req; 147214501Srpaulo} 148214501Srpaulo 149214501Srpaulo 150214501Srpaulostatic struct wpabuf * eap_gpsk_build_gpsk_3(struct eap_sm *sm, 151214501Srpaulo struct eap_gpsk_data *data, u8 id) 152214501Srpaulo{ 153214501Srpaulo u8 *pos, *start; 154214501Srpaulo size_t len, miclen; 155214501Srpaulo struct eap_gpsk_csuite *csuite; 156214501Srpaulo struct wpabuf *req; 157214501Srpaulo 158214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-3"); 159214501Srpaulo 160214501Srpaulo miclen = eap_gpsk_mic_len(data->vendor, data->specifier); 161214501Srpaulo len = 1 + 2 * EAP_GPSK_RAND_LEN + 2 + data->id_server_len + 162214501Srpaulo sizeof(struct eap_gpsk_csuite) + 2 + miclen; 163214501Srpaulo req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len, 164214501Srpaulo EAP_CODE_REQUEST, id); 165214501Srpaulo if (req == NULL) { 166214501Srpaulo wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to allocate memory " 167214501Srpaulo "for request/GPSK-3"); 168214501Srpaulo eap_gpsk_state(data, FAILURE); 169214501Srpaulo return NULL; 170214501Srpaulo } 171214501Srpaulo 172214501Srpaulo wpabuf_put_u8(req, EAP_GPSK_OPCODE_GPSK_3); 173214501Srpaulo start = wpabuf_put(req, 0); 174214501Srpaulo 175214501Srpaulo wpabuf_put_data(req, data->rand_peer, EAP_GPSK_RAND_LEN); 176214501Srpaulo wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN); 177214501Srpaulo wpabuf_put_be16(req, data->id_server_len); 178214501Srpaulo wpabuf_put_data(req, data->id_server, data->id_server_len); 179214501Srpaulo csuite = wpabuf_put(req, sizeof(*csuite)); 180214501Srpaulo WPA_PUT_BE32(csuite->vendor, data->vendor); 181214501Srpaulo WPA_PUT_BE16(csuite->specifier, data->specifier); 182214501Srpaulo 183214501Srpaulo /* no PD_Payload_2 */ 184214501Srpaulo wpabuf_put_be16(req, 0); 185214501Srpaulo 186214501Srpaulo pos = wpabuf_put(req, miclen); 187214501Srpaulo if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor, 188214501Srpaulo data->specifier, start, pos - start, pos) < 0) 189214501Srpaulo { 190214501Srpaulo os_free(req); 191214501Srpaulo eap_gpsk_state(data, FAILURE); 192214501Srpaulo return NULL; 193214501Srpaulo } 194214501Srpaulo 195214501Srpaulo return req; 196214501Srpaulo} 197214501Srpaulo 198214501Srpaulo 199214501Srpaulostatic struct wpabuf * eap_gpsk_buildReq(struct eap_sm *sm, void *priv, u8 id) 200214501Srpaulo{ 201214501Srpaulo struct eap_gpsk_data *data = priv; 202214501Srpaulo 203214501Srpaulo switch (data->state) { 204214501Srpaulo case GPSK_1: 205214501Srpaulo return eap_gpsk_build_gpsk_1(sm, data, id); 206214501Srpaulo case GPSK_3: 207214501Srpaulo return eap_gpsk_build_gpsk_3(sm, data, id); 208214501Srpaulo default: 209214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown state %d in buildReq", 210214501Srpaulo data->state); 211214501Srpaulo break; 212214501Srpaulo } 213214501Srpaulo return NULL; 214214501Srpaulo} 215214501Srpaulo 216214501Srpaulo 217214501Srpaulostatic Boolean eap_gpsk_check(struct eap_sm *sm, void *priv, 218214501Srpaulo struct wpabuf *respData) 219214501Srpaulo{ 220214501Srpaulo struct eap_gpsk_data *data = priv; 221214501Srpaulo const u8 *pos; 222214501Srpaulo size_t len; 223214501Srpaulo 224214501Srpaulo pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, respData, &len); 225214501Srpaulo if (pos == NULL || len < 1) { 226214501Srpaulo wpa_printf(MSG_INFO, "EAP-GPSK: Invalid frame"); 227214501Srpaulo return TRUE; 228214501Srpaulo } 229214501Srpaulo 230214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode=%d", *pos); 231214501Srpaulo 232214501Srpaulo if (data->state == GPSK_1 && *pos == EAP_GPSK_OPCODE_GPSK_2) 233214501Srpaulo return FALSE; 234214501Srpaulo 235214501Srpaulo if (data->state == GPSK_3 && *pos == EAP_GPSK_OPCODE_GPSK_4) 236214501Srpaulo return FALSE; 237214501Srpaulo 238214501Srpaulo wpa_printf(MSG_INFO, "EAP-GPSK: Unexpected opcode=%d in state=%d", 239214501Srpaulo *pos, data->state); 240214501Srpaulo 241214501Srpaulo return TRUE; 242214501Srpaulo} 243214501Srpaulo 244214501Srpaulo 245214501Srpaulostatic void eap_gpsk_process_gpsk_2(struct eap_sm *sm, 246214501Srpaulo struct eap_gpsk_data *data, 247214501Srpaulo const u8 *payload, size_t payloadlen) 248214501Srpaulo{ 249214501Srpaulo const u8 *pos, *end; 250214501Srpaulo u16 alen; 251214501Srpaulo const struct eap_gpsk_csuite *csuite; 252214501Srpaulo size_t i, miclen; 253214501Srpaulo u8 mic[EAP_GPSK_MAX_MIC_LEN]; 254214501Srpaulo 255214501Srpaulo if (data->state != GPSK_1) 256214501Srpaulo return; 257214501Srpaulo 258214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Response/GPSK-2"); 259214501Srpaulo 260214501Srpaulo pos = payload; 261214501Srpaulo end = payload + payloadlen; 262214501Srpaulo 263214501Srpaulo if (end - pos < 2) { 264214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 265214501Srpaulo "ID_Peer length"); 266214501Srpaulo eap_gpsk_state(data, FAILURE); 267214501Srpaulo return; 268214501Srpaulo } 269214501Srpaulo alen = WPA_GET_BE16(pos); 270214501Srpaulo pos += 2; 271214501Srpaulo if (end - pos < alen) { 272214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 273214501Srpaulo "ID_Peer"); 274214501Srpaulo eap_gpsk_state(data, FAILURE); 275214501Srpaulo return; 276214501Srpaulo } 277214501Srpaulo os_free(data->id_peer); 278214501Srpaulo data->id_peer = os_malloc(alen); 279214501Srpaulo if (data->id_peer == NULL) { 280214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Not enough memory to store " 281214501Srpaulo "%d-octet ID_Peer", alen); 282214501Srpaulo return; 283214501Srpaulo } 284214501Srpaulo os_memcpy(data->id_peer, pos, alen); 285214501Srpaulo data->id_peer_len = alen; 286214501Srpaulo wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Peer", 287214501Srpaulo data->id_peer, data->id_peer_len); 288214501Srpaulo pos += alen; 289214501Srpaulo 290214501Srpaulo if (end - pos < 2) { 291214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 292214501Srpaulo "ID_Server length"); 293214501Srpaulo eap_gpsk_state(data, FAILURE); 294214501Srpaulo return; 295214501Srpaulo } 296214501Srpaulo alen = WPA_GET_BE16(pos); 297214501Srpaulo pos += 2; 298214501Srpaulo if (end - pos < alen) { 299214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 300214501Srpaulo "ID_Server"); 301214501Srpaulo eap_gpsk_state(data, FAILURE); 302214501Srpaulo return; 303214501Srpaulo } 304214501Srpaulo if (alen != data->id_server_len || 305214501Srpaulo os_memcmp(pos, data->id_server, alen) != 0) { 306214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1 and " 307214501Srpaulo "GPSK-2 did not match"); 308214501Srpaulo eap_gpsk_state(data, FAILURE); 309214501Srpaulo return; 310214501Srpaulo } 311214501Srpaulo pos += alen; 312214501Srpaulo 313214501Srpaulo if (end - pos < EAP_GPSK_RAND_LEN) { 314214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 315214501Srpaulo "RAND_Peer"); 316214501Srpaulo eap_gpsk_state(data, FAILURE); 317214501Srpaulo return; 318214501Srpaulo } 319214501Srpaulo os_memcpy(data->rand_peer, pos, EAP_GPSK_RAND_LEN); 320214501Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer", 321214501Srpaulo data->rand_peer, EAP_GPSK_RAND_LEN); 322214501Srpaulo pos += EAP_GPSK_RAND_LEN; 323214501Srpaulo 324214501Srpaulo if (end - pos < EAP_GPSK_RAND_LEN) { 325214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 326214501Srpaulo "RAND_Server"); 327214501Srpaulo eap_gpsk_state(data, FAILURE); 328214501Srpaulo return; 329214501Srpaulo } 330214501Srpaulo if (os_memcmp(data->rand_server, pos, EAP_GPSK_RAND_LEN) != 0) { 331214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and " 332214501Srpaulo "GPSK-2 did not match"); 333214501Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1", 334214501Srpaulo data->rand_server, EAP_GPSK_RAND_LEN); 335214501Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-2", 336214501Srpaulo pos, EAP_GPSK_RAND_LEN); 337214501Srpaulo eap_gpsk_state(data, FAILURE); 338214501Srpaulo return; 339214501Srpaulo } 340214501Srpaulo pos += EAP_GPSK_RAND_LEN; 341214501Srpaulo 342214501Srpaulo if (end - pos < 2) { 343214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 344214501Srpaulo "CSuite_List length"); 345214501Srpaulo eap_gpsk_state(data, FAILURE); 346214501Srpaulo return; 347214501Srpaulo } 348214501Srpaulo alen = WPA_GET_BE16(pos); 349214501Srpaulo pos += 2; 350214501Srpaulo if (end - pos < alen) { 351214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 352214501Srpaulo "CSuite_List"); 353214501Srpaulo eap_gpsk_state(data, FAILURE); 354214501Srpaulo return; 355214501Srpaulo } 356214501Srpaulo if (alen != data->csuite_count * sizeof(struct eap_gpsk_csuite) || 357214501Srpaulo os_memcmp(pos, data->csuite_list, alen) != 0) { 358214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List in GPSK-1 and " 359214501Srpaulo "GPSK-2 did not match"); 360214501Srpaulo eap_gpsk_state(data, FAILURE); 361214501Srpaulo return; 362214501Srpaulo } 363214501Srpaulo pos += alen; 364214501Srpaulo 365214501Srpaulo if (end - pos < (int) sizeof(*csuite)) { 366214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 367214501Srpaulo "CSuite_Sel"); 368214501Srpaulo eap_gpsk_state(data, FAILURE); 369214501Srpaulo return; 370214501Srpaulo } 371214501Srpaulo csuite = (const struct eap_gpsk_csuite *) pos; 372214501Srpaulo for (i = 0; i < data->csuite_count; i++) { 373214501Srpaulo if (os_memcmp(csuite, &data->csuite_list[i], sizeof(*csuite)) 374214501Srpaulo == 0) 375214501Srpaulo break; 376214501Srpaulo } 377214501Srpaulo if (i == data->csuite_count) { 378214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Peer selected unsupported " 379214501Srpaulo "ciphersuite %d:%d", 380214501Srpaulo WPA_GET_BE32(csuite->vendor), 381214501Srpaulo WPA_GET_BE16(csuite->specifier)); 382214501Srpaulo eap_gpsk_state(data, FAILURE); 383214501Srpaulo return; 384214501Srpaulo } 385214501Srpaulo data->vendor = WPA_GET_BE32(csuite->vendor); 386214501Srpaulo data->specifier = WPA_GET_BE16(csuite->specifier); 387214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel %d:%d", 388214501Srpaulo data->vendor, data->specifier); 389214501Srpaulo pos += sizeof(*csuite); 390214501Srpaulo 391214501Srpaulo if (end - pos < 2) { 392214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 393214501Srpaulo "PD_Payload_1 length"); 394214501Srpaulo eap_gpsk_state(data, FAILURE); 395214501Srpaulo return; 396214501Srpaulo } 397214501Srpaulo alen = WPA_GET_BE16(pos); 398214501Srpaulo pos += 2; 399214501Srpaulo if (end - pos < alen) { 400214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 401214501Srpaulo "PD_Payload_1"); 402214501Srpaulo eap_gpsk_state(data, FAILURE); 403214501Srpaulo return; 404214501Srpaulo } 405214501Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_1", pos, alen); 406214501Srpaulo pos += alen; 407214501Srpaulo 408214501Srpaulo if (sm->user == NULL || sm->user->password == NULL) { 409214501Srpaulo wpa_printf(MSG_INFO, "EAP-GPSK: No PSK/password configured " 410214501Srpaulo "for the user"); 411214501Srpaulo eap_gpsk_state(data, FAILURE); 412214501Srpaulo return; 413214501Srpaulo } 414214501Srpaulo 415214501Srpaulo if (eap_gpsk_derive_keys(sm->user->password, sm->user->password_len, 416214501Srpaulo data->vendor, data->specifier, 417214501Srpaulo data->rand_peer, data->rand_server, 418214501Srpaulo data->id_peer, data->id_peer_len, 419214501Srpaulo data->id_server, data->id_server_len, 420214501Srpaulo data->msk, data->emsk, 421214501Srpaulo data->sk, &data->sk_len, 422214501Srpaulo data->pk, &data->pk_len) < 0) { 423214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys"); 424214501Srpaulo eap_gpsk_state(data, FAILURE); 425214501Srpaulo return; 426214501Srpaulo } 427214501Srpaulo 428214501Srpaulo miclen = eap_gpsk_mic_len(data->vendor, data->specifier); 429214501Srpaulo if (end - pos < (int) miclen) { 430214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC " 431214501Srpaulo "(left=%lu miclen=%lu)", 432214501Srpaulo (unsigned long) (end - pos), 433214501Srpaulo (unsigned long) miclen); 434214501Srpaulo eap_gpsk_state(data, FAILURE); 435214501Srpaulo return; 436214501Srpaulo } 437214501Srpaulo if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor, 438214501Srpaulo data->specifier, payload, pos - payload, mic) 439214501Srpaulo < 0) { 440214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC"); 441214501Srpaulo eap_gpsk_state(data, FAILURE); 442214501Srpaulo return; 443214501Srpaulo } 444214501Srpaulo if (os_memcmp(mic, pos, miclen) != 0) { 445214501Srpaulo wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-2"); 446214501Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen); 447214501Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen); 448214501Srpaulo eap_gpsk_state(data, FAILURE); 449214501Srpaulo return; 450214501Srpaulo } 451214501Srpaulo pos += miclen; 452214501Srpaulo 453214501Srpaulo if (pos != end) { 454214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra " 455214501Srpaulo "data in the end of GPSK-2", 456214501Srpaulo (unsigned long) (end - pos)); 457214501Srpaulo } 458214501Srpaulo 459214501Srpaulo eap_gpsk_state(data, GPSK_3); 460214501Srpaulo} 461214501Srpaulo 462214501Srpaulo 463214501Srpaulostatic void eap_gpsk_process_gpsk_4(struct eap_sm *sm, 464214501Srpaulo struct eap_gpsk_data *data, 465214501Srpaulo const u8 *payload, size_t payloadlen) 466214501Srpaulo{ 467214501Srpaulo const u8 *pos, *end; 468214501Srpaulo u16 alen; 469214501Srpaulo size_t miclen; 470214501Srpaulo u8 mic[EAP_GPSK_MAX_MIC_LEN]; 471214501Srpaulo 472214501Srpaulo if (data->state != GPSK_3) 473214501Srpaulo return; 474214501Srpaulo 475214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Response/GPSK-4"); 476214501Srpaulo 477214501Srpaulo pos = payload; 478214501Srpaulo end = payload + payloadlen; 479214501Srpaulo 480214501Srpaulo if (end - pos < 2) { 481214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 482214501Srpaulo "PD_Payload_1 length"); 483214501Srpaulo eap_gpsk_state(data, FAILURE); 484214501Srpaulo return; 485214501Srpaulo } 486214501Srpaulo alen = WPA_GET_BE16(pos); 487214501Srpaulo pos += 2; 488214501Srpaulo if (end - pos < alen) { 489214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 490214501Srpaulo "PD_Payload_1"); 491214501Srpaulo eap_gpsk_state(data, FAILURE); 492214501Srpaulo return; 493214501Srpaulo } 494214501Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_1", pos, alen); 495214501Srpaulo pos += alen; 496214501Srpaulo 497214501Srpaulo miclen = eap_gpsk_mic_len(data->vendor, data->specifier); 498214501Srpaulo if (end - pos < (int) miclen) { 499214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC " 500214501Srpaulo "(left=%lu miclen=%lu)", 501214501Srpaulo (unsigned long) (end - pos), 502214501Srpaulo (unsigned long) miclen); 503214501Srpaulo eap_gpsk_state(data, FAILURE); 504214501Srpaulo return; 505214501Srpaulo } 506214501Srpaulo if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor, 507214501Srpaulo data->specifier, payload, pos - payload, mic) 508214501Srpaulo < 0) { 509214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC"); 510214501Srpaulo eap_gpsk_state(data, FAILURE); 511214501Srpaulo return; 512214501Srpaulo } 513214501Srpaulo if (os_memcmp(mic, pos, miclen) != 0) { 514214501Srpaulo wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-4"); 515214501Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen); 516214501Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen); 517214501Srpaulo eap_gpsk_state(data, FAILURE); 518214501Srpaulo return; 519214501Srpaulo } 520214501Srpaulo pos += miclen; 521214501Srpaulo 522214501Srpaulo if (pos != end) { 523214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra " 524214501Srpaulo "data in the end of GPSK-4", 525214501Srpaulo (unsigned long) (end - pos)); 526214501Srpaulo } 527214501Srpaulo 528214501Srpaulo eap_gpsk_state(data, SUCCESS); 529214501Srpaulo} 530214501Srpaulo 531214501Srpaulo 532214501Srpaulostatic void eap_gpsk_process(struct eap_sm *sm, void *priv, 533214501Srpaulo struct wpabuf *respData) 534214501Srpaulo{ 535214501Srpaulo struct eap_gpsk_data *data = priv; 536214501Srpaulo const u8 *pos; 537214501Srpaulo size_t len; 538214501Srpaulo 539214501Srpaulo pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, respData, &len); 540214501Srpaulo if (pos == NULL || len < 1) 541214501Srpaulo return; 542214501Srpaulo 543214501Srpaulo switch (*pos) { 544214501Srpaulo case EAP_GPSK_OPCODE_GPSK_2: 545214501Srpaulo eap_gpsk_process_gpsk_2(sm, data, pos + 1, len - 1); 546214501Srpaulo break; 547214501Srpaulo case EAP_GPSK_OPCODE_GPSK_4: 548214501Srpaulo eap_gpsk_process_gpsk_4(sm, data, pos + 1, len - 1); 549214501Srpaulo break; 550214501Srpaulo } 551214501Srpaulo} 552214501Srpaulo 553214501Srpaulo 554214501Srpaulostatic Boolean eap_gpsk_isDone(struct eap_sm *sm, void *priv) 555214501Srpaulo{ 556214501Srpaulo struct eap_gpsk_data *data = priv; 557214501Srpaulo return data->state == SUCCESS || data->state == FAILURE; 558214501Srpaulo} 559214501Srpaulo 560214501Srpaulo 561214501Srpaulostatic u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len) 562214501Srpaulo{ 563214501Srpaulo struct eap_gpsk_data *data = priv; 564214501Srpaulo u8 *key; 565214501Srpaulo 566214501Srpaulo if (data->state != SUCCESS) 567214501Srpaulo return NULL; 568214501Srpaulo 569214501Srpaulo key = os_malloc(EAP_MSK_LEN); 570214501Srpaulo if (key == NULL) 571214501Srpaulo return NULL; 572214501Srpaulo os_memcpy(key, data->msk, EAP_MSK_LEN); 573214501Srpaulo *len = EAP_MSK_LEN; 574214501Srpaulo 575214501Srpaulo return key; 576214501Srpaulo} 577214501Srpaulo 578214501Srpaulo 579214501Srpaulostatic u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 580214501Srpaulo{ 581214501Srpaulo struct eap_gpsk_data *data = priv; 582214501Srpaulo u8 *key; 583214501Srpaulo 584214501Srpaulo if (data->state != SUCCESS) 585214501Srpaulo return NULL; 586214501Srpaulo 587214501Srpaulo key = os_malloc(EAP_EMSK_LEN); 588214501Srpaulo if (key == NULL) 589214501Srpaulo return NULL; 590214501Srpaulo os_memcpy(key, data->emsk, EAP_EMSK_LEN); 591214501Srpaulo *len = EAP_EMSK_LEN; 592214501Srpaulo 593214501Srpaulo return key; 594214501Srpaulo} 595214501Srpaulo 596214501Srpaulo 597214501Srpaulostatic Boolean eap_gpsk_isSuccess(struct eap_sm *sm, void *priv) 598214501Srpaulo{ 599214501Srpaulo struct eap_gpsk_data *data = priv; 600214501Srpaulo return data->state == SUCCESS; 601214501Srpaulo} 602214501Srpaulo 603214501Srpaulo 604214501Srpauloint eap_server_gpsk_register(void) 605214501Srpaulo{ 606214501Srpaulo struct eap_method *eap; 607214501Srpaulo int ret; 608214501Srpaulo 609214501Srpaulo eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 610214501Srpaulo EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK"); 611214501Srpaulo if (eap == NULL) 612214501Srpaulo return -1; 613214501Srpaulo 614214501Srpaulo eap->init = eap_gpsk_init; 615214501Srpaulo eap->reset = eap_gpsk_reset; 616214501Srpaulo eap->buildReq = eap_gpsk_buildReq; 617214501Srpaulo eap->check = eap_gpsk_check; 618214501Srpaulo eap->process = eap_gpsk_process; 619214501Srpaulo eap->isDone = eap_gpsk_isDone; 620214501Srpaulo eap->getKey = eap_gpsk_getKey; 621214501Srpaulo eap->isSuccess = eap_gpsk_isSuccess; 622214501Srpaulo eap->get_emsk = eap_gpsk_get_emsk; 623214501Srpaulo 624214501Srpaulo ret = eap_server_method_register(eap); 625214501Srpaulo if (ret) 626214501Srpaulo eap_server_method_free(eap); 627214501Srpaulo return ret; 628214501Srpaulo} 629