/*
 * Copyright (C) 2000-2013 Free Software Foundation, Inc.
 * Copyright (C) 2013 Nikos Mavrogiannopoulos
 * Copyright (C) 2017-2018 Red Hat, Inc.
 *
 * Author: Nikos Mavrogiannopoulos
 *
 * This file is part of GnuTLS.
 *
 * The GnuTLS is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
 *
 */

/* Some high level functions to be used in the record encryption are
 * included here.
 */

#include "gnutls_int.h"
#include "errors.h"
#include "cipher.h"
#include "algorithms.h"
#include "hash_int.h"
#include "cipher_int.h"
#include "debug.h"
#include "num.h"
#include "datum.h"
#include "kx.h"
#include "record.h"
#include "constate.h"
#include "mbuffers.h"
#include "state.h"
#include "random.h"

#include <nettle/memxor.h>

static int encrypt_packet(gnutls_session_t session, uint8_t *cipher_data,
			  int cipher_size, gnutls_datum_t *plain,
			  size_t min_pad, content_type_t _type,
			  record_parameters_st *params);

static int decrypt_packet(gnutls_session_t session, gnutls_datum_t *ciphertext,
			  gnutls_datum_t *plain, content_type_t type,
			  record_parameters_st *params, uint64_t sequence);

static int decrypt_packet_tls13(gnutls_session_t session,
				gnutls_datum_t *ciphertext,
				gnutls_datum_t *plain, content_type_t *type,
				record_parameters_st *params,
				uint64_t sequence);

static int encrypt_packet_tls13(gnutls_session_t session, uint8_t *cipher_data,
				size_t cipher_size, gnutls_datum_t *plain,
				size_t pad_size, uint8_t type,
				record_parameters_st *params);

/* returns ciphertext which contains the headers too. This also
 * calculates the size in the header field.
 *
 */
int _gnutls_encrypt(gnutls_session_t session, const uint8_t *data,
		    size_t data_size, size_t min_pad, mbuffer_st *bufel,
		    content_type_t type, record_parameters_st *params)
{
	gnutls_datum_t plaintext;
	const version_entry_st *vers =
		(session->internals.hsk_flags & HSK_EARLY_DATA_IN_FLIGHT) &&
				!IS_SERVER(session) ?
			session->internals.resumed_security_parameters.pversion :
			get_version(session);
	int ret;

	plaintext.data = (uint8_t *)data;
	plaintext.size = data_size;

	if (vers && vers->tls13_sem) {
		/* it fills the header, as it is included in the authenticated
		 * data of the AEAD cipher. */
		ret = encrypt_packet_tls13(session,
					   _mbuffer_get_udata_ptr(bufel),
					   _mbuffer_get_udata_size(bufel),
					   &plaintext, min_pad, type, params);
		if (ret < 0)
			return gnutls_assert_val(ret);
	} else {
		ret = encrypt_packet(session, _mbuffer_get_udata_ptr(bufel),
				     _mbuffer_get_udata_size(bufel), &plaintext,
				     min_pad, type, params);
		if (ret < 0)
			return gnutls_assert_val(ret);
	}

	if (IS_DTLS(session))
		_gnutls_write_uint16(
			ret, ((uint8_t *)_mbuffer_get_uhead_ptr(bufel)) + 11);
	else
		_gnutls_write_uint16(
			ret, ((uint8_t *)_mbuffer_get_uhead_ptr(bufel)) + 3);

	_mbuffer_set_udata_size(bufel, ret);
	_mbuffer_set_uhead_size(bufel, 0);

	return _mbuffer_get_udata_size(bufel);
}

/* Decrypts the given data.
 * Returns the decrypted data length.
 *
 * The output is preallocated with the maximum allowed data size.
 */
