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

📄 eap_tls.c

📁 freeradius-server-2.1.3.tar.gz安装源文件
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * eap_tls.c * * Version:     $Id$ * *   This program is free software; you can redistribute it and/or modify *   it under the terms of the GNU General Public License as published by *   the Free Software Foundation; either version 2 of the License, or *   (at your option) any later version. * *   This program is distributed in the hope that it will be useful, *   but WITHOUT ANY WARRANTY; without even the implied warranty of *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *   GNU General Public License for more details. * *   You should have received a copy of the GNU General Public License *   along with this program; if not, write to the Free Software *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * Copyright 2001  hereUare Communications, Inc. <raghud@hereuare.com> * Copyright 2003  Alan DeKok <aland@freeradius.org> * Copyright 2006  The FreeRADIUS server project *//* * *  TLS Packet Format in EAP *  --- ------ ------ -- --- * 0                   1                   2                   3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |     Code      |   Identifier  |            Length             | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |     Type      |     Flags     |      TLS Message Length * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |     TLS Message Length        |       TLS Data... * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * */#include <freeradius-devel/ident.h>RCSID("$Id$")#include <freeradius-devel/autoconf.h>#include <assert.h>#include "eap_tls.h"/* *      Allocate a new TLS_PACKET */EAPTLS_PACKET *eaptls_alloc(void){	EAPTLS_PACKET   *rp;	if ((rp = malloc(sizeof(EAPTLS_PACKET))) == NULL) {		radlog(L_ERR, "rlm_eap_tls: out of memory");		return NULL;	}	memset(rp, 0, sizeof(EAPTLS_PACKET));	return rp;}/* *      Free EAPTLS_PACKET */void eaptls_free(EAPTLS_PACKET **eaptls_packet_ptr){	EAPTLS_PACKET *eaptls_packet;	if (!eaptls_packet_ptr) return;	eaptls_packet = *eaptls_packet_ptr;	if (eaptls_packet == NULL) return;	if (eaptls_packet->data) {		free(eaptls_packet->data);		eaptls_packet->data = NULL;	}	free(eaptls_packet);	*eaptls_packet_ptr = NULL;}/*   The S flag is set only within the EAP-TLS start message   sent from the EAP server to the peer.*/int eaptls_start(EAP_DS *eap_ds, int peap_flag){	EAPTLS_PACKET 	reply;	reply.code = EAPTLS_START;	reply.length = TLS_HEADER_LEN + 1/*flags*/;	reply.flags = peap_flag;	reply.flags = SET_START(reply.flags);	reply.data = NULL;	reply.dlen = 0;	eaptls_compose(eap_ds, &reply);	return 1;}int eaptls_success(EAP_HANDLER *handler, int peap_flag){	EAPTLS_PACKET	reply;	VALUE_PAIR *vp, *vps = NULL;	REQUEST *request = handler->request;	tls_session_t *tls_session = handler->opaque;	reply.code = EAPTLS_SUCCESS;	reply.length = TLS_HEADER_LEN;	reply.flags = peap_flag;	reply.data = NULL;	reply.dlen = 0;	/*	 *	If there's no session resumption, delete the entry	 *	from the cache.  This means either it's disabled	 *	globally for this SSL context, OR we were told to	 *	disable it for this user.	 *	 *	This also means you can't turn it on just for one	 *	user.	 */	if ((!tls_session->allow_session_resumption) ||	    (((vp = pairfind(request->config_items, 1127)) != NULL) &&	     (vp->vp_integer == 0))) {		SSL_CTX_remove_session(tls_session->ctx,				       tls_session->ssl->session);		tls_session->allow_session_resumption = 0;		/*		 *	If we're in a resumed session and it's		 *	not allowed, 		 */		if (SSL_session_reused(tls_session->ssl)) {			RDEBUG("FAIL: Forcibly stopping session resumption as it is not allowed.");			return eaptls_fail(handler, peap_flag);		}				/*		 *	Else resumption IS allowed, so we store the		 *	user data in the cache.		 */	} else if (!SSL_session_reused(tls_session->ssl)) {		RDEBUG2("Saving response in the cache");				vp = paircopy2(request->reply->vps, PW_USER_NAME);		pairadd(&vps, vp);				vp = paircopy2(request->packet->vps, PW_STRIPPED_USER_NAME);		pairadd(&vps, vp);				if (vps) {			SSL_SESSION_set_ex_data(tls_session->ssl->session,						eaptls_session_idx, vps);		}		/*		 *	Else the session WAS allowed.  Copy the cached		 *	reply.		 */	} else {	       		vp = SSL_SESSION_get_ex_data(tls_session->ssl->session,					     eaptls_session_idx);		if (!vp) {			RDEBUG("WARNING: No information in cached session!");		} else {			RDEBUG("Adding cached attributes to the reply:");			debug_pair_list(vp);			pairadd(&request->reply->vps, paircopy(vp));			/*			 *	Mark the request as resumed.			 */			vp = pairmake("EAP-Session-Resumed", "0", T_OP_SET);			if (vp) pairadd(&request->packet->vps, vp);		}	}	/*	 *	Call compose AFTER checking for cached data.	 */	eaptls_compose(handler->eap_ds, &reply);	/*	 *	Automatically generate MPPE keying material.	 */	if (tls_session->prf_label) {		eaptls_gen_mppe_keys(&handler->request->reply->vps,				     tls_session->ssl, tls_session->prf_label);	} else {		RDEBUG("WARNING: Not adding MPPE keys because there is no PRF label");	}	return 1;}int eaptls_fail(EAP_HANDLER *handler, int peap_flag){	EAPTLS_PACKET	reply;	tls_session_t *tls_session = handler->opaque;	reply.code = EAPTLS_FAIL;	reply.length = TLS_HEADER_LEN;	reply.flags = peap_flag;	reply.data = NULL;	reply.dlen = 0;	/*	 *	Force the session to NOT be cached.	 */	SSL_CTX_remove_session(tls_session->ctx, tls_session->ssl->session);	eaptls_compose(handler->eap_ds, &reply);	return 1;}/*   A single TLS record may be up to 16384 octets in length, but a TLS   message may span multiple TLS records, and a TLS certificate message   may in principle be as long as 16MB.*//* *	Frame the Dirty data that needs to be send to the client in an *	EAP-Request.  We always embed the TLS-length in all EAP-TLS *	packets that we send, for easy reference purpose.  Handle *	fragmentation and sending the next fragment etc. */int eaptls_request(EAP_DS *eap_ds, tls_session_t *ssn){	EAPTLS_PACKET	reply;	unsigned int	size;	unsigned int 	nlen;	unsigned int 	lbit = 0;	/* This value determines whether we set (L)ength flag for		EVERY packet we send and add corresponding		"TLS Message Length" field.	length_flag = TRUE;		This means we include L flag and "TLS Msg Len" in EVERY		packet we send out.	length_flag = FALSE;		This means we include L flag and "TLS Msg Len" **ONLY**		in First packet of a fragment series. We do not use		it anywhere else.		Having L flag in every packet is prefered.	*/	if (ssn->length_flag) {		lbit = 4;	}	if (ssn->fragment == 0) {		ssn->tls_msg_len = ssn->dirty_out.used;	}	reply.code = EAPTLS_REQUEST;	reply.flags = ssn->peap_flag;	/* Send data, NOT more than the FRAGMENT size */	if (ssn->dirty_out.used > ssn->offset) {		size = ssn->offset;		reply.flags = SET_MORE_FRAGMENTS(reply.flags);		/* Length MUST be included if it is the First Fragment */		if (ssn->fragment == 0) {			lbit = 4;		}		ssn->fragment = 1;	} else {		size = ssn->dirty_out.used;		ssn->fragment = 0;	}	reply.dlen = lbit + size;	reply.length = TLS_HEADER_LEN + 1/*flags*/ + reply.dlen;	reply.data = malloc(reply.dlen);	if (lbit) {		nlen = htonl(ssn->tls_msg_len);		memcpy(reply.data, &nlen, lbit);		reply.flags = SET_LENGTH_INCLUDED(reply.flags);	}	(ssn->record_minus)(&ssn->dirty_out, reply.data + lbit, size);	eaptls_compose(eap_ds, &reply);	free(reply.data);	reply.data = NULL;	return 1;}/* * Acknowledge received is for one of the following messages sent earlier * 1. Handshake completed Message, so now send, EAP-Success * 2. Alert Message, now send, EAP-Failure * 3. Fragment Message, now send, next Fragment */static eaptls_status_t eaptls_ack_handler(EAP_HANDLER *handler){	tls_session_t *tls_session;	REQUEST *request = handler->request;	tls_session = (tls_session_t *)handler->opaque;	if (tls_session == NULL){		radlog_request(L_ERR, 0, request, "FAIL: Unexpected ACK received.  Could not obtain session information.");		return EAPTLS_FAIL;	}	if (tls_session->info.initialized == 0) {		RDEBUG("No SSL info available. Waiting for more SSL data.");		return EAPTLS_REQUEST;	}	if ((tls_session->info.content_type == handshake) &&	    (tls_session->info.origin == 0)) {		radlog_request(L_ERR, 0, request, "FAIL: ACK without earlier message.");		return EAPTLS_FAIL;	}	switch (tls_session->info.content_type) {	case alert:		RDEBUG2("ACK alert");		eaptls_fail(handler, tls_session->peap_flag);		return EAPTLS_FAIL;	case handshake:		if (tls_session->info.handshake_type == finished) {			RDEBUG2("ACK handshake is finished");			/* 			 *	From now on all the content is			 *	application data set it here as nobody else			 *	sets it.			 */			tls_session->info.content_type = application_data;			return EAPTLS_SUCCESS;		} /* else more data to send */		RDEBUG2("ACK handshake fragment handler");		/* Fragmentation handler, send next fragment */		return EAPTLS_REQUEST;	case application_data:		RDEBUG2("ACK handshake fragment handler in application data");		return EAPTLS_REQUEST;								/*		 *	For the rest of the conditions, switch over		 *	to the default section below.		 */	default:		RDEBUG2("ACK default");		radlog_request(L_ERR, 0, request, "Invalid ACK received: %d",		       tls_session->info.content_type);		return EAPTLS_FAIL;	}}/* *	Similarly, when the EAP server receives an EAP-Response with *	the M bit set, it MUST respond with an EAP-Request with *	EAP-Type=EAP-TLS and no data. This serves as a fragment ACK. * *	In order to prevent errors in the processing of fragments, the *	EAP server MUST use increment the Identifier value for each *	fragment ACK contained within an EAP-Request, and the peer *	MUST include this Identifier value in the subsequent fragment *	contained within an EAP- Reponse. * *	EAP server sends an ACK when it determines there are More *	fragments to receive to make the complete *	TLS-record/TLS-Message */static int eaptls_send_ack(EAP_DS *eap_ds, int peap_flag){	EAPTLS_PACKET 	reply;	reply.code = EAPTLS_ACK;	reply.length = TLS_HEADER_LEN + 1/*flags*/;	reply.flags = peap_flag;	reply.data = NULL;	reply.dlen = 0;	eaptls_compose(eap_ds, &reply);	return 1;}/* *	The S flag is set only within the EAP-TLS start message sent *	from the EAP server to the peer. * *	Similarly, when the EAP server receives an EAP-Response with *	the M bit set, it MUST respond with an EAP-Request with *	EAP-Type=EAP-TLS and no data. This serves as a fragment *	ACK. The EAP peer MUST wait. */static eaptls_status_t eaptls_verify(EAP_HANDLER *handler){	EAP_DS *eap_ds = handler->eap_ds;	EAP_DS *prev_eap_ds = handler->prev_eapds;	eaptls_packet_t	*eaptls_packet, *eaptls_prev = NULL;	REQUEST *request = handler->request;	/*	 *	We don't check ANY of the input parameters.  It's all	 *	code which works together, so if something is wrong,	 *	we SHOULD core dump.	 *	 *	e.g. if eap_ds is NULL, of if eap_ds->response is	 *	NULL, of if it's NOT an EAP-Response, or if the packet	 *	is too short.  See eap_validation()., in ../../eap.c	 *	 *	Also, eaptype_select() takes care of selecting the	 *	appropriate type, so we don't need to check	 *	eap_ds->response->type.type == PW_EAP_TLS, or anything	 *	else.	 */	eaptls_packet = (eaptls_packet_t *)eap_ds->response->type.data;	if (prev_eap_ds && prev_eap_ds->response)		eaptls_prev = (eaptls_packet_t *)prev_eap_ds->response->type.data;	/*	 *	check for ACK	 *	 *	If there's no TLS data, or there's 1 byte of TLS data,	 *	with the flags set to zero, then it's an ACK.	 *	 *	Find if this is a reply to the previous request sent	 */	if ((eaptls_packet == NULL) ||	    ((eap_ds->response->length == EAP_HEADER_LEN + 2) &&	     ((eaptls_packet->flags & 0xc0) == 0x00))) {#if 0		/*		 *	Un-comment this for TLS inside of TTLS/PEAP		 */		RDEBUG2("Received EAP-TLS ACK message");		return eaptls_ack_handler(handler);#else		if (prev_eap_ds->request->id == eap_ds->response->id) {			/*			 *	Run the ACK handler directly from here.			 */			RDEBUG2("Received TLS ACK");			return eaptls_ack_handler(handler);		} else {			radlog_request(L_ERR, 0, request, "Received Invalid TLS ACK");			return EAPTLS_INVALID;		}#endif	}	/*	 *	We send TLS_START, but do not receive it.	 */	if (TLS_START(eaptls_packet->flags)) {		RDEBUG("Received unexpected EAP-TLS Start message");		return EAPTLS_INVALID;	}	/*	 *	The L bit (length included) is set to indicate the	 *	presence of the four octet TLS Message Length field,	 *	and MUST be set for the first fragment of a fragmented	 *	TLS message or set of messages.	 *	 *	The M bit (more fragments) is set on all but the last	 *	fragment.	 *	 *	The S bit (EAP-TLS start) is set in an EAP-TLS Start	 *	message. This differentiates the EAP-TLS Start message	 *	from a fragment acknowledgement.	 */	if (TLS_LENGTH_INCLUDED(eaptls_packet->flags)) {		DEBUG2("  TLS Length %d",		       eaptls_packet->data[2] * 256 | eaptls_packet->data[3]);		if (TLS_MORE_FRAGMENTS(eaptls_packet->flags)) {			/*			 * FIRST_FRAGMENT is identified			 * 1. If there is no previous EAP-response received.			 * 2. If EAP-response received, then its M bit not set.			 * 	(It is because Last fragment will not have M bit set)			 */			if (!prev_eap_ds ||			    (prev_eap_ds->response == NULL) ||			    (eaptls_prev == NULL) ||			    !TLS_MORE_FRAGMENTS(eaptls_prev->flags)) {				RDEBUG2("Received EAP-TLS First Fragment of the message");				return EAPTLS_FIRST_FRAGMENT;			} else {				RDEBUG2("More Fragments with length included");				return EAPTLS_MORE_FRAGMENTS_WITH_LENGTH;			}		} else {			RDEBUG2("Length Included");			return EAPTLS_LENGTH_INCLUDED;		}	}	if (TLS_MORE_FRAGMENTS(eaptls_packet->flags)) {		RDEBUG2("More fragments to follow");		return EAPTLS_MORE_FRAGMENTS;	}	/*	 *	None of the flags are set, but it's still a valid	 *	EAPTLS packet.	 */	return EAPTLS_OK;}/* * EAPTLS_PACKET * code   =  EAP-code * id     =  EAP-id * length = code + id + length + flags + tlsdata

⌨️ 快捷键说明

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