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

📄 rlm_eap_tls.c

📁 freeradius-server-2.1.3.tar.gz安装源文件
💻 C
📖 第 1 页 / 共 2 页
字号:
	 */	verify_mode |= SSL_VERIFY_PEER;	verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;	verify_mode |= SSL_VERIFY_CLIENT_ONCE;	SSL_CTX_set_verify(ctx, verify_mode, cbtls_verify);	if (conf->verify_depth) {		SSL_CTX_set_verify_depth(ctx, conf->verify_depth);	}	/* Load randomness */	if (!(RAND_load_file(conf->random_file, 1024*1024))) {		radlog(L_ERR, "rlm_eap: SSL error %s", ERR_error_string(ERR_get_error(), NULL));		radlog(L_ERR, "rlm_eap_tls: Error loading randomness");		return NULL;	}	/*	 * Set the cipher list if we were told to	 */	if (conf->cipher_list) {		if (!SSL_CTX_set_cipher_list(ctx, conf->cipher_list)) {			radlog(L_ERR, "rlm_eap_tls: Error setting cipher list");			return NULL;		}	}	/*	 *	Setup session caching	 */	if (conf->session_cache_enable) {		/*		 *	Create a unique context Id per EAP-TLS configuration.		 */		if (conf->session_id_name) {			snprintf(conf->session_context_id,				 sizeof(conf->session_context_id),				 "FreeRADIUS EAP-TLS %s",				 conf->session_id_name);		} else {			snprintf(conf->session_context_id,				 sizeof(conf->session_context_id),				 "FreeRADIUS EAP-TLS %p", conf);		}		/*		 *	Cache it, and DON'T auto-clear it.		 */		SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER | SSL_SESS_CACHE_NO_AUTO_CLEAR);					       		SSL_CTX_set_session_id_context(ctx,					       (unsigned char *) conf->session_context_id,					       (unsigned int) strlen(conf->session_context_id));		/*		 *	Our timeout is in hours, this is in seconds.		 */		SSL_CTX_set_timeout(ctx, conf->session_timeout * 3600);				/*		 *	Set the maximum number of entries in the		 *	session cache.		 */		SSL_CTX_sess_set_cache_size(ctx, conf->session_cache_size);	} else {		SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);	}	/*	 *	Register the application indices.  We can't use	 *	hard-coded "0" and "1" as before, because we need to	 *	set up a "free" handler for the cached session	 *	information.	 */	if (eaptls_handle_idx < 0) {		eaptls_handle_idx = SSL_get_ex_new_index(0, "eaptls_handle_idx",							  NULL, NULL, NULL);	}		if (eaptls_conf_idx < 0) {		eaptls_conf_idx = SSL_get_ex_new_index(0, "eaptls_conf_idx",							  NULL, NULL, NULL);	}	if (eaptls_session_idx < 0) {		eaptls_session_idx = SSL_get_ex_new_index(0, "eaptls_session_idx",							  NULL, NULL,							  eaptls_session_free);	}	return ctx;}/* *	Detach the EAP-TLS module. */static int eaptls_detach(void *arg){	EAP_TLS_CONF	 *conf;	eap_tls_t 	 *inst;	inst = (eap_tls_t *) arg;	conf = inst->conf;	if (conf) {		memset(conf, 0, sizeof(*conf));		free(inst->conf);		inst->conf = NULL;	}	if (inst->ctx) SSL_CTX_free(inst->ctx);	inst->ctx = NULL;	free(inst);	return 0;}/* *	Attach the EAP-TLS module. */static int eaptls_attach(CONF_SECTION *cs, void **instance){	EAP_TLS_CONF	 *conf;	eap_tls_t 	 *inst;	/* Store all these values in the data structure for later references */	inst = (eap_tls_t *)malloc(sizeof(*inst));	if (!inst) {		radlog(L_ERR, "rlm_eap_tls: out of memory");		return -1;	}	memset(inst, 0, sizeof(*inst));	/*	 *	Parse the config file & get all the configured values	 */	conf = (EAP_TLS_CONF *)malloc(sizeof(*conf));	if (conf == NULL) {		free(inst);		radlog(L_ERR, "rlm_eap_tls: out of memory");		return -1;	}	memset(conf, 0, sizeof(*conf));	inst->conf = conf;	if (cf_section_parse(cs, conf, module_config) < 0) {		eaptls_detach(inst);		return -1;	}	/*	 *	The EAP RFC's say 1020, but we're less picky.	 */	if (conf->fragment_size < 100) {		radlog(L_ERR, "rlm_eap_tls: Fragment size is too small.");		eaptls_detach(inst);		return -1;	}	/*	 *	The maximum size for a RADIUS packet is 4096,	 *	minus the header (20), Message-Authenticator (18),	 *	and State (18), etc. results in about 4000 bytes of data	 *	that can be devoted *solely* to EAP.	 */	if (conf->fragment_size > 4000) {		radlog(L_ERR, "rlm_eap_tls: Fragment size is too large.");		eaptls_detach(inst);		return -1;	}	/*	 *	Account for the EAP header (4), and the EAP-TLS header	 *	(6), as per Section 4.2 of RFC 2716.  What's left is	 *	the maximum amount of data we read from a TLS buffer.	 */	conf->fragment_size -= 10;	/*	 *	This magic makes the administrators life HUGELY easier	 *	on initial deployments.	 *	 *	If the server starts up in debugging mode, AND the	 *	bootstrap command is configured, AND it exists, AND	 *	there is no server certificate	 */	if (conf->make_cert_command && (debug_flag >= 2)) {		struct stat buf;		if ((stat(conf->make_cert_command, &buf) == 0) &&		    (stat(conf->certificate_file, &buf) < 0) &&		    (errno == ENOENT) &&		    (radius_exec_program(conf->make_cert_command, NULL, 1,					 NULL, 0, NULL, NULL, 0) != 0)) {			eaptls_detach(inst);			return -1;		}	}	/*	 *	Initialize TLS	 */	inst->ctx = init_tls_ctx(conf);	if (inst->ctx == NULL) {		eaptls_detach(inst);		return -1;	}	if (load_dh_params(inst->ctx, conf->dh_file) < 0) {		eaptls_detach(inst);		return -1;	}        if (generate_eph_rsa_key(inst->ctx) < 0) {                return -1;        }	*instance = inst;	return 0;}/* *	Send an initial eap-tls request to the peer. * *	Frame eap reply packet. *	len = header + type + tls_typedata *	tls_typedata = flags(Start (S) bit set, and no data) * *	Once having received the peer's Identity, the EAP server MUST *	respond with an EAP-TLS/Start packet, which is an *	EAP-Request packet with EAP-Type=EAP-TLS, the Start (S) bit *	set, and no data.  The EAP-TLS conversation will then begin, *	with the peer sending an EAP-Response packet with *	EAP-Type = EAP-TLS.  The data field of that packet will *	be the TLS data. * *	Fragment length is Framed-MTU - 4. * *	http://mail.frascone.com/pipermail/public/eap/2003-July/001426.html */static int eaptls_initiate(void *type_arg, EAP_HANDLER *handler){	int		status;	tls_session_t	*ssn;	eap_tls_t	*inst;	VALUE_PAIR	*vp;	int		client_cert = TRUE;	int		verify_mode = 0;	REQUEST		*request = handler->request;	inst = (eap_tls_t *)type_arg;	/*	 *	Manually flush the sessions every so often.  If HALF	 *	of the session lifetime has passed since we last	 *	flushed, then flush it again.	 *	 *	FIXME: Also do it every N sessions?	 */	if (inst->conf->session_cache_enable &&	    ((inst->conf->session_last_flushed + (inst->conf->session_timeout * 1800)) <= request->timestamp)) {		RDEBUG2("Flushing SSL sessions (of #%ld)",			SSL_CTX_sess_number(inst->ctx));		SSL_CTX_flush_sessions(inst->ctx, request->timestamp);		inst->conf->session_last_flushed = request->timestamp;	}	/*	 *	If we're TTLS or PEAP, then do NOT require a client	 *	certificate.	 *	 *	FIXME: This should be more configurable.	 */	if (handler->eap_type != PW_EAP_TLS) {		vp = pairfind(handler->request->config_items,			      PW_EAP_TLS_REQUIRE_CLIENT_CERT);		if (!vp) {			client_cert = FALSE;		} else {			client_cert = vp->vp_integer;		}	}	/*	 *	Every new session is started only from EAP-TLS-START.	 *	Before Sending EAP-TLS-START, open a new SSL session.	 *	Create all the required data structures & store them	 *	in Opaque.  So that we can use these data structures	 *	when we get the response	 */	ssn = eaptls_new_session(inst->ctx, client_cert);	if (!ssn) {		return 0;	}	/*	 *	Verify the peer certificate, if asked.	 */	if (client_cert) {		RDEBUG2("Requiring client certificate");		verify_mode = SSL_VERIFY_PEER;		verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;		verify_mode |= SSL_VERIFY_CLIENT_ONCE;	}	SSL_set_verify(ssn->ssl, verify_mode, cbtls_verify);	/*	 *	Create a structure for all the items required to be	 *	verified for each client and set that as opaque data	 *	structure.	 *	 *	NOTE: If we want to set each item sepearately then	 *	this index should be global.	 */	SSL_set_ex_data(ssn->ssl, 0, (void *)handler);	SSL_set_ex_data(ssn->ssl, 1, (void *)inst->conf);	ssn->length_flag = inst->conf->include_length;	/*	 *	We use default fragment size, unless the Framed-MTU	 *	tells us it's too big.  Note that we do NOT account	 *	for the EAP-TLS headers if conf->fragment_size is	 *	large, because that config item looks to be confusing.	 *	 *	i.e. it should REALLY be called MTU, and the code here	 *	should figure out what that means for TLS fragment size.	 *	asking the administrator to know the internal details	 *	of EAP-TLS in order to calculate fragment sizes is	 *	just too much.	 */	ssn->offset = inst->conf->fragment_size;	vp = pairfind(handler->request->packet->vps, PW_FRAMED_MTU);	if (vp && ((vp->vp_integer - 14) < ssn->offset)) {		/*		 *	Discount the Framed-MTU by:		 *	 4 : EAPOL header		 *	 4 : EAP header (code + id + length)		 *	 1 : EAP type == EAP-TLS		 *	 1 : EAP-TLS Flags		 *	 4 : EAP-TLS Message length		 *	    (even if conf->include_length == 0,		 *	     just to be lazy).		 *	---		 *	14		 */		ssn->offset = vp->vp_integer - 14;	}	handler->opaque = ((void *)ssn);	handler->free_opaque = session_free;	RDEBUG2("Initiate");	/*	 *	Set up type-specific information.	 */	switch (handler->eap_type) {	case PW_EAP_TLS:	default:		ssn->prf_label = "client EAP encryption";		break;	case PW_EAP_TTLS:		ssn->prf_label = "ttls keying material";		break;		/*		 *	PEAP-specific breakage.		 */	case PW_EAP_PEAP:		/*		 *	As it is a poorly designed protocol, PEAP uses		 *	bits in the TLS header to indicate PEAP		 *	version numbers.  For now, we only support		 *	PEAP version 0, so it doesn't matter too much.		 *	However, if we support later versions of PEAP,		 *	we will need this flag to indicate which		 *	version we're currently dealing with.		 */		ssn->peap_flag = 0x00;		/*		 *	PEAP version 0 requires 'include_length = no',		 *	so rather than hoping the user figures it out,		 *	we force it here.		 */		ssn->length_flag = 0;		ssn->prf_label = "client EAP encryption";		break;	}	if (inst->conf->session_cache_enable) {		ssn->allow_session_resumption = 1; /* otherwise it's zero */	}	/*	 *	TLS session initialization is over.  Now handle TLS	 *	related handshaking or application data.	 */	status = eaptls_start(handler->eap_ds, ssn->peap_flag);	RDEBUG2("Start returned %d", status);	if (status == 0)		return 0;	/*	 *	The next stage to process the packet.	 */	handler->stage = AUTHENTICATE;	return 1;}/* *	Do authentication, by letting EAP-TLS do most of the work. */static int eaptls_authenticate(void *arg, EAP_HANDLER *handler){	eaptls_status_t	status;	tls_session_t *tls_session = (tls_session_t *) handler->opaque;	REQUEST *request = handler->request;	eap_tls_t *inst = (eap_tls_t *) arg;	RDEBUG2("Authenticate");	status = eaptls_process(handler);	RDEBUG2("eaptls_process returned %d\n", status);	switch (status) {		/*		 *	EAP-TLS handshake was successful, return an		 *	EAP-TLS-Success packet here.		 */	case EAPTLS_SUCCESS:		break;		/*		 *	The TLS code is still working on the TLS		 *	exchange, and it's a valid TLS request.		 *	do nothing.		 */	case EAPTLS_HANDLED:		return 1;		/*		 *	Handshake is done, proceed with decoding tunneled		 *	data.		 */	case EAPTLS_OK:		RDEBUG2("Received unexpected tunneled data after successful handshake.");#ifndef NDEBUG		if ((debug_flag > 2) && fr_log_fp) {			unsigned int i;			unsigned int data_len;			unsigned char buffer[1024];			data_len = (tls_session->record_minus)(&tls_session->dirty_in,						buffer, sizeof(buffer));			log_debug("  Tunneled data (%u bytes)\n", data_len);			for (i = 0; i < data_len; i++) {				if ((i & 0x0f) == 0x00) fprintf(fr_log_fp, "  %x: ", i);				if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");				fprintf(fr_log_fp, "%02x ", buffer[i]);			}			fprintf(fr_log_fp, "\n");		}#endif		eaptls_fail(handler, 0);		return 0;		break;		/*		 *	Anything else: fail.		 *		 *	Also, remove the session from the cache so that		 *	the client can't re-use it.		 */	default:		if (inst->conf->session_cache_enable) {				SSL_CTX_remove_session(inst->ctx,					       tls_session->ssl->session);		}		return 0;	}	/*	 *	New sessions cause some additional information to be	 *	cached.	 */	if (!SSL_session_reused(tls_session->ssl)) {		/*		 *	FIXME: Store miscellaneous data.		 */		RDEBUG2("Adding user data to cached session");		#if 0		SSL_SESSION_set_ex_data(tls_session->ssl->session,					ssl_session_idx_user_session, session_data);#endif	} else {		/*		 *	FIXME: Retrieve miscellaneous data.		 */#if 0		data = SSL_SESSION_get_ex_data(tls_session->ssl->session,					       ssl_session_idx_user_session);		if (!session_data) {			radlog_request(L_ERR, 0, request,				       "No user session data in cached session - "				       " REJECTING");			return 0;		}#endif		RDEBUG2("Retrieved session data from cached session");	}	/*	 *	Success: Automatically return MPPE keys.	 */	return eaptls_success(handler, 0);}/* *	The module name should be the only globally exported symbol. *	That is, everything else should be 'static'. */EAP_TYPE rlm_eap_tls = {	"eap_tls",	eaptls_attach,			/* attach */	eaptls_initiate,		/* Start the initial request */	NULL,				/* authorization */	eaptls_authenticate,		/* authentication */	eaptls_detach			/* detach */};

⌨️ 快捷键说明

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