⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 eap_fast.c

📁 最新的Host AP 新添加了许多pcmcia 的驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * EAP peer method: EAP-FAST (RFC 4851) * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */#include "includes.h"#include "common.h"#include "eap_i.h"#include "eap_tls_common.h"#include "eap_config.h"#include "tls.h"#include "eap_common/eap_tlv_common.h"#include "sha1.h"#include "eap_fast_pac.h"#ifdef EAP_FAST_DYNAMIC#include "eap_fast_pac.c"#endif /* EAP_FAST_DYNAMIC *//* TODO: * - test session resumption and enable it if it interoperates * - password change (pending mschapv2 packet; replay decrypted packet) */static void eap_fast_deinit(struct eap_sm *sm, void *priv);struct eap_fast_data {	struct eap_ssl_data ssl;	int fast_version;	const struct eap_method *phase2_method;	void *phase2_priv;	int phase2_success;	struct eap_method_type phase2_type;	struct eap_method_type *phase2_types;	size_t num_phase2_types;	int resuming; /* starting a resumed session */	struct eap_fast_key_block_provisioning *key_block_p;#define EAP_FAST_PROV_UNAUTH 1#define EAP_FAST_PROV_AUTH 2	int provisioning_allowed; /* Allowed PAC provisioning modes */	int provisioning; /* doing PAC provisioning (not the normal auth) */	int anon_provisioning; /* doing anonymous (unauthenticated)				* provisioning */	int session_ticket_used;	u8 key_data[EAP_FAST_KEY_LEN];	u8 emsk[EAP_EMSK_LEN];	int success;	struct eap_fast_pac *pac;	struct eap_fast_pac *current_pac;	size_t max_pac_list_len;	int use_pac_binary_format;	u8 simck[EAP_FAST_SIMCK_LEN];	int simck_idx;	struct wpabuf *pending_phase2_req;};static int eap_fast_session_ticket_cb(void *ctx, const u8 *ticket, size_t len,				      const u8 *client_random,				      const u8 *server_random,				      u8 *master_secret){	struct eap_fast_data *data = ctx;	wpa_printf(MSG_DEBUG, "EAP-FAST: SessionTicket callback");	if (client_random == NULL || server_random == NULL ||	    master_secret == NULL) {		wpa_printf(MSG_DEBUG, "EAP-FAST: SessionTicket failed - fall "			   "back to full TLS handshake");		data->session_ticket_used = 0;		if (data->provisioning_allowed) {			wpa_printf(MSG_DEBUG, "EAP-FAST: Try to provision a "				   "new PAC-Key");			data->provisioning = 1;			data->current_pac = NULL;		}		return 0;	}	wpa_hexdump(MSG_DEBUG, "EAP-FAST: SessionTicket", ticket, len);	if (data->current_pac == NULL) {		wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC-Key available for "			   "using SessionTicket");		data->session_ticket_used = 0;		return 0;	}	eap_fast_derive_master_secret(data->current_pac->pac_key,				      server_random, client_random,				      master_secret);	data->session_ticket_used = 1;	return 1;}static int eap_fast_parse_phase1(struct eap_fast_data *data,				 const char *phase1){	const char *pos;	pos = os_strstr(phase1, "fast_provisioning=");	if (pos) {		data->provisioning_allowed = atoi(pos + 18);		wpa_printf(MSG_DEBUG, "EAP-FAST: Automatic PAC provisioning "			   "mode: %d", data->provisioning_allowed);	}	pos = os_strstr(phase1, "fast_max_pac_list_len=");	if (pos) {		data->max_pac_list_len = atoi(pos + 22);		if (data->max_pac_list_len == 0)			data->max_pac_list_len = 1;		wpa_printf(MSG_DEBUG, "EAP-FAST: Maximum PAC list length: %lu",			   (unsigned long) data->max_pac_list_len);	}	pos = os_strstr(phase1, "fast_pac_format=binary");	if (pos) {		data->use_pac_binary_format = 1;		wpa_printf(MSG_DEBUG, "EAP-FAST: Using binary format for PAC "			   "list");	}	return 0;}static void * eap_fast_init(struct eap_sm *sm){	struct eap_fast_data *data;	struct eap_peer_config *config = eap_get_config(sm);	data = os_zalloc(sizeof(*data));	if (data == NULL)		return NULL;	data->fast_version = EAP_FAST_VERSION;	data->max_pac_list_len = 10;	if (config && config->phase1 &&	    eap_fast_parse_phase1(data, config->phase1) < 0) {		eap_fast_deinit(sm, data);		return NULL;	}	if (eap_peer_select_phase2_methods(config, "auth=",					   &data->phase2_types,					   &data->num_phase2_types) < 0) {		eap_fast_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)) {		wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize SSL.");		eap_fast_deinit(sm, data);		return NULL;	}	if (tls_connection_set_session_ticket_cb(sm->ssl_ctx, data->ssl.conn,						 eap_fast_session_ticket_cb,						 data) < 0) {		wpa_printf(MSG_INFO, "EAP-FAST: Failed to set SessionTicket "			   "callback");		eap_fast_deinit(sm, data);		return NULL;	}	/*	 * The local RADIUS server in a Cisco AP does not seem to like empty	 * fragments before data, so disable that workaround for CBC.	 * TODO: consider making this configurable	 */	if (tls_connection_enable_workaround(sm->ssl_ctx, data->ssl.conn)) {		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to enable TLS "			   "workarounds");	}	if (data->use_pac_binary_format &&	    eap_fast_load_pac_bin(sm, &data->pac, config->pac_file) < 0) {		eap_fast_deinit(sm, data);		return NULL;	}	if (!data->use_pac_binary_format &&	    eap_fast_load_pac(sm, &data->pac, config->pac_file) < 0) {		eap_fast_deinit(sm, data);		return NULL;	}	eap_fast_pac_list_truncate(data->pac, data->max_pac_list_len);	if (data->pac == NULL && !data->provisioning_allowed) {		wpa_printf(MSG_INFO, "EAP-FAST: No PAC configured and "			   "provisioning disabled");		eap_fast_deinit(sm, data);		return NULL;	}	return data;}static void eap_fast_deinit(struct eap_sm *sm, void *priv){	struct eap_fast_data *data = priv;	struct eap_fast_pac *pac, *prev;	if (data == NULL)		return;	if (data->phase2_priv && data->phase2_method)		data->phase2_method->deinit(sm, data->phase2_priv);	os_free(data->phase2_types);	os_free(data->key_block_p);	eap_peer_tls_ssl_deinit(sm, &data->ssl);	pac = data->pac;	prev = NULL;	while (pac) {		prev = pac;		pac = pac->next;		eap_fast_free_pac(prev);	}	wpabuf_free(data->pending_phase2_req);	os_free(data);}static int eap_fast_derive_msk(struct eap_fast_data *data){	eap_fast_derive_eap_msk(data->simck, data->key_data);	eap_fast_derive_eap_emsk(data->simck, data->emsk);	data->success = 1;	return 0;}static void eap_fast_derive_key_auth(struct eap_sm *sm,				     struct eap_fast_data *data){	u8 *sks;	/* RFC 4851, Section 5.1:	 * Extra key material after TLS key_block: session_key_seed[40]	 */	sks = eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn, "key expansion",				  EAP_FAST_SKS_LEN);	if (sks == NULL) {		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "			   "session_key_seed");		return;	}	/*	 * RFC 4851, Section 5.2:	 * S-IMCK[0] = session_key_seed	 */	wpa_hexdump_key(MSG_DEBUG,			"EAP-FAST: session_key_seed (SKS = S-IMCK[0])",			sks, EAP_FAST_SKS_LEN);	data->simck_idx = 0;	os_memcpy(data->simck, sks, EAP_FAST_SIMCK_LEN);	os_free(sks);}static void eap_fast_derive_key_provisioning(struct eap_sm *sm,					     struct eap_fast_data *data){	os_free(data->key_block_p);	data->key_block_p = (struct eap_fast_key_block_provisioning *)		eap_fast_derive_key(sm->ssl_ctx, data->ssl.conn,				    "key expansion",				    sizeof(*data->key_block_p));	if (data->key_block_p == NULL) {		wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block");		return;	}	/*	 * RFC 4851, Section 5.2:	 * S-IMCK[0] = session_key_seed	 */	wpa_hexdump_key(MSG_DEBUG,			"EAP-FAST: session_key_seed (SKS = S-IMCK[0])",			data->key_block_p->session_key_seed,			sizeof(data->key_block_p->session_key_seed));	data->simck_idx = 0;	os_memcpy(data->simck, data->key_block_p->session_key_seed,		  EAP_FAST_SIMCK_LEN);	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: server_challenge",			data->key_block_p->server_challenge,			sizeof(data->key_block_p->server_challenge));	wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: client_challenge",			data->key_block_p->client_challenge,			sizeof(data->key_block_p->client_challenge));}static void eap_fast_derive_keys(struct eap_sm *sm, struct eap_fast_data *data){	if (data->anon_provisioning)		eap_fast_derive_key_provisioning(sm, data);	else		eap_fast_derive_key_auth(sm, data);}static int eap_fast_init_phase2_method(struct eap_sm *sm,				       struct eap_fast_data *data){	data->phase2_method =		eap_peer_get_eap_method(data->phase2_type.vendor,					data->phase2_type.method);	if (data->phase2_method == NULL)		return -1;	if (data->key_block_p) {		sm->auth_challenge = data->key_block_p->server_challenge;		sm->peer_challenge = data->key_block_p->client_challenge;	}	sm->init_phase2 = 1;	data->phase2_priv = data->phase2_method->init(sm);	sm->init_phase2 = 0;	sm->auth_challenge = NULL;	sm->peer_challenge = NULL;	return data->phase2_priv == NULL ? -1 : 0;}static int eap_fast_select_phase2_method(struct eap_fast_data *data, u8 type){	size_t i;	/* TODO: TNC with anonymous provisioning; need to require both	 * completed MSCHAPv2 and TNC */	if (data->anon_provisioning && type != EAP_TYPE_MSCHAPV2) {		wpa_printf(MSG_INFO, "EAP-FAST: Only EAP-MSCHAPv2 is allowed "			   "during unauthenticated provisioning; reject phase2"			   " type %d", type);		return -1;	}#ifdef EAP_TNC	if (type == EAP_TYPE_TNC) {		data->phase2_type.vendor = EAP_VENDOR_IETF;		data->phase2_type.method = EAP_TYPE_TNC;		wpa_printf(MSG_DEBUG, "EAP-FAST: Selected Phase 2 EAP "			   "vendor %d method %d for TNC",			   data->phase2_type.vendor,			   data->phase2_type.method);		return 0;	}#endif /* EAP_TNC */	for (i = 0; i < data->num_phase2_types; i++) {		if (data->phase2_types[i].vendor != EAP_VENDOR_IETF ||		    data->phase2_types[i].method != type)			continue;		data->phase2_type.vendor = data->phase2_types[i].vendor;		data->phase2_type.method = data->phase2_types[i].method;		wpa_printf(MSG_DEBUG, "EAP-FAST: Selected Phase 2 EAP "			   "vendor %d method %d",			   data->phase2_type.vendor,			   data->phase2_type.method);		break;	}	if (type != data->phase2_type.method || type == EAP_TYPE_NONE)		return -1;	return 0;}static int eap_fast_phase2_request(struct eap_sm *sm,				   struct eap_fast_data *data,				   struct eap_method_ret *ret,				   struct eap_hdr *hdr,				   struct wpabuf **resp){	size_t len = be_to_host16(hdr->length);	u8 *pos;	struct eap_method_ret iret;	struct eap_peer_config *config = eap_get_config(sm);	struct wpabuf msg;	if (len <= sizeof(struct eap_hdr)) {		wpa_printf(MSG_INFO, "EAP-FAST: too short "			   "Phase 2 request (len=%lu)", (unsigned long) len);		return -1;	}	pos = (u8 *) (hdr + 1);	wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 Request: type=%d", *pos);	if (*pos == EAP_TYPE_IDENTITY) {		*resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);		return 0;	}	if (data->phase2_priv && data->phase2_method &&	    *pos != data->phase2_type.method) {		wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 EAP sequence - "			   "deinitialize previous method");		data->phase2_method->deinit(sm, data->phase2_priv);		data->phase2_method = NULL;		data->phase2_priv = NULL;		data->phase2_type.vendor = EAP_VENDOR_IETF;		data->phase2_type.method = EAP_TYPE_NONE;	}	if (data->phase2_type.vendor == EAP_VENDOR_IETF &&	    data->phase2_type.method == EAP_TYPE_NONE &&	    eap_fast_select_phase2_method(data, *pos) < 0) {		if (eap_peer_tls_phase2_nak(data->phase2_types,					    data->num_phase2_types,					    hdr, resp))			return -1;		return 0;	}	if (data->phase2_priv == NULL &&	    eap_fast_init_phase2_method(sm, data) < 0) {		wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize "			   "Phase 2 EAP method %d", *pos);		ret->methodState = METHOD_DONE;		ret->decision = DECISION_FAIL;		return -1;	}	os_memset(&iret, 0, sizeof(iret));	wpabuf_set(&msg, hdr, len);	*resp = data->phase2_method->process(sm, data->phase2_priv, &iret,					     &msg);	if (*resp == NULL ||	    (iret.methodState == METHOD_DONE &&	     iret.decision == DECISION_FAIL)) {		ret->methodState = METHOD_DONE;		ret->decision = DECISION_FAIL;	} else if ((iret.methodState == METHOD_DONE ||		    iret.methodState == METHOD_MAY_CONT) &&		   (iret.decision == DECISION_UNCOND_SUCC ||		    iret.decision == DECISION_COND_SUCC)) {		data->phase2_success = 1;	}	if (*resp == NULL && config &&	    (config->pending_req_identity || config->pending_req_password ||	     config->pending_req_otp || config->pending_req_new_password)) {		wpabuf_free(data->pending_phase2_req);		data->pending_phase2_req = wpabuf_alloc_copy(hdr, len);	} else if (*resp == NULL)		return -1;	return 0;}static struct wpabuf * eap_fast_tlv_nak(int vendor_id, int tlv_type){	struct wpabuf *buf;	struct eap_tlv_nak_tlv *nak;	buf = wpabuf_alloc(sizeof(*nak));	if (buf == NULL)		return NULL;	nak = wpabuf_put(buf, sizeof(*nak));	nak->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | EAP_TLV_NAK_TLV);	nak->length = host_to_be16(6);	nak->vendor_id = host_to_be32(vendor_id);	nak->nak_type = host_to_be16(tlv_type);	return buf;}static struct wpabuf * eap_fast_tlv_result(int status, int intermediate){	struct wpabuf *buf;	struct eap_tlv_intermediate_result_tlv *result;	buf = wpabuf_alloc(sizeof(*result));	if (buf == NULL)		return NULL;	wpa_printf(MSG_DEBUG, "EAP-FAST: Add %sResult TLV(status=%d)",		   intermediate ? "Intermediate " : "", status);	result = wpabuf_put(buf, sizeof(*result));	result->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |					(intermediate ?					 EAP_TLV_INTERMEDIATE_RESULT_TLV :					 EAP_TLV_RESULT_TLV));	result->length = host_to_be16(2);	result->status = host_to_be16(status);	return buf;}static struct wpabuf * eap_fast_tlv_pac_ack(void){	struct wpabuf *buf;	struct eap_tlv_result_tlv *res;	struct eap_tlv_pac_ack_tlv *ack;	buf = wpabuf_alloc(sizeof(*res) + sizeof(*ack));	if (buf == NULL)		return NULL;	wpa_printf(MSG_DEBUG, "EAP-FAST: Add PAC TLV (ack)");	ack = wpabuf_put(buf, sizeof(*ack));	ack->tlv_type = host_to_be16(EAP_TLV_PAC_TLV |				     EAP_TLV_TYPE_MANDATORY);	ack->length = host_to_be16(sizeof(*ack) - sizeof(struct eap_tlv_hdr));	ack->pac_type = host_to_be16(PAC_TYPE_PAC_ACKNOWLEDGEMENT);	ack->pac_len = host_to_be16(2);	ack->result = host_to_be16(EAP_TLV_RESULT_SUCCESS);	return buf;}static struct wpabuf * eap_fast_process_eap_payload_tlv(	struct eap_sm *sm, struct eap_fast_data *data,	struct eap_method_ret *ret, const struct eap_hdr *req,	u8 *eap_payload_tlv, size_t eap_payload_tlv_len){	struct eap_hdr *hdr;	struct wpabuf *resp = NULL;	if (eap_payload_tlv_len < sizeof(*hdr)) {		wpa_printf(MSG_DEBUG, "EAP-FAST: too short EAP "			   "Payload TLV (len=%lu)",			   (unsigned long) eap_payload_tlv_len);		return NULL;	}	hdr = (struct eap_hdr *) eap_payload_tlv;	if (be_to_host16(hdr->length) > eap_payload_tlv_len) {		wpa_printf(MSG_DEBUG, "EAP-FAST: EAP packet overflow in "			   "EAP Payload TLV");		return NULL;	}	if (hdr->code != EAP_CODE_REQUEST) {		wpa_printf(MSG_INFO, "EAP-FAST: Unexpected code=%d in "			   "Phase 2 EAP header", hdr->code);		return NULL;	}	if (eap_fast_phase2_request(sm, data, ret, hdr, &resp)) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -