1/* 2 * hostapd / EAP-GPSK (RFC 5433) server 3 * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi> 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9#include "includes.h" 10 11#include "common.h" 12#include "crypto/random.h" 13#include "eap_server/eap_i.h" 14#include "eap_common/eap_gpsk_common.h" 15 16 17struct eap_gpsk_data { 18 enum { GPSK_1, GPSK_3, SUCCESS, FAILURE } state; 19 u8 rand_server[EAP_GPSK_RAND_LEN]; 20 u8 rand_peer[EAP_GPSK_RAND_LEN]; 21 u8 msk[EAP_MSK_LEN]; 22 u8 emsk[EAP_EMSK_LEN]; 23 u8 sk[EAP_GPSK_MAX_SK_LEN]; 24 size_t sk_len; 25 u8 pk[EAP_GPSK_MAX_PK_LEN]; 26 size_t pk_len; 27 u8 *id_peer; 28 size_t id_peer_len; 29 u8 *id_server; 30 size_t id_server_len; 31#define MAX_NUM_CSUITES 2 32 struct eap_gpsk_csuite csuite_list[MAX_NUM_CSUITES]; 33 size_t csuite_count; 34 int vendor; /* CSuite/Vendor */ 35 int specifier; /* CSuite/Specifier */ 36}; 37 38 39static const char * eap_gpsk_state_txt(int state) 40{ 41 switch (state) { 42 case GPSK_1: 43 return "GPSK-1"; 44 case GPSK_3: 45 return "GPSK-3"; 46 case SUCCESS: 47 return "SUCCESS"; 48 case FAILURE: 49 return "FAILURE"; 50 default: 51 return "?"; 52 } 53} 54 55 56static void eap_gpsk_state(struct eap_gpsk_data *data, int state) 57{ 58 wpa_printf(MSG_DEBUG, "EAP-GPSK: %s -> %s", 59 eap_gpsk_state_txt(data->state), 60 eap_gpsk_state_txt(state)); 61 data->state = state; 62} 63 64 65static void * eap_gpsk_init(struct eap_sm *sm) 66{ 67 struct eap_gpsk_data *data; 68 69 data = os_zalloc(sizeof(*data)); 70 if (data == NULL) 71 return NULL; 72 data->state = GPSK_1; 73 74 /* TODO: add support for configuring ID_Server */ 75 data->id_server = (u8 *) os_strdup("hostapd"); 76 if (data->id_server) 77 data->id_server_len = os_strlen((char *) data->id_server); 78 79 data->csuite_count = 0; 80 if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF, 81 EAP_GPSK_CIPHER_AES)) { 82 WPA_PUT_BE32(data->csuite_list[data->csuite_count].vendor, 83 EAP_GPSK_VENDOR_IETF); 84 WPA_PUT_BE16(data->csuite_list[data->csuite_count].specifier, 85 EAP_GPSK_CIPHER_AES); 86 data->csuite_count++; 87 } 88 if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF, 89 EAP_GPSK_CIPHER_SHA256)) { 90 WPA_PUT_BE32(data->csuite_list[data->csuite_count].vendor, 91 EAP_GPSK_VENDOR_IETF); 92 WPA_PUT_BE16(data->csuite_list[data->csuite_count].specifier, 93 EAP_GPSK_CIPHER_SHA256); 94 data->csuite_count++; 95 } 96 97 return data; 98} 99 100 101static void eap_gpsk_reset(struct eap_sm *sm, void *priv) 102{ 103 struct eap_gpsk_data *data = priv; 104 os_free(data->id_server); 105 os_free(data->id_peer); 106 os_free(data); 107} 108 109 110static struct wpabuf * eap_gpsk_build_gpsk_1(struct eap_sm *sm, 111 struct eap_gpsk_data *data, u8 id) 112{ 113 size_t len; 114 struct wpabuf *req; 115 116 wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-1"); 117 118 if (random_get_bytes(data->rand_server, EAP_GPSK_RAND_LEN)) { 119 wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to get random data"); 120 eap_gpsk_state(data, FAILURE); 121 return NULL; 122 } 123 wpa_hexdump(MSG_MSGDUMP, "EAP-GPSK: RAND_Server", 124 data->rand_server, EAP_GPSK_RAND_LEN); 125 126 len = 1 + 2 + data->id_server_len + EAP_GPSK_RAND_LEN + 2 + 127 data->csuite_count * sizeof(struct eap_gpsk_csuite); 128 req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len, 129 EAP_CODE_REQUEST, id); 130 if (req == NULL) { 131 wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to allocate memory " 132 "for request/GPSK-1"); 133 eap_gpsk_state(data, FAILURE); 134 return NULL; 135 } 136 137 wpabuf_put_u8(req, EAP_GPSK_OPCODE_GPSK_1); 138 wpabuf_put_be16(req, data->id_server_len); 139 wpabuf_put_data(req, data->id_server, data->id_server_len); 140 wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN); 141 wpabuf_put_be16(req, 142 data->csuite_count * sizeof(struct eap_gpsk_csuite)); 143 wpabuf_put_data(req, data->csuite_list, 144 data->csuite_count * sizeof(struct eap_gpsk_csuite)); 145 146 return req; 147} 148 149 150static struct wpabuf * eap_gpsk_build_gpsk_3(struct eap_sm *sm, 151 struct eap_gpsk_data *data, u8 id) 152{ 153 u8 *pos, *start; 154 size_t len, miclen; 155 struct eap_gpsk_csuite *csuite; 156 struct wpabuf *req; 157 158 wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-3"); 159 160 miclen = eap_gpsk_mic_len(data->vendor, data->specifier); 161 len = 1 + 2 * EAP_GPSK_RAND_LEN + 2 + data->id_server_len + 162 sizeof(struct eap_gpsk_csuite) + 2 + miclen; 163 req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len, 164 EAP_CODE_REQUEST, id); 165 if (req == NULL) { 166 wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to allocate memory " 167 "for request/GPSK-3"); 168 eap_gpsk_state(data, FAILURE); 169 return NULL; 170 } 171 172 wpabuf_put_u8(req, EAP_GPSK_OPCODE_GPSK_3); 173 start = wpabuf_put(req, 0); 174 175 wpabuf_put_data(req, data->rand_peer, EAP_GPSK_RAND_LEN); 176 wpabuf_put_data(req, data->rand_server, EAP_GPSK_RAND_LEN); 177 wpabuf_put_be16(req, data->id_server_len); 178 wpabuf_put_data(req, data->id_server, data->id_server_len); 179 csuite = wpabuf_put(req, sizeof(*csuite)); 180 WPA_PUT_BE32(csuite->vendor, data->vendor); 181 WPA_PUT_BE16(csuite->specifier, data->specifier); 182 183 /* no PD_Payload_2 */ 184 wpabuf_put_be16(req, 0); 185 186 pos = wpabuf_put(req, miclen); 187 if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor, 188 data->specifier, start, pos - start, pos) < 0) 189 { 190 os_free(req); 191 eap_gpsk_state(data, FAILURE); 192 return NULL; 193 } 194 195 return req; 196} 197 198 199static struct wpabuf * eap_gpsk_buildReq(struct eap_sm *sm, void *priv, u8 id) 200{ 201 struct eap_gpsk_data *data = priv; 202 203 switch (data->state) { 204 case GPSK_1: 205 return eap_gpsk_build_gpsk_1(sm, data, id); 206 case GPSK_3: 207 return eap_gpsk_build_gpsk_3(sm, data, id); 208 default: 209 wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown state %d in buildReq", 210 data->state); 211 break; 212 } 213 return NULL; 214} 215 216 217static Boolean eap_gpsk_check(struct eap_sm *sm, void *priv, 218 struct wpabuf *respData) 219{ 220 struct eap_gpsk_data *data = priv; 221 const u8 *pos; 222 size_t len; 223 224 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, respData, &len); 225 if (pos == NULL || len < 1) { 226 wpa_printf(MSG_INFO, "EAP-GPSK: Invalid frame"); 227 return TRUE; 228 } 229 230 wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode=%d", *pos); 231 232 if (data->state == GPSK_1 && *pos == EAP_GPSK_OPCODE_GPSK_2) 233 return FALSE; 234 235 if (data->state == GPSK_3 && *pos == EAP_GPSK_OPCODE_GPSK_4) 236 return FALSE; 237 238 wpa_printf(MSG_INFO, "EAP-GPSK: Unexpected opcode=%d in state=%d", 239 *pos, data->state); 240 241 return TRUE; 242} 243 244 245static void eap_gpsk_process_gpsk_2(struct eap_sm *sm, 246 struct eap_gpsk_data *data, 247 const u8 *payload, size_t payloadlen) 248{ 249 const u8 *pos, *end; 250 u16 alen; 251 const struct eap_gpsk_csuite *csuite; 252 size_t i, miclen; 253 u8 mic[EAP_GPSK_MAX_MIC_LEN]; 254 255 if (data->state != GPSK_1) 256 return; 257 258 wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Response/GPSK-2"); 259 260 pos = payload; 261 end = payload + payloadlen; 262 263 if (end - pos < 2) { 264 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 265 "ID_Peer length"); 266 eap_gpsk_state(data, FAILURE); 267 return; 268 } 269 alen = WPA_GET_BE16(pos); 270 pos += 2; 271 if (end - pos < alen) { 272 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 273 "ID_Peer"); 274 eap_gpsk_state(data, FAILURE); 275 return; 276 } 277 os_free(data->id_peer); 278 data->id_peer = os_malloc(alen); 279 if (data->id_peer == NULL) { 280 wpa_printf(MSG_DEBUG, "EAP-GPSK: Not enough memory to store " 281 "%d-octet ID_Peer", alen); 282 return; 283 } 284 os_memcpy(data->id_peer, pos, alen); 285 data->id_peer_len = alen; 286 wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Peer", 287 data->id_peer, data->id_peer_len); 288 pos += alen; 289 290 if (end - pos < 2) { 291 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 292 "ID_Server length"); 293 eap_gpsk_state(data, FAILURE); 294 return; 295 } 296 alen = WPA_GET_BE16(pos); 297 pos += 2; 298 if (end - pos < alen) { 299 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 300 "ID_Server"); 301 eap_gpsk_state(data, FAILURE); 302 return; 303 } 304 if (alen != data->id_server_len || 305 os_memcmp(pos, data->id_server, alen) != 0) { 306 wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1 and " 307 "GPSK-2 did not match"); 308 eap_gpsk_state(data, FAILURE); 309 return; 310 } 311 pos += alen; 312 313 if (end - pos < EAP_GPSK_RAND_LEN) { 314 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 315 "RAND_Peer"); 316 eap_gpsk_state(data, FAILURE); 317 return; 318 } 319 os_memcpy(data->rand_peer, pos, EAP_GPSK_RAND_LEN); 320 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer", 321 data->rand_peer, EAP_GPSK_RAND_LEN); 322 pos += EAP_GPSK_RAND_LEN; 323 324 if (end - pos < EAP_GPSK_RAND_LEN) { 325 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 326 "RAND_Server"); 327 eap_gpsk_state(data, FAILURE); 328 return; 329 } 330 if (os_memcmp(data->rand_server, pos, EAP_GPSK_RAND_LEN) != 0) { 331 wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and " 332 "GPSK-2 did not match"); 333 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1", 334 data->rand_server, EAP_GPSK_RAND_LEN); 335 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-2", 336 pos, EAP_GPSK_RAND_LEN); 337 eap_gpsk_state(data, FAILURE); 338 return; 339 } 340 pos += EAP_GPSK_RAND_LEN; 341 342 if (end - pos < 2) { 343 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 344 "CSuite_List length"); 345 eap_gpsk_state(data, FAILURE); 346 return; 347 } 348 alen = WPA_GET_BE16(pos); 349 pos += 2; 350 if (end - pos < alen) { 351 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 352 "CSuite_List"); 353 eap_gpsk_state(data, FAILURE); 354 return; 355 } 356 if (alen != data->csuite_count * sizeof(struct eap_gpsk_csuite) || 357 os_memcmp(pos, data->csuite_list, alen) != 0) { 358 wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List in GPSK-1 and " 359 "GPSK-2 did not match"); 360 eap_gpsk_state(data, FAILURE); 361 return; 362 } 363 pos += alen; 364 365 if (end - pos < (int) sizeof(*csuite)) { 366 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 367 "CSuite_Sel"); 368 eap_gpsk_state(data, FAILURE); 369 return; 370 } 371 csuite = (const struct eap_gpsk_csuite *) pos; 372 for (i = 0; i < data->csuite_count; i++) { 373 if (os_memcmp(csuite, &data->csuite_list[i], sizeof(*csuite)) 374 == 0) 375 break; 376 } 377 if (i == data->csuite_count) { 378 wpa_printf(MSG_DEBUG, "EAP-GPSK: Peer selected unsupported " 379 "ciphersuite %d:%d", 380 WPA_GET_BE32(csuite->vendor), 381 WPA_GET_BE16(csuite->specifier)); 382 eap_gpsk_state(data, FAILURE); 383 return; 384 } 385 data->vendor = WPA_GET_BE32(csuite->vendor); 386 data->specifier = WPA_GET_BE16(csuite->specifier); 387 wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel %d:%d", 388 data->vendor, data->specifier); 389 pos += sizeof(*csuite); 390 391 if (end - pos < 2) { 392 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 393 "PD_Payload_1 length"); 394 eap_gpsk_state(data, FAILURE); 395 return; 396 } 397 alen = WPA_GET_BE16(pos); 398 pos += 2; 399 if (end - pos < alen) { 400 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 401 "PD_Payload_1"); 402 eap_gpsk_state(data, FAILURE); 403 return; 404 } 405 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_1", pos, alen); 406 pos += alen; 407 408 if (sm->user == NULL || sm->user->password == NULL) { 409 wpa_printf(MSG_INFO, "EAP-GPSK: No PSK/password configured " 410 "for the user"); 411 eap_gpsk_state(data, FAILURE); 412 return; 413 } 414 415 if (eap_gpsk_derive_keys(sm->user->password, sm->user->password_len, 416 data->vendor, data->specifier, 417 data->rand_peer, data->rand_server, 418 data->id_peer, data->id_peer_len, 419 data->id_server, data->id_server_len, 420 data->msk, data->emsk, 421 data->sk, &data->sk_len, 422 data->pk, &data->pk_len) < 0) { 423 wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys"); 424 eap_gpsk_state(data, FAILURE); 425 return; 426 } 427 428 miclen = eap_gpsk_mic_len(data->vendor, data->specifier); 429 if (end - pos < (int) miclen) { 430 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC " 431 "(left=%lu miclen=%lu)", 432 (unsigned long) (end - pos), 433 (unsigned long) miclen); 434 eap_gpsk_state(data, FAILURE); 435 return; 436 } 437 if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor, 438 data->specifier, payload, pos - payload, mic) 439 < 0) { 440 wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC"); 441 eap_gpsk_state(data, FAILURE); 442 return; 443 } 444 if (os_memcmp(mic, pos, miclen) != 0) { 445 wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-2"); 446 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen); 447 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen); 448 eap_gpsk_state(data, FAILURE); 449 return; 450 } 451 pos += miclen; 452 453 if (pos != end) { 454 wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra " 455 "data in the end of GPSK-2", 456 (unsigned long) (end - pos)); 457 } 458 459 eap_gpsk_state(data, GPSK_3); 460} 461 462 463static void eap_gpsk_process_gpsk_4(struct eap_sm *sm, 464 struct eap_gpsk_data *data, 465 const u8 *payload, size_t payloadlen) 466{ 467 const u8 *pos, *end; 468 u16 alen; 469 size_t miclen; 470 u8 mic[EAP_GPSK_MAX_MIC_LEN]; 471 472 if (data->state != GPSK_3) 473 return; 474 475 wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Response/GPSK-4"); 476 477 pos = payload; 478 end = payload + payloadlen; 479 480 if (end - pos < 2) { 481 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 482 "PD_Payload_1 length"); 483 eap_gpsk_state(data, FAILURE); 484 return; 485 } 486 alen = WPA_GET_BE16(pos); 487 pos += 2; 488 if (end - pos < alen) { 489 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for " 490 "PD_Payload_1"); 491 eap_gpsk_state(data, FAILURE); 492 return; 493 } 494 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_1", pos, alen); 495 pos += alen; 496 497 miclen = eap_gpsk_mic_len(data->vendor, data->specifier); 498 if (end - pos < (int) miclen) { 499 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC " 500 "(left=%lu miclen=%lu)", 501 (unsigned long) (end - pos), 502 (unsigned long) miclen); 503 eap_gpsk_state(data, FAILURE); 504 return; 505 } 506 if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor, 507 data->specifier, payload, pos - payload, mic) 508 < 0) { 509 wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC"); 510 eap_gpsk_state(data, FAILURE); 511 return; 512 } 513 if (os_memcmp(mic, pos, miclen) != 0) { 514 wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-4"); 515 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen); 516 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen); 517 eap_gpsk_state(data, FAILURE); 518 return; 519 } 520 pos += miclen; 521 522 if (pos != end) { 523 wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra " 524 "data in the end of GPSK-4", 525 (unsigned long) (end - pos)); 526 } 527 528 eap_gpsk_state(data, SUCCESS); 529} 530 531 532static void eap_gpsk_process(struct eap_sm *sm, void *priv, 533 struct wpabuf *respData) 534{ 535 struct eap_gpsk_data *data = priv; 536 const u8 *pos; 537 size_t len; 538 539 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, respData, &len); 540 if (pos == NULL || len < 1) 541 return; 542 543 switch (*pos) { 544 case EAP_GPSK_OPCODE_GPSK_2: 545 eap_gpsk_process_gpsk_2(sm, data, pos + 1, len - 1); 546 break; 547 case EAP_GPSK_OPCODE_GPSK_4: 548 eap_gpsk_process_gpsk_4(sm, data, pos + 1, len - 1); 549 break; 550 } 551} 552 553 554static Boolean eap_gpsk_isDone(struct eap_sm *sm, void *priv) 555{ 556 struct eap_gpsk_data *data = priv; 557 return data->state == SUCCESS || data->state == FAILURE; 558} 559 560 561static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len) 562{ 563 struct eap_gpsk_data *data = priv; 564 u8 *key; 565 566 if (data->state != SUCCESS) 567 return NULL; 568 569 key = os_malloc(EAP_MSK_LEN); 570 if (key == NULL) 571 return NULL; 572 os_memcpy(key, data->msk, EAP_MSK_LEN); 573 *len = EAP_MSK_LEN; 574 575 return key; 576} 577 578 579static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 580{ 581 struct eap_gpsk_data *data = priv; 582 u8 *key; 583 584 if (data->state != SUCCESS) 585 return NULL; 586 587 key = os_malloc(EAP_EMSK_LEN); 588 if (key == NULL) 589 return NULL; 590 os_memcpy(key, data->emsk, EAP_EMSK_LEN); 591 *len = EAP_EMSK_LEN; 592 593 return key; 594} 595 596 597static Boolean eap_gpsk_isSuccess(struct eap_sm *sm, void *priv) 598{ 599 struct eap_gpsk_data *data = priv; 600 return data->state == SUCCESS; 601} 602 603 604int eap_server_gpsk_register(void) 605{ 606 struct eap_method *eap; 607 int ret; 608 609 eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 610 EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK"); 611 if (eap == NULL) 612 return -1; 613 614 eap->init = eap_gpsk_init; 615 eap->reset = eap_gpsk_reset; 616 eap->buildReq = eap_gpsk_buildReq; 617 eap->check = eap_gpsk_check; 618 eap->process = eap_gpsk_process; 619 eap->isDone = eap_gpsk_isDone; 620 eap->getKey = eap_gpsk_getKey; 621 eap->isSuccess = eap_gpsk_isSuccess; 622 eap->get_emsk = eap_gpsk_get_emsk; 623 624 ret = eap_server_method_register(eap); 625 if (ret) 626 eap_server_method_free(eap); 627 return ret; 628} 629