Blame lib/session.c

Packit 549fdc
/*
Packit 549fdc
 * Copyright (C) 2000-2016 Free Software Foundation, Inc.
Packit 549fdc
 * Copyright (C) 2017 Red Hat, Inc.
Packit 549fdc
 *
Packit 549fdc
 * Author: Nikos Mavrogiannopoulos
Packit 549fdc
 *
Packit 549fdc
 * This file is part of GnuTLS.
Packit 549fdc
 *
Packit 549fdc
 * The GnuTLS is free software; you can redistribute it and/or
Packit 549fdc
 * modify it under the terms of the GNU Lesser General Public License
Packit 549fdc
 * as published by the Free Software Foundation; either version 2.1 of
Packit 549fdc
 * the License, or (at your option) any later version.
Packit 549fdc
 *
Packit 549fdc
 * This library is distributed in the hope that it will be useful, but
Packit 549fdc
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 549fdc
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 549fdc
 * Lesser General Public License for more details.
Packit 549fdc
 *
Packit 549fdc
 * You should have received a copy of the GNU Lesser General Public License
Packit 549fdc
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
Packit 549fdc
 *
Packit 549fdc
 */
Packit 549fdc
#include "gnutls_int.h"
Packit 549fdc
#include "errors.h"
Packit 549fdc
#include "debug.h"
Packit 549fdc
#include <session_pack.h>
Packit 549fdc
#include <datum.h>
Packit 549fdc
#include "state.h"
Packit 549fdc
Packit 549fdc
/**
Packit 549fdc
 * gnutls_session_get_data:
Packit 549fdc
 * @session: is a #gnutls_session_t type.
Packit 549fdc
 * @session_data: is a pointer to space to hold the session.
Packit 549fdc
 * @session_data_size: is the session_data's size, or it will be set by the function.
Packit 549fdc
 *
Packit 549fdc
 * Returns all session parameters needed to be stored to support resumption.
Packit 549fdc
 * The client should call this, and store the returned session data. A session
Packit 549fdc
 * may be resumed later by calling gnutls_session_set_data().  
Packit 549fdc
 *
Packit 549fdc
 * This function will fail if called prior to handshake completion. In
Packit 549fdc
 * case of false start TLS, the handshake completes only after data have
Packit 549fdc
 * been successfully received from the peer.
Packit 549fdc
 *
Packit 549fdc
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
Packit 549fdc
 *   an error code is returned.
Packit 549fdc
 **/
Packit 549fdc
int
Packit 549fdc
gnutls_session_get_data(gnutls_session_t session,
Packit 549fdc
			void *session_data, size_t * session_data_size)
