diff --git a/bundle.json b/bundle.json index 637549b2541ca01b7e5130d2b88eaddefaca9365..39257539a3e4677d1ca8fcb7d898b84ba344ff45 100644 --- a/bundle.json +++ b/bundle.json @@ -30,6 +30,7 @@ "wpa_supplicant_config_mlo", "wpa_supplicant_ieee80211be", "wpa_supplicant_config_okc_roam", + "wpa_supplicant_config_ext_auth", "wpa_supplicant_hisysevent_module" ], "adapted_system_type": ["small","standard"], diff --git a/wpa_supplicant-2.9/src/eap_peer/eap_peap.c b/wpa_supplicant-2.9/src/eap_peer/eap_peap.c old mode 100755 new mode 100644 index 6453afe2fc57fabab7d51f4ae3e79bc3fd1a3c15..152ce0af09dac5709442d77dec95aecd9002a82a --- a/wpa_supplicant-2.9/src/eap_peer/eap_peap.c +++ b/wpa_supplicant-2.9/src/eap_peer/eap_peap.c @@ -1,1341 +1,1341 @@ -/* - * EAP peer method: EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt) - * Copyright (c) 2004-2019, Jouni Malinen - * - * This software may be distributed under the terms of the BSD license. - * See README for more details. - */ - -#include "includes.h" - -#include "common.h" -#include "crypto/sha1.h" -#include "crypto/tls.h" -#include "eap_common/eap_tlv_common.h" -#include "eap_common/eap_peap_common.h" -#include "eap_i.h" -#include "eap_tls_common.h" -#include "eap_config.h" -#include "tncc.h" - - -/* Maximum supported PEAP version - * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt - * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt - */ -#define EAP_PEAP_VERSION 1 - - -static void eap_peap_deinit(struct eap_sm *sm, void *priv); - - -struct eap_peap_data { - struct eap_ssl_data ssl; - - int peap_version, force_peap_version, force_new_label; - - const struct eap_method *phase2_method; - void *phase2_priv; - int phase2_success; - int phase2_eap_success; - int phase2_eap_started; - - struct eap_method_type phase2_type; - struct eap_method_type *phase2_types; - size_t num_phase2_types; - - int peap_outer_success; /* 0 = PEAP terminated on Phase 2 inner - * EAP-Success - * 1 = reply with tunneled EAP-Success to inner - * EAP-Success and expect AS to send outer - * (unencrypted) EAP-Success after this - * 2 = reply with PEAP/TLS ACK to inner - * EAP-Success and expect AS to send outer - * (unencrypted) EAP-Success after this */ - int resuming; /* starting a resumed session */ - int reauth; /* reauthentication */ - u8 *key_data; - u8 *session_id; - size_t id_len; - - struct wpabuf *pending_phase2_req; - struct wpabuf *pending_resp; - enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding; - int crypto_binding_used; - u8 binding_nonce[32]; - u8 ipmk[40]; - u8 cmk[20]; - int soh; /* Whether IF-TNCCS-SOH (Statement of Health; Microsoft NAP) - * is enabled. */ -}; - - -static void eap_peap_parse_phase1(struct eap_peap_data *data, - const char *phase1) -{ - const char *pos; - - pos = os_strstr(phase1, "peapver="); - if (pos) { - data->force_peap_version = atoi(pos + 8); - data->peap_version = data->force_peap_version; - wpa_printf(MSG_DEBUG, "EAP-PEAP: Forced PEAP version %d", - data->force_peap_version); - } - - if (os_strstr(phase1, "peaplabel=1")) { - data->force_new_label = 1; - wpa_printf(MSG_DEBUG, "EAP-PEAP: Force new label for key " - "derivation"); - } - - if (os_strstr(phase1, "peap_outer_success=0")) { - data->peap_outer_success = 0; - wpa_printf(MSG_DEBUG, "EAP-PEAP: terminate authentication on " - "tunneled EAP-Success"); - } else if (os_strstr(phase1, "peap_outer_success=1")) { - data->peap_outer_success = 1; - wpa_printf(MSG_DEBUG, "EAP-PEAP: send tunneled EAP-Success " - "after receiving tunneled EAP-Success"); - } else if (os_strstr(phase1, "peap_outer_success=2")) { - data->peap_outer_success = 2; - wpa_printf(MSG_DEBUG, "EAP-PEAP: send PEAP/TLS ACK after " - "receiving tunneled EAP-Success"); - } - - if (os_strstr(phase1, "crypto_binding=0")) { - data->crypto_binding = NO_BINDING; - wpa_printf(MSG_DEBUG, "EAP-PEAP: Do not use cryptobinding"); - } else if (os_strstr(phase1, "crypto_binding=1")) { - data->crypto_binding = OPTIONAL_BINDING; - wpa_printf(MSG_DEBUG, "EAP-PEAP: Optional cryptobinding"); - } else if (os_strstr(phase1, "crypto_binding=2")) { - data->crypto_binding = REQUIRE_BINDING; - wpa_printf(MSG_DEBUG, "EAP-PEAP: Require cryptobinding"); - } - -#ifdef EAP_TNC - if (os_strstr(phase1, "tnc=soh2")) { - data->soh = 2; - wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled"); - } else if (os_strstr(phase1, "tnc=soh1")) { - data->soh = 1; - wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 1 enabled"); - } else if (os_strstr(phase1, "tnc=soh")) { - data->soh = 2; - wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled"); - } -#endif /* EAP_TNC */ -} - - -static void * eap_peap_init(struct eap_sm *sm) -{ - struct eap_peap_data *data; - struct eap_peer_config *config = eap_get_config(sm); - - data = os_zalloc(sizeof(*data)); - if (data == NULL) - return NULL; - sm->peap_done = FALSE; - data->peap_version = EAP_PEAP_VERSION; - data->force_peap_version = -1; - data->peap_outer_success = 2; - data->crypto_binding = OPTIONAL_BINDING; - - if (config && config->phase1) - eap_peap_parse_phase1(data, config->phase1); - - if (eap_peer_select_phase2_methods(config, "auth=", - &data->phase2_types, - &data->num_phase2_types) < 0) { - eap_peap_deinit(sm, data); - return NULL; - } - - data->phase2_type.vendor = EAP_VENDOR_IETF; - data->phase2_type.method = EAP_TYPE_NONE; - - if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_PEAP)) { - wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL."); - eap_peap_deinit(sm, data); - return NULL; - } - - return data; -} - - -static void eap_peap_free_key(struct eap_peap_data *data) -{ - if (data->key_data) { - bin_clear_free(data->key_data, EAP_TLS_KEY_LEN + EAP_EMSK_LEN); - data->key_data = NULL; - } -} - - -static void eap_peap_deinit(struct eap_sm *sm, void *priv) -{ - struct eap_peap_data *data = priv; - if (data == NULL) - return; - if (data->phase2_priv && data->phase2_method) - data->phase2_method->deinit(sm, data->phase2_priv); - os_free(data->phase2_types); - eap_peer_tls_ssl_deinit(sm, &data->ssl); - eap_peap_free_key(data); - os_free(data->session_id); - wpabuf_clear_free(data->pending_phase2_req); - wpabuf_clear_free(data->pending_resp); - bin_clear_free(data, sizeof(*data)); -} - - -/** - * eap_tlv_build_nak - Build EAP-TLV NAK message - * @id: EAP identifier for the header - * @nak_type: TLV type (EAP_TLV_*) - * Returns: Buffer to the allocated EAP-TLV NAK message or %NULL on failure - * - * This function builds an EAP-TLV NAK message. The caller is responsible for - * freeing the returned buffer. - */ -static struct wpabuf * eap_tlv_build_nak(int id, u16 nak_type) -{ - struct wpabuf *msg; - - msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, 10, - EAP_CODE_RESPONSE, id); - if (msg == NULL) - return NULL; - - wpabuf_put_u8(msg, 0x80); /* Mandatory */ - wpabuf_put_u8(msg, EAP_TLV_NAK_TLV); - wpabuf_put_be16(msg, 6); /* Length */ - wpabuf_put_be32(msg, 0); /* Vendor-Id */ - wpabuf_put_be16(msg, nak_type); /* NAK-Type */ - - return msg; -} - - -static int eap_peap_get_isk(struct eap_sm *sm, struct eap_peap_data *data, - u8 *isk, size_t isk_len) -{ - u8 *key; - size_t key_len; - - os_memset(isk, 0, isk_len); - if (data->phase2_method == NULL || data->phase2_priv == NULL || - data->phase2_method->isKeyAvailable == NULL || - data->phase2_method->getKey == NULL) - return 0; - - if (!data->phase2_method->isKeyAvailable(sm, data->phase2_priv) || - (key = data->phase2_method->getKey(sm, data->phase2_priv, - &key_len)) == NULL) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not get key material " - "from Phase 2"); - return -1; - } - - if (key_len > isk_len) - key_len = isk_len; - os_memcpy(isk, key, key_len); - os_free(key); - - return 0; -} - - -static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data) -{ - u8 *tk; - u8 isk[32], imck[60]; - int resumed, res; - - /* - * Tunnel key (TK) is the first 60 octets of the key generated by - * phase 1 of PEAP (based on TLS). - */ - tk = data->key_data; - if (tk == NULL) - return -1; - wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60); - - resumed = tls_connection_resumed(sm->ssl_ctx, data->ssl.conn); - wpa_printf(MSG_DEBUG, - "EAP-PEAP: CMK derivation - reauth=%d resumed=%d phase2_eap_started=%d phase2_success=%d", - data->reauth, resumed, data->phase2_eap_started, - data->phase2_success); - if (data->reauth && !data->phase2_eap_started && resumed) { - /* Fast-connect: IPMK|CMK = TK */ - os_memcpy(data->ipmk, tk, 40); - wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK from TK", - data->ipmk, 40); - os_memcpy(data->cmk, tk + 40, 20); - wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK from TK", - data->cmk, 20); - return 0; - } - - if (eap_peap_get_isk(sm, data, isk, sizeof(isk)) < 0) - return -1; - wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk)); - - /* - * IPMK Seed = "Inner Methods Compound Keys" | ISK - * TempKey = First 40 octets of TK - * IPMK|CMK = PRF+(TempKey, IPMK Seed, 60) - * (note: draft-josefsson-pppext-eap-tls-eap-10.txt includes a space - * in the end of the label just before ISK; is that just a typo?) - */ - wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40); - res = peap_prfplus(data->peap_version, tk, 40, - "Inner Methods Compound Keys", - isk, sizeof(isk), imck, sizeof(imck)); - forced_memzero(isk, sizeof(isk)); - if (res < 0) - return -1; - wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)", - imck, sizeof(imck)); - - os_memcpy(data->ipmk, imck, 40); - wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40); - os_memcpy(data->cmk, imck + 40, 20); - wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20); - forced_memzero(imck, sizeof(imck)); - - return 0; -} - - -static int eap_tlv_add_cryptobinding(struct eap_sm *sm, - struct eap_peap_data *data, - struct wpabuf *buf) -{ - u8 *mac; - u8 eap_type = EAP_TYPE_PEAP; - const u8 *addr[2]; - size_t len[2]; - u16 tlv_type; - - /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */ - addr[0] = wpabuf_put(buf, 0); - len[0] = 60; - addr[1] = &eap_type; - len[1] = 1; - - tlv_type = EAP_TLV_CRYPTO_BINDING_TLV; - wpabuf_put_be16(buf, tlv_type); - wpabuf_put_be16(buf, 56); - - wpabuf_put_u8(buf, 0); /* Reserved */ - wpabuf_put_u8(buf, data->peap_version); /* Version */ - wpabuf_put_u8(buf, data->peap_version); /* RecvVersion */ - wpabuf_put_u8(buf, 1); /* SubType: 0 = Request, 1 = Response */ - wpabuf_put_data(buf, data->binding_nonce, 32); /* Nonce */ - mac = wpabuf_put(buf, 20); /* Compound_MAC */ - wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK", data->cmk, 20); - wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1", - addr[0], len[0]); - wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2", - addr[1], len[1]); - if (hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac) < 0) - return -1; - wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC", mac, SHA1_MAC_LEN); - data->crypto_binding_used = 1; - - return 0; -} - - -/** - * eap_tlv_build_result - Build EAP-TLV Result message - * @id: EAP identifier for the header - * @status: Status (EAP_TLV_RESULT_SUCCESS or EAP_TLV_RESULT_FAILURE) - * Returns: Buffer to the allocated EAP-TLV Result message or %NULL on failure - * - * This function builds an EAP-TLV Result message. The caller is responsible - * for freeing the returned buffer. - */ -static struct wpabuf * eap_tlv_build_result(struct eap_sm *sm, - struct eap_peap_data *data, - int crypto_tlv_used, - int id, u16 status) -{ - struct wpabuf *msg; - size_t len; - - if (data->crypto_binding == NO_BINDING) - crypto_tlv_used = 0; - - len = 6; - if (crypto_tlv_used) - len += 60; /* Cryptobinding TLV */ - msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, len, - EAP_CODE_RESPONSE, id); - if (msg == NULL) - return NULL; - - wpabuf_put_u8(msg, 0x80); /* Mandatory */ - wpabuf_put_u8(msg, EAP_TLV_RESULT_TLV); - wpabuf_put_be16(msg, 2); /* Length */ - wpabuf_put_be16(msg, status); /* Status */ - - if (crypto_tlv_used && eap_tlv_add_cryptobinding(sm, data, msg)) { - wpabuf_clear_free(msg); - return NULL; - } - - return msg; -} - - -static int eap_tlv_validate_cryptobinding(struct eap_sm *sm, - struct eap_peap_data *data, - const u8 *crypto_tlv, - size_t crypto_tlv_len) -{ - u8 buf[61], mac[SHA1_MAC_LEN]; - const u8 *pos; - - if (eap_peap_derive_cmk(sm, data) < 0) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not derive CMK"); - return -1; - } - - if (crypto_tlv_len != 4 + 56) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid cryptobinding TLV " - "length %d", (int) crypto_tlv_len); - return -1; - } - - pos = crypto_tlv; - pos += 4; /* TLV header */ - if (pos[1] != data->peap_version) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV Version " - "mismatch (was %d; expected %d)", - pos[1], data->peap_version); - return -1; - } - - if (pos[3] != 0) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected Cryptobinding TLV " - "SubType %d", pos[3]); - return -1; - } - pos += 4; - os_memcpy(data->binding_nonce, pos, 32); - pos += 32; /* Nonce */ - - /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */ - os_memcpy(buf, crypto_tlv, 60); - os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */ - buf[60] = EAP_TYPE_PEAP; - wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Compound_MAC data", - buf, sizeof(buf)); - hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac); - - if (os_memcmp_const(mac, pos, SHA1_MAC_LEN) != 0) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in " - "cryptobinding TLV"); - wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received MAC", - pos, SHA1_MAC_LEN); - wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Expected MAC", - mac, SHA1_MAC_LEN); - return -1; - } - - wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received"); - - return 0; -} - - -/** - * eap_tlv_process - Process a received EAP-TLV message and generate a response - * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() - * @ret: Return values from EAP request validation and processing - * @req: EAP-TLV request to be processed. The caller must have validated that - * the buffer is large enough to contain full request (hdr->length bytes) and - * that the EAP type is EAP_TYPE_TLV. - * @resp: Buffer to return a pointer to the allocated response message. This - * field should be initialized to %NULL before the call. The value will be - * updated if a response message is generated. The caller is responsible for - * freeing the allocated message. - * @force_failure: Force negotiation to fail - * Returns: 0 on success, -1 on failure - */ -static int 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) -{ - size_t left, tlv_len; - const u8 *pos; - const u8 *result_tlv = NULL, *crypto_tlv = NULL; - size_t result_tlv_len = 0, crypto_tlv_len = 0; - int tlv_type, mandatory; - - /* Parse TLVs */ - pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, req, &left); - if (pos == NULL) - return -1; - wpa_hexdump(MSG_DEBUG, "EAP-TLV: Received TLVs", pos, left); - while (left >= 4) { - mandatory = !!(pos[0] & 0x80); - tlv_type = WPA_GET_BE16(pos) & 0x3fff; - pos += 2; - tlv_len = WPA_GET_BE16(pos); - pos += 2; - left -= 4; - if (tlv_len > left) { - wpa_printf(MSG_DEBUG, "EAP-TLV: TLV underrun " - "(tlv_len=%lu left=%lu)", - (unsigned long) tlv_len, - (unsigned long) left); - return -1; - } - switch (tlv_type) { - case EAP_TLV_RESULT_TLV: - result_tlv = pos; - result_tlv_len = tlv_len; - break; - case EAP_TLV_CRYPTO_BINDING_TLV: - crypto_tlv = pos; - crypto_tlv_len = tlv_len; - break; - default: - wpa_printf(MSG_DEBUG, "EAP-TLV: Unsupported TLV Type " - "%d%s", tlv_type, - mandatory ? " (mandatory)" : ""); - if (mandatory) { - /* NAK TLV and ignore all TLVs in this packet. - */ - *resp = eap_tlv_build_nak(eap_get_id(req), - tlv_type); - return *resp == NULL ? -1 : 0; - } - /* Ignore this TLV, but process other TLVs */ - break; - } - - pos += tlv_len; - left -= tlv_len; - } - if (left) { - wpa_printf(MSG_DEBUG, "EAP-TLV: Last TLV too short in " - "Request (left=%lu)", (unsigned long) left); - return -1; - } - - /* Process supported TLVs */ - if (crypto_tlv && data->crypto_binding != NO_BINDING) { - wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV", - crypto_tlv, crypto_tlv_len); - if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4, - crypto_tlv_len + 4) < 0) { - if (result_tlv == NULL) - return -1; - force_failure = 1; - crypto_tlv = NULL; /* do not include Cryptobinding TLV - * in response, if the received - * cryptobinding was invalid. */ - } - } else if (!crypto_tlv && data->crypto_binding == REQUIRE_BINDING) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV"); - return -1; - } - - if (result_tlv) { - int status, resp_status; - wpa_hexdump(MSG_DEBUG, "EAP-TLV: Result TLV", - result_tlv, result_tlv_len); - if (result_tlv_len < 2) { - wpa_printf(MSG_INFO, "EAP-TLV: Too short Result TLV " - "(len=%lu)", - (unsigned long) result_tlv_len); - return -1; - } - status = WPA_GET_BE16(result_tlv); - if (status == EAP_TLV_RESULT_SUCCESS) { - wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Success " - "- EAP-TLV/Phase2 Completed"); - if (force_failure) { - wpa_printf(MSG_INFO, "EAP-TLV: Earlier failure" - " - force failed Phase 2"); - resp_status = EAP_TLV_RESULT_FAILURE; - ret->decision = DECISION_FAIL; - } else { - resp_status = EAP_TLV_RESULT_SUCCESS; - ret->decision = DECISION_UNCOND_SUCC; - } - } else if (status == EAP_TLV_RESULT_FAILURE) { - wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Failure"); - resp_status = EAP_TLV_RESULT_FAILURE; - ret->decision = DECISION_FAIL; - } else { - wpa_printf(MSG_INFO, "EAP-TLV: Unknown TLV Result " - "Status %d", status); - resp_status = EAP_TLV_RESULT_FAILURE; - ret->decision = DECISION_FAIL; - } - ret->methodState = METHOD_DONE; - - *resp = eap_tlv_build_result(sm, data, crypto_tlv != NULL, - eap_get_id(req), resp_status); - } - - return 0; -} - - -static int eap_peap_phase2_request(struct eap_sm *sm, - struct eap_peap_data *data, - struct eap_method_ret *ret, - struct wpabuf *req, - struct wpabuf **resp) -{ - struct eap_hdr *hdr = wpabuf_mhead(req); - size_t len = be_to_host16(hdr->length); - u8 *pos; - struct eap_method_ret iret; - struct eap_peer_config *config = eap_get_config(sm); - - if (len <= sizeof(struct eap_hdr)) { - wpa_printf(MSG_INFO, "EAP-PEAP: too short " - "Phase 2 request (len=%lu)", (unsigned long) len); - return -1; - } - pos = (u8 *) (hdr + 1); - wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Request: type=%d", *pos); - switch (*pos) { - case EAP_TYPE_IDENTITY: - *resp = eap_sm_buildIdentity(sm, hdr->identifier, 1); - break; - case EAP_TYPE_TLV: - os_memset(&iret, 0, sizeof(iret)); - if (eap_tlv_process(sm, data, &iret, req, resp, - data->phase2_eap_started && - !data->phase2_eap_success)) { - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - return -1; - } - if (iret.methodState == METHOD_DONE || - iret.methodState == METHOD_MAY_CONT) { - ret->methodState = iret.methodState; - ret->decision = iret.decision; - data->phase2_success = 1; - } - break; - case EAP_TYPE_EXPANDED: -#ifdef EAP_TNC - if (data->soh) { - const u8 *epos; - size_t eleft; - - epos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21, - req, &eleft); - if (epos) { - struct wpabuf *buf; - wpa_printf(MSG_DEBUG, - "EAP-PEAP: SoH EAP Extensions"); - buf = tncc_process_soh_request(data->soh, - epos, eleft); - if (buf) { - *resp = eap_msg_alloc( - EAP_VENDOR_MICROSOFT, 0x21, - wpabuf_len(buf), - EAP_CODE_RESPONSE, - hdr->identifier); - if (*resp == NULL) { - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - wpabuf_clear_free(buf); - return -1; - } - wpabuf_put_buf(*resp, buf); - wpabuf_clear_free(buf); - break; - } - } - } -#endif /* EAP_TNC */ - /* fall through */ - default: - if (data->phase2_type.vendor == EAP_VENDOR_IETF && - data->phase2_type.method == EAP_TYPE_NONE) { - size_t i; - for (i = 0; i < data->num_phase2_types; i++) { - if (data->phase2_types[i].vendor != - EAP_VENDOR_IETF || - data->phase2_types[i].method != *pos) - continue; - - data->phase2_type.vendor = - data->phase2_types[i].vendor; - data->phase2_type.method = - data->phase2_types[i].method; - wpa_printf(MSG_DEBUG, "EAP-PEAP: Selected " - "Phase 2 EAP vendor %d method %d", - data->phase2_type.vendor, - data->phase2_type.method); - break; - } - } - if (*pos != data->phase2_type.method || - *pos == EAP_TYPE_NONE) { - if (eap_peer_tls_phase2_nak(data->phase2_types, - data->num_phase2_types, - hdr, resp)) - return -1; - return 0; - } - - if (data->phase2_priv == NULL) { - data->phase2_method = eap_peer_get_eap_method( - data->phase2_type.vendor, - data->phase2_type.method); - if (data->phase2_method) { - sm->init_phase2 = 1; - data->phase2_priv = - data->phase2_method->init(sm); - sm->init_phase2 = 0; - } - } - if (data->phase2_priv == NULL || data->phase2_method == NULL) { - wpa_printf(MSG_INFO, "EAP-PEAP: failed to initialize " - "Phase 2 EAP method %d", *pos); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - return -1; - } - data->phase2_eap_started = 1; - os_memset(&iret, 0, sizeof(iret)); - *resp = data->phase2_method->process(sm, data->phase2_priv, - &iret, req); - if ((iret.methodState == METHOD_DONE || - iret.methodState == METHOD_MAY_CONT) && - (iret.decision == DECISION_UNCOND_SUCC || - iret.decision == DECISION_COND_SUCC)) { - data->phase2_eap_success = 1; - data->phase2_success = 1; - } - break; - } - - if (*resp == NULL && - (config->pending_req_identity || config->pending_req_password || - config->pending_req_otp || config->pending_req_new_password || - config->pending_req_sim)) { - wpabuf_clear_free(data->pending_phase2_req); - data->pending_phase2_req = wpabuf_alloc_copy(hdr, len); - } - - return 0; -} - - -static int 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) -{ - struct wpabuf *in_decrypted = NULL; - int res, skip_change = 0; - struct eap_hdr *hdr, *rhdr; - struct wpabuf *resp = NULL; - size_t len; - - wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for" - " Phase 2", (unsigned long) wpabuf_len(in_data)); - - if (data->pending_phase2_req) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 request - " - "skip decryption and use old data"); - /* Clear TLS reassembly state. */ - eap_peer_tls_reset_input(&data->ssl); - in_decrypted = data->pending_phase2_req; - data->pending_phase2_req = NULL; - skip_change = 1; - goto continue_req; - } - - if (wpabuf_len(in_data) == 0 && sm->workaround && - data->phase2_success) { - /* - * Cisco ACS seems to be using TLS ACK to terminate - * EAP-PEAPv0/GTC. Try to reply with TLS ACK. - */ - wpa_printf(MSG_DEBUG, "EAP-PEAP: Received TLS ACK, but " - "expected data - acknowledge with TLS ACK since " - "Phase 2 has been completed"); - ret->decision = DECISION_COND_SUCC; - ret->methodState = METHOD_DONE; - return 1; - } else if (wpabuf_len(in_data) == 0) { - /* Received TLS ACK - requesting more fragments */ - return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP, - data->peap_version, - req->identifier, NULL, out_data); - } - - res = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted); - if (res) - return res; - -continue_req: - wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP", - in_decrypted); - - hdr = wpabuf_mhead(in_decrypted); - if (wpabuf_len(in_decrypted) == 5 && hdr->code == EAP_CODE_REQUEST && - be_to_host16(hdr->length) == 5 && - eap_get_type(in_decrypted) == EAP_TYPE_IDENTITY) { - /* At least FreeRADIUS seems to send full EAP header with - * EAP Request Identity */ - skip_change = 1; - } - if (wpabuf_len(in_decrypted) >= 5 && hdr->code == EAP_CODE_REQUEST && - eap_get_type(in_decrypted) == EAP_TYPE_TLV) { - skip_change = 1; - } - - if (data->peap_version == 0 && !skip_change) { - struct eap_hdr *nhdr; - struct wpabuf *nmsg = wpabuf_alloc(sizeof(struct eap_hdr) + - wpabuf_len(in_decrypted)); - if (nmsg == NULL) { - wpabuf_clear_free(in_decrypted); - return 0; - } - nhdr = wpabuf_put(nmsg, sizeof(*nhdr)); - wpabuf_put_buf(nmsg, in_decrypted); - nhdr->code = req->code; - nhdr->identifier = req->identifier; - nhdr->length = host_to_be16(sizeof(struct eap_hdr) + - wpabuf_len(in_decrypted)); - - wpabuf_clear_free(in_decrypted); - in_decrypted = nmsg; - } - - hdr = wpabuf_mhead(in_decrypted); - if (wpabuf_len(in_decrypted) < sizeof(*hdr)) { - wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 " - "EAP frame (len=%lu)", - (unsigned long) wpabuf_len(in_decrypted)); - wpabuf_clear_free(in_decrypted); - return 0; - } - len = be_to_host16(hdr->length); - if (len > wpabuf_len(in_decrypted)) { - wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in " - "Phase 2 EAP frame (len=%lu hdr->length=%lu)", - (unsigned long) wpabuf_len(in_decrypted), - (unsigned long) len); - wpabuf_clear_free(in_decrypted); - return 0; - } - if (len < wpabuf_len(in_decrypted)) { - wpa_printf(MSG_INFO, "EAP-PEAP: Odd.. Phase 2 EAP header has " - "shorter length than full decrypted data " - "(%lu < %lu)", - (unsigned long) len, - (unsigned long) wpabuf_len(in_decrypted)); - } - wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d " - "identifier=%d length=%lu", hdr->code, hdr->identifier, - (unsigned long) len); - switch (hdr->code) { - case EAP_CODE_REQUEST: - if (eap_peap_phase2_request(sm, data, ret, in_decrypted, - &resp)) { - wpabuf_clear_free(in_decrypted); - wpa_printf(MSG_INFO, "EAP-PEAP: Phase2 Request " - "processing failed"); - return 0; - } - break; - case EAP_CODE_SUCCESS: - wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success"); - if (data->peap_version == 1) { - /* EAP-Success within TLS tunnel is used to indicate - * shutdown of the TLS channel. The authentication has - * been completed. */ - if (data->phase2_eap_started && - !data->phase2_eap_success) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 " - "Success used to indicate success, " - "but Phase 2 EAP was not yet " - "completed successfully"); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - wpabuf_clear_free(in_decrypted); - return 0; - } - wpa_printf(MSG_DEBUG, "EAP-PEAP: Version 1 - " - "EAP-Success within TLS tunnel - " - "authentication completed"); - ret->decision = DECISION_UNCOND_SUCC; - ret->methodState = METHOD_DONE; - data->phase2_success = 1; - if (data->peap_outer_success == 2) { - wpabuf_clear_free(in_decrypted); - wpa_printf(MSG_DEBUG, "EAP-PEAP: Use TLS ACK " - "to finish authentication"); - return 1; - } else if (data->peap_outer_success == 1) { - /* Reply with EAP-Success within the TLS - * channel to complete the authentication. */ - resp = wpabuf_alloc(sizeof(struct eap_hdr)); - if (resp) { - rhdr = wpabuf_put(resp, sizeof(*rhdr)); - rhdr->code = EAP_CODE_SUCCESS; - rhdr->identifier = hdr->identifier; - rhdr->length = - host_to_be16(sizeof(*rhdr)); - } - } else { - /* No EAP-Success expected for Phase 1 (outer, - * unencrypted auth), so force EAP state - * machine to SUCCESS state. */ - sm->peap_done = TRUE; - } - } else { - /* FIX: ? */ - } - break; - case EAP_CODE_FAILURE: - wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure"); - ret->decision = DECISION_FAIL; - ret->methodState = METHOD_MAY_CONT; - ret->allowNotifications = FALSE; - /* Reply with EAP-Failure within the TLS channel to complete - * failure reporting. */ - resp = wpabuf_alloc(sizeof(struct eap_hdr)); - if (resp) { - rhdr = wpabuf_put(resp, sizeof(*rhdr)); - rhdr->code = EAP_CODE_FAILURE; - rhdr->identifier = hdr->identifier; - rhdr->length = host_to_be16(sizeof(*rhdr)); - } - break; - default: - wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in " - "Phase 2 EAP header", hdr->code); - break; - } - - wpabuf_clear_free(in_decrypted); - - if (resp) { - int skip_change2 = 0; - struct wpabuf *rmsg, buf; - - wpa_hexdump_buf_key(MSG_DEBUG, - "EAP-PEAP: Encrypting Phase 2 data", resp); - /* PEAP version changes */ - if (wpabuf_len(resp) >= 5 && - wpabuf_head_u8(resp)[0] == EAP_CODE_RESPONSE && - eap_get_type(resp) == EAP_TYPE_TLV) - skip_change2 = 1; - rmsg = resp; - if (data->peap_version == 0 && !skip_change2) { - wpabuf_set(&buf, wpabuf_head_u8(resp) + - sizeof(struct eap_hdr), - wpabuf_len(resp) - sizeof(struct eap_hdr)); - rmsg = &buf; - } - - if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP, - data->peap_version, req->identifier, - rmsg, out_data)) { - wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt " - "a Phase 2 frame"); - } - wpabuf_clear_free(resp); - } - - return 0; -} - - -static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv, - struct eap_method_ret *ret, - const struct wpabuf *reqData) -{ - const struct eap_hdr *req; - size_t left; - int res; - u8 flags, id; - struct wpabuf *resp; - const u8 *pos; - struct eap_peap_data *data = priv; - struct wpabuf msg; - - pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_PEAP, ret, - reqData, &left, &flags); - if (pos == NULL) - return NULL; - req = wpabuf_head(reqData); - id = req->identifier; - - if (flags & EAP_TLS_FLAGS_START) { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Start (server ver=%d, own " - "ver=%d)", flags & EAP_TLS_VERSION_MASK, - data->peap_version); - if ((flags & EAP_TLS_VERSION_MASK) < data->peap_version) - data->peap_version = flags & EAP_TLS_VERSION_MASK; - if (data->force_peap_version >= 0 && - data->force_peap_version != data->peap_version) { - wpa_printf(MSG_WARNING, "EAP-PEAP: Failed to select " - "forced PEAP version %d", - data->force_peap_version); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - ret->allowNotifications = FALSE; - return NULL; - } - wpa_printf(MSG_DEBUG, "EAP-PEAP: Using PEAP version %d", - data->peap_version); - left = 0; /* make sure that this frame is empty, even though it - * should always be, anyway */ - } - - wpabuf_set(&msg, pos, left); - - resp = NULL; - if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) && - !data->resuming) { - res = eap_peap_decrypt(sm, data, ret, req, &msg, &resp); - } else { - if (sm->waiting_ext_cert_check && data->pending_resp) { - struct eap_peer_config *config = eap_get_config(sm); - - if (config->pending_ext_cert_check == - EXT_CERT_CHECK_GOOD) { - wpa_printf(MSG_DEBUG, - "EAP-PEAP: External certificate check succeeded - continue handshake"); - resp = data->pending_resp; - data->pending_resp = NULL; - sm->waiting_ext_cert_check = 0; - return resp; - } - - if (config->pending_ext_cert_check == - EXT_CERT_CHECK_BAD) { - wpa_printf(MSG_DEBUG, - "EAP-PEAP: External certificate check failed - force authentication failure"); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - sm->waiting_ext_cert_check = 0; - return NULL; - } - - wpa_printf(MSG_DEBUG, - "EAP-PEAP: Continuing to wait external server certificate validation"); - return NULL; - } - - res = eap_peer_tls_process_helper(sm, &data->ssl, - EAP_TYPE_PEAP, - data->peap_version, id, &msg, - &resp); - - if (res < 0) { - wpa_printf(MSG_DEBUG, - "EAP-PEAP: TLS processing failed"); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - return resp; - } - - - if (sm->waiting_ext_cert_check) { - wpa_printf(MSG_DEBUG, - "EAP-PEAP: Waiting external server certificate validation"); - wpabuf_clear_free(data->pending_resp); - data->pending_resp = resp; - return NULL; - } - - if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { - char *label; - wpa_printf(MSG_DEBUG, - "EAP-PEAP: TLS done, proceed to Phase 2"); - eap_peap_free_key(data); - /* draft-josefsson-ppext-eap-tls-eap-05.txt - * specifies that PEAPv1 would use "client PEAP - * encryption" as the label. However, most existing - * PEAPv1 implementations seem to be using the old - * label, "client EAP encryption", instead. Use the old - * label by default, but allow it to be configured with - * phase1 parameter peaplabel=1. */ - if (data->force_new_label) - label = "client PEAP encryption"; - else - label = "client EAP encryption"; - wpa_printf(MSG_DEBUG, "EAP-PEAP: using label '%s' in " - "key derivation", label); - data->key_data = - eap_peer_tls_derive_key(sm, &data->ssl, label, - NULL, 0, - EAP_TLS_KEY_LEN + - EAP_EMSK_LEN); - if (data->key_data) { - wpa_hexdump_key(MSG_DEBUG, - "EAP-PEAP: Derived key", - data->key_data, - EAP_TLS_KEY_LEN); - wpa_hexdump_key(MSG_DEBUG, - "EAP-PEAP: Derived EMSK", - data->key_data + - EAP_TLS_KEY_LEN, - EAP_EMSK_LEN); - } else { - wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to " - "derive key"); - } - - os_free(data->session_id); - data->session_id = - eap_peer_tls_derive_session_id(sm, &data->ssl, - EAP_TYPE_PEAP, - &data->id_len); - if (data->session_id) { - wpa_hexdump(MSG_DEBUG, - "EAP-PEAP: Derived Session-Id", - data->session_id, data->id_len); - } else { - wpa_printf(MSG_ERROR, "EAP-PEAP: Failed to " - "derive Session-Id"); - } - - if (sm->workaround && data->resuming) { - /* - * At least few RADIUS servers (Aegis v1.1.6; - * but not v1.1.4; and Cisco ACS) seem to be - * terminating PEAPv1 (Aegis) or PEAPv0 (Cisco - * ACS) session resumption with outer - * EAP-Success. This does not seem to follow - * draft-josefsson-pppext-eap-tls-eap-05.txt - * section 4.2, so only allow this if EAP - * workarounds are enabled. - */ - wpa_printf(MSG_DEBUG, "EAP-PEAP: Workaround - " - "allow outer EAP-Success to " - "terminate PEAP resumption"); - ret->decision = DECISION_COND_SUCC; - data->phase2_success = 1; - } - - data->resuming = 0; - } - - if (res == 2) { - /* - * Application data included in the handshake message. - */ - wpabuf_clear_free(data->pending_phase2_req); - data->pending_phase2_req = resp; - resp = NULL; - res = eap_peap_decrypt(sm, data, ret, req, &msg, - &resp); - } - } - - if (ret->methodState == METHOD_DONE) { - ret->allowNotifications = FALSE; - } - - if (res == 1) { - wpabuf_clear_free(resp); - return eap_peer_tls_build_ack(id, EAP_TYPE_PEAP, - data->peap_version); - } - - return resp; -} - - -static Boolean eap_peap_has_reauth_data(struct eap_sm *sm, void *priv) -{ - struct eap_peap_data *data = priv; - return tls_connection_established(sm->ssl_ctx, data->ssl.conn) && - data->phase2_success; -} - - -static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv) -{ - struct eap_peap_data *data = priv; - - if (data->phase2_priv && data->phase2_method && - data->phase2_method->deinit_for_reauth) - data->phase2_method->deinit_for_reauth(sm, data->phase2_priv); - wpabuf_clear_free(data->pending_phase2_req); - data->pending_phase2_req = NULL; - wpabuf_clear_free(data->pending_resp); - data->pending_resp = NULL; - data->crypto_binding_used = 0; -} - - -static void * eap_peap_init_for_reauth(struct eap_sm *sm, void *priv) -{ - struct eap_peap_data *data = priv; - eap_peap_free_key(data); - os_free(data->session_id); - data->session_id = NULL; - if (eap_peer_tls_reauth_init(sm, &data->ssl)) { - os_free(data); - return NULL; - } - if (data->phase2_priv && data->phase2_method && - data->phase2_method->init_for_reauth) - data->phase2_method->init_for_reauth(sm, data->phase2_priv); - data->phase2_success = 0; - data->phase2_eap_success = 0; - data->phase2_eap_started = 0; - data->resuming = 1; - data->reauth = 1; - sm->peap_done = FALSE; - return priv; -} - - -static int eap_peap_get_status(struct eap_sm *sm, void *priv, char *buf, - size_t buflen, int verbose) -{ - struct eap_peap_data *data = priv; - int len, ret; - - len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose); - if (data->phase2_method) { - ret = os_snprintf(buf + len, buflen - len, - "EAP-PEAPv%d Phase2 method=%s\n", - data->peap_version, - data->phase2_method->name); - if (os_snprintf_error(buflen - len, ret)) - return len; - len += ret; - } - return len; -} - - -static Boolean eap_peap_isKeyAvailable(struct eap_sm *sm, void *priv) -{ - struct eap_peap_data *data = priv; - return data->key_data != NULL && data->phase2_success; -} - - -static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_peap_data *data = priv; - u8 *key; - - if (data->key_data == NULL || !data->phase2_success) - return NULL; - - key = os_malloc(EAP_TLS_KEY_LEN); - if (key == NULL) - return NULL; - - *len = EAP_TLS_KEY_LEN; - - if (data->crypto_binding_used) { - u8 csk[128]; - /* - * Note: It looks like Microsoft implementation requires null - * termination for this label while the one used for deriving - * IPMK|CMK did not use null termination. - */ - if (peap_prfplus(data->peap_version, data->ipmk, 40, - "Session Key Generating Function", - (u8 *) "\00", 1, csk, sizeof(csk)) < 0) { - os_free(key); - return NULL; - } - wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk)); - os_memcpy(key, csk, EAP_TLS_KEY_LEN); - wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key", - key, EAP_TLS_KEY_LEN); - forced_memzero(csk, sizeof(csk)); - } else - os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN); - - return key; -} - - -static u8 * eap_peap_get_emsk(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_peap_data *data = priv; - u8 *key; - - if (!data->key_data || !data->phase2_success) - return NULL; - - if (data->crypto_binding_used) { - /* [MS-PEAP] does not define EMSK derivation */ - return NULL; - } - - key = os_memdup(data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN); - if (!key) - return NULL; - - *len = EAP_EMSK_LEN; - - return key; -} - - -static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len) -{ - struct eap_peap_data *data = priv; - u8 *id; - - if (data->session_id == NULL || !data->phase2_success) - return NULL; - - id = os_memdup(data->session_id, data->id_len); - if (id == NULL) - return NULL; - - *len = data->id_len; - - return id; -} - - -int eap_peer_peap_register(void) -{ - struct eap_method *eap; - - eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, - EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP"); - if (eap == NULL) - return -1; - - eap->init = eap_peap_init; - eap->deinit = eap_peap_deinit; - eap->process = eap_peap_process; - eap->isKeyAvailable = eap_peap_isKeyAvailable; - eap->getKey = eap_peap_getKey; - eap->get_emsk = eap_peap_get_emsk; - eap->get_status = eap_peap_get_status; - eap->has_reauth_data = eap_peap_has_reauth_data; - eap->deinit_for_reauth = eap_peap_deinit_for_reauth; - eap->init_for_reauth = eap_peap_init_for_reauth; - eap->getSessionId = eap_peap_get_session_id; - - return eap_peer_method_register(eap); -} +/* + * EAP peer method: EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt) + * Copyright (c) 2004-2019, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "crypto/sha1.h" +#include "crypto/tls.h" +#include "eap_common/eap_tlv_common.h" +#include "eap_common/eap_peap_common.h" +#include "eap_i.h" +#include "eap_tls_common.h" +#include "eap_config.h" +#include "tncc.h" + + +/* Maximum supported PEAP version + * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt + * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt + */ +#define EAP_PEAP_VERSION 1 + + +static void eap_peap_deinit(struct eap_sm *sm, void *priv); + + +struct eap_peap_data { + struct eap_ssl_data ssl; + + int peap_version, force_peap_version, force_new_label; + + const struct eap_method *phase2_method; + void *phase2_priv; + int phase2_success; + int phase2_eap_success; + int phase2_eap_started; + + struct eap_method_type phase2_type; + struct eap_method_type *phase2_types; + size_t num_phase2_types; + + int peap_outer_success; /* 0 = PEAP terminated on Phase 2 inner + * EAP-Success + * 1 = reply with tunneled EAP-Success to inner + * EAP-Success and expect AS to send outer + * (unencrypted) EAP-Success after this + * 2 = reply with PEAP/TLS ACK to inner + * EAP-Success and expect AS to send outer + * (unencrypted) EAP-Success after this */ + int resuming; /* starting a resumed session */ + int reauth; /* reauthentication */ + u8 *key_data; + u8 *session_id; + size_t id_len; + + struct wpabuf *pending_phase2_req; + struct wpabuf *pending_resp; + enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding; + int crypto_binding_used; + u8 binding_nonce[32]; + u8 ipmk[40]; + u8 cmk[20]; + int soh; /* Whether IF-TNCCS-SOH (Statement of Health; Microsoft NAP) + * is enabled. */ +}; + + +static void eap_peap_parse_phase1(struct eap_peap_data *data, + const char *phase1) +{ + const char *pos; + + pos = os_strstr(phase1, "peapver="); + if (pos) { + data->force_peap_version = atoi(pos + 8); + data->peap_version = data->force_peap_version; + wpa_printf(MSG_DEBUG, "EAP-PEAP: Forced PEAP version %d", + data->force_peap_version); + } + + if (os_strstr(phase1, "peaplabel=1")) { + data->force_new_label = 1; + wpa_printf(MSG_DEBUG, "EAP-PEAP: Force new label for key " + "derivation"); + } + + if (os_strstr(phase1, "peap_outer_success=0")) { + data->peap_outer_success = 0; + wpa_printf(MSG_DEBUG, "EAP-PEAP: terminate authentication on " + "tunneled EAP-Success"); + } else if (os_strstr(phase1, "peap_outer_success=1")) { + data->peap_outer_success = 1; + wpa_printf(MSG_DEBUG, "EAP-PEAP: send tunneled EAP-Success " + "after receiving tunneled EAP-Success"); + } else if (os_strstr(phase1, "peap_outer_success=2")) { + data->peap_outer_success = 2; + wpa_printf(MSG_DEBUG, "EAP-PEAP: send PEAP/TLS ACK after " + "receiving tunneled EAP-Success"); + } + + if (os_strstr(phase1, "crypto_binding=0")) { + data->crypto_binding = NO_BINDING; + wpa_printf(MSG_DEBUG, "EAP-PEAP: Do not use cryptobinding"); + } else if (os_strstr(phase1, "crypto_binding=1")) { + data->crypto_binding = OPTIONAL_BINDING; + wpa_printf(MSG_DEBUG, "EAP-PEAP: Optional cryptobinding"); + } else if (os_strstr(phase1, "crypto_binding=2")) { + data->crypto_binding = REQUIRE_BINDING; + wpa_printf(MSG_DEBUG, "EAP-PEAP: Require cryptobinding"); + } + +#ifdef EAP_TNC + if (os_strstr(phase1, "tnc=soh2")) { + data->soh = 2; + wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled"); + } else if (os_strstr(phase1, "tnc=soh1")) { + data->soh = 1; + wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 1 enabled"); + } else if (os_strstr(phase1, "tnc=soh")) { + data->soh = 2; + wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled"); + } +#endif /* EAP_TNC */ +} + + +static void * eap_peap_init(struct eap_sm *sm) +{ + struct eap_peap_data *data; + struct eap_peer_config *config = eap_get_config(sm); + + data = os_zalloc(sizeof(*data)); + if (data == NULL) + return NULL; + sm->peap_done = FALSE; + data->peap_version = EAP_PEAP_VERSION; + data->force_peap_version = -1; + data->peap_outer_success = 2; + data->crypto_binding = OPTIONAL_BINDING; + + if (config && config->phase1) + eap_peap_parse_phase1(data, config->phase1); + + if (eap_peer_select_phase2_methods(config, "auth=", + &data->phase2_types, + &data->num_phase2_types) < 0) { + eap_peap_deinit(sm, data); + return NULL; + } + + data->phase2_type.vendor = EAP_VENDOR_IETF; + data->phase2_type.method = EAP_TYPE_NONE; + + if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_PEAP)) { + wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL."); + eap_peap_deinit(sm, data); + return NULL; + } + + return data; +} + + +static void eap_peap_free_key(struct eap_peap_data *data) +{ + if (data->key_data) { + bin_clear_free(data->key_data, EAP_TLS_KEY_LEN + EAP_EMSK_LEN); + data->key_data = NULL; + } +} + + +static void eap_peap_deinit(struct eap_sm *sm, void *priv) +{ + struct eap_peap_data *data = priv; + if (data == NULL) + return; + if (data->phase2_priv && data->phase2_method) + data->phase2_method->deinit(sm, data->phase2_priv); + os_free(data->phase2_types); + eap_peer_tls_ssl_deinit(sm, &data->ssl); + eap_peap_free_key(data); + os_free(data->session_id); + wpabuf_clear_free(data->pending_phase2_req); + wpabuf_clear_free(data->pending_resp); + bin_clear_free(data, sizeof(*data)); +} + + +/** + * eap_tlv_build_nak - Build EAP-TLV NAK message + * @id: EAP identifier for the header + * @nak_type: TLV type (EAP_TLV_*) + * Returns: Buffer to the allocated EAP-TLV NAK message or %NULL on failure + * + * This function builds an EAP-TLV NAK message. The caller is responsible for + * freeing the returned buffer. + */ +static struct wpabuf * eap_tlv_build_nak(int id, u16 nak_type) +{ + struct wpabuf *msg; + + msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, 10, + EAP_CODE_RESPONSE, id); + if (msg == NULL) + return NULL; + + wpabuf_put_u8(msg, 0x80); /* Mandatory */ + wpabuf_put_u8(msg, EAP_TLV_NAK_TLV); + wpabuf_put_be16(msg, 6); /* Length */ + wpabuf_put_be32(msg, 0); /* Vendor-Id */ + wpabuf_put_be16(msg, nak_type); /* NAK-Type */ + + return msg; +} + + +static int eap_peap_get_isk(struct eap_sm *sm, struct eap_peap_data *data, + u8 *isk, size_t isk_len) +{ + u8 *key; + size_t key_len; + + os_memset(isk, 0, isk_len); + if (data->phase2_method == NULL || data->phase2_priv == NULL || + data->phase2_method->isKeyAvailable == NULL || + data->phase2_method->getKey == NULL) + return 0; + + if (!data->phase2_method->isKeyAvailable(sm, data->phase2_priv) || + (key = data->phase2_method->getKey(sm, data->phase2_priv, + &key_len)) == NULL) { + wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not get key material " + "from Phase 2"); + return -1; + } + + if (key_len > isk_len) + key_len = isk_len; + os_memcpy(isk, key, key_len); + os_free(key); + + return 0; +} + + +static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data) +{ + u8 *tk; + u8 isk[32], imck[60]; + int resumed, res; + + /* + * Tunnel key (TK) is the first 60 octets of the key generated by + * phase 1 of PEAP (based on TLS). + */ + tk = data->key_data; + if (tk == NULL) + return -1; + wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60); + + resumed = tls_connection_resumed(sm->ssl_ctx, data->ssl.conn); + wpa_printf(MSG_DEBUG, + "EAP-PEAP: CMK derivation - reauth=%d resumed=%d phase2_eap_started=%d phase2_success=%d", + data->reauth, resumed, data->phase2_eap_started, + data->phase2_success); + if (data->reauth && !data->phase2_eap_started && resumed) { + /* Fast-connect: IPMK|CMK = TK */ + os_memcpy(data->ipmk, tk, 40); + wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK from TK", + data->ipmk, 40); + os_memcpy(data->cmk, tk + 40, 20); + wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK from TK", + data->cmk, 20); + return 0; + } + + if (eap_peap_get_isk(sm, data, isk, sizeof(isk)) < 0) + return -1; + wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk)); + + /* + * IPMK Seed = "Inner Methods Compound Keys" | ISK + * TempKey = First 40 octets of TK + * IPMK|CMK = PRF+(TempKey, IPMK Seed, 60) + * (note: draft-josefsson-pppext-eap-tls-eap-10.txt includes a space + * in the end of the label just before ISK; is that just a typo?) + */ + wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40); + res = peap_prfplus(data->peap_version, tk, 40, + "Inner Methods Compound Keys", + isk, sizeof(isk), imck, sizeof(imck)); + forced_memzero(isk, sizeof(isk)); + if (res < 0) + return -1; + wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)", + imck, sizeof(imck)); + + os_memcpy(data->ipmk, imck, 40); + wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40); + os_memcpy(data->cmk, imck + 40, 20); + wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20); + forced_memzero(imck, sizeof(imck)); + + return 0; +} + + +static int eap_tlv_add_cryptobinding(struct eap_sm *sm, + struct eap_peap_data *data, + struct wpabuf *buf) +{ + u8 *mac; + u8 eap_type = EAP_TYPE_PEAP; + const u8 *addr[2]; + size_t len[2]; + u16 tlv_type; + + /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */ + addr[0] = wpabuf_put(buf, 0); + len[0] = 60; + addr[1] = &eap_type; + len[1] = 1; + + tlv_type = EAP_TLV_CRYPTO_BINDING_TLV; + wpabuf_put_be16(buf, tlv_type); + wpabuf_put_be16(buf, 56); + + wpabuf_put_u8(buf, 0); /* Reserved */ + wpabuf_put_u8(buf, data->peap_version); /* Version */ + wpabuf_put_u8(buf, data->peap_version); /* RecvVersion */ + wpabuf_put_u8(buf, 1); /* SubType: 0 = Request, 1 = Response */ + wpabuf_put_data(buf, data->binding_nonce, 32); /* Nonce */ + mac = wpabuf_put(buf, 20); /* Compound_MAC */ + wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK", data->cmk, 20); + wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1", + addr[0], len[0]); + wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2", + addr[1], len[1]); + if (hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac) < 0) + return -1; + wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC", mac, SHA1_MAC_LEN); + data->crypto_binding_used = 1; + + return 0; +} + + +/** + * eap_tlv_build_result - Build EAP-TLV Result message + * @id: EAP identifier for the header + * @status: Status (EAP_TLV_RESULT_SUCCESS or EAP_TLV_RESULT_FAILURE) + * Returns: Buffer to the allocated EAP-TLV Result message or %NULL on failure + * + * This function builds an EAP-TLV Result message. The caller is responsible + * for freeing the returned buffer. + */ +static struct wpabuf * eap_tlv_build_result(struct eap_sm *sm, + struct eap_peap_data *data, + int crypto_tlv_used, + int id, u16 status) +{ + struct wpabuf *msg; + size_t len; + + if (data->crypto_binding == NO_BINDING) + crypto_tlv_used = 0; + + len = 6; + if (crypto_tlv_used) + len += 60; /* Cryptobinding TLV */ + msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, len, + EAP_CODE_RESPONSE, id); + if (msg == NULL) + return NULL; + + wpabuf_put_u8(msg, 0x80); /* Mandatory */ + wpabuf_put_u8(msg, EAP_TLV_RESULT_TLV); + wpabuf_put_be16(msg, 2); /* Length */ + wpabuf_put_be16(msg, status); /* Status */ + + if (crypto_tlv_used && eap_tlv_add_cryptobinding(sm, data, msg)) { + wpabuf_clear_free(msg); + return NULL; + } + + return msg; +} + + +static int eap_tlv_validate_cryptobinding(struct eap_sm *sm, + struct eap_peap_data *data, + const u8 *crypto_tlv, + size_t crypto_tlv_len) +{ + u8 buf[61], mac[SHA1_MAC_LEN]; + const u8 *pos; + + if (eap_peap_derive_cmk(sm, data) < 0) { + wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not derive CMK"); + return -1; + } + + if (crypto_tlv_len != 4 + 56) { + wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid cryptobinding TLV " + "length %d", (int) crypto_tlv_len); + return -1; + } + + pos = crypto_tlv; + pos += 4; /* TLV header */ + if (pos[1] != data->peap_version) { + wpa_printf(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV Version " + "mismatch (was %d; expected %d)", + pos[1], data->peap_version); + return -1; + } + + if (pos[3] != 0) { + wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected Cryptobinding TLV " + "SubType %d", pos[3]); + return -1; + } + pos += 4; + os_memcpy(data->binding_nonce, pos, 32); + pos += 32; /* Nonce */ + + /* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */ + os_memcpy(buf, crypto_tlv, 60); + os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */ + buf[60] = EAP_TYPE_PEAP; + wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Compound_MAC data", + buf, sizeof(buf)); + hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac); + + if (os_memcmp_const(mac, pos, SHA1_MAC_LEN) != 0) { + wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in " + "cryptobinding TLV"); + wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received MAC", + pos, SHA1_MAC_LEN); + wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Expected MAC", + mac, SHA1_MAC_LEN); + return -1; + } + + wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received"); + + return 0; +} + + +/** + * eap_tlv_process - Process a received EAP-TLV message and generate a response + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() + * @ret: Return values from EAP request validation and processing + * @req: EAP-TLV request to be processed. The caller must have validated that + * the buffer is large enough to contain full request (hdr->length bytes) and + * that the EAP type is EAP_TYPE_TLV. + * @resp: Buffer to return a pointer to the allocated response message. This + * field should be initialized to %NULL before the call. The value will be + * updated if a response message is generated. The caller is responsible for + * freeing the allocated message. + * @force_failure: Force negotiation to fail + * Returns: 0 on success, -1 on failure + */ +static int 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) +{ + size_t left, tlv_len; + const u8 *pos; + const u8 *result_tlv = NULL, *crypto_tlv = NULL; + size_t result_tlv_len = 0, crypto_tlv_len = 0; + int tlv_type, mandatory; + + /* Parse TLVs */ + pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, req, &left); + if (pos == NULL) + return -1; + wpa_hexdump(MSG_DEBUG, "EAP-TLV: Received TLVs", pos, left); + while (left >= 4) { + mandatory = !!(pos[0] & 0x80); + tlv_type = WPA_GET_BE16(pos) & 0x3fff; + pos += 2; + tlv_len = WPA_GET_BE16(pos); + pos += 2; + left -= 4; + if (tlv_len > left) { + wpa_printf(MSG_DEBUG, "EAP-TLV: TLV underrun " + "(tlv_len=%lu left=%lu)", + (unsigned long) tlv_len, + (unsigned long) left); + return -1; + } + switch (tlv_type) { + case EAP_TLV_RESULT_TLV: + result_tlv = pos; + result_tlv_len = tlv_len; + break; + case EAP_TLV_CRYPTO_BINDING_TLV: + crypto_tlv = pos; + crypto_tlv_len = tlv_len; + break; + default: + wpa_printf(MSG_DEBUG, "EAP-TLV: Unsupported TLV Type " + "%d%s", tlv_type, + mandatory ? " (mandatory)" : ""); + if (mandatory) { + /* NAK TLV and ignore all TLVs in this packet. + */ + *resp = eap_tlv_build_nak(eap_get_id(req), + tlv_type); + return *resp == NULL ? -1 : 0; + } + /* Ignore this TLV, but process other TLVs */ + break; + } + + pos += tlv_len; + left -= tlv_len; + } + if (left) { + wpa_printf(MSG_DEBUG, "EAP-TLV: Last TLV too short in " + "Request (left=%lu)", (unsigned long) left); + return -1; + } + + /* Process supported TLVs */ + if (crypto_tlv && data->crypto_binding != NO_BINDING) { + wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV", + crypto_tlv, crypto_tlv_len); + if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4, + crypto_tlv_len + 4) < 0) { + if (result_tlv == NULL) + return -1; + force_failure = 1; + crypto_tlv = NULL; /* do not include Cryptobinding TLV + * in response, if the received + * cryptobinding was invalid. */ + } + } else if (!crypto_tlv && data->crypto_binding == REQUIRE_BINDING) { + wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV"); + return -1; + } + + if (result_tlv) { + int status, resp_status; + wpa_hexdump(MSG_DEBUG, "EAP-TLV: Result TLV", + result_tlv, result_tlv_len); + if (result_tlv_len < 2) { + wpa_printf(MSG_INFO, "EAP-TLV: Too short Result TLV " + "(len=%lu)", + (unsigned long) result_tlv_len); + return -1; + } + status = WPA_GET_BE16(result_tlv); + if (status == EAP_TLV_RESULT_SUCCESS) { + wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Success " + "- EAP-TLV/Phase2 Completed"); + if (force_failure) { + wpa_printf(MSG_INFO, "EAP-TLV: Earlier failure" + " - force failed Phase 2"); + resp_status = EAP_TLV_RESULT_FAILURE; + ret->decision = DECISION_FAIL; + } else { + resp_status = EAP_TLV_RESULT_SUCCESS; + ret->decision = DECISION_UNCOND_SUCC; + } + } else if (status == EAP_TLV_RESULT_FAILURE) { + wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Failure"); + resp_status = EAP_TLV_RESULT_FAILURE; + ret->decision = DECISION_FAIL; + } else { + wpa_printf(MSG_INFO, "EAP-TLV: Unknown TLV Result " + "Status %d", status); + resp_status = EAP_TLV_RESULT_FAILURE; + ret->decision = DECISION_FAIL; + } + ret->methodState = METHOD_DONE; + + *resp = eap_tlv_build_result(sm, data, crypto_tlv != NULL, + eap_get_id(req), resp_status); + } + + return 0; +} + + +static int eap_peap_phase2_request(struct eap_sm *sm, + struct eap_peap_data *data, + struct eap_method_ret *ret, + struct wpabuf *req, + struct wpabuf **resp) +{ + struct eap_hdr *hdr = wpabuf_mhead(req); + size_t len = be_to_host16(hdr->length); + u8 *pos; + struct eap_method_ret iret; + struct eap_peer_config *config = eap_get_config(sm); + + if (len <= sizeof(struct eap_hdr)) { + wpa_printf(MSG_INFO, "EAP-PEAP: too short " + "Phase 2 request (len=%lu)", (unsigned long) len); + return -1; + } + pos = (u8 *) (hdr + 1); + wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Request: type=%d", *pos); + switch (*pos) { + case EAP_TYPE_IDENTITY: + *resp = eap_sm_buildIdentity(sm, hdr->identifier, 1); + break; + case EAP_TYPE_TLV: + os_memset(&iret, 0, sizeof(iret)); + if (eap_tlv_process(sm, data, &iret, req, resp, + data->phase2_eap_started && + !data->phase2_eap_success)) { + ret->methodState = METHOD_DONE; + ret->decision = DECISION_FAIL; + return -1; + } + if (iret.methodState == METHOD_DONE || + iret.methodState == METHOD_MAY_CONT) { + ret->methodState = iret.methodState; + ret->decision = iret.decision; + data->phase2_success = 1; + } + break; + case EAP_TYPE_EXPANDED: +#ifdef EAP_TNC + if (data->soh) { + const u8 *epos; + size_t eleft; + + epos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21, + req, &eleft); + if (epos) { + struct wpabuf *buf; + wpa_printf(MSG_DEBUG, + "EAP-PEAP: SoH EAP Extensions"); + buf = tncc_process_soh_request(data->soh, + epos, eleft); + if (buf) { + *resp = eap_msg_alloc( + EAP_VENDOR_MICROSOFT, 0x21, + wpabuf_len(buf), + EAP_CODE_RESPONSE, + hdr->identifier); + if (*resp == NULL) { + ret->methodState = METHOD_DONE; + ret->decision = DECISION_FAIL; + wpabuf_clear_free(buf); + return -1; + } + wpabuf_put_buf(*resp, buf); + wpabuf_clear_free(buf); + break; + } + } + } +#endif /* EAP_TNC */ + /* fall through */ + default: + if (data->phase2_type.vendor == EAP_VENDOR_IETF && + data->phase2_type.method == EAP_TYPE_NONE) { + size_t i; + for (i = 0; i < data->num_phase2_types; i++) { + if (data->phase2_types[i].vendor != + EAP_VENDOR_IETF || + data->phase2_types[i].method != *pos) + continue; + + data->phase2_type.vendor = + data->phase2_types[i].vendor; + data->phase2_type.method = + data->phase2_types[i].method; + wpa_printf(MSG_DEBUG, "EAP-PEAP: Selected " + "Phase 2 EAP vendor %d method %d", + data->phase2_type.vendor, + data->phase2_type.method); + break; + } + } + if (*pos != data->phase2_type.method || + *pos == EAP_TYPE_NONE) { + if (eap_peer_tls_phase2_nak(data->phase2_types, + data->num_phase2_types, + hdr, resp)) + return -1; + return 0; + } + + if (data->phase2_priv == NULL) { + data->phase2_method = eap_peer_get_eap_method( + data->phase2_type.vendor, + data->phase2_type.method); + if (data->phase2_method) { + sm->init_phase2 = 1; + data->phase2_priv = + data->phase2_method->init(sm); + sm->init_phase2 = 0; + } + } + if (data->phase2_priv == NULL || data->phase2_method == NULL) { + wpa_printf(MSG_INFO, "EAP-PEAP: failed to initialize " + "Phase 2 EAP method %d", *pos); + ret->methodState = METHOD_DONE; + ret->decision = DECISION_FAIL; + return -1; + } + data->phase2_eap_started = 1; + os_memset(&iret, 0, sizeof(iret)); + *resp = data->phase2_method->process(sm, data->phase2_priv, + &iret, req); + if ((iret.methodState == METHOD_DONE || + iret.methodState == METHOD_MAY_CONT) && + (iret.decision == DECISION_UNCOND_SUCC || + iret.decision == DECISION_COND_SUCC)) { + data->phase2_eap_success = 1; + data->phase2_success = 1; + } + break; + } + + if (*resp == NULL && + (config->pending_req_identity || config->pending_req_password || + config->pending_req_otp || config->pending_req_new_password || + config->pending_req_sim)) { + wpabuf_clear_free(data->pending_phase2_req); + data->pending_phase2_req = wpabuf_alloc_copy(hdr, len); + } + + return 0; +} + + +static int 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) +{ + struct wpabuf *in_decrypted = NULL; + int res, skip_change = 0; + struct eap_hdr *hdr, *rhdr; + struct wpabuf *resp = NULL; + size_t len; + + wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for" + " Phase 2", (unsigned long) wpabuf_len(in_data)); + + if (data->pending_phase2_req) { + wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 request - " + "skip decryption and use old data"); + /* Clear TLS reassembly state. */ + eap_peer_tls_reset_input(&data->ssl); + in_decrypted = data->pending_phase2_req; + data->pending_phase2_req = NULL; + skip_change = 1; + goto continue_req; + } + + if (wpabuf_len(in_data) == 0 && sm->workaround && + data->phase2_success) { + /* + * Cisco ACS seems to be using TLS ACK to terminate + * EAP-PEAPv0/GTC. Try to reply with TLS ACK. + */ + wpa_printf(MSG_DEBUG, "EAP-PEAP: Received TLS ACK, but " + "expected data - acknowledge with TLS ACK since " + "Phase 2 has been completed"); + ret->decision = DECISION_COND_SUCC; + ret->methodState = METHOD_DONE; + return 1; + } else if (wpabuf_len(in_data) == 0) { + /* Received TLS ACK - requesting more fragments */ + return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP, + data->peap_version, + req->identifier, NULL, out_data); + } + + res = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted); + if (res) + return res; + +continue_req: + wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP", + in_decrypted); + + hdr = wpabuf_mhead(in_decrypted); + if (wpabuf_len(in_decrypted) == 5 && hdr->code == EAP_CODE_REQUEST && + be_to_host16(hdr->length) == 5 && + eap_get_type(in_decrypted) == EAP_TYPE_IDENTITY) { + /* At least FreeRADIUS seems to send full EAP header with + * EAP Request Identity */ + skip_change = 1; + } + if (wpabuf_len(in_decrypted) >= 5 && hdr->code == EAP_CODE_REQUEST && + eap_get_type(in_decrypted) == EAP_TYPE_TLV) { + skip_change = 1; + } + + if (data->peap_version == 0 && !skip_change) { + struct eap_hdr *nhdr; + struct wpabuf *nmsg = wpabuf_alloc(sizeof(struct eap_hdr) + + wpabuf_len(in_decrypted)); + if (nmsg == NULL) { + wpabuf_clear_free(in_decrypted); + return 0; + } + nhdr = wpabuf_put(nmsg, sizeof(*nhdr)); + wpabuf_put_buf(nmsg, in_decrypted); + nhdr->code = req->code; + nhdr->identifier = req->identifier; + nhdr->length = host_to_be16(sizeof(struct eap_hdr) + + wpabuf_len(in_decrypted)); + + wpabuf_clear_free(in_decrypted); + in_decrypted = nmsg; + } + + hdr = wpabuf_mhead(in_decrypted); + if (wpabuf_len(in_decrypted) < sizeof(*hdr)) { + wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 " + "EAP frame (len=%lu)", + (unsigned long) wpabuf_len(in_decrypted)); + wpabuf_clear_free(in_decrypted); + return 0; + } + len = be_to_host16(hdr->length); + if (len > wpabuf_len(in_decrypted)) { + wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in " + "Phase 2 EAP frame (len=%lu hdr->length=%lu)", + (unsigned long) wpabuf_len(in_decrypted), + (unsigned long) len); + wpabuf_clear_free(in_decrypted); + return 0; + } + if (len < wpabuf_len(in_decrypted)) { + wpa_printf(MSG_INFO, "EAP-PEAP: Odd.. Phase 2 EAP header has " + "shorter length than full decrypted data " + "(%lu < %lu)", + (unsigned long) len, + (unsigned long) wpabuf_len(in_decrypted)); + } + wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d " + "identifier=%d length=%lu", hdr->code, hdr->identifier, + (unsigned long) len); + switch (hdr->code) { + case EAP_CODE_REQUEST: + if (eap_peap_phase2_request(sm, data, ret, in_decrypted, + &resp)) { + wpabuf_clear_free(in_decrypted); + wpa_printf(MSG_INFO, "EAP-PEAP: Phase2 Request " + "processing failed"); + return 0; + } + break; + case EAP_CODE_SUCCESS: + wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success"); + if (data->peap_version == 1) { + /* EAP-Success within TLS tunnel is used to indicate + * shutdown of the TLS channel. The authentication has + * been completed. */ + if (data->phase2_eap_started && + !data->phase2_eap_success) { + wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 " + "Success used to indicate success, " + "but Phase 2 EAP was not yet " + "completed successfully"); + ret->methodState = METHOD_DONE; + ret->decision = DECISION_FAIL; + wpabuf_clear_free(in_decrypted); + return 0; + } + wpa_printf(MSG_DEBUG, "EAP-PEAP: Version 1 - " + "EAP-Success within TLS tunnel - " + "authentication completed"); + ret->decision = DECISION_UNCOND_SUCC; + ret->methodState = METHOD_DONE; + data->phase2_success = 1; + if (data->peap_outer_success == 2) { + wpabuf_clear_free(in_decrypted); + wpa_printf(MSG_DEBUG, "EAP-PEAP: Use TLS ACK " + "to finish authentication"); + return 1; + } else if (data->peap_outer_success == 1) { + /* Reply with EAP-Success within the TLS + * channel to complete the authentication. */ + resp = wpabuf_alloc(sizeof(struct eap_hdr)); + if (resp) { + rhdr = wpabuf_put(resp, sizeof(*rhdr)); + rhdr->code = EAP_CODE_SUCCESS; + rhdr->identifier = hdr->identifier; + rhdr->length = + host_to_be16(sizeof(*rhdr)); + } + } else { + /* No EAP-Success expected for Phase 1 (outer, + * unencrypted auth), so force EAP state + * machine to SUCCESS state. */ + sm->peap_done = TRUE; + } + } else { + /* FIX: ? */ + } + break; + case EAP_CODE_FAILURE: + wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure"); + ret->decision = DECISION_FAIL; + ret->methodState = METHOD_MAY_CONT; + ret->allowNotifications = FALSE; + /* Reply with EAP-Failure within the TLS channel to complete + * failure reporting. */ + resp = wpabuf_alloc(sizeof(struct eap_hdr)); + if (resp) { + rhdr = wpabuf_put(resp, sizeof(*rhdr)); + rhdr->code = EAP_CODE_FAILURE; + rhdr->identifier = hdr->identifier; + rhdr->length = host_to_be16(sizeof(*rhdr)); + } + break; + default: + wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in " + "Phase 2 EAP header", hdr->code); + break; + } + + wpabuf_clear_free(in_decrypted); + + if (resp) { + int skip_change2 = 0; + struct wpabuf *rmsg, buf; + + wpa_hexdump_buf_key(MSG_DEBUG, + "EAP-PEAP: Encrypting Phase 2 data", resp); + /* PEAP version changes */ + if (wpabuf_len(resp) >= 5 && + wpabuf_head_u8(resp)[0] == EAP_CODE_RESPONSE && + eap_get_type(resp) == EAP_TYPE_TLV) + skip_change2 = 1; + rmsg = resp; + if (data->peap_version == 0 && !skip_change2) { + wpabuf_set(&buf, wpabuf_head_u8(resp) + + sizeof(struct eap_hdr), + wpabuf_len(resp) - sizeof(struct eap_hdr)); + rmsg = &buf; + } + + if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP, + data->peap_version, req->identifier, + rmsg, out_data)) { + wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt " + "a Phase 2 frame"); + } + wpabuf_clear_free(resp); + } + + return 0; +} + + +static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv, + struct eap_method_ret *ret, + const struct wpabuf *reqData) +{ + const struct eap_hdr *req; + size_t left; + int res; + u8 flags, id; + struct wpabuf *resp; + const u8 *pos; + struct eap_peap_data *data = priv; + struct wpabuf msg; + + pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_PEAP, ret, + reqData, &left, &flags); + if (pos == NULL) + return NULL; + req = wpabuf_head(reqData); + id = req->identifier; + + if (flags & EAP_TLS_FLAGS_START) { + wpa_printf(MSG_DEBUG, "EAP-PEAP: Start (server ver=%d, own " + "ver=%d)", flags & EAP_TLS_VERSION_MASK, + data->peap_version); + if ((flags & EAP_TLS_VERSION_MASK) < data->peap_version) + data->peap_version = flags & EAP_TLS_VERSION_MASK; + if (data->force_peap_version >= 0 && + data->force_peap_version != data->peap_version) { + wpa_printf(MSG_WARNING, "EAP-PEAP: Failed to select " + "forced PEAP version %d", + data->force_peap_version); + ret->methodState = METHOD_DONE; + ret->decision = DECISION_FAIL; + ret->allowNotifications = FALSE; + return NULL; + } + wpa_printf(MSG_DEBUG, "EAP-PEAP: Using PEAP version %d", + data->peap_version); + left = 0; /* make sure that this frame is empty, even though it + * should always be, anyway */ + } + + wpabuf_set(&msg, pos, left); + + resp = NULL; + if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) && + !data->resuming) { + res = eap_peap_decrypt(sm, data, ret, req, &msg, &resp); + } else { + if (sm->waiting_ext_cert_check && data->pending_resp) { + struct eap_peer_config *config = eap_get_config(sm); + + if (config->pending_ext_cert_check == + EXT_CERT_CHECK_GOOD) { + wpa_printf(MSG_DEBUG, + "EAP-PEAP: External certificate check succeeded - continue handshake"); + resp = data->pending_resp; + data->pending_resp = NULL; + sm->waiting_ext_cert_check = 0; + return resp; + } + + if (config->pending_ext_cert_check == + EXT_CERT_CHECK_BAD) { + wpa_printf(MSG_DEBUG, + "EAP-PEAP: External certificate check failed - force authentication failure"); + ret->methodState = METHOD_DONE; + ret->decision = DECISION_FAIL; + sm->waiting_ext_cert_check = 0; + return NULL; + } + + wpa_printf(MSG_DEBUG, + "EAP-PEAP: Continuing to wait external server certificate validation"); + return NULL; + } + + res = eap_peer_tls_process_helper(sm, &data->ssl, + EAP_TYPE_PEAP, + data->peap_version, id, &msg, + &resp); + + if (res < 0) { + wpa_printf(MSG_DEBUG, + "EAP-PEAP: TLS processing failed"); + ret->methodState = METHOD_DONE; + ret->decision = DECISION_FAIL; + return resp; + } + + + if (sm->waiting_ext_cert_check) { + wpa_printf(MSG_DEBUG, + "EAP-PEAP: Waiting external server certificate validation"); + wpabuf_clear_free(data->pending_resp); + data->pending_resp = resp; + return NULL; + } + + if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) { + char *label; + wpa_printf(MSG_DEBUG, + "EAP-PEAP: TLS done, proceed to Phase 2"); + eap_peap_free_key(data); + /* draft-josefsson-ppext-eap-tls-eap-05.txt + * specifies that PEAPv1 would use "client PEAP + * encryption" as the label. However, most existing + * PEAPv1 implementations seem to be using the old + * label, "client EAP encryption", instead. Use the old + * label by default, but allow it to be configured with + * phase1 parameter peaplabel=1. */ + if (data->force_new_label) + label = "client PEAP encryption"; + else + label = "client EAP encryption"; + wpa_printf(MSG_DEBUG, "EAP-PEAP: using label '%s' in " + "key derivation", label); + data->key_data = + eap_peer_tls_derive_key(sm, &data->ssl, label, + NULL, 0, + EAP_TLS_KEY_LEN + + EAP_EMSK_LEN); + if (data->key_data) { + wpa_hexdump_key(MSG_DEBUG, + "EAP-PEAP: Derived key", + data->key_data, + EAP_TLS_KEY_LEN); + wpa_hexdump_key(MSG_DEBUG, + "EAP-PEAP: Derived EMSK", + data->key_data + + EAP_TLS_KEY_LEN, + EAP_EMSK_LEN); + } else { + wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to " + "derive key"); + } + + os_free(data->session_id); + data->session_id = + eap_peer_tls_derive_session_id(sm, &data->ssl, + EAP_TYPE_PEAP, + &data->id_len); + if (data->session_id) { + wpa_hexdump(MSG_DEBUG, + "EAP-PEAP: Derived Session-Id", + data->session_id, data->id_len); + } else { + wpa_printf(MSG_ERROR, "EAP-PEAP: Failed to " + "derive Session-Id"); + } + + if (sm->workaround && data->resuming) { + /* + * At least few RADIUS servers (Aegis v1.1.6; + * but not v1.1.4; and Cisco ACS) seem to be + * terminating PEAPv1 (Aegis) or PEAPv0 (Cisco + * ACS) session resumption with outer + * EAP-Success. This does not seem to follow + * draft-josefsson-pppext-eap-tls-eap-05.txt + * section 4.2, so only allow this if EAP + * workarounds are enabled. + */ + wpa_printf(MSG_DEBUG, "EAP-PEAP: Workaround - " + "allow outer EAP-Success to " + "terminate PEAP resumption"); + ret->decision = DECISION_COND_SUCC; + data->phase2_success = 1; + } + + data->resuming = 0; + } + + if (res == 2) { + /* + * Application data included in the handshake message. + */ + wpabuf_clear_free(data->pending_phase2_req); + data->pending_phase2_req = resp; + resp = NULL; + res = eap_peap_decrypt(sm, data, ret, req, &msg, + &resp); + } + } + + if (ret->methodState == METHOD_DONE) { + ret->allowNotifications = FALSE; + } + + if (res == 1) { + wpabuf_clear_free(resp); + return eap_peer_tls_build_ack(id, EAP_TYPE_PEAP, + data->peap_version); + } + + return resp; +} + + +static Boolean eap_peap_has_reauth_data(struct eap_sm *sm, void *priv) +{ + struct eap_peap_data *data = priv; + return tls_connection_established(sm->ssl_ctx, data->ssl.conn) && + data->phase2_success; +} + + +static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv) +{ + struct eap_peap_data *data = priv; + + if (data->phase2_priv && data->phase2_method && + data->phase2_method->deinit_for_reauth) + data->phase2_method->deinit_for_reauth(sm, data->phase2_priv); + wpabuf_clear_free(data->pending_phase2_req); + data->pending_phase2_req = NULL; + wpabuf_clear_free(data->pending_resp); + data->pending_resp = NULL; + data->crypto_binding_used = 0; +} + + +static void * eap_peap_init_for_reauth(struct eap_sm *sm, void *priv) +{ + struct eap_peap_data *data = priv; + eap_peap_free_key(data); + os_free(data->session_id); + data->session_id = NULL; + if (eap_peer_tls_reauth_init(sm, &data->ssl)) { + os_free(data); + return NULL; + } + if (data->phase2_priv && data->phase2_method && + data->phase2_method->init_for_reauth) + data->phase2_method->init_for_reauth(sm, data->phase2_priv); + data->phase2_success = 0; + data->phase2_eap_success = 0; + data->phase2_eap_started = 0; + data->resuming = 1; + data->reauth = 1; + sm->peap_done = FALSE; + return priv; +} + + +static int eap_peap_get_status(struct eap_sm *sm, void *priv, char *buf, + size_t buflen, int verbose) +{ + struct eap_peap_data *data = priv; + int len, ret; + + len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose); + if (data->phase2_method) { + ret = os_snprintf(buf + len, buflen - len, + "EAP-PEAPv%d Phase2 method=%s\n", + data->peap_version, + data->phase2_method->name); + if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + } + return len; +} + + +static Boolean eap_peap_isKeyAvailable(struct eap_sm *sm, void *priv) +{ + struct eap_peap_data *data = priv; + return data->key_data != NULL && data->phase2_success; +} + + +static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len) +{ + struct eap_peap_data *data = priv; + u8 *key; + + if (data->key_data == NULL || !data->phase2_success) + return NULL; + + key = os_malloc(EAP_TLS_KEY_LEN); + if (key == NULL) + return NULL; + + *len = EAP_TLS_KEY_LEN; + + if (data->crypto_binding_used) { + u8 csk[128]; + /* + * Note: It looks like Microsoft implementation requires null + * termination for this label while the one used for deriving + * IPMK|CMK did not use null termination. + */ + if (peap_prfplus(data->peap_version, data->ipmk, 40, + "Session Key Generating Function", + (u8 *) "\00", 1, csk, sizeof(csk)) < 0) { + os_free(key); + return NULL; + } + wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk)); + os_memcpy(key, csk, EAP_TLS_KEY_LEN); + wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key", + key, EAP_TLS_KEY_LEN); + forced_memzero(csk, sizeof(csk)); + } else + os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN); + + return key; +} + + +static u8 * eap_peap_get_emsk(struct eap_sm *sm, void *priv, size_t *len) +{ + struct eap_peap_data *data = priv; + u8 *key; + + if (!data->key_data || !data->phase2_success) + return NULL; + + if (data->crypto_binding_used) { + /* [MS-PEAP] does not define EMSK derivation */ + return NULL; + } + + key = os_memdup(data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN); + if (!key) + return NULL; + + *len = EAP_EMSK_LEN; + + return key; +} + + +static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len) +{ + struct eap_peap_data *data = priv; + u8 *id; + + if (data->session_id == NULL || !data->phase2_success) + return NULL; + + id = os_memdup(data->session_id, data->id_len); + if (id == NULL) + return NULL; + + *len = data->id_len; + + return id; +} + + +int eap_peer_peap_register(void) +{ + struct eap_method *eap; + + eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, + EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP"); + if (eap == NULL) + return -1; + + eap->init = eap_peap_init; + eap->deinit = eap_peap_deinit; + eap->process = eap_peap_process; + eap->isKeyAvailable = eap_peap_isKeyAvailable; + eap->getKey = eap_peap_getKey; + eap->get_emsk = eap_peap_get_emsk; + eap->get_status = eap_peap_get_status; + eap->has_reauth_data = eap_peap_has_reauth_data; + eap->deinit_for_reauth = eap_peap_deinit_for_reauth; + eap->init_for_reauth = eap_peap_init_for_reauth; + eap->getSessionId = eap_peap_get_session_id; + + return eap_peer_method_register(eap); +} diff --git a/wpa_supplicant-2.9_standard/BUILD.gn b/wpa_supplicant-2.9_standard/BUILD.gn index 4461291f9d43eb8f977069c53dfb9855787b4bbc..226a4fc77b9b3b5b082e1c5763549696b765901a 100644 --- a/wpa_supplicant-2.9_standard/BUILD.gn +++ b/wpa_supplicant-2.9_standard/BUILD.gn @@ -31,6 +31,7 @@ declare_args() { wpa_supplicant_config_wfd = true wpa_supplicant_config_mlo = false wpa_supplicant_config_okc_roam = false + wpa_supplicant_config_ext_auth = false } if (wpa_supplicant_ohos_certmgr) { @@ -88,6 +89,9 @@ CONFIG_MAIN = "main" config("wpa_warnings") { cflags = [ "-Wno-error=sign-compare" ] + if (wpa_supplicant_config_ext_auth) { + cflags += [ "-DEXT_AUTHENTICATION_SUPPORT" ] + } ldflags = [ "-flto", "-fsanitize=cfi", @@ -173,6 +177,9 @@ ohos_shared_library("wpa_client") { include_dirs = wpa_client_base_include_dirs cflags = wpa_client_base_cflags + if (wpa_supplicant_config_ext_auth) { + cflags += [ "-DEXT_AUTHENTICATION_SUPPORT" ] + } if ("${CONFIG_CTRL_IFACE}" == "udp") { cflags += [ "-DCONFIG_CTRL_IFACE_UDP" ] } else { @@ -215,6 +222,9 @@ ohos_shared_library("wpa_client_vendor") { include_dirs = wpa_client_vendor_base_include_dirs cflags = wpa_client_base_cflags + if (wpa_supplicant_config_ext_auth) { + cflags += [ "-DEXT_AUTHENTICATION_SUPPORT" ] + } if ("${CONFIG_CTRL_IFACE}" == "udp") { cflags += [ "-DCONFIG_CTRL_IFACE_UDP" ] } else { @@ -258,6 +268,9 @@ ohos_shared_library("wpa_client_updater") { include_dirs = wpa_client_base_include_dirs cflags = wpa_client_base_cflags + if (wpa_supplicant_config_ext_auth) { + cflags += [ "-DEXT_AUTHENTICATION_SUPPORT" ] + } if ("${CONFIG_CTRL_IFACE}" == "udp") { cflags += [ "-DCONFIG_CTRL_IFACE_UDP" ] } else { @@ -408,6 +421,7 @@ wpa_base_sources = [ "$WPA_ROOT_DIR/src/eap_common/eap_pwd_common.c", "$WPA_ROOT_DIR/src/eap_common/eap_sim_common.c", "$WPA_ROOT_DIR/src/eap_common/eap_wsc_common.c", + "$WPA_ROOT_DIR/src/eap_common/ext_authentication.c", "$WPA_ROOT_DIR/src/eap_peer/eap_aka.c", "$WPA_ROOT_DIR/src/eap_peer/eap_gtc.c", "$WPA_ROOT_DIR/src/eap_peer/eap_mschapv2.c", @@ -552,6 +566,9 @@ ohos_shared_library("wpa_sys") { "-DEAP_GTC", "-DCONFIG_P2P_USER_REJECT", ] + if (wpa_supplicant_config_ext_auth) { + cflags += [ "-DEXT_AUTHENTICATION_SUPPORT" ] + } if ("${CONFIG_CTRL_IFACE}" == "udp") { cflags += [ "-DCONFIG_CTRL_IFACE_UDP" ] } else { @@ -587,6 +604,10 @@ ohos_shared_library("wpa_sys") { external_deps += [ "hilog:libhilog" ] } + if (wpa_supplicant_config_ext_auth) { + external_deps += [ "drivers_peripheral_wlan:wpa_hdi_client" ] + } + if ("${CONFIG_DRIVER}" == "nl80211") { sources += [ "$WPA_ROOT_DIR/src/ap/ieee802_11_he.c", @@ -714,6 +735,9 @@ ohos_shared_library("wpa_sys_updater") { "-DPKCS12_FUNCS", "-DCONFIG_P2P_USER_REJECT", ] + if (wpa_supplicant_config_ext_auth) { + cflags += [ "-DEXT_AUTHENTICATION_SUPPORT" ] + } if ("${CONFIG_CTRL_IFACE}" == "udp") { cflags += [ "-DCONFIG_CTRL_IFACE_UDP" ] } else { @@ -888,6 +912,9 @@ ohos_shared_library("wpa") { "-DCONFIG_P2P_USER_REJECT", "-DCONFIG_HUKS_ENCRYPTION_SUPPORT", ] + if (wpa_supplicant_config_ext_auth) { + cflags += [ "-DEXT_AUTHENTICATION_SUPPORT" ] + } if ("${CONFIG_CTRL_IFACE}" == "udp") { cflags += [ "-DCONFIG_CTRL_IFACE_UDP" ] } else { @@ -1057,6 +1084,9 @@ ohos_shared_library("wpa_updater") { "-DPKCS12_FUNCS", "-DCONFIG_P2P_USER_REJECT", ] + if (wpa_supplicant_config_ext_auth) { + cflags += [ "-DEXT_AUTHENTICATION_SUPPORT" ] + } if ("${CONFIG_CTRL_IFACE}" == "udp") { cflags += [ "-DCONFIG_CTRL_IFACE_UDP" ] } else { @@ -1082,6 +1112,9 @@ ohos_shared_library("wpa_updater") { "drivers_peripheral_wlan:wpa_hdi_client", "init:libbegetutil", ] + if (wpa_supplicant_config_ext_auth) { + external_deps += [ "drivers_peripheral_wlan:wpa_hdi_client" ] + } if (wpa_supplicant_config_openssl) { external_deps += [ "openssl:libcrypto_shared", @@ -1197,6 +1230,10 @@ ohos_executable("wpa_cli") { "-DCONFIG_DEBUG_FILE", "-DCONFIG_OPEN_HARMONY_PATCH", ] + if (wpa_supplicant_config_ext_auth) { + cflags += [ "-DEXT_AUTHENTICATION_SUPPORT" ] + } + if ("${CONFIG_CTRL_IFACE}" == "udp") { cflags += [ "-DCONFIG_CTRL_IFACE_UDP" ] } else { @@ -1291,6 +1328,9 @@ ohos_executable("hostapd_cli") { "-DCONFIG_DEBUG_FILE", "-DCONFIG_OPEN_HARMONY_PATCH", ] + if (wpa_supplicant_config_ext_auth) { + cflags += [ "-DEXT_AUTHENTICATION_SUPPORT" ] + } if ("${CONFIG_CTRL_IFACE}" == "udp") { cflags += [ "-DCONFIG_CTRL_IFACE_UDP" ] @@ -1340,6 +1380,9 @@ ohos_executable("wpa_supplicant") { "-DCONFIG_DEBUG_FILE", "-DCONFIG_OPEN_HARMONY_PATCH", ] + if (wpa_supplicant_config_ext_auth) { + cflags += [ "-DEXT_AUTHENTICATION_SUPPORT" ] + } install_images = [ chipset_base_dir ] part_name = "wpa_supplicant" subsystem_name = "thirdparty" @@ -1357,6 +1400,9 @@ ohos_executable("hostapd") { "-DCONFIG_DEBUG_FILE", "-DCONFIG_OPEN_HARMONY_PATCH", ] + if (wpa_supplicant_config_ext_auth) { + cflags += [ "-DEXT_AUTHENTICATION_SUPPORT" ] + } install_images = [ chipset_base_dir ] part_name = "wpa_supplicant" subsystem_name = "thirdparty" diff --git a/wpa_supplicant-2.9_standard/src/eap_common/ext_authentication.c b/wpa_supplicant-2.9_standard/src/eap_common/ext_authentication.c new file mode 100644 index 0000000000000000000000000000000000000000..cd7c4001721a31d9ecbb108a935bbafeaf676827 --- /dev/null +++ b/wpa_supplicant-2.9_standard/src/eap_common/ext_authentication.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 202502025. All rights reserved. + */ + +#ifdef EXT_AUTHENTICATION_SUPPORT +#include "ext_authentication.h" + +#include "common.h" +#include "includes.h" +#include "trace.h" +#include "wpa_debug.h" + +#define EXT_AUTH_CODE_SIZE 5 +#define EAP_TYPE_SIZE 255 + +static u8 g_authMap[EXT_AUTH_CODE_SIZE][EAP_TYPE_SIZE] = {0}; + +const char *IfnameToString[] = { + "unkown", + "wlan0", + "eth0" +}; + +bool RegExtAuth(int code, int type, int ifname) +{ + wpa_printf(MSG_INFO, "ext_certification RegExtAuth : code : %d , type : %d, ifname : %d", code, type, ifname); + bool illegal = code < 1 || code >= EXT_AUTH_CODE_SIZE || type < 0 || type >= EAP_TYPE_SIZE || ifname < 0 || + ifname >= IFNAME_SIZE; + if (illegal) { + wpa_printf(MSG_ERROR, "ext_certification RegExtAuth : code : %d , type : %d, ifname : %d", code, type, ifname); + return false; + } + g_authMap[code][type] = ifname; + return true; +} + +bool UnRegExtAuth(int code, int type) +{ + wpa_printf(MSG_INFO, "ext_certification UnRegExtAuth : code : %d , type : %d", code, type); + if (code < 1 || code >= EXT_AUTH_CODE_SIZE || type < 0 || type >= EAP_TYPE_SIZE) { + wpa_printf(MSG_ERROR, "ext_certification UnRegExtAuth : code : %d , type : %d", code, type); + return false; + } + g_authMap[code][type] = IFNAME_UNKOWN; + return true; +} + +int GetExtAuth(int code, int type) +{ + wpa_printf(MSG_INFO, "ext_certification GetExtAuth : code : %d , type : %d, res : %d", code, type, + (int)g_authMap[code][type]); + if (code < 1 || code >= EXT_AUTH_CODE_SIZE || type < 0 || type >= EAP_TYPE_SIZE) { + wpa_printf(MSG_ERROR, "ext_certification GetExtAuth : code : %d , type : %d", code, type); + return IFNAME_UNKOWN; + } + return g_authMap[code][type]; +} + +static int g_idx = 0; + +int GetAuthenticationIdx() +{ + return g_idx; +} + +void AddAuthenticationIdx() +{ + int idxMod = 100; + g_idx = (g_idx + 1) % idxMod; +} + +static uint8_t* g_eapData = NULL; +static int g_eapDataLen = 0; + +uint8_t* GetEapData() +{ + return g_eapData; +} + +int GetEapDataLen() +{ + return g_eapDataLen; +} + +void ClearEapData() +{ + free(g_eapData); + g_eapData = NULL; + g_eapDataLen = 0; +} + +void SetEapData(u8* eapData, int eapDataLen) +{ + if (eapData == NULL || eapDataLen <= 0) { + wpa_printf(MSG_ERROR, "SetEapData input error"); + return; + } + if (g_eapData != NULL) { + free(g_eapData); // 保险机制 + } + + g_eapDataLen = eapDataLen; + g_eapData = (u8*)malloc(eapDataLen * sizeof(u8)); +} + +void SetEapData(char* value) +{ + g_eapData = value; +} + +static struct eap_sm* g_eapSm = 0; + +void SetEapSm(struct eap_sm* eapSm) +{ + g_eapSm = eapSm; +} + +struct eap_sm* GetEapSm() +{ + return g_eapSm; +} + + +static struct EncryptData g_encryptData; +void SetEncryptData(struct eap_ssl_data* ssl, int eapType, int version, unsigned char id) +{ + wpa_printf(MSG_INFO, "ext_certification SetEncryptData : eapType : %d, version : %d, id : %hhu", eapType , version, + (u8)id); + g_encryptData.ssl = ssl; + g_encryptData.eapType = eapType; + g_encryptData.version = version; + g_encryptData.id = id; +} + +void SetEncryptEapType(int eapType) +{ + wpa_printf(MSG_INFO, "ext_certification SetEncryptEapType : eapType : %d", eapType); + g_encryptData.eapType = eapType; +} + +struct EncryptData* GetEncryptData() +{ + return &g_encyptData; +} + +int g_code = 0; + +int GetCode() +{ + return g_code; +} + +void SetCode(int code) +{ + g_code = code; +} + +#endif /* EXT_AUTHENTICATION_SUPPORT */ \ No newline at end of file diff --git a/wpa_supplicant-2.9_standard/src/eap_common/ext_authentication.h b/wpa_supplicant-2.9_standard/src/eap_common/ext_authentication.h new file mode 100644 index 0000000000000000000000000000000000000000..a7a6f121bfe0f04eefed3db5c0600151f5e632f1 --- /dev/null +++ b/wpa_supplicant-2.9_standard/src/eap_common/ext_authentication.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved. + */ + +#ifndef EXT_AUTHENTICATION_H +#define EXT_AUTHENTICATION_H + +#ifdef EXT_AUTHENTICATION_SUPPORT +#include + +#define TYPE_OFFSET 4 +#define IFNAME_LENGTH 2 +#define BUF_SIZE 2048 +#define PARAM_LEN 30 +#define BASE64_NUM 3 + +enum Ifname { + IFNAME_UNKOWN = 0, + IFNAME_WIFI0 = 1, + IFNAME_ETH0 = 2, + IFNAME_SIZE = 3 + }; + +extern const char* IfnameToString[]; + +bool RegExtAuth(int code, int type, int ifname); +bool UnRegExtAuth(int code, int type); +int GetExtAuth(int code, int type); + +// 递增的数字标识符 +int GetAuthenticationIdx(); +void AddAuthenticationIdx(); + +char* GetEapData(); +void SetEapData(char* value); + +struct eap_sm; +void SetEapSm(struct eap_sm *eapSm); +struct eap_sm* GetEapSm(); + +struct eap_ssl_data; +struct EncryptData { + struct eap_ssl_data* ssl; + int eapType; + int version; + unsigned char id; +}; + +void SetEncryptData(struct eap_ssl_data* ssl, int eapType, int version, unsigned char id); +void SetEncryptEapType(int eapType); +struct EncryptData* GetEncryptData(); + +int GetCode(); +void SetCode(int code); + +#endif /* EXT_AUTHENTICATION_SUPPORT */ +#endif /* EXT_AUTHENTICATION_H */ \ No newline at end of file diff --git a/wpa_supplicant-2.9_standard/src/eap_peer/eap.c b/wpa_supplicant-2.9_standard/src/eap_peer/eap.c index 5d77c15234ae036fecdb34b8d1f41a675b97a71e..ebc612b797df4f2856c7aaaa10b3eb723c5f744b 100644 --- a/wpa_supplicant-2.9_standard/src/eap_peer/eap.c +++ b/wpa_supplicant-2.9_standard/src/eap_peer/eap.c @@ -29,6 +29,17 @@ #include "eap_i.h" #include "eap_config.h" +#ifdef EXT_AUTHENTICATION_SUPPORT +#include "base64.h" +#include "ext_authentication.h" +#include "ext_auth_eap_peap.h" +#include "eap_tls_common.h" +#include "securec.h" +#ifdef CONFIG_LIBWPA_VENDOR +#include "wpa_client.h" +#endif +#endif /* EXT_AUTHENTICATION_SUPPORT */ + #define STATE_MACHINE_DATA struct eap_sm #define STATE_MACHINE_DEBUG_PREFIX "EAP" @@ -60,7 +71,7 @@ static bool eapol_get_bool(struct eap_sm *sm, enum eapol_bool_var var) } -static void eapol_set_bool(struct eap_sm *sm, enum eapol_bool_var var, +void eapol_set_bool(struct eap_sm *sm, enum eapol_bool_var var, bool value) { sm->eapol_cb->set_bool(sm->eapol_ctx, var, value); @@ -872,6 +883,44 @@ static int eap_peer_erp_reauth_start(struct eap_sm *sm, u8 eap_id) } #endif /* CONFIG_ERP */ +#ifdef EXT_AUTHENTICATION_SUPPORT +static void TxExtCertification(STATE_MACHINE_DATA* sm) +{ + if (sm == NULL || sm->eapRespData == NULL) { + wpa_printf(MSG_ERROR, "exT_certification TxExtCertification ptr is NULL"); + return; + } + wpa_printf(MSG_INFO, "ext_certification TxExtCertification %u:2:%d", GetAuthenticationIdx(), + sm->eapRespData->buf[TYPE_OFFSET]); + int ifname = GetExtAuth(EAP_CODE_RESPONSE, (int)(sm->eapRespData->buf[TYPE_OFFSET])); + if (ifname == IFNAME_UNKOWN || ifname >= IFNAME_SIZE) { + eapol_set_bool(sm, EAPOL_eapResp, true); + return; + } + + SetEapSm(sm); + size_t length = PARAM_LEN + (size_t)((sm->eapRespData->size + BASE64_NUM - 1) / BASE64_NUM * (BASE64_NUM + 1)); + if (length > BUF_SIZE) { + wpa_printf(MSG_ERROR ,"length overflow"); + return; + } + +#ifdef CONFIG_LIBWPA_VENDOR + char param[length]; + AddAuthenticationIdx(); + SetCode(EAP_CODE_RESPONSE); + size_t outLen = 0; + char* base64Param = base64_encode_no_lf((void*)(sm->eapRespData->buf), sm->eapRespData->size, &outLen); + //标识符 code:EAP_CODE_REQUEST type string长度 + (void)snprintf_s(param, sizeof(param), sizeof(param) - 1, "06:%u:2:%d:%zu:%s", GetAuthenticationIdx(), + sm->eapRespData->buf[TYPE_OFFSET], sm->eapRespData->size, base64Param); + wpa_printf(MSG_INFO, "ext_certification TxExtCertification param: %s", param); + + WpaEventReport(IfnameToString[ifname], WPA_EVENT_STA_NOTIFY, (void*)param); + eapol_set_bool(sm,EAPOL_eapResp, false); +#endif +} +#endif /* EXT_AUTHENTICATION_SUPPORT */ /* * The method processing happens here. The request from the authenticator is @@ -895,6 +944,9 @@ SM_STATE(EAP, METHOD) if (!eap_hdr_len_valid(eapReqData, min_len)) return; +#ifdef EXT_AUTHENTICATION_SUPPORT + SetEncryptEapType(EAP_TYPE_NONE); +#endif /* EXT_AUTHENTICATION_SUPPORT */ /* * Get ignore, methodState, decision, allowNotifications, and * eapRespData. RFC 4137 uses three separate method procedure (check, @@ -916,14 +968,10 @@ SM_STATE(EAP, METHOD) ret.allowNotifications = sm->allowNotifications; wpabuf_free(sm->eapRespData); sm->eapRespData = NULL; - sm->eapRespData = sm->m->process(sm, sm->eap_method_priv, &ret, - eapReqData); + sm->eapRespData = sm->m->process(sm, sm->eap_method_priv, &ret, eapReqData); wpa_printf(MSG_EXCESSIVE, "EAP: method process -> ignore=%s " - "methodState=%s decision=%s eapRespData=%p", - ret.ignore ? "TRUE" : "FALSE", - eap_sm_method_state_txt(ret.methodState), - eap_sm_decision_txt(ret.decision), - sm->eapRespData); + "methodState=%s decision=%s eapRespData=%p", ret.ignore ? "TRUE" : "FALSE", + eap_sm_method_state_txt(ret.methodState), eap_sm_decision_txt(ret.decision), sm->eapRespData); sm->ignore = ret.ignore; if (sm->ignore) @@ -932,19 +980,14 @@ SM_STATE(EAP, METHOD) sm->decision = ret.decision; sm->allowNotifications = ret.allowNotifications; - if (sm->m->isKeyAvailable && sm->m->getKey && - sm->m->isKeyAvailable(sm, sm->eap_method_priv)) { + if (sm->m->isKeyAvailable && sm->m->getKey && sm->m->isKeyAvailable(sm, sm->eap_method_priv)) { eap_sm_free_key(sm); - sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv, - &sm->eapKeyDataLen); + sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv, &sm->eapKeyDataLen); os_free(sm->eapSessionId); sm->eapSessionId = NULL; if (sm->m->getSessionId) { - sm->eapSessionId = sm->m->getSessionId( - sm, sm->eap_method_priv, - &sm->eapSessionIdLen); - wpa_hexdump(MSG_DEBUG, "EAP: Session-Id", - sm->eapSessionId, sm->eapSessionIdLen); + sm->eapSessionId = sm->m->getSessionId(sm, sm->eap_method_priv, &sm->eapSessionIdLen); + wpa_hexdump(MSG_DEBUG, "EAP: Session-Id", sm->eapSessionId, sm->eapSessionIdLen); } } } @@ -965,7 +1008,11 @@ SM_STATE(EAP, SEND_RESPONSE) os_memcpy(sm->last_sha1, sm->req_sha1, 20); sm->lastId = sm->reqId; sm->lastRespData = wpabuf_dup(sm->eapRespData); - eapol_set_bool(sm, EAPOL_eapResp, true); +#ifdef EXT_AUTHENTICATION_SUPPORT + TxExtCertification(sm); +#else + eapol_set_bool(sm, EAPOL_eapResp, true); +#endif /* EXT_AUTHENTICATION_SUPPORT */ } else { wpa_printf(MSG_DEBUG, "EAP: No eapRespData available"); sm->lastRespData = NULL; diff --git a/wpa_supplicant-2.9_standard/src/eap_peer/eap.h b/wpa_supplicant-2.9_standard/src/eap_peer/eap.h index a40d007d99605279e13a2553634a441bc3bb153e..17b9341c52415375d4961f6db64740be8251c87a 100644 --- a/wpa_supplicant-2.9_standard/src/eap_peer/eap.h +++ b/wpa_supplicant-2.9_standard/src/eap_peer/eap.h @@ -378,6 +378,7 @@ int eap_peer_update_erp_next_seq_num(struct eap_sm *sm, u16 seq_num); void eap_peer_erp_init(struct eap_sm *sm, u8 *ext_session_id, size_t ext_session_id_len, u8 *ext_emsk, size_t ext_emsk_len); +void eapol_set_bool(struct eap_sm* sm, enum eapol_bool_var var, bool value); #endif /* IEEE8021X_EAPOL */ diff --git a/wpa_supplicant-2.9_standard/src/eap_peer/eap_peap.c b/wpa_supplicant-2.9_standard/src/eap_peer/eap_peap.c index b1d0c314ccfb2a3ca8ceccc5db8b385fa6c48c65..0c3d6656c067d4c81b4d413dadd660ce421f2fb5 100644 --- a/wpa_supplicant-2.9_standard/src/eap_peer/eap_peap.c +++ b/wpa_supplicant-2.9_standard/src/eap_peer/eap_peap.c @@ -17,7 +17,9 @@ #include "eap_tls_common.h" #include "eap_config.h" #include "tncc.h" - +#ifdef EXT_AUTHENTICATION_SUPPORT +#include "ext_authentication.h" +#endif /* EXT_AUTHENTICATION_SUPPORT */ /* Maximum supported PEAP version * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt @@ -828,6 +830,10 @@ static int eap_peap_decrypt(struct eap_sm *sm, struct eap_peap_data *data, ret->methodState = METHOD_DONE; return 1; } else if (wpabuf_len(in_data) == 0) { +#ifdef EXT_AUTHENTICATION_SUPPORT + wpa_printf(MSG_INFO, "ext_certification SetEncryptData"); + SetEncryptData(&data->ssl, EAP_TYPE_PEAP, data->peap_version, req->identifier); +#endif /* EXT_AUTHENTICATION_SUPPORT */ /* Received TLS ACK - requesting more fragments */ return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP, data->peap_version, @@ -1005,6 +1011,10 @@ continue_req: rmsg = &buf; } +#ifdef EXT_AUTHENTICATION_SUPPORT + wpa_printf(MSG_INFO, "ext_certification SetEncryptData"); + SetEncryptData(&data->ssl, EAP_TYPE_PEAP, data->peap_version, req->identifier); +#endif /* EXT_AUTHENTICATION_SUPPORT */ if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP, data->peap_version, req->identifier, rmsg, out_data)) { diff --git a/wpa_supplicant-2.9_standard/src/eap_peer/eap_ttls.c b/wpa_supplicant-2.9_standard/src/eap_peer/eap_ttls.c index 6adc22277c3616818ce2d5f17281cf180c4bf729..6b7306429d7b4a149f4bafb65fdb06cb27c3ea31 100644 --- a/wpa_supplicant-2.9_standard/src/eap_peer/eap_ttls.c +++ b/wpa_supplicant-2.9_standard/src/eap_peer/eap_ttls.c @@ -18,7 +18,9 @@ #include "eap_i.h" #include "eap_tls_common.h" #include "eap_config.h" - +#ifdef EXT_AUTHENTICATION_SUPPORT +#include "ext_authentication.h" +#endif /* EXT_AUTHENTICATION_SUPPORT */ #define EAP_TTLS_VERSION 0 @@ -1124,6 +1126,10 @@ static int eap_ttls_encrypt_response(struct eap_sm *sm, wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS: Encrypting Phase 2 data", resp); +#ifdef EXT_AUTHENTICATION_SUPPORT + wpa_printf(MSG_INFO, "ext_certification SetEncryptData"); + SetEncryptData(&data->ssl, EAP_TYPE_PEAP, data->ttls_version, identifier); +#endif /* EXT_AUTHENTICATION_SUPPORT */ if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TTLS, data->ttls_version, identifier, resp, out_data)) { @@ -1484,6 +1490,10 @@ start: } if (in_data == NULL || wpabuf_len(in_data) == 0) { +#ifdef EXT_AUTHENTICATION_SUPPORT + wpa_printf(MSG_INFO, "ext_certification SetEncryptData"); + SetEncryptData(&data->ssl, EAP_TYPE_TTLS, data->ttls_version, identifier); +#endif /* EXT_AUTHENTICATION_SUPPORT */ /* Received TLS ACK - requesting more fragments */ return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TTLS, data->ttls_version, diff --git a/wpa_supplicant-2.9_standard/src/eap_peer/ext_auth_eap_peap.h b/wpa_supplicant-2.9_standard/src/eap_peer/ext_auth_eap_peap.h new file mode 100644 index 0000000000000000000000000000000000000000..e4648b75fdf9dae6f84573afd7087995e53631fc --- /dev/null +++ b/wpa_supplicant-2.9_standard/src/eap_peer/ext_auth_eap_peap.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved. + */ + +#ifndef EXT_AUTH_EAP_PEAP_H +#define EXT_AUTH_EAP_PEAP_H + +#include "eap_tls_common.h" +// 复制代码,不作修改 +struct eap_peap_data { + struct eap_ssl_data ssl; + + int peap_version, force_peap_version, force_new_label; + + const struct eap_method *phase2_method; + void *phase2_priv; + int phase2_success; + int phase2_eap_success; + int phase2_eap_started; + + struct eap_method_type phase2_type; + struct eap_method_type *phase2_types; + size_t num_phase2_types; + + int peap_outer_success; /* 0 = PEAP terminated on Phase 2 inner + * EAP-Success + * 1 = reply with tunneled EAP-Success to inner + * EAP-Success and expect AS to send outer + * (unencrypted) EAP-Success after this + * 2 = reply with PEAP/TLS ACK to inner + * EAP-Success and expect AS to send outer + * (unencrypted) EAP-Success after this */ + int resuming; /* starting a resumed session */ + int reauth; /* reauthentication */ + u8 *key_data; + u8 *session_id; + size_t id_len; + + struct wpabuf *pending_phase2_req; + struct wpabuf *pending_resp; + enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding; + int crypto_binding_used; + u8 binding_nonce[32]; + u8 ipmk[40]; + u8 cmk[20]; + int soh; /* Whether IF-TNCCS-SOH (Statement of Health; Microsoft NAP) + * is enabled. */ +}; + + #endif /* EXT_AUTH_EAP_PEAP_H */ \ No newline at end of file diff --git a/wpa_supplicant-2.9_standard/src/eapol_supp/eapol_supp_sm.c b/wpa_supplicant-2.9_standard/src/eapol_supp/eapol_supp_sm.c index b2a61acb10f0e9ebdddd32b21fbaf9c106f9e654..2dda0c62be4c8a0604e0166ef0a5fece593eab0e 100644 --- a/wpa_supplicant-2.9_standard/src/eapol_supp/eapol_supp_sm.c +++ b/wpa_supplicant-2.9_standard/src/eapol_supp/eapol_supp_sm.c @@ -19,137 +19,22 @@ #include "eap_peer/eap_config.h" #include "eap_peer/eap_proxy.h" #include "eapol_supp_sm.h" +#ifdef EXT_AUTHENTICATION_SUPPORT +#include "base64.h" +#include "eap_peer/eap_i.h" +#include "ext_authentication.h" +#include "list.h" +#include "securec.h" +#ifdef CONFIG_LIBWPA_VENDOR +#include "wpa_client.h" +#endif +#endif /* EXT_AUTHENTICATION_SUPPORT */ #define STATE_MACHINE_DATA struct eapol_sm #define STATE_MACHINE_DEBUG_PREFIX "EAPOL" #define EAP_FAIL_REASON 4 #define EAP_SM_ID_LEN 5 -/* IEEE 802.1X-2004 - Supplicant - EAPOL state machines */ - -/** - * struct eapol_sm - Internal data for EAPOL state machines - */ -struct eapol_sm { - /* Timers */ - unsigned int authWhile; - unsigned int heldWhile; - unsigned int startWhen; - unsigned int idleWhile; /* for EAP state machine */ - int timer_tick_enabled; - - /* Global variables */ - bool eapFail; - bool eapolEap; - bool eapSuccess; - bool initialize; - bool keyDone; - bool keyRun; - PortControl portControl; - bool portEnabled; - PortStatus suppPortStatus; /* dot1xSuppControlledPortStatus */ - bool portValid; - bool suppAbort; - bool suppFail; - bool suppStart; - bool suppSuccess; - bool suppTimeout; - - /* Supplicant PAE state machine */ - enum { - SUPP_PAE_UNKNOWN = 0, - SUPP_PAE_DISCONNECTED = 1, - SUPP_PAE_LOGOFF = 2, - SUPP_PAE_CONNECTING = 3, - SUPP_PAE_AUTHENTICATING = 4, - SUPP_PAE_AUTHENTICATED = 5, - /* unused(6) */ - SUPP_PAE_HELD = 7, - SUPP_PAE_RESTART = 8, - SUPP_PAE_S_FORCE_AUTH = 9, - SUPP_PAE_S_FORCE_UNAUTH = 10 - } SUPP_PAE_state; /* dot1xSuppPaeState */ - /* Variables */ - bool userLogoff; - bool logoffSent; - unsigned int startCount; - bool eapRestart; - PortControl sPortMode; - /* Constants */ - unsigned int heldPeriod; /* dot1xSuppHeldPeriod */ - unsigned int startPeriod; /* dot1xSuppStartPeriod */ - unsigned int maxStart; /* dot1xSuppMaxStart */ - - /* Key Receive state machine */ - enum { - KEY_RX_UNKNOWN = 0, - KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE - } KEY_RX_state; - /* Variables */ - bool rxKey; - - /* Supplicant Backend state machine */ - enum { - SUPP_BE_UNKNOWN = 0, - SUPP_BE_INITIALIZE = 1, - SUPP_BE_IDLE = 2, - SUPP_BE_REQUEST = 3, - SUPP_BE_RECEIVE = 4, - SUPP_BE_RESPONSE = 5, - SUPP_BE_FAIL = 6, - SUPP_BE_TIMEOUT = 7, - SUPP_BE_SUCCESS = 8 - } SUPP_BE_state; /* dot1xSuppBackendPaeState */ - /* Variables */ - bool eapNoResp; - bool eapReq; - bool eapResp; - /* Constants */ - unsigned int authPeriod; /* dot1xSuppAuthPeriod */ - - /* Statistics */ - unsigned int dot1xSuppEapolFramesRx; - unsigned int dot1xSuppEapolFramesTx; - unsigned int dot1xSuppEapolStartFramesTx; - unsigned int dot1xSuppEapolLogoffFramesTx; - unsigned int dot1xSuppEapolRespFramesTx; - unsigned int dot1xSuppEapolReqIdFramesRx; - unsigned int dot1xSuppEapolReqFramesRx; - unsigned int dot1xSuppInvalidEapolFramesRx; - unsigned int dot1xSuppEapLengthErrorFramesRx; - unsigned int dot1xSuppLastEapolFrameVersion; - unsigned char dot1xSuppLastEapolFrameSource[6]; - - /* Miscellaneous variables (not defined in IEEE 802.1X-2004) */ - bool changed; - struct eap_sm *eap; - struct eap_peer_config *config; - bool initial_req; - u8 *last_rx_key; - size_t last_rx_key_len; - struct wpabuf *eapReqData; /* for EAP */ - bool altAccept; /* for EAP */ - bool altReject; /* for EAP */ - bool eapTriggerStart; - bool replay_counter_valid; - u8 last_replay_counter[16]; - struct eapol_config conf; - struct eapol_ctx *ctx; - enum { EAPOL_CB_IN_PROGRESS = 0, EAPOL_CB_SUCCESS, EAPOL_CB_FAILURE } - cb_status; - bool cached_pmk; - - bool unicast_key_received, broadcast_key_received; - - bool force_authorized_update; - -#ifdef CONFIG_EAP_PROXY - bool use_eap_proxy; - struct eap_proxy_sm *eap_proxy; -#endif /* CONFIG_EAP_PROXY */ -}; - - static void eapol_sm_txLogoff(struct eapol_sm *sm); static void eapol_sm_txStart(struct eapol_sm *sm); static void eapol_sm_processKey(struct eapol_sm *sm); @@ -1285,6 +1170,43 @@ int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen) } #endif /* CONFIG_CTRL_IFACE */ +#ifdef EXT_AUTHENTICATION_SUPPORT +static void RxExtCertification(struct eapol_sm* sm) +{ + if (sm == NULL || sm->eap == NULL) { + wpa_printf(MSG_ERROR, "ext_certification RxExtCertification ptr is NULL"); + return; + } + wpa_printf(MSG_INFO, "ext_certification RxExtCertification %u:1:%d", GetAuthenticationIdx(), + sm->eapReqData->buf[TYPE_OFFSET]); + int ifname = GetExtAuth(EAP_CODE_REQUEST, (int)(sm->eapReqData->buf[TYPE_OFFSET])); + if (ifname == IFNAME_UNKOWN || ifname >= IFNAME_SIZE) { + eapol_sm_step(sm); + return; + } + + SetEapSm(sm->eap); + size_t length = PARAM_LEN + (size_t)((sm->eapReqData->size + BASE64_NUM - 1) / BASE64_NUM * (BASE64_NUM+1)); + if (length > BUF_SIZE) { + wpa_printf(MSG_ERROR, "ext_certification RxExtCertification ptr is NULL"); + return; + } +#ifdef CONFIG_LIBWPA_VENDOR + char param[lenght]; + AddAuthenticationIdx(); + SetCode(EAP_CODE_REQUEST); + + size_t outLen = 0; + char* base64Param = base64_encode_no_lf((void*)(sm->eapReqData->buf), sm->eapReqData->size, &outLen); + // 标识符 code:EAP_CODE_REQUEST type string长度 base64转换过的buf + (void)snprintf_s(param, sizeof(param), sizeof(param) - 1, "06:%u:1:%d:%zu:%s", GetAuthenticationIdx(), + sm->eapReqData->buf[TYPE_OFFSET], sm->eapReqData->size, base64Param); + free(base64Param); + wpa_printf(MSG_INFO, "ext_certification RxExtCertification param: %s", param); + WpaEventReport(IfnameToString[ifname], WPA_EVENT_STA_NOTIFY, (void*)param); +#endif +} +#endif /* EXT_AUTHENTICATION_SUPPORT */ /** * eapol_sm_rx_eapol - Process received EAPOL frames @@ -1410,7 +1332,11 @@ int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf, "EAP Req updated"); } #endif /* CONFIG_EAP_PROXY */ - eapol_sm_step(sm); +#ifdef EXT_AUTHENTICATION_SUPPORT + RxExtCertification(sm); +#else + eapol_sm_step(sm); +#endif /* EXT_AUTHENTICATION_SUPPORT */ } break; case IEEE802_1X_TYPE_EAPOL_KEY: @@ -1441,7 +1367,11 @@ int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf, os_memcpy(sm->last_rx_key, buf, data_len); sm->last_rx_key_len = data_len; sm->rxKey = true; - eapol_sm_step(sm); +#ifdef EXT_AUTHENTICATION_SUPPORT + RxExtCertification(sm); +#else + eapol_sm_step(sm); +#endif /* EXT_AUTHENTICATION_SUPPORT */ } break; #ifdef CONFIG_MACSEC @@ -1463,9 +1393,9 @@ int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf, #ifdef HARMONY_P2P_CONNECTIVITY_PATCH /* miss GO'EAP-Failure frame issue */ - + extern u8 eapol_sm_get_lastId(struct eap_sm *sm); - + void wps_eap_fail_timeout(void *eloop_data, void *user_ctx) { struct eapol_sm *sm; diff --git a/wpa_supplicant-2.9_standard/src/eapol_supp/eapol_supp_sm.h b/wpa_supplicant-2.9_standard/src/eapol_supp/eapol_supp_sm.h index d0eb523914d6d0f37aab41932dbbc012a65639ca..6eb50ba26d446708e885f99529139ffaead19241 100644 --- a/wpa_supplicant-2.9_standard/src/eapol_supp/eapol_supp_sm.h +++ b/wpa_supplicant-2.9_standard/src/eapol_supp/eapol_supp_sm.h @@ -69,7 +69,130 @@ struct eapol_config { int wps; }; -struct eapol_sm; +/* IEEE 802.1X-2004 - Supplicant - EAPOL state machines */ + +/** + * struct eapol_sm - Internal data for EAPOL state machines + */ +struct eapol_sm { + /* Timers */ + unsigned int authWhile; + unsigned int heldWhile; + unsigned int startWhen; + unsigned int idleWhile; /* for EAP state machine */ + int timer_tick_enabled; + + /* Global variables */ + Boolean eapFail; + Boolean eapolEap; + Boolean eapSuccess; + Boolean initialize; + Boolean keyDone; + Boolean keyRun; + PortControl portControl; + Boolean portEnabled; + PortStatus suppPortStatus; /* dot1xSuppControlledPortStatus */ + Boolean portValid; + Boolean suppAbort; + Boolean suppFail; + Boolean suppStart; + Boolean suppSuccess; + Boolean suppTimeout; + + /* Supplicant PAE state machine */ + enum { + SUPP_PAE_UNKNOWN = 0, + SUPP_PAE_DISCONNECTED = 1, + SUPP_PAE_LOGOFF = 2, + SUPP_PAE_CONNECTING = 3, + SUPP_PAE_AUTHENTICATING = 4, + SUPP_PAE_AUTHENTICATED = 5, + /* unused(6) */ + SUPP_PAE_HELD = 7, + SUPP_PAE_RESTART = 8, + SUPP_PAE_S_FORCE_AUTH = 9, + SUPP_PAE_S_FORCE_UNAUTH = 10 + } SUPP_PAE_state; /* dot1xSuppPaeState */ + /* Variables */ + Boolean userLogoff; + Boolean logoffSent; + unsigned int startCount; + Boolean eapRestart; + PortControl sPortMode; + /* Constants */ + unsigned int heldPeriod; /* dot1xSuppHeldPeriod */ + unsigned int startPeriod; /* dot1xSuppStartPeriod */ + unsigned int maxStart; /* dot1xSuppMaxStart */ + + /* Key Receive state machine */ + enum { + KEY_RX_UNKNOWN = 0, + KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE + } KEY_RX_state; + /* Variables */ + Boolean rxKey; + + /* Supplicant Backend state machine */ + enum { + SUPP_BE_UNKNOWN = 0, + SUPP_BE_INITIALIZE = 1, + SUPP_BE_IDLE = 2, + SUPP_BE_REQUEST = 3, + SUPP_BE_RECEIVE = 4, + SUPP_BE_RESPONSE = 5, + SUPP_BE_FAIL = 6, + SUPP_BE_TIMEOUT = 7, + SUPP_BE_SUCCESS = 8 + } SUPP_BE_state; /* dot1xSuppBackendPaeState */ + /* Variables */ + Boolean eapNoResp; + Boolean eapReq; + Boolean eapResp; + /* Constants */ + unsigned int authPeriod; /* dot1xSuppAuthPeriod */ + + /* Statistics */ + unsigned int dot1xSuppEapolFramesRx; + unsigned int dot1xSuppEapolFramesTx; + unsigned int dot1xSuppEapolStartFramesTx; + unsigned int dot1xSuppEapolLogoffFramesTx; + unsigned int dot1xSuppEapolRespFramesTx; + unsigned int dot1xSuppEapolReqIdFramesRx; + unsigned int dot1xSuppEapolReqFramesRx; + unsigned int dot1xSuppInvalidEapolFramesRx; + unsigned int dot1xSuppEapLengthErrorFramesRx; + unsigned int dot1xSuppLastEapolFrameVersion; + unsigned char dot1xSuppLastEapolFrameSource[6]; + + /* Miscellaneous variables (not defined in IEEE 802.1X-2004) */ + Boolean changed; + struct eap_sm *eap; + struct eap_peer_config *config; + Boolean initial_req; + u8 *last_rx_key; + size_t last_rx_key_len; + struct wpabuf *eapReqData; /* for EAP */ + Boolean altAccept; /* for EAP */ + Boolean altReject; /* for EAP */ + Boolean eapTriggerStart; + Boolean replay_counter_valid; + u8 last_replay_counter[16]; + struct eapol_config conf; + struct eapol_ctx *ctx; + enum { EAPOL_CB_IN_PROGRESS = 0, EAPOL_CB_SUCCESS, EAPOL_CB_FAILURE } + cb_status; + Boolean cached_pmk; + + Boolean unicast_key_received, broadcast_key_received; + + Boolean force_authorized_update; + +#ifdef CONFIG_EAP_PROXY + Boolean use_eap_proxy; + struct eap_proxy_sm *eap_proxy; +#endif /* CONFIG_EAP_PROXY */ +}; + struct wpa_config_blob; enum eapol_supp_result { diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/ctrl_iface.c b/wpa_supplicant-2.9_standard/wpa_supplicant/ctrl_iface.c index 545398bce889ab9772d6a78620b04e99284d6721..c80d5fe11f3c93c95a90023274edf7564cea7344 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/ctrl_iface.c @@ -98,6 +98,21 @@ #include "securec.h" #include "hilink_okc.h" #endif + +#ifdef EXT_AUTHENTICATION_SUPPORT +#include "base64.h" +#include "ext_authentication.h" +#include "eap_peer/eap_tls_common.h" +#include "securec.h" +#define EXT_OFFSET 8 + +enum { + EXT_AUTH_FAIL = 0, + EXT_AUTH_NEXT = 1, + EXT_AUTH_FINISH = 2 +} ExtResult; +#endif /* EXT_AUTHENTICATION_SUPPORT */ + #define P2P_160M_MASK 0x08000000 #define DISCOVER_TIMEOUT_S 120 #define DISCOVER_CHANNELID 20000 @@ -12757,6 +12772,169 @@ static int wpa_supplicant_ctrl_iface_get_require_pmf(struct wpa_supplicant *wpa_ return 0; } +#ifdef EXT_AUTHENTICATION_SUPPORT +static int* ParseCodes(char* input, int* count) +{ + char* token = strtok(input ":"); + if (token == NULL) { + *count = 0; + return NULL; + } + int num = atoi(token); + if (num <= 0) { + *count = 0; + return NULL; + } + + int* datas = (int*)malloc(num * sizeof(int)); + if (datas == NULL) { + *count = 0; + return NULL; + } + + int i = 0; + token = strtok(NULL, ":"); + while (token != NULL && i < num) { + datas[i++] = atoi(token); + token = strtok(NULL, ":"); + } + + *count = i; + if (i < num) { + datas = (int*)realloc(datas, i * sizeof(int)); + wpa_printf(MSG_ERROR, "num error"); + } + + return datas; +} + +static int ExtAuthReg(char* params) +{ + if (strlen(params) < 2) { + wpa_printf(MSG_ERROR, "ExtAuthReg params error %s", params); + return -1; + } + int count = 0; + int ifname = (params[EXT_AUTH_REG_PREFIX_SIZE] - '0'); + wpa_printf(MSG_INFO, "ext_certification EXT_AUTH_REG: ifname: %d, %s", ifname, params); + int* datas = ParseCodes(params + EXT_AUTH_REG_PREFIX_SIZE + IFNAME_LENGTH, &count); + + if (datas != NULL) { + //输出解析结果 + for (int i = 0; i < count; ++i) { + int value = datas[i]; + uint type = ((int64_t)value) & ((1 << EXT_OFFSET) - 1); + uint code = ((int64_t)value) >> EXT_OFFSET; + wpa_printf(MSG_INFO, "ext_certification EXT_AUTH_REG_PREFIX: value: %d, %u, %u", value, type, code); + RegExtAuth(code, type, ifname); + } + // 释放内存 + free(datas); + return 0; + } + wpa_printf(MSG_ERROR, "ExtAuthReg ParseCodes error, datas = NULL, %s", params); + return -1; +} + +static int ExtAuthUnReg(char* params) +{ + int count = 0; + int* datas = ParseCodes(params + EXT_AUTH_UNREG_PREFIX_SIZE, &count); + + if (datas != NULL) { + //输出解析结果 + for (int i = 0; i < count; ++i) { + int value = datas[i]; + uint type = ((int64_t)value) & ((1 << EXT_OFFSET) - 1); + uint code = ((int64_t)value) >> EXT_OFFSET; + wpa_printf(MSG_INFO, "ext_certification EXT_AUTH_UNREG_PREFIX_SIZE: value: %d, %u, %u", value, type, code); + UnRegExtAuth(code, type); + } + // 释放内存 + free(datas); + } + return 0; +} + +static int ExtAuthDataInner(struct wpa_supplicant* wpa_s, u8* dataBuf, int result, int bufferLen) +{ + int code = GetCode(); + if (result == EXT_AUTH_FAIL) { + eapol_sm_notify_eap_fail(wpa_s->eapol, true); + return 0; + } + if (result == EXT_AUTH_FINISH) { + eapol_sm_notify_eap_success(wpa_s->eapol, true); + return 0; + } + // 修改sm + if (code == EAP_CODE_REQUEST) { + wpa_printf(MSG_INFO, "ext_certification code = EAP_CODE_REQUEST"); + wpa_s->eapol->eapReqData->size = bufferLen; + wpa_s->eapol->eapReqData->buf = dataBuf; + eapol_sm_step(wpa_s->eapol); + return 0; + } else if (code == EAP_CODE_RESPONSE) { + struct wpabuf* respData = wpa_s->eapol->eap->eapRespData; + respData->size = bufferLen; + respData->buf = dataBuf; + struct EncryptData* data = GetEncryptData(); + wpa_printf(MSG_INFO, "ext_certification code = EAP_CODE_RESPONSE, eapType: %d", data->eapType); + if (data->eapType != EAP_TYPE_NONE) { + wpa_printf(MSG_INFO, "ext_certification Encrypt GetEncryptData"); + // 加密相关操作 + (void)eap_peer_tls_encrypt(GetEapSm(), data->ssl, data->eapType, data->version, data->id, + NULL, &wpa_s->eapol->eap->eapRespData); + SetEncryptEapType(EAP_TYPE_NONE); + } + eapol_set_bool(GetEapSm(), EAPOL_eapResp, true); + eapol_sm_step(wpa_s->eapol); + return 0; + } + return -1; +} + +static int ExtAuthData(struct wpa_supplicant *wpa_s, char* params) +{ + wpa_printf(MSG_INFO, "ext_certification ExtAuthData enter %s", params); + params = params + EXT_AUTH_DATA_PREFIX_SIZE; + + //处理字符串 + size_t result, idx, bufferLen; + if (sscanf_s(params, "%zu:%zu:%zu:", &result, &idx, &bufferLen) != 3) { + wpa_printf(MSG_ERROR, "sscanf error %zu:%zu:%zu", result, idx, bufferLen); + } + wpa_printf(MSG_INFO, "ext_certification ExtAuthData result %zu:%zu:%zu", result, idx, bufferLen); + size_t length = strlen(params); + size_t startIdx = 0; + size_t cnt = 0; + size_t paramCnt= 3; + for (; startIdx < length; ++ startIdx) { + if (params[startIdx] == ':') { + ++cnt; + } + if (cnt == paramCnt) { + break; + } + } + ++startIdx; + size_t count = 0; + u8* dataBuf = base64_decode(params + startIdx, strlen(params + startIdx), &count); + + if (count != bufferLen) { + wpa_printf(MSG_ERROR, "ExtAuthData cnt error %zu:%zu:%zu:%zu:%zu", result, idx, bufferLen, startIdx, length); + return -1; + } + + if (GetAuthenticationIdx() != (int)idx) { + wpa_printf(MSG_ERROR, "ExtAuthData idx error %zu:%zu:%zu", result, idx, bufferLen); + return -1; + } + + return ExtAuthDataInner(wpa_s, dataBuf, result, bufferLen); +} +#endif /* EXT_AUTHENTICATION_SUPPORT */ + static int wpa_supplicant_sta_shell_cmd(struct wpa_supplicant *wpa_s, char *params) { int ret; @@ -12765,6 +12943,22 @@ static int wpa_supplicant_sta_shell_cmd(struct wpa_supplicant *wpa_s, char *para } wpa_printf(MSG_DEBUG, "ctrl_iface: wpa_supplicant_sta_shell_cmd"); + +#ifdef EXT_AUTHENTICATION_SUPPORT + wpa_printf(MSG_INFO, "ext_certification wpa_supplicant_sta_shell_cmd: %zu , %s", strlen(params), params); + if (strncmp(params, EXT_AUTH_REG_PREFIX, EXT_AUTH_REG_PREFIX_SIZE) == 0) { + return ExtAuthReg(params); + } + + if (strncmp(params, EXT_AUTH_UNREG_PREFIX, EXT_AUTH_UNREG_PREFIX_SIZE) == 0) { + return ExtAuthUnReg(params); + } + + if (strncmp(params, EXT_AUTH_DATA_PREFIX, EXT_AUTH_DATA_PREFIX_SIZE) == 0) { + return ExtAuthData(wpa_s, params); + } +#endif /* EXT_AUTHENTICATION_SUPPORT */ + if ((strncmp(params, GSM_AUTH_PREFIX, GSM_AUTH_PREFIX_SIZE) == 0) || (strncmp(params, UMTS_AUTH_PREFIX, UMTS_AUTH_PREFIX_SIZE) == 0) || (strncmp(params, UMTS_AUTS_PREFIX, UMTS_AUTS_PREFIX_SIZE) == 0)) { diff --git a/wpa_supplicant-2.9_standard/wpa_supplicant/notify.h b/wpa_supplicant-2.9_standard/wpa_supplicant/notify.h index aaea046e1fc061c7bc9b31584ee1bf3e651ecfd8..71ffc535afcd462be2728483a39ca1d8cc5d840a 100644 --- a/wpa_supplicant-2.9_standard/wpa_supplicant/notify.h +++ b/wpa_supplicant-2.9_standard/wpa_supplicant/notify.h @@ -22,6 +22,16 @@ struct wpa_cred; struct rsn_pmksa_cache_entry; #define RSP_PARAM_SIZE 120 + +#ifdef EXT_AUTHENTICATION_SUPPORT +#define EXT_AUTH_REG_PREFIX "EXT_AUTH_REG " +#define EXT_AUTH_REG_PREFIX_SIZE 13 +#define EXT_AUTH_UNREG_PREFIX "EXT_AUTH_UNREG " +#define EXT_AUTH_UNREG_PREFIX_SIZE 15 +#define EXT_AUTH_DATA_PREFIX "EXT_AUTH_DATA " +#define EXT_AUTH_DATA_PREFIX_SIZE 14 +#endif /* EXT_AUTHENTICATION_SUPPORT */ + #define GSM_AUTH_PREFIX "GSM-AUTH" #define GSM_AUTH_PREFIX_SIZE 8 #define UMTS_AUTH_PREFIX "UMTS-AUTH"