int _gnutls_decrypt(gnutls_session_t session, gnutls_datum_t *ciphertext,
		    gnutls_datum_t *output, content_type_t *type,
		    record_parameters_st *params, uint64_t sequence)
{
	int ret;
	const version_entry_st *vers = get_version(session);

	if (ciphertext->size == 0)
		return 0;

	if (vers && vers->tls13_sem)
		ret = decrypt_packet_tls13(session, ciphertext, output, type,
					   params, sequence);
	else
		ret = decrypt_packet(session, ciphertext, output, *type, params,
				     sequence);
	if (ret < 0)
		return gnutls_assert_val(ret);

	return ret;
}

inline static int calc_enc_length_block(gnutls_session_t session,
					const version_entry_st *ver,
					int data_size, int hash_size,
					uint8_t *pad, unsigned auth_cipher,
					uint16_t blocksize, unsigned etm)
{
	/* pad is the LH pad the user wants us to add. Besides
	 * this LH pad, we only add minimal padding
	 */
	unsigned int pre_length = data_size + *pad;
	unsigned int length, new_pad;

	if (etm == 0)
		pre_length += hash_size;

	new_pad = (uint8_t)(blocksize - (pre_length % blocksize)) + *pad;

	if (new_pad > 255)
		new_pad -= blocksize;
	*pad = new_pad;

	length = data_size + hash_size + *pad;

	if (_gnutls_version_has_explicit_iv(ver))
		length += blocksize; /* for the IV */

	return length;
}

inline static int calc_enc_length_stream(gnutls_session_t session,
					 int data_size, int hash_size,
					 unsigned auth_cipher,
					 unsigned exp_iv_size)
{
	unsigned int length;

	length = data_size + hash_size;
	if (auth_cipher)
		length += exp_iv_size;

	return length;
}

/* generates the authentication data (data to be hashed only
 * and are not to be sent). Returns their size.
 */
int _gnutls_make_preamble(uint64_t uint64_data, uint8_t type,
			  unsigned int length, const version_entry_st *ver,
			  uint8_t preamble[MAX_PREAMBLE_SIZE])
{
	uint8_t *p = preamble;
	uint16_t c_length;

	c_length = _gnutls_conv_uint16(length);

	_gnutls_write_uint64(uint64_data, p);
	p += 8;
	*p = type;
	p++;
#ifdef ENABLE_SSL3
	if (ver->id != GNUTLS_SSL3)
#endif
	{ /* TLS protocols */
		*p = ver->major;
		p++;
		*p = ver->minor;
		p++;
	}
	memcpy(p, &c_length, 2);
	p += 2;
	return p - preamble;
}

/* This is the actual encryption
 * Encrypts the given plaintext datum, and puts the result to cipher_data,
 * which has cipher_size size.
 * return the actual encrypted data length.
 */
