Blame lib/supplemental.c

Packit Service 4684c1
/*
Packit Service 4684c1
 * Copyright (C) 2007-2012 Free Software Foundation, Inc.
Packit Service 4684c1
 *
Packit Service 4684c1
 * Author: Simon Josefsson
Packit Service 4684c1
 *
Packit Service 4684c1
 * This file is part of GnuTLS.
Packit Service 4684c1
 *
Packit Service 4684c1
 * The GnuTLS is free software; you can redistribute it and/or
Packit Service 4684c1
 * modify it under the terms of the GNU Lesser General Public License
Packit Service 4684c1
 * as published by the Free Software Foundation; either version 2.1 of
Packit Service 4684c1
 * the License, or (at your option) any later version.
Packit Service 4684c1
 *
Packit Service 4684c1
 * This library is distributed in the hope that it will be useful, but
Packit Service 4684c1
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 4684c1
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 4684c1
 * Lesser General Public License for more details.
Packit Service 4684c1
 *
Packit Service 4684c1
 * You should have received a copy of the GNU Lesser General Public License
Packit Service 4684c1
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
Packit Service 4684c1
 *
Packit Service 4684c1
 */
Packit Service 4684c1
Packit Service 4684c1
/* This file contains support functions for 'TLS Handshake Message for
Packit Service 4684c1
 * Supplemental Data' (RFC 4680).
Packit Service 4684c1
 *
Packit Service 4684c1
 * The idea here is simple.  gnutls_handshake() in gnuts_handshake.c
Packit Service 4684c1
 * will call _gnutls_gen_supplemental and _gnutls_parse_supplemental
Packit Service 4684c1
 * when some extension requested that supplemental data be sent or
Packit Service 4684c1
 * received.  Extension request this by setting the flags
Packit Service 4684c1
 * do_recv_supplemental or do_send_supplemental in the session.
Packit Service 4684c1
 *
Packit Service 4684c1
 * The functions in this file iterate through the _gnutls_supplemental
Packit Service 4684c1
 * array, and calls the send/recv functions for each respective data
Packit Service 4684c1
 * type.
Packit Service 4684c1
 *
Packit Service 4684c1
 * The receive function of each data type is responsible for decoding
Packit Service 4684c1
 * its own data.  If the extension did not expect to receive
Packit Service 4684c1
 * supplemental data, it should return GNUTLS_E_UNEXPECTED_PACKET.
Packit Service 4684c1
 * Otherwise, it just parse the data as normal.
Packit Service 4684c1
 *
Packit Service 4684c1
 * The send function needs to append the 2-byte data format type, and
Packit Service 4684c1
 * append the 2-byte length of its data, and the data.  If it doesn't
Packit Service 4684c1
 * want to send any data, it is fine to return without doing anything.
Packit Service 4684c1
 */
Packit Service 4684c1
Packit Service 4684c1
#include "gnutls_int.h"
Packit Service 4684c1
#include <gnutls/gnutls.h>
Packit Service 4684c1
#include "supplemental.h"
Packit Service 4684c1
#include "errors.h"
Packit Service 4684c1
#include "num.h"
Packit Service 4684c1
Packit Service 4684c1
typedef struct gnutls_supplemental_entry_st {
Packit Service 4684c1
	char *name;
Packit Service 4684c1
	gnutls_supplemental_data_format_type_t type;
Packit Service 4684c1
	gnutls_supp_recv_func supp_recv_func;
Packit Service 4684c1
	gnutls_supp_send_func supp_send_func;
Packit Service 4684c1
} gnutls_supplemental_entry_st;
Packit Service 4684c1
Packit Service 4684c1
static size_t suppfunc_size = 0;
Packit Service 4684c1
static gnutls_supplemental_entry_st *suppfunc = NULL;
Packit Service 4684c1
Packit Service 4684c1
/**
Packit Service 4684c1
 * gnutls_supplemental_get_name:
Packit Service 4684c1
 * @type: is a supplemental data format type
Packit Service 4684c1
 *
Packit Service 4684c1
 * Convert a #gnutls_supplemental_data_format_type_t value to a
Packit Service 4684c1
 * string.
Packit Service 4684c1
 *
Packit Service 4684c1
 * Returns: a string that contains the name of the specified
Packit Service 4684c1
 *   supplemental data format type, or %NULL for unknown types.
Packit Service 4684c1
 **/
