1214501Srpaulo/* 2214501Srpaulo * hostapd / EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt) 3214501Srpaulo * Copyright (c) 2004-2008, 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 "crypto/sha1.h" 19214501Srpaulo#include "crypto/tls.h" 20214501Srpaulo#include "eap_i.h" 21214501Srpaulo#include "eap_tls_common.h" 22214501Srpaulo#include "eap_common/eap_tlv_common.h" 23214501Srpaulo#include "eap_common/eap_peap_common.h" 24214501Srpaulo#include "tncs.h" 25214501Srpaulo 26214501Srpaulo 27214501Srpaulo/* Maximum supported PEAP version 28214501Srpaulo * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt 29214501Srpaulo * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt 30214501Srpaulo * 2 = draft-josefsson-ppext-eap-tls-eap-10.txt 31214501Srpaulo */ 32214501Srpaulo#define EAP_PEAP_VERSION 1 33214501Srpaulo 34214501Srpaulo 35214501Srpaulostatic void eap_peap_reset(struct eap_sm *sm, void *priv); 36214501Srpaulo 37214501Srpaulo 38214501Srpaulostruct eap_peap_data { 39214501Srpaulo struct eap_ssl_data ssl; 40214501Srpaulo enum { 41214501Srpaulo START, PHASE1, PHASE1_ID2, PHASE2_START, PHASE2_ID, 42214501Srpaulo PHASE2_METHOD, PHASE2_SOH, 43214501Srpaulo PHASE2_TLV, SUCCESS_REQ, FAILURE_REQ, SUCCESS, FAILURE 44214501Srpaulo } state; 45214501Srpaulo 46214501Srpaulo int peap_version; 47214501Srpaulo int recv_version; 48214501Srpaulo const struct eap_method *phase2_method; 49214501Srpaulo void *phase2_priv; 50214501Srpaulo int force_version; 51214501Srpaulo struct wpabuf *pending_phase2_resp; 52214501Srpaulo enum { TLV_REQ_NONE, TLV_REQ_SUCCESS, TLV_REQ_FAILURE } tlv_request; 53214501Srpaulo int crypto_binding_sent; 54214501Srpaulo int crypto_binding_used; 55214501Srpaulo enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding; 56214501Srpaulo u8 binding_nonce[32]; 57214501Srpaulo u8 ipmk[40]; 58214501Srpaulo u8 cmk[20]; 59214501Srpaulo u8 *phase2_key; 60214501Srpaulo size_t phase2_key_len; 61214501Srpaulo struct wpabuf *soh_response; 62214501Srpaulo}; 63214501Srpaulo 64214501Srpaulo 65214501Srpaulostatic const char * eap_peap_state_txt(int state) 66214501Srpaulo{ 67214501Srpaulo switch (state) { 68214501Srpaulo case START: 69214501Srpaulo return "START"; 70214501Srpaulo case PHASE1: 71214501Srpaulo return "PHASE1"; 72214501Srpaulo case PHASE1_ID2: 73214501Srpaulo return "PHASE1_ID2"; 74214501Srpaulo case PHASE2_START: 75214501Srpaulo return "PHASE2_START"; 76214501Srpaulo case PHASE2_ID: 77214501Srpaulo return "PHASE2_ID"; 78214501Srpaulo case PHASE2_METHOD: 79214501Srpaulo return "PHASE2_METHOD"; 80214501Srpaulo case PHASE2_SOH: 81214501Srpaulo return "PHASE2_SOH"; 82214501Srpaulo case PHASE2_TLV: 83214501Srpaulo return "PHASE2_TLV"; 84214501Srpaulo case SUCCESS_REQ: 85214501Srpaulo return "SUCCESS_REQ"; 86214501Srpaulo case FAILURE_REQ: 87214501Srpaulo return "FAILURE_REQ"; 88214501Srpaulo case SUCCESS: 89214501Srpaulo return "SUCCESS"; 90214501Srpaulo case FAILURE: 91214501Srpaulo return "FAILURE"; 92214501Srpaulo default: 93214501Srpaulo return "Unknown?!"; 94214501Srpaulo } 95214501Srpaulo} 96214501Srpaulo 97214501Srpaulo 98214501Srpaulostatic void eap_peap_state(struct eap_peap_data *data, int state) 99214501Srpaulo{ 100214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: %s -> %s", 101214501Srpaulo eap_peap_state_txt(data->state), 102214501Srpaulo eap_peap_state_txt(state)); 103214501Srpaulo data->state = state; 104214501Srpaulo} 105214501Srpaulo 106214501Srpaulo 107214501Srpaulostatic struct wpabuf * eap_peapv2_tlv_eap_payload(struct wpabuf *buf) 108214501Srpaulo{ 109214501Srpaulo struct wpabuf *e; 110214501Srpaulo struct eap_tlv_hdr *tlv; 111214501Srpaulo 112214501Srpaulo if (buf == NULL) 113214501Srpaulo return NULL; 114214501Srpaulo 115214501Srpaulo /* Encapsulate EAP packet in EAP-Payload TLV */ 116214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Add EAP-Payload TLV"); 117214501Srpaulo e = wpabuf_alloc(sizeof(*tlv) + wpabuf_len(buf)); 118214501Srpaulo if (e == NULL) { 119214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Failed to allocate memory " 120214501Srpaulo "for TLV encapsulation"); 121214501Srpaulo wpabuf_free(buf); 122214501Srpaulo return NULL; 123214501Srpaulo } 124214501Srpaulo tlv = wpabuf_put(e, sizeof(*tlv)); 125214501Srpaulo tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | 126214501Srpaulo EAP_TLV_EAP_PAYLOAD_TLV); 127214501Srpaulo tlv->length = host_to_be16(wpabuf_len(buf)); 128214501Srpaulo wpabuf_put_buf(e, buf); 129214501Srpaulo wpabuf_free(buf); 130214501Srpaulo return e; 131214501Srpaulo} 132214501Srpaulo 133214501Srpaulo 134214501Srpaulostatic void eap_peap_req_success(struct eap_sm *sm, 135214501Srpaulo struct eap_peap_data *data) 136214501Srpaulo{ 137214501Srpaulo if (data->state == FAILURE || data->state == FAILURE_REQ) { 138214501Srpaulo eap_peap_state(data, FAILURE); 139214501Srpaulo return; 140214501Srpaulo } 141214501Srpaulo 142214501Srpaulo if (data->peap_version == 0) { 143214501Srpaulo data->tlv_request = TLV_REQ_SUCCESS; 144214501Srpaulo eap_peap_state(data, PHASE2_TLV); 145214501Srpaulo } else { 146214501Srpaulo eap_peap_state(data, SUCCESS_REQ); 147214501Srpaulo } 148214501Srpaulo} 149214501Srpaulo 150214501Srpaulo 151214501Srpaulostatic void eap_peap_req_failure(struct eap_sm *sm, 152214501Srpaulo struct eap_peap_data *data) 153214501Srpaulo{ 154214501Srpaulo if (data->state == FAILURE || data->state == FAILURE_REQ || 155214501Srpaulo data->state == SUCCESS_REQ || data->tlv_request != TLV_REQ_NONE) { 156214501Srpaulo eap_peap_state(data, FAILURE); 157214501Srpaulo return; 158214501Srpaulo } 159214501Srpaulo 160214501Srpaulo if (data->peap_version == 0) { 161214501Srpaulo data->tlv_request = TLV_REQ_FAILURE; 162214501Srpaulo eap_peap_state(data, PHASE2_TLV); 163214501Srpaulo } else { 164214501Srpaulo eap_peap_state(data, FAILURE_REQ); 165214501Srpaulo } 166214501Srpaulo} 167214501Srpaulo 168214501Srpaulo 169214501Srpaulostatic void * eap_peap_init(struct eap_sm *sm) 170214501Srpaulo{ 171214501Srpaulo struct eap_peap_data *data; 172214501Srpaulo 173214501Srpaulo data = os_zalloc(sizeof(*data)); 174214501Srpaulo if (data == NULL) 175214501Srpaulo return NULL; 176214501Srpaulo data->peap_version = EAP_PEAP_VERSION; 177214501Srpaulo data->force_version = -1; 178214501Srpaulo if (sm->user && sm->user->force_version >= 0) { 179214501Srpaulo data->force_version = sm->user->force_version; 180214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: forcing version %d", 181214501Srpaulo data->force_version); 182214501Srpaulo data->peap_version = data->force_version; 183214501Srpaulo } 184214501Srpaulo data->state = START; 185214501Srpaulo data->crypto_binding = OPTIONAL_BINDING; 186214501Srpaulo 187214501Srpaulo if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) { 188214501Srpaulo wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL."); 189214501Srpaulo eap_peap_reset(sm, data); 190214501Srpaulo return NULL; 191214501Srpaulo } 192214501Srpaulo 193214501Srpaulo return data; 194214501Srpaulo} 195214501Srpaulo 196214501Srpaulo 197214501Srpaulostatic void eap_peap_reset(struct eap_sm *sm, void *priv) 198214501Srpaulo{ 199214501Srpaulo struct eap_peap_data *data = priv; 200214501Srpaulo if (data == NULL) 201214501Srpaulo return; 202214501Srpaulo if (data->phase2_priv && data->phase2_method) 203214501Srpaulo data->phase2_method->reset(sm, data->phase2_priv); 204214501Srpaulo eap_server_tls_ssl_deinit(sm, &data->ssl); 205214501Srpaulo wpabuf_free(data->pending_phase2_resp); 206214501Srpaulo os_free(data->phase2_key); 207214501Srpaulo wpabuf_free(data->soh_response); 208214501Srpaulo os_free(data); 209214501Srpaulo} 210214501Srpaulo 211214501Srpaulo 212214501Srpaulostatic struct wpabuf * eap_peap_build_start(struct eap_sm *sm, 213214501Srpaulo struct eap_peap_data *data, u8 id) 214214501Srpaulo{ 215214501Srpaulo struct wpabuf *req; 216214501Srpaulo 217214501Srpaulo req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PEAP, 1, 218214501Srpaulo EAP_CODE_REQUEST, id); 219214501Srpaulo if (req == NULL) { 220214501Srpaulo wpa_printf(MSG_ERROR, "EAP-PEAP: Failed to allocate memory for" 221214501Srpaulo " request"); 222214501Srpaulo eap_peap_state(data, FAILURE); 223214501Srpaulo return NULL; 224214501Srpaulo } 225214501Srpaulo 226214501Srpaulo wpabuf_put_u8(req, EAP_TLS_FLAGS_START | data->peap_version); 227214501Srpaulo 228214501Srpaulo eap_peap_state(data, PHASE1); 229214501Srpaulo 230214501Srpaulo return req; 231214501Srpaulo} 232214501Srpaulo 233214501Srpaulo 234214501Srpaulostatic struct wpabuf * eap_peap_build_phase2_req(struct eap_sm *sm, 235214501Srpaulo struct eap_peap_data *data, 236214501Srpaulo u8 id) 237214501Srpaulo{ 238214501Srpaulo struct wpabuf *buf, *encr_req, msgbuf; 239214501Srpaulo const u8 *req; 240214501Srpaulo size_t req_len; 241214501Srpaulo 242214501Srpaulo if (data->phase2_method == NULL || data->phase2_priv == NULL) { 243214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 method not ready"); 244214501Srpaulo return NULL; 245214501Srpaulo } 246214501Srpaulo buf = data->phase2_method->buildReq(sm, data->phase2_priv, id); 247214501Srpaulo if (data->peap_version >= 2 && buf) 248214501Srpaulo buf = eap_peapv2_tlv_eap_payload(buf); 249214501Srpaulo if (buf == NULL) 250214501Srpaulo return NULL; 251214501Srpaulo 252214501Srpaulo req = wpabuf_head(buf); 253214501Srpaulo req_len = wpabuf_len(buf); 254214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data", 255214501Srpaulo req, req_len); 256214501Srpaulo 257214501Srpaulo if (data->peap_version == 0 && 258214501Srpaulo data->phase2_method->method != EAP_TYPE_TLV) { 259214501Srpaulo req += sizeof(struct eap_hdr); 260214501Srpaulo req_len -= sizeof(struct eap_hdr); 261214501Srpaulo } 262214501Srpaulo 263214501Srpaulo wpabuf_set(&msgbuf, req, req_len); 264214501Srpaulo encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf); 265214501Srpaulo wpabuf_free(buf); 266214501Srpaulo 267214501Srpaulo return encr_req; 268214501Srpaulo} 269214501Srpaulo 270214501Srpaulo 271214501Srpaulo#ifdef EAP_SERVER_TNC 272214501Srpaulostatic struct wpabuf * eap_peap_build_phase2_soh(struct eap_sm *sm, 273214501Srpaulo struct eap_peap_data *data, 274214501Srpaulo u8 id) 275214501Srpaulo{ 276214501Srpaulo struct wpabuf *buf1, *buf, *encr_req, msgbuf; 277214501Srpaulo const u8 *req; 278214501Srpaulo size_t req_len; 279214501Srpaulo 280214501Srpaulo buf1 = tncs_build_soh_request(); 281214501Srpaulo if (buf1 == NULL) 282214501Srpaulo return NULL; 283214501Srpaulo 284214501Srpaulo buf = eap_msg_alloc(EAP_VENDOR_MICROSOFT, 0x21, wpabuf_len(buf1), 285214501Srpaulo EAP_CODE_REQUEST, id); 286214501Srpaulo if (buf == NULL) { 287214501Srpaulo wpabuf_free(buf1); 288214501Srpaulo return NULL; 289214501Srpaulo } 290214501Srpaulo wpabuf_put_buf(buf, buf1); 291214501Srpaulo wpabuf_free(buf1); 292214501Srpaulo 293214501Srpaulo req = wpabuf_head(buf); 294214501Srpaulo req_len = wpabuf_len(buf); 295214501Srpaulo 296214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 SOH data", 297214501Srpaulo req, req_len); 298214501Srpaulo 299214501Srpaulo req += sizeof(struct eap_hdr); 300214501Srpaulo req_len -= sizeof(struct eap_hdr); 301214501Srpaulo wpabuf_set(&msgbuf, req, req_len); 302214501Srpaulo 303214501Srpaulo encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf); 304214501Srpaulo wpabuf_free(buf); 305214501Srpaulo 306214501Srpaulo return encr_req; 307214501Srpaulo} 308214501Srpaulo#endif /* EAP_SERVER_TNC */ 309214501Srpaulo 310214501Srpaulo 311214501Srpaulostatic void eap_peap_get_isk(struct eap_peap_data *data, 312214501Srpaulo u8 *isk, size_t isk_len) 313214501Srpaulo{ 314214501Srpaulo size_t key_len; 315214501Srpaulo 316214501Srpaulo os_memset(isk, 0, isk_len); 317214501Srpaulo if (data->phase2_key == NULL) 318214501Srpaulo return; 319214501Srpaulo 320214501Srpaulo key_len = data->phase2_key_len; 321214501Srpaulo if (key_len > isk_len) 322214501Srpaulo key_len = isk_len; 323214501Srpaulo os_memcpy(isk, data->phase2_key, key_len); 324214501Srpaulo} 325214501Srpaulo 326214501Srpaulo 327214501Srpaulostatic int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data) 328214501Srpaulo{ 329214501Srpaulo u8 *tk; 330214501Srpaulo u8 isk[32], imck[60]; 331214501Srpaulo 332214501Srpaulo /* 333214501Srpaulo * Tunnel key (TK) is the first 60 octets of the key generated by 334214501Srpaulo * phase 1 of PEAP (based on TLS). 335214501Srpaulo */ 336214501Srpaulo tk = eap_server_tls_derive_key(sm, &data->ssl, "client EAP encryption", 337214501Srpaulo EAP_TLS_KEY_LEN); 338214501Srpaulo if (tk == NULL) 339214501Srpaulo return -1; 340214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60); 341214501Srpaulo 342214501Srpaulo eap_peap_get_isk(data, isk, sizeof(isk)); 343214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk)); 344214501Srpaulo 345214501Srpaulo /* 346214501Srpaulo * IPMK Seed = "Inner Methods Compound Keys" | ISK 347214501Srpaulo * TempKey = First 40 octets of TK 348214501Srpaulo * IPMK|CMK = PRF+(TempKey, IPMK Seed, 60) 349214501Srpaulo * (note: draft-josefsson-pppext-eap-tls-eap-10.txt includes a space 350214501Srpaulo * in the end of the label just before ISK; is that just a typo?) 351214501Srpaulo */ 352214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40); 353214501Srpaulo peap_prfplus(data->peap_version, tk, 40, "Inner Methods Compound Keys", 354214501Srpaulo isk, sizeof(isk), imck, sizeof(imck)); 355214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)", 356214501Srpaulo imck, sizeof(imck)); 357214501Srpaulo 358214501Srpaulo os_free(tk); 359214501Srpaulo 360214501Srpaulo /* TODO: fast-connect: IPMK|CMK = TK */ 361214501Srpaulo os_memcpy(data->ipmk, imck, 40); 362214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40); 363214501Srpaulo os_memcpy(data->cmk, imck + 40, 20); 364214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20); 365214501Srpaulo 366214501Srpaulo return 0; 367214501Srpaulo} 368214501Srpaulo 369214501Srpaulo 370214501Srpaulostatic struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm, 371214501Srpaulo struct eap_peap_data *data, 372214501Srpaulo u8 id) 373214501Srpaulo{ 374214501Srpaulo struct wpabuf *buf, *encr_req; 375214501Srpaulo size_t mlen; 376214501Srpaulo 377214501Srpaulo mlen = 6; /* Result TLV */ 378214501Srpaulo if (data->crypto_binding != NO_BINDING) 379214501Srpaulo mlen += 60; /* Cryptobinding TLV */ 380214501Srpaulo#ifdef EAP_SERVER_TNC 381214501Srpaulo if (data->soh_response) 382214501Srpaulo mlen += wpabuf_len(data->soh_response); 383214501Srpaulo#endif /* EAP_SERVER_TNC */ 384214501Srpaulo 385214501Srpaulo buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, mlen, 386214501Srpaulo EAP_CODE_REQUEST, id); 387214501Srpaulo if (buf == NULL) 388214501Srpaulo return NULL; 389214501Srpaulo 390214501Srpaulo wpabuf_put_u8(buf, 0x80); /* Mandatory */ 391214501Srpaulo wpabuf_put_u8(buf, EAP_TLV_RESULT_TLV); 392214501Srpaulo /* Length */ 393214501Srpaulo wpabuf_put_be16(buf, 2); 394214501Srpaulo /* Status */ 395214501Srpaulo wpabuf_put_be16(buf, data->tlv_request == TLV_REQ_SUCCESS ? 396214501Srpaulo EAP_TLV_RESULT_SUCCESS : EAP_TLV_RESULT_FAILURE); 397214501Srpaulo 398214501Srpaulo if (data->peap_version == 0 && data->tlv_request == TLV_REQ_SUCCESS && 399214501Srpaulo data->crypto_binding != NO_BINDING) { 400214501Srpaulo u8 *mac; 401214501Srpaulo u8 eap_type = EAP_TYPE_PEAP; 402214501Srpaulo const u8 *addr[2]; 403214501Srpaulo size_t len[2]; 404214501Srpaulo u16 tlv_type; 405214501Srpaulo 406214501Srpaulo#ifdef EAP_SERVER_TNC 407214501Srpaulo if (data->soh_response) { 408214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: Adding MS-SOH " 409214501Srpaulo "Response TLV"); 410214501Srpaulo wpabuf_put_buf(buf, data->soh_response); 411214501Srpaulo wpabuf_free(data->soh_response); 412214501Srpaulo data->soh_response = NULL; 413214501Srpaulo } 414214501Srpaulo#endif /* EAP_SERVER_TNC */ 415214501Srpaulo 416214501Srpaulo if (eap_peap_derive_cmk(sm, data) < 0 || 417214501Srpaulo os_get_random(data->binding_nonce, 32)) { 418214501Srpaulo wpabuf_free(buf); 419214501Srpaulo return NULL; 420214501Srpaulo } 421214501Srpaulo 422214501Srpaulo /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */ 423214501Srpaulo addr[0] = wpabuf_put(buf, 0); 424214501Srpaulo len[0] = 60; 425214501Srpaulo addr[1] = &eap_type; 426214501Srpaulo len[1] = 1; 427214501Srpaulo 428214501Srpaulo tlv_type = EAP_TLV_CRYPTO_BINDING_TLV; 429214501Srpaulo if (data->peap_version >= 2) 430214501Srpaulo tlv_type |= EAP_TLV_TYPE_MANDATORY; 431214501Srpaulo wpabuf_put_be16(buf, tlv_type); 432214501Srpaulo wpabuf_put_be16(buf, 56); 433214501Srpaulo 434214501Srpaulo wpabuf_put_u8(buf, 0); /* Reserved */ 435214501Srpaulo wpabuf_put_u8(buf, data->peap_version); /* Version */ 436214501Srpaulo wpabuf_put_u8(buf, data->recv_version); /* RecvVersion */ 437214501Srpaulo wpabuf_put_u8(buf, 0); /* SubType: 0 = Request, 1 = Response */ 438214501Srpaulo wpabuf_put_data(buf, data->binding_nonce, 32); /* Nonce */ 439214501Srpaulo mac = wpabuf_put(buf, 20); /* Compound_MAC */ 440214501Srpaulo wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK", 441214501Srpaulo data->cmk, 20); 442214501Srpaulo wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1", 443214501Srpaulo addr[0], len[0]); 444214501Srpaulo wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2", 445214501Srpaulo addr[1], len[1]); 446214501Srpaulo hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac); 447214501Srpaulo wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC", 448214501Srpaulo mac, SHA1_MAC_LEN); 449214501Srpaulo data->crypto_binding_sent = 1; 450214501Srpaulo } 451214501Srpaulo 452214501Srpaulo wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 TLV data", 453214501Srpaulo buf); 454214501Srpaulo 455214501Srpaulo encr_req = eap_server_tls_encrypt(sm, &data->ssl, buf); 456214501Srpaulo wpabuf_free(buf); 457214501Srpaulo 458214501Srpaulo return encr_req; 459214501Srpaulo} 460214501Srpaulo 461214501Srpaulo 462214501Srpaulostatic struct wpabuf * eap_peap_build_phase2_term(struct eap_sm *sm, 463214501Srpaulo struct eap_peap_data *data, 464214501Srpaulo u8 id, int success) 465214501Srpaulo{ 466214501Srpaulo struct wpabuf *encr_req, msgbuf; 467214501Srpaulo size_t req_len; 468214501Srpaulo struct eap_hdr *hdr; 469214501Srpaulo 470214501Srpaulo req_len = sizeof(*hdr); 471214501Srpaulo hdr = os_zalloc(req_len); 472214501Srpaulo if (hdr == NULL) 473214501Srpaulo return NULL; 474214501Srpaulo 475214501Srpaulo hdr->code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE; 476214501Srpaulo hdr->identifier = id; 477214501Srpaulo hdr->length = host_to_be16(req_len); 478214501Srpaulo 479214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data", 480214501Srpaulo (u8 *) hdr, req_len); 481214501Srpaulo 482214501Srpaulo wpabuf_set(&msgbuf, hdr, req_len); 483214501Srpaulo encr_req = eap_server_tls_encrypt(sm, &data->ssl, &msgbuf); 484214501Srpaulo os_free(hdr); 485214501Srpaulo 486214501Srpaulo return encr_req; 487214501Srpaulo} 488214501Srpaulo 489214501Srpaulo 490214501Srpaulostatic struct wpabuf * eap_peap_buildReq(struct eap_sm *sm, void *priv, u8 id) 491214501Srpaulo{ 492214501Srpaulo struct eap_peap_data *data = priv; 493214501Srpaulo 494214501Srpaulo if (data->ssl.state == FRAG_ACK) { 495214501Srpaulo return eap_server_tls_build_ack(id, EAP_TYPE_PEAP, 496214501Srpaulo data->peap_version); 497214501Srpaulo } 498214501Srpaulo 499214501Srpaulo if (data->ssl.state == WAIT_FRAG_ACK) { 500214501Srpaulo return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP, 501214501Srpaulo data->peap_version, id); 502214501Srpaulo } 503214501Srpaulo 504214501Srpaulo switch (data->state) { 505214501Srpaulo case START: 506214501Srpaulo return eap_peap_build_start(sm, data, id); 507214501Srpaulo case PHASE1: 508214501Srpaulo case PHASE1_ID2: 509214501Srpaulo if (data->peap_version < 2 && 510214501Srpaulo tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { 511214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase1 done, " 512214501Srpaulo "starting Phase2"); 513214501Srpaulo eap_peap_state(data, PHASE2_START); 514214501Srpaulo } 515214501Srpaulo break; 516214501Srpaulo case PHASE2_ID: 517214501Srpaulo case PHASE2_METHOD: 518214501Srpaulo wpabuf_free(data->ssl.tls_out); 519214501Srpaulo data->ssl.tls_out_pos = 0; 520214501Srpaulo data->ssl.tls_out = eap_peap_build_phase2_req(sm, data, id); 521214501Srpaulo break; 522214501Srpaulo#ifdef EAP_SERVER_TNC 523214501Srpaulo case PHASE2_SOH: 524214501Srpaulo wpabuf_free(data->ssl.tls_out); 525214501Srpaulo data->ssl.tls_out_pos = 0; 526214501Srpaulo data->ssl.tls_out = eap_peap_build_phase2_soh(sm, data, id); 527214501Srpaulo break; 528214501Srpaulo#endif /* EAP_SERVER_TNC */ 529214501Srpaulo case PHASE2_TLV: 530214501Srpaulo wpabuf_free(data->ssl.tls_out); 531214501Srpaulo data->ssl.tls_out_pos = 0; 532214501Srpaulo data->ssl.tls_out = eap_peap_build_phase2_tlv(sm, data, id); 533214501Srpaulo break; 534214501Srpaulo case SUCCESS_REQ: 535214501Srpaulo wpabuf_free(data->ssl.tls_out); 536214501Srpaulo data->ssl.tls_out_pos = 0; 537214501Srpaulo data->ssl.tls_out = eap_peap_build_phase2_term(sm, data, id, 538214501Srpaulo 1); 539214501Srpaulo break; 540214501Srpaulo case FAILURE_REQ: 541214501Srpaulo wpabuf_free(data->ssl.tls_out); 542214501Srpaulo data->ssl.tls_out_pos = 0; 543214501Srpaulo data->ssl.tls_out = eap_peap_build_phase2_term(sm, data, id, 544214501Srpaulo 0); 545214501Srpaulo break; 546214501Srpaulo default: 547214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d", 548214501Srpaulo __func__, data->state); 549214501Srpaulo return NULL; 550214501Srpaulo } 551214501Srpaulo 552214501Srpaulo return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_PEAP, 553214501Srpaulo data->peap_version, id); 554214501Srpaulo} 555214501Srpaulo 556214501Srpaulo 557214501Srpaulostatic Boolean eap_peap_check(struct eap_sm *sm, void *priv, 558214501Srpaulo struct wpabuf *respData) 559214501Srpaulo{ 560214501Srpaulo const u8 *pos; 561214501Srpaulo size_t len; 562214501Srpaulo 563214501Srpaulo pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PEAP, respData, &len); 564214501Srpaulo if (pos == NULL || len < 1) { 565214501Srpaulo wpa_printf(MSG_INFO, "EAP-PEAP: Invalid frame"); 566214501Srpaulo return TRUE; 567214501Srpaulo } 568214501Srpaulo 569214501Srpaulo return FALSE; 570214501Srpaulo} 571214501Srpaulo 572214501Srpaulo 573214501Srpaulostatic int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data, 574214501Srpaulo EapType eap_type) 575214501Srpaulo{ 576214501Srpaulo if (data->phase2_priv && data->phase2_method) { 577214501Srpaulo data->phase2_method->reset(sm, data->phase2_priv); 578214501Srpaulo data->phase2_method = NULL; 579214501Srpaulo data->phase2_priv = NULL; 580214501Srpaulo } 581214501Srpaulo data->phase2_method = eap_server_get_eap_method(EAP_VENDOR_IETF, 582214501Srpaulo eap_type); 583214501Srpaulo if (!data->phase2_method) 584214501Srpaulo return -1; 585214501Srpaulo 586214501Srpaulo sm->init_phase2 = 1; 587214501Srpaulo data->phase2_priv = data->phase2_method->init(sm); 588214501Srpaulo sm->init_phase2 = 0; 589214501Srpaulo return 0; 590214501Srpaulo} 591214501Srpaulo 592214501Srpaulo 593214501Srpaulostatic int eap_tlv_validate_cryptobinding(struct eap_sm *sm, 594214501Srpaulo struct eap_peap_data *data, 595214501Srpaulo const u8 *crypto_tlv, 596214501Srpaulo size_t crypto_tlv_len) 597214501Srpaulo{ 598214501Srpaulo u8 buf[61], mac[SHA1_MAC_LEN]; 599214501Srpaulo const u8 *pos; 600214501Srpaulo 601214501Srpaulo if (crypto_tlv_len != 4 + 56) { 602214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid cryptobinding TLV " 603214501Srpaulo "length %d", (int) crypto_tlv_len); 604214501Srpaulo return -1; 605214501Srpaulo } 606214501Srpaulo 607214501Srpaulo pos = crypto_tlv; 608214501Srpaulo pos += 4; /* TLV header */ 609214501Srpaulo if (pos[1] != data->peap_version) { 610214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV Version " 611214501Srpaulo "mismatch (was %d; expected %d)", 612214501Srpaulo pos[1], data->peap_version); 613214501Srpaulo return -1; 614214501Srpaulo } 615214501Srpaulo 616214501Srpaulo if (pos[3] != 1) { 617214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected Cryptobinding TLV " 618214501Srpaulo "SubType %d", pos[3]); 619214501Srpaulo return -1; 620214501Srpaulo } 621214501Srpaulo pos += 4; 622214501Srpaulo pos += 32; /* Nonce */ 623214501Srpaulo 624214501Srpaulo /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */ 625214501Srpaulo os_memcpy(buf, crypto_tlv, 60); 626214501Srpaulo os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */ 627214501Srpaulo buf[60] = EAP_TYPE_PEAP; 628214501Srpaulo hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac); 629214501Srpaulo 630214501Srpaulo if (os_memcmp(mac, pos, SHA1_MAC_LEN) != 0) { 631214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in " 632214501Srpaulo "cryptobinding TLV"); 633214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK", data->cmk, 20); 634214501Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding seed data", 635214501Srpaulo buf, 61); 636214501Srpaulo return -1; 637214501Srpaulo } 638214501Srpaulo 639214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received"); 640214501Srpaulo 641214501Srpaulo return 0; 642214501Srpaulo} 643214501Srpaulo 644214501Srpaulo 645214501Srpaulostatic void eap_peap_process_phase2_tlv(struct eap_sm *sm, 646214501Srpaulo struct eap_peap_data *data, 647214501Srpaulo struct wpabuf *in_data) 648214501Srpaulo{ 649214501Srpaulo const u8 *pos; 650214501Srpaulo size_t left; 651214501Srpaulo const u8 *result_tlv = NULL, *crypto_tlv = NULL; 652214501Srpaulo size_t result_tlv_len = 0, crypto_tlv_len = 0; 653214501Srpaulo int tlv_type, mandatory, tlv_len; 654214501Srpaulo 655214501Srpaulo pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, in_data, &left); 656214501Srpaulo if (pos == NULL) { 657214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid EAP-TLV header"); 658214501Srpaulo return; 659214501Srpaulo } 660214501Srpaulo 661214501Srpaulo /* Parse TLVs */ 662214501Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received TLVs", pos, left); 663214501Srpaulo while (left >= 4) { 664214501Srpaulo mandatory = !!(pos[0] & 0x80); 665214501Srpaulo tlv_type = pos[0] & 0x3f; 666214501Srpaulo tlv_type = (tlv_type << 8) | pos[1]; 667214501Srpaulo tlv_len = ((int) pos[2] << 8) | pos[3]; 668214501Srpaulo pos += 4; 669214501Srpaulo left -= 4; 670214501Srpaulo if ((size_t) tlv_len > left) { 671214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: TLV underrun " 672214501Srpaulo "(tlv_len=%d left=%lu)", tlv_len, 673214501Srpaulo (unsigned long) left); 674214501Srpaulo eap_peap_state(data, FAILURE); 675214501Srpaulo return; 676214501Srpaulo } 677214501Srpaulo switch (tlv_type) { 678214501Srpaulo case EAP_TLV_RESULT_TLV: 679214501Srpaulo result_tlv = pos; 680214501Srpaulo result_tlv_len = tlv_len; 681214501Srpaulo break; 682214501Srpaulo case EAP_TLV_CRYPTO_BINDING_TLV: 683214501Srpaulo crypto_tlv = pos; 684214501Srpaulo crypto_tlv_len = tlv_len; 685214501Srpaulo break; 686214501Srpaulo default: 687214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported TLV Type " 688214501Srpaulo "%d%s", tlv_type, 689214501Srpaulo mandatory ? " (mandatory)" : ""); 690214501Srpaulo if (mandatory) { 691214501Srpaulo eap_peap_state(data, FAILURE); 692214501Srpaulo return; 693214501Srpaulo } 694214501Srpaulo /* Ignore this TLV, but process other TLVs */ 695214501Srpaulo break; 696214501Srpaulo } 697214501Srpaulo 698214501Srpaulo pos += tlv_len; 699214501Srpaulo left -= tlv_len; 700214501Srpaulo } 701214501Srpaulo if (left) { 702214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: Last TLV too short in " 703214501Srpaulo "Request (left=%lu)", (unsigned long) left); 704214501Srpaulo eap_peap_state(data, FAILURE); 705214501Srpaulo return; 706214501Srpaulo } 707214501Srpaulo 708214501Srpaulo /* Process supported TLVs */ 709214501Srpaulo if (crypto_tlv && data->crypto_binding_sent) { 710214501Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV", 711214501Srpaulo crypto_tlv, crypto_tlv_len); 712214501Srpaulo if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4, 713214501Srpaulo crypto_tlv_len + 4) < 0) { 714214501Srpaulo eap_peap_state(data, FAILURE); 715214501Srpaulo return; 716214501Srpaulo } 717214501Srpaulo data->crypto_binding_used = 1; 718214501Srpaulo } else if (!crypto_tlv && data->crypto_binding_sent && 719214501Srpaulo data->crypto_binding == REQUIRE_BINDING) { 720214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV"); 721214501Srpaulo eap_peap_state(data, FAILURE); 722214501Srpaulo return; 723214501Srpaulo } 724214501Srpaulo 725214501Srpaulo if (result_tlv) { 726214501Srpaulo int status; 727214501Srpaulo const char *requested; 728214501Srpaulo 729214501Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Result TLV", 730214501Srpaulo result_tlv, result_tlv_len); 731214501Srpaulo if (result_tlv_len < 2) { 732214501Srpaulo wpa_printf(MSG_INFO, "EAP-PEAP: Too short Result TLV " 733214501Srpaulo "(len=%lu)", 734214501Srpaulo (unsigned long) result_tlv_len); 735214501Srpaulo eap_peap_state(data, FAILURE); 736214501Srpaulo return; 737214501Srpaulo } 738214501Srpaulo requested = data->tlv_request == TLV_REQ_SUCCESS ? "Success" : 739214501Srpaulo "Failure"; 740214501Srpaulo status = WPA_GET_BE16(result_tlv); 741214501Srpaulo if (status == EAP_TLV_RESULT_SUCCESS) { 742214501Srpaulo wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Success " 743214501Srpaulo "- requested %s", requested); 744214501Srpaulo if (data->tlv_request == TLV_REQ_SUCCESS) 745214501Srpaulo eap_peap_state(data, SUCCESS); 746214501Srpaulo else 747214501Srpaulo eap_peap_state(data, FAILURE); 748214501Srpaulo 749214501Srpaulo } else if (status == EAP_TLV_RESULT_FAILURE) { 750214501Srpaulo wpa_printf(MSG_INFO, "EAP-PEAP: TLV Result - Failure " 751214501Srpaulo "- requested %s", requested); 752214501Srpaulo eap_peap_state(data, FAILURE); 753214501Srpaulo } else { 754214501Srpaulo wpa_printf(MSG_INFO, "EAP-PEAP: Unknown TLV Result " 755214501Srpaulo "Status %d", status); 756214501Srpaulo eap_peap_state(data, FAILURE); 757214501Srpaulo } 758214501Srpaulo } 759214501Srpaulo} 760214501Srpaulo 761214501Srpaulo 762214501Srpaulo#ifdef EAP_SERVER_TNC 763214501Srpaulostatic void eap_peap_process_phase2_soh(struct eap_sm *sm, 764214501Srpaulo struct eap_peap_data *data, 765214501Srpaulo struct wpabuf *in_data) 766214501Srpaulo{ 767214501Srpaulo const u8 *pos, *vpos; 768214501Srpaulo size_t left; 769214501Srpaulo const u8 *soh_tlv = NULL; 770214501Srpaulo size_t soh_tlv_len = 0; 771214501Srpaulo int tlv_type, mandatory, tlv_len, vtlv_len; 772214501Srpaulo u8 next_type; 773214501Srpaulo u32 vendor_id; 774214501Srpaulo 775214501Srpaulo pos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21, in_data, &left); 776214501Srpaulo if (pos == NULL) { 777214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: Not a valid SoH EAP " 778214501Srpaulo "Extensions Method header - skip TNC"); 779214501Srpaulo goto auth_method; 780214501Srpaulo } 781214501Srpaulo 782214501Srpaulo /* Parse TLVs */ 783214501Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received TLVs (SoH)", pos, left); 784214501Srpaulo while (left >= 4) { 785214501Srpaulo mandatory = !!(pos[0] & 0x80); 786214501Srpaulo tlv_type = pos[0] & 0x3f; 787214501Srpaulo tlv_type = (tlv_type << 8) | pos[1]; 788214501Srpaulo tlv_len = ((int) pos[2] << 8) | pos[3]; 789214501Srpaulo pos += 4; 790214501Srpaulo left -= 4; 791214501Srpaulo if ((size_t) tlv_len > left) { 792214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: TLV underrun " 793214501Srpaulo "(tlv_len=%d left=%lu)", tlv_len, 794214501Srpaulo (unsigned long) left); 795214501Srpaulo eap_peap_state(data, FAILURE); 796214501Srpaulo return; 797214501Srpaulo } 798214501Srpaulo switch (tlv_type) { 799214501Srpaulo case EAP_TLV_VENDOR_SPECIFIC_TLV: 800214501Srpaulo if (tlv_len < 4) { 801214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: Too short " 802214501Srpaulo "vendor specific TLV (len=%d)", 803214501Srpaulo (int) tlv_len); 804214501Srpaulo eap_peap_state(data, FAILURE); 805214501Srpaulo return; 806214501Srpaulo } 807214501Srpaulo 808214501Srpaulo vendor_id = WPA_GET_BE32(pos); 809214501Srpaulo if (vendor_id != EAP_VENDOR_MICROSOFT) { 810214501Srpaulo if (mandatory) { 811214501Srpaulo eap_peap_state(data, FAILURE); 812214501Srpaulo return; 813214501Srpaulo } 814214501Srpaulo break; 815214501Srpaulo } 816214501Srpaulo 817214501Srpaulo vpos = pos + 4; 818214501Srpaulo mandatory = !!(vpos[0] & 0x80); 819214501Srpaulo tlv_type = vpos[0] & 0x3f; 820214501Srpaulo tlv_type = (tlv_type << 8) | vpos[1]; 821214501Srpaulo vtlv_len = ((int) vpos[2] << 8) | vpos[3]; 822214501Srpaulo vpos += 4; 823214501Srpaulo if (vpos + vtlv_len > pos + left) { 824214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: Vendor TLV " 825214501Srpaulo "underrun"); 826214501Srpaulo eap_peap_state(data, FAILURE); 827214501Srpaulo return; 828214501Srpaulo } 829214501Srpaulo 830214501Srpaulo if (tlv_type == 1) { 831214501Srpaulo soh_tlv = vpos; 832214501Srpaulo soh_tlv_len = vtlv_len; 833214501Srpaulo break; 834214501Srpaulo } 835214501Srpaulo 836214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported MS-TLV " 837214501Srpaulo "Type %d%s", tlv_type, 838214501Srpaulo mandatory ? " (mandatory)" : ""); 839214501Srpaulo if (mandatory) { 840214501Srpaulo eap_peap_state(data, FAILURE); 841214501Srpaulo return; 842214501Srpaulo } 843214501Srpaulo /* Ignore this TLV, but process other TLVs */ 844214501Srpaulo break; 845214501Srpaulo default: 846214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: Unsupported TLV Type " 847214501Srpaulo "%d%s", tlv_type, 848214501Srpaulo mandatory ? " (mandatory)" : ""); 849214501Srpaulo if (mandatory) { 850214501Srpaulo eap_peap_state(data, FAILURE); 851214501Srpaulo return; 852214501Srpaulo } 853214501Srpaulo /* Ignore this TLV, but process other TLVs */ 854214501Srpaulo break; 855214501Srpaulo } 856214501Srpaulo 857214501Srpaulo pos += tlv_len; 858214501Srpaulo left -= tlv_len; 859214501Srpaulo } 860214501Srpaulo if (left) { 861214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: Last TLV too short in " 862214501Srpaulo "Request (left=%lu)", (unsigned long) left); 863214501Srpaulo eap_peap_state(data, FAILURE); 864214501Srpaulo return; 865214501Srpaulo } 866214501Srpaulo 867214501Srpaulo /* Process supported TLVs */ 868214501Srpaulo if (soh_tlv) { 869214501Srpaulo int failure = 0; 870214501Srpaulo wpabuf_free(data->soh_response); 871214501Srpaulo data->soh_response = tncs_process_soh(soh_tlv, soh_tlv_len, 872214501Srpaulo &failure); 873214501Srpaulo if (failure) { 874214501Srpaulo eap_peap_state(data, FAILURE); 875214501Srpaulo return; 876214501Srpaulo } 877214501Srpaulo } else { 878214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: No SoH TLV received"); 879214501Srpaulo eap_peap_state(data, FAILURE); 880214501Srpaulo return; 881214501Srpaulo } 882214501Srpaulo 883214501Srpauloauth_method: 884214501Srpaulo eap_peap_state(data, PHASE2_METHOD); 885214501Srpaulo next_type = sm->user->methods[0].method; 886214501Srpaulo sm->user_eap_method_index = 1; 887214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type); 888214501Srpaulo eap_peap_phase2_init(sm, data, next_type); 889214501Srpaulo} 890214501Srpaulo#endif /* EAP_SERVER_TNC */ 891214501Srpaulo 892214501Srpaulo 893214501Srpaulostatic void eap_peap_process_phase2_response(struct eap_sm *sm, 894214501Srpaulo struct eap_peap_data *data, 895214501Srpaulo struct wpabuf *in_data) 896214501Srpaulo{ 897214501Srpaulo u8 next_type = EAP_TYPE_NONE; 898214501Srpaulo const struct eap_hdr *hdr; 899214501Srpaulo const u8 *pos; 900214501Srpaulo size_t left; 901214501Srpaulo 902214501Srpaulo if (data->state == PHASE2_TLV) { 903214501Srpaulo eap_peap_process_phase2_tlv(sm, data, in_data); 904214501Srpaulo return; 905214501Srpaulo } 906214501Srpaulo 907214501Srpaulo#ifdef EAP_SERVER_TNC 908214501Srpaulo if (data->state == PHASE2_SOH) { 909214501Srpaulo eap_peap_process_phase2_soh(sm, data, in_data); 910214501Srpaulo return; 911214501Srpaulo } 912214501Srpaulo#endif /* EAP_SERVER_TNC */ 913214501Srpaulo 914214501Srpaulo if (data->phase2_priv == NULL) { 915214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - Phase2 not " 916214501Srpaulo "initialized?!", __func__); 917214501Srpaulo return; 918214501Srpaulo } 919214501Srpaulo 920214501Srpaulo hdr = wpabuf_head(in_data); 921214501Srpaulo pos = (const u8 *) (hdr + 1); 922214501Srpaulo 923214501Srpaulo if (wpabuf_len(in_data) > sizeof(*hdr) && *pos == EAP_TYPE_NAK) { 924214501Srpaulo left = wpabuf_len(in_data) - sizeof(*hdr); 925214501Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Phase2 type Nak'ed; " 926214501Srpaulo "allowed types", pos + 1, left - 1); 927214501Srpaulo eap_sm_process_nak(sm, pos + 1, left - 1); 928214501Srpaulo if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS && 929214501Srpaulo sm->user->methods[sm->user_eap_method_index].method != 930214501Srpaulo EAP_TYPE_NONE) { 931214501Srpaulo next_type = sm->user->methods[ 932214501Srpaulo sm->user_eap_method_index++].method; 933214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", 934214501Srpaulo next_type); 935214501Srpaulo } else { 936214501Srpaulo eap_peap_req_failure(sm, data); 937214501Srpaulo next_type = EAP_TYPE_NONE; 938214501Srpaulo } 939214501Srpaulo eap_peap_phase2_init(sm, data, next_type); 940214501Srpaulo return; 941214501Srpaulo } 942214501Srpaulo 943214501Srpaulo if (data->phase2_method->check(sm, data->phase2_priv, in_data)) { 944214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 check() asked to " 945214501Srpaulo "ignore the packet"); 946214501Srpaulo return; 947214501Srpaulo } 948214501Srpaulo 949214501Srpaulo data->phase2_method->process(sm, data->phase2_priv, in_data); 950214501Srpaulo 951214501Srpaulo if (sm->method_pending == METHOD_PENDING_WAIT) { 952214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method is in " 953214501Srpaulo "pending wait state - save decrypted response"); 954214501Srpaulo wpabuf_free(data->pending_phase2_resp); 955214501Srpaulo data->pending_phase2_resp = wpabuf_dup(in_data); 956214501Srpaulo } 957214501Srpaulo 958214501Srpaulo if (!data->phase2_method->isDone(sm, data->phase2_priv)) 959214501Srpaulo return; 960214501Srpaulo 961214501Srpaulo if (!data->phase2_method->isSuccess(sm, data->phase2_priv)) { 962214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 method failed"); 963214501Srpaulo eap_peap_req_failure(sm, data); 964214501Srpaulo next_type = EAP_TYPE_NONE; 965214501Srpaulo eap_peap_phase2_init(sm, data, next_type); 966214501Srpaulo return; 967214501Srpaulo } 968214501Srpaulo 969214501Srpaulo os_free(data->phase2_key); 970214501Srpaulo if (data->phase2_method->getKey) { 971214501Srpaulo data->phase2_key = data->phase2_method->getKey( 972214501Srpaulo sm, data->phase2_priv, &data->phase2_key_len); 973214501Srpaulo if (data->phase2_key == NULL) { 974214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase2 getKey " 975214501Srpaulo "failed"); 976214501Srpaulo eap_peap_req_failure(sm, data); 977214501Srpaulo eap_peap_phase2_init(sm, data, EAP_TYPE_NONE); 978214501Srpaulo return; 979214501Srpaulo } 980214501Srpaulo } 981214501Srpaulo 982214501Srpaulo switch (data->state) { 983214501Srpaulo case PHASE1_ID2: 984214501Srpaulo case PHASE2_ID: 985214501Srpaulo case PHASE2_SOH: 986214501Srpaulo if (eap_user_get(sm, sm->identity, sm->identity_len, 1) != 0) { 987214501Srpaulo wpa_hexdump_ascii(MSG_DEBUG, "EAP_PEAP: Phase2 " 988214501Srpaulo "Identity not found in the user " 989214501Srpaulo "database", 990214501Srpaulo sm->identity, sm->identity_len); 991214501Srpaulo eap_peap_req_failure(sm, data); 992214501Srpaulo next_type = EAP_TYPE_NONE; 993214501Srpaulo break; 994214501Srpaulo } 995214501Srpaulo 996214501Srpaulo#ifdef EAP_SERVER_TNC 997214501Srpaulo if (data->state != PHASE2_SOH && sm->tnc && 998214501Srpaulo data->peap_version == 0) { 999214501Srpaulo eap_peap_state(data, PHASE2_SOH); 1000214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: Try to initialize " 1001214501Srpaulo "TNC (NAP SOH)"); 1002214501Srpaulo next_type = EAP_TYPE_NONE; 1003214501Srpaulo break; 1004214501Srpaulo } 1005214501Srpaulo#endif /* EAP_SERVER_TNC */ 1006214501Srpaulo 1007214501Srpaulo eap_peap_state(data, PHASE2_METHOD); 1008214501Srpaulo next_type = sm->user->methods[0].method; 1009214501Srpaulo sm->user_eap_method_index = 1; 1010214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type); 1011214501Srpaulo break; 1012214501Srpaulo case PHASE2_METHOD: 1013214501Srpaulo eap_peap_req_success(sm, data); 1014214501Srpaulo next_type = EAP_TYPE_NONE; 1015214501Srpaulo break; 1016214501Srpaulo case FAILURE: 1017214501Srpaulo break; 1018214501Srpaulo default: 1019214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: %s - unexpected state %d", 1020214501Srpaulo __func__, data->state); 1021214501Srpaulo break; 1022214501Srpaulo } 1023214501Srpaulo 1024214501Srpaulo eap_peap_phase2_init(sm, data, next_type); 1025214501Srpaulo} 1026214501Srpaulo 1027214501Srpaulo 1028214501Srpaulostatic void eap_peap_process_phase2(struct eap_sm *sm, 1029214501Srpaulo struct eap_peap_data *data, 1030214501Srpaulo const struct wpabuf *respData, 1031214501Srpaulo struct wpabuf *in_buf) 1032214501Srpaulo{ 1033214501Srpaulo struct wpabuf *in_decrypted; 1034214501Srpaulo const struct eap_hdr *hdr; 1035214501Srpaulo size_t len; 1036214501Srpaulo 1037214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for" 1038214501Srpaulo " Phase 2", (unsigned long) wpabuf_len(in_buf)); 1039214501Srpaulo 1040214501Srpaulo if (data->pending_phase2_resp) { 1041214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 response - " 1042214501Srpaulo "skip decryption and use old data"); 1043214501Srpaulo eap_peap_process_phase2_response(sm, data, 1044214501Srpaulo data->pending_phase2_resp); 1045214501Srpaulo wpabuf_free(data->pending_phase2_resp); 1046214501Srpaulo data->pending_phase2_resp = NULL; 1047214501Srpaulo return; 1048214501Srpaulo } 1049214501Srpaulo 1050214501Srpaulo in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn, 1051214501Srpaulo in_buf); 1052214501Srpaulo if (in_decrypted == NULL) { 1053214501Srpaulo wpa_printf(MSG_INFO, "EAP-PEAP: Failed to decrypt Phase 2 " 1054214501Srpaulo "data"); 1055214501Srpaulo eap_peap_state(data, FAILURE); 1056214501Srpaulo return; 1057214501Srpaulo } 1058214501Srpaulo 1059214501Srpaulo wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP", 1060214501Srpaulo in_decrypted); 1061214501Srpaulo 1062214501Srpaulo hdr = wpabuf_head(in_decrypted); 1063214501Srpaulo 1064214501Srpaulo if (data->peap_version == 0 && data->state != PHASE2_TLV) { 1065214501Srpaulo const struct eap_hdr *resp; 1066214501Srpaulo struct eap_hdr *nhdr; 1067214501Srpaulo struct wpabuf *nbuf = 1068214501Srpaulo wpabuf_alloc(sizeof(struct eap_hdr) + 1069214501Srpaulo wpabuf_len(in_decrypted)); 1070214501Srpaulo if (nbuf == NULL) { 1071214501Srpaulo wpabuf_free(in_decrypted); 1072214501Srpaulo return; 1073214501Srpaulo } 1074214501Srpaulo 1075214501Srpaulo resp = wpabuf_head(respData); 1076214501Srpaulo nhdr = wpabuf_put(nbuf, sizeof(*nhdr)); 1077214501Srpaulo nhdr->code = resp->code; 1078214501Srpaulo nhdr->identifier = resp->identifier; 1079214501Srpaulo nhdr->length = host_to_be16(sizeof(struct eap_hdr) + 1080214501Srpaulo wpabuf_len(in_decrypted)); 1081214501Srpaulo wpabuf_put_buf(nbuf, in_decrypted); 1082214501Srpaulo wpabuf_free(in_decrypted); 1083214501Srpaulo 1084214501Srpaulo in_decrypted = nbuf; 1085214501Srpaulo } else if (data->peap_version >= 2) { 1086214501Srpaulo struct eap_tlv_hdr *tlv; 1087214501Srpaulo struct wpabuf *nmsg; 1088214501Srpaulo 1089214501Srpaulo if (wpabuf_len(in_decrypted) < sizeof(*tlv) + sizeof(*hdr)) { 1090214501Srpaulo wpa_printf(MSG_INFO, "EAP-PEAPv2: Too short Phase 2 " 1091214501Srpaulo "EAP TLV"); 1092214501Srpaulo wpabuf_free(in_decrypted); 1093214501Srpaulo return; 1094214501Srpaulo } 1095214501Srpaulo tlv = wpabuf_mhead(in_decrypted); 1096214501Srpaulo if ((be_to_host16(tlv->tlv_type) & EAP_TLV_TYPE_MASK) != 1097214501Srpaulo EAP_TLV_EAP_PAYLOAD_TLV) { 1098214501Srpaulo wpa_printf(MSG_INFO, "EAP-PEAPv2: Not an EAP TLV"); 1099214501Srpaulo wpabuf_free(in_decrypted); 1100214501Srpaulo return; 1101214501Srpaulo } 1102214501Srpaulo if (sizeof(*tlv) + be_to_host16(tlv->length) > 1103214501Srpaulo wpabuf_len(in_decrypted)) { 1104214501Srpaulo wpa_printf(MSG_INFO, "EAP-PEAPv2: Invalid EAP TLV " 1105214501Srpaulo "length"); 1106214501Srpaulo wpabuf_free(in_decrypted); 1107214501Srpaulo return; 1108214501Srpaulo } 1109214501Srpaulo hdr = (struct eap_hdr *) (tlv + 1); 1110214501Srpaulo if (be_to_host16(hdr->length) > be_to_host16(tlv->length)) { 1111214501Srpaulo wpa_printf(MSG_INFO, "EAP-PEAPv2: No room for full " 1112214501Srpaulo "EAP packet in EAP TLV"); 1113214501Srpaulo wpabuf_free(in_decrypted); 1114214501Srpaulo return; 1115214501Srpaulo } 1116214501Srpaulo 1117214501Srpaulo nmsg = wpabuf_alloc(be_to_host16(hdr->length)); 1118214501Srpaulo if (nmsg == NULL) { 1119214501Srpaulo wpabuf_free(in_decrypted); 1120214501Srpaulo return; 1121214501Srpaulo } 1122214501Srpaulo 1123214501Srpaulo wpabuf_put_data(nmsg, hdr, be_to_host16(hdr->length)); 1124214501Srpaulo wpabuf_free(in_decrypted); 1125214501Srpaulo in_decrypted = nmsg; 1126214501Srpaulo } 1127214501Srpaulo 1128214501Srpaulo hdr = wpabuf_head(in_decrypted); 1129214501Srpaulo if (wpabuf_len(in_decrypted) < (int) sizeof(*hdr)) { 1130214501Srpaulo wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 " 1131214501Srpaulo "EAP frame (len=%lu)", 1132214501Srpaulo (unsigned long) wpabuf_len(in_decrypted)); 1133214501Srpaulo wpabuf_free(in_decrypted); 1134214501Srpaulo eap_peap_req_failure(sm, data); 1135214501Srpaulo return; 1136214501Srpaulo } 1137214501Srpaulo len = be_to_host16(hdr->length); 1138214501Srpaulo if (len > wpabuf_len(in_decrypted)) { 1139214501Srpaulo wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in " 1140214501Srpaulo "Phase 2 EAP frame (len=%lu hdr->length=%lu)", 1141214501Srpaulo (unsigned long) wpabuf_len(in_decrypted), 1142214501Srpaulo (unsigned long) len); 1143214501Srpaulo wpabuf_free(in_decrypted); 1144214501Srpaulo eap_peap_req_failure(sm, data); 1145214501Srpaulo return; 1146214501Srpaulo } 1147214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d " 1148214501Srpaulo "identifier=%d length=%lu", hdr->code, hdr->identifier, 1149214501Srpaulo (unsigned long) len); 1150214501Srpaulo switch (hdr->code) { 1151214501Srpaulo case EAP_CODE_RESPONSE: 1152214501Srpaulo eap_peap_process_phase2_response(sm, data, in_decrypted); 1153214501Srpaulo break; 1154214501Srpaulo case EAP_CODE_SUCCESS: 1155214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success"); 1156214501Srpaulo if (data->state == SUCCESS_REQ) { 1157214501Srpaulo eap_peap_state(data, SUCCESS); 1158214501Srpaulo } 1159214501Srpaulo break; 1160214501Srpaulo case EAP_CODE_FAILURE: 1161214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure"); 1162214501Srpaulo eap_peap_state(data, FAILURE); 1163214501Srpaulo break; 1164214501Srpaulo default: 1165214501Srpaulo wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in " 1166214501Srpaulo "Phase 2 EAP header", hdr->code); 1167214501Srpaulo break; 1168214501Srpaulo } 1169214501Srpaulo 1170214501Srpaulo wpabuf_free(in_decrypted); 1171214501Srpaulo} 1172214501Srpaulo 1173214501Srpaulo 1174214501Srpaulostatic int eap_peapv2_start_phase2(struct eap_sm *sm, 1175214501Srpaulo struct eap_peap_data *data) 1176214501Srpaulo{ 1177214501Srpaulo struct wpabuf *buf, *buf2; 1178214501Srpaulo 1179214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Phase1 done, include first Phase2 " 1180214501Srpaulo "payload in the same message"); 1181214501Srpaulo eap_peap_state(data, PHASE1_ID2); 1182214501Srpaulo if (eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY)) 1183214501Srpaulo return -1; 1184214501Srpaulo 1185214501Srpaulo /* TODO: which Id to use here? */ 1186214501Srpaulo buf = data->phase2_method->buildReq(sm, data->phase2_priv, 6); 1187214501Srpaulo if (buf == NULL) 1188214501Srpaulo return -1; 1189214501Srpaulo 1190214501Srpaulo buf2 = eap_peapv2_tlv_eap_payload(buf); 1191214501Srpaulo if (buf2 == NULL) 1192214501Srpaulo return -1; 1193214501Srpaulo 1194214501Srpaulo wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Identity Request", buf2); 1195214501Srpaulo 1196214501Srpaulo buf = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn, 1197214501Srpaulo buf2); 1198214501Srpaulo wpabuf_free(buf2); 1199214501Srpaulo 1200214501Srpaulo if (buf == NULL) { 1201214501Srpaulo wpa_printf(MSG_INFO, "EAP-PEAPv2: Failed to encrypt Phase 2 " 1202214501Srpaulo "data"); 1203214501Srpaulo return -1; 1204214501Srpaulo } 1205214501Srpaulo 1206214501Srpaulo wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAPv2: Encrypted Identity Request", 1207214501Srpaulo buf); 1208214501Srpaulo 1209214501Srpaulo /* Append TLS data into the pending buffer after the Server Finished */ 1210214501Srpaulo if (wpabuf_resize(&data->ssl.tls_out, wpabuf_len(buf)) < 0) { 1211214501Srpaulo wpabuf_free(buf); 1212214501Srpaulo return -1; 1213214501Srpaulo } 1214214501Srpaulo wpabuf_put_buf(data->ssl.tls_out, buf); 1215214501Srpaulo wpabuf_free(buf); 1216214501Srpaulo 1217214501Srpaulo return 0; 1218214501Srpaulo} 1219214501Srpaulo 1220214501Srpaulo 1221214501Srpaulostatic int eap_peap_process_version(struct eap_sm *sm, void *priv, 1222214501Srpaulo int peer_version) 1223214501Srpaulo{ 1224214501Srpaulo struct eap_peap_data *data = priv; 1225214501Srpaulo 1226214501Srpaulo data->recv_version = peer_version; 1227214501Srpaulo if (data->force_version >= 0 && peer_version != data->force_version) { 1228214501Srpaulo wpa_printf(MSG_INFO, "EAP-PEAP: peer did not select the forced" 1229214501Srpaulo " version (forced=%d peer=%d) - reject", 1230214501Srpaulo data->force_version, peer_version); 1231214501Srpaulo return -1; 1232214501Srpaulo } 1233214501Srpaulo if (peer_version < data->peap_version) { 1234214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: peer ver=%d, own ver=%d; " 1235214501Srpaulo "use version %d", 1236214501Srpaulo peer_version, data->peap_version, peer_version); 1237214501Srpaulo data->peap_version = peer_version; 1238214501Srpaulo } 1239214501Srpaulo 1240214501Srpaulo return 0; 1241214501Srpaulo} 1242214501Srpaulo 1243214501Srpaulo 1244214501Srpaulostatic void eap_peap_process_msg(struct eap_sm *sm, void *priv, 1245214501Srpaulo const struct wpabuf *respData) 1246214501Srpaulo{ 1247214501Srpaulo struct eap_peap_data *data = priv; 1248214501Srpaulo 1249214501Srpaulo switch (data->state) { 1250214501Srpaulo case PHASE1: 1251214501Srpaulo if (eap_server_tls_phase1(sm, &data->ssl) < 0) { 1252214501Srpaulo eap_peap_state(data, FAILURE); 1253214501Srpaulo break; 1254214501Srpaulo } 1255214501Srpaulo 1256214501Srpaulo if (data->peap_version >= 2 && 1257214501Srpaulo tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { 1258214501Srpaulo if (eap_peapv2_start_phase2(sm, data)) { 1259214501Srpaulo eap_peap_state(data, FAILURE); 1260214501Srpaulo break; 1261214501Srpaulo } 1262214501Srpaulo } 1263214501Srpaulo break; 1264214501Srpaulo case PHASE2_START: 1265214501Srpaulo eap_peap_state(data, PHASE2_ID); 1266214501Srpaulo eap_peap_phase2_init(sm, data, EAP_TYPE_IDENTITY); 1267214501Srpaulo break; 1268214501Srpaulo case PHASE1_ID2: 1269214501Srpaulo case PHASE2_ID: 1270214501Srpaulo case PHASE2_METHOD: 1271214501Srpaulo case PHASE2_SOH: 1272214501Srpaulo case PHASE2_TLV: 1273214501Srpaulo eap_peap_process_phase2(sm, data, respData, data->ssl.tls_in); 1274214501Srpaulo break; 1275214501Srpaulo case SUCCESS_REQ: 1276214501Srpaulo eap_peap_state(data, SUCCESS); 1277214501Srpaulo break; 1278214501Srpaulo case FAILURE_REQ: 1279214501Srpaulo eap_peap_state(data, FAILURE); 1280214501Srpaulo break; 1281214501Srpaulo default: 1282214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected state %d in %s", 1283214501Srpaulo data->state, __func__); 1284214501Srpaulo break; 1285214501Srpaulo } 1286214501Srpaulo} 1287214501Srpaulo 1288214501Srpaulo 1289214501Srpaulostatic void eap_peap_process(struct eap_sm *sm, void *priv, 1290214501Srpaulo struct wpabuf *respData) 1291214501Srpaulo{ 1292214501Srpaulo struct eap_peap_data *data = priv; 1293214501Srpaulo if (eap_server_tls_process(sm, &data->ssl, respData, data, 1294214501Srpaulo EAP_TYPE_PEAP, eap_peap_process_version, 1295214501Srpaulo eap_peap_process_msg) < 0) 1296214501Srpaulo eap_peap_state(data, FAILURE); 1297214501Srpaulo} 1298214501Srpaulo 1299214501Srpaulo 1300214501Srpaulostatic Boolean eap_peap_isDone(struct eap_sm *sm, void *priv) 1301214501Srpaulo{ 1302214501Srpaulo struct eap_peap_data *data = priv; 1303214501Srpaulo return data->state == SUCCESS || data->state == FAILURE; 1304214501Srpaulo} 1305214501Srpaulo 1306214501Srpaulo 1307214501Srpaulostatic u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len) 1308214501Srpaulo{ 1309214501Srpaulo struct eap_peap_data *data = priv; 1310214501Srpaulo u8 *eapKeyData; 1311214501Srpaulo 1312214501Srpaulo if (data->state != SUCCESS) 1313214501Srpaulo return NULL; 1314214501Srpaulo 1315214501Srpaulo if (data->crypto_binding_used) { 1316214501Srpaulo u8 csk[128]; 1317214501Srpaulo /* 1318214501Srpaulo * Note: It looks like Microsoft implementation requires null 1319214501Srpaulo * termination for this label while the one used for deriving 1320214501Srpaulo * IPMK|CMK did not use null termination. 1321214501Srpaulo */ 1322214501Srpaulo peap_prfplus(data->peap_version, data->ipmk, 40, 1323214501Srpaulo "Session Key Generating Function", 1324214501Srpaulo (u8 *) "\00", 1, csk, sizeof(csk)); 1325214501Srpaulo wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk)); 1326214501Srpaulo eapKeyData = os_malloc(EAP_TLS_KEY_LEN); 1327214501Srpaulo if (eapKeyData) { 1328214501Srpaulo os_memcpy(eapKeyData, csk, EAP_TLS_KEY_LEN); 1329214501Srpaulo *len = EAP_TLS_KEY_LEN; 1330214501Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key", 1331214501Srpaulo eapKeyData, EAP_TLS_KEY_LEN); 1332214501Srpaulo } else { 1333214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive " 1334214501Srpaulo "key"); 1335214501Srpaulo } 1336214501Srpaulo 1337214501Srpaulo return eapKeyData; 1338214501Srpaulo } 1339214501Srpaulo 1340214501Srpaulo /* TODO: PEAPv1 - different label in some cases */ 1341214501Srpaulo eapKeyData = eap_server_tls_derive_key(sm, &data->ssl, 1342214501Srpaulo "client EAP encryption", 1343214501Srpaulo EAP_TLS_KEY_LEN); 1344214501Srpaulo if (eapKeyData) { 1345214501Srpaulo *len = EAP_TLS_KEY_LEN; 1346214501Srpaulo wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key", 1347214501Srpaulo eapKeyData, EAP_TLS_KEY_LEN); 1348214501Srpaulo } else { 1349214501Srpaulo wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to derive key"); 1350214501Srpaulo } 1351214501Srpaulo 1352214501Srpaulo return eapKeyData; 1353214501Srpaulo} 1354214501Srpaulo 1355214501Srpaulo 1356214501Srpaulostatic Boolean eap_peap_isSuccess(struct eap_sm *sm, void *priv) 1357214501Srpaulo{ 1358214501Srpaulo struct eap_peap_data *data = priv; 1359214501Srpaulo return data->state == SUCCESS; 1360214501Srpaulo} 1361214501Srpaulo 1362214501Srpaulo 1363214501Srpauloint eap_server_peap_register(void) 1364214501Srpaulo{ 1365214501Srpaulo struct eap_method *eap; 1366214501Srpaulo int ret; 1367214501Srpaulo 1368214501Srpaulo eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION, 1369214501Srpaulo EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP"); 1370214501Srpaulo if (eap == NULL) 1371214501Srpaulo return -1; 1372214501Srpaulo 1373214501Srpaulo eap->init = eap_peap_init; 1374214501Srpaulo eap->reset = eap_peap_reset; 1375214501Srpaulo eap->buildReq = eap_peap_buildReq; 1376214501Srpaulo eap->check = eap_peap_check; 1377214501Srpaulo eap->process = eap_peap_process; 1378214501Srpaulo eap->isDone = eap_peap_isDone; 1379214501Srpaulo eap->getKey = eap_peap_getKey; 1380214501Srpaulo eap->isSuccess = eap_peap_isSuccess; 1381214501Srpaulo 1382214501Srpaulo ret = eap_server_method_register(eap); 1383214501Srpaulo if (ret) 1384214501Srpaulo eap_server_method_free(eap); 1385214501Srpaulo return ret; 1386214501Srpaulo} 1387