139beb93cSSam Leffler /* 239beb93cSSam Leffler * EAP peer method: EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt) 34bc52338SCy Schubert * Copyright (c) 2004-2019, Jouni Malinen <j@w1.fi> 439beb93cSSam Leffler * 5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license. 6f05cddf9SRui Paulo * See README for more details. 739beb93cSSam Leffler */ 839beb93cSSam Leffler 939beb93cSSam Leffler #include "includes.h" 1039beb93cSSam Leffler 1139beb93cSSam Leffler #include "common.h" 1239beb93cSSam Leffler #include "crypto/sha1.h" 13e28a4053SRui Paulo #include "crypto/tls.h" 14e28a4053SRui Paulo #include "eap_common/eap_tlv_common.h" 15e28a4053SRui Paulo #include "eap_common/eap_peap_common.h" 1639beb93cSSam Leffler #include "eap_i.h" 1739beb93cSSam Leffler #include "eap_tls_common.h" 1839beb93cSSam Leffler #include "eap_config.h" 1939beb93cSSam Leffler #include "tncc.h" 2039beb93cSSam Leffler 2139beb93cSSam Leffler 2239beb93cSSam Leffler /* Maximum supported PEAP version 2339beb93cSSam Leffler * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt 2439beb93cSSam Leffler * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt 2539beb93cSSam Leffler */ 2639beb93cSSam Leffler #define EAP_PEAP_VERSION 1 2739beb93cSSam Leffler 2839beb93cSSam Leffler 2939beb93cSSam Leffler static void eap_peap_deinit(struct eap_sm *sm, void *priv); 3039beb93cSSam Leffler 3139beb93cSSam Leffler 3239beb93cSSam Leffler struct eap_peap_data { 3339beb93cSSam Leffler struct eap_ssl_data ssl; 3439beb93cSSam Leffler 3539beb93cSSam Leffler int peap_version, force_peap_version, force_new_label; 3639beb93cSSam Leffler 3739beb93cSSam Leffler const struct eap_method *phase2_method; 3839beb93cSSam Leffler void *phase2_priv; 3939beb93cSSam Leffler int phase2_success; 4039beb93cSSam Leffler int phase2_eap_success; 4139beb93cSSam Leffler int phase2_eap_started; 4239beb93cSSam Leffler 4339beb93cSSam Leffler struct eap_method_type phase2_type; 4439beb93cSSam Leffler struct eap_method_type *phase2_types; 4539beb93cSSam Leffler size_t num_phase2_types; 4639beb93cSSam Leffler 4739beb93cSSam Leffler int peap_outer_success; /* 0 = PEAP terminated on Phase 2 inner 4839beb93cSSam Leffler * EAP-Success 4939beb93cSSam Leffler * 1 = reply with tunneled EAP-Success to inner 5039beb93cSSam Leffler * EAP-Success and expect AS to send outer 5139beb93cSSam Leffler * (unencrypted) EAP-Success after this 5239beb93cSSam Leffler * 2 = reply with PEAP/TLS ACK to inner 5339beb93cSSam Leffler * EAP-Success and expect AS to send outer 5439beb93cSSam Leffler * (unencrypted) EAP-Success after this */ 5539beb93cSSam Leffler int resuming; /* starting a resumed session */ 5639beb93cSSam Leffler int reauth; /* reauthentication */ 5739beb93cSSam Leffler u8 *key_data; 585b9c547cSRui Paulo u8 *session_id; 595b9c547cSRui Paulo size_t id_len; 6039beb93cSSam Leffler 6139beb93cSSam Leffler struct wpabuf *pending_phase2_req; 62780fb4a2SCy Schubert struct wpabuf *pending_resp; 6339beb93cSSam Leffler enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding; 6439beb93cSSam Leffler int crypto_binding_used; 6539beb93cSSam Leffler u8 binding_nonce[32]; 6639beb93cSSam Leffler u8 ipmk[40]; 6739beb93cSSam Leffler u8 cmk[20]; 6839beb93cSSam Leffler int soh; /* Whether IF-TNCCS-SOH (Statement of Health; Microsoft NAP) 6939beb93cSSam Leffler * is enabled. */ 70*a90b9d01SCy Schubert enum { NO_AUTH, FOR_INITIAL, ALWAYS } phase2_auth; 7139beb93cSSam Leffler }; 7239beb93cSSam Leffler 7339beb93cSSam Leffler 74780fb4a2SCy Schubert static void eap_peap_parse_phase1(struct eap_peap_data *data, 7539beb93cSSam Leffler const char *phase1) 7639beb93cSSam Leffler { 7739beb93cSSam Leffler const char *pos; 7839beb93cSSam Leffler 7939beb93cSSam Leffler pos = os_strstr(phase1, "peapver="); 8039beb93cSSam Leffler if (pos) { 8139beb93cSSam Leffler data->force_peap_version = atoi(pos + 8); 8239beb93cSSam Leffler data->peap_version = data->force_peap_version; 8339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: Forced PEAP version %d", 8439beb93cSSam Leffler data->force_peap_version); 8539beb93cSSam Leffler } 8639beb93cSSam Leffler 8739beb93cSSam Leffler if (os_strstr(phase1, "peaplabel=1")) { 8839beb93cSSam Leffler data->force_new_label = 1; 8939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: Force new label for key " 9039beb93cSSam Leffler "derivation"); 9139beb93cSSam Leffler } 9239beb93cSSam Leffler 9339beb93cSSam Leffler if (os_strstr(phase1, "peap_outer_success=0")) { 9439beb93cSSam Leffler data->peap_outer_success = 0; 9539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: terminate authentication on " 9639beb93cSSam Leffler "tunneled EAP-Success"); 9739beb93cSSam Leffler } else if (os_strstr(phase1, "peap_outer_success=1")) { 9839beb93cSSam Leffler data->peap_outer_success = 1; 9939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: send tunneled EAP-Success " 10039beb93cSSam Leffler "after receiving tunneled EAP-Success"); 10139beb93cSSam Leffler } else if (os_strstr(phase1, "peap_outer_success=2")) { 10239beb93cSSam Leffler data->peap_outer_success = 2; 10339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: send PEAP/TLS ACK after " 10439beb93cSSam Leffler "receiving tunneled EAP-Success"); 10539beb93cSSam Leffler } 10639beb93cSSam Leffler 10739beb93cSSam Leffler if (os_strstr(phase1, "crypto_binding=0")) { 10839beb93cSSam Leffler data->crypto_binding = NO_BINDING; 10939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: Do not use cryptobinding"); 11039beb93cSSam Leffler } else if (os_strstr(phase1, "crypto_binding=1")) { 11139beb93cSSam Leffler data->crypto_binding = OPTIONAL_BINDING; 11239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: Optional cryptobinding"); 11339beb93cSSam Leffler } else if (os_strstr(phase1, "crypto_binding=2")) { 11439beb93cSSam Leffler data->crypto_binding = REQUIRE_BINDING; 11539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: Require cryptobinding"); 11639beb93cSSam Leffler } 11739beb93cSSam Leffler 118*a90b9d01SCy Schubert if (os_strstr(phase1, "phase2_auth=0")) { 119*a90b9d01SCy Schubert data->phase2_auth = NO_AUTH; 120*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, 121*a90b9d01SCy Schubert "EAP-PEAP: Do not require Phase 2 authentication"); 122*a90b9d01SCy Schubert } else if (os_strstr(phase1, "phase2_auth=1")) { 123*a90b9d01SCy Schubert data->phase2_auth = FOR_INITIAL; 124*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, 125*a90b9d01SCy Schubert "EAP-PEAP: Require Phase 2 authentication for initial connection"); 126*a90b9d01SCy Schubert } else if (os_strstr(phase1, "phase2_auth=2")) { 127*a90b9d01SCy Schubert data->phase2_auth = ALWAYS; 128*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, 129*a90b9d01SCy Schubert "EAP-PEAP: Require Phase 2 authentication for all cases"); 130*a90b9d01SCy Schubert } 13139beb93cSSam Leffler #ifdef EAP_TNC 13239beb93cSSam Leffler if (os_strstr(phase1, "tnc=soh2")) { 13339beb93cSSam Leffler data->soh = 2; 13439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled"); 13539beb93cSSam Leffler } else if (os_strstr(phase1, "tnc=soh1")) { 13639beb93cSSam Leffler data->soh = 1; 13739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 1 enabled"); 13839beb93cSSam Leffler } else if (os_strstr(phase1, "tnc=soh")) { 13939beb93cSSam Leffler data->soh = 2; 14039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled"); 14139beb93cSSam Leffler } 14239beb93cSSam Leffler #endif /* EAP_TNC */ 14339beb93cSSam Leffler } 14439beb93cSSam Leffler 14539beb93cSSam Leffler 14639beb93cSSam Leffler static void * eap_peap_init(struct eap_sm *sm) 14739beb93cSSam Leffler { 14839beb93cSSam Leffler struct eap_peap_data *data; 14939beb93cSSam Leffler struct eap_peer_config *config = eap_get_config(sm); 15039beb93cSSam Leffler 15139beb93cSSam Leffler data = os_zalloc(sizeof(*data)); 15239beb93cSSam Leffler if (data == NULL) 15339beb93cSSam Leffler return NULL; 154c1d255d3SCy Schubert sm->peap_done = false; 15539beb93cSSam Leffler data->peap_version = EAP_PEAP_VERSION; 15639beb93cSSam Leffler data->force_peap_version = -1; 15739beb93cSSam Leffler data->peap_outer_success = 2; 15839beb93cSSam Leffler data->crypto_binding = OPTIONAL_BINDING; 159*a90b9d01SCy Schubert data->phase2_auth = FOR_INITIAL; 16039beb93cSSam Leffler 161780fb4a2SCy Schubert if (config && config->phase1) 162780fb4a2SCy Schubert eap_peap_parse_phase1(data, config->phase1); 16339beb93cSSam Leffler 16439beb93cSSam Leffler if (eap_peer_select_phase2_methods(config, "auth=", 16539beb93cSSam Leffler &data->phase2_types, 166c1d255d3SCy Schubert &data->num_phase2_types, 0) < 0) { 16739beb93cSSam Leffler eap_peap_deinit(sm, data); 16839beb93cSSam Leffler return NULL; 16939beb93cSSam Leffler } 17039beb93cSSam Leffler 17139beb93cSSam Leffler data->phase2_type.vendor = EAP_VENDOR_IETF; 17239beb93cSSam Leffler data->phase2_type.method = EAP_TYPE_NONE; 17339beb93cSSam Leffler 174f05cddf9SRui Paulo if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_PEAP)) { 17539beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL."); 17639beb93cSSam Leffler eap_peap_deinit(sm, data); 17739beb93cSSam Leffler return NULL; 17839beb93cSSam Leffler } 17939beb93cSSam Leffler 18039beb93cSSam Leffler return data; 18139beb93cSSam Leffler } 18239beb93cSSam Leffler 18339beb93cSSam Leffler 1845b9c547cSRui Paulo static void eap_peap_free_key(struct eap_peap_data *data) 1855b9c547cSRui Paulo { 1865b9c547cSRui Paulo if (data->key_data) { 1874bc52338SCy Schubert bin_clear_free(data->key_data, EAP_TLS_KEY_LEN + EAP_EMSK_LEN); 1885b9c547cSRui Paulo data->key_data = NULL; 1895b9c547cSRui Paulo } 1905b9c547cSRui Paulo } 1915b9c547cSRui Paulo 1925b9c547cSRui Paulo 19339beb93cSSam Leffler static void eap_peap_deinit(struct eap_sm *sm, void *priv) 19439beb93cSSam Leffler { 19539beb93cSSam Leffler struct eap_peap_data *data = priv; 19639beb93cSSam Leffler if (data == NULL) 19739beb93cSSam Leffler return; 19839beb93cSSam Leffler if (data->phase2_priv && data->phase2_method) 19939beb93cSSam Leffler data->phase2_method->deinit(sm, data->phase2_priv); 20039beb93cSSam Leffler os_free(data->phase2_types); 20139beb93cSSam Leffler eap_peer_tls_ssl_deinit(sm, &data->ssl); 2025b9c547cSRui Paulo eap_peap_free_key(data); 2035b9c547cSRui Paulo os_free(data->session_id); 2044bc52338SCy Schubert wpabuf_clear_free(data->pending_phase2_req); 2054bc52338SCy Schubert wpabuf_clear_free(data->pending_resp); 2064bc52338SCy Schubert bin_clear_free(data, sizeof(*data)); 20739beb93cSSam Leffler } 20839beb93cSSam Leffler 20939beb93cSSam Leffler 21039beb93cSSam Leffler /** 21139beb93cSSam Leffler * eap_tlv_build_nak - Build EAP-TLV NAK message 21239beb93cSSam Leffler * @id: EAP identifier for the header 21339beb93cSSam Leffler * @nak_type: TLV type (EAP_TLV_*) 21439beb93cSSam Leffler * Returns: Buffer to the allocated EAP-TLV NAK message or %NULL on failure 21539beb93cSSam Leffler * 216f05cddf9SRui Paulo * This function builds an EAP-TLV NAK message. The caller is responsible for 21739beb93cSSam Leffler * freeing the returned buffer. 21839beb93cSSam Leffler */ 21939beb93cSSam Leffler static struct wpabuf * eap_tlv_build_nak(int id, u16 nak_type) 22039beb93cSSam Leffler { 22139beb93cSSam Leffler struct wpabuf *msg; 22239beb93cSSam Leffler 22339beb93cSSam Leffler msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, 10, 22439beb93cSSam Leffler EAP_CODE_RESPONSE, id); 22539beb93cSSam Leffler if (msg == NULL) 22639beb93cSSam Leffler return NULL; 22739beb93cSSam Leffler 22839beb93cSSam Leffler wpabuf_put_u8(msg, 0x80); /* Mandatory */ 22939beb93cSSam Leffler wpabuf_put_u8(msg, EAP_TLV_NAK_TLV); 23039beb93cSSam Leffler wpabuf_put_be16(msg, 6); /* Length */ 23139beb93cSSam Leffler wpabuf_put_be32(msg, 0); /* Vendor-Id */ 23239beb93cSSam Leffler wpabuf_put_be16(msg, nak_type); /* NAK-Type */ 23339beb93cSSam Leffler 23439beb93cSSam Leffler return msg; 23539beb93cSSam Leffler } 23639beb93cSSam Leffler 23739beb93cSSam Leffler 23839beb93cSSam Leffler static int eap_peap_get_isk(struct eap_sm *sm, struct eap_peap_data *data, 23939beb93cSSam Leffler u8 *isk, size_t isk_len) 24039beb93cSSam Leffler { 24139beb93cSSam Leffler u8 *key; 24239beb93cSSam Leffler size_t key_len; 24339beb93cSSam Leffler 24439beb93cSSam Leffler os_memset(isk, 0, isk_len); 24539beb93cSSam Leffler if (data->phase2_method == NULL || data->phase2_priv == NULL || 24639beb93cSSam Leffler data->phase2_method->isKeyAvailable == NULL || 24739beb93cSSam Leffler data->phase2_method->getKey == NULL) 24839beb93cSSam Leffler return 0; 24939beb93cSSam Leffler 25039beb93cSSam Leffler if (!data->phase2_method->isKeyAvailable(sm, data->phase2_priv) || 25139beb93cSSam Leffler (key = data->phase2_method->getKey(sm, data->phase2_priv, 25239beb93cSSam Leffler &key_len)) == NULL) { 25339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not get key material " 25439beb93cSSam Leffler "from Phase 2"); 25539beb93cSSam Leffler return -1; 25639beb93cSSam Leffler } 25739beb93cSSam Leffler 25839beb93cSSam Leffler if (key_len > isk_len) 25939beb93cSSam Leffler key_len = isk_len; 26039beb93cSSam Leffler os_memcpy(isk, key, key_len); 26139beb93cSSam Leffler os_free(key); 26239beb93cSSam Leffler 26339beb93cSSam Leffler return 0; 26439beb93cSSam Leffler } 26539beb93cSSam Leffler 26639beb93cSSam Leffler 26739beb93cSSam Leffler static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data) 26839beb93cSSam Leffler { 26939beb93cSSam Leffler u8 *tk; 27039beb93cSSam Leffler u8 isk[32], imck[60]; 2714bc52338SCy Schubert int resumed, res; 27239beb93cSSam Leffler 27339beb93cSSam Leffler /* 27439beb93cSSam Leffler * Tunnel key (TK) is the first 60 octets of the key generated by 27539beb93cSSam Leffler * phase 1 of PEAP (based on TLS). 27639beb93cSSam Leffler */ 27739beb93cSSam Leffler tk = data->key_data; 27839beb93cSSam Leffler if (tk == NULL) 27939beb93cSSam Leffler return -1; 28039beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60); 28139beb93cSSam Leffler 282780fb4a2SCy Schubert resumed = tls_connection_resumed(sm->ssl_ctx, data->ssl.conn); 283780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, 284780fb4a2SCy Schubert "EAP-PEAP: CMK derivation - reauth=%d resumed=%d phase2_eap_started=%d phase2_success=%d", 285780fb4a2SCy Schubert data->reauth, resumed, data->phase2_eap_started, 286780fb4a2SCy Schubert data->phase2_success); 287780fb4a2SCy Schubert if (data->reauth && !data->phase2_eap_started && resumed) { 28839beb93cSSam Leffler /* Fast-connect: IPMK|CMK = TK */ 28939beb93cSSam Leffler os_memcpy(data->ipmk, tk, 40); 29039beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK from TK", 29139beb93cSSam Leffler data->ipmk, 40); 29239beb93cSSam Leffler os_memcpy(data->cmk, tk + 40, 20); 29339beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK from TK", 29439beb93cSSam Leffler data->cmk, 20); 29539beb93cSSam Leffler return 0; 29639beb93cSSam Leffler } 29739beb93cSSam Leffler 29839beb93cSSam Leffler if (eap_peap_get_isk(sm, data, isk, sizeof(isk)) < 0) 29939beb93cSSam Leffler return -1; 30039beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk)); 30139beb93cSSam Leffler 30239beb93cSSam Leffler /* 30339beb93cSSam Leffler * IPMK Seed = "Inner Methods Compound Keys" | ISK 30439beb93cSSam Leffler * TempKey = First 40 octets of TK 30539beb93cSSam Leffler * IPMK|CMK = PRF+(TempKey, IPMK Seed, 60) 30639beb93cSSam Leffler * (note: draft-josefsson-pppext-eap-tls-eap-10.txt includes a space 30739beb93cSSam Leffler * in the end of the label just before ISK; is that just a typo?) 30839beb93cSSam Leffler */ 30939beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40); 3104bc52338SCy Schubert res = peap_prfplus(data->peap_version, tk, 40, 311f05cddf9SRui Paulo "Inner Methods Compound Keys", 3124bc52338SCy Schubert isk, sizeof(isk), imck, sizeof(imck)); 313206b73d0SCy Schubert forced_memzero(isk, sizeof(isk)); 3144bc52338SCy Schubert if (res < 0) 315f05cddf9SRui Paulo return -1; 31639beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)", 31739beb93cSSam Leffler imck, sizeof(imck)); 31839beb93cSSam Leffler 31939beb93cSSam Leffler os_memcpy(data->ipmk, imck, 40); 32039beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40); 32139beb93cSSam Leffler os_memcpy(data->cmk, imck + 40, 20); 32239beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20); 323206b73d0SCy Schubert forced_memzero(imck, sizeof(imck)); 32439beb93cSSam Leffler 32539beb93cSSam Leffler return 0; 32639beb93cSSam Leffler } 32739beb93cSSam Leffler 32839beb93cSSam Leffler 32939beb93cSSam Leffler static int eap_tlv_add_cryptobinding(struct eap_sm *sm, 33039beb93cSSam Leffler struct eap_peap_data *data, 33139beb93cSSam Leffler struct wpabuf *buf) 33239beb93cSSam Leffler { 33339beb93cSSam Leffler u8 *mac; 33439beb93cSSam Leffler u8 eap_type = EAP_TYPE_PEAP; 33539beb93cSSam Leffler const u8 *addr[2]; 33639beb93cSSam Leffler size_t len[2]; 33739beb93cSSam Leffler u16 tlv_type; 33839beb93cSSam Leffler 33939beb93cSSam Leffler /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */ 34039beb93cSSam Leffler addr[0] = wpabuf_put(buf, 0); 34139beb93cSSam Leffler len[0] = 60; 34239beb93cSSam Leffler addr[1] = &eap_type; 34339beb93cSSam Leffler len[1] = 1; 34439beb93cSSam Leffler 34539beb93cSSam Leffler tlv_type = EAP_TLV_CRYPTO_BINDING_TLV; 34639beb93cSSam Leffler wpabuf_put_be16(buf, tlv_type); 34739beb93cSSam Leffler wpabuf_put_be16(buf, 56); 34839beb93cSSam Leffler 34939beb93cSSam Leffler wpabuf_put_u8(buf, 0); /* Reserved */ 35039beb93cSSam Leffler wpabuf_put_u8(buf, data->peap_version); /* Version */ 35139beb93cSSam Leffler wpabuf_put_u8(buf, data->peap_version); /* RecvVersion */ 35239beb93cSSam Leffler wpabuf_put_u8(buf, 1); /* SubType: 0 = Request, 1 = Response */ 35339beb93cSSam Leffler wpabuf_put_data(buf, data->binding_nonce, 32); /* Nonce */ 35439beb93cSSam Leffler mac = wpabuf_put(buf, 20); /* Compound_MAC */ 35539beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK", data->cmk, 20); 35639beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1", 35739beb93cSSam Leffler addr[0], len[0]); 35839beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2", 35939beb93cSSam Leffler addr[1], len[1]); 360780fb4a2SCy Schubert if (hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac) < 0) 361780fb4a2SCy Schubert return -1; 36239beb93cSSam Leffler wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC", mac, SHA1_MAC_LEN); 36339beb93cSSam Leffler data->crypto_binding_used = 1; 36439beb93cSSam Leffler 36539beb93cSSam Leffler return 0; 36639beb93cSSam Leffler } 36739beb93cSSam Leffler 36839beb93cSSam Leffler 36939beb93cSSam Leffler /** 37039beb93cSSam Leffler * eap_tlv_build_result - Build EAP-TLV Result message 37139beb93cSSam Leffler * @id: EAP identifier for the header 37239beb93cSSam Leffler * @status: Status (EAP_TLV_RESULT_SUCCESS or EAP_TLV_RESULT_FAILURE) 37339beb93cSSam Leffler * Returns: Buffer to the allocated EAP-TLV Result message or %NULL on failure 37439beb93cSSam Leffler * 375f05cddf9SRui Paulo * This function builds an EAP-TLV Result message. The caller is responsible 376f05cddf9SRui Paulo * for freeing the returned buffer. 37739beb93cSSam Leffler */ 37839beb93cSSam Leffler static struct wpabuf * eap_tlv_build_result(struct eap_sm *sm, 37939beb93cSSam Leffler struct eap_peap_data *data, 38039beb93cSSam Leffler int crypto_tlv_used, 38139beb93cSSam Leffler int id, u16 status) 38239beb93cSSam Leffler { 38339beb93cSSam Leffler struct wpabuf *msg; 38439beb93cSSam Leffler size_t len; 38539beb93cSSam Leffler 38639beb93cSSam Leffler if (data->crypto_binding == NO_BINDING) 38739beb93cSSam Leffler crypto_tlv_used = 0; 38839beb93cSSam Leffler 38939beb93cSSam Leffler len = 6; 39039beb93cSSam Leffler if (crypto_tlv_used) 39139beb93cSSam Leffler len += 60; /* Cryptobinding TLV */ 39239beb93cSSam Leffler msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, len, 39339beb93cSSam Leffler EAP_CODE_RESPONSE, id); 39439beb93cSSam Leffler if (msg == NULL) 39539beb93cSSam Leffler return NULL; 39639beb93cSSam Leffler 39739beb93cSSam Leffler wpabuf_put_u8(msg, 0x80); /* Mandatory */ 39839beb93cSSam Leffler wpabuf_put_u8(msg, EAP_TLV_RESULT_TLV); 39939beb93cSSam Leffler wpabuf_put_be16(msg, 2); /* Length */ 40039beb93cSSam Leffler wpabuf_put_be16(msg, status); /* Status */ 40139beb93cSSam Leffler 40239beb93cSSam Leffler if (crypto_tlv_used && eap_tlv_add_cryptobinding(sm, data, msg)) { 4034bc52338SCy Schubert wpabuf_clear_free(msg); 40439beb93cSSam Leffler return NULL; 40539beb93cSSam Leffler } 40639beb93cSSam Leffler 40739beb93cSSam Leffler return msg; 40839beb93cSSam Leffler } 40939beb93cSSam Leffler 41039beb93cSSam Leffler 41139beb93cSSam Leffler static int eap_tlv_validate_cryptobinding(struct eap_sm *sm, 41239beb93cSSam Leffler struct eap_peap_data *data, 41339beb93cSSam Leffler const u8 *crypto_tlv, 41439beb93cSSam Leffler size_t crypto_tlv_len) 41539beb93cSSam Leffler { 41639beb93cSSam Leffler u8 buf[61], mac[SHA1_MAC_LEN]; 41739beb93cSSam Leffler const u8 *pos; 41839beb93cSSam Leffler 41939beb93cSSam Leffler if (eap_peap_derive_cmk(sm, data) < 0) { 42039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not derive CMK"); 42139beb93cSSam Leffler return -1; 42239beb93cSSam Leffler } 42339beb93cSSam Leffler 42439beb93cSSam Leffler if (crypto_tlv_len != 4 + 56) { 42539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid cryptobinding TLV " 42639beb93cSSam Leffler "length %d", (int) crypto_tlv_len); 42739beb93cSSam Leffler return -1; 42839beb93cSSam Leffler } 42939beb93cSSam Leffler 43039beb93cSSam Leffler pos = crypto_tlv; 43139beb93cSSam Leffler pos += 4; /* TLV header */ 43239beb93cSSam Leffler if (pos[1] != data->peap_version) { 43339beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV Version " 43439beb93cSSam Leffler "mismatch (was %d; expected %d)", 43539beb93cSSam Leffler pos[1], data->peap_version); 43639beb93cSSam Leffler return -1; 43739beb93cSSam Leffler } 43839beb93cSSam Leffler 43939beb93cSSam Leffler if (pos[3] != 0) { 44039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected Cryptobinding TLV " 44139beb93cSSam Leffler "SubType %d", pos[3]); 44239beb93cSSam Leffler return -1; 44339beb93cSSam Leffler } 44439beb93cSSam Leffler pos += 4; 44539beb93cSSam Leffler os_memcpy(data->binding_nonce, pos, 32); 44639beb93cSSam Leffler pos += 32; /* Nonce */ 44739beb93cSSam Leffler 44839beb93cSSam Leffler /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */ 44939beb93cSSam Leffler os_memcpy(buf, crypto_tlv, 60); 45039beb93cSSam Leffler os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */ 45139beb93cSSam Leffler buf[60] = EAP_TYPE_PEAP; 45239beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Compound_MAC data", 45339beb93cSSam Leffler buf, sizeof(buf)); 45439beb93cSSam Leffler hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac); 45539beb93cSSam Leffler 4565b9c547cSRui Paulo if (os_memcmp_const(mac, pos, SHA1_MAC_LEN) != 0) { 45739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in " 45839beb93cSSam Leffler "cryptobinding TLV"); 45939beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received MAC", 46039beb93cSSam Leffler pos, SHA1_MAC_LEN); 46139beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Expected MAC", 46239beb93cSSam Leffler mac, SHA1_MAC_LEN); 46339beb93cSSam Leffler return -1; 46439beb93cSSam Leffler } 46539beb93cSSam Leffler 46639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received"); 46739beb93cSSam Leffler 46839beb93cSSam Leffler return 0; 46939beb93cSSam Leffler } 47039beb93cSSam Leffler 47139beb93cSSam Leffler 472*a90b9d01SCy Schubert static bool peap_phase2_sufficient(struct eap_sm *sm, 473*a90b9d01SCy Schubert struct eap_peap_data *data) 474*a90b9d01SCy Schubert { 475*a90b9d01SCy Schubert if ((data->phase2_auth == ALWAYS || 476*a90b9d01SCy Schubert (data->phase2_auth == FOR_INITIAL && 477*a90b9d01SCy Schubert !tls_connection_resumed(sm->ssl_ctx, data->ssl.conn) && 478*a90b9d01SCy Schubert !data->ssl.client_cert_conf) || 479*a90b9d01SCy Schubert data->phase2_eap_started) && 480*a90b9d01SCy Schubert !data->phase2_eap_success) 481*a90b9d01SCy Schubert return false; 482*a90b9d01SCy Schubert return true; 483*a90b9d01SCy Schubert } 484*a90b9d01SCy Schubert 485*a90b9d01SCy Schubert 48639beb93cSSam Leffler /** 48739beb93cSSam Leffler * eap_tlv_process - Process a received EAP-TLV message and generate a response 48839beb93cSSam Leffler * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() 48939beb93cSSam Leffler * @ret: Return values from EAP request validation and processing 49039beb93cSSam Leffler * @req: EAP-TLV request to be processed. The caller must have validated that 49139beb93cSSam Leffler * the buffer is large enough to contain full request (hdr->length bytes) and 49239beb93cSSam Leffler * that the EAP type is EAP_TYPE_TLV. 49339beb93cSSam Leffler * @resp: Buffer to return a pointer to the allocated response message. This 49439beb93cSSam Leffler * field should be initialized to %NULL before the call. The value will be 49539beb93cSSam Leffler * updated if a response message is generated. The caller is responsible for 49639beb93cSSam Leffler * freeing the allocated message. 49739beb93cSSam Leffler * @force_failure: Force negotiation to fail 49839beb93cSSam Leffler * Returns: 0 on success, -1 on failure 49939beb93cSSam Leffler */ 50039beb93cSSam Leffler static int eap_tlv_process(struct eap_sm *sm, struct eap_peap_data *data, 50139beb93cSSam Leffler struct eap_method_ret *ret, 50239beb93cSSam Leffler const struct wpabuf *req, struct wpabuf **resp, 50339beb93cSSam Leffler int force_failure) 50439beb93cSSam Leffler { 50539beb93cSSam Leffler size_t left, tlv_len; 50639beb93cSSam Leffler const u8 *pos; 50739beb93cSSam Leffler const u8 *result_tlv = NULL, *crypto_tlv = NULL; 50839beb93cSSam Leffler size_t result_tlv_len = 0, crypto_tlv_len = 0; 50939beb93cSSam Leffler int tlv_type, mandatory; 51039beb93cSSam Leffler 51139beb93cSSam Leffler /* Parse TLVs */ 51239beb93cSSam Leffler pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, req, &left); 51339beb93cSSam Leffler if (pos == NULL) 51439beb93cSSam Leffler return -1; 51539beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-TLV: Received TLVs", pos, left); 51639beb93cSSam Leffler while (left >= 4) { 51739beb93cSSam Leffler mandatory = !!(pos[0] & 0x80); 51839beb93cSSam Leffler tlv_type = WPA_GET_BE16(pos) & 0x3fff; 51939beb93cSSam Leffler pos += 2; 52039beb93cSSam Leffler tlv_len = WPA_GET_BE16(pos); 52139beb93cSSam Leffler pos += 2; 52239beb93cSSam Leffler left -= 4; 52339beb93cSSam Leffler if (tlv_len > left) { 52439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TLV: TLV underrun " 52539beb93cSSam Leffler "(tlv_len=%lu left=%lu)", 52639beb93cSSam Leffler (unsigned long) tlv_len, 52739beb93cSSam Leffler (unsigned long) left); 52839beb93cSSam Leffler return -1; 52939beb93cSSam Leffler } 53039beb93cSSam Leffler switch (tlv_type) { 53139beb93cSSam Leffler case EAP_TLV_RESULT_TLV: 53239beb93cSSam Leffler result_tlv = pos; 53339beb93cSSam Leffler result_tlv_len = tlv_len; 53439beb93cSSam Leffler break; 53539beb93cSSam Leffler case EAP_TLV_CRYPTO_BINDING_TLV: 53639beb93cSSam Leffler crypto_tlv = pos; 53739beb93cSSam Leffler crypto_tlv_len = tlv_len; 53839beb93cSSam Leffler break; 53939beb93cSSam Leffler default: 54039beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TLV: Unsupported TLV Type " 54139beb93cSSam Leffler "%d%s", tlv_type, 54239beb93cSSam Leffler mandatory ? " (mandatory)" : ""); 54339beb93cSSam Leffler if (mandatory) { 54439beb93cSSam Leffler /* NAK TLV and ignore all TLVs in this packet. 54539beb93cSSam Leffler */ 54639beb93cSSam Leffler *resp = eap_tlv_build_nak(eap_get_id(req), 54739beb93cSSam Leffler tlv_type); 54839beb93cSSam Leffler return *resp == NULL ? -1 : 0; 54939beb93cSSam Leffler } 55039beb93cSSam Leffler /* Ignore this TLV, but process other TLVs */ 55139beb93cSSam Leffler break; 55239beb93cSSam Leffler } 55339beb93cSSam Leffler 55439beb93cSSam Leffler pos += tlv_len; 55539beb93cSSam Leffler left -= tlv_len; 55639beb93cSSam Leffler } 55739beb93cSSam Leffler if (left) { 55839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-TLV: Last TLV too short in " 55939beb93cSSam Leffler "Request (left=%lu)", (unsigned long) left); 56039beb93cSSam Leffler return -1; 56139beb93cSSam Leffler } 56239beb93cSSam Leffler 56339beb93cSSam Leffler /* Process supported TLVs */ 56439beb93cSSam Leffler if (crypto_tlv && data->crypto_binding != NO_BINDING) { 56539beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV", 56639beb93cSSam Leffler crypto_tlv, crypto_tlv_len); 56739beb93cSSam Leffler if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4, 56839beb93cSSam Leffler crypto_tlv_len + 4) < 0) { 56939beb93cSSam Leffler if (result_tlv == NULL) 57039beb93cSSam Leffler return -1; 57139beb93cSSam Leffler force_failure = 1; 57239beb93cSSam Leffler crypto_tlv = NULL; /* do not include Cryptobinding TLV 57339beb93cSSam Leffler * in response, if the received 57439beb93cSSam Leffler * cryptobinding was invalid. */ 57539beb93cSSam Leffler } 57639beb93cSSam Leffler } else if (!crypto_tlv && data->crypto_binding == REQUIRE_BINDING) { 57739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV"); 57839beb93cSSam Leffler return -1; 57939beb93cSSam Leffler } 58039beb93cSSam Leffler 58139beb93cSSam Leffler if (result_tlv) { 58239beb93cSSam Leffler int status, resp_status; 58339beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-TLV: Result TLV", 58439beb93cSSam Leffler result_tlv, result_tlv_len); 58539beb93cSSam Leffler if (result_tlv_len < 2) { 58639beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TLV: Too short Result TLV " 58739beb93cSSam Leffler "(len=%lu)", 58839beb93cSSam Leffler (unsigned long) result_tlv_len); 58939beb93cSSam Leffler return -1; 59039beb93cSSam Leffler } 59139beb93cSSam Leffler status = WPA_GET_BE16(result_tlv); 59239beb93cSSam Leffler if (status == EAP_TLV_RESULT_SUCCESS) { 59339beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Success " 59439beb93cSSam Leffler "- EAP-TLV/Phase2 Completed"); 59539beb93cSSam Leffler if (force_failure) { 59639beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TLV: Earlier failure" 59739beb93cSSam Leffler " - force failed Phase 2"); 59839beb93cSSam Leffler resp_status = EAP_TLV_RESULT_FAILURE; 59939beb93cSSam Leffler ret->decision = DECISION_FAIL; 600*a90b9d01SCy Schubert } else if (!peap_phase2_sufficient(sm, data)) { 601*a90b9d01SCy Schubert wpa_printf(MSG_INFO, 602*a90b9d01SCy Schubert "EAP-PEAP: Server indicated Phase 2 success, but sufficient Phase 2 authentication has not been completed"); 603*a90b9d01SCy Schubert resp_status = EAP_TLV_RESULT_FAILURE; 604*a90b9d01SCy Schubert ret->decision = DECISION_FAIL; 60539beb93cSSam Leffler } else { 60639beb93cSSam Leffler resp_status = EAP_TLV_RESULT_SUCCESS; 60739beb93cSSam Leffler ret->decision = DECISION_UNCOND_SUCC; 60839beb93cSSam Leffler } 60939beb93cSSam Leffler } else if (status == EAP_TLV_RESULT_FAILURE) { 61039beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Failure"); 61139beb93cSSam Leffler resp_status = EAP_TLV_RESULT_FAILURE; 61239beb93cSSam Leffler ret->decision = DECISION_FAIL; 61339beb93cSSam Leffler } else { 61439beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-TLV: Unknown TLV Result " 61539beb93cSSam Leffler "Status %d", status); 61639beb93cSSam Leffler resp_status = EAP_TLV_RESULT_FAILURE; 61739beb93cSSam Leffler ret->decision = DECISION_FAIL; 61839beb93cSSam Leffler } 61939beb93cSSam Leffler ret->methodState = METHOD_DONE; 62039beb93cSSam Leffler 62139beb93cSSam Leffler *resp = eap_tlv_build_result(sm, data, crypto_tlv != NULL, 62239beb93cSSam Leffler eap_get_id(req), resp_status); 62339beb93cSSam Leffler } 62439beb93cSSam Leffler 62539beb93cSSam Leffler return 0; 62639beb93cSSam Leffler } 62739beb93cSSam Leffler 62839beb93cSSam Leffler 62939beb93cSSam Leffler static int eap_peap_phase2_request(struct eap_sm *sm, 63039beb93cSSam Leffler struct eap_peap_data *data, 63139beb93cSSam Leffler struct eap_method_ret *ret, 63239beb93cSSam Leffler struct wpabuf *req, 63339beb93cSSam Leffler struct wpabuf **resp) 63439beb93cSSam Leffler { 63539beb93cSSam Leffler struct eap_hdr *hdr = wpabuf_mhead(req); 63639beb93cSSam Leffler size_t len = be_to_host16(hdr->length); 63739beb93cSSam Leffler u8 *pos; 63839beb93cSSam Leffler struct eap_method_ret iret; 63939beb93cSSam Leffler struct eap_peer_config *config = eap_get_config(sm); 640c1d255d3SCy Schubert int vendor; 641c1d255d3SCy Schubert enum eap_type method; 64239beb93cSSam Leffler 64339beb93cSSam Leffler if (len <= sizeof(struct eap_hdr)) { 64439beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-PEAP: too short " 64539beb93cSSam Leffler "Phase 2 request (len=%lu)", (unsigned long) len); 64639beb93cSSam Leffler return -1; 64739beb93cSSam Leffler } 64839beb93cSSam Leffler pos = (u8 *) (hdr + 1); 64939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Request: type=%d", *pos); 65039beb93cSSam Leffler switch (*pos) { 65139beb93cSSam Leffler case EAP_TYPE_IDENTITY: 65239beb93cSSam Leffler *resp = eap_sm_buildIdentity(sm, hdr->identifier, 1); 65339beb93cSSam Leffler break; 65439beb93cSSam Leffler case EAP_TYPE_TLV: 65539beb93cSSam Leffler os_memset(&iret, 0, sizeof(iret)); 65639beb93cSSam Leffler if (eap_tlv_process(sm, data, &iret, req, resp, 65739beb93cSSam Leffler data->phase2_eap_started && 65839beb93cSSam Leffler !data->phase2_eap_success)) { 65939beb93cSSam Leffler ret->methodState = METHOD_DONE; 66039beb93cSSam Leffler ret->decision = DECISION_FAIL; 66139beb93cSSam Leffler return -1; 66239beb93cSSam Leffler } 66339beb93cSSam Leffler if (iret.methodState == METHOD_DONE || 66439beb93cSSam Leffler iret.methodState == METHOD_MAY_CONT) { 66539beb93cSSam Leffler ret->methodState = iret.methodState; 66639beb93cSSam Leffler ret->decision = iret.decision; 66739beb93cSSam Leffler data->phase2_success = 1; 66839beb93cSSam Leffler } 66939beb93cSSam Leffler break; 67039beb93cSSam Leffler case EAP_TYPE_EXPANDED: 67139beb93cSSam Leffler #ifdef EAP_TNC 67239beb93cSSam Leffler if (data->soh) { 67339beb93cSSam Leffler const u8 *epos; 67439beb93cSSam Leffler size_t eleft; 67539beb93cSSam Leffler 67639beb93cSSam Leffler epos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21, 67739beb93cSSam Leffler req, &eleft); 67839beb93cSSam Leffler if (epos) { 67939beb93cSSam Leffler struct wpabuf *buf; 68039beb93cSSam Leffler wpa_printf(MSG_DEBUG, 68139beb93cSSam Leffler "EAP-PEAP: SoH EAP Extensions"); 68239beb93cSSam Leffler buf = tncc_process_soh_request(data->soh, 68339beb93cSSam Leffler epos, eleft); 68439beb93cSSam Leffler if (buf) { 68539beb93cSSam Leffler *resp = eap_msg_alloc( 68639beb93cSSam Leffler EAP_VENDOR_MICROSOFT, 0x21, 68739beb93cSSam Leffler wpabuf_len(buf), 68839beb93cSSam Leffler EAP_CODE_RESPONSE, 68939beb93cSSam Leffler hdr->identifier); 69039beb93cSSam Leffler if (*resp == NULL) { 69139beb93cSSam Leffler ret->methodState = METHOD_DONE; 69239beb93cSSam Leffler ret->decision = DECISION_FAIL; 6934bc52338SCy Schubert wpabuf_clear_free(buf); 69439beb93cSSam Leffler return -1; 69539beb93cSSam Leffler } 69639beb93cSSam Leffler wpabuf_put_buf(*resp, buf); 6974bc52338SCy Schubert wpabuf_clear_free(buf); 69839beb93cSSam Leffler break; 69939beb93cSSam Leffler } 70039beb93cSSam Leffler } 70139beb93cSSam Leffler } 70239beb93cSSam Leffler #endif /* EAP_TNC */ 70339beb93cSSam Leffler /* fall through */ 70439beb93cSSam Leffler default: 705c1d255d3SCy Schubert vendor = EAP_VENDOR_IETF; 706c1d255d3SCy Schubert method = *pos; 707c1d255d3SCy Schubert 708c1d255d3SCy Schubert if (method == EAP_TYPE_EXPANDED) { 709c1d255d3SCy Schubert if (len < sizeof(struct eap_hdr) + 8) { 710c1d255d3SCy Schubert wpa_printf(MSG_INFO, 711c1d255d3SCy Schubert "EAP-PEAP: Too short Phase 2 request (expanded header) (len=%lu)", 712c1d255d3SCy Schubert (unsigned long) len); 713c1d255d3SCy Schubert return -1; 714c1d255d3SCy Schubert } 715c1d255d3SCy Schubert vendor = WPA_GET_BE24(pos + 1); 716c1d255d3SCy Schubert method = WPA_GET_BE32(pos + 4); 717c1d255d3SCy Schubert } 718c1d255d3SCy Schubert 71939beb93cSSam Leffler if (data->phase2_type.vendor == EAP_VENDOR_IETF && 72039beb93cSSam Leffler data->phase2_type.method == EAP_TYPE_NONE) { 72139beb93cSSam Leffler size_t i; 72239beb93cSSam Leffler for (i = 0; i < data->num_phase2_types; i++) { 723c1d255d3SCy Schubert if (data->phase2_types[i].vendor != vendor || 724c1d255d3SCy Schubert data->phase2_types[i].method != method) 72539beb93cSSam Leffler continue; 72639beb93cSSam Leffler 72739beb93cSSam Leffler data->phase2_type.vendor = 72839beb93cSSam Leffler data->phase2_types[i].vendor; 72939beb93cSSam Leffler data->phase2_type.method = 73039beb93cSSam Leffler data->phase2_types[i].method; 73139beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: Selected " 73239beb93cSSam Leffler "Phase 2 EAP vendor %d method %d", 73339beb93cSSam Leffler data->phase2_type.vendor, 73439beb93cSSam Leffler data->phase2_type.method); 73539beb93cSSam Leffler break; 73639beb93cSSam Leffler } 73739beb93cSSam Leffler } 738c1d255d3SCy Schubert if (vendor != data->phase2_type.vendor || 739c1d255d3SCy Schubert method != data->phase2_type.method || 740c1d255d3SCy Schubert (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_NONE)) { 74139beb93cSSam Leffler if (eap_peer_tls_phase2_nak(data->phase2_types, 74239beb93cSSam Leffler data->num_phase2_types, 74339beb93cSSam Leffler hdr, resp)) 74439beb93cSSam Leffler return -1; 74539beb93cSSam Leffler return 0; 74639beb93cSSam Leffler } 74739beb93cSSam Leffler 74839beb93cSSam Leffler if (data->phase2_priv == NULL) { 74939beb93cSSam Leffler data->phase2_method = eap_peer_get_eap_method( 75039beb93cSSam Leffler data->phase2_type.vendor, 75139beb93cSSam Leffler data->phase2_type.method); 75239beb93cSSam Leffler if (data->phase2_method) { 75339beb93cSSam Leffler sm->init_phase2 = 1; 75439beb93cSSam Leffler data->phase2_priv = 75539beb93cSSam Leffler data->phase2_method->init(sm); 75639beb93cSSam Leffler sm->init_phase2 = 0; 75739beb93cSSam Leffler } 75839beb93cSSam Leffler } 75939beb93cSSam Leffler if (data->phase2_priv == NULL || data->phase2_method == NULL) { 76039beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-PEAP: failed to initialize " 76139beb93cSSam Leffler "Phase 2 EAP method %d", *pos); 76239beb93cSSam Leffler ret->methodState = METHOD_DONE; 76339beb93cSSam Leffler ret->decision = DECISION_FAIL; 76439beb93cSSam Leffler return -1; 76539beb93cSSam Leffler } 76639beb93cSSam Leffler data->phase2_eap_started = 1; 76739beb93cSSam Leffler os_memset(&iret, 0, sizeof(iret)); 76839beb93cSSam Leffler *resp = data->phase2_method->process(sm, data->phase2_priv, 76939beb93cSSam Leffler &iret, req); 77039beb93cSSam Leffler if ((iret.methodState == METHOD_DONE || 77139beb93cSSam Leffler iret.methodState == METHOD_MAY_CONT) && 77239beb93cSSam Leffler (iret.decision == DECISION_UNCOND_SUCC || 77339beb93cSSam Leffler iret.decision == DECISION_COND_SUCC)) { 77439beb93cSSam Leffler data->phase2_eap_success = 1; 77539beb93cSSam Leffler data->phase2_success = 1; 77639beb93cSSam Leffler } 77739beb93cSSam Leffler break; 77839beb93cSSam Leffler } 77939beb93cSSam Leffler 78039beb93cSSam Leffler if (*resp == NULL && 78139beb93cSSam Leffler (config->pending_req_identity || config->pending_req_password || 78285732ac8SCy Schubert config->pending_req_otp || config->pending_req_new_password || 78385732ac8SCy Schubert config->pending_req_sim)) { 7844bc52338SCy Schubert wpabuf_clear_free(data->pending_phase2_req); 78539beb93cSSam Leffler data->pending_phase2_req = wpabuf_alloc_copy(hdr, len); 78639beb93cSSam Leffler } 78739beb93cSSam Leffler 78839beb93cSSam Leffler return 0; 78939beb93cSSam Leffler } 79039beb93cSSam Leffler 79139beb93cSSam Leffler 79239beb93cSSam Leffler static int eap_peap_decrypt(struct eap_sm *sm, struct eap_peap_data *data, 79339beb93cSSam Leffler struct eap_method_ret *ret, 79439beb93cSSam Leffler const struct eap_hdr *req, 79539beb93cSSam Leffler const struct wpabuf *in_data, 79639beb93cSSam Leffler struct wpabuf **out_data) 79739beb93cSSam Leffler { 79839beb93cSSam Leffler struct wpabuf *in_decrypted = NULL; 79939beb93cSSam Leffler int res, skip_change = 0; 80039beb93cSSam Leffler struct eap_hdr *hdr, *rhdr; 80139beb93cSSam Leffler struct wpabuf *resp = NULL; 80239beb93cSSam Leffler size_t len; 80339beb93cSSam Leffler 80439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for" 80539beb93cSSam Leffler " Phase 2", (unsigned long) wpabuf_len(in_data)); 80639beb93cSSam Leffler 80739beb93cSSam Leffler if (data->pending_phase2_req) { 80839beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 request - " 80939beb93cSSam Leffler "skip decryption and use old data"); 81039beb93cSSam Leffler /* Clear TLS reassembly state. */ 81139beb93cSSam Leffler eap_peer_tls_reset_input(&data->ssl); 81239beb93cSSam Leffler in_decrypted = data->pending_phase2_req; 81339beb93cSSam Leffler data->pending_phase2_req = NULL; 81439beb93cSSam Leffler skip_change = 1; 81539beb93cSSam Leffler goto continue_req; 81639beb93cSSam Leffler } 81739beb93cSSam Leffler 81839beb93cSSam Leffler if (wpabuf_len(in_data) == 0 && sm->workaround && 81939beb93cSSam Leffler data->phase2_success) { 82039beb93cSSam Leffler /* 82139beb93cSSam Leffler * Cisco ACS seems to be using TLS ACK to terminate 82239beb93cSSam Leffler * EAP-PEAPv0/GTC. Try to reply with TLS ACK. 82339beb93cSSam Leffler */ 82439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: Received TLS ACK, but " 82539beb93cSSam Leffler "expected data - acknowledge with TLS ACK since " 82639beb93cSSam Leffler "Phase 2 has been completed"); 82739beb93cSSam Leffler ret->decision = DECISION_COND_SUCC; 82839beb93cSSam Leffler ret->methodState = METHOD_DONE; 82939beb93cSSam Leffler return 1; 83039beb93cSSam Leffler } else if (wpabuf_len(in_data) == 0) { 83139beb93cSSam Leffler /* Received TLS ACK - requesting more fragments */ 83239beb93cSSam Leffler return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP, 83339beb93cSSam Leffler data->peap_version, 83439beb93cSSam Leffler req->identifier, NULL, out_data); 83539beb93cSSam Leffler } 83639beb93cSSam Leffler 83739beb93cSSam Leffler res = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted); 83839beb93cSSam Leffler if (res) 83939beb93cSSam Leffler return res; 840c1d255d3SCy Schubert if (wpabuf_len(in_decrypted) == 0) { 841c1d255d3SCy Schubert wpabuf_free(in_decrypted); 842c1d255d3SCy Schubert return 1; 843c1d255d3SCy Schubert } 84439beb93cSSam Leffler 84539beb93cSSam Leffler continue_req: 84639beb93cSSam Leffler wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP", 84739beb93cSSam Leffler in_decrypted); 84839beb93cSSam Leffler 84939beb93cSSam Leffler hdr = wpabuf_mhead(in_decrypted); 85039beb93cSSam Leffler if (wpabuf_len(in_decrypted) == 5 && hdr->code == EAP_CODE_REQUEST && 85139beb93cSSam Leffler be_to_host16(hdr->length) == 5 && 85239beb93cSSam Leffler eap_get_type(in_decrypted) == EAP_TYPE_IDENTITY) { 85339beb93cSSam Leffler /* At least FreeRADIUS seems to send full EAP header with 85439beb93cSSam Leffler * EAP Request Identity */ 85539beb93cSSam Leffler skip_change = 1; 85639beb93cSSam Leffler } 85739beb93cSSam Leffler if (wpabuf_len(in_decrypted) >= 5 && hdr->code == EAP_CODE_REQUEST && 85839beb93cSSam Leffler eap_get_type(in_decrypted) == EAP_TYPE_TLV) { 85939beb93cSSam Leffler skip_change = 1; 86039beb93cSSam Leffler } 86139beb93cSSam Leffler 86239beb93cSSam Leffler if (data->peap_version == 0 && !skip_change) { 86339beb93cSSam Leffler struct eap_hdr *nhdr; 86439beb93cSSam Leffler struct wpabuf *nmsg = wpabuf_alloc(sizeof(struct eap_hdr) + 86539beb93cSSam Leffler wpabuf_len(in_decrypted)); 86639beb93cSSam Leffler if (nmsg == NULL) { 8674bc52338SCy Schubert wpabuf_clear_free(in_decrypted); 86839beb93cSSam Leffler return 0; 86939beb93cSSam Leffler } 87039beb93cSSam Leffler nhdr = wpabuf_put(nmsg, sizeof(*nhdr)); 87139beb93cSSam Leffler wpabuf_put_buf(nmsg, in_decrypted); 87239beb93cSSam Leffler nhdr->code = req->code; 87339beb93cSSam Leffler nhdr->identifier = req->identifier; 87439beb93cSSam Leffler nhdr->length = host_to_be16(sizeof(struct eap_hdr) + 87539beb93cSSam Leffler wpabuf_len(in_decrypted)); 87639beb93cSSam Leffler 8774bc52338SCy Schubert wpabuf_clear_free(in_decrypted); 87839beb93cSSam Leffler in_decrypted = nmsg; 87939beb93cSSam Leffler } 88039beb93cSSam Leffler 88139beb93cSSam Leffler hdr = wpabuf_mhead(in_decrypted); 88239beb93cSSam Leffler if (wpabuf_len(in_decrypted) < sizeof(*hdr)) { 88339beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 " 88439beb93cSSam Leffler "EAP frame (len=%lu)", 88539beb93cSSam Leffler (unsigned long) wpabuf_len(in_decrypted)); 8864bc52338SCy Schubert wpabuf_clear_free(in_decrypted); 88739beb93cSSam Leffler return 0; 88839beb93cSSam Leffler } 88939beb93cSSam Leffler len = be_to_host16(hdr->length); 89039beb93cSSam Leffler if (len > wpabuf_len(in_decrypted)) { 89139beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in " 89239beb93cSSam Leffler "Phase 2 EAP frame (len=%lu hdr->length=%lu)", 89339beb93cSSam Leffler (unsigned long) wpabuf_len(in_decrypted), 89439beb93cSSam Leffler (unsigned long) len); 8954bc52338SCy Schubert wpabuf_clear_free(in_decrypted); 89639beb93cSSam Leffler return 0; 89739beb93cSSam Leffler } 89839beb93cSSam Leffler if (len < wpabuf_len(in_decrypted)) { 89939beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-PEAP: Odd.. Phase 2 EAP header has " 90039beb93cSSam Leffler "shorter length than full decrypted data " 90139beb93cSSam Leffler "(%lu < %lu)", 90239beb93cSSam Leffler (unsigned long) len, 90339beb93cSSam Leffler (unsigned long) wpabuf_len(in_decrypted)); 90439beb93cSSam Leffler } 90539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d " 90639beb93cSSam Leffler "identifier=%d length=%lu", hdr->code, hdr->identifier, 90739beb93cSSam Leffler (unsigned long) len); 90839beb93cSSam Leffler switch (hdr->code) { 90939beb93cSSam Leffler case EAP_CODE_REQUEST: 91039beb93cSSam Leffler if (eap_peap_phase2_request(sm, data, ret, in_decrypted, 91139beb93cSSam Leffler &resp)) { 9124bc52338SCy Schubert wpabuf_clear_free(in_decrypted); 91339beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-PEAP: Phase2 Request " 91439beb93cSSam Leffler "processing failed"); 91539beb93cSSam Leffler return 0; 91639beb93cSSam Leffler } 91739beb93cSSam Leffler break; 91839beb93cSSam Leffler case EAP_CODE_SUCCESS: 91939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success"); 92039beb93cSSam Leffler if (data->peap_version == 1) { 92139beb93cSSam Leffler /* EAP-Success within TLS tunnel is used to indicate 92239beb93cSSam Leffler * shutdown of the TLS channel. The authentication has 92339beb93cSSam Leffler * been completed. */ 924*a90b9d01SCy Schubert if (!peap_phase2_sufficient(sm, data)) { 92539beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 " 92639beb93cSSam Leffler "Success used to indicate success, " 92739beb93cSSam Leffler "but Phase 2 EAP was not yet " 92839beb93cSSam Leffler "completed successfully"); 92939beb93cSSam Leffler ret->methodState = METHOD_DONE; 93039beb93cSSam Leffler ret->decision = DECISION_FAIL; 9314bc52338SCy Schubert wpabuf_clear_free(in_decrypted); 93239beb93cSSam Leffler return 0; 93339beb93cSSam Leffler } 93439beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: Version 1 - " 93539beb93cSSam Leffler "EAP-Success within TLS tunnel - " 93639beb93cSSam Leffler "authentication completed"); 93739beb93cSSam Leffler ret->decision = DECISION_UNCOND_SUCC; 93839beb93cSSam Leffler ret->methodState = METHOD_DONE; 93939beb93cSSam Leffler data->phase2_success = 1; 94039beb93cSSam Leffler if (data->peap_outer_success == 2) { 9414bc52338SCy Schubert wpabuf_clear_free(in_decrypted); 94239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: Use TLS ACK " 94339beb93cSSam Leffler "to finish authentication"); 94439beb93cSSam Leffler return 1; 94539beb93cSSam Leffler } else if (data->peap_outer_success == 1) { 94639beb93cSSam Leffler /* Reply with EAP-Success within the TLS 94739beb93cSSam Leffler * channel to complete the authentication. */ 94839beb93cSSam Leffler resp = wpabuf_alloc(sizeof(struct eap_hdr)); 94939beb93cSSam Leffler if (resp) { 95039beb93cSSam Leffler rhdr = wpabuf_put(resp, sizeof(*rhdr)); 95139beb93cSSam Leffler rhdr->code = EAP_CODE_SUCCESS; 95239beb93cSSam Leffler rhdr->identifier = hdr->identifier; 95339beb93cSSam Leffler rhdr->length = 95439beb93cSSam Leffler host_to_be16(sizeof(*rhdr)); 95539beb93cSSam Leffler } 95639beb93cSSam Leffler } else { 95739beb93cSSam Leffler /* No EAP-Success expected for Phase 1 (outer, 95839beb93cSSam Leffler * unencrypted auth), so force EAP state 95939beb93cSSam Leffler * machine to SUCCESS state. */ 960c1d255d3SCy Schubert sm->peap_done = true; 96139beb93cSSam Leffler } 96239beb93cSSam Leffler } else { 96339beb93cSSam Leffler /* FIX: ? */ 96439beb93cSSam Leffler } 96539beb93cSSam Leffler break; 96639beb93cSSam Leffler case EAP_CODE_FAILURE: 96739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure"); 96839beb93cSSam Leffler ret->decision = DECISION_FAIL; 96939beb93cSSam Leffler ret->methodState = METHOD_MAY_CONT; 970c1d255d3SCy Schubert ret->allowNotifications = false; 97139beb93cSSam Leffler /* Reply with EAP-Failure within the TLS channel to complete 97239beb93cSSam Leffler * failure reporting. */ 97339beb93cSSam Leffler resp = wpabuf_alloc(sizeof(struct eap_hdr)); 97439beb93cSSam Leffler if (resp) { 97539beb93cSSam Leffler rhdr = wpabuf_put(resp, sizeof(*rhdr)); 97639beb93cSSam Leffler rhdr->code = EAP_CODE_FAILURE; 97739beb93cSSam Leffler rhdr->identifier = hdr->identifier; 97839beb93cSSam Leffler rhdr->length = host_to_be16(sizeof(*rhdr)); 97939beb93cSSam Leffler } 98039beb93cSSam Leffler break; 98139beb93cSSam Leffler default: 98239beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in " 98339beb93cSSam Leffler "Phase 2 EAP header", hdr->code); 98439beb93cSSam Leffler break; 98539beb93cSSam Leffler } 98639beb93cSSam Leffler 9874bc52338SCy Schubert wpabuf_clear_free(in_decrypted); 98839beb93cSSam Leffler 98939beb93cSSam Leffler if (resp) { 99039beb93cSSam Leffler int skip_change2 = 0; 99139beb93cSSam Leffler struct wpabuf *rmsg, buf; 99239beb93cSSam Leffler 99339beb93cSSam Leffler wpa_hexdump_buf_key(MSG_DEBUG, 99439beb93cSSam Leffler "EAP-PEAP: Encrypting Phase 2 data", resp); 99539beb93cSSam Leffler /* PEAP version changes */ 99639beb93cSSam Leffler if (wpabuf_len(resp) >= 5 && 99739beb93cSSam Leffler wpabuf_head_u8(resp)[0] == EAP_CODE_RESPONSE && 99839beb93cSSam Leffler eap_get_type(resp) == EAP_TYPE_TLV) 99939beb93cSSam Leffler skip_change2 = 1; 100039beb93cSSam Leffler rmsg = resp; 100139beb93cSSam Leffler if (data->peap_version == 0 && !skip_change2) { 100239beb93cSSam Leffler wpabuf_set(&buf, wpabuf_head_u8(resp) + 100339beb93cSSam Leffler sizeof(struct eap_hdr), 100439beb93cSSam Leffler wpabuf_len(resp) - sizeof(struct eap_hdr)); 100539beb93cSSam Leffler rmsg = &buf; 100639beb93cSSam Leffler } 100739beb93cSSam Leffler 100839beb93cSSam Leffler if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP, 100939beb93cSSam Leffler data->peap_version, req->identifier, 101039beb93cSSam Leffler rmsg, out_data)) { 101139beb93cSSam Leffler wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt " 101239beb93cSSam Leffler "a Phase 2 frame"); 101339beb93cSSam Leffler } 10144bc52338SCy Schubert wpabuf_clear_free(resp); 101539beb93cSSam Leffler } 101639beb93cSSam Leffler 101739beb93cSSam Leffler return 0; 101839beb93cSSam Leffler } 101939beb93cSSam Leffler 102039beb93cSSam Leffler 102139beb93cSSam Leffler static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv, 102239beb93cSSam Leffler struct eap_method_ret *ret, 102339beb93cSSam Leffler const struct wpabuf *reqData) 102439beb93cSSam Leffler { 102539beb93cSSam Leffler const struct eap_hdr *req; 102639beb93cSSam Leffler size_t left; 102739beb93cSSam Leffler int res; 102839beb93cSSam Leffler u8 flags, id; 102939beb93cSSam Leffler struct wpabuf *resp; 103039beb93cSSam Leffler const u8 *pos; 103139beb93cSSam Leffler struct eap_peap_data *data = priv; 1032325151a3SRui Paulo struct wpabuf msg; 103339beb93cSSam Leffler 103439beb93cSSam Leffler pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_PEAP, ret, 103539beb93cSSam Leffler reqData, &left, &flags); 103639beb93cSSam Leffler if (pos == NULL) 103739beb93cSSam Leffler return NULL; 103839beb93cSSam Leffler req = wpabuf_head(reqData); 103939beb93cSSam Leffler id = req->identifier; 104039beb93cSSam Leffler 104139beb93cSSam Leffler if (flags & EAP_TLS_FLAGS_START) { 104239beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: Start (server ver=%d, own " 1043e28a4053SRui Paulo "ver=%d)", flags & EAP_TLS_VERSION_MASK, 104439beb93cSSam Leffler data->peap_version); 1045e28a4053SRui Paulo if ((flags & EAP_TLS_VERSION_MASK) < data->peap_version) 1046e28a4053SRui Paulo data->peap_version = flags & EAP_TLS_VERSION_MASK; 104739beb93cSSam Leffler if (data->force_peap_version >= 0 && 104839beb93cSSam Leffler data->force_peap_version != data->peap_version) { 104939beb93cSSam Leffler wpa_printf(MSG_WARNING, "EAP-PEAP: Failed to select " 105039beb93cSSam Leffler "forced PEAP version %d", 105139beb93cSSam Leffler data->force_peap_version); 105239beb93cSSam Leffler ret->methodState = METHOD_DONE; 105339beb93cSSam Leffler ret->decision = DECISION_FAIL; 1054c1d255d3SCy Schubert ret->allowNotifications = false; 105539beb93cSSam Leffler return NULL; 105639beb93cSSam Leffler } 105739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: Using PEAP version %d", 105839beb93cSSam Leffler data->peap_version); 105939beb93cSSam Leffler left = 0; /* make sure that this frame is empty, even though it 106039beb93cSSam Leffler * should always be, anyway */ 106139beb93cSSam Leffler } 106239beb93cSSam Leffler 1063325151a3SRui Paulo wpabuf_set(&msg, pos, left); 1064325151a3SRui Paulo 106539beb93cSSam Leffler resp = NULL; 106639beb93cSSam Leffler if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) && 106739beb93cSSam Leffler !data->resuming) { 106839beb93cSSam Leffler res = eap_peap_decrypt(sm, data, ret, req, &msg, &resp); 106939beb93cSSam Leffler } else { 1070780fb4a2SCy Schubert if (sm->waiting_ext_cert_check && data->pending_resp) { 1071780fb4a2SCy Schubert struct eap_peer_config *config = eap_get_config(sm); 1072780fb4a2SCy Schubert 1073780fb4a2SCy Schubert if (config->pending_ext_cert_check == 1074780fb4a2SCy Schubert EXT_CERT_CHECK_GOOD) { 1075780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, 1076780fb4a2SCy Schubert "EAP-PEAP: External certificate check succeeded - continue handshake"); 1077780fb4a2SCy Schubert resp = data->pending_resp; 1078780fb4a2SCy Schubert data->pending_resp = NULL; 1079780fb4a2SCy Schubert sm->waiting_ext_cert_check = 0; 1080780fb4a2SCy Schubert return resp; 1081780fb4a2SCy Schubert } 1082780fb4a2SCy Schubert 1083780fb4a2SCy Schubert if (config->pending_ext_cert_check == 1084780fb4a2SCy Schubert EXT_CERT_CHECK_BAD) { 1085780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, 1086780fb4a2SCy Schubert "EAP-PEAP: External certificate check failed - force authentication failure"); 1087780fb4a2SCy Schubert ret->methodState = METHOD_DONE; 1088780fb4a2SCy Schubert ret->decision = DECISION_FAIL; 1089780fb4a2SCy Schubert sm->waiting_ext_cert_check = 0; 1090780fb4a2SCy Schubert return NULL; 1091780fb4a2SCy Schubert } 1092780fb4a2SCy Schubert 1093780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, 1094780fb4a2SCy Schubert "EAP-PEAP: Continuing to wait external server certificate validation"); 1095780fb4a2SCy Schubert return NULL; 1096780fb4a2SCy Schubert } 1097780fb4a2SCy Schubert 109839beb93cSSam Leffler res = eap_peer_tls_process_helper(sm, &data->ssl, 109939beb93cSSam Leffler EAP_TYPE_PEAP, 1100325151a3SRui Paulo data->peap_version, id, &msg, 1101325151a3SRui Paulo &resp); 110239beb93cSSam Leffler 1103325151a3SRui Paulo if (res < 0) { 1104325151a3SRui Paulo wpa_printf(MSG_DEBUG, 1105325151a3SRui Paulo "EAP-PEAP: TLS processing failed"); 1106325151a3SRui Paulo ret->methodState = METHOD_DONE; 1107325151a3SRui Paulo ret->decision = DECISION_FAIL; 1108325151a3SRui Paulo return resp; 1109325151a3SRui Paulo } 1110780fb4a2SCy Schubert 1111780fb4a2SCy Schubert 1112780fb4a2SCy Schubert if (sm->waiting_ext_cert_check) { 1113780fb4a2SCy Schubert wpa_printf(MSG_DEBUG, 1114780fb4a2SCy Schubert "EAP-PEAP: Waiting external server certificate validation"); 11154bc52338SCy Schubert wpabuf_clear_free(data->pending_resp); 1116780fb4a2SCy Schubert data->pending_resp = resp; 1117780fb4a2SCy Schubert return NULL; 1118780fb4a2SCy Schubert } 1119780fb4a2SCy Schubert 112039beb93cSSam Leffler if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { 1121c1d255d3SCy Schubert const char *label; 1122c1d255d3SCy Schubert const u8 eap_tls13_context[1] = { EAP_TYPE_PEAP }; 1123c1d255d3SCy Schubert const u8 *context = NULL; 1124c1d255d3SCy Schubert size_t context_len = 0; 1125c1d255d3SCy Schubert 112639beb93cSSam Leffler wpa_printf(MSG_DEBUG, 112739beb93cSSam Leffler "EAP-PEAP: TLS done, proceed to Phase 2"); 11285b9c547cSRui Paulo eap_peap_free_key(data); 112939beb93cSSam Leffler /* draft-josefsson-ppext-eap-tls-eap-05.txt 113039beb93cSSam Leffler * specifies that PEAPv1 would use "client PEAP 113139beb93cSSam Leffler * encryption" as the label. However, most existing 113239beb93cSSam Leffler * PEAPv1 implementations seem to be using the old 113339beb93cSSam Leffler * label, "client EAP encryption", instead. Use the old 113439beb93cSSam Leffler * label by default, but allow it to be configured with 1135c1d255d3SCy Schubert * phase1 parameter peaplabel=1. 1136c1d255d3SCy Schubert * 1137c1d255d3SCy Schubert * When using TLS 1.3, draft-ietf-emu-tls-eap-types 1138c1d255d3SCy Schubert * defines a new set of label and context parameters. 1139c1d255d3SCy Schubert */ 1140c1d255d3SCy Schubert if (data->ssl.tls_v13) { 1141c1d255d3SCy Schubert label = "EXPORTER_EAP_TLS_Key_Material"; 1142c1d255d3SCy Schubert context = eap_tls13_context; 1143c1d255d3SCy Schubert context_len = sizeof(eap_tls13_context); 1144c1d255d3SCy Schubert } else if (data->force_new_label) { 114539beb93cSSam Leffler label = "client PEAP encryption"; 1146c1d255d3SCy Schubert } else { 114739beb93cSSam Leffler label = "client EAP encryption"; 1148c1d255d3SCy Schubert } 114939beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: using label '%s' in " 115039beb93cSSam Leffler "key derivation", label); 115139beb93cSSam Leffler data->key_data = 115239beb93cSSam Leffler eap_peer_tls_derive_key(sm, &data->ssl, label, 1153c1d255d3SCy Schubert context, context_len, 11544bc52338SCy Schubert EAP_TLS_KEY_LEN + 11554bc52338SCy Schubert EAP_EMSK_LEN); 115639beb93cSSam Leffler if (data->key_data) { 115739beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, 115839beb93cSSam Leffler "EAP-PEAP: Derived key", 115939beb93cSSam Leffler data->key_data, 116039beb93cSSam Leffler EAP_TLS_KEY_LEN); 11614bc52338SCy Schubert wpa_hexdump_key(MSG_DEBUG, 11624bc52338SCy Schubert "EAP-PEAP: Derived EMSK", 11634bc52338SCy Schubert data->key_data + 11644bc52338SCy Schubert EAP_TLS_KEY_LEN, 11654bc52338SCy Schubert EAP_EMSK_LEN); 116639beb93cSSam Leffler } else { 116739beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to " 116839beb93cSSam Leffler "derive key"); 116939beb93cSSam Leffler } 117039beb93cSSam Leffler 11715b9c547cSRui Paulo os_free(data->session_id); 11725b9c547cSRui Paulo data->session_id = 11735b9c547cSRui Paulo eap_peer_tls_derive_session_id(sm, &data->ssl, 11745b9c547cSRui Paulo EAP_TYPE_PEAP, 11755b9c547cSRui Paulo &data->id_len); 11765b9c547cSRui Paulo if (data->session_id) { 11775b9c547cSRui Paulo wpa_hexdump(MSG_DEBUG, 11785b9c547cSRui Paulo "EAP-PEAP: Derived Session-Id", 11795b9c547cSRui Paulo data->session_id, data->id_len); 11805b9c547cSRui Paulo } else { 11815b9c547cSRui Paulo wpa_printf(MSG_ERROR, "EAP-PEAP: Failed to " 11825b9c547cSRui Paulo "derive Session-Id"); 11835b9c547cSRui Paulo } 11845b9c547cSRui Paulo 118539beb93cSSam Leffler if (sm->workaround && data->resuming) { 118639beb93cSSam Leffler /* 118739beb93cSSam Leffler * At least few RADIUS servers (Aegis v1.1.6; 118839beb93cSSam Leffler * but not v1.1.4; and Cisco ACS) seem to be 118939beb93cSSam Leffler * terminating PEAPv1 (Aegis) or PEAPv0 (Cisco 119039beb93cSSam Leffler * ACS) session resumption with outer 119139beb93cSSam Leffler * EAP-Success. This does not seem to follow 119239beb93cSSam Leffler * draft-josefsson-pppext-eap-tls-eap-05.txt 119339beb93cSSam Leffler * section 4.2, so only allow this if EAP 119439beb93cSSam Leffler * workarounds are enabled. 119539beb93cSSam Leffler */ 119639beb93cSSam Leffler wpa_printf(MSG_DEBUG, "EAP-PEAP: Workaround - " 119739beb93cSSam Leffler "allow outer EAP-Success to " 119839beb93cSSam Leffler "terminate PEAP resumption"); 119939beb93cSSam Leffler ret->decision = DECISION_COND_SUCC; 120039beb93cSSam Leffler data->phase2_success = 1; 120139beb93cSSam Leffler } 120239beb93cSSam Leffler 120339beb93cSSam Leffler data->resuming = 0; 120439beb93cSSam Leffler } 120539beb93cSSam Leffler 120639beb93cSSam Leffler if (res == 2) { 120739beb93cSSam Leffler /* 120839beb93cSSam Leffler * Application data included in the handshake message. 120939beb93cSSam Leffler */ 12104bc52338SCy Schubert wpabuf_clear_free(data->pending_phase2_req); 121139beb93cSSam Leffler data->pending_phase2_req = resp; 121239beb93cSSam Leffler resp = NULL; 121339beb93cSSam Leffler res = eap_peap_decrypt(sm, data, ret, req, &msg, 121439beb93cSSam Leffler &resp); 121539beb93cSSam Leffler } 121639beb93cSSam Leffler } 121739beb93cSSam Leffler 121839beb93cSSam Leffler if (ret->methodState == METHOD_DONE) { 1219c1d255d3SCy Schubert ret->allowNotifications = false; 122039beb93cSSam Leffler } 122139beb93cSSam Leffler 122239beb93cSSam Leffler if (res == 1) { 12234bc52338SCy Schubert wpabuf_clear_free(resp); 122439beb93cSSam Leffler return eap_peer_tls_build_ack(id, EAP_TYPE_PEAP, 122539beb93cSSam Leffler data->peap_version); 122639beb93cSSam Leffler } 122739beb93cSSam Leffler 122839beb93cSSam Leffler return resp; 122939beb93cSSam Leffler } 123039beb93cSSam Leffler 123139beb93cSSam Leffler 1232c1d255d3SCy Schubert static bool eap_peap_has_reauth_data(struct eap_sm *sm, void *priv) 123339beb93cSSam Leffler { 123439beb93cSSam Leffler struct eap_peap_data *data = priv; 1235*a90b9d01SCy Schubert 123639beb93cSSam Leffler return tls_connection_established(sm->ssl_ctx, data->ssl.conn) && 1237*a90b9d01SCy Schubert data->phase2_success && data->phase2_auth != ALWAYS; 123839beb93cSSam Leffler } 123939beb93cSSam Leffler 124039beb93cSSam Leffler 124139beb93cSSam Leffler static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv) 124239beb93cSSam Leffler { 124339beb93cSSam Leffler struct eap_peap_data *data = priv; 124485732ac8SCy Schubert 124585732ac8SCy Schubert if (data->phase2_priv && data->phase2_method && 124685732ac8SCy Schubert data->phase2_method->deinit_for_reauth) 124785732ac8SCy Schubert data->phase2_method->deinit_for_reauth(sm, data->phase2_priv); 12484bc52338SCy Schubert wpabuf_clear_free(data->pending_phase2_req); 124939beb93cSSam Leffler data->pending_phase2_req = NULL; 12504bc52338SCy Schubert wpabuf_clear_free(data->pending_resp); 1251780fb4a2SCy Schubert data->pending_resp = NULL; 125239beb93cSSam Leffler data->crypto_binding_used = 0; 125339beb93cSSam Leffler } 125439beb93cSSam Leffler 125539beb93cSSam Leffler 125639beb93cSSam Leffler static void * eap_peap_init_for_reauth(struct eap_sm *sm, void *priv) 125739beb93cSSam Leffler { 125839beb93cSSam Leffler struct eap_peap_data *data = priv; 12595b9c547cSRui Paulo eap_peap_free_key(data); 12605b9c547cSRui Paulo os_free(data->session_id); 12615b9c547cSRui Paulo data->session_id = NULL; 126239beb93cSSam Leffler if (eap_peer_tls_reauth_init(sm, &data->ssl)) { 126339beb93cSSam Leffler os_free(data); 126439beb93cSSam Leffler return NULL; 126539beb93cSSam Leffler } 126639beb93cSSam Leffler if (data->phase2_priv && data->phase2_method && 126739beb93cSSam Leffler data->phase2_method->init_for_reauth) 126839beb93cSSam Leffler data->phase2_method->init_for_reauth(sm, data->phase2_priv); 126939beb93cSSam Leffler data->phase2_success = 0; 127039beb93cSSam Leffler data->phase2_eap_success = 0; 127139beb93cSSam Leffler data->phase2_eap_started = 0; 127239beb93cSSam Leffler data->resuming = 1; 127339beb93cSSam Leffler data->reauth = 1; 1274c1d255d3SCy Schubert sm->peap_done = false; 127539beb93cSSam Leffler return priv; 127639beb93cSSam Leffler } 127739beb93cSSam Leffler 127839beb93cSSam Leffler 127939beb93cSSam Leffler static int eap_peap_get_status(struct eap_sm *sm, void *priv, char *buf, 128039beb93cSSam Leffler size_t buflen, int verbose) 128139beb93cSSam Leffler { 128239beb93cSSam Leffler struct eap_peap_data *data = priv; 128339beb93cSSam Leffler int len, ret; 128439beb93cSSam Leffler 128539beb93cSSam Leffler len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose); 128639beb93cSSam Leffler if (data->phase2_method) { 128739beb93cSSam Leffler ret = os_snprintf(buf + len, buflen - len, 128839beb93cSSam Leffler "EAP-PEAPv%d Phase2 method=%s\n", 128939beb93cSSam Leffler data->peap_version, 129039beb93cSSam Leffler data->phase2_method->name); 12915b9c547cSRui Paulo if (os_snprintf_error(buflen - len, ret)) 129239beb93cSSam Leffler return len; 129339beb93cSSam Leffler len += ret; 129439beb93cSSam Leffler } 129539beb93cSSam Leffler return len; 129639beb93cSSam Leffler } 129739beb93cSSam Leffler 129839beb93cSSam Leffler 1299c1d255d3SCy Schubert static bool eap_peap_isKeyAvailable(struct eap_sm *sm, void *priv) 130039beb93cSSam Leffler { 130139beb93cSSam Leffler struct eap_peap_data *data = priv; 130239beb93cSSam Leffler return data->key_data != NULL && data->phase2_success; 130339beb93cSSam Leffler } 130439beb93cSSam Leffler 130539beb93cSSam Leffler 130639beb93cSSam Leffler static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len) 130739beb93cSSam Leffler { 130839beb93cSSam Leffler struct eap_peap_data *data = priv; 130939beb93cSSam Leffler u8 *key; 131039beb93cSSam Leffler 131139beb93cSSam Leffler if (data->key_data == NULL || !data->phase2_success) 131239beb93cSSam Leffler return NULL; 131339beb93cSSam Leffler 131439beb93cSSam Leffler key = os_malloc(EAP_TLS_KEY_LEN); 131539beb93cSSam Leffler if (key == NULL) 131639beb93cSSam Leffler return NULL; 131739beb93cSSam Leffler 131839beb93cSSam Leffler *len = EAP_TLS_KEY_LEN; 131939beb93cSSam Leffler 132039beb93cSSam Leffler if (data->crypto_binding_used) { 132139beb93cSSam Leffler u8 csk[128]; 132239beb93cSSam Leffler /* 132339beb93cSSam Leffler * Note: It looks like Microsoft implementation requires null 132439beb93cSSam Leffler * termination for this label while the one used for deriving 132539beb93cSSam Leffler * IPMK|CMK did not use null termination. 132639beb93cSSam Leffler */ 1327f05cddf9SRui Paulo if (peap_prfplus(data->peap_version, data->ipmk, 40, 132839beb93cSSam Leffler "Session Key Generating Function", 1329f05cddf9SRui Paulo (u8 *) "\00", 1, csk, sizeof(csk)) < 0) { 1330f05cddf9SRui Paulo os_free(key); 1331f05cddf9SRui Paulo return NULL; 1332f05cddf9SRui Paulo } 133339beb93cSSam Leffler wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk)); 133439beb93cSSam Leffler os_memcpy(key, csk, EAP_TLS_KEY_LEN); 133539beb93cSSam Leffler wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key", 133639beb93cSSam Leffler key, EAP_TLS_KEY_LEN); 1337206b73d0SCy Schubert forced_memzero(csk, sizeof(csk)); 133839beb93cSSam Leffler } else 133939beb93cSSam Leffler os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN); 134039beb93cSSam Leffler 134139beb93cSSam Leffler return key; 134239beb93cSSam Leffler } 134339beb93cSSam Leffler 134439beb93cSSam Leffler 13454bc52338SCy Schubert static u8 * eap_peap_get_emsk(struct eap_sm *sm, void *priv, size_t *len) 13464bc52338SCy Schubert { 13474bc52338SCy Schubert struct eap_peap_data *data = priv; 13484bc52338SCy Schubert u8 *key; 13494bc52338SCy Schubert 13504bc52338SCy Schubert if (!data->key_data || !data->phase2_success) 13514bc52338SCy Schubert return NULL; 13524bc52338SCy Schubert 13534bc52338SCy Schubert if (data->crypto_binding_used) { 13544bc52338SCy Schubert /* [MS-PEAP] does not define EMSK derivation */ 13554bc52338SCy Schubert return NULL; 13564bc52338SCy Schubert } 13574bc52338SCy Schubert 13584bc52338SCy Schubert key = os_memdup(data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN); 13594bc52338SCy Schubert if (!key) 13604bc52338SCy Schubert return NULL; 13614bc52338SCy Schubert 13624bc52338SCy Schubert *len = EAP_EMSK_LEN; 13634bc52338SCy Schubert 13644bc52338SCy Schubert return key; 13654bc52338SCy Schubert } 13664bc52338SCy Schubert 13674bc52338SCy Schubert 13685b9c547cSRui Paulo static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len) 13695b9c547cSRui Paulo { 13705b9c547cSRui Paulo struct eap_peap_data *data = priv; 13715b9c547cSRui Paulo u8 *id; 13725b9c547cSRui Paulo 13735b9c547cSRui Paulo if (data->session_id == NULL || !data->phase2_success) 13745b9c547cSRui Paulo return NULL; 13755b9c547cSRui Paulo 137685732ac8SCy Schubert id = os_memdup(data->session_id, data->id_len); 13775b9c547cSRui Paulo if (id == NULL) 13785b9c547cSRui Paulo return NULL; 13795b9c547cSRui Paulo 13805b9c547cSRui Paulo *len = data->id_len; 13815b9c547cSRui Paulo 13825b9c547cSRui Paulo return id; 13835b9c547cSRui Paulo } 13845b9c547cSRui Paulo 13855b9c547cSRui Paulo 138639beb93cSSam Leffler int eap_peer_peap_register(void) 138739beb93cSSam Leffler { 138839beb93cSSam Leffler struct eap_method *eap; 138939beb93cSSam Leffler 139039beb93cSSam Leffler eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, 139139beb93cSSam Leffler EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP"); 139239beb93cSSam Leffler if (eap == NULL) 139339beb93cSSam Leffler return -1; 139439beb93cSSam Leffler 139539beb93cSSam Leffler eap->init = eap_peap_init; 139639beb93cSSam Leffler eap->deinit = eap_peap_deinit; 139739beb93cSSam Leffler eap->process = eap_peap_process; 139839beb93cSSam Leffler eap->isKeyAvailable = eap_peap_isKeyAvailable; 139939beb93cSSam Leffler eap->getKey = eap_peap_getKey; 14004bc52338SCy Schubert eap->get_emsk = eap_peap_get_emsk; 140139beb93cSSam Leffler eap->get_status = eap_peap_get_status; 140239beb93cSSam Leffler eap->has_reauth_data = eap_peap_has_reauth_data; 140339beb93cSSam Leffler eap->deinit_for_reauth = eap_peap_deinit_for_reauth; 140439beb93cSSam Leffler eap->init_for_reauth = eap_peap_init_for_reauth; 14055b9c547cSRui Paulo eap->getSessionId = eap_peap_get_session_id; 140639beb93cSSam Leffler 1407780fb4a2SCy Schubert return eap_peer_method_register(eap); 140839beb93cSSam Leffler } 1409