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

📄 eap_peap.c

📁 一个Linux下无线网卡的设置工具
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * WPA Supplicant / EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-07.txt) * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>#include <stdio.h>#include <string.h>#include "common.h"#include "eap_i.h"#include "eap_tls_common.h"#include "wpa_supplicant.h"#include "config_ssid.h"#include "tls.h"#include "eap_tlv.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-07.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;	u8 phase2_type;	u8 *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;	u8 *pending_phase2_req;	size_t pending_phase2_req_len;};static void * eap_peap_init(struct eap_sm *sm){	struct eap_peap_data *data;	struct wpa_ssid *config = eap_get_config(sm);	data = malloc(sizeof(*data));	if (data == NULL)		return NULL;	sm->peap_done = FALSE;	memset(data, 0, sizeof(*data));	data->peap_version = EAP_PEAP_VERSION;	data->force_peap_version = -1;	data->peap_outer_success = 2;	if (config && config->phase1) {		char *pos = strstr(config->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 (strstr(config->phase1, "peaplabel=1")) {			data->force_new_label = 1;			wpa_printf(MSG_DEBUG, "EAP-PEAP: Force new label for "				   "key derivation");		}		if (strstr(config->phase1, "peap_outer_success=0")) {			data->peap_outer_success = 0;			wpa_printf(MSG_DEBUG, "EAP-PEAP: terminate "				   "authentication on tunneled EAP-Success");		} else if (strstr(config->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 (strstr(config->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 (config && config->phase2) {		char *start, *pos, *buf;		u8 method, *methods = NULL, *_methods;		size_t num_methods = 0;		start = buf = strdup(config->phase2);		if (buf == NULL) {			eap_peap_deinit(sm, data);			return NULL;		}		while (start && *start != '\0') {			pos = strstr(start, "auth=");			if (pos == NULL)				break;			if (start != pos && *(pos - 1) != ' ') {				start = pos + 5;				continue;			}			start = pos + 5;			pos = strchr(start, ' ');			if (pos)				*pos++ = '\0';			method = eap_get_phase2_type(start);			if (method == EAP_TYPE_NONE) {				wpa_printf(MSG_ERROR, "EAP-PEAP: Unsupported "					   "Phase2 method '%s'", start);			} else {				num_methods++;				_methods = realloc(methods, num_methods);				if (_methods == NULL) {					free(methods);					free(buf);					eap_peap_deinit(sm, data);					return NULL;				}				methods = _methods;				methods[num_methods - 1] = method;			}			start = pos;		}		free(buf);		data->phase2_types = methods;		data->num_phase2_types = num_methods;	}	if (data->phase2_types == NULL) {		data->phase2_types =			eap_get_phase2_types(config, &data->num_phase2_types);	}	if (data->phase2_types == NULL) {		wpa_printf(MSG_ERROR, "EAP-PEAP: No Phase2 method available");		eap_peap_deinit(sm, data);		return NULL;	}	wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Phase2 EAP types",		    data->phase2_types, data->num_phase2_types);	data->phase2_type = EAP_TYPE_NONE;	if (eap_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);	free(data->phase2_types);	eap_tls_ssl_deinit(sm, &data->ssl);	free(data->key_data);	free(data->pending_phase2_req);	free(data);}static int eap_peap_encrypt(struct eap_sm *sm, struct eap_peap_data *data,			    int id, const u8 *plain, size_t plain_len,			    u8 **out_data, size_t *out_len){	int res;	u8 *pos;	struct eap_hdr *resp;	/* TODO: add support for fragmentation, if needed. This will need to	 * add TLS Message Length field, if the frame is fragmented.	 * Note: Microsoft IAS did not seem to like TLS Message Length with	 * PEAP/MSCHAPv2. */	resp = malloc(sizeof(struct eap_hdr) + 2 + data->ssl.tls_out_limit);	if (resp == NULL)		return -1;	resp->code = EAP_CODE_RESPONSE;	resp->identifier = id;	pos = (u8 *) (resp + 1);	*pos++ = EAP_TYPE_PEAP;	*pos++ = data->peap_version;	res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,				     plain, plain_len,				     pos, data->ssl.tls_out_limit);	if (res < 0) {		wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt Phase 2 "			   "data");		free(resp);		return -1;	}	*out_len = sizeof(struct eap_hdr) + 2 + res;	resp->length = host_to_be16(*out_len);	*out_data = (u8 *) resp;	return 0;}static int eap_peap_phase2_nak(struct eap_sm *sm,			       struct eap_peap_data *data,			       struct eap_hdr *hdr,			       u8 **resp, size_t *resp_len){	struct eap_hdr *resp_hdr;	u8 *pos = (u8 *) (hdr + 1);	wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Request: Nak type=%d", *pos);	wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Allowed Phase2 EAP types",		    data->phase2_types, data->num_phase2_types);	*resp_len = sizeof(struct eap_hdr) + 1 + data->num_phase2_types;	*resp = malloc(*resp_len);	if (*resp == NULL)		return -1;	resp_hdr = (struct eap_hdr *) (*resp);	resp_hdr->code = EAP_CODE_RESPONSE;	resp_hdr->identifier = hdr->identifier;	resp_hdr->length = host_to_be16(*resp_len);	pos = (u8 *) (resp_hdr + 1);	*pos++ = EAP_TYPE_NAK;	memcpy(pos, data->phase2_types, data->num_phase2_types);	return 0;}static int eap_peap_phase2_request(struct eap_sm *sm,				   struct eap_peap_data *data,				   struct eap_method_ret *ret,				   const struct eap_hdr *req,				   struct eap_hdr *hdr,				   u8 **resp, size_t *resp_len){	size_t len = be_to_host16(hdr->length);	u8 *pos;	struct eap_method_ret iret;	struct wpa_ssid *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, req->identifier, resp_len, 1);		break;	case EAP_TYPE_TLV:		memset(&iret, 0, sizeof(iret));		if (eap_tlv_process(sm, &iret, hdr, resp, resp_len)) {			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;	default:		if (data->phase2_type == EAP_TYPE_NONE) {			int i;			for (i = 0; i < data->num_phase2_types; i++) {				if (data->phase2_types[i] != *pos)					continue;				data->phase2_type = *pos;				wpa_printf(MSG_DEBUG, "EAP-PEAP: Selected "					   "Phase 2 EAP method %d",					   data->phase2_type);				break;			}		}		if (*pos != data->phase2_type || *pos == EAP_TYPE_NONE) {			if (eap_peap_phase2_nak(sm, data, hdr, resp, resp_len))				return -1;			return 0;		}		if (data->phase2_priv == NULL) {			data->phase2_method = eap_sm_get_eap_methods(*pos);			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;		}		memset(&iret, 0, sizeof(iret));		*resp = data->phase2_method->process(sm, data->phase2_priv,						     &iret, (u8 *) hdr, len,						     resp_len);		if ((iret.methodState == METHOD_DONE ||		     iret.methodState == METHOD_MAY_CONT) &&		    (iret.decision == DECISION_UNCOND_SUCC ||		     iret.decision == DECISION_COND_SUCC)) {			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)) {		free(data->pending_phase2_req);		data->pending_phase2_req = malloc(len);		if (data->pending_phase2_req) {			memcpy(data->pending_phase2_req, hdr, len);			data->pending_phase2_req_len = 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 u8 *in_data, size_t in_len,			    u8 **out_data, size_t *out_len){	u8 *in_decrypted;	int buf_len, len_decrypted, len, skip_change = 0;	struct eap_hdr *hdr, *rhdr;	u8 *resp = NULL;	size_t resp_len;	const u8 *msg;	size_t msg_len;	int need_more_input;	wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"		   " Phase 2", (unsigned long) in_len);	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. */		free(data->ssl.tls_in);		data->ssl.tls_in = NULL;		data->ssl.tls_in_len = 0;		data->ssl.tls_in_left = 0;		data->ssl.tls_in_total = 0;		in_decrypted = data->pending_phase2_req;		data->pending_phase2_req = NULL;		len_decrypted = data->pending_phase2_req_len;		skip_change = 1;		goto continue_req;	}	msg = eap_tls_data_reassemble(sm, &data->ssl, in_data, in_len,				      &msg_len, &need_more_input);	if (msg == NULL)		return need_more_input ? 1 : -1;	if (in_len == 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;

⌨️ 快捷键说明

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