1*6d49e1aeSJan Lentfer /* 2*6d49e1aeSJan Lentfer * EAP peer method: EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt) 3*6d49e1aeSJan Lentfer * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi> 4*6d49e1aeSJan Lentfer * 5*6d49e1aeSJan Lentfer * This program is free software; you can redistribute it and/or modify 6*6d49e1aeSJan Lentfer * it under the terms of the GNU General Public License version 2 as 7*6d49e1aeSJan Lentfer * published by the Free Software Foundation. 8*6d49e1aeSJan Lentfer * 9*6d49e1aeSJan Lentfer * Alternatively, this software may be distributed under the terms of BSD 10*6d49e1aeSJan Lentfer * license. 11*6d49e1aeSJan Lentfer * 12*6d49e1aeSJan Lentfer * See README and COPYING for more details. 13*6d49e1aeSJan Lentfer */ 14*6d49e1aeSJan Lentfer 15*6d49e1aeSJan Lentfer #include "includes.h" 16*6d49e1aeSJan Lentfer 17*6d49e1aeSJan Lentfer #include "common.h" 18*6d49e1aeSJan Lentfer #include "crypto/sha1.h" 19*6d49e1aeSJan Lentfer #include "eap_i.h" 20*6d49e1aeSJan Lentfer #include "eap_tls_common.h" 21*6d49e1aeSJan Lentfer #include "eap_config.h" 22*6d49e1aeSJan Lentfer #include "tls.h" 23*6d49e1aeSJan Lentfer #include "eap_common/eap_tlv_common.h" 24*6d49e1aeSJan Lentfer #include "eap_common/eap_peap_common.h" 25*6d49e1aeSJan Lentfer #include "tncc.h" 26*6d49e1aeSJan Lentfer 27*6d49e1aeSJan Lentfer 28*6d49e1aeSJan Lentfer /* Maximum supported PEAP version 29*6d49e1aeSJan Lentfer * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt 30*6d49e1aeSJan Lentfer * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt 31*6d49e1aeSJan Lentfer * 2 = draft-josefsson-ppext-eap-tls-eap-10.txt 32*6d49e1aeSJan Lentfer */ 33*6d49e1aeSJan Lentfer #define EAP_PEAP_VERSION 1 34*6d49e1aeSJan Lentfer 35*6d49e1aeSJan Lentfer 36*6d49e1aeSJan Lentfer static void eap_peap_deinit(struct eap_sm *sm, void *priv); 37*6d49e1aeSJan Lentfer 38*6d49e1aeSJan Lentfer 39*6d49e1aeSJan Lentfer struct eap_peap_data { 40*6d49e1aeSJan Lentfer struct eap_ssl_data ssl; 41*6d49e1aeSJan Lentfer 42*6d49e1aeSJan Lentfer int peap_version, force_peap_version, force_new_label; 43*6d49e1aeSJan Lentfer 44*6d49e1aeSJan Lentfer const struct eap_method *phase2_method; 45*6d49e1aeSJan Lentfer void *phase2_priv; 46*6d49e1aeSJan Lentfer int phase2_success; 47*6d49e1aeSJan Lentfer int phase2_eap_success; 48*6d49e1aeSJan Lentfer int phase2_eap_started; 49*6d49e1aeSJan Lentfer 50*6d49e1aeSJan Lentfer struct eap_method_type phase2_type; 51*6d49e1aeSJan Lentfer struct eap_method_type *phase2_types; 52*6d49e1aeSJan Lentfer size_t num_phase2_types; 53*6d49e1aeSJan Lentfer 54*6d49e1aeSJan Lentfer int peap_outer_success; /* 0 = PEAP terminated on Phase 2 inner 55*6d49e1aeSJan Lentfer * EAP-Success 56*6d49e1aeSJan Lentfer * 1 = reply with tunneled EAP-Success to inner 57*6d49e1aeSJan Lentfer * EAP-Success and expect AS to send outer 58*6d49e1aeSJan Lentfer * (unencrypted) EAP-Success after this 59*6d49e1aeSJan Lentfer * 2 = reply with PEAP/TLS ACK to inner 60*6d49e1aeSJan Lentfer * EAP-Success and expect AS to send outer 61*6d49e1aeSJan Lentfer * (unencrypted) EAP-Success after this */ 62*6d49e1aeSJan Lentfer int resuming; /* starting a resumed session */ 63*6d49e1aeSJan Lentfer int reauth; /* reauthentication */ 64*6d49e1aeSJan Lentfer u8 *key_data; 65*6d49e1aeSJan Lentfer 66*6d49e1aeSJan Lentfer struct wpabuf *pending_phase2_req; 67*6d49e1aeSJan Lentfer enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding; 68*6d49e1aeSJan Lentfer int crypto_binding_used; 69*6d49e1aeSJan Lentfer u8 binding_nonce[32]; 70*6d49e1aeSJan Lentfer u8 ipmk[40]; 71*6d49e1aeSJan Lentfer u8 cmk[20]; 72*6d49e1aeSJan Lentfer int soh; /* Whether IF-TNCCS-SOH (Statement of Health; Microsoft NAP) 73*6d49e1aeSJan Lentfer * is enabled. */ 74*6d49e1aeSJan Lentfer }; 75*6d49e1aeSJan Lentfer 76*6d49e1aeSJan Lentfer 77*6d49e1aeSJan Lentfer static int eap_peap_parse_phase1(struct eap_peap_data *data, 78*6d49e1aeSJan Lentfer const char *phase1) 79*6d49e1aeSJan Lentfer { 80*6d49e1aeSJan Lentfer const char *pos; 81*6d49e1aeSJan Lentfer 82*6d49e1aeSJan Lentfer pos = os_strstr(phase1, "peapver="); 83*6d49e1aeSJan Lentfer if (pos) { 84*6d49e1aeSJan Lentfer data->force_peap_version = atoi(pos + 8); 85*6d49e1aeSJan Lentfer data->peap_version = data->force_peap_version; 86*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Forced PEAP version %d", 87*6d49e1aeSJan Lentfer data->force_peap_version); 88*6d49e1aeSJan Lentfer } 89*6d49e1aeSJan Lentfer 90*6d49e1aeSJan Lentfer if (os_strstr(phase1, "peaplabel=1")) { 91*6d49e1aeSJan Lentfer data->force_new_label = 1; 92*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Force new label for key " 93*6d49e1aeSJan Lentfer "derivation"); 94*6d49e1aeSJan Lentfer } 95*6d49e1aeSJan Lentfer 96*6d49e1aeSJan Lentfer if (os_strstr(phase1, "peap_outer_success=0")) { 97*6d49e1aeSJan Lentfer data->peap_outer_success = 0; 98*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: terminate authentication on " 99*6d49e1aeSJan Lentfer "tunneled EAP-Success"); 100*6d49e1aeSJan Lentfer } else if (os_strstr(phase1, "peap_outer_success=1")) { 101*6d49e1aeSJan Lentfer data->peap_outer_success = 1; 102*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: send tunneled EAP-Success " 103*6d49e1aeSJan Lentfer "after receiving tunneled EAP-Success"); 104*6d49e1aeSJan Lentfer } else if (os_strstr(phase1, "peap_outer_success=2")) { 105*6d49e1aeSJan Lentfer data->peap_outer_success = 2; 106*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: send PEAP/TLS ACK after " 107*6d49e1aeSJan Lentfer "receiving tunneled EAP-Success"); 108*6d49e1aeSJan Lentfer } 109*6d49e1aeSJan Lentfer 110*6d49e1aeSJan Lentfer if (os_strstr(phase1, "crypto_binding=0")) { 111*6d49e1aeSJan Lentfer data->crypto_binding = NO_BINDING; 112*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Do not use cryptobinding"); 113*6d49e1aeSJan Lentfer } else if (os_strstr(phase1, "crypto_binding=1")) { 114*6d49e1aeSJan Lentfer data->crypto_binding = OPTIONAL_BINDING; 115*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Optional cryptobinding"); 116*6d49e1aeSJan Lentfer } else if (os_strstr(phase1, "crypto_binding=2")) { 117*6d49e1aeSJan Lentfer data->crypto_binding = REQUIRE_BINDING; 118*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Require cryptobinding"); 119*6d49e1aeSJan Lentfer } 120*6d49e1aeSJan Lentfer 121*6d49e1aeSJan Lentfer #ifdef EAP_TNC 122*6d49e1aeSJan Lentfer if (os_strstr(phase1, "tnc=soh2")) { 123*6d49e1aeSJan Lentfer data->soh = 2; 124*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled"); 125*6d49e1aeSJan Lentfer } else if (os_strstr(phase1, "tnc=soh1")) { 126*6d49e1aeSJan Lentfer data->soh = 1; 127*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 1 enabled"); 128*6d49e1aeSJan Lentfer } else if (os_strstr(phase1, "tnc=soh")) { 129*6d49e1aeSJan Lentfer data->soh = 2; 130*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled"); 131*6d49e1aeSJan Lentfer } 132*6d49e1aeSJan Lentfer #endif /* EAP_TNC */ 133*6d49e1aeSJan Lentfer 134*6d49e1aeSJan Lentfer return 0; 135*6d49e1aeSJan Lentfer } 136*6d49e1aeSJan Lentfer 137*6d49e1aeSJan Lentfer 138*6d49e1aeSJan Lentfer static void * eap_peap_init(struct eap_sm *sm) 139*6d49e1aeSJan Lentfer { 140*6d49e1aeSJan Lentfer struct eap_peap_data *data; 141*6d49e1aeSJan Lentfer struct eap_peer_config *config = eap_get_config(sm); 142*6d49e1aeSJan Lentfer 143*6d49e1aeSJan Lentfer data = os_zalloc(sizeof(*data)); 144*6d49e1aeSJan Lentfer if (data == NULL) 145*6d49e1aeSJan Lentfer return NULL; 146*6d49e1aeSJan Lentfer sm->peap_done = FALSE; 147*6d49e1aeSJan Lentfer data->peap_version = EAP_PEAP_VERSION; 148*6d49e1aeSJan Lentfer data->force_peap_version = -1; 149*6d49e1aeSJan Lentfer data->peap_outer_success = 2; 150*6d49e1aeSJan Lentfer data->crypto_binding = OPTIONAL_BINDING; 151*6d49e1aeSJan Lentfer 152*6d49e1aeSJan Lentfer if (config && config->phase1 && 153*6d49e1aeSJan Lentfer eap_peap_parse_phase1(data, config->phase1) < 0) { 154*6d49e1aeSJan Lentfer eap_peap_deinit(sm, data); 155*6d49e1aeSJan Lentfer return NULL; 156*6d49e1aeSJan Lentfer } 157*6d49e1aeSJan Lentfer 158*6d49e1aeSJan Lentfer if (eap_peer_select_phase2_methods(config, "auth=", 159*6d49e1aeSJan Lentfer &data->phase2_types, 160*6d49e1aeSJan Lentfer &data->num_phase2_types) < 0) { 161*6d49e1aeSJan Lentfer eap_peap_deinit(sm, data); 162*6d49e1aeSJan Lentfer return NULL; 163*6d49e1aeSJan Lentfer } 164*6d49e1aeSJan Lentfer 165*6d49e1aeSJan Lentfer data->phase2_type.vendor = EAP_VENDOR_IETF; 166*6d49e1aeSJan Lentfer data->phase2_type.method = EAP_TYPE_NONE; 167*6d49e1aeSJan Lentfer 168*6d49e1aeSJan Lentfer if (eap_peer_tls_ssl_init(sm, &data->ssl, config)) { 169*6d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL."); 170*6d49e1aeSJan Lentfer eap_peap_deinit(sm, data); 171*6d49e1aeSJan Lentfer return NULL; 172*6d49e1aeSJan Lentfer } 173*6d49e1aeSJan Lentfer 174*6d49e1aeSJan Lentfer return data; 175*6d49e1aeSJan Lentfer } 176*6d49e1aeSJan Lentfer 177*6d49e1aeSJan Lentfer 178*6d49e1aeSJan Lentfer static void eap_peap_deinit(struct eap_sm *sm, void *priv) 179*6d49e1aeSJan Lentfer { 180*6d49e1aeSJan Lentfer struct eap_peap_data *data = priv; 181*6d49e1aeSJan Lentfer if (data == NULL) 182*6d49e1aeSJan Lentfer return; 183*6d49e1aeSJan Lentfer if (data->phase2_priv && data->phase2_method) 184*6d49e1aeSJan Lentfer data->phase2_method->deinit(sm, data->phase2_priv); 185*6d49e1aeSJan Lentfer os_free(data->phase2_types); 186*6d49e1aeSJan Lentfer eap_peer_tls_ssl_deinit(sm, &data->ssl); 187*6d49e1aeSJan Lentfer os_free(data->key_data); 188*6d49e1aeSJan Lentfer wpabuf_free(data->pending_phase2_req); 189*6d49e1aeSJan Lentfer os_free(data); 190*6d49e1aeSJan Lentfer } 191*6d49e1aeSJan Lentfer 192*6d49e1aeSJan Lentfer 193*6d49e1aeSJan Lentfer /** 194*6d49e1aeSJan Lentfer * eap_tlv_build_nak - Build EAP-TLV NAK message 195*6d49e1aeSJan Lentfer * @id: EAP identifier for the header 196*6d49e1aeSJan Lentfer * @nak_type: TLV type (EAP_TLV_*) 197*6d49e1aeSJan Lentfer * Returns: Buffer to the allocated EAP-TLV NAK message or %NULL on failure 198*6d49e1aeSJan Lentfer * 199*6d49e1aeSJan Lentfer * This funtion builds an EAP-TLV NAK message. The caller is responsible for 200*6d49e1aeSJan Lentfer * freeing the returned buffer. 201*6d49e1aeSJan Lentfer */ 202*6d49e1aeSJan Lentfer static struct wpabuf * eap_tlv_build_nak(int id, u16 nak_type) 203*6d49e1aeSJan Lentfer { 204*6d49e1aeSJan Lentfer struct wpabuf *msg; 205*6d49e1aeSJan Lentfer 206*6d49e1aeSJan Lentfer msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, 10, 207*6d49e1aeSJan Lentfer EAP_CODE_RESPONSE, id); 208*6d49e1aeSJan Lentfer if (msg == NULL) 209*6d49e1aeSJan Lentfer return NULL; 210*6d49e1aeSJan Lentfer 211*6d49e1aeSJan Lentfer wpabuf_put_u8(msg, 0x80); /* Mandatory */ 212*6d49e1aeSJan Lentfer wpabuf_put_u8(msg, EAP_TLV_NAK_TLV); 213*6d49e1aeSJan Lentfer wpabuf_put_be16(msg, 6); /* Length */ 214*6d49e1aeSJan Lentfer wpabuf_put_be32(msg, 0); /* Vendor-Id */ 215*6d49e1aeSJan Lentfer wpabuf_put_be16(msg, nak_type); /* NAK-Type */ 216*6d49e1aeSJan Lentfer 217*6d49e1aeSJan Lentfer return msg; 218*6d49e1aeSJan Lentfer } 219*6d49e1aeSJan Lentfer 220*6d49e1aeSJan Lentfer 221*6d49e1aeSJan Lentfer static int eap_peap_get_isk(struct eap_sm *sm, struct eap_peap_data *data, 222*6d49e1aeSJan Lentfer u8 *isk, size_t isk_len) 223*6d49e1aeSJan Lentfer { 224*6d49e1aeSJan Lentfer u8 *key; 225*6d49e1aeSJan Lentfer size_t key_len; 226*6d49e1aeSJan Lentfer 227*6d49e1aeSJan Lentfer os_memset(isk, 0, isk_len); 228*6d49e1aeSJan Lentfer if (data->phase2_method == NULL || data->phase2_priv == NULL || 229*6d49e1aeSJan Lentfer data->phase2_method->isKeyAvailable == NULL || 230*6d49e1aeSJan Lentfer data->phase2_method->getKey == NULL) 231*6d49e1aeSJan Lentfer return 0; 232*6d49e1aeSJan Lentfer 233*6d49e1aeSJan Lentfer if (!data->phase2_method->isKeyAvailable(sm, data->phase2_priv) || 234*6d49e1aeSJan Lentfer (key = data->phase2_method->getKey(sm, data->phase2_priv, 235*6d49e1aeSJan Lentfer &key_len)) == NULL) { 236*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not get key material " 237*6d49e1aeSJan Lentfer "from Phase 2"); 238*6d49e1aeSJan Lentfer return -1; 239*6d49e1aeSJan Lentfer } 240*6d49e1aeSJan Lentfer 241*6d49e1aeSJan Lentfer if (key_len > isk_len) 242*6d49e1aeSJan Lentfer key_len = isk_len; 243*6d49e1aeSJan Lentfer os_memcpy(isk, key, key_len); 244*6d49e1aeSJan Lentfer os_free(key); 245*6d49e1aeSJan Lentfer 246*6d49e1aeSJan Lentfer return 0; 247*6d49e1aeSJan Lentfer } 248*6d49e1aeSJan Lentfer 249*6d49e1aeSJan Lentfer 250*6d49e1aeSJan Lentfer static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data) 251*6d49e1aeSJan Lentfer { 252*6d49e1aeSJan Lentfer u8 *tk; 253*6d49e1aeSJan Lentfer u8 isk[32], imck[60]; 254*6d49e1aeSJan Lentfer 255*6d49e1aeSJan Lentfer /* 256*6d49e1aeSJan Lentfer * Tunnel key (TK) is the first 60 octets of the key generated by 257*6d49e1aeSJan Lentfer * phase 1 of PEAP (based on TLS). 258*6d49e1aeSJan Lentfer */ 259*6d49e1aeSJan Lentfer tk = data->key_data; 260*6d49e1aeSJan Lentfer if (tk == NULL) 261*6d49e1aeSJan Lentfer return -1; 262*6d49e1aeSJan Lentfer wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60); 263*6d49e1aeSJan Lentfer 264*6d49e1aeSJan Lentfer if (data->reauth && 265*6d49e1aeSJan Lentfer tls_connection_resumed(sm->ssl_ctx, data->ssl.conn)) { 266*6d49e1aeSJan Lentfer /* Fast-connect: IPMK|CMK = TK */ 267*6d49e1aeSJan Lentfer os_memcpy(data->ipmk, tk, 40); 268*6d49e1aeSJan Lentfer wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK from TK", 269*6d49e1aeSJan Lentfer data->ipmk, 40); 270*6d49e1aeSJan Lentfer os_memcpy(data->cmk, tk + 40, 20); 271*6d49e1aeSJan Lentfer wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK from TK", 272*6d49e1aeSJan Lentfer data->cmk, 20); 273*6d49e1aeSJan Lentfer return 0; 274*6d49e1aeSJan Lentfer } 275*6d49e1aeSJan Lentfer 276*6d49e1aeSJan Lentfer if (eap_peap_get_isk(sm, data, isk, sizeof(isk)) < 0) 277*6d49e1aeSJan Lentfer return -1; 278*6d49e1aeSJan Lentfer wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk)); 279*6d49e1aeSJan Lentfer 280*6d49e1aeSJan Lentfer /* 281*6d49e1aeSJan Lentfer * IPMK Seed = "Inner Methods Compound Keys" | ISK 282*6d49e1aeSJan Lentfer * TempKey = First 40 octets of TK 283*6d49e1aeSJan Lentfer * IPMK|CMK = PRF+(TempKey, IPMK Seed, 60) 284*6d49e1aeSJan Lentfer * (note: draft-josefsson-pppext-eap-tls-eap-10.txt includes a space 285*6d49e1aeSJan Lentfer * in the end of the label just before ISK; is that just a typo?) 286*6d49e1aeSJan Lentfer */ 287*6d49e1aeSJan Lentfer wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40); 288*6d49e1aeSJan Lentfer peap_prfplus(data->peap_version, tk, 40, "Inner Methods Compound Keys", 289*6d49e1aeSJan Lentfer isk, sizeof(isk), imck, sizeof(imck)); 290*6d49e1aeSJan Lentfer wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)", 291*6d49e1aeSJan Lentfer imck, sizeof(imck)); 292*6d49e1aeSJan Lentfer 293*6d49e1aeSJan Lentfer os_memcpy(data->ipmk, imck, 40); 294*6d49e1aeSJan Lentfer wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40); 295*6d49e1aeSJan Lentfer os_memcpy(data->cmk, imck + 40, 20); 296*6d49e1aeSJan Lentfer wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20); 297*6d49e1aeSJan Lentfer 298*6d49e1aeSJan Lentfer return 0; 299*6d49e1aeSJan Lentfer } 300*6d49e1aeSJan Lentfer 301*6d49e1aeSJan Lentfer 302*6d49e1aeSJan Lentfer static int eap_tlv_add_cryptobinding(struct eap_sm *sm, 303*6d49e1aeSJan Lentfer struct eap_peap_data *data, 304*6d49e1aeSJan Lentfer struct wpabuf *buf) 305*6d49e1aeSJan Lentfer { 306*6d49e1aeSJan Lentfer u8 *mac; 307*6d49e1aeSJan Lentfer u8 eap_type = EAP_TYPE_PEAP; 308*6d49e1aeSJan Lentfer const u8 *addr[2]; 309*6d49e1aeSJan Lentfer size_t len[2]; 310*6d49e1aeSJan Lentfer u16 tlv_type; 311*6d49e1aeSJan Lentfer 312*6d49e1aeSJan Lentfer /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */ 313*6d49e1aeSJan Lentfer addr[0] = wpabuf_put(buf, 0); 314*6d49e1aeSJan Lentfer len[0] = 60; 315*6d49e1aeSJan Lentfer addr[1] = &eap_type; 316*6d49e1aeSJan Lentfer len[1] = 1; 317*6d49e1aeSJan Lentfer 318*6d49e1aeSJan Lentfer tlv_type = EAP_TLV_CRYPTO_BINDING_TLV; 319*6d49e1aeSJan Lentfer if (data->peap_version >= 2) 320*6d49e1aeSJan Lentfer tlv_type |= EAP_TLV_TYPE_MANDATORY; 321*6d49e1aeSJan Lentfer wpabuf_put_be16(buf, tlv_type); 322*6d49e1aeSJan Lentfer wpabuf_put_be16(buf, 56); 323*6d49e1aeSJan Lentfer 324*6d49e1aeSJan Lentfer wpabuf_put_u8(buf, 0); /* Reserved */ 325*6d49e1aeSJan Lentfer wpabuf_put_u8(buf, data->peap_version); /* Version */ 326*6d49e1aeSJan Lentfer wpabuf_put_u8(buf, data->peap_version); /* RecvVersion */ 327*6d49e1aeSJan Lentfer wpabuf_put_u8(buf, 1); /* SubType: 0 = Request, 1 = Response */ 328*6d49e1aeSJan Lentfer wpabuf_put_data(buf, data->binding_nonce, 32); /* Nonce */ 329*6d49e1aeSJan Lentfer mac = wpabuf_put(buf, 20); /* Compound_MAC */ 330*6d49e1aeSJan Lentfer wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK", data->cmk, 20); 331*6d49e1aeSJan Lentfer wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1", 332*6d49e1aeSJan Lentfer addr[0], len[0]); 333*6d49e1aeSJan Lentfer wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2", 334*6d49e1aeSJan Lentfer addr[1], len[1]); 335*6d49e1aeSJan Lentfer hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac); 336*6d49e1aeSJan Lentfer wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC", mac, SHA1_MAC_LEN); 337*6d49e1aeSJan Lentfer data->crypto_binding_used = 1; 338*6d49e1aeSJan Lentfer 339*6d49e1aeSJan Lentfer return 0; 340*6d49e1aeSJan Lentfer } 341*6d49e1aeSJan Lentfer 342*6d49e1aeSJan Lentfer 343*6d49e1aeSJan Lentfer /** 344*6d49e1aeSJan Lentfer * eap_tlv_build_result - Build EAP-TLV Result message 345*6d49e1aeSJan Lentfer * @id: EAP identifier for the header 346*6d49e1aeSJan Lentfer * @status: Status (EAP_TLV_RESULT_SUCCESS or EAP_TLV_RESULT_FAILURE) 347*6d49e1aeSJan Lentfer * Returns: Buffer to the allocated EAP-TLV Result message or %NULL on failure 348*6d49e1aeSJan Lentfer * 349*6d49e1aeSJan Lentfer * This funtion builds an EAP-TLV Result message. The caller is responsible for 350*6d49e1aeSJan Lentfer * freeing the returned buffer. 351*6d49e1aeSJan Lentfer */ 352*6d49e1aeSJan Lentfer static struct wpabuf * eap_tlv_build_result(struct eap_sm *sm, 353*6d49e1aeSJan Lentfer struct eap_peap_data *data, 354*6d49e1aeSJan Lentfer int crypto_tlv_used, 355*6d49e1aeSJan Lentfer int id, u16 status) 356*6d49e1aeSJan Lentfer { 357*6d49e1aeSJan Lentfer struct wpabuf *msg; 358*6d49e1aeSJan Lentfer size_t len; 359*6d49e1aeSJan Lentfer 360*6d49e1aeSJan Lentfer if (data->crypto_binding == NO_BINDING) 361*6d49e1aeSJan Lentfer crypto_tlv_used = 0; 362*6d49e1aeSJan Lentfer 363*6d49e1aeSJan Lentfer len = 6; 364*6d49e1aeSJan Lentfer if (crypto_tlv_used) 365*6d49e1aeSJan Lentfer len += 60; /* Cryptobinding TLV */ 366*6d49e1aeSJan Lentfer msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, len, 367*6d49e1aeSJan Lentfer EAP_CODE_RESPONSE, id); 368*6d49e1aeSJan Lentfer if (msg == NULL) 369*6d49e1aeSJan Lentfer return NULL; 370*6d49e1aeSJan Lentfer 371*6d49e1aeSJan Lentfer wpabuf_put_u8(msg, 0x80); /* Mandatory */ 372*6d49e1aeSJan Lentfer wpabuf_put_u8(msg, EAP_TLV_RESULT_TLV); 373*6d49e1aeSJan Lentfer wpabuf_put_be16(msg, 2); /* Length */ 374*6d49e1aeSJan Lentfer wpabuf_put_be16(msg, status); /* Status */ 375*6d49e1aeSJan Lentfer 376*6d49e1aeSJan Lentfer if (crypto_tlv_used && eap_tlv_add_cryptobinding(sm, data, msg)) { 377*6d49e1aeSJan Lentfer wpabuf_free(msg); 378*6d49e1aeSJan Lentfer return NULL; 379*6d49e1aeSJan Lentfer } 380*6d49e1aeSJan Lentfer 381*6d49e1aeSJan Lentfer return msg; 382*6d49e1aeSJan Lentfer } 383*6d49e1aeSJan Lentfer 384*6d49e1aeSJan Lentfer 385*6d49e1aeSJan Lentfer static int eap_tlv_validate_cryptobinding(struct eap_sm *sm, 386*6d49e1aeSJan Lentfer struct eap_peap_data *data, 387*6d49e1aeSJan Lentfer const u8 *crypto_tlv, 388*6d49e1aeSJan Lentfer size_t crypto_tlv_len) 389*6d49e1aeSJan Lentfer { 390*6d49e1aeSJan Lentfer u8 buf[61], mac[SHA1_MAC_LEN]; 391*6d49e1aeSJan Lentfer const u8 *pos; 392*6d49e1aeSJan Lentfer 393*6d49e1aeSJan Lentfer if (eap_peap_derive_cmk(sm, data) < 0) { 394*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not derive CMK"); 395*6d49e1aeSJan Lentfer return -1; 396*6d49e1aeSJan Lentfer } 397*6d49e1aeSJan Lentfer 398*6d49e1aeSJan Lentfer if (crypto_tlv_len != 4 + 56) { 399*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid cryptobinding TLV " 400*6d49e1aeSJan Lentfer "length %d", (int) crypto_tlv_len); 401*6d49e1aeSJan Lentfer return -1; 402*6d49e1aeSJan Lentfer } 403*6d49e1aeSJan Lentfer 404*6d49e1aeSJan Lentfer pos = crypto_tlv; 405*6d49e1aeSJan Lentfer pos += 4; /* TLV header */ 406*6d49e1aeSJan Lentfer if (pos[1] != data->peap_version) { 407*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV Version " 408*6d49e1aeSJan Lentfer "mismatch (was %d; expected %d)", 409*6d49e1aeSJan Lentfer pos[1], data->peap_version); 410*6d49e1aeSJan Lentfer return -1; 411*6d49e1aeSJan Lentfer } 412*6d49e1aeSJan Lentfer 413*6d49e1aeSJan Lentfer if (pos[3] != 0) { 414*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected Cryptobinding TLV " 415*6d49e1aeSJan Lentfer "SubType %d", pos[3]); 416*6d49e1aeSJan Lentfer return -1; 417*6d49e1aeSJan Lentfer } 418*6d49e1aeSJan Lentfer pos += 4; 419*6d49e1aeSJan Lentfer os_memcpy(data->binding_nonce, pos, 32); 420*6d49e1aeSJan Lentfer pos += 32; /* Nonce */ 421*6d49e1aeSJan Lentfer 422*6d49e1aeSJan Lentfer /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */ 423*6d49e1aeSJan Lentfer os_memcpy(buf, crypto_tlv, 60); 424*6d49e1aeSJan Lentfer os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */ 425*6d49e1aeSJan Lentfer buf[60] = EAP_TYPE_PEAP; 426*6d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Compound_MAC data", 427*6d49e1aeSJan Lentfer buf, sizeof(buf)); 428*6d49e1aeSJan Lentfer hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac); 429*6d49e1aeSJan Lentfer 430*6d49e1aeSJan Lentfer if (os_memcmp(mac, pos, SHA1_MAC_LEN) != 0) { 431*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in " 432*6d49e1aeSJan Lentfer "cryptobinding TLV"); 433*6d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received MAC", 434*6d49e1aeSJan Lentfer pos, SHA1_MAC_LEN); 435*6d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Expected MAC", 436*6d49e1aeSJan Lentfer mac, SHA1_MAC_LEN); 437*6d49e1aeSJan Lentfer return -1; 438*6d49e1aeSJan Lentfer } 439*6d49e1aeSJan Lentfer 440*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received"); 441*6d49e1aeSJan Lentfer 442*6d49e1aeSJan Lentfer return 0; 443*6d49e1aeSJan Lentfer } 444*6d49e1aeSJan Lentfer 445*6d49e1aeSJan Lentfer 446*6d49e1aeSJan Lentfer /** 447*6d49e1aeSJan Lentfer * eap_tlv_process - Process a received EAP-TLV message and generate a response 448*6d49e1aeSJan Lentfer * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() 449*6d49e1aeSJan Lentfer * @ret: Return values from EAP request validation and processing 450*6d49e1aeSJan Lentfer * @req: EAP-TLV request to be processed. The caller must have validated that 451*6d49e1aeSJan Lentfer * the buffer is large enough to contain full request (hdr->length bytes) and 452*6d49e1aeSJan Lentfer * that the EAP type is EAP_TYPE_TLV. 453*6d49e1aeSJan Lentfer * @resp: Buffer to return a pointer to the allocated response message. This 454*6d49e1aeSJan Lentfer * field should be initialized to %NULL before the call. The value will be 455*6d49e1aeSJan Lentfer * updated if a response message is generated. The caller is responsible for 456*6d49e1aeSJan Lentfer * freeing the allocated message. 457*6d49e1aeSJan Lentfer * @force_failure: Force negotiation to fail 458*6d49e1aeSJan Lentfer * Returns: 0 on success, -1 on failure 459*6d49e1aeSJan Lentfer */ 460*6d49e1aeSJan Lentfer static int eap_tlv_process(struct eap_sm *sm, struct eap_peap_data *data, 461*6d49e1aeSJan Lentfer struct eap_method_ret *ret, 462*6d49e1aeSJan Lentfer const struct wpabuf *req, struct wpabuf **resp, 463*6d49e1aeSJan Lentfer int force_failure) 464*6d49e1aeSJan Lentfer { 465*6d49e1aeSJan Lentfer size_t left, tlv_len; 466*6d49e1aeSJan Lentfer const u8 *pos; 467*6d49e1aeSJan Lentfer const u8 *result_tlv = NULL, *crypto_tlv = NULL; 468*6d49e1aeSJan Lentfer size_t result_tlv_len = 0, crypto_tlv_len = 0; 469*6d49e1aeSJan Lentfer int tlv_type, mandatory; 470*6d49e1aeSJan Lentfer 471*6d49e1aeSJan Lentfer /* Parse TLVs */ 472*6d49e1aeSJan Lentfer pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, req, &left); 473*6d49e1aeSJan Lentfer if (pos == NULL) 474*6d49e1aeSJan Lentfer return -1; 475*6d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-TLV: Received TLVs", pos, left); 476*6d49e1aeSJan Lentfer while (left >= 4) { 477*6d49e1aeSJan Lentfer mandatory = !!(pos[0] & 0x80); 478*6d49e1aeSJan Lentfer tlv_type = WPA_GET_BE16(pos) & 0x3fff; 479*6d49e1aeSJan Lentfer pos += 2; 480*6d49e1aeSJan Lentfer tlv_len = WPA_GET_BE16(pos); 481*6d49e1aeSJan Lentfer pos += 2; 482*6d49e1aeSJan Lentfer left -= 4; 483*6d49e1aeSJan Lentfer if (tlv_len > left) { 484*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-TLV: TLV underrun " 485*6d49e1aeSJan Lentfer "(tlv_len=%lu left=%lu)", 486*6d49e1aeSJan Lentfer (unsigned long) tlv_len, 487*6d49e1aeSJan Lentfer (unsigned long) left); 488*6d49e1aeSJan Lentfer return -1; 489*6d49e1aeSJan Lentfer } 490*6d49e1aeSJan Lentfer switch (tlv_type) { 491*6d49e1aeSJan Lentfer case EAP_TLV_RESULT_TLV: 492*6d49e1aeSJan Lentfer result_tlv = pos; 493*6d49e1aeSJan Lentfer result_tlv_len = tlv_len; 494*6d49e1aeSJan Lentfer break; 495*6d49e1aeSJan Lentfer case EAP_TLV_CRYPTO_BINDING_TLV: 496*6d49e1aeSJan Lentfer crypto_tlv = pos; 497*6d49e1aeSJan Lentfer crypto_tlv_len = tlv_len; 498*6d49e1aeSJan Lentfer break; 499*6d49e1aeSJan Lentfer default: 500*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-TLV: Unsupported TLV Type " 501*6d49e1aeSJan Lentfer "%d%s", tlv_type, 502*6d49e1aeSJan Lentfer mandatory ? " (mandatory)" : ""); 503*6d49e1aeSJan Lentfer if (mandatory) { 504*6d49e1aeSJan Lentfer /* NAK TLV and ignore all TLVs in this packet. 505*6d49e1aeSJan Lentfer */ 506*6d49e1aeSJan Lentfer *resp = eap_tlv_build_nak(eap_get_id(req), 507*6d49e1aeSJan Lentfer tlv_type); 508*6d49e1aeSJan Lentfer return *resp == NULL ? -1 : 0; 509*6d49e1aeSJan Lentfer } 510*6d49e1aeSJan Lentfer /* Ignore this TLV, but process other TLVs */ 511*6d49e1aeSJan Lentfer break; 512*6d49e1aeSJan Lentfer } 513*6d49e1aeSJan Lentfer 514*6d49e1aeSJan Lentfer pos += tlv_len; 515*6d49e1aeSJan Lentfer left -= tlv_len; 516*6d49e1aeSJan Lentfer } 517*6d49e1aeSJan Lentfer if (left) { 518*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-TLV: Last TLV too short in " 519*6d49e1aeSJan Lentfer "Request (left=%lu)", (unsigned long) left); 520*6d49e1aeSJan Lentfer return -1; 521*6d49e1aeSJan Lentfer } 522*6d49e1aeSJan Lentfer 523*6d49e1aeSJan Lentfer /* Process supported TLVs */ 524*6d49e1aeSJan Lentfer if (crypto_tlv && data->crypto_binding != NO_BINDING) { 525*6d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV", 526*6d49e1aeSJan Lentfer crypto_tlv, crypto_tlv_len); 527*6d49e1aeSJan Lentfer if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4, 528*6d49e1aeSJan Lentfer crypto_tlv_len + 4) < 0) { 529*6d49e1aeSJan Lentfer if (result_tlv == NULL) 530*6d49e1aeSJan Lentfer return -1; 531*6d49e1aeSJan Lentfer force_failure = 1; 532*6d49e1aeSJan Lentfer crypto_tlv = NULL; /* do not include Cryptobinding TLV 533*6d49e1aeSJan Lentfer * in response, if the received 534*6d49e1aeSJan Lentfer * cryptobinding was invalid. */ 535*6d49e1aeSJan Lentfer } 536*6d49e1aeSJan Lentfer } else if (!crypto_tlv && data->crypto_binding == REQUIRE_BINDING) { 537*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV"); 538*6d49e1aeSJan Lentfer return -1; 539*6d49e1aeSJan Lentfer } 540*6d49e1aeSJan Lentfer 541*6d49e1aeSJan Lentfer if (result_tlv) { 542*6d49e1aeSJan Lentfer int status, resp_status; 543*6d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-TLV: Result TLV", 544*6d49e1aeSJan Lentfer result_tlv, result_tlv_len); 545*6d49e1aeSJan Lentfer if (result_tlv_len < 2) { 546*6d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-TLV: Too short Result TLV " 547*6d49e1aeSJan Lentfer "(len=%lu)", 548*6d49e1aeSJan Lentfer (unsigned long) result_tlv_len); 549*6d49e1aeSJan Lentfer return -1; 550*6d49e1aeSJan Lentfer } 551*6d49e1aeSJan Lentfer status = WPA_GET_BE16(result_tlv); 552*6d49e1aeSJan Lentfer if (status == EAP_TLV_RESULT_SUCCESS) { 553*6d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Success " 554*6d49e1aeSJan Lentfer "- EAP-TLV/Phase2 Completed"); 555*6d49e1aeSJan Lentfer if (force_failure) { 556*6d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-TLV: Earlier failure" 557*6d49e1aeSJan Lentfer " - force failed Phase 2"); 558*6d49e1aeSJan Lentfer resp_status = EAP_TLV_RESULT_FAILURE; 559*6d49e1aeSJan Lentfer ret->decision = DECISION_FAIL; 560*6d49e1aeSJan Lentfer } else { 561*6d49e1aeSJan Lentfer resp_status = EAP_TLV_RESULT_SUCCESS; 562*6d49e1aeSJan Lentfer ret->decision = DECISION_UNCOND_SUCC; 563*6d49e1aeSJan Lentfer } 564*6d49e1aeSJan Lentfer } else if (status == EAP_TLV_RESULT_FAILURE) { 565*6d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Failure"); 566*6d49e1aeSJan Lentfer resp_status = EAP_TLV_RESULT_FAILURE; 567*6d49e1aeSJan Lentfer ret->decision = DECISION_FAIL; 568*6d49e1aeSJan Lentfer } else { 569*6d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-TLV: Unknown TLV Result " 570*6d49e1aeSJan Lentfer "Status %d", status); 571*6d49e1aeSJan Lentfer resp_status = EAP_TLV_RESULT_FAILURE; 572*6d49e1aeSJan Lentfer ret->decision = DECISION_FAIL; 573*6d49e1aeSJan Lentfer } 574*6d49e1aeSJan Lentfer ret->methodState = METHOD_DONE; 575*6d49e1aeSJan Lentfer 576*6d49e1aeSJan Lentfer *resp = eap_tlv_build_result(sm, data, crypto_tlv != NULL, 577*6d49e1aeSJan Lentfer eap_get_id(req), resp_status); 578*6d49e1aeSJan Lentfer } 579*6d49e1aeSJan Lentfer 580*6d49e1aeSJan Lentfer return 0; 581*6d49e1aeSJan Lentfer } 582*6d49e1aeSJan Lentfer 583*6d49e1aeSJan Lentfer 584*6d49e1aeSJan Lentfer static struct wpabuf * eap_peapv2_tlv_eap_payload(struct wpabuf *buf) 585*6d49e1aeSJan Lentfer { 586*6d49e1aeSJan Lentfer struct wpabuf *e; 587*6d49e1aeSJan Lentfer struct eap_tlv_hdr *tlv; 588*6d49e1aeSJan Lentfer 589*6d49e1aeSJan Lentfer if (buf == NULL) 590*6d49e1aeSJan Lentfer return NULL; 591*6d49e1aeSJan Lentfer 592*6d49e1aeSJan Lentfer /* Encapsulate EAP packet in EAP-Payload TLV */ 593*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Add EAP-Payload TLV"); 594*6d49e1aeSJan Lentfer e = wpabuf_alloc(sizeof(*tlv) + wpabuf_len(buf)); 595*6d49e1aeSJan Lentfer if (e == NULL) { 596*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Failed to allocate memory " 597*6d49e1aeSJan Lentfer "for TLV encapsulation"); 598*6d49e1aeSJan Lentfer wpabuf_free(buf); 599*6d49e1aeSJan Lentfer return NULL; 600*6d49e1aeSJan Lentfer } 601*6d49e1aeSJan Lentfer tlv = wpabuf_put(e, sizeof(*tlv)); 602*6d49e1aeSJan Lentfer tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | 603*6d49e1aeSJan Lentfer EAP_TLV_EAP_PAYLOAD_TLV); 604*6d49e1aeSJan Lentfer tlv->length = host_to_be16(wpabuf_len(buf)); 605*6d49e1aeSJan Lentfer wpabuf_put_buf(e, buf); 606*6d49e1aeSJan Lentfer wpabuf_free(buf); 607*6d49e1aeSJan Lentfer return e; 608*6d49e1aeSJan Lentfer } 609*6d49e1aeSJan Lentfer 610*6d49e1aeSJan Lentfer 611*6d49e1aeSJan Lentfer static int eap_peap_phase2_request(struct eap_sm *sm, 612*6d49e1aeSJan Lentfer struct eap_peap_data *data, 613*6d49e1aeSJan Lentfer struct eap_method_ret *ret, 614*6d49e1aeSJan Lentfer struct wpabuf *req, 615*6d49e1aeSJan Lentfer struct wpabuf **resp) 616*6d49e1aeSJan Lentfer { 617*6d49e1aeSJan Lentfer struct eap_hdr *hdr = wpabuf_mhead(req); 618*6d49e1aeSJan Lentfer size_t len = be_to_host16(hdr->length); 619*6d49e1aeSJan Lentfer u8 *pos; 620*6d49e1aeSJan Lentfer struct eap_method_ret iret; 621*6d49e1aeSJan Lentfer struct eap_peer_config *config = eap_get_config(sm); 622*6d49e1aeSJan Lentfer 623*6d49e1aeSJan Lentfer if (len <= sizeof(struct eap_hdr)) { 624*6d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-PEAP: too short " 625*6d49e1aeSJan Lentfer "Phase 2 request (len=%lu)", (unsigned long) len); 626*6d49e1aeSJan Lentfer return -1; 627*6d49e1aeSJan Lentfer } 628*6d49e1aeSJan Lentfer pos = (u8 *) (hdr + 1); 629*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Request: type=%d", *pos); 630*6d49e1aeSJan Lentfer switch (*pos) { 631*6d49e1aeSJan Lentfer case EAP_TYPE_IDENTITY: 632*6d49e1aeSJan Lentfer *resp = eap_sm_buildIdentity(sm, hdr->identifier, 1); 633*6d49e1aeSJan Lentfer break; 634*6d49e1aeSJan Lentfer case EAP_TYPE_TLV: 635*6d49e1aeSJan Lentfer os_memset(&iret, 0, sizeof(iret)); 636*6d49e1aeSJan Lentfer if (eap_tlv_process(sm, data, &iret, req, resp, 637*6d49e1aeSJan Lentfer data->phase2_eap_started && 638*6d49e1aeSJan Lentfer !data->phase2_eap_success)) { 639*6d49e1aeSJan Lentfer ret->methodState = METHOD_DONE; 640*6d49e1aeSJan Lentfer ret->decision = DECISION_FAIL; 641*6d49e1aeSJan Lentfer return -1; 642*6d49e1aeSJan Lentfer } 643*6d49e1aeSJan Lentfer if (iret.methodState == METHOD_DONE || 644*6d49e1aeSJan Lentfer iret.methodState == METHOD_MAY_CONT) { 645*6d49e1aeSJan Lentfer ret->methodState = iret.methodState; 646*6d49e1aeSJan Lentfer ret->decision = iret.decision; 647*6d49e1aeSJan Lentfer data->phase2_success = 1; 648*6d49e1aeSJan Lentfer } 649*6d49e1aeSJan Lentfer break; 650*6d49e1aeSJan Lentfer case EAP_TYPE_EXPANDED: 651*6d49e1aeSJan Lentfer #ifdef EAP_TNC 652*6d49e1aeSJan Lentfer if (data->soh) { 653*6d49e1aeSJan Lentfer const u8 *epos; 654*6d49e1aeSJan Lentfer size_t eleft; 655*6d49e1aeSJan Lentfer 656*6d49e1aeSJan Lentfer epos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21, 657*6d49e1aeSJan Lentfer req, &eleft); 658*6d49e1aeSJan Lentfer if (epos) { 659*6d49e1aeSJan Lentfer struct wpabuf *buf; 660*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, 661*6d49e1aeSJan Lentfer "EAP-PEAP: SoH EAP Extensions"); 662*6d49e1aeSJan Lentfer buf = tncc_process_soh_request(data->soh, 663*6d49e1aeSJan Lentfer epos, eleft); 664*6d49e1aeSJan Lentfer if (buf) { 665*6d49e1aeSJan Lentfer *resp = eap_msg_alloc( 666*6d49e1aeSJan Lentfer EAP_VENDOR_MICROSOFT, 0x21, 667*6d49e1aeSJan Lentfer wpabuf_len(buf), 668*6d49e1aeSJan Lentfer EAP_CODE_RESPONSE, 669*6d49e1aeSJan Lentfer hdr->identifier); 670*6d49e1aeSJan Lentfer if (*resp == NULL) { 671*6d49e1aeSJan Lentfer ret->methodState = METHOD_DONE; 672*6d49e1aeSJan Lentfer ret->decision = DECISION_FAIL; 673*6d49e1aeSJan Lentfer return -1; 674*6d49e1aeSJan Lentfer } 675*6d49e1aeSJan Lentfer wpabuf_put_buf(*resp, buf); 676*6d49e1aeSJan Lentfer wpabuf_free(buf); 677*6d49e1aeSJan Lentfer break; 678*6d49e1aeSJan Lentfer } 679*6d49e1aeSJan Lentfer } 680*6d49e1aeSJan Lentfer } 681*6d49e1aeSJan Lentfer #endif /* EAP_TNC */ 682*6d49e1aeSJan Lentfer /* fall through */ 683*6d49e1aeSJan Lentfer default: 684*6d49e1aeSJan Lentfer if (data->phase2_type.vendor == EAP_VENDOR_IETF && 685*6d49e1aeSJan Lentfer data->phase2_type.method == EAP_TYPE_NONE) { 686*6d49e1aeSJan Lentfer size_t i; 687*6d49e1aeSJan Lentfer for (i = 0; i < data->num_phase2_types; i++) { 688*6d49e1aeSJan Lentfer if (data->phase2_types[i].vendor != 689*6d49e1aeSJan Lentfer EAP_VENDOR_IETF || 690*6d49e1aeSJan Lentfer data->phase2_types[i].method != *pos) 691*6d49e1aeSJan Lentfer continue; 692*6d49e1aeSJan Lentfer 693*6d49e1aeSJan Lentfer data->phase2_type.vendor = 694*6d49e1aeSJan Lentfer data->phase2_types[i].vendor; 695*6d49e1aeSJan Lentfer data->phase2_type.method = 696*6d49e1aeSJan Lentfer data->phase2_types[i].method; 697*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Selected " 698*6d49e1aeSJan Lentfer "Phase 2 EAP vendor %d method %d", 699*6d49e1aeSJan Lentfer data->phase2_type.vendor, 700*6d49e1aeSJan Lentfer data->phase2_type.method); 701*6d49e1aeSJan Lentfer break; 702*6d49e1aeSJan Lentfer } 703*6d49e1aeSJan Lentfer } 704*6d49e1aeSJan Lentfer if (*pos != data->phase2_type.method || 705*6d49e1aeSJan Lentfer *pos == EAP_TYPE_NONE) { 706*6d49e1aeSJan Lentfer if (eap_peer_tls_phase2_nak(data->phase2_types, 707*6d49e1aeSJan Lentfer data->num_phase2_types, 708*6d49e1aeSJan Lentfer hdr, resp)) 709*6d49e1aeSJan Lentfer return -1; 710*6d49e1aeSJan Lentfer return 0; 711*6d49e1aeSJan Lentfer } 712*6d49e1aeSJan Lentfer 713*6d49e1aeSJan Lentfer if (data->phase2_priv == NULL) { 714*6d49e1aeSJan Lentfer data->phase2_method = eap_peer_get_eap_method( 715*6d49e1aeSJan Lentfer data->phase2_type.vendor, 716*6d49e1aeSJan Lentfer data->phase2_type.method); 717*6d49e1aeSJan Lentfer if (data->phase2_method) { 718*6d49e1aeSJan Lentfer sm->init_phase2 = 1; 719*6d49e1aeSJan Lentfer data->phase2_priv = 720*6d49e1aeSJan Lentfer data->phase2_method->init(sm); 721*6d49e1aeSJan Lentfer sm->init_phase2 = 0; 722*6d49e1aeSJan Lentfer } 723*6d49e1aeSJan Lentfer } 724*6d49e1aeSJan Lentfer if (data->phase2_priv == NULL || data->phase2_method == NULL) { 725*6d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-PEAP: failed to initialize " 726*6d49e1aeSJan Lentfer "Phase 2 EAP method %d", *pos); 727*6d49e1aeSJan Lentfer ret->methodState = METHOD_DONE; 728*6d49e1aeSJan Lentfer ret->decision = DECISION_FAIL; 729*6d49e1aeSJan Lentfer return -1; 730*6d49e1aeSJan Lentfer } 731*6d49e1aeSJan Lentfer data->phase2_eap_started = 1; 732*6d49e1aeSJan Lentfer os_memset(&iret, 0, sizeof(iret)); 733*6d49e1aeSJan Lentfer *resp = data->phase2_method->process(sm, data->phase2_priv, 734*6d49e1aeSJan Lentfer &iret, req); 735*6d49e1aeSJan Lentfer if ((iret.methodState == METHOD_DONE || 736*6d49e1aeSJan Lentfer iret.methodState == METHOD_MAY_CONT) && 737*6d49e1aeSJan Lentfer (iret.decision == DECISION_UNCOND_SUCC || 738*6d49e1aeSJan Lentfer iret.decision == DECISION_COND_SUCC)) { 739*6d49e1aeSJan Lentfer data->phase2_eap_success = 1; 740*6d49e1aeSJan Lentfer data->phase2_success = 1; 741*6d49e1aeSJan Lentfer } 742*6d49e1aeSJan Lentfer break; 743*6d49e1aeSJan Lentfer } 744*6d49e1aeSJan Lentfer 745*6d49e1aeSJan Lentfer if (*resp == NULL && 746*6d49e1aeSJan Lentfer (config->pending_req_identity || config->pending_req_password || 747*6d49e1aeSJan Lentfer config->pending_req_otp || config->pending_req_new_password)) { 748*6d49e1aeSJan Lentfer wpabuf_free(data->pending_phase2_req); 749*6d49e1aeSJan Lentfer data->pending_phase2_req = wpabuf_alloc_copy(hdr, len); 750*6d49e1aeSJan Lentfer } 751*6d49e1aeSJan Lentfer 752*6d49e1aeSJan Lentfer return 0; 753*6d49e1aeSJan Lentfer } 754*6d49e1aeSJan Lentfer 755*6d49e1aeSJan Lentfer 756*6d49e1aeSJan Lentfer static int eap_peap_decrypt(struct eap_sm *sm, struct eap_peap_data *data, 757*6d49e1aeSJan Lentfer struct eap_method_ret *ret, 758*6d49e1aeSJan Lentfer const struct eap_hdr *req, 759*6d49e1aeSJan Lentfer const struct wpabuf *in_data, 760*6d49e1aeSJan Lentfer struct wpabuf **out_data) 761*6d49e1aeSJan Lentfer { 762*6d49e1aeSJan Lentfer struct wpabuf *in_decrypted = NULL; 763*6d49e1aeSJan Lentfer int res, skip_change = 0; 764*6d49e1aeSJan Lentfer struct eap_hdr *hdr, *rhdr; 765*6d49e1aeSJan Lentfer struct wpabuf *resp = NULL; 766*6d49e1aeSJan Lentfer size_t len; 767*6d49e1aeSJan Lentfer 768*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for" 769*6d49e1aeSJan Lentfer " Phase 2", (unsigned long) wpabuf_len(in_data)); 770*6d49e1aeSJan Lentfer 771*6d49e1aeSJan Lentfer if (data->pending_phase2_req) { 772*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 request - " 773*6d49e1aeSJan Lentfer "skip decryption and use old data"); 774*6d49e1aeSJan Lentfer /* Clear TLS reassembly state. */ 775*6d49e1aeSJan Lentfer eap_peer_tls_reset_input(&data->ssl); 776*6d49e1aeSJan Lentfer in_decrypted = data->pending_phase2_req; 777*6d49e1aeSJan Lentfer data->pending_phase2_req = NULL; 778*6d49e1aeSJan Lentfer skip_change = 1; 779*6d49e1aeSJan Lentfer goto continue_req; 780*6d49e1aeSJan Lentfer } 781*6d49e1aeSJan Lentfer 782*6d49e1aeSJan Lentfer if (wpabuf_len(in_data) == 0 && sm->workaround && 783*6d49e1aeSJan Lentfer data->phase2_success) { 784*6d49e1aeSJan Lentfer /* 785*6d49e1aeSJan Lentfer * Cisco ACS seems to be using TLS ACK to terminate 786*6d49e1aeSJan Lentfer * EAP-PEAPv0/GTC. Try to reply with TLS ACK. 787*6d49e1aeSJan Lentfer */ 788*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Received TLS ACK, but " 789*6d49e1aeSJan Lentfer "expected data - acknowledge with TLS ACK since " 790*6d49e1aeSJan Lentfer "Phase 2 has been completed"); 791*6d49e1aeSJan Lentfer ret->decision = DECISION_COND_SUCC; 792*6d49e1aeSJan Lentfer ret->methodState = METHOD_DONE; 793*6d49e1aeSJan Lentfer return 1; 794*6d49e1aeSJan Lentfer } else if (wpabuf_len(in_data) == 0) { 795*6d49e1aeSJan Lentfer /* Received TLS ACK - requesting more fragments */ 796*6d49e1aeSJan Lentfer return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP, 797*6d49e1aeSJan Lentfer data->peap_version, 798*6d49e1aeSJan Lentfer req->identifier, NULL, out_data); 799*6d49e1aeSJan Lentfer } 800*6d49e1aeSJan Lentfer 801*6d49e1aeSJan Lentfer res = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted); 802*6d49e1aeSJan Lentfer if (res) 803*6d49e1aeSJan Lentfer return res; 804*6d49e1aeSJan Lentfer 805*6d49e1aeSJan Lentfer continue_req: 806*6d49e1aeSJan Lentfer wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP", 807*6d49e1aeSJan Lentfer in_decrypted); 808*6d49e1aeSJan Lentfer 809*6d49e1aeSJan Lentfer hdr = wpabuf_mhead(in_decrypted); 810*6d49e1aeSJan Lentfer if (wpabuf_len(in_decrypted) == 5 && hdr->code == EAP_CODE_REQUEST && 811*6d49e1aeSJan Lentfer be_to_host16(hdr->length) == 5 && 812*6d49e1aeSJan Lentfer eap_get_type(in_decrypted) == EAP_TYPE_IDENTITY) { 813*6d49e1aeSJan Lentfer /* At least FreeRADIUS seems to send full EAP header with 814*6d49e1aeSJan Lentfer * EAP Request Identity */ 815*6d49e1aeSJan Lentfer skip_change = 1; 816*6d49e1aeSJan Lentfer } 817*6d49e1aeSJan Lentfer if (wpabuf_len(in_decrypted) >= 5 && hdr->code == EAP_CODE_REQUEST && 818*6d49e1aeSJan Lentfer eap_get_type(in_decrypted) == EAP_TYPE_TLV) { 819*6d49e1aeSJan Lentfer skip_change = 1; 820*6d49e1aeSJan Lentfer } 821*6d49e1aeSJan Lentfer 822*6d49e1aeSJan Lentfer if (data->peap_version == 0 && !skip_change) { 823*6d49e1aeSJan Lentfer struct eap_hdr *nhdr; 824*6d49e1aeSJan Lentfer struct wpabuf *nmsg = wpabuf_alloc(sizeof(struct eap_hdr) + 825*6d49e1aeSJan Lentfer wpabuf_len(in_decrypted)); 826*6d49e1aeSJan Lentfer if (nmsg == NULL) { 827*6d49e1aeSJan Lentfer wpabuf_free(in_decrypted); 828*6d49e1aeSJan Lentfer return 0; 829*6d49e1aeSJan Lentfer } 830*6d49e1aeSJan Lentfer nhdr = wpabuf_put(nmsg, sizeof(*nhdr)); 831*6d49e1aeSJan Lentfer wpabuf_put_buf(nmsg, in_decrypted); 832*6d49e1aeSJan Lentfer nhdr->code = req->code; 833*6d49e1aeSJan Lentfer nhdr->identifier = req->identifier; 834*6d49e1aeSJan Lentfer nhdr->length = host_to_be16(sizeof(struct eap_hdr) + 835*6d49e1aeSJan Lentfer wpabuf_len(in_decrypted)); 836*6d49e1aeSJan Lentfer 837*6d49e1aeSJan Lentfer wpabuf_free(in_decrypted); 838*6d49e1aeSJan Lentfer in_decrypted = nmsg; 839*6d49e1aeSJan Lentfer } 840*6d49e1aeSJan Lentfer 841*6d49e1aeSJan Lentfer if (data->peap_version >= 2) { 842*6d49e1aeSJan Lentfer struct eap_tlv_hdr *tlv; 843*6d49e1aeSJan Lentfer struct wpabuf *nmsg; 844*6d49e1aeSJan Lentfer 845*6d49e1aeSJan Lentfer if (wpabuf_len(in_decrypted) < sizeof(*tlv) + sizeof(*hdr)) { 846*6d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-PEAPv2: Too short Phase 2 " 847*6d49e1aeSJan Lentfer "EAP TLV"); 848*6d49e1aeSJan Lentfer wpabuf_free(in_decrypted); 849*6d49e1aeSJan Lentfer return 0; 850*6d49e1aeSJan Lentfer } 851*6d49e1aeSJan Lentfer tlv = wpabuf_mhead(in_decrypted); 852*6d49e1aeSJan Lentfer if ((be_to_host16(tlv->tlv_type) & 0x3fff) != 853*6d49e1aeSJan Lentfer EAP_TLV_EAP_PAYLOAD_TLV) { 854*6d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-PEAPv2: Not an EAP TLV"); 855*6d49e1aeSJan Lentfer wpabuf_free(in_decrypted); 856*6d49e1aeSJan Lentfer return 0; 857*6d49e1aeSJan Lentfer } 858*6d49e1aeSJan Lentfer if (sizeof(*tlv) + be_to_host16(tlv->length) > 859*6d49e1aeSJan Lentfer wpabuf_len(in_decrypted)) { 860*6d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-PEAPv2: Invalid EAP TLV " 861*6d49e1aeSJan Lentfer "length"); 862*6d49e1aeSJan Lentfer wpabuf_free(in_decrypted); 863*6d49e1aeSJan Lentfer return 0; 864*6d49e1aeSJan Lentfer } 865*6d49e1aeSJan Lentfer hdr = (struct eap_hdr *) (tlv + 1); 866*6d49e1aeSJan Lentfer if (be_to_host16(hdr->length) > be_to_host16(tlv->length)) { 867*6d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-PEAPv2: No room for full " 868*6d49e1aeSJan Lentfer "EAP packet in EAP TLV"); 869*6d49e1aeSJan Lentfer wpabuf_free(in_decrypted); 870*6d49e1aeSJan Lentfer return 0; 871*6d49e1aeSJan Lentfer } 872*6d49e1aeSJan Lentfer 873*6d49e1aeSJan Lentfer nmsg = wpabuf_alloc(be_to_host16(hdr->length)); 874*6d49e1aeSJan Lentfer if (nmsg == NULL) { 875*6d49e1aeSJan Lentfer wpabuf_free(in_decrypted); 876*6d49e1aeSJan Lentfer return 0; 877*6d49e1aeSJan Lentfer } 878*6d49e1aeSJan Lentfer 879*6d49e1aeSJan Lentfer wpabuf_put_data(nmsg, hdr, be_to_host16(hdr->length)); 880*6d49e1aeSJan Lentfer wpabuf_free(in_decrypted); 881*6d49e1aeSJan Lentfer in_decrypted = nmsg; 882*6d49e1aeSJan Lentfer } 883*6d49e1aeSJan Lentfer 884*6d49e1aeSJan Lentfer hdr = wpabuf_mhead(in_decrypted); 885*6d49e1aeSJan Lentfer if (wpabuf_len(in_decrypted) < sizeof(*hdr)) { 886*6d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 " 887*6d49e1aeSJan Lentfer "EAP frame (len=%lu)", 888*6d49e1aeSJan Lentfer (unsigned long) wpabuf_len(in_decrypted)); 889*6d49e1aeSJan Lentfer wpabuf_free(in_decrypted); 890*6d49e1aeSJan Lentfer return 0; 891*6d49e1aeSJan Lentfer } 892*6d49e1aeSJan Lentfer len = be_to_host16(hdr->length); 893*6d49e1aeSJan Lentfer if (len > wpabuf_len(in_decrypted)) { 894*6d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in " 895*6d49e1aeSJan Lentfer "Phase 2 EAP frame (len=%lu hdr->length=%lu)", 896*6d49e1aeSJan Lentfer (unsigned long) wpabuf_len(in_decrypted), 897*6d49e1aeSJan Lentfer (unsigned long) len); 898*6d49e1aeSJan Lentfer wpabuf_free(in_decrypted); 899*6d49e1aeSJan Lentfer return 0; 900*6d49e1aeSJan Lentfer } 901*6d49e1aeSJan Lentfer if (len < wpabuf_len(in_decrypted)) { 902*6d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-PEAP: Odd.. Phase 2 EAP header has " 903*6d49e1aeSJan Lentfer "shorter length than full decrypted data " 904*6d49e1aeSJan Lentfer "(%lu < %lu)", 905*6d49e1aeSJan Lentfer (unsigned long) len, 906*6d49e1aeSJan Lentfer (unsigned long) wpabuf_len(in_decrypted)); 907*6d49e1aeSJan Lentfer } 908*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d " 909*6d49e1aeSJan Lentfer "identifier=%d length=%lu", hdr->code, hdr->identifier, 910*6d49e1aeSJan Lentfer (unsigned long) len); 911*6d49e1aeSJan Lentfer switch (hdr->code) { 912*6d49e1aeSJan Lentfer case EAP_CODE_REQUEST: 913*6d49e1aeSJan Lentfer if (eap_peap_phase2_request(sm, data, ret, in_decrypted, 914*6d49e1aeSJan Lentfer &resp)) { 915*6d49e1aeSJan Lentfer wpabuf_free(in_decrypted); 916*6d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-PEAP: Phase2 Request " 917*6d49e1aeSJan Lentfer "processing failed"); 918*6d49e1aeSJan Lentfer return 0; 919*6d49e1aeSJan Lentfer } 920*6d49e1aeSJan Lentfer break; 921*6d49e1aeSJan Lentfer case EAP_CODE_SUCCESS: 922*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success"); 923*6d49e1aeSJan Lentfer if (data->peap_version == 1) { 924*6d49e1aeSJan Lentfer /* EAP-Success within TLS tunnel is used to indicate 925*6d49e1aeSJan Lentfer * shutdown of the TLS channel. The authentication has 926*6d49e1aeSJan Lentfer * been completed. */ 927*6d49e1aeSJan Lentfer if (data->phase2_eap_started && 928*6d49e1aeSJan Lentfer !data->phase2_eap_success) { 929*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 " 930*6d49e1aeSJan Lentfer "Success used to indicate success, " 931*6d49e1aeSJan Lentfer "but Phase 2 EAP was not yet " 932*6d49e1aeSJan Lentfer "completed successfully"); 933*6d49e1aeSJan Lentfer ret->methodState = METHOD_DONE; 934*6d49e1aeSJan Lentfer ret->decision = DECISION_FAIL; 935*6d49e1aeSJan Lentfer wpabuf_free(in_decrypted); 936*6d49e1aeSJan Lentfer return 0; 937*6d49e1aeSJan Lentfer } 938*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Version 1 - " 939*6d49e1aeSJan Lentfer "EAP-Success within TLS tunnel - " 940*6d49e1aeSJan Lentfer "authentication completed"); 941*6d49e1aeSJan Lentfer ret->decision = DECISION_UNCOND_SUCC; 942*6d49e1aeSJan Lentfer ret->methodState = METHOD_DONE; 943*6d49e1aeSJan Lentfer data->phase2_success = 1; 944*6d49e1aeSJan Lentfer if (data->peap_outer_success == 2) { 945*6d49e1aeSJan Lentfer wpabuf_free(in_decrypted); 946*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Use TLS ACK " 947*6d49e1aeSJan Lentfer "to finish authentication"); 948*6d49e1aeSJan Lentfer return 1; 949*6d49e1aeSJan Lentfer } else if (data->peap_outer_success == 1) { 950*6d49e1aeSJan Lentfer /* Reply with EAP-Success within the TLS 951*6d49e1aeSJan Lentfer * channel to complete the authentication. */ 952*6d49e1aeSJan Lentfer resp = wpabuf_alloc(sizeof(struct eap_hdr)); 953*6d49e1aeSJan Lentfer if (resp) { 954*6d49e1aeSJan Lentfer rhdr = wpabuf_put(resp, sizeof(*rhdr)); 955*6d49e1aeSJan Lentfer rhdr->code = EAP_CODE_SUCCESS; 956*6d49e1aeSJan Lentfer rhdr->identifier = hdr->identifier; 957*6d49e1aeSJan Lentfer rhdr->length = 958*6d49e1aeSJan Lentfer host_to_be16(sizeof(*rhdr)); 959*6d49e1aeSJan Lentfer } 960*6d49e1aeSJan Lentfer } else { 961*6d49e1aeSJan Lentfer /* No EAP-Success expected for Phase 1 (outer, 962*6d49e1aeSJan Lentfer * unencrypted auth), so force EAP state 963*6d49e1aeSJan Lentfer * machine to SUCCESS state. */ 964*6d49e1aeSJan Lentfer sm->peap_done = TRUE; 965*6d49e1aeSJan Lentfer } 966*6d49e1aeSJan Lentfer } else { 967*6d49e1aeSJan Lentfer /* FIX: ? */ 968*6d49e1aeSJan Lentfer } 969*6d49e1aeSJan Lentfer break; 970*6d49e1aeSJan Lentfer case EAP_CODE_FAILURE: 971*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure"); 972*6d49e1aeSJan Lentfer ret->decision = DECISION_FAIL; 973*6d49e1aeSJan Lentfer ret->methodState = METHOD_MAY_CONT; 974*6d49e1aeSJan Lentfer ret->allowNotifications = FALSE; 975*6d49e1aeSJan Lentfer /* Reply with EAP-Failure within the TLS channel to complete 976*6d49e1aeSJan Lentfer * failure reporting. */ 977*6d49e1aeSJan Lentfer resp = wpabuf_alloc(sizeof(struct eap_hdr)); 978*6d49e1aeSJan Lentfer if (resp) { 979*6d49e1aeSJan Lentfer rhdr = wpabuf_put(resp, sizeof(*rhdr)); 980*6d49e1aeSJan Lentfer rhdr->code = EAP_CODE_FAILURE; 981*6d49e1aeSJan Lentfer rhdr->identifier = hdr->identifier; 982*6d49e1aeSJan Lentfer rhdr->length = host_to_be16(sizeof(*rhdr)); 983*6d49e1aeSJan Lentfer } 984*6d49e1aeSJan Lentfer break; 985*6d49e1aeSJan Lentfer default: 986*6d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in " 987*6d49e1aeSJan Lentfer "Phase 2 EAP header", hdr->code); 988*6d49e1aeSJan Lentfer break; 989*6d49e1aeSJan Lentfer } 990*6d49e1aeSJan Lentfer 991*6d49e1aeSJan Lentfer wpabuf_free(in_decrypted); 992*6d49e1aeSJan Lentfer 993*6d49e1aeSJan Lentfer if (resp) { 994*6d49e1aeSJan Lentfer int skip_change2 = 0; 995*6d49e1aeSJan Lentfer struct wpabuf *rmsg, buf; 996*6d49e1aeSJan Lentfer 997*6d49e1aeSJan Lentfer wpa_hexdump_buf_key(MSG_DEBUG, 998*6d49e1aeSJan Lentfer "EAP-PEAP: Encrypting Phase 2 data", resp); 999*6d49e1aeSJan Lentfer /* PEAP version changes */ 1000*6d49e1aeSJan Lentfer if (data->peap_version >= 2) { 1001*6d49e1aeSJan Lentfer resp = eap_peapv2_tlv_eap_payload(resp); 1002*6d49e1aeSJan Lentfer if (resp == NULL) 1003*6d49e1aeSJan Lentfer return -1; 1004*6d49e1aeSJan Lentfer } 1005*6d49e1aeSJan Lentfer if (wpabuf_len(resp) >= 5 && 1006*6d49e1aeSJan Lentfer wpabuf_head_u8(resp)[0] == EAP_CODE_RESPONSE && 1007*6d49e1aeSJan Lentfer eap_get_type(resp) == EAP_TYPE_TLV) 1008*6d49e1aeSJan Lentfer skip_change2 = 1; 1009*6d49e1aeSJan Lentfer rmsg = resp; 1010*6d49e1aeSJan Lentfer if (data->peap_version == 0 && !skip_change2) { 1011*6d49e1aeSJan Lentfer wpabuf_set(&buf, wpabuf_head_u8(resp) + 1012*6d49e1aeSJan Lentfer sizeof(struct eap_hdr), 1013*6d49e1aeSJan Lentfer wpabuf_len(resp) - sizeof(struct eap_hdr)); 1014*6d49e1aeSJan Lentfer rmsg = &buf; 1015*6d49e1aeSJan Lentfer } 1016*6d49e1aeSJan Lentfer 1017*6d49e1aeSJan Lentfer if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP, 1018*6d49e1aeSJan Lentfer data->peap_version, req->identifier, 1019*6d49e1aeSJan Lentfer rmsg, out_data)) { 1020*6d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt " 1021*6d49e1aeSJan Lentfer "a Phase 2 frame"); 1022*6d49e1aeSJan Lentfer } 1023*6d49e1aeSJan Lentfer wpabuf_free(resp); 1024*6d49e1aeSJan Lentfer } 1025*6d49e1aeSJan Lentfer 1026*6d49e1aeSJan Lentfer return 0; 1027*6d49e1aeSJan Lentfer } 1028*6d49e1aeSJan Lentfer 1029*6d49e1aeSJan Lentfer 1030*6d49e1aeSJan Lentfer static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv, 1031*6d49e1aeSJan Lentfer struct eap_method_ret *ret, 1032*6d49e1aeSJan Lentfer const struct wpabuf *reqData) 1033*6d49e1aeSJan Lentfer { 1034*6d49e1aeSJan Lentfer const struct eap_hdr *req; 1035*6d49e1aeSJan Lentfer size_t left; 1036*6d49e1aeSJan Lentfer int res; 1037*6d49e1aeSJan Lentfer u8 flags, id; 1038*6d49e1aeSJan Lentfer struct wpabuf *resp; 1039*6d49e1aeSJan Lentfer const u8 *pos; 1040*6d49e1aeSJan Lentfer struct eap_peap_data *data = priv; 1041*6d49e1aeSJan Lentfer 1042*6d49e1aeSJan Lentfer pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_PEAP, ret, 1043*6d49e1aeSJan Lentfer reqData, &left, &flags); 1044*6d49e1aeSJan Lentfer if (pos == NULL) 1045*6d49e1aeSJan Lentfer return NULL; 1046*6d49e1aeSJan Lentfer req = wpabuf_head(reqData); 1047*6d49e1aeSJan Lentfer id = req->identifier; 1048*6d49e1aeSJan Lentfer 1049*6d49e1aeSJan Lentfer if (flags & EAP_TLS_FLAGS_START) { 1050*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Start (server ver=%d, own " 1051*6d49e1aeSJan Lentfer "ver=%d)", flags & EAP_PEAP_VERSION_MASK, 1052*6d49e1aeSJan Lentfer data->peap_version); 1053*6d49e1aeSJan Lentfer if ((flags & EAP_PEAP_VERSION_MASK) < data->peap_version) 1054*6d49e1aeSJan Lentfer data->peap_version = flags & EAP_PEAP_VERSION_MASK; 1055*6d49e1aeSJan Lentfer if (data->force_peap_version >= 0 && 1056*6d49e1aeSJan Lentfer data->force_peap_version != data->peap_version) { 1057*6d49e1aeSJan Lentfer wpa_printf(MSG_WARNING, "EAP-PEAP: Failed to select " 1058*6d49e1aeSJan Lentfer "forced PEAP version %d", 1059*6d49e1aeSJan Lentfer data->force_peap_version); 1060*6d49e1aeSJan Lentfer ret->methodState = METHOD_DONE; 1061*6d49e1aeSJan Lentfer ret->decision = DECISION_FAIL; 1062*6d49e1aeSJan Lentfer ret->allowNotifications = FALSE; 1063*6d49e1aeSJan Lentfer return NULL; 1064*6d49e1aeSJan Lentfer } 1065*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Using PEAP version %d", 1066*6d49e1aeSJan Lentfer data->peap_version); 1067*6d49e1aeSJan Lentfer left = 0; /* make sure that this frame is empty, even though it 1068*6d49e1aeSJan Lentfer * should always be, anyway */ 1069*6d49e1aeSJan Lentfer } 1070*6d49e1aeSJan Lentfer 1071*6d49e1aeSJan Lentfer resp = NULL; 1072*6d49e1aeSJan Lentfer if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) && 1073*6d49e1aeSJan Lentfer !data->resuming) { 1074*6d49e1aeSJan Lentfer struct wpabuf msg; 1075*6d49e1aeSJan Lentfer wpabuf_set(&msg, pos, left); 1076*6d49e1aeSJan Lentfer res = eap_peap_decrypt(sm, data, ret, req, &msg, &resp); 1077*6d49e1aeSJan Lentfer } else { 1078*6d49e1aeSJan Lentfer res = eap_peer_tls_process_helper(sm, &data->ssl, 1079*6d49e1aeSJan Lentfer EAP_TYPE_PEAP, 1080*6d49e1aeSJan Lentfer data->peap_version, id, pos, 1081*6d49e1aeSJan Lentfer left, &resp); 1082*6d49e1aeSJan Lentfer 1083*6d49e1aeSJan Lentfer if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { 1084*6d49e1aeSJan Lentfer char *label; 1085*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, 1086*6d49e1aeSJan Lentfer "EAP-PEAP: TLS done, proceed to Phase 2"); 1087*6d49e1aeSJan Lentfer os_free(data->key_data); 1088*6d49e1aeSJan Lentfer /* draft-josefsson-ppext-eap-tls-eap-05.txt 1089*6d49e1aeSJan Lentfer * specifies that PEAPv1 would use "client PEAP 1090*6d49e1aeSJan Lentfer * encryption" as the label. However, most existing 1091*6d49e1aeSJan Lentfer * PEAPv1 implementations seem to be using the old 1092*6d49e1aeSJan Lentfer * label, "client EAP encryption", instead. Use the old 1093*6d49e1aeSJan Lentfer * label by default, but allow it to be configured with 1094*6d49e1aeSJan Lentfer * phase1 parameter peaplabel=1. */ 1095*6d49e1aeSJan Lentfer if (data->peap_version > 1 || data->force_new_label) 1096*6d49e1aeSJan Lentfer label = "client PEAP encryption"; 1097*6d49e1aeSJan Lentfer else 1098*6d49e1aeSJan Lentfer label = "client EAP encryption"; 1099*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: using label '%s' in " 1100*6d49e1aeSJan Lentfer "key derivation", label); 1101*6d49e1aeSJan Lentfer data->key_data = 1102*6d49e1aeSJan Lentfer eap_peer_tls_derive_key(sm, &data->ssl, label, 1103*6d49e1aeSJan Lentfer EAP_TLS_KEY_LEN); 1104*6d49e1aeSJan Lentfer if (data->key_data) { 1105*6d49e1aeSJan Lentfer wpa_hexdump_key(MSG_DEBUG, 1106*6d49e1aeSJan Lentfer "EAP-PEAP: Derived key", 1107*6d49e1aeSJan Lentfer data->key_data, 1108*6d49e1aeSJan Lentfer EAP_TLS_KEY_LEN); 1109*6d49e1aeSJan Lentfer } else { 1110*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to " 1111*6d49e1aeSJan Lentfer "derive key"); 1112*6d49e1aeSJan Lentfer } 1113*6d49e1aeSJan Lentfer 1114*6d49e1aeSJan Lentfer if (sm->workaround && data->resuming) { 1115*6d49e1aeSJan Lentfer /* 1116*6d49e1aeSJan Lentfer * At least few RADIUS servers (Aegis v1.1.6; 1117*6d49e1aeSJan Lentfer * but not v1.1.4; and Cisco ACS) seem to be 1118*6d49e1aeSJan Lentfer * terminating PEAPv1 (Aegis) or PEAPv0 (Cisco 1119*6d49e1aeSJan Lentfer * ACS) session resumption with outer 1120*6d49e1aeSJan Lentfer * EAP-Success. This does not seem to follow 1121*6d49e1aeSJan Lentfer * draft-josefsson-pppext-eap-tls-eap-05.txt 1122*6d49e1aeSJan Lentfer * section 4.2, so only allow this if EAP 1123*6d49e1aeSJan Lentfer * workarounds are enabled. 1124*6d49e1aeSJan Lentfer */ 1125*6d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Workaround - " 1126*6d49e1aeSJan Lentfer "allow outer EAP-Success to " 1127*6d49e1aeSJan Lentfer "terminate PEAP resumption"); 1128*6d49e1aeSJan Lentfer ret->decision = DECISION_COND_SUCC; 1129*6d49e1aeSJan Lentfer data->phase2_success = 1; 1130*6d49e1aeSJan Lentfer } 1131*6d49e1aeSJan Lentfer 1132*6d49e1aeSJan Lentfer data->resuming = 0; 1133*6d49e1aeSJan Lentfer } 1134*6d49e1aeSJan Lentfer 1135*6d49e1aeSJan Lentfer if (res == 2) { 1136*6d49e1aeSJan Lentfer struct wpabuf msg; 1137*6d49e1aeSJan Lentfer /* 1138*6d49e1aeSJan Lentfer * Application data included in the handshake message. 1139*6d49e1aeSJan Lentfer */ 1140*6d49e1aeSJan Lentfer wpabuf_free(data->pending_phase2_req); 1141*6d49e1aeSJan Lentfer data->pending_phase2_req = resp; 1142*6d49e1aeSJan Lentfer resp = NULL; 1143*6d49e1aeSJan Lentfer wpabuf_set(&msg, pos, left); 1144*6d49e1aeSJan Lentfer res = eap_peap_decrypt(sm, data, ret, req, &msg, 1145*6d49e1aeSJan Lentfer &resp); 1146*6d49e1aeSJan Lentfer } 1147*6d49e1aeSJan Lentfer } 1148*6d49e1aeSJan Lentfer 1149*6d49e1aeSJan Lentfer if (ret->methodState == METHOD_DONE) { 1150*6d49e1aeSJan Lentfer ret->allowNotifications = FALSE; 1151*6d49e1aeSJan Lentfer } 1152*6d49e1aeSJan Lentfer 1153*6d49e1aeSJan Lentfer if (res == 1) { 1154*6d49e1aeSJan Lentfer wpabuf_free(resp); 1155*6d49e1aeSJan Lentfer return eap_peer_tls_build_ack(id, EAP_TYPE_PEAP, 1156*6d49e1aeSJan Lentfer data->peap_version); 1157*6d49e1aeSJan Lentfer } 1158*6d49e1aeSJan Lentfer 1159*6d49e1aeSJan Lentfer return resp; 1160*6d49e1aeSJan Lentfer } 1161*6d49e1aeSJan Lentfer 1162*6d49e1aeSJan Lentfer 1163*6d49e1aeSJan Lentfer static Boolean eap_peap_has_reauth_data(struct eap_sm *sm, void *priv) 1164*6d49e1aeSJan Lentfer { 1165*6d49e1aeSJan Lentfer struct eap_peap_data *data = priv; 1166*6d49e1aeSJan Lentfer return tls_connection_established(sm->ssl_ctx, data->ssl.conn) && 1167*6d49e1aeSJan Lentfer data->phase2_success; 1168*6d49e1aeSJan Lentfer } 1169*6d49e1aeSJan Lentfer 1170*6d49e1aeSJan Lentfer 1171*6d49e1aeSJan Lentfer static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv) 1172*6d49e1aeSJan Lentfer { 1173*6d49e1aeSJan Lentfer struct eap_peap_data *data = priv; 1174*6d49e1aeSJan Lentfer wpabuf_free(data->pending_phase2_req); 1175*6d49e1aeSJan Lentfer data->pending_phase2_req = NULL; 1176*6d49e1aeSJan Lentfer data->crypto_binding_used = 0; 1177*6d49e1aeSJan Lentfer } 1178*6d49e1aeSJan Lentfer 1179*6d49e1aeSJan Lentfer 1180*6d49e1aeSJan Lentfer static void * eap_peap_init_for_reauth(struct eap_sm *sm, void *priv) 1181*6d49e1aeSJan Lentfer { 1182*6d49e1aeSJan Lentfer struct eap_peap_data *data = priv; 1183*6d49e1aeSJan Lentfer os_free(data->key_data); 1184*6d49e1aeSJan Lentfer data->key_data = NULL; 1185*6d49e1aeSJan Lentfer if (eap_peer_tls_reauth_init(sm, &data->ssl)) { 1186*6d49e1aeSJan Lentfer os_free(data); 1187*6d49e1aeSJan Lentfer return NULL; 1188*6d49e1aeSJan Lentfer } 1189*6d49e1aeSJan Lentfer if (data->phase2_priv && data->phase2_method && 1190*6d49e1aeSJan Lentfer data->phase2_method->init_for_reauth) 1191*6d49e1aeSJan Lentfer data->phase2_method->init_for_reauth(sm, data->phase2_priv); 1192*6d49e1aeSJan Lentfer data->phase2_success = 0; 1193*6d49e1aeSJan Lentfer data->phase2_eap_success = 0; 1194*6d49e1aeSJan Lentfer data->phase2_eap_started = 0; 1195*6d49e1aeSJan Lentfer data->resuming = 1; 1196*6d49e1aeSJan Lentfer data->reauth = 1; 1197*6d49e1aeSJan Lentfer sm->peap_done = FALSE; 1198*6d49e1aeSJan Lentfer return priv; 1199*6d49e1aeSJan Lentfer } 1200*6d49e1aeSJan Lentfer 1201*6d49e1aeSJan Lentfer 1202*6d49e1aeSJan Lentfer static int eap_peap_get_status(struct eap_sm *sm, void *priv, char *buf, 1203*6d49e1aeSJan Lentfer size_t buflen, int verbose) 1204*6d49e1aeSJan Lentfer { 1205*6d49e1aeSJan Lentfer struct eap_peap_data *data = priv; 1206*6d49e1aeSJan Lentfer int len, ret; 1207*6d49e1aeSJan Lentfer 1208*6d49e1aeSJan Lentfer len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose); 1209*6d49e1aeSJan Lentfer if (data->phase2_method) { 1210*6d49e1aeSJan Lentfer ret = os_snprintf(buf + len, buflen - len, 1211*6d49e1aeSJan Lentfer "EAP-PEAPv%d Phase2 method=%s\n", 1212*6d49e1aeSJan Lentfer data->peap_version, 1213*6d49e1aeSJan Lentfer data->phase2_method->name); 1214*6d49e1aeSJan Lentfer if (ret < 0 || (size_t) ret >= buflen - len) 1215*6d49e1aeSJan Lentfer return len; 1216*6d49e1aeSJan Lentfer len += ret; 1217*6d49e1aeSJan Lentfer } 1218*6d49e1aeSJan Lentfer return len; 1219*6d49e1aeSJan Lentfer } 1220*6d49e1aeSJan Lentfer 1221*6d49e1aeSJan Lentfer 1222*6d49e1aeSJan Lentfer static Boolean eap_peap_isKeyAvailable(struct eap_sm *sm, void *priv) 1223*6d49e1aeSJan Lentfer { 1224*6d49e1aeSJan Lentfer struct eap_peap_data *data = priv; 1225*6d49e1aeSJan Lentfer return data->key_data != NULL && data->phase2_success; 1226*6d49e1aeSJan Lentfer } 1227*6d49e1aeSJan Lentfer 1228*6d49e1aeSJan Lentfer 1229*6d49e1aeSJan Lentfer static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len) 1230*6d49e1aeSJan Lentfer { 1231*6d49e1aeSJan Lentfer struct eap_peap_data *data = priv; 1232*6d49e1aeSJan Lentfer u8 *key; 1233*6d49e1aeSJan Lentfer 1234*6d49e1aeSJan Lentfer if (data->key_data == NULL || !data->phase2_success) 1235*6d49e1aeSJan Lentfer return NULL; 1236*6d49e1aeSJan Lentfer 1237*6d49e1aeSJan Lentfer key = os_malloc(EAP_TLS_KEY_LEN); 1238*6d49e1aeSJan Lentfer if (key == NULL) 1239*6d49e1aeSJan Lentfer return NULL; 1240*6d49e1aeSJan Lentfer 1241*6d49e1aeSJan Lentfer *len = EAP_TLS_KEY_LEN; 1242*6d49e1aeSJan Lentfer 1243*6d49e1aeSJan Lentfer if (data->crypto_binding_used) { 1244*6d49e1aeSJan Lentfer u8 csk[128]; 1245*6d49e1aeSJan Lentfer /* 1246*6d49e1aeSJan Lentfer * Note: It looks like Microsoft implementation requires null 1247*6d49e1aeSJan Lentfer * termination for this label while the one used for deriving 1248*6d49e1aeSJan Lentfer * IPMK|CMK did not use null termination. 1249*6d49e1aeSJan Lentfer */ 1250*6d49e1aeSJan Lentfer peap_prfplus(data->peap_version, data->ipmk, 40, 1251*6d49e1aeSJan Lentfer "Session Key Generating Function", 1252*6d49e1aeSJan Lentfer (u8 *) "\00", 1, csk, sizeof(csk)); 1253*6d49e1aeSJan Lentfer wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk)); 1254*6d49e1aeSJan Lentfer os_memcpy(key, csk, EAP_TLS_KEY_LEN); 1255*6d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key", 1256*6d49e1aeSJan Lentfer key, EAP_TLS_KEY_LEN); 1257*6d49e1aeSJan Lentfer } else 1258*6d49e1aeSJan Lentfer os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN); 1259*6d49e1aeSJan Lentfer 1260*6d49e1aeSJan Lentfer return key; 1261*6d49e1aeSJan Lentfer } 1262*6d49e1aeSJan Lentfer 1263*6d49e1aeSJan Lentfer 1264*6d49e1aeSJan Lentfer int eap_peer_peap_register(void) 1265*6d49e1aeSJan Lentfer { 1266*6d49e1aeSJan Lentfer struct eap_method *eap; 1267*6d49e1aeSJan Lentfer int ret; 1268*6d49e1aeSJan Lentfer 1269*6d49e1aeSJan Lentfer eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 1270*6d49e1aeSJan Lentfer EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP"); 1271*6d49e1aeSJan Lentfer if (eap == NULL) 1272*6d49e1aeSJan Lentfer return -1; 1273*6d49e1aeSJan Lentfer 1274*6d49e1aeSJan Lentfer eap->init = eap_peap_init; 1275*6d49e1aeSJan Lentfer eap->deinit = eap_peap_deinit; 1276*6d49e1aeSJan Lentfer eap->process = eap_peap_process; 1277*6d49e1aeSJan Lentfer eap->isKeyAvailable = eap_peap_isKeyAvailable; 1278*6d49e1aeSJan Lentfer eap->getKey = eap_peap_getKey; 1279*6d49e1aeSJan Lentfer eap->get_status = eap_peap_get_status; 1280*6d49e1aeSJan Lentfer eap->has_reauth_data = eap_peap_has_reauth_data; 1281*6d49e1aeSJan Lentfer eap->deinit_for_reauth = eap_peap_deinit_for_reauth; 1282*6d49e1aeSJan Lentfer eap->init_for_reauth = eap_peap_init_for_reauth; 1283*6d49e1aeSJan Lentfer 1284*6d49e1aeSJan Lentfer ret = eap_peer_method_register(eap); 1285*6d49e1aeSJan Lentfer if (ret) 1286*6d49e1aeSJan Lentfer eap_peer_method_free(eap); 1287*6d49e1aeSJan Lentfer return ret; 1288*6d49e1aeSJan Lentfer } 1289