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

📄 eap_peap.c

📁 IEEE 802.11a/b/g 服务器端AP
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * hostapd / EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt) * 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 "sha1.h"#include "eap_i.h"#include "eap_tls_common.h"#include "eap_common/eap_tlv_common.h"#include "eap_common/eap_peap_common.h"#include "tls.h"#include "tncs.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 * 2 = draft-josefsson-ppext-eap-tls-eap-10.txt */#define EAP_PEAP_VERSION 1static void eap_peap_reset(struct eap_sm *sm, void *priv);struct eap_peap_data {	struct eap_ssl_data ssl;	enum {		START, PHASE1, PHASE1_ID2, PHASE2_START, PHASE2_ID,		PHASE2_METHOD, PHASE2_SOH,		PHASE2_TLV, SUCCESS_REQ, FAILURE_REQ, SUCCESS, FAILURE	} state;	int peap_version;	int recv_version;	const struct eap_method *phase2_method;	void *phase2_priv;	int force_version;	struct wpabuf *pending_phase2_resp;	enum { TLV_REQ_NONE, TLV_REQ_SUCCESS, TLV_REQ_FAILURE } tlv_request;	int crypto_binding_sent;	int crypto_binding_used;	enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;	u8 binding_nonce[32];	u8 ipmk[40];	u8 cmk[20];	u8 *phase2_key;	size_t phase2_key_len;	struct wpabuf *soh_response;};static const char * eap_peap_state_txt(int state){	switch (state) {	case START:		return "START";	case PHASE1:		return "PHASE1";	case PHASE1_ID2:		return "PHASE1_ID2";	case PHASE2_START:		return "PHASE2_START";	case PHASE2_ID:		return "PHASE2_ID";	case PHASE2_METHOD:		return "PHASE2_METHOD";	case PHASE2_SOH:		return "PHASE2_SOH";	case PHASE2_TLV:		return "PHASE2_TLV";	case SUCCESS_REQ:		return "SUCCESS_REQ";	case FAILURE_REQ:		return "FAILURE_REQ";	case SUCCESS:		return "SUCCESS";	case FAILURE:		return "FAILURE";	default:		return "Unknown?!";	}}static void eap_peap_state(struct eap_peap_data *data, int state){	wpa_printf(MSG_DEBUG, "EAP-PEAP: %s -> %s",		   eap_peap_state_txt(data->state),		   eap_peap_state_txt(state));	data->state = state;}static struct wpabuf * eap_peapv2_tlv_eap_payload(struct wpabuf *buf){	struct wpabuf *e;	struct eap_tlv_hdr *tlv;	if (buf == NULL)		return NULL;	/* Encapsulate EAP packet in EAP-Payload TLV */	wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Add EAP-Payload TLV");	e = wpabuf_alloc(sizeof(*tlv) + wpabuf_len(buf));	if (e == NULL) {		wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Failed to allocate memory "			   "for TLV encapsulation");		wpabuf_free(buf);		return NULL;	}	tlv = wpabuf_put(e, sizeof(*tlv));	tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |				     EAP_TLV_EAP_PAYLOAD_TLV);	tlv->length = host_to_be16(wpabuf_len(buf));	wpabuf_put_buf(e, buf);	wpabuf_free(buf);	return e;}static void eap_peap_req_success(struct eap_sm *sm,				 struct eap_peap_data *data){	if (data->state == FAILURE || data->state == FAILURE_REQ) {		eap_peap_state(data, FAILURE);		return;	}	if (data->peap_version == 0) {		data->tlv_request = TLV_REQ_SUCCESS;		eap_peap_state(data, PHASE2_TLV);	} else {		eap_peap_state(data, SUCCESS_REQ);	}}static void eap_peap_req_failure(struct eap_sm *sm,				 struct eap_peap_data *data){	if (data->state == FAILURE || data->state == FAILURE_REQ ||	    data->state == SUCCESS_REQ || data->tlv_request != TLV_REQ_NONE) {		eap_peap_state(data, FAILURE);		return;	}	if (data->peap_version == 0) {		data->tlv_request = TLV_REQ_FAILURE;		eap_peap_state(data, PHASE2_TLV);	} else {		eap_peap_state(data, FAILURE_REQ);	}}static void * eap_peap_init(struct eap_sm *sm){	struct eap_peap_data *data;	data = os_zalloc(sizeof(*data));	if (data == NULL)		return NULL;	data->peap_version = EAP_PEAP_VERSION;	data->force_version = -1;	if (sm->user && sm->user->force_version >= 0) {		data->force_version = sm->user->force_version;		wpa_printf(MSG_DEBUG, "EAP-PEAP: forcing version %d",			   data->force_version);		data->peap_version = data->force_version;	}	data->state = START;	data->crypto_binding = OPTIONAL_BINDING;	if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {		wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL.");		eap_peap_reset(sm, data);		return NULL;	}	return data;}static void eap_peap_reset(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->reset(sm, data->phase2_priv);	eap_server_tls_ssl_deinit(sm, &data->ssl);	wpabuf_free(data->pending_phase2_resp);	os_free(data->phase2_key);	wpabuf_free(data->soh_response);	os_free(data);}static struct wpabuf * eap_peap_build_start(struct eap_sm *sm,					    struct eap_peap_data *data, u8 id){	struct wpabuf *req;	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PEAP, 1,			    EAP_CODE_REQUEST, id);	if (req == NULL) {		wpa_printf(MSG_ERROR, "EAP-PEAP: Failed to allocate memory for"			   " request");		eap_peap_state(data, FAILURE);		return NULL;	}	wpabuf_put_u8(req, EAP_TLS_FLAGS_START | data->peap_version);	eap_peap_state(data, PHASE1);	return req;}static struct wpabuf * eap_peap_build_phase2_req(struct eap_sm *sm,						 struct eap_peap_data *data,						 u8 id){	struct wpabuf *buf, *encr_req;	const u8 *req;	size_t req_len;	if (data->phase2_method == NULL || data->phase2_priv == NULL) {		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 method not ready");		return NULL;	}	buf = data->phase2_method->buildReq(sm, data->phase2_priv, id);	if (data->peap_version >= 2 && buf)		buf = eap_peapv2_tlv_eap_payload(buf);	if (buf == NULL)		return NULL;	req = wpabuf_head(buf);	req_len = wpabuf_len(buf);	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",			req, req_len);	if (data->peap_version == 0 &&	    data->phase2_method->method != EAP_TYPE_TLV) {		req += sizeof(struct eap_hdr);		req_len -= sizeof(struct eap_hdr);	}	encr_req = eap_server_tls_encrypt(sm, &data->ssl, req, req_len);	wpabuf_free(buf);	return encr_req;}#ifdef EAP_TNCstatic struct wpabuf * eap_peap_build_phase2_soh(struct eap_sm *sm,						 struct eap_peap_data *data,						 u8 id){	struct wpabuf *buf1, *buf, *encr_req;	const u8 *req;	size_t req_len;	buf1 = tncs_build_soh_request();	if (buf1 == NULL)		return NULL;	buf = eap_msg_alloc(EAP_VENDOR_MICROSOFT, 0x21, wpabuf_len(buf1),			    EAP_CODE_REQUEST, id);	if (buf == NULL) {		wpabuf_free(buf1);		return NULL;	}	wpabuf_put_buf(buf, buf1);	wpabuf_free(buf1);	req = wpabuf_head(buf);	req_len = wpabuf_len(buf);	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 SOH data",			req, req_len);	req += sizeof(struct eap_hdr);	req_len -= sizeof(struct eap_hdr);	encr_req = eap_server_tls_encrypt(sm, &data->ssl, req, req_len);	wpabuf_free(buf);	return encr_req;}#endif /* EAP_TNC */static void eap_peap_get_isk(struct eap_peap_data *data,			     u8 *isk, size_t isk_len){	size_t key_len;	os_memset(isk, 0, isk_len);	if (data->phase2_key == NULL)		return;	key_len = data->phase2_key_len;	if (key_len > isk_len)		key_len = isk_len;	os_memcpy(isk, data->phase2_key, key_len);}static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data){	u8 *tk;	u8 isk[32], imck[60];	/*	 * Tunnel key (TK) is the first 60 octets of the key generated by	 * phase 1 of PEAP (based on TLS).	 */	tk = eap_server_tls_derive_key(sm, &data->ssl, "client EAP encryption",				       EAP_TLS_KEY_LEN);	if (tk == NULL)		return -1;	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);	eap_peap_get_isk(data, isk, sizeof(isk));	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);	peap_prfplus(data->peap_version, tk, 40, "Inner Methods Compound Keys",		     isk, sizeof(isk), imck, sizeof(imck));	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",			imck, sizeof(imck));	os_free(tk);	/* TODO: fast-connect: IPMK|CMK = TK */	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);	return 0;}static struct wpabuf * eap_peap_build_phase2_tlv(struct eap_sm *sm,						 struct eap_peap_data *data,						 u8 id){	struct wpabuf *buf, *encr_req;	size_t len;	len = 6; /* Result TLV */	if (data->crypto_binding != NO_BINDING)		len += 60; /* Cryptobinding TLV */#ifdef EAP_TNC	if (data->soh_response)		len += wpabuf_len(data->soh_response);#endif /* EAP_TNC */	buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, len,			    EAP_CODE_REQUEST, id);	if (buf == NULL)		return NULL;	wpabuf_put_u8(buf, 0x80); /* Mandatory */	wpabuf_put_u8(buf, EAP_TLV_RESULT_TLV);	/* Length */	wpabuf_put_be16(buf, 2);	/* Status */	wpabuf_put_be16(buf, data->tlv_request == TLV_REQ_SUCCESS ?			EAP_TLV_RESULT_SUCCESS : EAP_TLV_RESULT_FAILURE);	if (data->peap_version == 0 && data->tlv_request == TLV_REQ_SUCCESS &&	    data->crypto_binding != NO_BINDING) {		u8 *mac;		u8 eap_type = EAP_TYPE_PEAP;		const u8 *addr[2];		size_t len[2];		u16 tlv_type;#ifdef EAP_TNC		if (data->soh_response) {			wpa_printf(MSG_DEBUG, "EAP-PEAP: Adding MS-SOH "				   "Response TLV");			wpabuf_put_buf(buf, data->soh_response);			wpabuf_free(data->soh_response);			data->soh_response = NULL;		}#endif /* EAP_TNC */		if (eap_peap_derive_cmk(sm, data) < 0 ||		    os_get_random(data->binding_nonce, 32)) {			wpabuf_free(buf);			return NULL;		}		/* 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;		if (data->peap_version >= 2)			tlv_type |= EAP_TLV_TYPE_MANDATORY;		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->recv_version); /* RecvVersion */		wpabuf_put_u8(buf, 0); /* 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]);		hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac);		wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC",			    mac, SHA1_MAC_LEN);		data->crypto_binding_sent = 1;	}	wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 TLV data",			    buf);	encr_req = eap_server_tls_encrypt(sm, &data->ssl, wpabuf_head(buf),					  wpabuf_len(buf));	wpabuf_free(buf);	return encr_req;}static struct wpabuf * eap_peap_build_phase2_term(struct eap_sm *sm,						  struct eap_peap_data *data,						  u8 id, int success){	struct wpabuf *encr_req;	size_t req_len;	struct eap_hdr *hdr;	req_len = sizeof(*hdr);	hdr = os_zalloc(req_len);	if (hdr == NULL)		return NULL;	hdr->code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE;	hdr->identifier = id;	hdr->length = host_to_be16(req_len);	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",			(u8 *) hdr, req_len);

⌨️ 快捷键说明

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