Blame lib/ext/key_share.c

Packit aea12f
/*
Packit aea12f
 * Copyright (C) 2017 Red Hat, Inc.
Packit aea12f
 *
Packit aea12f
 * Author: Nikos Mavrogiannopoulos
Packit aea12f
 *
Packit aea12f
 * This file is part of GnuTLS.
Packit aea12f
 *
Packit aea12f
 * The GnuTLS is free software; you can redistribute it and/or
Packit aea12f
 * modify it under the terms of the GNU Lesser General Public License
Packit aea12f
 * as published by the Free Software Foundation; either version 2.1 of
Packit aea12f
 * the License, or (at your option) any later version.
Packit aea12f
 *
Packit aea12f
 * This library is distributed in the hope that it will be useful, but
Packit aea12f
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit aea12f
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit aea12f
 * Lesser General Public License for more details.
Packit aea12f
 *
Packit aea12f
 * You should have received a copy of the GNU Lesser General Public License
Packit aea12f
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
Packit aea12f
 *
Packit aea12f
 */
Packit aea12f
Packit aea12f
/* This file contains the code the Key Share TLS 1.3 extension.
Packit aea12f
 */
Packit aea12f
Packit aea12f
#include "gnutls_int.h"
Packit aea12f
#include "errors.h"
Packit aea12f
#include "num.h"
Packit aea12f
#include "ext/supported_groups.h"
Packit aea12f
#include <state.h>
Packit aea12f
#include <num.h>
Packit aea12f
#include <algorithms.h>
Packit aea12f
#include "auth/psk.h"
Packit aea12f
#include "auth/cert.h"
Packit aea12f
#include "handshake.h"
Packit aea12f
#include "../ecc.h"
Packit aea12f
#include "../algorithms.h"
Packit aea12f
#include "pk.h"
Packit aea12f
Packit aea12f
static int key_share_recv_params(gnutls_session_t session,
Packit aea12f
					     const uint8_t * data,
Packit aea12f
					     size_t data_size);
Packit aea12f
static int key_share_send_params(gnutls_session_t session,
Packit aea12f
					     gnutls_buffer_st * extdata);
Packit aea12f
Packit aea12f
const hello_ext_entry_st ext_mod_key_share = {
Packit aea12f
	.name = "Key Share",
Packit aea12f
	.tls_id = 51,
Packit aea12f
	.gid = GNUTLS_EXTENSION_KEY_SHARE,
Packit aea12f
	.parse_type = _GNUTLS_EXT_TLS_POST_CS,
Packit aea12f
	.validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_CLIENT_HELLO | GNUTLS_EXT_FLAG_TLS13_SERVER_HELLO |
Packit aea12f
		    GNUTLS_EXT_FLAG_HRR,
Packit aea12f
	.recv_func = key_share_recv_params,
Packit aea12f
	.send_func = key_share_send_params,
Packit aea12f
	.pack_func = NULL,
Packit aea12f
	.unpack_func = NULL,
Packit aea12f
	.deinit_func = NULL,
Packit aea12f
	.cannot_be_overriden = 1
Packit aea12f
};
Packit aea12f
Packit aea12f
/*
Packit aea12f
 * Generates key exchange parameters, and stores them in
Packit aea12f
 * session->key.kshare_*_params.
Packit aea12f
 *
Packit aea12f
 * struct {
Packit aea12f
 *     NamedGroup group;
Packit aea12f
 *     opaque key_exchange<1..2^16-1>;
Packit aea12f
 * } KeyShareEntry;
Packit aea12f
 *
Packit aea12f
 */