static int encrypt_packet(gnutls_session_t session, uint8_t *cipher_data,
			  int cipher_size, gnutls_datum_t *plain,
			  size_t min_pad, content_type_t type,
			  record_parameters_st *params)
{
	uint8_t pad;
	int length, ret;
	uint8_t preamble[MAX_PREAMBLE_SIZE];
	int preamble_size;
	int tag_size = _gnutls_auth_cipher_tag_len(&params->write.ctx.tls12);
	int blocksize = _gnutls_cipher_get_block_size(params->cipher);
	unsigned algo_type = _gnutls_cipher_type(params->cipher);
	uint8_t *data_ptr, *full_cipher_ptr;
	const version_entry_st *ver = get_version(session);
	int explicit_iv = _gnutls_version_has_explicit_iv(ver);
	int auth_cipher = _gnutls_auth_cipher_is_aead(&params->write.ctx.tls12);
	uint8_t nonce[MAX_CIPHER_IV_SIZE];
	unsigned imp_iv_size = 0, exp_iv_size = 0;
	bool etm = 0;

	if (unlikely(ver == NULL))
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

	if (algo_type == CIPHER_BLOCK && params->etm != 0)
		etm = 1;

	_gnutls_hard_log("ENC[%p]: cipher: %s, MAC: %s, Epoch: %u\n", session,
			 _gnutls_cipher_get_name(params->cipher),
			 _gnutls_mac_get_name(params->mac),
			 (unsigned int)params->epoch);

	/* Calculate the encrypted length (padding etc.)
	 */
	if (algo_type == CIPHER_BLOCK) {
		/* Call gnutls_rnd() once. Get data used for the IV
		 */
		ret = gnutls_rnd(GNUTLS_RND_NONCE, nonce, blocksize);
		if (ret < 0)
			return gnutls_assert_val(ret);

		pad = min_pad;

		length = calc_enc_length_block(session, ver, plain->size,
					       tag_size, &pad, auth_cipher,
					       blocksize, etm);
	} else { /* AEAD + STREAM */
		imp_iv_size =
			_gnutls_cipher_get_implicit_iv_size(params->cipher);
		exp_iv_size =
			_gnutls_cipher_get_explicit_iv_size(params->cipher);

		pad = 0;
		length = calc_enc_length_stream(session, plain->size, tag_size,
						auth_cipher, exp_iv_size);
	}

	if (length < 0)
		return gnutls_assert_val(length);

	/* copy the encrypted data to cipher_data.
	 */
	if (cipher_size < length)
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

	data_ptr = cipher_data;
	full_cipher_ptr = data_ptr;

	if (algo_type == CIPHER_BLOCK || algo_type == CIPHER_STREAM) {
		if (algo_type == CIPHER_BLOCK && explicit_iv != 0) {
			/* copy the random IV.
			 */
			memcpy(data_ptr, nonce, blocksize);
			ret = _gnutls_auth_cipher_setiv(
				&params->write.ctx.tls12, data_ptr, blocksize);
			if (ret < 0)
				return gnutls_assert_val(ret);

			/*data_ptr += blocksize; */
			cipher_data += blocksize;
		}
	} else { /* AEAD */
		if ((params->cipher->flags & GNUTLS_CIPHER_FLAG_XOR_NONCE) ==
		    0) {
			/* Values in AEAD are pretty fixed in TLS 1.2 for 128-bit block
			 */
			if (params->write.iv_size != imp_iv_size)
				return gnutls_assert_val(
					GNUTLS_E_INTERNAL_ERROR);

			/* Instead of generating a new nonce on every packet, we use the
			 * write.sequence_number (It is a MAY on RFC 5288), and safer
			 * as it will never reuse a value.
			 */
			memcpy(nonce, params->write.iv, params->write.iv_size);
			_gnutls_write_uint64(params->write.sequence_number,
					     &nonce[imp_iv_size]);

			memcpy(data_ptr, &nonce[imp_iv_size], exp_iv_size);

			/*data_ptr += exp_iv_size; */
			cipher_data += exp_iv_size;
		} else { /* XOR nonce with IV */
			if (unlikely(params->write.iv_size != 12 ||
				     imp_iv_size != 12 || exp_iv_size != 0))
				return gnutls_assert_val(
					GNUTLS_E_INTERNAL_ERROR);

			memset(nonce, 0, 4);
			_gnutls_write_uint64(params->write.sequence_number,
					     &nonce[4]);

			memxor(nonce, params->write.iv, 12);
		}
	}

	if (etm)
		ret = length - tag_size;
	else
		ret = plain->size;

	preamble_size = _gnutls_make_preamble(params->write.sequence_number,
					      type, ret, ver, preamble);

	if (algo_type == CIPHER_BLOCK || algo_type == CIPHER_STREAM) {
		/* add the authenticated data */
		ret = _gnutls_auth_cipher_add_auth(&params->write.ctx.tls12,
						   preamble, preamble_size);
		if (ret < 0)
			return gnutls_assert_val(ret);

		if (etm && explicit_iv) {
			/* In EtM we need to hash the IV as well */
			ret = _gnutls_auth_cipher_add_auth(
				&params->write.ctx.tls12, full_cipher_ptr,
				blocksize);
			if (ret < 0)
				return gnutls_assert_val(ret);
		}

		/* Actual encryption.
		 */
		ret = _gnutls_auth_cipher_encrypt2_tag(&params->write.ctx.tls12,
						       plain->data, plain->size,
						       cipher_data, cipher_size,
						       pad);
		if (ret < 0)
			return gnutls_assert_val(ret);
	} else { /* AEAD */
		ret = _gnutls_aead_cipher_encrypt(
			&params->write.ctx.tls12.cipher, nonce,
			imp_iv_size + exp_iv_size, preamble, preamble_size,
			tag_size, plain->data, plain->size, cipher_data,
			cipher_size);
		if (ret < 0)
			return gnutls_assert_val(ret);
	}

	return length;
}