Packit Service 4684c1
const char
Packit Service 4684c1
    *gnutls_supplemental_get_name(gnutls_supplemental_data_format_type_t
Packit Service 4684c1
				  type)
Packit Service 4684c1
{
Packit Service 4684c1
	size_t i;
Packit Service 4684c1
Packit Service 4684c1
	for (i = 0; i < suppfunc_size; i++) {
Packit Service 4684c1
		if (suppfunc[i].type == type)
Packit Service 4684c1
			return suppfunc[i].name;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	return NULL;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
void _gnutls_supplemental_deinit(void)
Packit Service 4684c1
{
Packit Service 4684c1
	unsigned i;
Packit Service 4684c1
Packit Service 4684c1
	for (i = 0; i < suppfunc_size; i++) {
Packit Service 4684c1
		gnutls_free(suppfunc[i].name);
Packit Service 4684c1
	}
Packit Service 4684c1
	gnutls_free(suppfunc);
Packit Service 4684c1
Packit Service 4684c1
	suppfunc = NULL;
Packit Service 4684c1
	suppfunc_size = 0;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
static gnutls_supp_recv_func
Packit Service 4684c1
get_supp_func_recv(gnutls_session_t session, gnutls_supplemental_data_format_type_t type)
Packit Service 4684c1
{
Packit Service 4684c1
	size_t i;
Packit Service 4684c1
Packit Service 4684c1
	for (i = 0; i < session->internals.rsup_size; i++) {
Packit Service 4684c1
		if (session->internals.rsup[i].type == type)
Packit Service 4684c1
			return session->internals.rsup[i].supp_recv_func;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	for (i = 0; i < suppfunc_size; i++) {
Packit Service 4684c1
		if (suppfunc[i].type == type)
Packit Service 4684c1
			return suppfunc[i].supp_recv_func;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	return NULL;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
static int gen_supplemental(gnutls_session_t session, const gnutls_supplemental_entry_st *supp,
Packit Service 4684c1
			    gnutls_buffer_st * buf)
Packit Service 4684c1
{
Packit Service 4684c1
	int ret;
Packit Service 4684c1
	gnutls_supp_send_func supp_send = supp->supp_send_func;
Packit Service 4684c1
	size_t sizepos = buf->length;
Packit Service 4684c1
Packit Service 4684c1
	/* Make room for supplement type and length byte length field. */
Packit Service 4684c1
	ret = _gnutls_buffer_append_data(buf, "\0\0\0\0", 4);
Packit Service 4684c1
	if (ret < 0) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		return ret;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	ret = supp_send(session, buf);
Packit Service 4684c1
	if (ret < 0) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		return ret;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	/* If data were added, store type+length, otherwise reset. */
Packit Service 4684c1
	if (buf->length > sizepos + 4) {
Packit Service 4684c1
		buf->data[sizepos] = (supp->type >> 8) & 0xFF;
Packit Service 4684c1
		buf->data[sizepos + 1] = supp->type & 0xFF;
Packit Service 4684c1
		buf->data[sizepos + 2] =
Packit Service 4684c1
		    ((buf->length - sizepos - 4) >> 8) & 0xFF;
Packit Service 4684c1
		buf->data[sizepos + 3] =
Packit Service 4684c1
		    (buf->length - sizepos - 4) & 0xFF;
Packit Service 4684c1
	} else
Packit Service 4684c1
		buf->length -= 4;
Packit Service 4684c1
Packit Service 4684c1
	return 0;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
int
Packit Service 4684c1
_gnutls_gen_supplemental(gnutls_session_t session, gnutls_buffer_st * buf)
Packit Service 4684c1
{
Packit Service 4684c1
	size_t i;
Packit Service 4684c1
	int ret;
Packit Service 4684c1
	unsigned init_pos = buf->length;
Packit Service 4684c1
Packit Service 4684c1
	/* Make room for 3 byte length field. */
Packit Service 4684c1
	ret = _gnutls_buffer_append_data(buf, "\0\0\0", 3);
Packit Service 4684c1
	if (ret < 0) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		return ret;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	for (i = 0; i < session->internals.rsup_size; i++) {
Packit Service 4684c1
		ret = gen_supplemental(session, &session->internals.rsup[i], buf);
Packit Service 4684c1
		if (ret < 0)
Packit Service 4684c1
			return gnutls_assert_val(ret);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	for (i = 0; i < suppfunc_size; i++) {
Packit Service 4684c1
		ret = gen_supplemental(session, &suppfunc[i], buf);
Packit Service 4684c1
		if (ret < 0)
Packit Service 4684c1
			return gnutls_assert_val(ret);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	i = buf->length - init_pos - 3;
Packit Service 4684c1
Packit Service 4684c1
	buf->data[init_pos] = (i >> 16) & 0xFF;
Packit Service 4684c1
	buf->data[init_pos+1] = (i >> 8) & 0xFF;
Packit Service 4684c1
	buf->data[init_pos+2] = i & 0xFF;
Packit Service 4684c1
Packit Service 4684c1
	_gnutls_debug_log
Packit Service 4684c1
	    ("EXT[%p]: Sending %d bytes of supplemental data\n", session,
Packit Service 4684c1
	     (int) buf->length);
Packit Service 4684c1
Packit Service 4684c1
	return buf->length - init_pos;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
int
Packit Service 4684c1
_gnutls_parse_supplemental(gnutls_session_t session,
Packit Service 4684c1
			   const uint8_t * data, int datalen)
Packit Service 4684c1
{
Packit Service 4684c1
	const uint8_t *p = data;
Packit Service 4684c1
	size_t dsize = datalen;
Packit Service 4684c1
	size_t total_size;
Packit Service 4684c1
Packit Service 4684c1
	DECR_LEN(dsize, 3);
Packit Service 4684c1
	total_size = _gnutls_read_uint24(p);
Packit Service 4684c1
	p += 3;
Packit Service 4684c1
Packit Service 4684c1
	if (dsize != total_size) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	do {
Packit Service 4684c1
		uint16_t supp_data_type;
Packit Service 4684c1
		uint16_t supp_data_length;
Packit Service 4684c1
		gnutls_supp_recv_func recv_func;
Packit Service 4684c1
Packit Service 4684c1
		DECR_LEN(dsize, 2);
Packit Service 4684c1
		supp_data_type = _gnutls_read_uint16(p);
Packit Service 4684c1
		p += 2;
Packit Service 4684c1
Packit Service 4684c1
		DECR_LEN(dsize, 2);
Packit Service 4684c1
		supp_data_length = _gnutls_read_uint16(p);
Packit Service 4684c1
		p += 2;
Packit Service 4684c1
Packit Service 4684c1
		_gnutls_debug_log
Packit Service 4684c1
		    ("EXT[%p]: Got supplemental type=%02x length=%d\n",
Packit Service 4684c1
		     session, supp_data_type, supp_data_length);
Packit Service 4684c1
Packit Service 4684c1
		recv_func = get_supp_func_recv(session, supp_data_type);
Packit Service 4684c1
		if (recv_func) {
Packit Service 4684c1
			int ret = recv_func(session, p, supp_data_length);
Packit Service 4684c1
			if (ret < 0) {
Packit Service 4684c1
				gnutls_assert();
Packit Service 4684c1
				return ret;
Packit Service 4684c1
			}
Packit Service 4684c1
		} else {
Packit Service 4684c1
			gnutls_assert();
Packit Service 4684c1
			return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
Packit Service 4684c1
		}
Packit Service 4684c1
Packit Service 4684c1
		DECR_LEN(dsize, supp_data_length);
Packit Service 4684c1
		p += supp_data_length;
Packit Service 4684c1
	}
Packit Service 4684c1
	while (dsize > 0);
Packit Service 4684c1
Packit Service 4684c1
	return 0;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
static int
Packit Service 4684c1
_gnutls_supplemental_register(gnutls_supplemental_entry_st *entry)
Packit Service 4684c1
{
Packit Service 4684c1
	gnutls_supplemental_entry_st *p;
Packit Service 4684c1
	unsigned i;
Packit Service 4684c1
Packit Service 4684c1
	for (i = 0; i < suppfunc_size; i++) {
Packit Service 4684c1
		if (entry->type == suppfunc[i].type)
Packit Service 4684c1
			return gnutls_assert_val(GNUTLS_E_ALREADY_REGISTERED);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	p = gnutls_realloc_fast(suppfunc,
Packit Service 4684c1
				sizeof(*suppfunc) * (suppfunc_size + 1));
Packit Service 4684c1
	if (!p) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		return GNUTLS_E_MEMORY_ERROR;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	suppfunc = p;
Packit Service 4684c1
Packit Service 4684c1
	memcpy(&suppfunc[suppfunc_size], entry, sizeof(*entry));
Packit Service 4684c1
Packit Service 4684c1
	suppfunc_size++;
Packit Service 4684c1
Packit Service 4684c1
	return GNUTLS_E_SUCCESS;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/**
Packit Service 4684c1
 * gnutls_supplemental_register:
Packit Service 4684c1
 * @name: the name of the supplemental data to register
Packit Service 4684c1
 * @type: the type of the supplemental data format
Packit Service 4684c1
 * @recv_func: the function to receive the data
Packit Service 4684c1
 * @send_func: the function to send the data
Packit Service 4684c1
 *
Packit Service 4684c1
 * This function will register a new supplemental data type (rfc4680).
Packit Service 4684c1
 * The registered data will remain until gnutls_global_deinit()
Packit Service 4684c1
 * is called. The provided @type must be an unassigned type in
Packit Service 4684c1
 * %gnutls_supplemental_data_format_type_t. If the type is already
Packit Service 4684c1
 * registered or handled by GnuTLS internally %GNUTLS_E_ALREADY_REGISTERED
Packit Service 4684c1
 * will be returned.
Packit Service 4684c1
 *
Packit Service 4684c1
 * This function is not thread safe. As supplemental data are not defined under
Packit Service 4684c1
 * TLS 1.3, this function will disable TLS 1.3 support globally.
Packit Service 4684c1
 *
Packit Service 4684c1
 * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
Packit Service 4684c1
 *
Packit Service 4684c1
 * Since: 3.4.0
Packit Service 4684c1
 **/
Packit Service 4684c1
int
Packit Service 4684c1
gnutls_supplemental_register(const char *name, gnutls_supplemental_data_format_type_t type,
Packit Service 4684c1
			     gnutls_supp_recv_func recv_func, gnutls_supp_send_func send_func)
Packit Service 4684c1
{
Packit Service 4684c1
	gnutls_supplemental_entry_st tmp_entry;
Packit Service 4684c1
	int ret;
Packit Service 4684c1
Packit Service 4684c1
	tmp_entry.name = gnutls_strdup(name);
Packit Service 4684c1
	tmp_entry.type = type;
Packit Service 4684c1
	tmp_entry.supp_recv_func = recv_func;
Packit Service 4684c1
	tmp_entry.supp_send_func = send_func;
Packit Service 4684c1
	
Packit Service 4684c1
	ret = _gnutls_supplemental_register(&tmp_entry);
Packit Service 4684c1
	if (ret < 0) {
Packit Service 4684c1
		gnutls_free(tmp_entry.name);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	_gnutls_disable_tls13 = 1;
Packit Service 4684c1
Packit Service 4684c1
	return ret;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/**
Packit Service 4684c1
 * gnutls_session_supplemental_register:
Packit Service 4684c1
 * @session: the session for which this will be registered
Packit Service 4684c1
 * @name: the name of the supplemental data to register
Packit Service 4684c1
 * @type: the type of the supplemental data format
Packit Service 4684c1
 * @recv_func: the function to receive the data
Packit Service 4684c1
 * @send_func: the function to send the data
Packit Service 4684c1
 * @flags: must be zero
Packit Service 4684c1
 *
Packit Service 4684c1
 * This function will register a new supplemental data type (rfc4680).
Packit Service 4684c1
 * The registered supplemental functions will be used for that specific
Packit Service 4684c1
 * session. The provided @type must be an unassigned type in
Packit Service 4684c1
 * %gnutls_supplemental_data_format_type_t.
Packit Service 4684c1
 *
Packit Service 4684c1
 * If the type is already registered or handled by GnuTLS internally
Packit Service 4684c1
 * %GNUTLS_E_ALREADY_REGISTERED will be returned.
Packit Service 4684c1
 *
Packit Service 4684c1
 * As supplemental data are not defined under TLS 1.3, this function will
Packit Service 4684c1
 * disable TLS 1.3 support for the given session.
Packit Service 4684c1
 *
Packit Service 4684c1
 * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
Packit Service 4684c1
 *
Packit Service 4684c1
 * Since: 3.5.5
Packit Service 4684c1
 **/
Packit Service 4684c1
int
Packit Service 4684c1
gnutls_session_supplemental_register(gnutls_session_t session, const char *name,
Packit Service 4684c1
				     gnutls_supplemental_data_format_type_t type,
Packit Service 4684c1
				     gnutls_supp_recv_func recv_func,
Packit Service 4684c1
				     gnutls_supp_send_func send_func,
Packit Service 4684c1
				     unsigned flags)
Packit Service 4684c1
{
Packit Service 4684c1
	gnutls_supplemental_entry_st tmp_entry;
Packit Service 4684c1
	gnutls_supplemental_entry_st *p;
Packit Service 4684c1
	unsigned i;
Packit Service 4684c1
Packit Service 4684c1
	tmp_entry.name = NULL;
Packit Service 4684c1
	tmp_entry.type = type;
Packit Service 4684c1
	tmp_entry.supp_recv_func = recv_func;
Packit Service 4684c1
	tmp_entry.supp_send_func = send_func;
Packit Service 4684c1
Packit Service 4684c1
	for (i = 0; i < suppfunc_size; i++) {
Packit Service 4684c1
		if (type == suppfunc[i].type)
Packit Service 4684c1
			return gnutls_assert_val(GNUTLS_E_ALREADY_REGISTERED);
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	p = gnutls_realloc(session->internals.rsup,
Packit Service 4684c1
			   sizeof(gnutls_supplemental_entry_st)*(session->internals.rsup_size + 1));
Packit Service 4684c1
	if (!p)
Packit Service 4684c1
		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
Packit Service 4684c1
Packit Service 4684c1
	session->internals.rsup = p;
Packit Service 4684c1
Packit Service 4684c1
	memcpy(&session->internals.rsup[session->internals.rsup_size], &tmp_entry, sizeof(tmp_entry));
Packit Service 4684c1
	session->internals.rsup_size++;
Packit Service 4684c1
Packit Service 4684c1
	session->internals.flags |= INT_FLAG_NO_TLS13;
Packit Service 4684c1
Packit Service 4684c1
	return GNUTLS_E_SUCCESS;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/**
Packit Service 4684c1
 * gnutls_supplemental_recv:
Packit Service 4684c1
 * @session: is a #gnutls_session_t type.
Packit Service 4684c1
 * @do_recv_supplemental: non-zero in order to expect supplemental data
Packit Service 4684c1
 *
Packit Service 4684c1
 * This function is to be called by an extension handler to
Packit Service 4684c1
 * instruct gnutls to attempt to receive supplemental data
Packit Service 4684c1
 * during the handshake process.
Packit Service 4684c1
 *
Packit Service 4684c1
 * Since: 3.4.0
Packit Service 4684c1
 **/
Packit Service 4684c1
void
Packit Service 4684c1
gnutls_supplemental_recv(gnutls_session_t session, unsigned do_recv_supplemental)
Packit Service 4684c1
{
Packit Service 4684c1
	session->security_parameters.do_recv_supplemental = do_recv_supplemental;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
/**
Packit Service 4684c1
 * gnutls_supplemental_send:
Packit Service 4684c1
 * @session: is a #gnutls_session_t type.
Packit Service 4684c1
 * @do_send_supplemental: non-zero in order to send supplemental data
Packit Service 4684c1
 *
Packit Service 4684c1
 * This function is to be called by an extension handler to
Packit Service 4684c1
 * instruct gnutls to send supplemental data during the handshake process.
Packit Service 4684c1
 *
Packit Service 4684c1
 * Since: 3.4.0
Packit Service 4684c1
 **/
Packit Service 4684c1
void
Packit Service 4684c1
gnutls_supplemental_send(gnutls_session_t session, unsigned do_send_supplemental)
Packit Service 4684c1
{
Packit Service 4684c1
	session->security_parameters.do_send_supplemental = do_send_supplemental;
Packit Service 4684c1
}