Packit aea12f
static int client_gen_key_share(gnutls_session_t session, const gnutls_group_entry_st *group, gnutls_buffer_st *extdata)
Packit aea12f
{
Packit aea12f
	gnutls_datum_t tmp = {NULL, 0};
Packit aea12f
	int ret;
Packit aea12f
Packit aea12f
	if (group->pk != GNUTLS_PK_EC && group->pk != GNUTLS_PK_ECDH_X25519 &&
Packit aea12f
	    group->pk != GNUTLS_PK_DH) {
Packit aea12f
		_gnutls_debug_log("Cannot send key share for group %s!\n", group->name);
Packit aea12f
		return GNUTLS_E_INT_RET_0;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	_gnutls_handshake_log("EXT[%p]: sending key share for %s\n", session, group->name);
Packit aea12f
Packit aea12f
	ret =
Packit aea12f
	    _gnutls_buffer_append_prefix(extdata, 16, group->tls_id);
Packit aea12f
	if (ret < 0)
Packit aea12f
		return gnutls_assert_val(ret);
Packit aea12f
Packit aea12f
	if (group->pk == GNUTLS_PK_EC) {
Packit aea12f
		gnutls_pk_params_release(&session->key.kshare.ecdh_params);
Packit aea12f
		gnutls_pk_params_init(&session->key.kshare.ecdh_params);
Packit aea12f
Packit aea12f
		ret = _gnutls_pk_generate_keys(group->pk, group->curve,
Packit aea12f
						&session->key.kshare.ecdh_params, 1);
Packit aea12f
		if (ret < 0)
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
Packit aea12f
		ret = _gnutls_ecc_ansi_x962_export(group->curve,
Packit aea12f
				session->key.kshare.ecdh_params.params[ECC_X],
Packit aea12f
				session->key.kshare.ecdh_params.params[ECC_Y],
Packit aea12f
				&tmp);
Packit aea12f
		if (ret < 0)
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
Packit aea12f
		ret =
Packit aea12f
		    _gnutls_buffer_append_data_prefix(extdata, 16, tmp.data, tmp.size);
Packit aea12f
		if (ret < 0) {
Packit aea12f
			gnutls_assert();
Packit aea12f
			goto cleanup;
Packit aea12f
		}
Packit aea12f
Packit aea12f
		session->key.kshare.ecdh_params.algo = group->pk;
Packit aea12f
		session->key.kshare.ecdh_params.curve = group->curve;
Packit aea12f
Packit aea12f
		ret = 0;
Packit aea12f
Packit aea12f
	} else if (group->pk == GNUTLS_PK_ECDH_X25519) {
Packit aea12f
		gnutls_pk_params_release(&session->key.kshare.ecdhx_params);
Packit aea12f
		gnutls_pk_params_init(&session->key.kshare.ecdhx_params);
Packit aea12f
Packit aea12f
		ret = _gnutls_pk_generate_keys(group->pk, group->curve,
Packit aea12f
						&session->key.kshare.ecdhx_params, 1);
Packit aea12f
		if (ret < 0)
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
Packit aea12f
		ret =
Packit aea12f
		    _gnutls_buffer_append_data_prefix(extdata, 16,
Packit aea12f
				session->key.kshare.ecdhx_params.raw_pub.data,
Packit aea12f
				session->key.kshare.ecdhx_params.raw_pub.size);
Packit aea12f
		if (ret < 0) {
Packit aea12f
			gnutls_assert();
Packit aea12f
			goto cleanup;
Packit aea12f
		}
Packit aea12f
Packit aea12f
		session->key.kshare.ecdhx_params.algo = group->pk;
Packit aea12f
		session->key.kshare.ecdhx_params.curve = group->curve;
Packit aea12f
Packit aea12f
		ret = 0;
Packit aea12f
Packit aea12f
	} else if (group->pk == GNUTLS_PK_DH) {
Packit aea12f
		/* we need to initialize the group parameters first */
Packit aea12f
		gnutls_pk_params_release(&session->key.kshare.dh_params);
Packit aea12f
		gnutls_pk_params_init(&session->key.kshare.dh_params);
Packit aea12f
Packit aea12f
		ret = _gnutls_mpi_init_scan_nz(&session->key.kshare.dh_params.params[DH_G],
Packit aea12f
			group->generator->data, group->generator->size);
Packit aea12f
		if (ret < 0)
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
Packit aea12f
		ret = _gnutls_mpi_init_scan_nz(&session->key.kshare.dh_params.params[DH_P],
Packit aea12f
			group->prime->data, group->prime->size);
Packit aea12f
		if (ret < 0)
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
Packit aea12f
		ret = _gnutls_mpi_init_scan_nz(&session->key.kshare.dh_params.params[DH_Q],
Packit aea12f
			group->q->data, group->q->size);
Packit aea12f
		if (ret < 0)
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
Packit aea12f
		session->key.kshare.dh_params.algo = group->pk;
Packit aea12f
		session->key.kshare.dh_params.dh_group = group->id; /* no curve in FFDH, we write the group */
Packit aea12f
		session->key.kshare.dh_params.qbits = *group->q_bits;
Packit aea12f
		session->key.kshare.dh_params.params_nr = 3;
Packit aea12f
Packit aea12f
		ret = _gnutls_pk_generate_keys(group->pk, 0, &session->key.kshare.dh_params, 1);
Packit aea12f
		if (ret < 0)
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
Packit aea12f
		ret =
Packit aea12f
		    _gnutls_buffer_append_prefix(extdata, 16, group->prime->size);
Packit aea12f
		if (ret < 0)
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
Packit aea12f
		ret = _gnutls_buffer_append_fixed_mpi(extdata, session->key.kshare.dh_params.params[DH_Y],
Packit aea12f
				group->prime->size);
Packit aea12f
		if (ret < 0)
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
Packit aea12f
		ret = 0;
Packit aea12f
	}
Packit aea12f
Packit aea12f
 cleanup:
Packit aea12f
	gnutls_free(tmp.data);
Packit aea12f
	return ret;
Packit aea12f
}
Packit aea12f
Packit aea12f
/*
Packit aea12f
 * Sends server key exchange parameters
Packit aea12f
 *
Packit aea12f
 */
Packit aea12f
static int server_gen_key_share(gnutls_session_t session, const gnutls_group_entry_st *group, gnutls_buffer_st *extdata)
Packit aea12f
{
Packit aea12f
	gnutls_datum_t tmp = {NULL, 0};
Packit aea12f
	int ret;
Packit aea12f
Packit aea12f
	if (group->pk != GNUTLS_PK_EC && group->pk != GNUTLS_PK_ECDH_X25519 &&
Packit aea12f
	    group->pk != GNUTLS_PK_DH) {
Packit aea12f
		_gnutls_debug_log("Cannot send key share for group %s!\n", group->name);
Packit aea12f
		return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	_gnutls_handshake_log("EXT[%p]: sending key share for %s\n", session, group->name);
Packit aea12f
Packit aea12f
	ret =
Packit aea12f
	    _gnutls_buffer_append_prefix(extdata, 16, group->tls_id);
Packit aea12f
	if (ret < 0)
Packit aea12f
		return gnutls_assert_val(ret);
Packit aea12f
Packit aea12f
	if (group->pk == GNUTLS_PK_EC) {
Packit aea12f
		ret = _gnutls_ecc_ansi_x962_export(group->curve,
Packit aea12f
				session->key.kshare.ecdh_params.params[ECC_X],
Packit aea12f
				session->key.kshare.ecdh_params.params[ECC_Y],
Packit aea12f
				&tmp);
Packit aea12f
		if (ret < 0)
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
Packit aea12f
		ret =
Packit aea12f
		    _gnutls_buffer_append_data_prefix(extdata, 16, tmp.data, tmp.size);
Packit aea12f
		if (ret < 0) {
Packit aea12f
			gnutls_assert();
Packit aea12f
			goto cleanup;
Packit aea12f
		}
Packit aea12f
Packit aea12f
		ret = 0;
Packit aea12f
Packit aea12f
	} else if (group->pk == GNUTLS_PK_ECDH_X25519) {
Packit aea12f
		ret =
Packit aea12f
		    _gnutls_buffer_append_data_prefix(extdata, 16,
Packit aea12f
				session->key.kshare.ecdhx_params.raw_pub.data,
Packit aea12f
				session->key.kshare.ecdhx_params.raw_pub.size);
Packit aea12f
		if (ret < 0)
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
Packit aea12f
		ret = 0;
Packit aea12f
Packit aea12f
	} else if (group->pk == GNUTLS_PK_DH) {
Packit aea12f
		ret =
Packit aea12f
		    _gnutls_buffer_append_prefix(extdata, 16, group->prime->size);
Packit aea12f
		if (ret < 0)
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
Packit aea12f
		ret = _gnutls_buffer_append_fixed_mpi(extdata, session->key.kshare.dh_params.params[DH_Y],
Packit aea12f
				group->prime->size);
Packit aea12f
		if (ret < 0)
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
Packit aea12f
		ret = 0;
Packit aea12f
	}
Packit aea12f
Packit aea12f
 cleanup:
Packit aea12f
	gnutls_free(tmp.data);
Packit aea12f
	return ret;
Packit aea12f
}
Packit aea12f
Packit aea12f
/* Generates shared key and stores it in session->key.key
Packit aea12f
 */
Packit aea12f
static int
Packit aea12f
server_use_key_share(gnutls_session_t session, const gnutls_group_entry_st *group,
Packit aea12f
		     const uint8_t * data, size_t data_size)
Packit aea12f
{
Packit aea12f
	const gnutls_ecc_curve_entry_st *curve;
Packit aea12f
	int ret;
Packit aea12f
Packit aea12f
	if (group->pk == GNUTLS_PK_EC) {
Packit aea12f
		gnutls_pk_params_st pub;
Packit aea12f
Packit aea12f
		gnutls_pk_params_release(&session->key.kshare.ecdh_params);
Packit aea12f
		gnutls_pk_params_init(&session->key.kshare.ecdh_params);
Packit aea12f
Packit aea12f
		curve = _gnutls_ecc_curve_get_params(group->curve);
Packit aea12f
Packit aea12f
		gnutls_pk_params_init(&pub;;
Packit aea12f
Packit aea12f
		if (curve->size*2+1 != data_size)
Packit aea12f
			return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
Packit aea12f
Packit aea12f
		/* generate our key */
Packit aea12f
		ret = _gnutls_pk_generate_keys(curve->pk, curve->id, &session->key.kshare.ecdh_params, 1);
Packit aea12f
		if (ret < 0)
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
Packit aea12f
		/* read the public key */
Packit aea12f
		ret = _gnutls_ecc_ansi_x962_import(data, data_size,
Packit aea12f
						   &pub.params[ECC_X],
Packit aea12f
						   &pub.params[ECC_Y]);
Packit aea12f
		if (ret < 0)
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
Packit aea12f
		pub.algo = group->pk;
Packit aea12f
		pub.curve = curve->id;
Packit aea12f
		pub.params_nr = 2;
Packit aea12f
Packit aea12f
		/* generate shared */
Packit aea12f
		ret = _gnutls_pk_derive_tls13(curve->pk, &session->key.key, &session->key.kshare.ecdh_params, &pub;;
Packit aea12f
		gnutls_pk_params_release(&pub;;
Packit aea12f
		if (ret < 0) {
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
		}
Packit aea12f
Packit aea12f
		ret = 0;
Packit aea12f
Packit aea12f
	} else if (group->pk == GNUTLS_PK_ECDH_X25519) {
Packit aea12f
		gnutls_pk_params_st pub;
Packit aea12f
Packit aea12f
		gnutls_pk_params_release(&session->key.kshare.ecdhx_params);
Packit aea12f
		gnutls_pk_params_init(&session->key.kshare.ecdhx_params);
Packit aea12f
Packit aea12f
		curve = _gnutls_ecc_curve_get_params(group->curve);
Packit aea12f
Packit aea12f
		if (curve->size != data_size)
Packit aea12f
			return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
Packit aea12f
Packit aea12f
		/* generate our key */
Packit aea12f
		ret = _gnutls_pk_generate_keys(curve->pk, curve->id, &session->key.kshare.ecdhx_params, 1);
Packit aea12f
		if (ret < 0)
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
Packit aea12f
		/* read the public key and generate shared */
Packit aea12f
		gnutls_pk_params_init(&pub;;
Packit aea12f
Packit aea12f
		pub.algo = group->pk;
Packit aea12f
		pub.curve = curve->id;
Packit aea12f
Packit aea12f
		pub.raw_pub.data = (void*)data;
Packit aea12f
		pub.raw_pub.size = data_size;
Packit aea12f
Packit aea12f
		/* We don't mask the MSB in the final byte as required
Packit aea12f
		 * by RFC7748. This will be done internally by nettle 3.3 or later.
Packit aea12f
		 */
Packit aea12f
		ret = _gnutls_pk_derive_tls13(curve->pk, &session->key.key, &session->key.kshare.ecdhx_params, &pub;;
Packit aea12f
		if (ret < 0) {
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
		}
Packit aea12f
Packit aea12f
		ret = 0;
Packit aea12f
Packit aea12f
	} else if (group->pk == GNUTLS_PK_DH) {
Packit aea12f
		gnutls_pk_params_st pub;
Packit aea12f
Packit aea12f
		/* we need to initialize the group parameters first */
Packit aea12f
		gnutls_pk_params_release(&session->key.kshare.dh_params);
Packit aea12f
		gnutls_pk_params_init(&session->key.kshare.dh_params);
Packit aea12f
Packit aea12f
		if (data_size != group->prime->size)
Packit aea12f
			return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
Packit aea12f
Packit aea12f
		/* set group params */
Packit aea12f
		ret = _gnutls_mpi_init_scan_nz(&session->key.kshare.dh_params.params[DH_G],
Packit aea12f
			group->generator->data, group->generator->size);
Packit aea12f
		if (ret < 0)
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
Packit aea12f
		ret = _gnutls_mpi_init_scan_nz(&session->key.kshare.dh_params.params[DH_P],
Packit aea12f
			group->prime->data, group->prime->size);
Packit aea12f
		if (ret < 0)
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
Packit aea12f
		ret = _gnutls_mpi_init_scan_nz(&session->key.kshare.dh_params.params[DH_Q],
Packit aea12f
			group->q->data, group->q->size);
Packit aea12f
		if (ret < 0)
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
Packit aea12f
		session->key.kshare.dh_params.algo = GNUTLS_PK_DH;
Packit aea12f
		session->key.kshare.dh_params.qbits = *group->q_bits;
Packit aea12f
		session->key.kshare.dh_params.params_nr = 3;
Packit aea12f
Packit aea12f
		/* generate our keys */
Packit aea12f
		ret = _gnutls_pk_generate_keys(group->pk, 0, &session->key.kshare.dh_params, 1);
Packit aea12f
		if (ret < 0)
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
Packit aea12f
		/* read the public key and generate shared */
Packit aea12f
		gnutls_pk_params_init(&pub;;
Packit aea12f
Packit aea12f
		ret = _gnutls_mpi_init_scan_nz(&pub.params[DH_Y],
Packit aea12f
			data, data_size);
Packit aea12f
		if (ret < 0)
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
Packit aea12f
		pub.algo = group->pk;
Packit aea12f
Packit aea12f
		/* generate shared key */
Packit aea12f
		ret = _gnutls_pk_derive_tls13(GNUTLS_PK_DH, &session->key.key, &session->key.kshare.dh_params, &pub;;
Packit aea12f
		_gnutls_mpi_release(&pub.params[DH_Y]);
Packit aea12f
		if (ret < 0)
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
Packit aea12f
		ret = 0;
Packit aea12f
	} else {
Packit aea12f
		return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
Packit aea12f
	}
Packit aea12f
Packit aea12f
	_gnutls_debug_log("EXT[%p]: server generated %s shared key\n", session, group->name);
Packit aea12f
Packit aea12f
	return ret;
Packit aea12f
}
Packit aea12f
Packit aea12f
/* Generates shared key and stores it in session->key.key
Packit aea12f
 */
Packit aea12f
static int
Packit aea12f
client_use_key_share(gnutls_session_t session, const gnutls_group_entry_st *group,
Packit aea12f
		     const uint8_t * data, size_t data_size)
Packit aea12f
{
Packit aea12f
	const gnutls_ecc_curve_entry_st *curve;
Packit aea12f
	int ret;
Packit aea12f
Packit aea12f
	if (group->pk == GNUTLS_PK_EC) {
Packit aea12f
		gnutls_pk_params_st pub;
Packit aea12f
Packit aea12f
		curve = _gnutls_ecc_curve_get_params(group->curve);
Packit aea12f
Packit aea12f
		gnutls_pk_params_init(&pub;;
Packit aea12f
Packit aea12f
		if (session->key.kshare.ecdh_params.algo != group->pk || session->key.kshare.ecdh_params.curve != curve->id)
Packit aea12f
			return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
Packit aea12f
Packit aea12f
		if (curve->size*2+1 != data_size)
Packit aea12f
			return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
Packit aea12f
Packit aea12f
		/* read the server's public key */
Packit aea12f
		ret = _gnutls_ecc_ansi_x962_import(data, data_size,
Packit aea12f
						   &pub.params[ECC_X],
Packit aea12f
						   &pub.params[ECC_Y]);
Packit aea12f
		if (ret < 0)
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
Packit aea12f
		pub.algo = group->pk;
Packit aea12f
		pub.curve = curve->id;
Packit aea12f
		pub.params_nr = 2;
Packit aea12f
Packit aea12f
		/* generate shared key */
Packit aea12f
		ret = _gnutls_pk_derive_tls13(curve->pk, &session->key.key, &session->key.kshare.ecdh_params, &pub;;
Packit aea12f
		gnutls_pk_params_release(&pub;;
Packit aea12f
		if (ret < 0) {
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
		}
Packit aea12f
Packit aea12f
		ret = 0;
Packit aea12f
Packit aea12f
	} else if (group->pk == GNUTLS_PK_ECDH_X25519) {
Packit aea12f
		gnutls_pk_params_st pub;
Packit aea12f
Packit aea12f
		curve = _gnutls_ecc_curve_get_params(group->curve);
Packit aea12f
Packit aea12f
		if (session->key.kshare.ecdhx_params.algo != group->pk || session->key.kshare.ecdhx_params.curve != curve->id)
Packit aea12f
			return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
Packit aea12f
Packit aea12f
		if (curve->size != data_size)
Packit aea12f
			return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
Packit aea12f
Packit aea12f
		/* read the public key and generate shared */
Packit aea12f
		gnutls_pk_params_init(&pub;;
Packit aea12f
Packit aea12f
		pub.algo = group->pk;
Packit aea12f
		pub.curve = curve->id;
Packit aea12f
Packit aea12f
		pub.raw_pub.data = (void*)data;
Packit aea12f
		pub.raw_pub.size = data_size;
Packit aea12f
Packit aea12f
		/* We don't mask the MSB in the final byte as required
Packit aea12f
		 * by RFC7748. This will be done internally by nettle 3.3 or later.
Packit aea12f
		 */
Packit aea12f
		ret = _gnutls_pk_derive_tls13(curve->pk, &session->key.key, &session->key.kshare.ecdhx_params, &pub;;
Packit aea12f
		if (ret < 0) {
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
		}
Packit aea12f
Packit aea12f
		ret = 0;
Packit aea12f
Packit aea12f
	} else if (group->pk == GNUTLS_PK_DH) {
Packit aea12f
		gnutls_pk_params_st pub;
Packit aea12f
Packit aea12f
		if (session->key.kshare.dh_params.algo != group->pk || session->key.kshare.dh_params.dh_group != group->id)
Packit aea12f
			return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
Packit aea12f
Packit aea12f
		if (data_size != group->prime->size)
Packit aea12f
			return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
Packit aea12f
Packit aea12f
		/* read the public key and generate shared */
Packit aea12f
		gnutls_pk_params_init(&pub;;
Packit aea12f
Packit aea12f
		ret = _gnutls_mpi_init_scan_nz(&pub.params[DH_Y],
Packit aea12f
			data, data_size);
Packit aea12f
		if (ret < 0)
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
Packit aea12f
		pub.algo = group->pk;
Packit aea12f
Packit aea12f
		/* generate shared key */
Packit aea12f
		ret = _gnutls_pk_derive_tls13(GNUTLS_PK_DH, &session->key.key, &session->key.kshare.dh_params, &pub;;
Packit aea12f
		_gnutls_mpi_release(&pub.params[DH_Y]);
Packit aea12f
		if (ret < 0)
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
Packit aea12f
		ret = 0;
Packit aea12f
	} else {
Packit aea12f
		return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
Packit aea12f
	}
Packit aea12f
Packit aea12f
	_gnutls_debug_log("EXT[%p]: client generated %s shared key\n", session, group->name);
Packit aea12f
Packit aea12f
	return ret;
Packit aea12f
}
Packit aea12f
Packit aea12f
static int
Packit aea12f
key_share_recv_params(gnutls_session_t session,
Packit 5407aa
		      const uint8_t * data, size_t data_size)
Packit aea12f
{
Packit aea12f
	int ret;
Packit 5407aa
	size_t size;
Packit aea12f
	unsigned gid;
Packit aea12f
	const version_entry_st *ver;
Packit aea12f
	const gnutls_group_entry_st *group;
Packit aea12f
	unsigned used_share = 0;
Packit aea12f
Packit aea12f
	if (session->security_parameters.entity == GNUTLS_SERVER) {
Packit aea12f
		ver = get_version(session);
Packit aea12f
		if (ver == NULL || ver->key_shares == 0)
Packit aea12f
			return gnutls_assert_val(0);
Packit aea12f
Packit aea12f
		DECR_LEN(data_size, 2);
Packit aea12f
		size = _gnutls_read_uint16(data);
Packit aea12f
		data += 2;
Packit aea12f
Packit aea12f
		if (data_size != size)
Packit aea12f
			return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
Packit aea12f
Packit aea12f
		/* if we do PSK without DH ignore that share */
Packit aea12f
		if ((session->internals.hsk_flags & HSK_PSK_SELECTED) &&
Packit aea12f
		    (session->internals.hsk_flags & HSK_PSK_KE_MODE_PSK)) {
Packit aea12f
			reset_cand_groups(session);
Packit aea12f
			return 0;
Packit aea12f
		}
Packit aea12f
Packit aea12f
		while(data_size > 0) {
Packit aea12f
			DECR_LEN(data_size, 2);
Packit aea12f
			gid = _gnutls_read_uint16(data);
Packit aea12f
			data += 2;
Packit aea12f
Packit aea12f
			DECR_LEN(data_size, 2);
Packit aea12f
			size = _gnutls_read_uint16(data);
Packit aea12f
			data += 2;
Packit aea12f
Packit aea12f
			DECR_LEN(data_size, size);
Packit aea12f
Packit aea12f
			/* at this point we have already negotiated a group;
Packit aea12f
			 * find the group's share. */
Packit aea12f
			group = _gnutls_tls_id_to_group(gid);
Packit aea12f
Packit aea12f
			if (group != NULL)
Packit aea12f
				_gnutls_handshake_log("EXT[%p]: Received key share for %s\n", session, group->name);
Packit aea12f
Packit aea12f
			if (group != NULL && group == session->internals.cand_group) {
Packit aea12f
				_gnutls_session_group_set(session, group);
Packit aea12f
Packit aea12f
				ret = server_use_key_share(session, group, data, size);
Packit aea12f
				if (ret < 0)
Packit aea12f
					return gnutls_assert_val(ret);
Packit aea12f
Packit aea12f
				used_share = 1;
Packit aea12f
				break;
Packit aea12f
Packit aea12f
			}
Packit aea12f
Packit aea12f
			data += size;
Packit aea12f
			continue;
Packit aea12f
		}
Packit aea12f
Packit aea12f
		/* we utilize GNUTLS_E_NO_COMMON_KEY_SHARE for:
Packit aea12f
		 * 1. signal for hello-retry-request in the handshake
Packit aea12f
		 *    layer during first client hello parsing (server side - here).
Packit aea12f
		 *    This does not result to error code being
Packit aea12f
		 *    propagated to app layer.
Packit aea12f
		 * 2. Propagate to application error code that no
Packit aea12f
		 *    common key share was found after an HRR was
Packit aea12f
		 *    received (client side)
Packit aea12f
		 * 3. Propagate to application error code that no
Packit aea12f
		 *    common key share was found after an HRR was
Packit aea12f
		 *    sent (server side).
Packit aea12f
		 * In cases (2,3) the error is translated to illegal
Packit aea12f
		 * parameter alert.
Packit aea12f
		 */
Packit aea12f
		if (used_share == 0) {
Packit aea12f
			return gnutls_assert_val(GNUTLS_E_NO_COMMON_KEY_SHARE);
Packit aea12f
		}
Packit aea12f
Packit aea12f
		session->internals.hsk_flags |= HSK_KEY_SHARE_RECEIVED;
Packit aea12f
	} else { /* Client */
Packit aea12f
		ver = get_version(session);
Packit aea12f
		if (unlikely(ver == NULL || ver->key_shares == 0))
Packit aea12f
			return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
Packit aea12f
Packit aea12f
		if (_gnutls_ext_get_msg(session) == GNUTLS_EXT_FLAG_HRR) {
Packit aea12f
			if (unlikely(!(session->internals.hsk_flags & HSK_HRR_RECEIVED)))
Packit aea12f
				return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
Packit aea12f
Packit aea12f
			DECR_LEN(data_size, 2);
Packit aea12f
			gid = _gnutls_read_uint16(data);
Packit aea12f
Packit aea12f
			group = _gnutls_tls_id_to_group(gid);
Packit aea12f
			if (group == NULL)
Packit aea12f
				return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
Packit aea12f
Packit aea12f
			_gnutls_handshake_log("EXT[%p]: HRR key share with %s\n", session, group->name);
Packit aea12f
Packit aea12f
			/* check if we support it */
Packit aea12f
			ret = _gnutls_session_supports_group(session, group->id);
Packit aea12f
			if (ret < 0) {
Packit aea12f
				_gnutls_handshake_log("EXT[%p]: received share for %s which is disabled\n", session, group->name);
Packit aea12f
				return gnutls_assert_val(ret);
Packit aea12f
			}
Packit aea12f
Packit aea12f
			_gnutls_session_group_set(session, group);
Packit aea12f
Packit aea12f
			return 0;
Packit aea12f
		}
Packit aea12f
		/* else */
Packit aea12f
Packit aea12f
		DECR_LEN(data_size, 2);
Packit aea12f
		gid = _gnutls_read_uint16(data);
Packit aea12f
		data += 2;
Packit aea12f
Packit aea12f
		DECR_LEN(data_size, 2);
Packit aea12f
		size = _gnutls_read_uint16(data);
Packit aea12f
		data+=2;
Packit aea12f
Packit aea12f
		if (data_size != size)
Packit aea12f
			return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
Packit aea12f
Packit aea12f
		group = _gnutls_tls_id_to_group(gid);
Packit aea12f
		if (group == NULL)
Packit aea12f
			return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
Packit aea12f
Packit aea12f
		/* check if we support it */
Packit aea12f
		ret = _gnutls_session_supports_group(session, group->id);
Packit aea12f
		if (ret < 0) {
Packit aea12f
			_gnutls_handshake_log("EXT[%p]: received share for %s which is disabled\n", session, group->name);
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
		}
Packit aea12f
Packit aea12f
		_gnutls_session_group_set(session, group);
Packit aea12f
		session->internals.hsk_flags |= HSK_KEY_SHARE_RECEIVED;
Packit aea12f
Packit aea12f
		ret = client_use_key_share(session, group, data, size);
Packit aea12f
		if (ret < 0)
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
	}
Packit aea12f
Packit aea12f
	return 0;
Packit aea12f
}
Packit aea12f
Packit aea12f
/* returns data_size or a negative number on failure
Packit aea12f
 */
Packit aea12f
static int
Packit aea12f
key_share_send_params(gnutls_session_t session,
Packit aea12f
		      gnutls_buffer_st * extdata)
Packit aea12f
{
Packit aea12f
	unsigned i;
Packit aea12f
	int ret;
Packit aea12f
	unsigned char *lengthp;
Packit aea12f
	unsigned int cur_length;
Packit aea12f
	unsigned int generated = 0;
Packit aea12f
	const gnutls_group_entry_st *group;
Packit aea12f
	const version_entry_st *ver;
Packit aea12f
Packit aea12f
	/* this extension is only being sent on client side */
Packit aea12f
	if (session->security_parameters.entity == GNUTLS_CLIENT) {
Packit aea12f
		ver = _gnutls_version_max(session);
Packit aea12f
		if (unlikely(ver == NULL || ver->key_shares == 0))
Packit aea12f
			return 0;
Packit aea12f
Packit aea12f
		if (!have_creds_for_tls13(session))
Packit aea12f
			return 0;
Packit aea12f
Packit aea12f
		/* write the total length later */
Packit aea12f
		lengthp = &extdata->data[extdata->length];
Packit aea12f
Packit aea12f
		ret =
Packit aea12f
		    _gnutls_buffer_append_prefix(extdata, 16, 0);
Packit aea12f
		if (ret < 0)
Packit aea12f
			return gnutls_assert_val(ret);
Packit aea12f
Packit aea12f
		cur_length = extdata->length;
Packit aea12f
Packit aea12f
		if (session->internals.hsk_flags & HSK_HRR_RECEIVED) { /* we know the group */
Packit aea12f
			group = get_group(session);
Packit aea12f
			if (unlikely(group == NULL))
Packit aea12f
				return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
Packit aea12f
Packit aea12f
			ret = client_gen_key_share(session, group, extdata);
Packit aea12f
			if (ret == GNUTLS_E_INT_RET_0)
Packit aea12f
				return gnutls_assert_val(GNUTLS_E_NO_COMMON_KEY_SHARE);
Packit aea12f
			if (ret < 0)
Packit aea12f
				return gnutls_assert_val(ret);
Packit aea12f
		} else {
Packit aea12f
			gnutls_pk_algorithm_t selected_groups[3];
Packit aea12f
			unsigned max_groups = 2; /* GNUTLS_KEY_SHARE_TOP2 */
Packit aea12f
Packit aea12f
			if (session->internals.flags & GNUTLS_KEY_SHARE_TOP)
Packit aea12f
				max_groups = 1;
Packit aea12f
			else if (session->internals.flags & GNUTLS_KEY_SHARE_TOP3)
Packit aea12f
				max_groups = 3;
Packit aea12f
Packit aea12f
			assert(max_groups <= sizeof(selected_groups)/sizeof(selected_groups[0]));
Packit aea12f
Packit aea12f
			/* generate key shares for out top-(max_groups) groups
Packit aea12f
			 * if they are of different PK type. */
Packit aea12f
			for (i = 0; i < session->internals.priorities->groups.size; i++) {
Packit aea12f
				group = session->internals.priorities->groups.entry[i];
Packit aea12f
Packit aea12f
				if (generated == 1 && group->pk == selected_groups[0])
Packit aea12f
					continue;
Packit aea12f
				else if (generated == 2 && (group->pk == selected_groups[1] || group->pk == selected_groups[0]))
Packit aea12f
					continue;
Packit aea12f
Packit aea12f
				selected_groups[generated] = group->pk;
Packit aea12f
Packit aea12f
				ret = client_gen_key_share(session, group, extdata);
Packit aea12f
				if (ret == GNUTLS_E_INT_RET_0)
Packit aea12f
					continue; /* no key share for this algorithm */
Packit aea12f
				if (ret < 0)
Packit aea12f
					return gnutls_assert_val(ret);
Packit aea12f
Packit aea12f
				generated++;
Packit aea12f
Packit aea12f
				if (generated >= max_groups)
Packit aea12f
					break;
Packit aea12f
			}
Packit aea12f
		}
Packit aea12f
Packit aea12f
		/* copy actual length */
Packit aea12f
		_gnutls_write_uint16(extdata->length - cur_length, lengthp);
Packit aea12f
Packit aea12f
	} else { /* server */
Packit aea12f
		ver = get_version(session);
Packit aea12f
		if (unlikely(ver == NULL || ver->key_shares == 0))
Packit aea12f
			return gnutls_assert_val(0);
Packit aea12f
Packit aea12f
		if (_gnutls_ext_get_msg(session) == GNUTLS_EXT_FLAG_HRR) {
Packit aea12f
			group = session->internals.cand_group;
Packit aea12f
Packit aea12f
			if (group == NULL)
Packit aea12f
				return gnutls_assert_val(GNUTLS_E_NO_COMMON_KEY_SHARE);
Packit aea12f
Packit aea12f
			_gnutls_session_group_set(session, group);
Packit aea12f
Packit aea12f
			_gnutls_handshake_log("EXT[%p]: requesting retry with group %s\n", session, group->name);
Packit aea12f
			ret =
Packit aea12f
			    _gnutls_buffer_append_prefix(extdata, 16, group->tls_id);
Packit aea12f
			if (ret < 0)
Packit aea12f
				return gnutls_assert_val(ret);
Packit aea12f
		} else {
Packit aea12f
			/* if we are negotiating PSK without DH, do not send a key share */
Packit aea12f
			if ((session->internals.hsk_flags & HSK_PSK_SELECTED) &&
Packit aea12f
			    (session->internals.hsk_flags & HSK_PSK_KE_MODE_PSK))
Packit aea12f
				return gnutls_assert_val(0);
Packit aea12f
Packit aea12f
			group = get_group(session);
Packit aea12f
			if (unlikely(group == NULL))
Packit aea12f
				return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
Packit aea12f
Packit aea12f
			ret = server_gen_key_share(session, group, extdata);
Packit aea12f
			if (ret < 0)
Packit aea12f
				return gnutls_assert_val(ret);
Packit aea12f
		}
Packit aea12f
Packit aea12f
		session->internals.hsk_flags |= HSK_KEY_SHARE_SENT;
Packit aea12f
	}
Packit aea12f
Packit aea12f
	return 0;
Packit aea12f
}