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