Blame lib/tls13/finished.c

Packit Service 4684c1
/*
Packit Service 4684c1
 * Copyright (C) 2017 Red Hat, Inc.
Packit Service 4684c1
 *
Packit Service 4684c1
 * Author: Nikos Mavrogiannopoulos
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
#include "gnutls_int.h"
Packit Service 4684c1
#include "errors.h"
Packit Service 4684c1
#include "handshake.h"
Packit Service 4684c1
#include "tls13/finished.h"
Packit Service 4684c1
#include "mem.h"
Packit Service 4684c1
#include "mbuffers.h"
Packit Service 4684c1
#include "secrets.h"
Packit Service 4684c1
Packit Service 4684c1
int _gnutls13_compute_finished(const mac_entry_st *prf,
Packit Service 4684c1
		const uint8_t *base_key,
Packit Service 4684c1
		gnutls_buffer_st *handshake_hash_buffer,
Packit Service 4684c1
		void *out)
Packit Service 4684c1
{
Packit Service 4684c1
	int ret;
Packit Service 4684c1
	uint8_t fkey[MAX_HASH_SIZE];
Packit Service 4684c1
	uint8_t ts_hash[MAX_HASH_SIZE];
Packit Service 4684c1
Packit Service 4684c1
	ret = _tls13_expand_secret2(prf,
Packit Service 4684c1
			"finished", 8,
Packit Service 4684c1
			NULL, 0,
Packit Service 4684c1
			base_key,
Packit Service 4684c1
			prf->output_size, fkey);
Packit Service 4684c1
	if (ret < 0)
Packit Service 4684c1
		return gnutls_assert_val(ret);
Packit Service 4684c1
Packit Service 4684c1
	ret = gnutls_hash_fast(prf->id,
Packit Service 4684c1
			       handshake_hash_buffer->data,
Packit Service 4684c1
			       handshake_hash_buffer->length,
Packit Service 4684c1
			       ts_hash);
Packit Service 4684c1
	if (ret < 0)
Packit Service 4684c1
		return gnutls_assert_val(ret);
Packit Service 4684c1
Packit Service 4684c1
	ret = gnutls_hmac_fast(prf->id,
Packit Service 4684c1
			       fkey, prf->output_size,
Packit Service 4684c1
			       ts_hash, prf->output_size,
Packit Service 4684c1
			       out);
Packit Service 4684c1
	if (ret < 0)
Packit Service 4684c1
		return gnutls_assert_val(ret);
Packit Service 4684c1
Packit Service 4684c1
	return 0;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
int _gnutls13_recv_finished(gnutls_session_t session)
Packit Service 4684c1
{
Packit Service 4684c1
	int ret;
Packit Service 4684c1
	gnutls_buffer_st buf;
Packit Service 4684c1
	uint8_t verifier[MAX_HASH_SIZE];
Packit Service 4684c1
	const uint8_t *base_key;
Packit Service 4684c1
	unsigned hash_size;
Packit Service 4684c1
Packit Service 4684c1
	if (unlikely(session->security_parameters.prf == NULL))
Packit Service 4684c1
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
Packit Service 4684c1
Packit Service 4684c1
	hash_size = session->security_parameters.prf->output_size;
Packit Service 4684c1
Packit Service 4684c1
	if (!session->internals.initial_negotiation_completed) {
Packit Service 4684c1
		if (session->security_parameters.entity == GNUTLS_CLIENT)
Packit Service 4684c1
			base_key = session->key.proto.tls13.hs_skey;
Packit Service 4684c1
		else
Packit Service 4684c1
			base_key = session->key.proto.tls13.hs_ckey;
Packit Service 4684c1
	} else {
Packit Service 4684c1
		if (session->security_parameters.entity == GNUTLS_CLIENT)
Packit Service 4684c1
			base_key = session->key.proto.tls13.ap_skey;
Packit Service 4684c1
		else
Packit Service 4684c1
			base_key = session->key.proto.tls13.ap_ckey;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	ret = _gnutls13_compute_finished(session->security_parameters.prf,
Packit Service 4684c1
			base_key,
Packit Service 4684c1
			&session->internals.handshake_hash_buffer,
Packit Service 4684c1
			verifier);
Packit Service 4684c1
	if (ret < 0) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		goto cleanup;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	ret = _gnutls_recv_handshake(session, GNUTLS_HANDSHAKE_FINISHED, 0, &buf;;
Packit Service 4684c1
	if (ret < 0)
Packit Service 4684c1
		return gnutls_assert_val(ret);
Packit Service 4684c1
Packit Service 4684c1
	_gnutls_handshake_log("HSK[%p]: parsing finished\n", session);
Packit Service 4684c1
Packit Service 4684c1
	if (buf.length != hash_size) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
Packit Service 4684c1
		goto cleanup;
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
Packit Service 4684c1
#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
Packit Service 4684c1
# warning This is unsafe for production builds
Packit Service 4684c1
#else
Packit Service 4684c1
	if (safe_memcmp(verifier, buf.data, buf.length) != 0) {
Packit Service 4684c1
		gnutls_assert();
Packit Service 4684c1
		ret = GNUTLS_E_ERROR_IN_FINISHED_PACKET;
Packit Service 4684c1
		goto cleanup;
Packit Service 4684c1
	}
Packit Service 4684c1
#endif
Packit Service 4684c1
Packit Service 4684c1
	ret = 0;
Packit Service 4684c1
cleanup:
Packit Service 4684c1
	
Packit Service 4684c1
	_gnutls_buffer_clear(&buf;;
Packit Service 4684c1
	return ret;
Packit Service 4684c1
}
Packit Service 4684c1
Packit Service 4684c1
int _gnutls13_send_finished(gnutls_session_t session, unsigned again)
Packit Service 4684c1
{
Packit Service 4684c1
	int ret;
Packit Service 4684c1
	uint8_t verifier[MAX_HASH_SIZE];
Packit Service 4684c1
	mbuffer_st *bufel = NULL;
Packit Service 4684c1
	const uint8_t *base_key;
Packit Service 4684c1
	unsigned hash_size;
Packit Service 4684c1
Packit Service 4684c1
	if (again == 0) {
Packit Service 4684c1
		if (unlikely(session->security_parameters.prf == NULL))
Packit Service 4684c1
			return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
Packit Service 4684c1
Packit Service 4684c1
		hash_size = session->security_parameters.prf->output_size;
Packit Service 4684c1
Packit Service 4684c1
		if (!session->internals.initial_negotiation_completed) {
Packit Service 4684c1
			if (session->security_parameters.entity == GNUTLS_CLIENT)
Packit Service 4684c1
				base_key = session->key.proto.tls13.hs_ckey;
Packit Service 4684c1
			else
Packit Service 4684c1
				base_key = session->key.proto.tls13.hs_skey;
Packit Service 4684c1
		} else {
Packit Service 4684c1
			if (session->security_parameters.entity == GNUTLS_CLIENT)
Packit Service 4684c1
				base_key = session->key.proto.tls13.ap_ckey;
Packit Service 4684c1
			else
Packit Service 4684c1
				base_key = session->key.proto.tls13.ap_skey;
Packit Service 4684c1
		}
Packit Service 4684c1
Packit Service 4684c1
		ret = _gnutls13_compute_finished(session->security_parameters.prf,
Packit Service 4684c1
				base_key,
Packit Service 4684c1
				&session->internals.handshake_hash_buffer,
Packit Service 4684c1
				verifier);
Packit Service 4684c1
		if (ret < 0) {
Packit Service 4684c1
			gnutls_assert();
Packit Service 4684c1
			goto cleanup;
Packit Service 4684c1
		}
Packit Service 4684c1
Packit Service 4684c1
		_gnutls_handshake_log("HSK[%p]: sending finished\n", session);
Packit Service 4684c1
Packit Service 4684c1
		bufel = _gnutls_handshake_alloc(session, hash_size);
Packit Service 4684c1
		if (bufel == NULL)
Packit Service 4684c1
			return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
Packit Service 4684c1
Packit Service 4684c1
		_mbuffer_set_udata_size(bufel, 0);
Packit Service 4684c1
		ret = _mbuffer_append_data(bufel, verifier, hash_size);
Packit Service 4684c1
		if (ret < 0) {
Packit Service 4684c1
			gnutls_assert();
Packit Service 4684c1
			goto cleanup;
Packit Service 4684c1
		}
Packit Service 4684c1
	}
Packit Service 4684c1
Packit Service 4684c1
	return _gnutls_send_handshake(session, bufel, GNUTLS_HANDSHAKE_FINISHED);
Packit Service 4684c1
Packit Service 4684c1
cleanup:
Packit Service 4684c1
	_mbuffer_xfree(&bufel);
Packit Service 4684c1
	return ret;
Packit Service 4684c1
}