Packit 549fdc
{
Packit 549fdc
Packit 549fdc
	gnutls_datum_t psession;
Packit 549fdc
	int ret;
Packit 549fdc
Packit 549fdc
	ret = gnutls_session_get_data2(session, &psession);
Packit 549fdc
	if (ret < 0) {
Packit 549fdc
		gnutls_assert();
Packit 549fdc
		return ret;
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	if (psession.size > *session_data_size) {
Packit 549fdc
		*session_data_size = psession.size;
Packit 549fdc
		ret = GNUTLS_E_SHORT_MEMORY_BUFFER;
Packit 549fdc
		goto error;
Packit 549fdc
	}
Packit 549fdc
	*session_data_size = psession.size;
Packit 549fdc
Packit 549fdc
	if (session_data != NULL)
Packit 549fdc
		memcpy(session_data, psession.data, psession.size);
Packit 549fdc
Packit 549fdc
	ret = 0;
Packit 549fdc
Packit 549fdc
      error:
Packit 549fdc
	_gnutls_free_datum(&psession);
Packit 549fdc
	return ret;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
/**
Packit 549fdc
 * gnutls_session_get_data2:
Packit 549fdc
 * @session: is a #gnutls_session_t type.
Packit 549fdc
 * @data: is a pointer to a datum that will hold the session.
Packit 549fdc
 *
Packit 549fdc
 * Returns all session parameters needed to be stored to support resumption.
Packit 549fdc
 * The client should call this, and store the returned session data. A session
Packit 549fdc
 * may be resumed later by calling gnutls_session_set_data().  
Packit 549fdc
 *
Packit 549fdc
 * The returned @data are allocated and must be released using gnutls_free().
Packit 549fdc
 *
Packit 549fdc
 * This function will fail if called prior to handshake completion. In
Packit 549fdc
 * case of false start TLS, the handshake completes only after data have
Packit 549fdc
 * been successfully received from the peer.
Packit 549fdc
 *
Packit 549fdc
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
Packit 549fdc
 *   an error code is returned.
Packit 549fdc
 **/
Packit 549fdc
int
Packit 549fdc
gnutls_session_get_data2(gnutls_session_t session, gnutls_datum_t *data)
Packit 549fdc
{
Packit 549fdc
Packit 549fdc
	int ret;
Packit 549fdc
Packit 549fdc
	if (data == NULL) {
Packit 549fdc
		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	if (gnutls_session_is_resumed(session) && session->internals.resumption_data.data) {
Packit 549fdc
		ret = _gnutls_set_datum(data, session->internals.resumption_data.data, session->internals.resumption_data.size);
Packit 549fdc
		if (ret < 0)
Packit 549fdc
			return gnutls_assert_val(ret);
Packit 549fdc
Packit 549fdc
		return 0;
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	if (session->internals.resumable == RESUME_FALSE)
Packit 549fdc
		return GNUTLS_E_INVALID_SESSION;
Packit 549fdc
Packit 549fdc
	ret = _gnutls_session_pack(session, data);
Packit 549fdc
	if (ret < 0) {
Packit 549fdc
		gnutls_assert();
Packit 549fdc
		return ret;
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	return 0;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
Packit 549fdc
/**
Packit 549fdc
 * gnutls_session_get_id:
Packit 549fdc
 * @session: is a #gnutls_session_t type.
Packit 549fdc
 * @session_id: is a pointer to space to hold the session id.
Packit 549fdc
 * @session_id_size: initially should contain the maximum @session_id size and will be updated.
Packit 549fdc
 *
Packit 549fdc
 * Returns the current session ID. This can be used if you want to
Packit 549fdc
 * check if the next session you tried to resume was actually
Packit 549fdc
 * resumed.  That is because resumed sessions share the same session ID
Packit 549fdc
 * with the original session.
Packit 549fdc
 *
Packit 549fdc
 * The session ID is selected by the server, that identify the
Packit 549fdc
 * current session.  In all supported TLS protocols, the session id
Packit 549fdc
 * is less than %GNUTLS_MAX_SESSION_ID_SIZE.
Packit 549fdc
 *
Packit 549fdc
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
Packit 549fdc
 *   an error code is returned.
Packit 549fdc
 **/
Packit 549fdc
int
Packit 549fdc
gnutls_session_get_id(gnutls_session_t session,
Packit 549fdc
		      void *session_id, size_t * session_id_size)
Packit 549fdc
{
Packit 549fdc
	size_t given_session_id_size = *session_id_size;
Packit 549fdc
Packit 549fdc
	*session_id_size = session->security_parameters.session_id_size;
Packit 549fdc
Packit 549fdc
	/* just return the session size */
Packit 549fdc
	if (session_id == NULL) {
Packit 549fdc
		return 0;
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	if (given_session_id_size <
Packit 549fdc
	    session->security_parameters.session_id_size) {
Packit 549fdc
		return GNUTLS_E_SHORT_MEMORY_BUFFER;
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	memcpy(session_id, &session->security_parameters.session_id,
Packit 549fdc
	       *session_id_size);
Packit 549fdc
Packit 549fdc
	return 0;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
/**
Packit 549fdc
 * gnutls_session_get_id2:
Packit 549fdc
 * @session: is a #gnutls_session_t type.
Packit 549fdc
 * @session_id: will point to the session ID.
Packit 549fdc
 *
Packit 549fdc
 * Returns the current session ID. The returned data should be
Packit 549fdc
 * treated as constant.
Packit 549fdc
 *
Packit 549fdc
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
Packit 549fdc
 *   an error code is returned.
Packit 549fdc
 *
Packit 549fdc
 * Since: 3.1.4
Packit 549fdc
 **/
Packit 549fdc
int
Packit 549fdc
gnutls_session_get_id2(gnutls_session_t session,
Packit 549fdc
		       gnutls_datum_t * session_id)
Packit 549fdc
{
Packit 549fdc
	session_id->size = session->security_parameters.session_id_size;
Packit 549fdc
	session_id->data = session->security_parameters.session_id;
Packit 549fdc
Packit 549fdc
	return 0;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
/**
Packit 549fdc
 * gnutls_session_set_data:
Packit 549fdc
 * @session: is a #gnutls_session_t type.
Packit 549fdc
 * @session_data: is a pointer to space to hold the session.
Packit 549fdc
 * @session_data_size: is the session's size
Packit 549fdc
 *
Packit 549fdc
 * Sets all session parameters, in order to resume a previously
Packit 549fdc
 * established session.  The session data given must be the one
Packit 549fdc
 * returned by gnutls_session_get_data().  This function should be
Packit 549fdc
 * called before gnutls_handshake().
Packit 549fdc
 *
Packit 549fdc
 * Keep in mind that session resuming is advisory. The server may
Packit 549fdc
 * choose not to resume the session, thus a full handshake will be
Packit 549fdc
 * performed.
Packit 549fdc
 *
Packit 549fdc
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
Packit 549fdc
 *   an error code is returned.
Packit 549fdc
 **/
Packit 549fdc
int
Packit 549fdc
gnutls_session_set_data(gnutls_session_t session,
Packit 549fdc
			const void *session_data, size_t session_data_size)
Packit 549fdc
{
Packit 549fdc
	int ret;
Packit 549fdc
	gnutls_datum_t psession;
Packit 549fdc
Packit 549fdc
	psession.data = (uint8_t *) session_data;
Packit 549fdc
	psession.size = session_data_size;
Packit 549fdc
Packit 549fdc
	if (session_data == NULL || session_data_size == 0) {
Packit 549fdc
		gnutls_assert();
Packit 549fdc
		return GNUTLS_E_INVALID_REQUEST;
Packit 549fdc
	}
Packit 549fdc
	ret = _gnutls_session_unpack(session, &psession);
Packit 549fdc
	if (ret < 0) {
Packit 549fdc
		gnutls_assert();
Packit 549fdc
		return ret;
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	session->internals.resumption_requested = 1;
Packit 549fdc
Packit 549fdc
	if (session->internals.resumption_data.data != NULL)
Packit 549fdc
		gnutls_free(session->internals.resumption_data.data);
Packit 549fdc
	_gnutls_set_datum(&session->internals.resumption_data, session_data, session_data_size);
Packit 549fdc
Packit 549fdc
	return 0;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
/**
Packit 549fdc
 * gnutls_session_force_valid:
Packit 549fdc
 * @session: is a #gnutls_session_t type.
Packit 549fdc
 *
Packit 549fdc
 * Clears the invalid flag in a session. That means
Packit 549fdc
 * that sessions were corrupt or invalid data were received 
Packit 549fdc
 * can be re-used. Use only when debugging or experimenting
Packit 549fdc
 * with the TLS protocol. Should not be used in typical
Packit 549fdc
 * applications.
Packit 549fdc
 *
Packit 549fdc
 **/
Packit 549fdc
void gnutls_session_force_valid(gnutls_session_t session)
Packit 549fdc
{
Packit 549fdc
	session->internals.invalid_connection = 0;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
#define DESC_SIZE 64
Packit 549fdc
Packit 549fdc
/**
Packit 549fdc
 * gnutls_session_get_desc:
Packit 549fdc
 * @session: is a gnutls session
Packit 549fdc
 *
Packit 549fdc
 * This function returns a string describing the current session.
Packit 549fdc
 * The string is null terminated and allocated using gnutls_malloc().
Packit 549fdc
 *
Packit 549fdc
 * If initial negotiation is not complete when this function is called,
Packit 549fdc
 * %NULL will be returned.
Packit 549fdc
 *
Packit 549fdc
 * Returns: a description of the protocols and algorithms in the current session.
Packit 549fdc
 *
Packit 549fdc
 * Since: 3.1.10
Packit 549fdc
 **/
Packit 549fdc
char *gnutls_session_get_desc(gnutls_session_t session)
Packit 549fdc
{
Packit 549fdc
	gnutls_kx_algorithm_t kx;
Packit 549fdc
	const char *kx_str, *sign_str;
Packit 549fdc
	unsigned type;
Packit 549fdc
	char kx_name[64];
Packit 549fdc
	char proto_name[32];
Packit 549fdc
	char _group_name[24];
Packit 549fdc
	const char *group_name = NULL;
Packit 549fdc
	unsigned dh_bits = 0;
Packit 549fdc
	unsigned mac_id;
Packit 549fdc
	unsigned sign_algo;
Packit 549fdc
	char *desc;
Packit 549fdc
	const struct gnutls_group_entry_st *group = get_group(session);
Packit 549fdc
Packit 549fdc
	if (session->internals.initial_negotiation_completed == 0)
Packit 549fdc
		return NULL;
Packit 549fdc
Packit 549fdc
	kx = session->security_parameters.cs->kx_algorithm;
Packit 549fdc
	if (group)
Packit 549fdc
		group_name = group->name;
Packit 549fdc
#if defined(ENABLE_DHE) || defined(ENABLE_ANON)
Packit 549fdc
	if (group_name == NULL && _gnutls_kx_is_dhe(kx)) {
Packit 549fdc
		dh_bits = gnutls_dh_get_prime_bits(session);
Packit 549fdc
		snprintf(_group_name, sizeof(_group_name), "CUSTOM%u", dh_bits);
Packit 549fdc
		group_name = _group_name;
Packit 549fdc
	}
Packit 549fdc
#endif
Packit 549fdc
Packit 549fdc
	/* Key exchange    - Signature algorithm */
Packit 549fdc
	/* DHE-3072        - RSA-PSS-2048        */
Packit 549fdc
	/* ECDHE-SECP256R1 - ECDSA-SECP256R1     */
Packit 549fdc
Packit 549fdc
	sign_algo = gnutls_sign_algorithm_get(session);
Packit 549fdc
	sign_str = gnutls_sign_get_name(sign_algo);
Packit 549fdc
Packit 549fdc
	kx_str = gnutls_kx_get_name(kx);
Packit 549fdc
	if (kx_str) {
Packit 549fdc
		if (kx == GNUTLS_KX_ECDHE_ECDSA || kx == GNUTLS_KX_ECDHE_RSA || 
Packit 549fdc
		    kx == GNUTLS_KX_ECDHE_PSK) {
Packit 549fdc
			if (sign_str)
Packit 549fdc
				snprintf(kx_name, sizeof(kx_name), "(ECDHE-%s)-(%s)",
Packit 549fdc
					 group_name, sign_str);
Packit 549fdc
			else
Packit 549fdc
				snprintf(kx_name, sizeof(kx_name), "(ECDHE-%s)",
Packit 549fdc
					 group_name);
Packit 549fdc
		} else if (kx == GNUTLS_KX_DHE_DSS || kx == GNUTLS_KX_DHE_RSA || 
Packit 549fdc
		    kx == GNUTLS_KX_DHE_PSK) {
Packit 549fdc
			if (sign_str)
Packit 549fdc
				snprintf(kx_name, sizeof(kx_name), "(DHE-%s)-(%s)", group_name, sign_str);
Packit 549fdc
			else
Packit 549fdc
				snprintf(kx_name, sizeof(kx_name), "(DHE-%s)", group_name);
Packit 549fdc
		} else if (kx == GNUTLS_KX_RSA) {
Packit 549fdc
			/* Possible enhancement: include the certificate bits */
Packit 549fdc
			snprintf(kx_name, sizeof(kx_name), "(RSA)");
Packit 549fdc
		} else {
Packit 549fdc
			snprintf(kx_name, sizeof(kx_name), "(%s)",
Packit 549fdc
				 kx_str);
Packit 549fdc
		}
Packit 549fdc
	} else {
Packit 549fdc
		strcpy(kx_name, "(NULL)");
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
Packit 549fdc
	type = gnutls_certificate_type_get(session);
Packit 549fdc
	if (type == GNUTLS_CRT_X509)
Packit 549fdc
		snprintf(proto_name, sizeof(proto_name), "%s",
Packit 549fdc
			 gnutls_protocol_get_name(get_num_version
Packit 549fdc
						  (session)));
Packit 549fdc
	else
Packit 549fdc
		snprintf(proto_name, sizeof(proto_name), "%s-%s",
Packit 549fdc
			 gnutls_protocol_get_name(get_num_version
Packit 549fdc
						  (session)),
Packit 549fdc
			 gnutls_certificate_type_get_name(type));
Packit 549fdc
Packit 549fdc
	desc = gnutls_malloc(DESC_SIZE);
Packit 549fdc
	if (desc == NULL)
Packit 549fdc
		return NULL;
Packit 549fdc
Packit 549fdc
	mac_id = gnutls_mac_get(session);
Packit 549fdc
	if (mac_id == GNUTLS_MAC_AEAD) { /* no need to print */
Packit 549fdc
		snprintf(desc, DESC_SIZE,
Packit 549fdc
			 "(%s)-%s-(%s)",
Packit 549fdc
			 proto_name,
Packit 549fdc
			 kx_name,
Packit 549fdc
			 gnutls_cipher_get_name(gnutls_cipher_get(session)));
Packit 549fdc
	} else {
Packit 549fdc
		snprintf(desc, DESC_SIZE,
Packit 549fdc
			 "(%s)-%s-(%s)-(%s)",
Packit 549fdc
			 proto_name,
Packit 549fdc
			 kx_name,
Packit 549fdc
			 gnutls_cipher_get_name(gnutls_cipher_get(session)),
Packit 549fdc
			 gnutls_mac_get_name(mac_id));
Packit 549fdc
	}
Packit 549fdc
Packit 549fdc
	return desc;
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
/**
Packit 549fdc
 * gnutls_session_set_id:
Packit 549fdc
 * @session: is a #gnutls_session_t type.
Packit 549fdc
 * @sid: the session identifier
Packit 549fdc
 *
Packit 549fdc
 * This function sets the session ID to be used in a client hello.
Packit 549fdc
 * This is a function intended for exceptional uses. Do not use this
Packit 549fdc
 * function unless you are implementing a custom protocol.
Packit 549fdc
 *
Packit 549fdc
 * To set session resumption parameters use gnutls_session_set_data() instead.
Packit 549fdc
 *
Packit 549fdc
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
Packit 549fdc
 *   an error code is returned.
Packit 549fdc
 *
Packit 549fdc
 * Since: 3.2.1
Packit 549fdc
 **/
Packit 549fdc
int
Packit 549fdc
gnutls_session_set_id(gnutls_session_t session, const gnutls_datum_t * sid)
Packit 549fdc
{
Packit 549fdc
	if (session->security_parameters.entity == GNUTLS_SERVER ||
Packit 549fdc
	    sid->size > GNUTLS_MAX_SESSION_ID_SIZE)
Packit 549fdc
		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
Packit 549fdc
Packit 549fdc
	memset(&session->internals.resumed_security_parameters, 0,
Packit 549fdc
	       sizeof(session->internals.resumed_security_parameters));
Packit 549fdc
Packit 549fdc
	session->internals.resumed_security_parameters.session_id_size =
Packit 549fdc
	    sid->size;
Packit 549fdc
	memcpy(session->internals.resumed_security_parameters.session_id,
Packit 549fdc
	       sid->data, sid->size);
Packit 549fdc
Packit 549fdc
	return 0;
Packit 549fdc
}