static int encrypt_packet_tls13(gnutls_session_t session, uint8_t *cipher_data,
				size_t cipher_size, gnutls_datum_t *plain,
				size_t pad_size, uint8_t type,
				record_parameters_st *params)
{
	int ret;
	unsigned int tag_size = params->write.aead_tag_size;
	const version_entry_st *ver = get_version(session);
	uint8_t nonce[MAX_CIPHER_IV_SIZE];
	unsigned iv_size = 0;
	ssize_t max, total;
	uint8_t aad[5];
	giovec_t auth_iov[1];
	giovec_t iov[2];

	if (unlikely(ver == NULL))
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

	_gnutls_hard_log("ENC[%p]: cipher: %s, MAC: %s, Epoch: %u\n", session,
			 _gnutls_cipher_get_name(params->cipher),
			 _gnutls_mac_get_name(params->mac),
			 (unsigned int)params->epoch);

	iv_size = params->write.iv_size;

	if (params->cipher->id == GNUTLS_CIPHER_NULL) {
		if (cipher_size < plain->size + 1)
			return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
		memcpy(cipher_data, plain->data, plain->size);
		return plain->size;
	}

	if (unlikely(iv_size < 8))
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

	memset(nonce, 0, iv_size - 8);
	_gnutls_write_uint64(params->write.sequence_number,
			     &nonce[iv_size - 8]);
	memxor(nonce, params->write.iv, iv_size);

	max = max_record_send_size(session) + MAX_RECORD_SEND_OVERHEAD(session);

	/* make TLS 1.3 form of data */
	total = plain->size + 1 + pad_size;

	/* check whether padding would exceed max */
	if (total > max) {
		if (unlikely(max < (ssize_t)plain->size + 1))
			return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

		pad_size = max - plain->size - 1;
		total = max;
	}

	/* create authenticated data header */
	aad[0] = GNUTLS_APPLICATION_DATA;
	aad[1] = 0x03;
	aad[2] = 0x03;
	_gnutls_write_uint16(total + tag_size, &aad[3]);

	auth_iov[0].iov_base = aad;
	auth_iov[0].iov_len = sizeof(aad);

	iov[0].iov_base = plain->data;
	iov[0].iov_len = plain->size;

	if (pad_size ||
	    (session->internals.flags & GNUTLS_SAFE_PADDING_CHECK)) {
		uint8_t *pad = gnutls_calloc(1, 1 + pad_size);
		if (pad == NULL)
			return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);

		pad[0] = type;

		iov[1].iov_base = pad;
		iov[1].iov_len = 1 + pad_size;

		ret = gnutls_aead_cipher_encryptv(&params->write.ctx.aead,
						  nonce, iv_size, auth_iov, 1,
						  tag_size, iov, 2, cipher_data,
						  &cipher_size);
		gnutls_free(pad);
	} else {
		iov[1].iov_base = &type;
		iov[1].iov_len = 1;

		ret = gnutls_aead_cipher_encryptv(&params->write.ctx.aead,
						  nonce, iv_size, auth_iov, 1,
						  tag_size, iov, 2, cipher_data,
						  &cipher_size);
	}

	if (ret < 0)
		return gnutls_assert_val(ret);

	return cipher_size;
}

/* Deciphers the ciphertext packet, and puts the result to plain.
 * Returns the actual plaintext packet size.
 */
