16d49e1aeSJan Lentfer /*
26d49e1aeSJan Lentfer * EAP peer method: EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt)
3*a1157835SDaniel Fojt * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi>
46d49e1aeSJan Lentfer *
53ff40c12SJohn Marino * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino * See README for more details.
76d49e1aeSJan Lentfer */
86d49e1aeSJan Lentfer
96d49e1aeSJan Lentfer #include "includes.h"
106d49e1aeSJan Lentfer
116d49e1aeSJan Lentfer #include "common.h"
126d49e1aeSJan Lentfer #include "crypto/sha1.h"
133ff40c12SJohn Marino #include "crypto/tls.h"
143ff40c12SJohn Marino #include "eap_common/eap_tlv_common.h"
153ff40c12SJohn Marino #include "eap_common/eap_peap_common.h"
166d49e1aeSJan Lentfer #include "eap_i.h"
176d49e1aeSJan Lentfer #include "eap_tls_common.h"
186d49e1aeSJan Lentfer #include "eap_config.h"
196d49e1aeSJan Lentfer #include "tncc.h"
206d49e1aeSJan Lentfer
216d49e1aeSJan Lentfer
226d49e1aeSJan Lentfer /* Maximum supported PEAP version
236d49e1aeSJan Lentfer * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt
246d49e1aeSJan Lentfer * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt
256d49e1aeSJan Lentfer */
266d49e1aeSJan Lentfer #define EAP_PEAP_VERSION 1
276d49e1aeSJan Lentfer
286d49e1aeSJan Lentfer
296d49e1aeSJan Lentfer static void eap_peap_deinit(struct eap_sm *sm, void *priv);
306d49e1aeSJan Lentfer
316d49e1aeSJan Lentfer
326d49e1aeSJan Lentfer struct eap_peap_data {
336d49e1aeSJan Lentfer struct eap_ssl_data ssl;
346d49e1aeSJan Lentfer
356d49e1aeSJan Lentfer int peap_version, force_peap_version, force_new_label;
366d49e1aeSJan Lentfer
376d49e1aeSJan Lentfer const struct eap_method *phase2_method;
386d49e1aeSJan Lentfer void *phase2_priv;
396d49e1aeSJan Lentfer int phase2_success;
406d49e1aeSJan Lentfer int phase2_eap_success;
416d49e1aeSJan Lentfer int phase2_eap_started;
426d49e1aeSJan Lentfer
436d49e1aeSJan Lentfer struct eap_method_type phase2_type;
446d49e1aeSJan Lentfer struct eap_method_type *phase2_types;
456d49e1aeSJan Lentfer size_t num_phase2_types;
466d49e1aeSJan Lentfer
476d49e1aeSJan Lentfer int peap_outer_success; /* 0 = PEAP terminated on Phase 2 inner
486d49e1aeSJan Lentfer * EAP-Success
496d49e1aeSJan Lentfer * 1 = reply with tunneled EAP-Success to inner
506d49e1aeSJan Lentfer * EAP-Success and expect AS to send outer
516d49e1aeSJan Lentfer * (unencrypted) EAP-Success after this
526d49e1aeSJan Lentfer * 2 = reply with PEAP/TLS ACK to inner
536d49e1aeSJan Lentfer * EAP-Success and expect AS to send outer
546d49e1aeSJan Lentfer * (unencrypted) EAP-Success after this */
556d49e1aeSJan Lentfer int resuming; /* starting a resumed session */
566d49e1aeSJan Lentfer int reauth; /* reauthentication */
576d49e1aeSJan Lentfer u8 *key_data;
583ff40c12SJohn Marino u8 *session_id;
593ff40c12SJohn Marino size_t id_len;
606d49e1aeSJan Lentfer
616d49e1aeSJan Lentfer struct wpabuf *pending_phase2_req;
62*a1157835SDaniel Fojt struct wpabuf *pending_resp;
636d49e1aeSJan Lentfer enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
646d49e1aeSJan Lentfer int crypto_binding_used;
656d49e1aeSJan Lentfer u8 binding_nonce[32];
666d49e1aeSJan Lentfer u8 ipmk[40];
676d49e1aeSJan Lentfer u8 cmk[20];
686d49e1aeSJan Lentfer int soh; /* Whether IF-TNCCS-SOH (Statement of Health; Microsoft NAP)
696d49e1aeSJan Lentfer * is enabled. */
706d49e1aeSJan Lentfer };
716d49e1aeSJan Lentfer
726d49e1aeSJan Lentfer
eap_peap_parse_phase1(struct eap_peap_data * data,const char * phase1)73*a1157835SDaniel Fojt static void eap_peap_parse_phase1(struct eap_peap_data *data,
746d49e1aeSJan Lentfer const char *phase1)
756d49e1aeSJan Lentfer {
766d49e1aeSJan Lentfer const char *pos;
776d49e1aeSJan Lentfer
786d49e1aeSJan Lentfer pos = os_strstr(phase1, "peapver=");
796d49e1aeSJan Lentfer if (pos) {
806d49e1aeSJan Lentfer data->force_peap_version = atoi(pos + 8);
816d49e1aeSJan Lentfer data->peap_version = data->force_peap_version;
826d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Forced PEAP version %d",
836d49e1aeSJan Lentfer data->force_peap_version);
846d49e1aeSJan Lentfer }
856d49e1aeSJan Lentfer
866d49e1aeSJan Lentfer if (os_strstr(phase1, "peaplabel=1")) {
876d49e1aeSJan Lentfer data->force_new_label = 1;
886d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Force new label for key "
896d49e1aeSJan Lentfer "derivation");
906d49e1aeSJan Lentfer }
916d49e1aeSJan Lentfer
926d49e1aeSJan Lentfer if (os_strstr(phase1, "peap_outer_success=0")) {
936d49e1aeSJan Lentfer data->peap_outer_success = 0;
946d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: terminate authentication on "
956d49e1aeSJan Lentfer "tunneled EAP-Success");
966d49e1aeSJan Lentfer } else if (os_strstr(phase1, "peap_outer_success=1")) {
976d49e1aeSJan Lentfer data->peap_outer_success = 1;
986d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: send tunneled EAP-Success "
996d49e1aeSJan Lentfer "after receiving tunneled EAP-Success");
1006d49e1aeSJan Lentfer } else if (os_strstr(phase1, "peap_outer_success=2")) {
1016d49e1aeSJan Lentfer data->peap_outer_success = 2;
1026d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: send PEAP/TLS ACK after "
1036d49e1aeSJan Lentfer "receiving tunneled EAP-Success");
1046d49e1aeSJan Lentfer }
1056d49e1aeSJan Lentfer
1066d49e1aeSJan Lentfer if (os_strstr(phase1, "crypto_binding=0")) {
1076d49e1aeSJan Lentfer data->crypto_binding = NO_BINDING;
1086d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Do not use cryptobinding");
1096d49e1aeSJan Lentfer } else if (os_strstr(phase1, "crypto_binding=1")) {
1106d49e1aeSJan Lentfer data->crypto_binding = OPTIONAL_BINDING;
1116d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Optional cryptobinding");
1126d49e1aeSJan Lentfer } else if (os_strstr(phase1, "crypto_binding=2")) {
1136d49e1aeSJan Lentfer data->crypto_binding = REQUIRE_BINDING;
1146d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Require cryptobinding");
1156d49e1aeSJan Lentfer }
1166d49e1aeSJan Lentfer
1176d49e1aeSJan Lentfer #ifdef EAP_TNC
1186d49e1aeSJan Lentfer if (os_strstr(phase1, "tnc=soh2")) {
1196d49e1aeSJan Lentfer data->soh = 2;
1206d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled");
1216d49e1aeSJan Lentfer } else if (os_strstr(phase1, "tnc=soh1")) {
1226d49e1aeSJan Lentfer data->soh = 1;
1236d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 1 enabled");
1246d49e1aeSJan Lentfer } else if (os_strstr(phase1, "tnc=soh")) {
1256d49e1aeSJan Lentfer data->soh = 2;
1266d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled");
1276d49e1aeSJan Lentfer }
1286d49e1aeSJan Lentfer #endif /* EAP_TNC */
1296d49e1aeSJan Lentfer }
1306d49e1aeSJan Lentfer
1316d49e1aeSJan Lentfer
eap_peap_init(struct eap_sm * sm)1326d49e1aeSJan Lentfer static void * eap_peap_init(struct eap_sm *sm)
1336d49e1aeSJan Lentfer {
1346d49e1aeSJan Lentfer struct eap_peap_data *data;
1356d49e1aeSJan Lentfer struct eap_peer_config *config = eap_get_config(sm);
1366d49e1aeSJan Lentfer
1376d49e1aeSJan Lentfer data = os_zalloc(sizeof(*data));
1386d49e1aeSJan Lentfer if (data == NULL)
1396d49e1aeSJan Lentfer return NULL;
1406d49e1aeSJan Lentfer sm->peap_done = FALSE;
1416d49e1aeSJan Lentfer data->peap_version = EAP_PEAP_VERSION;
1426d49e1aeSJan Lentfer data->force_peap_version = -1;
1436d49e1aeSJan Lentfer data->peap_outer_success = 2;
1446d49e1aeSJan Lentfer data->crypto_binding = OPTIONAL_BINDING;
1456d49e1aeSJan Lentfer
146*a1157835SDaniel Fojt if (config && config->phase1)
147*a1157835SDaniel Fojt eap_peap_parse_phase1(data, config->phase1);
1486d49e1aeSJan Lentfer
1496d49e1aeSJan Lentfer if (eap_peer_select_phase2_methods(config, "auth=",
1506d49e1aeSJan Lentfer &data->phase2_types,
1516d49e1aeSJan Lentfer &data->num_phase2_types) < 0) {
1526d49e1aeSJan Lentfer eap_peap_deinit(sm, data);
1536d49e1aeSJan Lentfer return NULL;
1546d49e1aeSJan Lentfer }
1556d49e1aeSJan Lentfer
1566d49e1aeSJan Lentfer data->phase2_type.vendor = EAP_VENDOR_IETF;
1576d49e1aeSJan Lentfer data->phase2_type.method = EAP_TYPE_NONE;
1586d49e1aeSJan Lentfer
1593ff40c12SJohn Marino if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_PEAP)) {
1606d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL.");
1616d49e1aeSJan Lentfer eap_peap_deinit(sm, data);
1626d49e1aeSJan Lentfer return NULL;
1636d49e1aeSJan Lentfer }
1646d49e1aeSJan Lentfer
1656d49e1aeSJan Lentfer return data;
1666d49e1aeSJan Lentfer }
1676d49e1aeSJan Lentfer
1686d49e1aeSJan Lentfer
eap_peap_free_key(struct eap_peap_data * data)169*a1157835SDaniel Fojt static void eap_peap_free_key(struct eap_peap_data *data)
170*a1157835SDaniel Fojt {
171*a1157835SDaniel Fojt if (data->key_data) {
172*a1157835SDaniel Fojt bin_clear_free(data->key_data, EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
173*a1157835SDaniel Fojt data->key_data = NULL;
174*a1157835SDaniel Fojt }
175*a1157835SDaniel Fojt }
176*a1157835SDaniel Fojt
177*a1157835SDaniel Fojt
eap_peap_deinit(struct eap_sm * sm,void * priv)1786d49e1aeSJan Lentfer static void eap_peap_deinit(struct eap_sm *sm, void *priv)
1796d49e1aeSJan Lentfer {
1806d49e1aeSJan Lentfer struct eap_peap_data *data = priv;
1816d49e1aeSJan Lentfer if (data == NULL)
1826d49e1aeSJan Lentfer return;
1836d49e1aeSJan Lentfer if (data->phase2_priv && data->phase2_method)
1846d49e1aeSJan Lentfer data->phase2_method->deinit(sm, data->phase2_priv);
1856d49e1aeSJan Lentfer os_free(data->phase2_types);
1866d49e1aeSJan Lentfer eap_peer_tls_ssl_deinit(sm, &data->ssl);
187*a1157835SDaniel Fojt eap_peap_free_key(data);
1883ff40c12SJohn Marino os_free(data->session_id);
189*a1157835SDaniel Fojt wpabuf_clear_free(data->pending_phase2_req);
190*a1157835SDaniel Fojt wpabuf_clear_free(data->pending_resp);
191*a1157835SDaniel Fojt bin_clear_free(data, sizeof(*data));
1926d49e1aeSJan Lentfer }
1936d49e1aeSJan Lentfer
1946d49e1aeSJan Lentfer
1956d49e1aeSJan Lentfer /**
1966d49e1aeSJan Lentfer * eap_tlv_build_nak - Build EAP-TLV NAK message
1976d49e1aeSJan Lentfer * @id: EAP identifier for the header
1986d49e1aeSJan Lentfer * @nak_type: TLV type (EAP_TLV_*)
1996d49e1aeSJan Lentfer * Returns: Buffer to the allocated EAP-TLV NAK message or %NULL on failure
2006d49e1aeSJan Lentfer *
2013ff40c12SJohn Marino * This function builds an EAP-TLV NAK message. The caller is responsible for
2026d49e1aeSJan Lentfer * freeing the returned buffer.
2036d49e1aeSJan Lentfer */
eap_tlv_build_nak(int id,u16 nak_type)2046d49e1aeSJan Lentfer static struct wpabuf * eap_tlv_build_nak(int id, u16 nak_type)
2056d49e1aeSJan Lentfer {
2066d49e1aeSJan Lentfer struct wpabuf *msg;
2076d49e1aeSJan Lentfer
2086d49e1aeSJan Lentfer msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, 10,
2096d49e1aeSJan Lentfer EAP_CODE_RESPONSE, id);
2106d49e1aeSJan Lentfer if (msg == NULL)
2116d49e1aeSJan Lentfer return NULL;
2126d49e1aeSJan Lentfer
2136d49e1aeSJan Lentfer wpabuf_put_u8(msg, 0x80); /* Mandatory */
2146d49e1aeSJan Lentfer wpabuf_put_u8(msg, EAP_TLV_NAK_TLV);
2156d49e1aeSJan Lentfer wpabuf_put_be16(msg, 6); /* Length */
2166d49e1aeSJan Lentfer wpabuf_put_be32(msg, 0); /* Vendor-Id */
2176d49e1aeSJan Lentfer wpabuf_put_be16(msg, nak_type); /* NAK-Type */
2186d49e1aeSJan Lentfer
2196d49e1aeSJan Lentfer return msg;
2206d49e1aeSJan Lentfer }
2216d49e1aeSJan Lentfer
2226d49e1aeSJan Lentfer
eap_peap_get_isk(struct eap_sm * sm,struct eap_peap_data * data,u8 * isk,size_t isk_len)2236d49e1aeSJan Lentfer static int eap_peap_get_isk(struct eap_sm *sm, struct eap_peap_data *data,
2246d49e1aeSJan Lentfer u8 *isk, size_t isk_len)
2256d49e1aeSJan Lentfer {
2266d49e1aeSJan Lentfer u8 *key;
2276d49e1aeSJan Lentfer size_t key_len;
2286d49e1aeSJan Lentfer
2296d49e1aeSJan Lentfer os_memset(isk, 0, isk_len);
2306d49e1aeSJan Lentfer if (data->phase2_method == NULL || data->phase2_priv == NULL ||
2316d49e1aeSJan Lentfer data->phase2_method->isKeyAvailable == NULL ||
2326d49e1aeSJan Lentfer data->phase2_method->getKey == NULL)
2336d49e1aeSJan Lentfer return 0;
2346d49e1aeSJan Lentfer
2356d49e1aeSJan Lentfer if (!data->phase2_method->isKeyAvailable(sm, data->phase2_priv) ||
2366d49e1aeSJan Lentfer (key = data->phase2_method->getKey(sm, data->phase2_priv,
2376d49e1aeSJan Lentfer &key_len)) == NULL) {
2386d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not get key material "
2396d49e1aeSJan Lentfer "from Phase 2");
2406d49e1aeSJan Lentfer return -1;
2416d49e1aeSJan Lentfer }
2426d49e1aeSJan Lentfer
2436d49e1aeSJan Lentfer if (key_len > isk_len)
2446d49e1aeSJan Lentfer key_len = isk_len;
2456d49e1aeSJan Lentfer os_memcpy(isk, key, key_len);
2466d49e1aeSJan Lentfer os_free(key);
2476d49e1aeSJan Lentfer
2486d49e1aeSJan Lentfer return 0;
2496d49e1aeSJan Lentfer }
2506d49e1aeSJan Lentfer
2516d49e1aeSJan Lentfer
eap_peap_derive_cmk(struct eap_sm * sm,struct eap_peap_data * data)2526d49e1aeSJan Lentfer static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
2536d49e1aeSJan Lentfer {
2546d49e1aeSJan Lentfer u8 *tk;
2556d49e1aeSJan Lentfer u8 isk[32], imck[60];
256*a1157835SDaniel Fojt int resumed, res;
2576d49e1aeSJan Lentfer
2586d49e1aeSJan Lentfer /*
2596d49e1aeSJan Lentfer * Tunnel key (TK) is the first 60 octets of the key generated by
2606d49e1aeSJan Lentfer * phase 1 of PEAP (based on TLS).
2616d49e1aeSJan Lentfer */
2626d49e1aeSJan Lentfer tk = data->key_data;
2636d49e1aeSJan Lentfer if (tk == NULL)
2646d49e1aeSJan Lentfer return -1;
2656d49e1aeSJan Lentfer wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
2666d49e1aeSJan Lentfer
267*a1157835SDaniel Fojt resumed = tls_connection_resumed(sm->ssl_ctx, data->ssl.conn);
268*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
269*a1157835SDaniel Fojt "EAP-PEAP: CMK derivation - reauth=%d resumed=%d phase2_eap_started=%d phase2_success=%d",
270*a1157835SDaniel Fojt data->reauth, resumed, data->phase2_eap_started,
271*a1157835SDaniel Fojt data->phase2_success);
272*a1157835SDaniel Fojt if (data->reauth && !data->phase2_eap_started && resumed) {
2736d49e1aeSJan Lentfer /* Fast-connect: IPMK|CMK = TK */
2746d49e1aeSJan Lentfer os_memcpy(data->ipmk, tk, 40);
2756d49e1aeSJan Lentfer wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK from TK",
2766d49e1aeSJan Lentfer data->ipmk, 40);
2776d49e1aeSJan Lentfer os_memcpy(data->cmk, tk + 40, 20);
2786d49e1aeSJan Lentfer wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK from TK",
2796d49e1aeSJan Lentfer data->cmk, 20);
2806d49e1aeSJan Lentfer return 0;
2816d49e1aeSJan Lentfer }
2826d49e1aeSJan Lentfer
2836d49e1aeSJan Lentfer if (eap_peap_get_isk(sm, data, isk, sizeof(isk)) < 0)
2846d49e1aeSJan Lentfer return -1;
2856d49e1aeSJan Lentfer wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk));
2866d49e1aeSJan Lentfer
2876d49e1aeSJan Lentfer /*
2886d49e1aeSJan Lentfer * IPMK Seed = "Inner Methods Compound Keys" | ISK
2896d49e1aeSJan Lentfer * TempKey = First 40 octets of TK
2906d49e1aeSJan Lentfer * IPMK|CMK = PRF+(TempKey, IPMK Seed, 60)
2916d49e1aeSJan Lentfer * (note: draft-josefsson-pppext-eap-tls-eap-10.txt includes a space
2926d49e1aeSJan Lentfer * in the end of the label just before ISK; is that just a typo?)
2936d49e1aeSJan Lentfer */
2946d49e1aeSJan Lentfer wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
295*a1157835SDaniel Fojt res = peap_prfplus(data->peap_version, tk, 40,
2963ff40c12SJohn Marino "Inner Methods Compound Keys",
297*a1157835SDaniel Fojt isk, sizeof(isk), imck, sizeof(imck));
298*a1157835SDaniel Fojt forced_memzero(isk, sizeof(isk));
299*a1157835SDaniel Fojt if (res < 0)
3003ff40c12SJohn Marino return -1;
3016d49e1aeSJan Lentfer wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
3026d49e1aeSJan Lentfer imck, sizeof(imck));
3036d49e1aeSJan Lentfer
3046d49e1aeSJan Lentfer os_memcpy(data->ipmk, imck, 40);
3056d49e1aeSJan Lentfer wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40);
3066d49e1aeSJan Lentfer os_memcpy(data->cmk, imck + 40, 20);
3076d49e1aeSJan Lentfer wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20);
308*a1157835SDaniel Fojt forced_memzero(imck, sizeof(imck));
3096d49e1aeSJan Lentfer
3106d49e1aeSJan Lentfer return 0;
3116d49e1aeSJan Lentfer }
3126d49e1aeSJan Lentfer
3136d49e1aeSJan Lentfer
eap_tlv_add_cryptobinding(struct eap_sm * sm,struct eap_peap_data * data,struct wpabuf * buf)3146d49e1aeSJan Lentfer static int eap_tlv_add_cryptobinding(struct eap_sm *sm,
3156d49e1aeSJan Lentfer struct eap_peap_data *data,
3166d49e1aeSJan Lentfer struct wpabuf *buf)
3176d49e1aeSJan Lentfer {
3186d49e1aeSJan Lentfer u8 *mac;
3196d49e1aeSJan Lentfer u8 eap_type = EAP_TYPE_PEAP;
3206d49e1aeSJan Lentfer const u8 *addr[2];
3216d49e1aeSJan Lentfer size_t len[2];
3226d49e1aeSJan Lentfer u16 tlv_type;
3236d49e1aeSJan Lentfer
3246d49e1aeSJan Lentfer /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
3256d49e1aeSJan Lentfer addr[0] = wpabuf_put(buf, 0);
3266d49e1aeSJan Lentfer len[0] = 60;
3276d49e1aeSJan Lentfer addr[1] = &eap_type;
3286d49e1aeSJan Lentfer len[1] = 1;
3296d49e1aeSJan Lentfer
3306d49e1aeSJan Lentfer tlv_type = EAP_TLV_CRYPTO_BINDING_TLV;
3316d49e1aeSJan Lentfer wpabuf_put_be16(buf, tlv_type);
3326d49e1aeSJan Lentfer wpabuf_put_be16(buf, 56);
3336d49e1aeSJan Lentfer
3346d49e1aeSJan Lentfer wpabuf_put_u8(buf, 0); /* Reserved */
3356d49e1aeSJan Lentfer wpabuf_put_u8(buf, data->peap_version); /* Version */
3366d49e1aeSJan Lentfer wpabuf_put_u8(buf, data->peap_version); /* RecvVersion */
3376d49e1aeSJan Lentfer wpabuf_put_u8(buf, 1); /* SubType: 0 = Request, 1 = Response */
3386d49e1aeSJan Lentfer wpabuf_put_data(buf, data->binding_nonce, 32); /* Nonce */
3396d49e1aeSJan Lentfer mac = wpabuf_put(buf, 20); /* Compound_MAC */
3406d49e1aeSJan Lentfer wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK", data->cmk, 20);
3416d49e1aeSJan Lentfer wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1",
3426d49e1aeSJan Lentfer addr[0], len[0]);
3436d49e1aeSJan Lentfer wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2",
3446d49e1aeSJan Lentfer addr[1], len[1]);
345*a1157835SDaniel Fojt if (hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac) < 0)
346*a1157835SDaniel Fojt return -1;
3476d49e1aeSJan Lentfer wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC", mac, SHA1_MAC_LEN);
3486d49e1aeSJan Lentfer data->crypto_binding_used = 1;
3496d49e1aeSJan Lentfer
3506d49e1aeSJan Lentfer return 0;
3516d49e1aeSJan Lentfer }
3526d49e1aeSJan Lentfer
3536d49e1aeSJan Lentfer
3546d49e1aeSJan Lentfer /**
3556d49e1aeSJan Lentfer * eap_tlv_build_result - Build EAP-TLV Result message
3566d49e1aeSJan Lentfer * @id: EAP identifier for the header
3576d49e1aeSJan Lentfer * @status: Status (EAP_TLV_RESULT_SUCCESS or EAP_TLV_RESULT_FAILURE)
3586d49e1aeSJan Lentfer * Returns: Buffer to the allocated EAP-TLV Result message or %NULL on failure
3596d49e1aeSJan Lentfer *
3603ff40c12SJohn Marino * This function builds an EAP-TLV Result message. The caller is responsible
3613ff40c12SJohn Marino * for freeing the returned buffer.
3626d49e1aeSJan Lentfer */
eap_tlv_build_result(struct eap_sm * sm,struct eap_peap_data * data,int crypto_tlv_used,int id,u16 status)3636d49e1aeSJan Lentfer static struct wpabuf * eap_tlv_build_result(struct eap_sm *sm,
3646d49e1aeSJan Lentfer struct eap_peap_data *data,
3656d49e1aeSJan Lentfer int crypto_tlv_used,
3666d49e1aeSJan Lentfer int id, u16 status)
3676d49e1aeSJan Lentfer {
3686d49e1aeSJan Lentfer struct wpabuf *msg;
3696d49e1aeSJan Lentfer size_t len;
3706d49e1aeSJan Lentfer
3716d49e1aeSJan Lentfer if (data->crypto_binding == NO_BINDING)
3726d49e1aeSJan Lentfer crypto_tlv_used = 0;
3736d49e1aeSJan Lentfer
3746d49e1aeSJan Lentfer len = 6;
3756d49e1aeSJan Lentfer if (crypto_tlv_used)
3766d49e1aeSJan Lentfer len += 60; /* Cryptobinding TLV */
3776d49e1aeSJan Lentfer msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, len,
3786d49e1aeSJan Lentfer EAP_CODE_RESPONSE, id);
3796d49e1aeSJan Lentfer if (msg == NULL)
3806d49e1aeSJan Lentfer return NULL;
3816d49e1aeSJan Lentfer
3826d49e1aeSJan Lentfer wpabuf_put_u8(msg, 0x80); /* Mandatory */
3836d49e1aeSJan Lentfer wpabuf_put_u8(msg, EAP_TLV_RESULT_TLV);
3846d49e1aeSJan Lentfer wpabuf_put_be16(msg, 2); /* Length */
3856d49e1aeSJan Lentfer wpabuf_put_be16(msg, status); /* Status */
3866d49e1aeSJan Lentfer
3876d49e1aeSJan Lentfer if (crypto_tlv_used && eap_tlv_add_cryptobinding(sm, data, msg)) {
388*a1157835SDaniel Fojt wpabuf_clear_free(msg);
3896d49e1aeSJan Lentfer return NULL;
3906d49e1aeSJan Lentfer }
3916d49e1aeSJan Lentfer
3926d49e1aeSJan Lentfer return msg;
3936d49e1aeSJan Lentfer }
3946d49e1aeSJan Lentfer
3956d49e1aeSJan Lentfer
eap_tlv_validate_cryptobinding(struct eap_sm * sm,struct eap_peap_data * data,const u8 * crypto_tlv,size_t crypto_tlv_len)3966d49e1aeSJan Lentfer static int eap_tlv_validate_cryptobinding(struct eap_sm *sm,
3976d49e1aeSJan Lentfer struct eap_peap_data *data,
3986d49e1aeSJan Lentfer const u8 *crypto_tlv,
3996d49e1aeSJan Lentfer size_t crypto_tlv_len)
4006d49e1aeSJan Lentfer {
4016d49e1aeSJan Lentfer u8 buf[61], mac[SHA1_MAC_LEN];
4026d49e1aeSJan Lentfer const u8 *pos;
4036d49e1aeSJan Lentfer
4046d49e1aeSJan Lentfer if (eap_peap_derive_cmk(sm, data) < 0) {
4056d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not derive CMK");
4066d49e1aeSJan Lentfer return -1;
4076d49e1aeSJan Lentfer }
4086d49e1aeSJan Lentfer
4096d49e1aeSJan Lentfer if (crypto_tlv_len != 4 + 56) {
4106d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid cryptobinding TLV "
4116d49e1aeSJan Lentfer "length %d", (int) crypto_tlv_len);
4126d49e1aeSJan Lentfer return -1;
4136d49e1aeSJan Lentfer }
4146d49e1aeSJan Lentfer
4156d49e1aeSJan Lentfer pos = crypto_tlv;
4166d49e1aeSJan Lentfer pos += 4; /* TLV header */
4176d49e1aeSJan Lentfer if (pos[1] != data->peap_version) {
4186d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV Version "
4196d49e1aeSJan Lentfer "mismatch (was %d; expected %d)",
4206d49e1aeSJan Lentfer pos[1], data->peap_version);
4216d49e1aeSJan Lentfer return -1;
4226d49e1aeSJan Lentfer }
4236d49e1aeSJan Lentfer
4246d49e1aeSJan Lentfer if (pos[3] != 0) {
4256d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected Cryptobinding TLV "
4266d49e1aeSJan Lentfer "SubType %d", pos[3]);
4276d49e1aeSJan Lentfer return -1;
4286d49e1aeSJan Lentfer }
4296d49e1aeSJan Lentfer pos += 4;
4306d49e1aeSJan Lentfer os_memcpy(data->binding_nonce, pos, 32);
4316d49e1aeSJan Lentfer pos += 32; /* Nonce */
4326d49e1aeSJan Lentfer
4336d49e1aeSJan Lentfer /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
4346d49e1aeSJan Lentfer os_memcpy(buf, crypto_tlv, 60);
4356d49e1aeSJan Lentfer os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */
4366d49e1aeSJan Lentfer buf[60] = EAP_TYPE_PEAP;
4376d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Compound_MAC data",
4386d49e1aeSJan Lentfer buf, sizeof(buf));
4396d49e1aeSJan Lentfer hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac);
4406d49e1aeSJan Lentfer
441*a1157835SDaniel Fojt if (os_memcmp_const(mac, pos, SHA1_MAC_LEN) != 0) {
4426d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in "
4436d49e1aeSJan Lentfer "cryptobinding TLV");
4446d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received MAC",
4456d49e1aeSJan Lentfer pos, SHA1_MAC_LEN);
4466d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Expected MAC",
4476d49e1aeSJan Lentfer mac, SHA1_MAC_LEN);
4486d49e1aeSJan Lentfer return -1;
4496d49e1aeSJan Lentfer }
4506d49e1aeSJan Lentfer
4516d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received");
4526d49e1aeSJan Lentfer
4536d49e1aeSJan Lentfer return 0;
4546d49e1aeSJan Lentfer }
4556d49e1aeSJan Lentfer
4566d49e1aeSJan Lentfer
4576d49e1aeSJan Lentfer /**
4586d49e1aeSJan Lentfer * eap_tlv_process - Process a received EAP-TLV message and generate a response
4596d49e1aeSJan Lentfer * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
4606d49e1aeSJan Lentfer * @ret: Return values from EAP request validation and processing
4616d49e1aeSJan Lentfer * @req: EAP-TLV request to be processed. The caller must have validated that
4626d49e1aeSJan Lentfer * the buffer is large enough to contain full request (hdr->length bytes) and
4636d49e1aeSJan Lentfer * that the EAP type is EAP_TYPE_TLV.
4646d49e1aeSJan Lentfer * @resp: Buffer to return a pointer to the allocated response message. This
4656d49e1aeSJan Lentfer * field should be initialized to %NULL before the call. The value will be
4666d49e1aeSJan Lentfer * updated if a response message is generated. The caller is responsible for
4676d49e1aeSJan Lentfer * freeing the allocated message.
4686d49e1aeSJan Lentfer * @force_failure: Force negotiation to fail
4696d49e1aeSJan Lentfer * Returns: 0 on success, -1 on failure
4706d49e1aeSJan Lentfer */
eap_tlv_process(struct eap_sm * sm,struct eap_peap_data * data,struct eap_method_ret * ret,const struct wpabuf * req,struct wpabuf ** resp,int force_failure)4716d49e1aeSJan Lentfer static int eap_tlv_process(struct eap_sm *sm, struct eap_peap_data *data,
4726d49e1aeSJan Lentfer struct eap_method_ret *ret,
4736d49e1aeSJan Lentfer const struct wpabuf *req, struct wpabuf **resp,
4746d49e1aeSJan Lentfer int force_failure)
4756d49e1aeSJan Lentfer {
4766d49e1aeSJan Lentfer size_t left, tlv_len;
4776d49e1aeSJan Lentfer const u8 *pos;
4786d49e1aeSJan Lentfer const u8 *result_tlv = NULL, *crypto_tlv = NULL;
4796d49e1aeSJan Lentfer size_t result_tlv_len = 0, crypto_tlv_len = 0;
4806d49e1aeSJan Lentfer int tlv_type, mandatory;
4816d49e1aeSJan Lentfer
4826d49e1aeSJan Lentfer /* Parse TLVs */
4836d49e1aeSJan Lentfer pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, req, &left);
4846d49e1aeSJan Lentfer if (pos == NULL)
4856d49e1aeSJan Lentfer return -1;
4866d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-TLV: Received TLVs", pos, left);
4876d49e1aeSJan Lentfer while (left >= 4) {
4886d49e1aeSJan Lentfer mandatory = !!(pos[0] & 0x80);
4896d49e1aeSJan Lentfer tlv_type = WPA_GET_BE16(pos) & 0x3fff;
4906d49e1aeSJan Lentfer pos += 2;
4916d49e1aeSJan Lentfer tlv_len = WPA_GET_BE16(pos);
4926d49e1aeSJan Lentfer pos += 2;
4936d49e1aeSJan Lentfer left -= 4;
4946d49e1aeSJan Lentfer if (tlv_len > left) {
4956d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-TLV: TLV underrun "
4966d49e1aeSJan Lentfer "(tlv_len=%lu left=%lu)",
4976d49e1aeSJan Lentfer (unsigned long) tlv_len,
4986d49e1aeSJan Lentfer (unsigned long) left);
4996d49e1aeSJan Lentfer return -1;
5006d49e1aeSJan Lentfer }
5016d49e1aeSJan Lentfer switch (tlv_type) {
5026d49e1aeSJan Lentfer case EAP_TLV_RESULT_TLV:
5036d49e1aeSJan Lentfer result_tlv = pos;
5046d49e1aeSJan Lentfer result_tlv_len = tlv_len;
5056d49e1aeSJan Lentfer break;
5066d49e1aeSJan Lentfer case EAP_TLV_CRYPTO_BINDING_TLV:
5076d49e1aeSJan Lentfer crypto_tlv = pos;
5086d49e1aeSJan Lentfer crypto_tlv_len = tlv_len;
5096d49e1aeSJan Lentfer break;
5106d49e1aeSJan Lentfer default:
5116d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-TLV: Unsupported TLV Type "
5126d49e1aeSJan Lentfer "%d%s", tlv_type,
5136d49e1aeSJan Lentfer mandatory ? " (mandatory)" : "");
5146d49e1aeSJan Lentfer if (mandatory) {
5156d49e1aeSJan Lentfer /* NAK TLV and ignore all TLVs in this packet.
5166d49e1aeSJan Lentfer */
5176d49e1aeSJan Lentfer *resp = eap_tlv_build_nak(eap_get_id(req),
5186d49e1aeSJan Lentfer tlv_type);
5196d49e1aeSJan Lentfer return *resp == NULL ? -1 : 0;
5206d49e1aeSJan Lentfer }
5216d49e1aeSJan Lentfer /* Ignore this TLV, but process other TLVs */
5226d49e1aeSJan Lentfer break;
5236d49e1aeSJan Lentfer }
5246d49e1aeSJan Lentfer
5256d49e1aeSJan Lentfer pos += tlv_len;
5266d49e1aeSJan Lentfer left -= tlv_len;
5276d49e1aeSJan Lentfer }
5286d49e1aeSJan Lentfer if (left) {
5296d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-TLV: Last TLV too short in "
5306d49e1aeSJan Lentfer "Request (left=%lu)", (unsigned long) left);
5316d49e1aeSJan Lentfer return -1;
5326d49e1aeSJan Lentfer }
5336d49e1aeSJan Lentfer
5346d49e1aeSJan Lentfer /* Process supported TLVs */
5356d49e1aeSJan Lentfer if (crypto_tlv && data->crypto_binding != NO_BINDING) {
5366d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV",
5376d49e1aeSJan Lentfer crypto_tlv, crypto_tlv_len);
5386d49e1aeSJan Lentfer if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4,
5396d49e1aeSJan Lentfer crypto_tlv_len + 4) < 0) {
5406d49e1aeSJan Lentfer if (result_tlv == NULL)
5416d49e1aeSJan Lentfer return -1;
5426d49e1aeSJan Lentfer force_failure = 1;
5436d49e1aeSJan Lentfer crypto_tlv = NULL; /* do not include Cryptobinding TLV
5446d49e1aeSJan Lentfer * in response, if the received
5456d49e1aeSJan Lentfer * cryptobinding was invalid. */
5466d49e1aeSJan Lentfer }
5476d49e1aeSJan Lentfer } else if (!crypto_tlv && data->crypto_binding == REQUIRE_BINDING) {
5486d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV");
5496d49e1aeSJan Lentfer return -1;
5506d49e1aeSJan Lentfer }
5516d49e1aeSJan Lentfer
5526d49e1aeSJan Lentfer if (result_tlv) {
5536d49e1aeSJan Lentfer int status, resp_status;
5546d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-TLV: Result TLV",
5556d49e1aeSJan Lentfer result_tlv, result_tlv_len);
5566d49e1aeSJan Lentfer if (result_tlv_len < 2) {
5576d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-TLV: Too short Result TLV "
5586d49e1aeSJan Lentfer "(len=%lu)",
5596d49e1aeSJan Lentfer (unsigned long) result_tlv_len);
5606d49e1aeSJan Lentfer return -1;
5616d49e1aeSJan Lentfer }
5626d49e1aeSJan Lentfer status = WPA_GET_BE16(result_tlv);
5636d49e1aeSJan Lentfer if (status == EAP_TLV_RESULT_SUCCESS) {
5646d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Success "
5656d49e1aeSJan Lentfer "- EAP-TLV/Phase2 Completed");
5666d49e1aeSJan Lentfer if (force_failure) {
5676d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-TLV: Earlier failure"
5686d49e1aeSJan Lentfer " - force failed Phase 2");
5696d49e1aeSJan Lentfer resp_status = EAP_TLV_RESULT_FAILURE;
5706d49e1aeSJan Lentfer ret->decision = DECISION_FAIL;
5716d49e1aeSJan Lentfer } else {
5726d49e1aeSJan Lentfer resp_status = EAP_TLV_RESULT_SUCCESS;
5736d49e1aeSJan Lentfer ret->decision = DECISION_UNCOND_SUCC;
5746d49e1aeSJan Lentfer }
5756d49e1aeSJan Lentfer } else if (status == EAP_TLV_RESULT_FAILURE) {
5766d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Failure");
5776d49e1aeSJan Lentfer resp_status = EAP_TLV_RESULT_FAILURE;
5786d49e1aeSJan Lentfer ret->decision = DECISION_FAIL;
5796d49e1aeSJan Lentfer } else {
5806d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-TLV: Unknown TLV Result "
5816d49e1aeSJan Lentfer "Status %d", status);
5826d49e1aeSJan Lentfer resp_status = EAP_TLV_RESULT_FAILURE;
5836d49e1aeSJan Lentfer ret->decision = DECISION_FAIL;
5846d49e1aeSJan Lentfer }
5856d49e1aeSJan Lentfer ret->methodState = METHOD_DONE;
5866d49e1aeSJan Lentfer
5876d49e1aeSJan Lentfer *resp = eap_tlv_build_result(sm, data, crypto_tlv != NULL,
5886d49e1aeSJan Lentfer eap_get_id(req), resp_status);
5896d49e1aeSJan Lentfer }
5906d49e1aeSJan Lentfer
5916d49e1aeSJan Lentfer return 0;
5926d49e1aeSJan Lentfer }
5936d49e1aeSJan Lentfer
5946d49e1aeSJan Lentfer
eap_peap_phase2_request(struct eap_sm * sm,struct eap_peap_data * data,struct eap_method_ret * ret,struct wpabuf * req,struct wpabuf ** resp)5956d49e1aeSJan Lentfer static int eap_peap_phase2_request(struct eap_sm *sm,
5966d49e1aeSJan Lentfer struct eap_peap_data *data,
5976d49e1aeSJan Lentfer struct eap_method_ret *ret,
5986d49e1aeSJan Lentfer struct wpabuf *req,
5996d49e1aeSJan Lentfer struct wpabuf **resp)
6006d49e1aeSJan Lentfer {
6016d49e1aeSJan Lentfer struct eap_hdr *hdr = wpabuf_mhead(req);
6026d49e1aeSJan Lentfer size_t len = be_to_host16(hdr->length);
6036d49e1aeSJan Lentfer u8 *pos;
6046d49e1aeSJan Lentfer struct eap_method_ret iret;
6056d49e1aeSJan Lentfer struct eap_peer_config *config = eap_get_config(sm);
6066d49e1aeSJan Lentfer
6076d49e1aeSJan Lentfer if (len <= sizeof(struct eap_hdr)) {
6086d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-PEAP: too short "
6096d49e1aeSJan Lentfer "Phase 2 request (len=%lu)", (unsigned long) len);
6106d49e1aeSJan Lentfer return -1;
6116d49e1aeSJan Lentfer }
6126d49e1aeSJan Lentfer pos = (u8 *) (hdr + 1);
6136d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Request: type=%d", *pos);
6146d49e1aeSJan Lentfer switch (*pos) {
6156d49e1aeSJan Lentfer case EAP_TYPE_IDENTITY:
6166d49e1aeSJan Lentfer *resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
6176d49e1aeSJan Lentfer break;
6186d49e1aeSJan Lentfer case EAP_TYPE_TLV:
6196d49e1aeSJan Lentfer os_memset(&iret, 0, sizeof(iret));
6206d49e1aeSJan Lentfer if (eap_tlv_process(sm, data, &iret, req, resp,
6216d49e1aeSJan Lentfer data->phase2_eap_started &&
6226d49e1aeSJan Lentfer !data->phase2_eap_success)) {
6236d49e1aeSJan Lentfer ret->methodState = METHOD_DONE;
6246d49e1aeSJan Lentfer ret->decision = DECISION_FAIL;
6256d49e1aeSJan Lentfer return -1;
6266d49e1aeSJan Lentfer }
6276d49e1aeSJan Lentfer if (iret.methodState == METHOD_DONE ||
6286d49e1aeSJan Lentfer iret.methodState == METHOD_MAY_CONT) {
6296d49e1aeSJan Lentfer ret->methodState = iret.methodState;
6306d49e1aeSJan Lentfer ret->decision = iret.decision;
6316d49e1aeSJan Lentfer data->phase2_success = 1;
6326d49e1aeSJan Lentfer }
6336d49e1aeSJan Lentfer break;
6346d49e1aeSJan Lentfer case EAP_TYPE_EXPANDED:
6356d49e1aeSJan Lentfer #ifdef EAP_TNC
6366d49e1aeSJan Lentfer if (data->soh) {
6376d49e1aeSJan Lentfer const u8 *epos;
6386d49e1aeSJan Lentfer size_t eleft;
6396d49e1aeSJan Lentfer
6406d49e1aeSJan Lentfer epos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21,
6416d49e1aeSJan Lentfer req, &eleft);
6426d49e1aeSJan Lentfer if (epos) {
6436d49e1aeSJan Lentfer struct wpabuf *buf;
6446d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG,
6456d49e1aeSJan Lentfer "EAP-PEAP: SoH EAP Extensions");
6466d49e1aeSJan Lentfer buf = tncc_process_soh_request(data->soh,
6476d49e1aeSJan Lentfer epos, eleft);
6486d49e1aeSJan Lentfer if (buf) {
6496d49e1aeSJan Lentfer *resp = eap_msg_alloc(
6506d49e1aeSJan Lentfer EAP_VENDOR_MICROSOFT, 0x21,
6516d49e1aeSJan Lentfer wpabuf_len(buf),
6526d49e1aeSJan Lentfer EAP_CODE_RESPONSE,
6536d49e1aeSJan Lentfer hdr->identifier);
6546d49e1aeSJan Lentfer if (*resp == NULL) {
6556d49e1aeSJan Lentfer ret->methodState = METHOD_DONE;
6566d49e1aeSJan Lentfer ret->decision = DECISION_FAIL;
657*a1157835SDaniel Fojt wpabuf_clear_free(buf);
6586d49e1aeSJan Lentfer return -1;
6596d49e1aeSJan Lentfer }
6606d49e1aeSJan Lentfer wpabuf_put_buf(*resp, buf);
661*a1157835SDaniel Fojt wpabuf_clear_free(buf);
6626d49e1aeSJan Lentfer break;
6636d49e1aeSJan Lentfer }
6646d49e1aeSJan Lentfer }
6656d49e1aeSJan Lentfer }
6666d49e1aeSJan Lentfer #endif /* EAP_TNC */
6676d49e1aeSJan Lentfer /* fall through */
6686d49e1aeSJan Lentfer default:
6696d49e1aeSJan Lentfer if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
6706d49e1aeSJan Lentfer data->phase2_type.method == EAP_TYPE_NONE) {
6716d49e1aeSJan Lentfer size_t i;
6726d49e1aeSJan Lentfer for (i = 0; i < data->num_phase2_types; i++) {
6736d49e1aeSJan Lentfer if (data->phase2_types[i].vendor !=
6746d49e1aeSJan Lentfer EAP_VENDOR_IETF ||
6756d49e1aeSJan Lentfer data->phase2_types[i].method != *pos)
6766d49e1aeSJan Lentfer continue;
6776d49e1aeSJan Lentfer
6786d49e1aeSJan Lentfer data->phase2_type.vendor =
6796d49e1aeSJan Lentfer data->phase2_types[i].vendor;
6806d49e1aeSJan Lentfer data->phase2_type.method =
6816d49e1aeSJan Lentfer data->phase2_types[i].method;
6826d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Selected "
6836d49e1aeSJan Lentfer "Phase 2 EAP vendor %d method %d",
6846d49e1aeSJan Lentfer data->phase2_type.vendor,
6856d49e1aeSJan Lentfer data->phase2_type.method);
6866d49e1aeSJan Lentfer break;
6876d49e1aeSJan Lentfer }
6886d49e1aeSJan Lentfer }
6896d49e1aeSJan Lentfer if (*pos != data->phase2_type.method ||
6906d49e1aeSJan Lentfer *pos == EAP_TYPE_NONE) {
6916d49e1aeSJan Lentfer if (eap_peer_tls_phase2_nak(data->phase2_types,
6926d49e1aeSJan Lentfer data->num_phase2_types,
6936d49e1aeSJan Lentfer hdr, resp))
6946d49e1aeSJan Lentfer return -1;
6956d49e1aeSJan Lentfer return 0;
6966d49e1aeSJan Lentfer }
6976d49e1aeSJan Lentfer
6986d49e1aeSJan Lentfer if (data->phase2_priv == NULL) {
6996d49e1aeSJan Lentfer data->phase2_method = eap_peer_get_eap_method(
7006d49e1aeSJan Lentfer data->phase2_type.vendor,
7016d49e1aeSJan Lentfer data->phase2_type.method);
7026d49e1aeSJan Lentfer if (data->phase2_method) {
7036d49e1aeSJan Lentfer sm->init_phase2 = 1;
7046d49e1aeSJan Lentfer data->phase2_priv =
7056d49e1aeSJan Lentfer data->phase2_method->init(sm);
7066d49e1aeSJan Lentfer sm->init_phase2 = 0;
7076d49e1aeSJan Lentfer }
7086d49e1aeSJan Lentfer }
7096d49e1aeSJan Lentfer if (data->phase2_priv == NULL || data->phase2_method == NULL) {
7106d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-PEAP: failed to initialize "
7116d49e1aeSJan Lentfer "Phase 2 EAP method %d", *pos);
7126d49e1aeSJan Lentfer ret->methodState = METHOD_DONE;
7136d49e1aeSJan Lentfer ret->decision = DECISION_FAIL;
7146d49e1aeSJan Lentfer return -1;
7156d49e1aeSJan Lentfer }
7166d49e1aeSJan Lentfer data->phase2_eap_started = 1;
7176d49e1aeSJan Lentfer os_memset(&iret, 0, sizeof(iret));
7186d49e1aeSJan Lentfer *resp = data->phase2_method->process(sm, data->phase2_priv,
7196d49e1aeSJan Lentfer &iret, req);
7206d49e1aeSJan Lentfer if ((iret.methodState == METHOD_DONE ||
7216d49e1aeSJan Lentfer iret.methodState == METHOD_MAY_CONT) &&
7226d49e1aeSJan Lentfer (iret.decision == DECISION_UNCOND_SUCC ||
7236d49e1aeSJan Lentfer iret.decision == DECISION_COND_SUCC)) {
7246d49e1aeSJan Lentfer data->phase2_eap_success = 1;
7256d49e1aeSJan Lentfer data->phase2_success = 1;
7266d49e1aeSJan Lentfer }
7276d49e1aeSJan Lentfer break;
7286d49e1aeSJan Lentfer }
7296d49e1aeSJan Lentfer
7306d49e1aeSJan Lentfer if (*resp == NULL &&
7316d49e1aeSJan Lentfer (config->pending_req_identity || config->pending_req_password ||
732*a1157835SDaniel Fojt config->pending_req_otp || config->pending_req_new_password ||
733*a1157835SDaniel Fojt config->pending_req_sim)) {
734*a1157835SDaniel Fojt wpabuf_clear_free(data->pending_phase2_req);
7356d49e1aeSJan Lentfer data->pending_phase2_req = wpabuf_alloc_copy(hdr, len);
7366d49e1aeSJan Lentfer }
7376d49e1aeSJan Lentfer
7386d49e1aeSJan Lentfer return 0;
7396d49e1aeSJan Lentfer }
7406d49e1aeSJan Lentfer
7416d49e1aeSJan Lentfer
eap_peap_decrypt(struct eap_sm * sm,struct eap_peap_data * data,struct eap_method_ret * ret,const struct eap_hdr * req,const struct wpabuf * in_data,struct wpabuf ** out_data)7426d49e1aeSJan Lentfer static int eap_peap_decrypt(struct eap_sm *sm, struct eap_peap_data *data,
7436d49e1aeSJan Lentfer struct eap_method_ret *ret,
7446d49e1aeSJan Lentfer const struct eap_hdr *req,
7456d49e1aeSJan Lentfer const struct wpabuf *in_data,
7466d49e1aeSJan Lentfer struct wpabuf **out_data)
7476d49e1aeSJan Lentfer {
7486d49e1aeSJan Lentfer struct wpabuf *in_decrypted = NULL;
7496d49e1aeSJan Lentfer int res, skip_change = 0;
7506d49e1aeSJan Lentfer struct eap_hdr *hdr, *rhdr;
7516d49e1aeSJan Lentfer struct wpabuf *resp = NULL;
7526d49e1aeSJan Lentfer size_t len;
7536d49e1aeSJan Lentfer
7546d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
7556d49e1aeSJan Lentfer " Phase 2", (unsigned long) wpabuf_len(in_data));
7566d49e1aeSJan Lentfer
7576d49e1aeSJan Lentfer if (data->pending_phase2_req) {
7586d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 request - "
7596d49e1aeSJan Lentfer "skip decryption and use old data");
7606d49e1aeSJan Lentfer /* Clear TLS reassembly state. */
7616d49e1aeSJan Lentfer eap_peer_tls_reset_input(&data->ssl);
7626d49e1aeSJan Lentfer in_decrypted = data->pending_phase2_req;
7636d49e1aeSJan Lentfer data->pending_phase2_req = NULL;
7646d49e1aeSJan Lentfer skip_change = 1;
7656d49e1aeSJan Lentfer goto continue_req;
7666d49e1aeSJan Lentfer }
7676d49e1aeSJan Lentfer
7686d49e1aeSJan Lentfer if (wpabuf_len(in_data) == 0 && sm->workaround &&
7696d49e1aeSJan Lentfer data->phase2_success) {
7706d49e1aeSJan Lentfer /*
7716d49e1aeSJan Lentfer * Cisco ACS seems to be using TLS ACK to terminate
7726d49e1aeSJan Lentfer * EAP-PEAPv0/GTC. Try to reply with TLS ACK.
7736d49e1aeSJan Lentfer */
7746d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Received TLS ACK, but "
7756d49e1aeSJan Lentfer "expected data - acknowledge with TLS ACK since "
7766d49e1aeSJan Lentfer "Phase 2 has been completed");
7776d49e1aeSJan Lentfer ret->decision = DECISION_COND_SUCC;
7786d49e1aeSJan Lentfer ret->methodState = METHOD_DONE;
7796d49e1aeSJan Lentfer return 1;
7806d49e1aeSJan Lentfer } else if (wpabuf_len(in_data) == 0) {
7816d49e1aeSJan Lentfer /* Received TLS ACK - requesting more fragments */
7826d49e1aeSJan Lentfer return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP,
7836d49e1aeSJan Lentfer data->peap_version,
7846d49e1aeSJan Lentfer req->identifier, NULL, out_data);
7856d49e1aeSJan Lentfer }
7866d49e1aeSJan Lentfer
7876d49e1aeSJan Lentfer res = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted);
7886d49e1aeSJan Lentfer if (res)
7896d49e1aeSJan Lentfer return res;
7906d49e1aeSJan Lentfer
7916d49e1aeSJan Lentfer continue_req:
7926d49e1aeSJan Lentfer wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP",
7936d49e1aeSJan Lentfer in_decrypted);
7946d49e1aeSJan Lentfer
7956d49e1aeSJan Lentfer hdr = wpabuf_mhead(in_decrypted);
7966d49e1aeSJan Lentfer if (wpabuf_len(in_decrypted) == 5 && hdr->code == EAP_CODE_REQUEST &&
7976d49e1aeSJan Lentfer be_to_host16(hdr->length) == 5 &&
7986d49e1aeSJan Lentfer eap_get_type(in_decrypted) == EAP_TYPE_IDENTITY) {
7996d49e1aeSJan Lentfer /* At least FreeRADIUS seems to send full EAP header with
8006d49e1aeSJan Lentfer * EAP Request Identity */
8016d49e1aeSJan Lentfer skip_change = 1;
8026d49e1aeSJan Lentfer }
8036d49e1aeSJan Lentfer if (wpabuf_len(in_decrypted) >= 5 && hdr->code == EAP_CODE_REQUEST &&
8046d49e1aeSJan Lentfer eap_get_type(in_decrypted) == EAP_TYPE_TLV) {
8056d49e1aeSJan Lentfer skip_change = 1;
8066d49e1aeSJan Lentfer }
8076d49e1aeSJan Lentfer
8086d49e1aeSJan Lentfer if (data->peap_version == 0 && !skip_change) {
8096d49e1aeSJan Lentfer struct eap_hdr *nhdr;
8106d49e1aeSJan Lentfer struct wpabuf *nmsg = wpabuf_alloc(sizeof(struct eap_hdr) +
8116d49e1aeSJan Lentfer wpabuf_len(in_decrypted));
8126d49e1aeSJan Lentfer if (nmsg == NULL) {
813*a1157835SDaniel Fojt wpabuf_clear_free(in_decrypted);
8146d49e1aeSJan Lentfer return 0;
8156d49e1aeSJan Lentfer }
8166d49e1aeSJan Lentfer nhdr = wpabuf_put(nmsg, sizeof(*nhdr));
8176d49e1aeSJan Lentfer wpabuf_put_buf(nmsg, in_decrypted);
8186d49e1aeSJan Lentfer nhdr->code = req->code;
8196d49e1aeSJan Lentfer nhdr->identifier = req->identifier;
8206d49e1aeSJan Lentfer nhdr->length = host_to_be16(sizeof(struct eap_hdr) +
8216d49e1aeSJan Lentfer wpabuf_len(in_decrypted));
8226d49e1aeSJan Lentfer
823*a1157835SDaniel Fojt wpabuf_clear_free(in_decrypted);
8246d49e1aeSJan Lentfer in_decrypted = nmsg;
8256d49e1aeSJan Lentfer }
8266d49e1aeSJan Lentfer
8276d49e1aeSJan Lentfer hdr = wpabuf_mhead(in_decrypted);
8286d49e1aeSJan Lentfer if (wpabuf_len(in_decrypted) < sizeof(*hdr)) {
8296d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 "
8306d49e1aeSJan Lentfer "EAP frame (len=%lu)",
8316d49e1aeSJan Lentfer (unsigned long) wpabuf_len(in_decrypted));
832*a1157835SDaniel Fojt wpabuf_clear_free(in_decrypted);
8336d49e1aeSJan Lentfer return 0;
8346d49e1aeSJan Lentfer }
8356d49e1aeSJan Lentfer len = be_to_host16(hdr->length);
8366d49e1aeSJan Lentfer if (len > wpabuf_len(in_decrypted)) {
8376d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in "
8386d49e1aeSJan Lentfer "Phase 2 EAP frame (len=%lu hdr->length=%lu)",
8396d49e1aeSJan Lentfer (unsigned long) wpabuf_len(in_decrypted),
8406d49e1aeSJan Lentfer (unsigned long) len);
841*a1157835SDaniel Fojt wpabuf_clear_free(in_decrypted);
8426d49e1aeSJan Lentfer return 0;
8436d49e1aeSJan Lentfer }
8446d49e1aeSJan Lentfer if (len < wpabuf_len(in_decrypted)) {
8456d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-PEAP: Odd.. Phase 2 EAP header has "
8466d49e1aeSJan Lentfer "shorter length than full decrypted data "
8476d49e1aeSJan Lentfer "(%lu < %lu)",
8486d49e1aeSJan Lentfer (unsigned long) len,
8496d49e1aeSJan Lentfer (unsigned long) wpabuf_len(in_decrypted));
8506d49e1aeSJan Lentfer }
8516d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d "
8526d49e1aeSJan Lentfer "identifier=%d length=%lu", hdr->code, hdr->identifier,
8536d49e1aeSJan Lentfer (unsigned long) len);
8546d49e1aeSJan Lentfer switch (hdr->code) {
8556d49e1aeSJan Lentfer case EAP_CODE_REQUEST:
8566d49e1aeSJan Lentfer if (eap_peap_phase2_request(sm, data, ret, in_decrypted,
8576d49e1aeSJan Lentfer &resp)) {
858*a1157835SDaniel Fojt wpabuf_clear_free(in_decrypted);
8596d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-PEAP: Phase2 Request "
8606d49e1aeSJan Lentfer "processing failed");
8616d49e1aeSJan Lentfer return 0;
8626d49e1aeSJan Lentfer }
8636d49e1aeSJan Lentfer break;
8646d49e1aeSJan Lentfer case EAP_CODE_SUCCESS:
8656d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success");
8666d49e1aeSJan Lentfer if (data->peap_version == 1) {
8676d49e1aeSJan Lentfer /* EAP-Success within TLS tunnel is used to indicate
8686d49e1aeSJan Lentfer * shutdown of the TLS channel. The authentication has
8696d49e1aeSJan Lentfer * been completed. */
8706d49e1aeSJan Lentfer if (data->phase2_eap_started &&
8716d49e1aeSJan Lentfer !data->phase2_eap_success) {
8726d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 "
8736d49e1aeSJan Lentfer "Success used to indicate success, "
8746d49e1aeSJan Lentfer "but Phase 2 EAP was not yet "
8756d49e1aeSJan Lentfer "completed successfully");
8766d49e1aeSJan Lentfer ret->methodState = METHOD_DONE;
8776d49e1aeSJan Lentfer ret->decision = DECISION_FAIL;
878*a1157835SDaniel Fojt wpabuf_clear_free(in_decrypted);
8796d49e1aeSJan Lentfer return 0;
8806d49e1aeSJan Lentfer }
8816d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Version 1 - "
8826d49e1aeSJan Lentfer "EAP-Success within TLS tunnel - "
8836d49e1aeSJan Lentfer "authentication completed");
8846d49e1aeSJan Lentfer ret->decision = DECISION_UNCOND_SUCC;
8856d49e1aeSJan Lentfer ret->methodState = METHOD_DONE;
8866d49e1aeSJan Lentfer data->phase2_success = 1;
8876d49e1aeSJan Lentfer if (data->peap_outer_success == 2) {
888*a1157835SDaniel Fojt wpabuf_clear_free(in_decrypted);
8896d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Use TLS ACK "
8906d49e1aeSJan Lentfer "to finish authentication");
8916d49e1aeSJan Lentfer return 1;
8926d49e1aeSJan Lentfer } else if (data->peap_outer_success == 1) {
8936d49e1aeSJan Lentfer /* Reply with EAP-Success within the TLS
8946d49e1aeSJan Lentfer * channel to complete the authentication. */
8956d49e1aeSJan Lentfer resp = wpabuf_alloc(sizeof(struct eap_hdr));
8966d49e1aeSJan Lentfer if (resp) {
8976d49e1aeSJan Lentfer rhdr = wpabuf_put(resp, sizeof(*rhdr));
8986d49e1aeSJan Lentfer rhdr->code = EAP_CODE_SUCCESS;
8996d49e1aeSJan Lentfer rhdr->identifier = hdr->identifier;
9006d49e1aeSJan Lentfer rhdr->length =
9016d49e1aeSJan Lentfer host_to_be16(sizeof(*rhdr));
9026d49e1aeSJan Lentfer }
9036d49e1aeSJan Lentfer } else {
9046d49e1aeSJan Lentfer /* No EAP-Success expected for Phase 1 (outer,
9056d49e1aeSJan Lentfer * unencrypted auth), so force EAP state
9066d49e1aeSJan Lentfer * machine to SUCCESS state. */
9076d49e1aeSJan Lentfer sm->peap_done = TRUE;
9086d49e1aeSJan Lentfer }
9096d49e1aeSJan Lentfer } else {
9106d49e1aeSJan Lentfer /* FIX: ? */
9116d49e1aeSJan Lentfer }
9126d49e1aeSJan Lentfer break;
9136d49e1aeSJan Lentfer case EAP_CODE_FAILURE:
9146d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure");
9156d49e1aeSJan Lentfer ret->decision = DECISION_FAIL;
9166d49e1aeSJan Lentfer ret->methodState = METHOD_MAY_CONT;
9176d49e1aeSJan Lentfer ret->allowNotifications = FALSE;
9186d49e1aeSJan Lentfer /* Reply with EAP-Failure within the TLS channel to complete
9196d49e1aeSJan Lentfer * failure reporting. */
9206d49e1aeSJan Lentfer resp = wpabuf_alloc(sizeof(struct eap_hdr));
9216d49e1aeSJan Lentfer if (resp) {
9226d49e1aeSJan Lentfer rhdr = wpabuf_put(resp, sizeof(*rhdr));
9236d49e1aeSJan Lentfer rhdr->code = EAP_CODE_FAILURE;
9246d49e1aeSJan Lentfer rhdr->identifier = hdr->identifier;
9256d49e1aeSJan Lentfer rhdr->length = host_to_be16(sizeof(*rhdr));
9266d49e1aeSJan Lentfer }
9276d49e1aeSJan Lentfer break;
9286d49e1aeSJan Lentfer default:
9296d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in "
9306d49e1aeSJan Lentfer "Phase 2 EAP header", hdr->code);
9316d49e1aeSJan Lentfer break;
9326d49e1aeSJan Lentfer }
9336d49e1aeSJan Lentfer
934*a1157835SDaniel Fojt wpabuf_clear_free(in_decrypted);
9356d49e1aeSJan Lentfer
9366d49e1aeSJan Lentfer if (resp) {
9376d49e1aeSJan Lentfer int skip_change2 = 0;
9386d49e1aeSJan Lentfer struct wpabuf *rmsg, buf;
9396d49e1aeSJan Lentfer
9406d49e1aeSJan Lentfer wpa_hexdump_buf_key(MSG_DEBUG,
9416d49e1aeSJan Lentfer "EAP-PEAP: Encrypting Phase 2 data", resp);
9426d49e1aeSJan Lentfer /* PEAP version changes */
9436d49e1aeSJan Lentfer if (wpabuf_len(resp) >= 5 &&
9446d49e1aeSJan Lentfer wpabuf_head_u8(resp)[0] == EAP_CODE_RESPONSE &&
9456d49e1aeSJan Lentfer eap_get_type(resp) == EAP_TYPE_TLV)
9466d49e1aeSJan Lentfer skip_change2 = 1;
9476d49e1aeSJan Lentfer rmsg = resp;
9486d49e1aeSJan Lentfer if (data->peap_version == 0 && !skip_change2) {
9496d49e1aeSJan Lentfer wpabuf_set(&buf, wpabuf_head_u8(resp) +
9506d49e1aeSJan Lentfer sizeof(struct eap_hdr),
9516d49e1aeSJan Lentfer wpabuf_len(resp) - sizeof(struct eap_hdr));
9526d49e1aeSJan Lentfer rmsg = &buf;
9536d49e1aeSJan Lentfer }
9546d49e1aeSJan Lentfer
9556d49e1aeSJan Lentfer if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP,
9566d49e1aeSJan Lentfer data->peap_version, req->identifier,
9576d49e1aeSJan Lentfer rmsg, out_data)) {
9586d49e1aeSJan Lentfer wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt "
9596d49e1aeSJan Lentfer "a Phase 2 frame");
9606d49e1aeSJan Lentfer }
961*a1157835SDaniel Fojt wpabuf_clear_free(resp);
9626d49e1aeSJan Lentfer }
9636d49e1aeSJan Lentfer
9646d49e1aeSJan Lentfer return 0;
9656d49e1aeSJan Lentfer }
9666d49e1aeSJan Lentfer
9676d49e1aeSJan Lentfer
eap_peap_process(struct eap_sm * sm,void * priv,struct eap_method_ret * ret,const struct wpabuf * reqData)9686d49e1aeSJan Lentfer static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
9696d49e1aeSJan Lentfer struct eap_method_ret *ret,
9706d49e1aeSJan Lentfer const struct wpabuf *reqData)
9716d49e1aeSJan Lentfer {
9726d49e1aeSJan Lentfer const struct eap_hdr *req;
9736d49e1aeSJan Lentfer size_t left;
9746d49e1aeSJan Lentfer int res;
9756d49e1aeSJan Lentfer u8 flags, id;
9766d49e1aeSJan Lentfer struct wpabuf *resp;
9776d49e1aeSJan Lentfer const u8 *pos;
9786d49e1aeSJan Lentfer struct eap_peap_data *data = priv;
979*a1157835SDaniel Fojt struct wpabuf msg;
9806d49e1aeSJan Lentfer
9816d49e1aeSJan Lentfer pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_PEAP, ret,
9826d49e1aeSJan Lentfer reqData, &left, &flags);
9836d49e1aeSJan Lentfer if (pos == NULL)
9846d49e1aeSJan Lentfer return NULL;
9856d49e1aeSJan Lentfer req = wpabuf_head(reqData);
9866d49e1aeSJan Lentfer id = req->identifier;
9876d49e1aeSJan Lentfer
9886d49e1aeSJan Lentfer if (flags & EAP_TLS_FLAGS_START) {
9896d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Start (server ver=%d, own "
9903ff40c12SJohn Marino "ver=%d)", flags & EAP_TLS_VERSION_MASK,
9916d49e1aeSJan Lentfer data->peap_version);
9923ff40c12SJohn Marino if ((flags & EAP_TLS_VERSION_MASK) < data->peap_version)
9933ff40c12SJohn Marino data->peap_version = flags & EAP_TLS_VERSION_MASK;
9946d49e1aeSJan Lentfer if (data->force_peap_version >= 0 &&
9956d49e1aeSJan Lentfer data->force_peap_version != data->peap_version) {
9966d49e1aeSJan Lentfer wpa_printf(MSG_WARNING, "EAP-PEAP: Failed to select "
9976d49e1aeSJan Lentfer "forced PEAP version %d",
9986d49e1aeSJan Lentfer data->force_peap_version);
9996d49e1aeSJan Lentfer ret->methodState = METHOD_DONE;
10006d49e1aeSJan Lentfer ret->decision = DECISION_FAIL;
10016d49e1aeSJan Lentfer ret->allowNotifications = FALSE;
10026d49e1aeSJan Lentfer return NULL;
10036d49e1aeSJan Lentfer }
10046d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Using PEAP version %d",
10056d49e1aeSJan Lentfer data->peap_version);
10066d49e1aeSJan Lentfer left = 0; /* make sure that this frame is empty, even though it
10076d49e1aeSJan Lentfer * should always be, anyway */
10086d49e1aeSJan Lentfer }
10096d49e1aeSJan Lentfer
1010*a1157835SDaniel Fojt wpabuf_set(&msg, pos, left);
1011*a1157835SDaniel Fojt
10126d49e1aeSJan Lentfer resp = NULL;
10136d49e1aeSJan Lentfer if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
10146d49e1aeSJan Lentfer !data->resuming) {
10156d49e1aeSJan Lentfer res = eap_peap_decrypt(sm, data, ret, req, &msg, &resp);
10166d49e1aeSJan Lentfer } else {
1017*a1157835SDaniel Fojt if (sm->waiting_ext_cert_check && data->pending_resp) {
1018*a1157835SDaniel Fojt struct eap_peer_config *config = eap_get_config(sm);
1019*a1157835SDaniel Fojt
1020*a1157835SDaniel Fojt if (config->pending_ext_cert_check ==
1021*a1157835SDaniel Fojt EXT_CERT_CHECK_GOOD) {
1022*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
1023*a1157835SDaniel Fojt "EAP-PEAP: External certificate check succeeded - continue handshake");
1024*a1157835SDaniel Fojt resp = data->pending_resp;
1025*a1157835SDaniel Fojt data->pending_resp = NULL;
1026*a1157835SDaniel Fojt sm->waiting_ext_cert_check = 0;
1027*a1157835SDaniel Fojt return resp;
1028*a1157835SDaniel Fojt }
1029*a1157835SDaniel Fojt
1030*a1157835SDaniel Fojt if (config->pending_ext_cert_check ==
1031*a1157835SDaniel Fojt EXT_CERT_CHECK_BAD) {
1032*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
1033*a1157835SDaniel Fojt "EAP-PEAP: External certificate check failed - force authentication failure");
1034*a1157835SDaniel Fojt ret->methodState = METHOD_DONE;
1035*a1157835SDaniel Fojt ret->decision = DECISION_FAIL;
1036*a1157835SDaniel Fojt sm->waiting_ext_cert_check = 0;
1037*a1157835SDaniel Fojt return NULL;
1038*a1157835SDaniel Fojt }
1039*a1157835SDaniel Fojt
1040*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
1041*a1157835SDaniel Fojt "EAP-PEAP: Continuing to wait external server certificate validation");
1042*a1157835SDaniel Fojt return NULL;
1043*a1157835SDaniel Fojt }
1044*a1157835SDaniel Fojt
10456d49e1aeSJan Lentfer res = eap_peer_tls_process_helper(sm, &data->ssl,
10466d49e1aeSJan Lentfer EAP_TYPE_PEAP,
1047*a1157835SDaniel Fojt data->peap_version, id, &msg,
1048*a1157835SDaniel Fojt &resp);
1049*a1157835SDaniel Fojt
1050*a1157835SDaniel Fojt if (res < 0) {
1051*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
1052*a1157835SDaniel Fojt "EAP-PEAP: TLS processing failed");
1053*a1157835SDaniel Fojt ret->methodState = METHOD_DONE;
1054*a1157835SDaniel Fojt ret->decision = DECISION_FAIL;
1055*a1157835SDaniel Fojt return resp;
1056*a1157835SDaniel Fojt }
1057*a1157835SDaniel Fojt
1058*a1157835SDaniel Fojt
1059*a1157835SDaniel Fojt if (sm->waiting_ext_cert_check) {
1060*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG,
1061*a1157835SDaniel Fojt "EAP-PEAP: Waiting external server certificate validation");
1062*a1157835SDaniel Fojt wpabuf_clear_free(data->pending_resp);
1063*a1157835SDaniel Fojt data->pending_resp = resp;
1064*a1157835SDaniel Fojt return NULL;
1065*a1157835SDaniel Fojt }
10666d49e1aeSJan Lentfer
10676d49e1aeSJan Lentfer if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
10686d49e1aeSJan Lentfer char *label;
10696d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG,
10706d49e1aeSJan Lentfer "EAP-PEAP: TLS done, proceed to Phase 2");
1071*a1157835SDaniel Fojt eap_peap_free_key(data);
10726d49e1aeSJan Lentfer /* draft-josefsson-ppext-eap-tls-eap-05.txt
10736d49e1aeSJan Lentfer * specifies that PEAPv1 would use "client PEAP
10746d49e1aeSJan Lentfer * encryption" as the label. However, most existing
10756d49e1aeSJan Lentfer * PEAPv1 implementations seem to be using the old
10766d49e1aeSJan Lentfer * label, "client EAP encryption", instead. Use the old
10776d49e1aeSJan Lentfer * label by default, but allow it to be configured with
10786d49e1aeSJan Lentfer * phase1 parameter peaplabel=1. */
10793ff40c12SJohn Marino if (data->force_new_label)
10806d49e1aeSJan Lentfer label = "client PEAP encryption";
10816d49e1aeSJan Lentfer else
10826d49e1aeSJan Lentfer label = "client EAP encryption";
10836d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: using label '%s' in "
10846d49e1aeSJan Lentfer "key derivation", label);
10856d49e1aeSJan Lentfer data->key_data =
10866d49e1aeSJan Lentfer eap_peer_tls_derive_key(sm, &data->ssl, label,
1087*a1157835SDaniel Fojt NULL, 0,
1088*a1157835SDaniel Fojt EAP_TLS_KEY_LEN +
1089*a1157835SDaniel Fojt EAP_EMSK_LEN);
10906d49e1aeSJan Lentfer if (data->key_data) {
10916d49e1aeSJan Lentfer wpa_hexdump_key(MSG_DEBUG,
10926d49e1aeSJan Lentfer "EAP-PEAP: Derived key",
10936d49e1aeSJan Lentfer data->key_data,
10946d49e1aeSJan Lentfer EAP_TLS_KEY_LEN);
1095*a1157835SDaniel Fojt wpa_hexdump_key(MSG_DEBUG,
1096*a1157835SDaniel Fojt "EAP-PEAP: Derived EMSK",
1097*a1157835SDaniel Fojt data->key_data +
1098*a1157835SDaniel Fojt EAP_TLS_KEY_LEN,
1099*a1157835SDaniel Fojt EAP_EMSK_LEN);
11006d49e1aeSJan Lentfer } else {
11016d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to "
11026d49e1aeSJan Lentfer "derive key");
11036d49e1aeSJan Lentfer }
11046d49e1aeSJan Lentfer
11053ff40c12SJohn Marino os_free(data->session_id);
11063ff40c12SJohn Marino data->session_id =
11073ff40c12SJohn Marino eap_peer_tls_derive_session_id(sm, &data->ssl,
11083ff40c12SJohn Marino EAP_TYPE_PEAP,
11093ff40c12SJohn Marino &data->id_len);
11103ff40c12SJohn Marino if (data->session_id) {
11113ff40c12SJohn Marino wpa_hexdump(MSG_DEBUG,
11123ff40c12SJohn Marino "EAP-PEAP: Derived Session-Id",
11133ff40c12SJohn Marino data->session_id, data->id_len);
11143ff40c12SJohn Marino } else {
11153ff40c12SJohn Marino wpa_printf(MSG_ERROR, "EAP-PEAP: Failed to "
11163ff40c12SJohn Marino "derive Session-Id");
11173ff40c12SJohn Marino }
11183ff40c12SJohn Marino
11196d49e1aeSJan Lentfer if (sm->workaround && data->resuming) {
11206d49e1aeSJan Lentfer /*
11216d49e1aeSJan Lentfer * At least few RADIUS servers (Aegis v1.1.6;
11226d49e1aeSJan Lentfer * but not v1.1.4; and Cisco ACS) seem to be
11236d49e1aeSJan Lentfer * terminating PEAPv1 (Aegis) or PEAPv0 (Cisco
11246d49e1aeSJan Lentfer * ACS) session resumption with outer
11256d49e1aeSJan Lentfer * EAP-Success. This does not seem to follow
11266d49e1aeSJan Lentfer * draft-josefsson-pppext-eap-tls-eap-05.txt
11276d49e1aeSJan Lentfer * section 4.2, so only allow this if EAP
11286d49e1aeSJan Lentfer * workarounds are enabled.
11296d49e1aeSJan Lentfer */
11306d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "EAP-PEAP: Workaround - "
11316d49e1aeSJan Lentfer "allow outer EAP-Success to "
11326d49e1aeSJan Lentfer "terminate PEAP resumption");
11336d49e1aeSJan Lentfer ret->decision = DECISION_COND_SUCC;
11346d49e1aeSJan Lentfer data->phase2_success = 1;
11356d49e1aeSJan Lentfer }
11366d49e1aeSJan Lentfer
11376d49e1aeSJan Lentfer data->resuming = 0;
11386d49e1aeSJan Lentfer }
11396d49e1aeSJan Lentfer
11406d49e1aeSJan Lentfer if (res == 2) {
11416d49e1aeSJan Lentfer /*
11426d49e1aeSJan Lentfer * Application data included in the handshake message.
11436d49e1aeSJan Lentfer */
1144*a1157835SDaniel Fojt wpabuf_clear_free(data->pending_phase2_req);
11456d49e1aeSJan Lentfer data->pending_phase2_req = resp;
11466d49e1aeSJan Lentfer resp = NULL;
11476d49e1aeSJan Lentfer res = eap_peap_decrypt(sm, data, ret, req, &msg,
11486d49e1aeSJan Lentfer &resp);
11496d49e1aeSJan Lentfer }
11506d49e1aeSJan Lentfer }
11516d49e1aeSJan Lentfer
11526d49e1aeSJan Lentfer if (ret->methodState == METHOD_DONE) {
11536d49e1aeSJan Lentfer ret->allowNotifications = FALSE;
11546d49e1aeSJan Lentfer }
11556d49e1aeSJan Lentfer
11566d49e1aeSJan Lentfer if (res == 1) {
1157*a1157835SDaniel Fojt wpabuf_clear_free(resp);
11586d49e1aeSJan Lentfer return eap_peer_tls_build_ack(id, EAP_TYPE_PEAP,
11596d49e1aeSJan Lentfer data->peap_version);
11606d49e1aeSJan Lentfer }
11616d49e1aeSJan Lentfer
11626d49e1aeSJan Lentfer return resp;
11636d49e1aeSJan Lentfer }
11646d49e1aeSJan Lentfer
11656d49e1aeSJan Lentfer
eap_peap_has_reauth_data(struct eap_sm * sm,void * priv)11666d49e1aeSJan Lentfer static Boolean eap_peap_has_reauth_data(struct eap_sm *sm, void *priv)
11676d49e1aeSJan Lentfer {
11686d49e1aeSJan Lentfer struct eap_peap_data *data = priv;
11696d49e1aeSJan Lentfer return tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
11706d49e1aeSJan Lentfer data->phase2_success;
11716d49e1aeSJan Lentfer }
11726d49e1aeSJan Lentfer
11736d49e1aeSJan Lentfer
eap_peap_deinit_for_reauth(struct eap_sm * sm,void * priv)11746d49e1aeSJan Lentfer static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv)
11756d49e1aeSJan Lentfer {
11766d49e1aeSJan Lentfer struct eap_peap_data *data = priv;
1177*a1157835SDaniel Fojt
1178*a1157835SDaniel Fojt if (data->phase2_priv && data->phase2_method &&
1179*a1157835SDaniel Fojt data->phase2_method->deinit_for_reauth)
1180*a1157835SDaniel Fojt data->phase2_method->deinit_for_reauth(sm, data->phase2_priv);
1181*a1157835SDaniel Fojt wpabuf_clear_free(data->pending_phase2_req);
11826d49e1aeSJan Lentfer data->pending_phase2_req = NULL;
1183*a1157835SDaniel Fojt wpabuf_clear_free(data->pending_resp);
1184*a1157835SDaniel Fojt data->pending_resp = NULL;
11856d49e1aeSJan Lentfer data->crypto_binding_used = 0;
11866d49e1aeSJan Lentfer }
11876d49e1aeSJan Lentfer
11886d49e1aeSJan Lentfer
eap_peap_init_for_reauth(struct eap_sm * sm,void * priv)11896d49e1aeSJan Lentfer static void * eap_peap_init_for_reauth(struct eap_sm *sm, void *priv)
11906d49e1aeSJan Lentfer {
11916d49e1aeSJan Lentfer struct eap_peap_data *data = priv;
1192*a1157835SDaniel Fojt eap_peap_free_key(data);
11933ff40c12SJohn Marino os_free(data->session_id);
11943ff40c12SJohn Marino data->session_id = NULL;
11956d49e1aeSJan Lentfer if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
11966d49e1aeSJan Lentfer os_free(data);
11976d49e1aeSJan Lentfer return NULL;
11986d49e1aeSJan Lentfer }
11996d49e1aeSJan Lentfer if (data->phase2_priv && data->phase2_method &&
12006d49e1aeSJan Lentfer data->phase2_method->init_for_reauth)
12016d49e1aeSJan Lentfer data->phase2_method->init_for_reauth(sm, data->phase2_priv);
12026d49e1aeSJan Lentfer data->phase2_success = 0;
12036d49e1aeSJan Lentfer data->phase2_eap_success = 0;
12046d49e1aeSJan Lentfer data->phase2_eap_started = 0;
12056d49e1aeSJan Lentfer data->resuming = 1;
12066d49e1aeSJan Lentfer data->reauth = 1;
12076d49e1aeSJan Lentfer sm->peap_done = FALSE;
12086d49e1aeSJan Lentfer return priv;
12096d49e1aeSJan Lentfer }
12106d49e1aeSJan Lentfer
12116d49e1aeSJan Lentfer
eap_peap_get_status(struct eap_sm * sm,void * priv,char * buf,size_t buflen,int verbose)12126d49e1aeSJan Lentfer static int eap_peap_get_status(struct eap_sm *sm, void *priv, char *buf,
12136d49e1aeSJan Lentfer size_t buflen, int verbose)
12146d49e1aeSJan Lentfer {
12156d49e1aeSJan Lentfer struct eap_peap_data *data = priv;
12166d49e1aeSJan Lentfer int len, ret;
12176d49e1aeSJan Lentfer
12186d49e1aeSJan Lentfer len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose);
12196d49e1aeSJan Lentfer if (data->phase2_method) {
12206d49e1aeSJan Lentfer ret = os_snprintf(buf + len, buflen - len,
12216d49e1aeSJan Lentfer "EAP-PEAPv%d Phase2 method=%s\n",
12226d49e1aeSJan Lentfer data->peap_version,
12236d49e1aeSJan Lentfer data->phase2_method->name);
1224*a1157835SDaniel Fojt if (os_snprintf_error(buflen - len, ret))
12256d49e1aeSJan Lentfer return len;
12266d49e1aeSJan Lentfer len += ret;
12276d49e1aeSJan Lentfer }
12286d49e1aeSJan Lentfer return len;
12296d49e1aeSJan Lentfer }
12306d49e1aeSJan Lentfer
12316d49e1aeSJan Lentfer
eap_peap_isKeyAvailable(struct eap_sm * sm,void * priv)12326d49e1aeSJan Lentfer static Boolean eap_peap_isKeyAvailable(struct eap_sm *sm, void *priv)
12336d49e1aeSJan Lentfer {
12346d49e1aeSJan Lentfer struct eap_peap_data *data = priv;
12356d49e1aeSJan Lentfer return data->key_data != NULL && data->phase2_success;
12366d49e1aeSJan Lentfer }
12376d49e1aeSJan Lentfer
12386d49e1aeSJan Lentfer
eap_peap_getKey(struct eap_sm * sm,void * priv,size_t * len)12396d49e1aeSJan Lentfer static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
12406d49e1aeSJan Lentfer {
12416d49e1aeSJan Lentfer struct eap_peap_data *data = priv;
12426d49e1aeSJan Lentfer u8 *key;
12436d49e1aeSJan Lentfer
12446d49e1aeSJan Lentfer if (data->key_data == NULL || !data->phase2_success)
12456d49e1aeSJan Lentfer return NULL;
12466d49e1aeSJan Lentfer
12476d49e1aeSJan Lentfer key = os_malloc(EAP_TLS_KEY_LEN);
12486d49e1aeSJan Lentfer if (key == NULL)
12496d49e1aeSJan Lentfer return NULL;
12506d49e1aeSJan Lentfer
12516d49e1aeSJan Lentfer *len = EAP_TLS_KEY_LEN;
12526d49e1aeSJan Lentfer
12536d49e1aeSJan Lentfer if (data->crypto_binding_used) {
12546d49e1aeSJan Lentfer u8 csk[128];
12556d49e1aeSJan Lentfer /*
12566d49e1aeSJan Lentfer * Note: It looks like Microsoft implementation requires null
12576d49e1aeSJan Lentfer * termination for this label while the one used for deriving
12586d49e1aeSJan Lentfer * IPMK|CMK did not use null termination.
12596d49e1aeSJan Lentfer */
12603ff40c12SJohn Marino if (peap_prfplus(data->peap_version, data->ipmk, 40,
12616d49e1aeSJan Lentfer "Session Key Generating Function",
12623ff40c12SJohn Marino (u8 *) "\00", 1, csk, sizeof(csk)) < 0) {
12633ff40c12SJohn Marino os_free(key);
12643ff40c12SJohn Marino return NULL;
12653ff40c12SJohn Marino }
12666d49e1aeSJan Lentfer wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk));
12676d49e1aeSJan Lentfer os_memcpy(key, csk, EAP_TLS_KEY_LEN);
12686d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
12696d49e1aeSJan Lentfer key, EAP_TLS_KEY_LEN);
1270*a1157835SDaniel Fojt forced_memzero(csk, sizeof(csk));
12716d49e1aeSJan Lentfer } else
12726d49e1aeSJan Lentfer os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
12736d49e1aeSJan Lentfer
12746d49e1aeSJan Lentfer return key;
12756d49e1aeSJan Lentfer }
12766d49e1aeSJan Lentfer
12776d49e1aeSJan Lentfer
eap_peap_get_emsk(struct eap_sm * sm,void * priv,size_t * len)1278*a1157835SDaniel Fojt static u8 * eap_peap_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
1279*a1157835SDaniel Fojt {
1280*a1157835SDaniel Fojt struct eap_peap_data *data = priv;
1281*a1157835SDaniel Fojt u8 *key;
1282*a1157835SDaniel Fojt
1283*a1157835SDaniel Fojt if (!data->key_data || !data->phase2_success)
1284*a1157835SDaniel Fojt return NULL;
1285*a1157835SDaniel Fojt
1286*a1157835SDaniel Fojt if (data->crypto_binding_used) {
1287*a1157835SDaniel Fojt /* [MS-PEAP] does not define EMSK derivation */
1288*a1157835SDaniel Fojt return NULL;
1289*a1157835SDaniel Fojt }
1290*a1157835SDaniel Fojt
1291*a1157835SDaniel Fojt key = os_memdup(data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN);
1292*a1157835SDaniel Fojt if (!key)
1293*a1157835SDaniel Fojt return NULL;
1294*a1157835SDaniel Fojt
1295*a1157835SDaniel Fojt *len = EAP_EMSK_LEN;
1296*a1157835SDaniel Fojt
1297*a1157835SDaniel Fojt return key;
1298*a1157835SDaniel Fojt }
1299*a1157835SDaniel Fojt
1300*a1157835SDaniel Fojt
eap_peap_get_session_id(struct eap_sm * sm,void * priv,size_t * len)13013ff40c12SJohn Marino static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
13023ff40c12SJohn Marino {
13033ff40c12SJohn Marino struct eap_peap_data *data = priv;
13043ff40c12SJohn Marino u8 *id;
13053ff40c12SJohn Marino
13063ff40c12SJohn Marino if (data->session_id == NULL || !data->phase2_success)
13073ff40c12SJohn Marino return NULL;
13083ff40c12SJohn Marino
1309*a1157835SDaniel Fojt id = os_memdup(data->session_id, data->id_len);
13103ff40c12SJohn Marino if (id == NULL)
13113ff40c12SJohn Marino return NULL;
13123ff40c12SJohn Marino
13133ff40c12SJohn Marino *len = data->id_len;
13143ff40c12SJohn Marino
13153ff40c12SJohn Marino return id;
13163ff40c12SJohn Marino }
13173ff40c12SJohn Marino
13183ff40c12SJohn Marino
eap_peer_peap_register(void)13196d49e1aeSJan Lentfer int eap_peer_peap_register(void)
13206d49e1aeSJan Lentfer {
13216d49e1aeSJan Lentfer struct eap_method *eap;
13226d49e1aeSJan Lentfer
13236d49e1aeSJan Lentfer eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
13246d49e1aeSJan Lentfer EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP");
13256d49e1aeSJan Lentfer if (eap == NULL)
13266d49e1aeSJan Lentfer return -1;
13276d49e1aeSJan Lentfer
13286d49e1aeSJan Lentfer eap->init = eap_peap_init;
13296d49e1aeSJan Lentfer eap->deinit = eap_peap_deinit;
13306d49e1aeSJan Lentfer eap->process = eap_peap_process;
13316d49e1aeSJan Lentfer eap->isKeyAvailable = eap_peap_isKeyAvailable;
13326d49e1aeSJan Lentfer eap->getKey = eap_peap_getKey;
1333*a1157835SDaniel Fojt eap->get_emsk = eap_peap_get_emsk;
13346d49e1aeSJan Lentfer eap->get_status = eap_peap_get_status;
13356d49e1aeSJan Lentfer eap->has_reauth_data = eap_peap_has_reauth_data;
13366d49e1aeSJan Lentfer eap->deinit_for_reauth = eap_peap_deinit_for_reauth;
13376d49e1aeSJan Lentfer eap->init_for_reauth = eap_peap_init_for_reauth;
13383ff40c12SJohn Marino eap->getSessionId = eap_peap_get_session_id;
13396d49e1aeSJan Lentfer
1340*a1157835SDaniel Fojt return eap_peer_method_register(eap);
13416d49e1aeSJan Lentfer }
1342