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

📄 eap_peap.c

📁 IEEE802.11 a/b/g 客户端应用程序源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * EAP peer method: 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 "crypto/sha1.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 "eap_common/eap_peap_common.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 * 2 = draft-josefsson-ppext-eap-tls-eap-10.txt */#define EAP_PEAP_VERSION 1static 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 */	u8 *key_data;	struct wpabuf *pending_phase2_req;	enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;	int crypto_binding_used;	u8 ipmk[40];	u8 cmk[20];	int soh; /* Whether IF-TNCCS-SOH (Statement of Health; Microsoft NAP)		  * is enabled. */};static int 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=soh")) {		data->soh = 1;		wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH enabled");	}#endif /* EAP_TNC */	return 0;}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) < 0) {		eap_peap_deinit(sm, data);		return NULL;	}	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)) {		wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL.");		eap_peap_deinit(sm, data);		return NULL;	}	return data;}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);	os_free(data->key_data);	wpabuf_free(data->pending_phase2_req);	os_free(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 funtion 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 == 32 &&	    data->phase2_method->vendor == EAP_VENDOR_IETF &&	    data->phase2_method->method == EAP_TYPE_MSCHAPV2) {		/*		 * Microsoft uses reverse order for MS-MPPE keys in		 * EAP-PEAP when compared to EAP-FAST derivation of		 * ISK. Swap the keys here to get the correct ISK for		 * EAP-PEAPv0 cryptobinding.		 */		u8 tmp[16];		os_memcpy(tmp, key, 16);		os_memcpy(key, key + 16, 16);		os_memcpy(key + 16, tmp, 16);	}	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];	/*	 * 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);	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);	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));	/* 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 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;	u8 binding_nonce[32];	/* FIX: should binding_nonce be copied from request? */	if (os_get_random(binding_nonce, 32))		return -1;	/* 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->peap_version); /* RecvVersion */	wpabuf_put_u8(buf, 1); /* SubType: 0 = Request, 1 = Response */	wpabuf_put_data(buf, 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_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 funtion 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_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;	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;	hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac);

⌨️ 快捷键说明

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