static int decrypt_packet(gnutls_session_t session, gnutls_datum_t *ciphertext,
			  gnutls_datum_t *plain, content_type_t type,
			  record_parameters_st *params, uint64_t sequence)
{
	uint8_t tag[MAX_HASH_SIZE];
	uint8_t nonce[MAX_CIPHER_IV_SIZE];
	const uint8_t *tag_ptr = NULL;
	unsigned int pad = 0;
	int length, length_to_decrypt;
	uint16_t blocksize;
	int ret;
	uint8_t preamble[MAX_PREAMBLE_SIZE];
	unsigned int preamble_size = 0;
	const version_entry_st *ver = get_version(session);
	unsigned int tag_size =
		_gnutls_auth_cipher_tag_len(&params->read.ctx.tls12);
	unsigned int explicit_iv = _gnutls_version_has_explicit_iv(ver);
	unsigned imp_iv_size, exp_iv_size;
	unsigned cipher_type = _gnutls_cipher_type(params->cipher);
	bool etm = 0;

	if (unlikely(ver == NULL))
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

	imp_iv_size = _gnutls_cipher_get_implicit_iv_size(params->cipher);
	exp_iv_size = _gnutls_cipher_get_explicit_iv_size(params->cipher);
	blocksize = _gnutls_cipher_get_block_size(params->cipher);

	if (params->etm != 0 && cipher_type == CIPHER_BLOCK)
		etm = 1;

	/* if EtM mode and not AEAD */
	if (etm) {
		if (unlikely(ciphertext->size < tag_size))
			return gnutls_assert_val(
				GNUTLS_E_UNEXPECTED_PACKET_LENGTH);

		preamble_size = _gnutls_make_preamble(
			sequence, type, ciphertext->size - tag_size, ver,
			preamble);

		ret = _gnutls_auth_cipher_add_auth(&params->read.ctx.tls12,
						   preamble, preamble_size);
		if (unlikely(ret < 0))
			return gnutls_assert_val(ret);

		ret = _gnutls_auth_cipher_add_auth(&params->read.ctx.tls12,
						   ciphertext->data,
						   ciphertext->size - tag_size);
		if (unlikely(ret < 0))
			return gnutls_assert_val(ret);

		ret = _gnutls_auth_cipher_tag(&params->read.ctx.tls12, tag,
					      tag_size);
		if (unlikely(ret < 0))
			return gnutls_assert_val(ret);

		if (unlikely(gnutls_memcmp(tag,
					   &ciphertext->data[ciphertext->size -
							     tag_size],
					   tag_size) != 0)) {
			/* HMAC was not the same. */
			return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
		}
	}

	/* actual decryption (inplace)
	 */
	switch (cipher_type) {
	case CIPHER_AEAD:
		/* The way AEAD ciphers are defined in RFC5246, it allows
		 * only stream ciphers.
		 */
		if (unlikely(_gnutls_auth_cipher_is_aead(
				     &params->read.ctx.tls12) == 0))
			return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);

		if (unlikely(ciphertext->size < (tag_size + exp_iv_size)))
			return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);

		if ((params->cipher->flags & GNUTLS_CIPHER_FLAG_XOR_NONCE) ==
		    0) {
			/* Values in AEAD are pretty fixed in TLS 1.2 for 128-bit block
			 */
			if (unlikely(params->read.iv_size != 4))
				return gnutls_assert_val(
					GNUTLS_E_DECRYPTION_FAILED);

			memcpy(nonce, params->read.iv, imp_iv_size);

			memcpy(&nonce[imp_iv_size], ciphertext->data,
			       exp_iv_size);

			ciphertext->data += exp_iv_size;
			ciphertext->size -= exp_iv_size;
		} else { /* XOR nonce with IV */
			if (unlikely(params->read.iv_size != 12 ||
				     imp_iv_size != 12 || exp_iv_size != 0))
				return gnutls_assert_val(
					GNUTLS_E_DECRYPTION_FAILED);

			memset(nonce, 0, 4);
			_gnutls_write_uint64(sequence, &nonce[4]);

			memxor(nonce, params->read.iv, 12);
		}

		length = ciphertext->size - tag_size;

		length_to_decrypt = ciphertext->size;

		/* Pass the type, version, length and plain through
		 * MAC.
		 */
		preamble_size = _gnutls_make_preamble(sequence, type, length,
						      ver, preamble);

		if (unlikely((unsigned)length_to_decrypt > plain->size)) {
			_gnutls_audit_log(
				session,
				"Received %u bytes, while expecting less than %u\n",
				(unsigned int)length_to_decrypt,
				(unsigned int)plain->size);
			return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
		}

		ret = _gnutls_aead_cipher_decrypt(
			&params->read.ctx.tls12.cipher, nonce,
			exp_iv_size + imp_iv_size, preamble, preamble_size,
			tag_size, ciphertext->data, length_to_decrypt,
			plain->data, plain->size);
		if (unlikely(ret < 0))
			return gnutls_assert_val(ret);

		return length;

		break;
	case CIPHER_STREAM:
		if (unlikely(ciphertext->size < tag_size))
			return gnutls_assert_val(
				GNUTLS_E_UNEXPECTED_PACKET_LENGTH);

		length_to_decrypt = ciphertext->size;
		length = ciphertext->size - tag_size;
		tag_ptr = plain->data + length;

		/* Pass the type, version, length and plain through
		 * MAC.
		 */
		preamble_size = _gnutls_make_preamble(sequence, type, length,
						      ver, preamble);

		ret = _gnutls_auth_cipher_add_auth(&params->read.ctx.tls12,
						   preamble, preamble_size);
		if (unlikely(ret < 0))
			return gnutls_assert_val(ret);

		if (unlikely((unsigned)length_to_decrypt > plain->size)) {
			_gnutls_audit_log(
				session,
				"Received %u bytes, while expecting less than %u\n",
				(unsigned int)length_to_decrypt,
				(unsigned int)plain->size);
			return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
		}

		ret = _gnutls_auth_cipher_decrypt2(&params->read.ctx.tls12,
						   ciphertext->data,
						   length_to_decrypt,
						   plain->data, plain->size);

		if (unlikely(ret < 0))
			return gnutls_assert_val(ret);

		ret = _gnutls_auth_cipher_tag(&params->read.ctx.tls12, tag,
					      tag_size);
		if (unlikely(ret < 0))
			return gnutls_assert_val(ret);

		if (unlikely(gnutls_memcmp(tag, tag_ptr, tag_size) != 0)) {
			return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
		}

		break;
	case CIPHER_BLOCK:
		if (unlikely(ciphertext->size < blocksize))
			return gnutls_assert_val(
				GNUTLS_E_UNEXPECTED_PACKET_LENGTH);

		if (etm == 0) {
			if (unlikely(ciphertext->size % blocksize != 0))
				return gnutls_assert_val(
					GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
		} else {
			if (unlikely((ciphertext->size - tag_size) %
					     blocksize !=
				     0))
				return gnutls_assert_val(
					GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
		}

		/* ignore the IV in TLS 1.1+
		 */
		if (explicit_iv) {
			ret = _gnutls_auth_cipher_setiv(&params->read.ctx.tls12,
							ciphertext->data,
							blocksize);
			if (ret < 0)
				return gnutls_assert_val(ret);

			memcpy(nonce, ciphertext->data, blocksize);
			ciphertext->size -= blocksize;
			ciphertext->data += blocksize;
		}

		if (unlikely(ciphertext->size < tag_size + 1))
			return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);

		/* we don't use the auth_cipher interface here, since
		 * TLS with block ciphers is impossible to be used under such
		 * an API. (the length of plaintext is required to calculate
		 * auth_data, but it is not available before decryption).
		 */
		if (unlikely(ciphertext->size > plain->size))
			return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);

		if (etm == 0) {
			ret = _gnutls_cipher_decrypt2(
				&params->read.ctx.tls12.cipher,
				ciphertext->data, ciphertext->size, plain->data,
				plain->size);
			if (unlikely(ret < 0))
				return gnutls_assert_val(ret);

			ret = cbc_mac_verify(session, params, preamble, type,
					     sequence, plain->data,
					     ciphertext->size, tag_size);
			if (unlikely(ret < 0))
				return gnutls_assert_val(ret);

			length = ret;
		} else { /* EtM */
			ret = _gnutls_cipher_decrypt2(
				&params->read.ctx.tls12.cipher,
				ciphertext->data, ciphertext->size - tag_size,
				plain->data, plain->size);
			if (unlikely(ret < 0))
				return gnutls_assert_val(ret);

			pad = plain->data[ciphertext->size - tag_size -
					  1]; /* pad */
			length = ciphertext->size - tag_size - pad - 1;

			if (unlikely(length < 0))
				return gnutls_assert_val(
					GNUTLS_E_DECRYPTION_FAILED);
		}
		break;
	default:
		return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
	}

	return length;
}

