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

📄 eap_tls_common.c

📁 IEEE 802.11a/b/g 服务器端AP
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions * 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 "eap_i.h"#include "eap_tls_common.h"#include "eap_config.h"#include "sha1.h"#include "tls.h"static int eap_tls_check_blob(struct eap_sm *sm, const char **name,			      const u8 **data, size_t *data_len){	const struct wpa_config_blob *blob;	if (*name == NULL || os_strncmp(*name, "blob://", 7) != 0)		return 0;	blob = eap_get_config_blob(sm, *name + 7);	if (blob == NULL) {		wpa_printf(MSG_ERROR, "%s: Named configuration blob '%s' not "			   "found", __func__, *name + 7);		return -1;	}	*name = NULL;	*data = blob->data;	*data_len = blob->len;	return 0;}static void eap_tls_params_from_conf1(struct tls_connection_params *params,				      struct eap_peer_config *config){	params->ca_cert = (char *) config->ca_cert;	params->ca_path = (char *) config->ca_path;	params->client_cert = (char *) config->client_cert;	params->private_key = (char *) config->private_key;	params->private_key_passwd = (char *) config->private_key_passwd;	params->dh_file = (char *) config->dh_file;	params->subject_match = (char *) config->subject_match;	params->altsubject_match = (char *) config->altsubject_match;	params->engine_id = config->engine_id;	params->pin = config->pin;	params->key_id = config->key_id;	params->cert_id = config->cert_id;	params->ca_cert_id = config->ca_cert_id;}static void eap_tls_params_from_conf2(struct tls_connection_params *params,				      struct eap_peer_config *config){	params->ca_cert = (char *) config->ca_cert2;	params->ca_path = (char *) config->ca_path2;	params->client_cert = (char *) config->client_cert2;	params->private_key = (char *) config->private_key2;	params->private_key_passwd = (char *) config->private_key2_passwd;	params->dh_file = (char *) config->dh_file2;	params->subject_match = (char *) config->subject_match2;	params->altsubject_match = (char *) config->altsubject_match2;	params->engine_id = config->engine_id;	params->pin = config->pin;	params->key_id = config->key2_id;	params->cert_id = config->cert2_id;	params->ca_cert_id = config->ca_cert2_id;}static int eap_tls_params_from_conf(struct eap_sm *sm,				    struct eap_ssl_data *data,				    struct tls_connection_params *params,				    struct eap_peer_config *config, int phase2){	os_memset(params, 0, sizeof(*params));	params->engine = config->engine;	if (phase2)		eap_tls_params_from_conf2(params, config);	else		eap_tls_params_from_conf1(params, config);	params->tls_ia = data->tls_ia;	/*	 * Use blob data, if available. Otherwise, leave reference to external	 * file as-is.	 */	if (eap_tls_check_blob(sm, &params->ca_cert, &params->ca_cert_blob,			       &params->ca_cert_blob_len) ||	    eap_tls_check_blob(sm, &params->client_cert,			       &params->client_cert_blob,			       &params->client_cert_blob_len) ||	    eap_tls_check_blob(sm, &params->private_key,			       &params->private_key_blob,			       &params->private_key_blob_len) ||	    eap_tls_check_blob(sm, &params->dh_file, &params->dh_blob,			       &params->dh_blob_len)) {		wpa_printf(MSG_INFO, "SSL: Failed to get configuration blobs");		return -1;	}	return 0;}static int eap_tls_init_connection(struct eap_sm *sm,				   struct eap_ssl_data *data,				   struct eap_peer_config *config,				   struct tls_connection_params *params){	int res;	data->conn = tls_connection_init(sm->ssl_ctx);	if (data->conn == NULL) {		wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "			   "connection");		return -1;	}	res = tls_connection_set_params(sm->ssl_ctx, data->conn, params);	if (res == TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED) {		/*		 * At this point with the pkcs11 engine the PIN might be wrong.		 * We reset the PIN in the configuration to be sure to not use		 * it again and the calling function must request a new one.		 */		os_free(config->pin);		config->pin = NULL;	} else if (res == TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED) {		wpa_printf(MSG_INFO, "TLS: Failed to load private key");		/*		 * We do not know exactly but maybe the PIN was wrong,		 * so ask for a new one.		 */		os_free(config->pin);		config->pin = NULL;		eap_sm_request_pin(sm);		sm->ignore = TRUE;		return -1;	} else if (res) {		wpa_printf(MSG_INFO, "TLS: Failed to set TLS connection "			   "parameters");		return -1;	}	return 0;}/** * eap_peer_tls_ssl_init - Initialize shared TLS functionality * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() * @data: Data for TLS processing * @config: Pointer to the network configuration * Returns: 0 on success, -1 on failure * * This function is used to initialize shared TLS functionality for EAP-TLS, * EAP-PEAP, EAP-TTLS, and EAP-FAST. */int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,			  struct eap_peer_config *config){	struct tls_connection_params params;	if (config == NULL)		return -1;	data->eap = sm;	data->phase2 = sm->init_phase2;	if (eap_tls_params_from_conf(sm, data, &params, config, data->phase2) <	    0)		return -1;	if (eap_tls_init_connection(sm, data, config, &params) < 0)		return -1;	data->tls_out_limit = config->fragment_size;	if (data->phase2) {		/* Limit the fragment size in the inner TLS authentication		 * since the outer authentication with EAP-PEAP does not yet		 * support fragmentation */		if (data->tls_out_limit > 100)			data->tls_out_limit -= 100;	}	if (config->phase1 &&	    os_strstr(config->phase1, "include_tls_length=1")) {		wpa_printf(MSG_DEBUG, "TLS: Include TLS Message Length in "			   "unfragmented packets");		data->include_tls_length = 1;	}	return 0;}/** * eap_peer_tls_ssl_deinit - Deinitialize shared TLS functionality * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() * @data: Data for TLS processing * * This function deinitializes shared TLS functionality that was initialized * with eap_peer_tls_ssl_init(). */void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data){	tls_connection_deinit(sm->ssl_ctx, data->conn);	eap_peer_tls_reset_input(data);	eap_peer_tls_reset_output(data);}/** * eap_peer_tls_derive_key - Derive a key based on TLS session data * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() * @data: Data for TLS processing * @label: Label string for deriving the keys, e.g., "client EAP encryption" * @len: Length of the key material to generate (usually 64 for MSK) * Returns: Pointer to allocated key on success or %NULL on failure * * This function uses TLS-PRF to generate pseudo-random data based on the TLS * session data (client/server random and master key). Each key type may use a * different label to bind the key usage into the generated material. * * The caller is responsible for freeing the returned buffer. */u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,			     const char *label, size_t len){	struct tls_keys keys;	u8 *rnd = NULL, *out;	out = os_malloc(len);	if (out == NULL)		return NULL;	/* First, try to use TLS library function for PRF, if available. */	if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, out, len) ==	    0)		return out;	/*	 * TLS library did not support key generation, so get the needed TLS	 * session parameters and use an internal implementation of TLS PRF to	 * derive the key.	 */	if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))		goto fail;	if (keys.client_random == NULL || keys.server_random == NULL ||	    keys.master_key == NULL)		goto fail;	rnd = os_malloc(keys.client_random_len + keys.server_random_len);	if (rnd == NULL)		goto fail;	os_memcpy(rnd, keys.client_random, keys.client_random_len);	os_memcpy(rnd + keys.client_random_len, keys.server_random,		  keys.server_random_len);	if (tls_prf(keys.master_key, keys.master_key_len,		    label, rnd, keys.client_random_len +		    keys.server_random_len, out, len))		goto fail;	os_free(rnd);	return out;fail:	os_free(out);	os_free(rnd);	return NULL;}/** * eap_peer_tls_reassemble_fragment - Reassemble a received fragment * @data: Data for TLS processing * @in_data: Next incoming TLS segment * @in_len: Length of in_data * Returns: 0 on success, 1 if more data is needed for the full message, or * -1 on error */static int eap_peer_tls_reassemble_fragment(struct eap_ssl_data *data,					    const u8 *in_data, size_t in_len){	u8 *buf;	if (data->tls_in_len + in_len == 0) {		/* No message data received?! */		wpa_printf(MSG_WARNING, "SSL: Invalid reassembly state: "			   "tls_in_left=%lu tls_in_len=%lu in_len=%lu",			   (unsigned long) data->tls_in_left,			   (unsigned long) data->tls_in_len,			   (unsigned long) in_len);		eap_peer_tls_reset_input(data);		return -1;	}	if (data->tls_in_len + in_len > 65536) {		/*		 * Limit length to avoid rogue servers from causing large		 * memory allocations.		 */		wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size over "			   "64 kB)");		eap_peer_tls_reset_input(data);		return -1;	}	if (in_len > data->tls_in_left) {		/* Sender is doing something odd - reject message */		wpa_printf(MSG_INFO, "SSL: more data than TLS message length "			   "indicated");		eap_peer_tls_reset_input(data);		return -1;	}	buf = os_realloc(data->tls_in, data->tls_in_len + in_len);	if (buf == NULL) {		wpa_printf(MSG_INFO, "SSL: Could not allocate memory for TLS "			   "data");		eap_peer_tls_reset_input(data);		return -1;	}	os_memcpy(buf + data->tls_in_len, in_data, in_len);	data->tls_in = buf;	data->tls_in_len += in_len;	data->tls_in_left -= in_len;	if (data->tls_in_left > 0) {		wpa_printf(MSG_DEBUG, "SSL: Need %lu bytes more input "			   "data", (unsigned long) data->tls_in_left);		return 1;	}	return 0;}/** * eap_peer_tls_data_reassemble - Reassemble TLS data * @data: Data for TLS processing * @in_data: Next incoming TLS segment * @in_len: Length of in_data * @out_len: Variable for returning length of the reassembled message * @need_more_input: Variable for returning whether more input data is needed * to reassemble this TLS packet * Returns: Pointer to output data, %NULL on error or when more data is needed * for the full message (in which case, *need_more_input is also set to 1). * * This function reassembles TLS fragments. Caller must not free the returned * data buffer since an internal pointer to it is maintained. */const u8 * eap_peer_tls_data_reassemble(	struct eap_ssl_data *data, const u8 *in_data, size_t in_len,	size_t *out_len, int *need_more_input){	*need_more_input = 0;	if (data->tls_in_left > in_len || data->tls_in) {		/* Message has fragments */		int res = eap_peer_tls_reassemble_fragment(data, in_data,							   in_len);		if (res) {			if (res == 1)				*need_more_input = 1;			return NULL;		}		/* Message is now fully reassembled. */	} else {		/* No fragments in this message, so just make a copy of it. */		data->tls_in_left = 0;		data->tls_in = os_malloc(in_len ? in_len : 1);		if (data->tls_in == NULL)			return NULL;		os_memcpy(data->tls_in, in_data, in_len);		data->tls_in_len = in_len;	}	*out_len = data->tls_in_len;	return data->tls_in;}/** * eap_tls_process_input - Process incoming TLS message * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() * @data: Data for TLS processing * @in_data: Message received from the server * @in_len: Length of in_data * @out_data: Buffer for returning a pointer to application data (if available) * Returns: 0 on success, 1 if more input data is needed, 2 if application data * is available, -1 on failure */static int eap_tls_process_input(struct eap_sm *sm, struct eap_ssl_data *data,				 const u8 *in_data, size_t in_len,				 struct wpabuf **out_data){	const u8 *msg;	size_t msg_len;	int need_more_input;	u8 *appl_data;	size_t appl_data_len;	msg = eap_peer_tls_data_reassemble(data, in_data, in_len,					   &msg_len, &need_more_input);	if (msg == NULL)		return need_more_input ? 1 : -1;	/* Full TLS message reassembled - continue handshake processing */	if (data->tls_out) {		/* This should not happen.. */		wpa_printf(MSG_INFO, "SSL: eap_tls_process_input - pending "			   "tls_out data even though tls_out_len = 0");		os_free(data->tls_out);		WPA_ASSERT(data->tls_out == NULL);	}	appl_data = NULL;	data->tls_out = tls_connection_handshake(sm->ssl_ctx, data->conn,						 msg, msg_len,						 &data->tls_out_len,						 &appl_data, &appl_data_len);	eap_peer_tls_reset_input(data);	if (appl_data &&	    tls_connection_established(sm->ssl_ctx, data->conn) &&	    !tls_connection_get_failed(sm->ssl_ctx, data->conn)) {		wpa_hexdump_key(MSG_MSGDUMP, "SSL: Application data",				appl_data, appl_data_len);		*out_data = wpabuf_alloc_ext_data(appl_data, appl_data_len);		if (*out_data == NULL) {			os_free(appl_data);			return -1;		}		return 2;	}	os_free(appl_data);	return 0;}/** * eap_tls_process_output - Process outgoing TLS message * @data: Data for TLS processing * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...) * @peap_version: Version number for EAP-PEAP/TTLS * @id: EAP identifier for the response * @ret: Return value to use on success * @out_data: Buffer for returning the allocated output buffer * Returns: ret (0 or 1) on success, -1 on failure */static int eap_tls_process_output(struct eap_ssl_data *data, EapType eap_type,				  int peap_version, u8 id, int ret,				  struct wpabuf **out_data){	size_t len;	u8 *flags;	int more_fragments, length_included;		len = data->tls_out_len - data->tls_out_pos;	wpa_printf(MSG_DEBUG, "SSL: %lu bytes left to be sent out (of total "		   "%lu bytes)",		   (unsigned long) len, (unsigned long) data->tls_out_len);	/*	 * Limit outgoing message to the configured maximum size. Fragment	 * message if needed.	 */	if (len > data->tls_out_limit) {		more_fragments = 1;		len = data->tls_out_limit;		wpa_printf(MSG_DEBUG, "SSL: sending %lu bytes, more fragments "			   "will follow", (unsigned long) len);	} else		more_fragments = 0;	length_included = data->tls_out_pos == 0 &&		(data->tls_out_len > data->tls_out_limit ||		 data->include_tls_length);	*out_data = eap_msg_alloc(EAP_VENDOR_IETF, eap_type,				  1 + length_included * 4 + len,				  EAP_CODE_RESPONSE, id);	if (*out_data == NULL)		return -1;	flags = wpabuf_put(*out_data, 1);	*flags = peap_version;	if (more_fragments)		*flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS;	if (length_included) {		*flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED;

⌨️ 快捷键说明

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