$search
00001 /* 00002 * EAP peer method: EAP-GPSK (RFC 5433) 00003 * Copyright (c) 2006-2008, Jouni Malinen <j@w1.fi> 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation. 00008 * 00009 * Alternatively, this software may be distributed under the terms of BSD 00010 * license. 00011 * 00012 * See README and COPYING for more details. 00013 */ 00014 00015 #include "includes.h" 00016 00017 #include "common.h" 00018 #include "eap_peer/eap_i.h" 00019 #include "eap_common/eap_gpsk_common.h" 00020 00021 struct eap_gpsk_data { 00022 enum { GPSK_1, GPSK_3, SUCCESS, FAILURE } state; 00023 u8 rand_server[EAP_GPSK_RAND_LEN]; 00024 u8 rand_peer[EAP_GPSK_RAND_LEN]; 00025 u8 msk[EAP_MSK_LEN]; 00026 u8 emsk[EAP_EMSK_LEN]; 00027 u8 sk[EAP_GPSK_MAX_SK_LEN]; 00028 size_t sk_len; 00029 u8 pk[EAP_GPSK_MAX_PK_LEN]; 00030 size_t pk_len; 00031 u8 session_id; 00032 int session_id_set; 00033 u8 *id_peer; 00034 size_t id_peer_len; 00035 u8 *id_server; 00036 size_t id_server_len; 00037 int vendor; /* CSuite/Specifier */ 00038 int specifier; /* CSuite/Specifier */ 00039 u8 *psk; 00040 size_t psk_len; 00041 }; 00042 00043 00044 static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data, 00045 u8 identifier, 00046 const u8 *csuite_list, 00047 size_t csuite_list_len); 00048 static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data, 00049 u8 identifier); 00050 00051 00052 #ifndef CONFIG_NO_STDOUT_DEBUG 00053 static const char * eap_gpsk_state_txt(int state) 00054 { 00055 switch (state) { 00056 case GPSK_1: 00057 return "GPSK-1"; 00058 case GPSK_3: 00059 return "GPSK-3"; 00060 case SUCCESS: 00061 return "SUCCESS"; 00062 case FAILURE: 00063 return "FAILURE"; 00064 default: 00065 return "?"; 00066 } 00067 } 00068 #endif /* CONFIG_NO_STDOUT_DEBUG */ 00069 00070 00071 static void eap_gpsk_state(struct eap_gpsk_data *data, int state) 00072 { 00073 wpa_printf(MSG_DEBUG, "EAP-GPSK: %s -> %s", 00074 eap_gpsk_state_txt(data->state), 00075 eap_gpsk_state_txt(state)); 00076 data->state = state; 00077 } 00078 00079 00080 static void eap_gpsk_deinit(struct eap_sm *sm, void *priv); 00081 00082 00083 static void * eap_gpsk_init(struct eap_sm *sm) 00084 { 00085 struct eap_gpsk_data *data; 00086 const u8 *identity, *password; 00087 size_t identity_len, password_len; 00088 00089 password = eap_get_config_password(sm, &password_len); 00090 if (password == NULL) { 00091 wpa_printf(MSG_INFO, "EAP-GPSK: No key (password) configured"); 00092 return NULL; 00093 } 00094 00095 data = os_zalloc(sizeof(*data)); 00096 if (data == NULL) 00097 return NULL; 00098 data->state = GPSK_1; 00099 00100 identity = eap_get_config_identity(sm, &identity_len); 00101 if (identity) { 00102 data->id_peer = os_malloc(identity_len); 00103 if (data->id_peer == NULL) { 00104 eap_gpsk_deinit(sm, data); 00105 return NULL; 00106 } 00107 os_memcpy(data->id_peer, identity, identity_len); 00108 data->id_peer_len = identity_len; 00109 } 00110 00111 data->psk = os_malloc(password_len); 00112 if (data->psk == NULL) { 00113 eap_gpsk_deinit(sm, data); 00114 return NULL; 00115 } 00116 os_memcpy(data->psk, password, password_len); 00117 data->psk_len = password_len; 00118 00119 return data; 00120 } 00121 00122 00123 static void eap_gpsk_deinit(struct eap_sm *sm, void *priv) 00124 { 00125 struct eap_gpsk_data *data = priv; 00126 os_free(data->id_server); 00127 os_free(data->id_peer); 00128 os_free(data->psk); 00129 os_free(data); 00130 } 00131 00132 00133 static const u8 * eap_gpsk_process_id_server(struct eap_gpsk_data *data, 00134 const u8 *pos, const u8 *end) 00135 { 00136 u16 alen; 00137 00138 if (end - pos < 2) { 00139 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet"); 00140 return NULL; 00141 } 00142 alen = WPA_GET_BE16(pos); 00143 pos += 2; 00144 if (end - pos < alen) { 00145 wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server overflow"); 00146 return NULL; 00147 } 00148 os_free(data->id_server); 00149 data->id_server = os_malloc(alen); 00150 if (data->id_server == NULL) { 00151 wpa_printf(MSG_DEBUG, "EAP-GPSK: No memory for ID_Server"); 00152 return NULL; 00153 } 00154 os_memcpy(data->id_server, pos, alen); 00155 data->id_server_len = alen; 00156 wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server", 00157 data->id_server, data->id_server_len); 00158 pos += alen; 00159 00160 return pos; 00161 } 00162 00163 00164 static const u8 * eap_gpsk_process_rand_server(struct eap_gpsk_data *data, 00165 const u8 *pos, const u8 *end) 00166 { 00167 if (pos == NULL) 00168 return NULL; 00169 00170 if (end - pos < EAP_GPSK_RAND_LEN) { 00171 wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server overflow"); 00172 return NULL; 00173 } 00174 os_memcpy(data->rand_server, pos, EAP_GPSK_RAND_LEN); 00175 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server", 00176 data->rand_server, EAP_GPSK_RAND_LEN); 00177 pos += EAP_GPSK_RAND_LEN; 00178 00179 return pos; 00180 } 00181 00182 00183 static int eap_gpsk_select_csuite(struct eap_sm *sm, 00184 struct eap_gpsk_data *data, 00185 const u8 *csuite_list, 00186 size_t csuite_list_len) 00187 { 00188 struct eap_gpsk_csuite *csuite; 00189 int i, count; 00190 00191 count = csuite_list_len / sizeof(struct eap_gpsk_csuite); 00192 data->vendor = EAP_GPSK_VENDOR_IETF; 00193 data->specifier = EAP_GPSK_CIPHER_RESERVED; 00194 csuite = (struct eap_gpsk_csuite *) csuite_list; 00195 for (i = 0; i < count; i++) { 00196 int vendor, specifier; 00197 vendor = WPA_GET_BE32(csuite->vendor); 00198 specifier = WPA_GET_BE16(csuite->specifier); 00199 wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite[%d]: %d:%d", 00200 i, vendor, specifier); 00201 if (data->vendor == EAP_GPSK_VENDOR_IETF && 00202 data->specifier == EAP_GPSK_CIPHER_RESERVED && 00203 eap_gpsk_supported_ciphersuite(vendor, specifier)) { 00204 data->vendor = vendor; 00205 data->specifier = specifier; 00206 } 00207 csuite++; 00208 } 00209 if (data->vendor == EAP_GPSK_VENDOR_IETF && 00210 data->specifier == EAP_GPSK_CIPHER_RESERVED) { 00211 wpa_msg(sm->msg_ctx, MSG_INFO, "EAP-GPSK: No supported " 00212 "ciphersuite found"); 00213 return -1; 00214 } 00215 wpa_printf(MSG_DEBUG, "EAP-GPSK: Selected ciphersuite %d:%d", 00216 data->vendor, data->specifier); 00217 00218 return 0; 00219 } 00220 00221 00222 static const u8 * eap_gpsk_process_csuite_list(struct eap_sm *sm, 00223 struct eap_gpsk_data *data, 00224 const u8 **list, 00225 size_t *list_len, 00226 const u8 *pos, const u8 *end) 00227 { 00228 if (pos == NULL) 00229 return NULL; 00230 00231 if (end - pos < 2) { 00232 wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet"); 00233 return NULL; 00234 } 00235 *list_len = WPA_GET_BE16(pos); 00236 pos += 2; 00237 if (end - pos < (int) *list_len) { 00238 wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List overflow"); 00239 return NULL; 00240 } 00241 if (*list_len == 0 || (*list_len % sizeof(struct eap_gpsk_csuite))) { 00242 wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid CSuite_List len %lu", 00243 (unsigned long) *list_len); 00244 return NULL; 00245 } 00246 *list = pos; 00247 pos += *list_len; 00248 00249 if (eap_gpsk_select_csuite(sm, data, *list, *list_len) < 0) 00250 return NULL; 00251 00252 return pos; 00253 } 00254 00255 00256 static struct wpabuf * eap_gpsk_process_gpsk_1(struct eap_sm *sm, 00257 struct eap_gpsk_data *data, 00258 struct eap_method_ret *ret, 00259 const struct wpabuf *reqData, 00260 const u8 *payload, 00261 size_t payload_len) 00262 { 00263 size_t csuite_list_len; 00264 const u8 *csuite_list, *pos, *end; 00265 struct wpabuf *resp; 00266 00267 if (data->state != GPSK_1) { 00268 ret->ignore = TRUE; 00269 return NULL; 00270 } 00271 00272 wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-1"); 00273 00274 end = payload + payload_len; 00275 00276 pos = eap_gpsk_process_id_server(data, payload, end); 00277 pos = eap_gpsk_process_rand_server(data, pos, end); 00278 pos = eap_gpsk_process_csuite_list(sm, data, &csuite_list, 00279 &csuite_list_len, pos, end); 00280 if (pos == NULL) { 00281 eap_gpsk_state(data, FAILURE); 00282 return NULL; 00283 } 00284 00285 resp = eap_gpsk_send_gpsk_2(data, eap_get_id(reqData), 00286 csuite_list, csuite_list_len); 00287 if (resp == NULL) 00288 return NULL; 00289 00290 eap_gpsk_state(data, GPSK_3); 00291 00292 return resp; 00293 } 00294 00295 00296 static struct wpabuf * eap_gpsk_send_gpsk_2(struct eap_gpsk_data *data, 00297 u8 identifier, 00298 const u8 *csuite_list, 00299 size_t csuite_list_len) 00300 { 00301 struct wpabuf *resp; 00302 size_t len, miclen; 00303 u8 *rpos, *start; 00304 struct eap_gpsk_csuite *csuite; 00305 00306 wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-2"); 00307 00308 miclen = eap_gpsk_mic_len(data->vendor, data->specifier); 00309 len = 1 + 2 + data->id_peer_len + 2 + data->id_server_len + 00310 2 * EAP_GPSK_RAND_LEN + 2 + csuite_list_len + 00311 sizeof(struct eap_gpsk_csuite) + 2 + miclen; 00312 00313 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, len, 00314 EAP_CODE_RESPONSE, identifier); 00315 if (resp == NULL) 00316 return NULL; 00317 00318 wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_2); 00319 start = wpabuf_put(resp, 0); 00320 00321 wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Peer", 00322 data->id_peer, data->id_peer_len); 00323 wpabuf_put_be16(resp, data->id_peer_len); 00324 wpabuf_put_data(resp, data->id_peer, data->id_peer_len); 00325 00326 wpabuf_put_be16(resp, data->id_server_len); 00327 wpabuf_put_data(resp, data->id_server, data->id_server_len); 00328 00329 if (os_get_random(data->rand_peer, EAP_GPSK_RAND_LEN)) { 00330 wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to get random data " 00331 "for RAND_Peer"); 00332 eap_gpsk_state(data, FAILURE); 00333 wpabuf_free(resp); 00334 return NULL; 00335 } 00336 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer", 00337 data->rand_peer, EAP_GPSK_RAND_LEN); 00338 wpabuf_put_data(resp, data->rand_peer, EAP_GPSK_RAND_LEN); 00339 wpabuf_put_data(resp, data->rand_server, EAP_GPSK_RAND_LEN); 00340 00341 wpabuf_put_be16(resp, csuite_list_len); 00342 wpabuf_put_data(resp, csuite_list, csuite_list_len); 00343 00344 csuite = wpabuf_put(resp, sizeof(*csuite)); 00345 WPA_PUT_BE32(csuite->vendor, data->vendor); 00346 WPA_PUT_BE16(csuite->specifier, data->specifier); 00347 00348 if (eap_gpsk_derive_keys(data->psk, data->psk_len, 00349 data->vendor, data->specifier, 00350 data->rand_peer, data->rand_server, 00351 data->id_peer, data->id_peer_len, 00352 data->id_server, data->id_server_len, 00353 data->msk, data->emsk, 00354 data->sk, &data->sk_len, 00355 data->pk, &data->pk_len) < 0) { 00356 wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys"); 00357 eap_gpsk_state(data, FAILURE); 00358 wpabuf_free(resp); 00359 return NULL; 00360 } 00361 00362 /* No PD_Payload_1 */ 00363 wpabuf_put_be16(resp, 0); 00364 00365 rpos = wpabuf_put(resp, miclen); 00366 if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor, 00367 data->specifier, start, rpos - start, rpos) < 00368 0) { 00369 eap_gpsk_state(data, FAILURE); 00370 wpabuf_free(resp); 00371 return NULL; 00372 } 00373 00374 return resp; 00375 } 00376 00377 00378 static const u8 * eap_gpsk_validate_rand(struct eap_gpsk_data *data, 00379 const u8 *pos, const u8 *end) 00380 { 00381 if (end - pos < EAP_GPSK_RAND_LEN) { 00382 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for " 00383 "RAND_Peer"); 00384 return NULL; 00385 } 00386 if (os_memcmp(pos, data->rand_peer, EAP_GPSK_RAND_LEN) != 0) { 00387 wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-2 and " 00388 "GPSK-3 did not match"); 00389 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-2", 00390 data->rand_peer, EAP_GPSK_RAND_LEN); 00391 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Peer in GPSK-3", 00392 pos, EAP_GPSK_RAND_LEN); 00393 return NULL; 00394 } 00395 pos += EAP_GPSK_RAND_LEN; 00396 00397 if (end - pos < EAP_GPSK_RAND_LEN) { 00398 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for " 00399 "RAND_Server"); 00400 return NULL; 00401 } 00402 if (os_memcmp(pos, data->rand_server, EAP_GPSK_RAND_LEN) != 0) { 00403 wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and " 00404 "GPSK-3 did not match"); 00405 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1", 00406 data->rand_server, EAP_GPSK_RAND_LEN); 00407 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-3", 00408 pos, EAP_GPSK_RAND_LEN); 00409 return NULL; 00410 } 00411 pos += EAP_GPSK_RAND_LEN; 00412 00413 return pos; 00414 } 00415 00416 00417 static const u8 * eap_gpsk_validate_id_server(struct eap_gpsk_data *data, 00418 const u8 *pos, const u8 *end) 00419 { 00420 size_t len; 00421 00422 if (pos == NULL) 00423 return NULL; 00424 00425 if (end - pos < (int) 2) { 00426 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for " 00427 "length(ID_Server)"); 00428 return NULL; 00429 } 00430 00431 len = WPA_GET_BE16(pos); 00432 pos += 2; 00433 00434 if (end - pos < (int) len) { 00435 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for " 00436 "ID_Server"); 00437 return NULL; 00438 } 00439 00440 if (len != data->id_server_len || 00441 os_memcmp(pos, data->id_server, len) != 0) { 00442 wpa_printf(MSG_INFO, "EAP-GPSK: ID_Server did not match with " 00443 "the one used in GPSK-1"); 00444 wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1", 00445 data->id_server, data->id_server_len); 00446 wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-3", 00447 pos, len); 00448 return NULL; 00449 } 00450 00451 pos += len; 00452 00453 return pos; 00454 } 00455 00456 00457 static const u8 * eap_gpsk_validate_csuite(struct eap_gpsk_data *data, 00458 const u8 *pos, const u8 *end) 00459 { 00460 int vendor, specifier; 00461 const struct eap_gpsk_csuite *csuite; 00462 00463 if (pos == NULL) 00464 return NULL; 00465 00466 if (end - pos < (int) sizeof(*csuite)) { 00467 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for " 00468 "CSuite_Sel"); 00469 return NULL; 00470 } 00471 csuite = (const struct eap_gpsk_csuite *) pos; 00472 vendor = WPA_GET_BE32(csuite->vendor); 00473 specifier = WPA_GET_BE16(csuite->specifier); 00474 pos += sizeof(*csuite); 00475 if (vendor != data->vendor || specifier != data->specifier) { 00476 wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel (%d:%d) does not " 00477 "match with the one sent in GPSK-2 (%d:%d)", 00478 vendor, specifier, data->vendor, data->specifier); 00479 return NULL; 00480 } 00481 00482 return pos; 00483 } 00484 00485 00486 static const u8 * eap_gpsk_validate_pd_payload_2(struct eap_gpsk_data *data, 00487 const u8 *pos, const u8 *end) 00488 { 00489 u16 alen; 00490 00491 if (pos == NULL) 00492 return NULL; 00493 00494 if (end - pos < 2) { 00495 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for " 00496 "PD_Payload_2 length"); 00497 return NULL; 00498 } 00499 alen = WPA_GET_BE16(pos); 00500 pos += 2; 00501 if (end - pos < alen) { 00502 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for " 00503 "%d-octet PD_Payload_2", alen); 00504 return NULL; 00505 } 00506 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_2", pos, alen); 00507 pos += alen; 00508 00509 return pos; 00510 } 00511 00512 00513 static const u8 * eap_gpsk_validate_gpsk_3_mic(struct eap_gpsk_data *data, 00514 const u8 *payload, 00515 const u8 *pos, const u8 *end) 00516 { 00517 size_t miclen; 00518 u8 mic[EAP_GPSK_MAX_MIC_LEN]; 00519 00520 if (pos == NULL) 00521 return NULL; 00522 00523 miclen = eap_gpsk_mic_len(data->vendor, data->specifier); 00524 if (end - pos < (int) miclen) { 00525 wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC " 00526 "(left=%lu miclen=%lu)", 00527 (unsigned long) (end - pos), 00528 (unsigned long) miclen); 00529 return NULL; 00530 } 00531 if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor, 00532 data->specifier, payload, pos - payload, mic) 00533 < 0) { 00534 wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC"); 00535 return NULL; 00536 } 00537 if (os_memcmp(mic, pos, miclen) != 0) { 00538 wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-3"); 00539 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen); 00540 wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen); 00541 return NULL; 00542 } 00543 pos += miclen; 00544 00545 return pos; 00546 } 00547 00548 00549 static struct wpabuf * eap_gpsk_process_gpsk_3(struct eap_sm *sm, 00550 struct eap_gpsk_data *data, 00551 struct eap_method_ret *ret, 00552 const struct wpabuf *reqData, 00553 const u8 *payload, 00554 size_t payload_len) 00555 { 00556 struct wpabuf *resp; 00557 const u8 *pos, *end; 00558 00559 if (data->state != GPSK_3) { 00560 ret->ignore = TRUE; 00561 return NULL; 00562 } 00563 00564 wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-3"); 00565 00566 end = payload + payload_len; 00567 00568 pos = eap_gpsk_validate_rand(data, payload, end); 00569 pos = eap_gpsk_validate_id_server(data, pos, end); 00570 pos = eap_gpsk_validate_csuite(data, pos, end); 00571 pos = eap_gpsk_validate_pd_payload_2(data, pos, end); 00572 pos = eap_gpsk_validate_gpsk_3_mic(data, payload, pos, end); 00573 00574 if (pos == NULL) { 00575 eap_gpsk_state(data, FAILURE); 00576 return NULL; 00577 } 00578 if (pos != end) { 00579 wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %lu bytes of extra " 00580 "data in the end of GPSK-2", 00581 (unsigned long) (end - pos)); 00582 } 00583 00584 resp = eap_gpsk_send_gpsk_4(data, eap_get_id(reqData)); 00585 if (resp == NULL) 00586 return NULL; 00587 00588 eap_gpsk_state(data, SUCCESS); 00589 ret->methodState = METHOD_DONE; 00590 ret->decision = DECISION_UNCOND_SUCC; 00591 00592 return resp; 00593 } 00594 00595 00596 static struct wpabuf * eap_gpsk_send_gpsk_4(struct eap_gpsk_data *data, 00597 u8 identifier) 00598 { 00599 struct wpabuf *resp; 00600 u8 *rpos, *start; 00601 size_t mlen; 00602 00603 wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-4"); 00604 00605 mlen = eap_gpsk_mic_len(data->vendor, data->specifier); 00606 00607 resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, 1 + 2 + mlen, 00608 EAP_CODE_RESPONSE, identifier); 00609 if (resp == NULL) 00610 return NULL; 00611 00612 wpabuf_put_u8(resp, EAP_GPSK_OPCODE_GPSK_4); 00613 start = wpabuf_put(resp, 0); 00614 00615 /* No PD_Payload_3 */ 00616 wpabuf_put_be16(resp, 0); 00617 00618 rpos = wpabuf_put(resp, mlen); 00619 if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor, 00620 data->specifier, start, rpos - start, rpos) < 00621 0) { 00622 eap_gpsk_state(data, FAILURE); 00623 wpabuf_free(resp); 00624 return NULL; 00625 } 00626 00627 return resp; 00628 } 00629 00630 00631 static struct wpabuf * eap_gpsk_process(struct eap_sm *sm, void *priv, 00632 struct eap_method_ret *ret, 00633 const struct wpabuf *reqData) 00634 { 00635 struct eap_gpsk_data *data = priv; 00636 struct wpabuf *resp; 00637 const u8 *pos; 00638 size_t len; 00639 00640 pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK, reqData, &len); 00641 if (pos == NULL || len < 1) { 00642 ret->ignore = TRUE; 00643 return NULL; 00644 } 00645 00646 wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode %d", *pos); 00647 00648 ret->ignore = FALSE; 00649 ret->methodState = METHOD_MAY_CONT; 00650 ret->decision = DECISION_FAIL; 00651 ret->allowNotifications = FALSE; 00652 00653 switch (*pos) { 00654 case EAP_GPSK_OPCODE_GPSK_1: 00655 resp = eap_gpsk_process_gpsk_1(sm, data, ret, reqData, 00656 pos + 1, len - 1); 00657 break; 00658 case EAP_GPSK_OPCODE_GPSK_3: 00659 resp = eap_gpsk_process_gpsk_3(sm, data, ret, reqData, 00660 pos + 1, len - 1); 00661 break; 00662 default: 00663 wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignoring message with " 00664 "unknown opcode %d", *pos); 00665 ret->ignore = TRUE; 00666 return NULL; 00667 } 00668 00669 return resp; 00670 } 00671 00672 00673 static Boolean eap_gpsk_isKeyAvailable(struct eap_sm *sm, void *priv) 00674 { 00675 struct eap_gpsk_data *data = priv; 00676 return data->state == SUCCESS; 00677 } 00678 00679 00680 static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len) 00681 { 00682 struct eap_gpsk_data *data = priv; 00683 u8 *key; 00684 00685 if (data->state != SUCCESS) 00686 return NULL; 00687 00688 key = os_malloc(EAP_MSK_LEN); 00689 if (key == NULL) 00690 return NULL; 00691 os_memcpy(key, data->msk, EAP_MSK_LEN); 00692 *len = EAP_MSK_LEN; 00693 00694 return key; 00695 } 00696 00697 00698 static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 00699 { 00700 struct eap_gpsk_data *data = priv; 00701 u8 *key; 00702 00703 if (data->state != SUCCESS) 00704 return NULL; 00705 00706 key = os_malloc(EAP_EMSK_LEN); 00707 if (key == NULL) 00708 return NULL; 00709 os_memcpy(key, data->emsk, EAP_EMSK_LEN); 00710 *len = EAP_EMSK_LEN; 00711 00712 return key; 00713 } 00714 00715 00716 int eap_peer_gpsk_register(void) 00717 { 00718 struct eap_method *eap; 00719 int ret; 00720 00721 eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 00722 EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK"); 00723 if (eap == NULL) 00724 return -1; 00725 00726 eap->init = eap_gpsk_init; 00727 eap->deinit = eap_gpsk_deinit; 00728 eap->process = eap_gpsk_process; 00729 eap->isKeyAvailable = eap_gpsk_isKeyAvailable; 00730 eap->getKey = eap_gpsk_getKey; 00731 eap->get_emsk = eap_gpsk_get_emsk; 00732 00733 ret = eap_peer_method_register(eap); 00734 if (ret) 00735 eap_peer_method_free(eap); 00736 return ret; 00737 }