static int decrypt_packet_tls13(gnutls_session_t session,
				gnutls_datum_t *ciphertext,
				gnutls_datum_t *plain, content_type_t *type,
				record_parameters_st *params, uint64_t sequence)
{
	uint8_t nonce[MAX_CIPHER_IV_SIZE];
	size_t length, length_to_decrypt;
	int ret;
	const version_entry_st *ver = get_version(session);
	unsigned int tag_size = params->read.aead_tag_size;
	unsigned iv_size;
	unsigned j;
	volatile unsigned length_set;
	uint8_t aad[5];

	if (unlikely(ver == NULL))
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

	if (params->cipher->id == GNUTLS_CIPHER_NULL) {
		if (plain->size < ciphertext->size)
			return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

		length = ciphertext->size;
		memcpy(plain->data, ciphertext->data, length);

		return length;
	}

	iv_size = _gnutls_cipher_get_iv_size(params->cipher);

	/* The way AEAD ciphers are defined in RFC5246, it allows
	 * only stream ciphers.
	 */
	if (unlikely(ciphertext->size < tag_size))
		return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);

	if (unlikely(params->read.iv_size != iv_size || iv_size < 8))
		return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);

	memset(nonce, 0, iv_size - 8);
	_gnutls_write_uint64(sequence, &nonce[iv_size - 8]);
	memxor(nonce, params->read.iv, params->read.iv_size);

	length = ciphertext->size - tag_size;

	length_to_decrypt = ciphertext->size;

	if (unlikely((unsigned)length_to_decrypt > plain->size)) {
		_gnutls_audit_log(
			session,
			"Received %u bytes, while expecting less than %u\n",
			(unsigned int)length_to_decrypt,
			(unsigned int)plain->size);
		return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
	}

	aad[0] = GNUTLS_APPLICATION_DATA;
	aad[1] = 0x03;
	aad[2] = 0x03;
	_gnutls_write_uint16(ciphertext->size, &aad[3]);

	ret = gnutls_aead_cipher_decrypt(&params->read.ctx.aead, nonce, iv_size,
					 aad, sizeof(aad), tag_size,
					 ciphertext->data, length_to_decrypt,
					 plain->data, &length);
	if (unlikely(ret < 0))
		return gnutls_assert_val(ret);

	/* 1 octet for content type */
	if (length > max_decrypted_size(session) + 1) {
		_gnutls_audit_log(session,
				  "Received packet with illegal length: %u\n",
				  (unsigned int)length);

		return gnutls_assert_val(GNUTLS_E_RECORD_OVERFLOW);
	}

	length_set = 0;

	/* now figure the actual data size. We intentionally iterate through all data,
	 * to avoid leaking the padding length due to timing differences in processing.
	 */
	for (j = length; j > 0; j--) {
		if (plain->data[j - 1] != 0 && length_set == 0) {
			*type = plain->data[j - 1];
			length = j - 1;
			length_set = 1;
			if (!(session->internals.flags &
			      GNUTLS_SAFE_PADDING_CHECK))
				break;
		}
	}

	if (!length_set)
		return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);

	return length;
}
