eap_server_gpsk.c revision 337817
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; 27281806Srpaulo u8 session_id[128]; 28281806Srpaulo size_t id_len; 29214501Srpaulo u8 *id_peer; 30214501Srpaulo size_t id_peer_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 data->csuite_count = 0; 75214501Srpaulo if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF, 76214501Srpaulo EAP_GPSK_CIPHER_AES)) { 77214501Srpaulo WPA_PUT_BE32(data->csuite_list[data->csuite_count].vendor, 78214501Srpaulo EAP_GPSK_VENDOR_IETF); 79214501Srpaulo WPA_PUT_BE16(data->csuite_list[data->csuite_count].specifier, 80214501Srpaulo EAP_GPSK_CIPHER_AES); 81214501Srpaulo data->csuite_count++; 82214501Srpaulo } 83214501Srpaulo if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF, 84214501Srpaulo EAP_GPSK_CIPHER_SHA256)) { 85214501Srpaulo WPA_PUT_BE32(data->csuite_list[data->csuite_count].vendor, 86214501Srpaulo EAP_GPSK_VENDOR_IETF); 87214501Srpaulo WPA_PUT_BE16(data->csuite_list[data->csuite_count].specifier, 88214501Srpaulo EAP_GPSK_CIPHER_SHA256); 89214501Srpaulo data->csuite_count++; 90214501Srpaulo } 91214501Srpaulo 92214501Srpaulo return data; 93214501Srpaulo} 94214501Srpaulo 95214501Srpaulo 96214501Srpaulostatic void eap_gpsk_reset(struct eap_sm *sm, void *priv) 97214501Srpaulo{ 98214501Srpaulo struct eap_gpsk_data *data = priv; 99214501Srpaulo os_free(data->id_peer); 100281806Srpaulo bin_clear_free(data, sizeof(*data)); 101214501Srpaulo} 102214501Srpaulo 103214501Srpaulo 104214501Srpaulostatic struct wpabuf * eap_gpsk_build_gpsk_1(struct eap_sm *sm, 105214501Srpaulo struct eap_gpsk_data *data, u8 id) 106214501Srpaulo{ 107214501Srpaulo size_t len; 108214501Srpaulo struct wpabuf *req; 109214501Srpaulo 110214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-1"); 111214501Srpaulo 112252726Srpaulo if (random_get_bytes(data->rand_server, EAP_GPSK_RAND_LEN)) { 113214501Srpaulo wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to get random data"); 114214501Srpaulo eap_gpsk_state(data, FAILURE); 115214501Srpaulo return NULL; 116214501Srpaulo } 117214501Srpaulo wpa_hexdump(MSG_MSGDUMP, "EAP-GPSK: RAND_Server", 118214501Srpaulo data->rand_server, EAP_GPSK_RAND_LEN); 119214501Srpaulo 120281806Srpaulo len = 1 + 2 + sm->server_id_len + EAP_GPSK_RAND_LEN + 2 + 121214501Srpaulo data->csuite_count * sizeof(struct eap_gpsk_csuite); 122214501Srpaulo req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len, 123214501Srpaulo EAP_CODE_REQUEST, id); 124214501Srpaulo if (req == NULL) { 125214501Srpaulo wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to allocate memory " 126214501Srpaulo "for request/GPSK-1"); 127214501Srpaulo eap_gpsk_state(data, FAILURE); 128214501Srpaulo return NULL; 129214501Srpaulo } 130214501Srpaulo 131214501Srpaulo wpabuf_put_u8(req, EAP_GPSK_OPCODE_GPSK_1); 132281806Srpaulo wpabuf_put_be16(req, sm->server_id_len); 133281806Srpaulo wpabuf_put_data(req, sm->server_id, sm->server_id_len); 134214501Srpaulo wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN); 135214501Srpaulo wpabuf_put_be16(req, 136214501Srpaulo data->csuite_count * sizeof(struct eap_gpsk_csuite)); 137214501Srpaulo wpabuf_put_data(req, data->csuite_list, 138214501Srpaulo data->csuite_count * sizeof(struct eap_gpsk_csuite)); 139214501Srpaulo 140214501Srpaulo return req; 141214501Srpaulo} 142214501Srpaulo 143214501Srpaulo 144214501Srpaulostatic struct wpabuf * eap_gpsk_build_gpsk_3(struct eap_sm *sm, 145214501Srpaulo struct eap_gpsk_data *data, u8 id) 146214501Srpaulo{ 147214501Srpaulo u8 *pos, *start; 148214501Srpaulo size_t len, miclen; 149214501Srpaulo struct eap_gpsk_csuite *csuite; 150214501Srpaulo struct wpabuf *req; 151214501Srpaulo 152214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-3"); 153214501Srpaulo 154214501Srpaulo miclen = eap_gpsk_mic_len(data->vendor, data->specifier); 155281806Srpaulo len = 1 + 2 * EAP_GPSK_RAND_LEN + 2 + sm->server_id_len + 156214501Srpaulo sizeof(struct eap_gpsk_csuite) + 2 + miclen; 157214501Srpaulo req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len, 158214501Srpaulo EAP_CODE_REQUEST, id); 159214501Srpaulo if (req == NULL) { 160214501Srpaulo wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to allocate memory " 161214501Srpaulo "for request/GPSK-3"); 162214501Srpaulo eap_gpsk_state(data, FAILURE); 163214501Srpaulo return NULL; 164214501Srpaulo } 165214501Srpaulo 166214501Srpaulo wpabuf_put_u8(req, EAP_GPSK_OPCODE_GPSK_3); 167214501Srpaulo start = wpabuf_put(req, 0); 168214501Srpaulo 169214501Srpaulo wpabuf_put_data(req, data->rand_peer, EAP_GPSK_RAND_LEN); 170214501Srpaulo wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN); 171281806Srpaulo wpabuf_put_be16(req, sm->server_id_len); 172281806Srpaulo wpabuf_put_data(req, sm->server_id, sm->server_id_len); 173214501Srpaulo csuite = wpabuf_put(req, sizeof(*csuite)); 174214501Srpaulo WPA_PUT_BE32(csuite->vendor, data->vendor); 175214501Srpaulo WPA_PUT_BE16(csuite->specifier, data->specifier); 176214501Srpaulo 177214501Srpaulo /* no PD_Payload_2 */ 178214501Srpaulo wpabuf_put_be16(req, 0); 179214501Srpaulo 180214501Srpaulo pos = wpabuf_put(req, miclen); 181214501Srpaulo if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor, 182214501Srpaulo data->specifier, start, pos - start, pos) < 0) 183214501Srpaulo { 184214501Srpaulo os_free(req); 185214501Srpaulo eap_gpsk_state(data, FAILURE); 186214501Srpaulo return NULL; 187214501Srpaulo } 188214501Srpaulo 189214501Srpaulo return req; 190214501Srpaulo} 191214501Srpaulo 192214501Srpaulo 193214501Srpaulostatic struct wpabuf * eap_gpsk_buildReq(struct eap_sm *sm, void *priv, u8 id) 194214501Srpaulo{ 195214501Srpaulo struct eap_gpsk_data *data = priv; 196214501Srpaulo 197214501Srpaulo switch (data->state) { 198214501Srpaulo case GPSK_1: 199214501Srpaulo return eap_gpsk_build_gpsk_1(sm, data, id); 200214501Srpaulo case GPSK_3: 201214501Srpaulo return eap_gpsk_build_gpsk_3(sm, data, id); 202214501Srpaulo default: 203214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown state %d in buildReq", 204214501Srpaulo data->state); 205214501Srpaulo break; 206214501Srpaulo } 207214501Srpaulo return NULL; 208214501Srpaulo} 209214501Srpaulo 210214501Srpaulo 211214501Srpaulostatic Boolean eap_gpsk_check(struct eap_sm *sm, void *priv, 212214501Srpaulo struct wpabuf *respData) 213214501Srpaulo{ 214214501Srpaulo struct eap_gpsk_data *data = priv; 215214501Srpaulo const u8 *pos; 216214501Srpaulo size_t len; 217214501Srpaulo 218214501Srpaulo pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, respData, &len); 219214501Srpaulo if (pos == NULL || len < 1) { 220214501Srpaulo wpa_printf(MSG_INFO, "EAP-GPSK: Invalid frame"); 221214501Srpaulo return TRUE; 222214501Srpaulo } 223214501Srpaulo 224214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode=%d", *pos); 225214501Srpaulo 226214501Srpaulo if (data->state == GPSK_1 && *pos == EAP_GPSK_OPCODE_GPSK_2) 227214501Srpaulo return FALSE; 228214501Srpaulo 229214501Srpaulo if (data->state == GPSK_3 && *pos == EAP_GPSK_OPCODE_GPSK_4) 230214501Srpaulo return FALSE; 231214501Srpaulo 232214501Srpaulo wpa_printf(MSG_INFO, "EAP-GPSK: Unexpected opcode=%d in state=%d", 233214501Srpaulo *pos, data->state); 234214501Srpaulo 235214501Srpaulo return TRUE; 236214501Srpaulo} 237214501Srpaulo 238214501Srpaulo 239214501Srpaulostatic void eap_gpsk_process_gpsk_2(struct eap_sm *sm, 240214501Srpaulo struct eap_gpsk_data *data, 241214501Srpaulo const u8 *payload, size_t payloadlen) 242214501Srpaulo{ 243214501Srpaulo const u8 *pos, *end; 244214501Srpaulo u16 alen; 245214501Srpaulo const struct eap_gpsk_csuite *csuite; 246214501Srpaulo size_t i, miclen; 247214501Srpaulo u8 mic[EAP_GPSK_MAX_MIC_LEN]; 248214501Srpaulo 249214501Srpaulo if (data->state != GPSK_1) 250214501Srpaulo return; 251214501Srpaulo 252214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Response/GPSK-2"); 253214501Srpaulo 254214501Srpaulo pos = payload; 255214501Srpaulo end = payload + payloadlen; 256214501Srpaulo 257214501Srpaulo if (end - pos < 2) { 258214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 259214501Srpaulo "ID_Peer length"); 260214501Srpaulo eap_gpsk_state(data, FAILURE); 261214501Srpaulo return; 262214501Srpaulo } 263214501Srpaulo alen = WPA_GET_BE16(pos); 264214501Srpaulo pos += 2; 265214501Srpaulo if (end - pos < alen) { 266214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 267214501Srpaulo "ID_Peer"); 268214501Srpaulo eap_gpsk_state(data, FAILURE); 269214501Srpaulo return; 270214501Srpaulo } 271214501Srpaulo os_free(data->id_peer); 272214501Srpaulo data->id_peer = os_malloc(alen); 273214501Srpaulo if (data->id_peer == NULL) { 274214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Not enough memory to store " 275214501Srpaulo "%d-octet ID_Peer", alen); 276214501Srpaulo return; 277214501Srpaulo } 278214501Srpaulo os_memcpy(data->id_peer, pos, alen); 279214501Srpaulo data->id_peer_len = alen; 280214501Srpaulo wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Peer", 281214501Srpaulo data->id_peer, data->id_peer_len); 282214501Srpaulo pos += alen; 283214501Srpaulo 284214501Srpaulo if (end - pos < 2) { 285214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 286214501Srpaulo "ID_Server length"); 287214501Srpaulo eap_gpsk_state(data, FAILURE); 288214501Srpaulo return; 289214501Srpaulo } 290214501Srpaulo alen = WPA_GET_BE16(pos); 291214501Srpaulo pos += 2; 292214501Srpaulo if (end - pos < alen) { 293214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 294214501Srpaulo "ID_Server"); 295214501Srpaulo eap_gpsk_state(data, FAILURE); 296214501Srpaulo return; 297214501Srpaulo } 298281806Srpaulo if (alen != sm->server_id_len || 299281806Srpaulo os_memcmp(pos, sm->server_id, alen) != 0) { 300214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1 and " 301214501Srpaulo "GPSK-2 did not match"); 302214501Srpaulo eap_gpsk_state(data, FAILURE); 303214501Srpaulo return; 304214501Srpaulo } 305214501Srpaulo pos += alen; 306214501Srpaulo 307214501Srpaulo if (end - pos < EAP_GPSK_RAND_LEN) { 308214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 309214501Srpaulo "RAND_Peer"); 310214501Srpaulo eap_gpsk_state(data, FAILURE); 311214501Srpaulo return; 312214501Srpaulo } 313214501Srpaulo os_memcpy(data->rand_peer, pos, EAP_GPSK_RAND_LEN); 314214501Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer", 315214501Srpaulo data->rand_peer, EAP_GPSK_RAND_LEN); 316214501Srpaulo pos += EAP_GPSK_RAND_LEN; 317214501Srpaulo 318214501Srpaulo if (end - pos < EAP_GPSK_RAND_LEN) { 319214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 320214501Srpaulo "RAND_Server"); 321214501Srpaulo eap_gpsk_state(data, FAILURE); 322214501Srpaulo return; 323214501Srpaulo } 324214501Srpaulo if (os_memcmp(data->rand_server, pos, EAP_GPSK_RAND_LEN) != 0) { 325214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and " 326214501Srpaulo "GPSK-2 did not match"); 327214501Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1", 328214501Srpaulo data->rand_server, EAP_GPSK_RAND_LEN); 329214501Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-2", 330214501Srpaulo pos, EAP_GPSK_RAND_LEN); 331214501Srpaulo eap_gpsk_state(data, FAILURE); 332214501Srpaulo return; 333214501Srpaulo } 334214501Srpaulo pos += EAP_GPSK_RAND_LEN; 335214501Srpaulo 336214501Srpaulo if (end - pos < 2) { 337214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 338214501Srpaulo "CSuite_List length"); 339214501Srpaulo eap_gpsk_state(data, FAILURE); 340214501Srpaulo return; 341214501Srpaulo } 342214501Srpaulo alen = WPA_GET_BE16(pos); 343214501Srpaulo pos += 2; 344214501Srpaulo if (end - pos < alen) { 345214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 346214501Srpaulo "CSuite_List"); 347214501Srpaulo eap_gpsk_state(data, FAILURE); 348214501Srpaulo return; 349214501Srpaulo } 350214501Srpaulo if (alen != data->csuite_count * sizeof(struct eap_gpsk_csuite) || 351214501Srpaulo os_memcmp(pos, data->csuite_list, alen) != 0) { 352214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List in GPSK-1 and " 353214501Srpaulo "GPSK-2 did not match"); 354214501Srpaulo eap_gpsk_state(data, FAILURE); 355214501Srpaulo return; 356214501Srpaulo } 357214501Srpaulo pos += alen; 358214501Srpaulo 359214501Srpaulo if (end - pos < (int) sizeof(*csuite)) { 360214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 361214501Srpaulo "CSuite_Sel"); 362214501Srpaulo eap_gpsk_state(data, FAILURE); 363214501Srpaulo return; 364214501Srpaulo } 365214501Srpaulo csuite = (const struct eap_gpsk_csuite *) pos; 366214501Srpaulo for (i = 0; i < data->csuite_count; i++) { 367214501Srpaulo if (os_memcmp(csuite, &data->csuite_list[i], sizeof(*csuite)) 368214501Srpaulo == 0) 369214501Srpaulo break; 370214501Srpaulo } 371214501Srpaulo if (i == data->csuite_count) { 372214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Peer selected unsupported " 373214501Srpaulo "ciphersuite %d:%d", 374214501Srpaulo WPA_GET_BE32(csuite->vendor), 375214501Srpaulo WPA_GET_BE16(csuite->specifier)); 376214501Srpaulo eap_gpsk_state(data, FAILURE); 377214501Srpaulo return; 378214501Srpaulo } 379214501Srpaulo data->vendor = WPA_GET_BE32(csuite->vendor); 380214501Srpaulo data->specifier = WPA_GET_BE16(csuite->specifier); 381214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel %d:%d", 382214501Srpaulo data->vendor, data->specifier); 383214501Srpaulo pos += sizeof(*csuite); 384214501Srpaulo 385214501Srpaulo if (end - pos < 2) { 386214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 387214501Srpaulo "PD_Payload_1 length"); 388214501Srpaulo eap_gpsk_state(data, FAILURE); 389214501Srpaulo return; 390214501Srpaulo } 391214501Srpaulo alen = WPA_GET_BE16(pos); 392214501Srpaulo pos += 2; 393214501Srpaulo if (end - pos < alen) { 394214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 395214501Srpaulo "PD_Payload_1"); 396214501Srpaulo eap_gpsk_state(data, FAILURE); 397214501Srpaulo return; 398214501Srpaulo } 399214501Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_1", pos, alen); 400214501Srpaulo pos += alen; 401214501Srpaulo 402214501Srpaulo if (sm->user == NULL || sm->user->password == NULL) { 403214501Srpaulo wpa_printf(MSG_INFO, "EAP-GPSK: No PSK/password configured " 404214501Srpaulo "for the user"); 405214501Srpaulo eap_gpsk_state(data, FAILURE); 406214501Srpaulo return; 407214501Srpaulo } 408214501Srpaulo 409214501Srpaulo if (eap_gpsk_derive_keys(sm->user->password, sm->user->password_len, 410214501Srpaulo data->vendor, data->specifier, 411214501Srpaulo data->rand_peer, data->rand_server, 412214501Srpaulo data->id_peer, data->id_peer_len, 413281806Srpaulo sm->server_id, sm->server_id_len, 414214501Srpaulo data->msk, data->emsk, 415214501Srpaulo data->sk, &data->sk_len, 416214501Srpaulo data->pk, &data->pk_len) < 0) { 417214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys"); 418214501Srpaulo eap_gpsk_state(data, FAILURE); 419214501Srpaulo return; 420214501Srpaulo } 421214501Srpaulo 422281806Srpaulo if (eap_gpsk_derive_session_id(sm->user->password, 423281806Srpaulo sm->user->password_len, 424281806Srpaulo data->vendor, data->specifier, 425281806Srpaulo data->rand_peer, data->rand_server, 426281806Srpaulo data->id_peer, data->id_peer_len, 427281806Srpaulo sm->server_id, sm->server_id_len, 428281806Srpaulo EAP_TYPE_GPSK, 429281806Srpaulo data->session_id, &data->id_len) < 0) { 430281806Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive Session-Id"); 431281806Srpaulo eap_gpsk_state(data, FAILURE); 432281806Srpaulo return; 433281806Srpaulo } 434281806Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Derived Session-Id", 435281806Srpaulo data->session_id, data->id_len); 436281806Srpaulo 437214501Srpaulo miclen = eap_gpsk_mic_len(data->vendor, data->specifier); 438214501Srpaulo if (end - pos < (int) miclen) { 439214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC " 440214501Srpaulo "(left=%lu miclen=%lu)", 441214501Srpaulo (unsigned long) (end - pos), 442214501Srpaulo (unsigned long) miclen); 443214501Srpaulo eap_gpsk_state(data, FAILURE); 444214501Srpaulo return; 445214501Srpaulo } 446214501Srpaulo if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor, 447214501Srpaulo data->specifier, payload, pos - payload, mic) 448214501Srpaulo < 0) { 449214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC"); 450214501Srpaulo eap_gpsk_state(data, FAILURE); 451214501Srpaulo return; 452214501Srpaulo } 453281806Srpaulo if (os_memcmp_const(mic, pos, miclen) != 0) { 454214501Srpaulo wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-2"); 455214501Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen); 456214501Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen); 457214501Srpaulo eap_gpsk_state(data, FAILURE); 458214501Srpaulo return; 459214501Srpaulo } 460214501Srpaulo pos += miclen; 461214501Srpaulo 462214501Srpaulo if (pos != end) { 463214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra " 464214501Srpaulo "data in the end of GPSK-2", 465214501Srpaulo (unsigned long) (end - pos)); 466214501Srpaulo } 467214501Srpaulo 468214501Srpaulo eap_gpsk_state(data, GPSK_3); 469214501Srpaulo} 470214501Srpaulo 471214501Srpaulo 472214501Srpaulostatic void eap_gpsk_process_gpsk_4(struct eap_sm *sm, 473214501Srpaulo struct eap_gpsk_data *data, 474214501Srpaulo const u8 *payload, size_t payloadlen) 475214501Srpaulo{ 476214501Srpaulo const u8 *pos, *end; 477214501Srpaulo u16 alen; 478214501Srpaulo size_t miclen; 479214501Srpaulo u8 mic[EAP_GPSK_MAX_MIC_LEN]; 480214501Srpaulo 481214501Srpaulo if (data->state != GPSK_3) 482214501Srpaulo return; 483214501Srpaulo 484214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Response/GPSK-4"); 485214501Srpaulo 486214501Srpaulo pos = payload; 487214501Srpaulo end = payload + payloadlen; 488214501Srpaulo 489214501Srpaulo if (end - pos < 2) { 490214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 491214501Srpaulo "PD_Payload_1 length"); 492214501Srpaulo eap_gpsk_state(data, FAILURE); 493214501Srpaulo return; 494214501Srpaulo } 495214501Srpaulo alen = WPA_GET_BE16(pos); 496214501Srpaulo pos += 2; 497214501Srpaulo if (end - pos < alen) { 498214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 499214501Srpaulo "PD_Payload_1"); 500214501Srpaulo eap_gpsk_state(data, FAILURE); 501214501Srpaulo return; 502214501Srpaulo } 503214501Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_1", pos, alen); 504214501Srpaulo pos += alen; 505214501Srpaulo 506214501Srpaulo miclen = eap_gpsk_mic_len(data->vendor, data->specifier); 507214501Srpaulo if (end - pos < (int) miclen) { 508214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC " 509214501Srpaulo "(left=%lu miclen=%lu)", 510214501Srpaulo (unsigned long) (end - pos), 511214501Srpaulo (unsigned long) miclen); 512214501Srpaulo eap_gpsk_state(data, FAILURE); 513214501Srpaulo return; 514214501Srpaulo } 515214501Srpaulo if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor, 516214501Srpaulo data->specifier, payload, pos - payload, mic) 517214501Srpaulo < 0) { 518214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC"); 519214501Srpaulo eap_gpsk_state(data, FAILURE); 520214501Srpaulo return; 521214501Srpaulo } 522281806Srpaulo if (os_memcmp_const(mic, pos, miclen) != 0) { 523214501Srpaulo wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-4"); 524214501Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen); 525214501Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen); 526214501Srpaulo eap_gpsk_state(data, FAILURE); 527214501Srpaulo return; 528214501Srpaulo } 529214501Srpaulo pos += miclen; 530214501Srpaulo 531214501Srpaulo if (pos != end) { 532214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra " 533214501Srpaulo "data in the end of GPSK-4", 534214501Srpaulo (unsigned long) (end - pos)); 535214501Srpaulo } 536214501Srpaulo 537214501Srpaulo eap_gpsk_state(data, SUCCESS); 538214501Srpaulo} 539214501Srpaulo 540214501Srpaulo 541214501Srpaulostatic void eap_gpsk_process(struct eap_sm *sm, void *priv, 542214501Srpaulo struct wpabuf *respData) 543214501Srpaulo{ 544214501Srpaulo struct eap_gpsk_data *data = priv; 545214501Srpaulo const u8 *pos; 546214501Srpaulo size_t len; 547214501Srpaulo 548214501Srpaulo pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, respData, &len); 549214501Srpaulo if (pos == NULL || len < 1) 550214501Srpaulo return; 551214501Srpaulo 552214501Srpaulo switch (*pos) { 553214501Srpaulo case EAP_GPSK_OPCODE_GPSK_2: 554214501Srpaulo eap_gpsk_process_gpsk_2(sm, data, pos + 1, len - 1); 555214501Srpaulo break; 556214501Srpaulo case EAP_GPSK_OPCODE_GPSK_4: 557214501Srpaulo eap_gpsk_process_gpsk_4(sm, data, pos + 1, len - 1); 558214501Srpaulo break; 559214501Srpaulo } 560214501Srpaulo} 561214501Srpaulo 562214501Srpaulo 563214501Srpaulostatic Boolean eap_gpsk_isDone(struct eap_sm *sm, void *priv) 564214501Srpaulo{ 565214501Srpaulo struct eap_gpsk_data *data = priv; 566214501Srpaulo return data->state == SUCCESS || data->state == FAILURE; 567214501Srpaulo} 568214501Srpaulo 569214501Srpaulo 570214501Srpaulostatic u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len) 571214501Srpaulo{ 572214501Srpaulo struct eap_gpsk_data *data = priv; 573214501Srpaulo u8 *key; 574214501Srpaulo 575214501Srpaulo if (data->state != SUCCESS) 576214501Srpaulo return NULL; 577214501Srpaulo 578214501Srpaulo key = os_malloc(EAP_MSK_LEN); 579214501Srpaulo if (key == NULL) 580214501Srpaulo return NULL; 581214501Srpaulo os_memcpy(key, data->msk, EAP_MSK_LEN); 582214501Srpaulo *len = EAP_MSK_LEN; 583214501Srpaulo 584214501Srpaulo return key; 585214501Srpaulo} 586214501Srpaulo 587214501Srpaulo 588214501Srpaulostatic u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 589214501Srpaulo{ 590214501Srpaulo struct eap_gpsk_data *data = priv; 591214501Srpaulo u8 *key; 592214501Srpaulo 593214501Srpaulo if (data->state != SUCCESS) 594214501Srpaulo return NULL; 595214501Srpaulo 596214501Srpaulo key = os_malloc(EAP_EMSK_LEN); 597214501Srpaulo if (key == NULL) 598214501Srpaulo return NULL; 599214501Srpaulo os_memcpy(key, data->emsk, EAP_EMSK_LEN); 600214501Srpaulo *len = EAP_EMSK_LEN; 601214501Srpaulo 602214501Srpaulo return key; 603214501Srpaulo} 604214501Srpaulo 605214501Srpaulo 606214501Srpaulostatic Boolean eap_gpsk_isSuccess(struct eap_sm *sm, void *priv) 607214501Srpaulo{ 608214501Srpaulo struct eap_gpsk_data *data = priv; 609214501Srpaulo return data->state == SUCCESS; 610214501Srpaulo} 611214501Srpaulo 612214501Srpaulo 613281806Srpaulostatic u8 * eap_gpsk_get_session_id(struct eap_sm *sm, void *priv, size_t *len) 614281806Srpaulo{ 615281806Srpaulo struct eap_gpsk_data *data = priv; 616281806Srpaulo u8 *sid; 617281806Srpaulo 618281806Srpaulo if (data->state != SUCCESS) 619281806Srpaulo return NULL; 620281806Srpaulo 621281806Srpaulo sid = os_malloc(data->id_len); 622281806Srpaulo if (sid == NULL) 623281806Srpaulo return NULL; 624281806Srpaulo os_memcpy(sid, data->session_id, data->id_len); 625281806Srpaulo *len = data->id_len; 626281806Srpaulo 627281806Srpaulo return sid; 628281806Srpaulo} 629281806Srpaulo 630281806Srpaulo 631214501Srpauloint eap_server_gpsk_register(void) 632214501Srpaulo{ 633214501Srpaulo struct eap_method *eap; 634214501Srpaulo 635214501Srpaulo eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 636214501Srpaulo EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK"); 637214501Srpaulo if (eap == NULL) 638214501Srpaulo return -1; 639214501Srpaulo 640214501Srpaulo eap->init = eap_gpsk_init; 641214501Srpaulo eap->reset = eap_gpsk_reset; 642214501Srpaulo eap->buildReq = eap_gpsk_buildReq; 643214501Srpaulo eap->check = eap_gpsk_check; 644214501Srpaulo eap->process = eap_gpsk_process; 645214501Srpaulo eap->isDone = eap_gpsk_isDone; 646214501Srpaulo eap->getKey = eap_gpsk_getKey; 647214501Srpaulo eap->isSuccess = eap_gpsk_isSuccess; 648214501Srpaulo eap->get_emsk = eap_gpsk_get_emsk; 649281806Srpaulo eap->getSessionId = eap_gpsk_get_session_id; 650214501Srpaulo 651337817Scy return eap_server_method_register(eap); 652214501Srpaulo} 653