break;
case GNUTLS_E_DH_PRIME_UNACCEPTABLE:
case GNUTLS_E_SESSION_USER_ID_CHANGED:
+ case GNUTLS_E_INSUFFICIENT_SECURITY:
ret = GNUTLS_A_INSUFFICIENT_SECURITY;
_level = GNUTLS_AL_FATAL;
break;
unsigned _gnutls_version_is_too_high(gnutls_session_t session, uint8_t major, uint8_t minor);
/* Functions for feature checks */
-const gnutls_cipher_suite_entry_st *
+int
_gnutls_figure_common_ciphersuite(gnutls_session_t session,
- const ciphersuite_list_st *peer_clist);
+ const ciphersuite_list_st *peer_clist,
+ const gnutls_cipher_suite_entry_st **ce);
inline static int
_gnutls_version_has_selectable_prf(const version_entry_st * ver)
bool _gnutls_pk_is_not_prehashed(gnutls_pk_algorithm_t algorithm);
/* ECC */
-struct gnutls_ecc_curve_entry_st {
+typedef struct gnutls_ecc_curve_entry_st {
const char *name;
const char *oid;
gnutls_ecc_curve_t id;
gnutls_pk_algorithm_t pk;
- int tls_id; /* The RFC4492 namedCurve ID */
unsigned size; /* the size in bytes */
unsigned sig_size; /* the size of curve signatures in bytes (EdDSA) */
-};
-typedef struct gnutls_ecc_curve_entry_st gnutls_ecc_curve_entry_st;
+} gnutls_ecc_curve_entry_st;
const gnutls_ecc_curve_entry_st
*_gnutls_ecc_curve_get_params(gnutls_ecc_curve_t curve);
-gnutls_ecc_curve_t gnutls_ecc_curve_get_id(const char *name);
-int _gnutls_tls_id_to_ecc_curve(int num);
-int _gnutls_ecc_curve_get_tls_id(gnutls_ecc_curve_t supported_ecc);
+
+const gnutls_group_entry_st *_gnutls_tls_id_to_group(unsigned num);
+const gnutls_group_entry_st * _gnutls_id_to_group(unsigned id);
+
+inline static const gnutls_ecc_curve_entry_st
+ *_gnutls_group_get_curve_params(gnutls_group_t group)
+{
+ const gnutls_group_entry_st *e = _gnutls_id_to_group(group);
+ if (e)
+ return _gnutls_ecc_curve_get_params(e->curve);
+ return NULL;
+}
+
gnutls_ecc_curve_t _gnutls_ecc_bits_to_curve(gnutls_pk_algorithm_t pk, int bits);
#define MAX_ECC_CURVE_SIZE 66
return 0;
}
+static inline int _gnutls_kx_is_dhe(gnutls_kx_algorithm_t kx)
+{
+ if (kx == GNUTLS_KX_DHE_RSA || kx == GNUTLS_KX_DHE_DSS ||
+ kx == GNUTLS_KX_ANON_DH || kx == GNUTLS_KX_DHE_PSK)
+ return 1;
+
+ return 0;
+}
+
static inline int _sig_is_ecdsa(gnutls_sign_algorithm_t sig)
{
if (sig == GNUTLS_SIGN_ECDSA_SHA1 || sig == GNUTLS_SIGN_ECDSA_SHA224 ||
noinst_LTLIBRARIES = libgnutls_alg.la
libgnutls_alg_la_SOURCES = cert_types.c ciphers.c ciphersuites.c \
- ecc.c kx.c mac.c protocols.c publickey.c secparams.c sign.c
+ ecc.c kx.c mac.c protocols.c publickey.c secparams.c sign.c \
+ groups.c
unsigned cred_type,
gnutls_kx_algorithm_t kx)
{
- gnutls_dh_params_t dh_params = NULL;
+ unsigned have_dh_params = 0;
if (!_gnutls_kx_needs_dh_params(kx)) {
return 1;
}
+ if (session->internals.have_ffdhe) {
+ /* if the client has advertized FFDHE then it doesn't matter
+ * whether we have server DH parameters. They are no good. */
+ gnutls_assert();
+ return 0;
+ }
+
/* Read the Diffie-Hellman parameters, if any.
*/
if (cred_type == GNUTLS_CRD_CERTIFICATE) {
(gnutls_certificate_credentials_t)
_gnutls_get_cred(session, cred_type);
- if (x509_cred != NULL) {
- dh_params =
- _gnutls_get_dh_params(x509_cred->dh_params,
- x509_cred->params_func,
- session);
+ if (x509_cred != NULL && (x509_cred->dh_params || x509_cred->params_func || x509_cred->dh_sec_param)) {
+ have_dh_params = 1;
}
#ifdef ENABLE_ANON
(gnutls_anon_server_credentials_t)
_gnutls_get_cred(session, cred_type);
- if (anon_cred != NULL) {
- dh_params =
- _gnutls_get_dh_params(anon_cred->dh_params,
- anon_cred->params_func,
- session);
+ if (anon_cred != NULL && (anon_cred->dh_params || anon_cred->params_func || anon_cred->dh_sec_param)) {
+ have_dh_params = 1;
}
#endif
#ifdef ENABLE_PSK
(gnutls_psk_server_credentials_t)
_gnutls_get_cred(session, cred_type);
- if (psk_cred != NULL) {
- dh_params =
- _gnutls_get_dh_params(psk_cred->dh_params,
- psk_cred->params_func,
- session);
+ if (psk_cred != NULL && (psk_cred->dh_params || psk_cred->params_func || psk_cred->dh_sec_param)) {
+ have_dh_params = 1;
}
#endif
} else {
return 1; /* no need for params */
}
- /* If DH params are not set then fail.
- */
- if (_gnutls_dh_params_to_mpi(dh_params) == NULL) {
- gnutls_assert();
- return 0;
- }
-
- return 1;
+ return have_dh_params;
}
/**
} \
}
-#define KX_CHECKS(kx, cred_type, action) \
+#define KX_CHECKS(kx, group, cred_type, action) \
{ \
- if (_gnutls_session_ecc_curve_get(session) == GNUTLS_ECC_CURVE_INVALID && \
- _gnutls_kx_is_ecc(kx)) { \
- action; \
+ if (_gnutls_kx_is_ecc(kx)) { \
+ if (group == NULL || group->curve == 0) { \
+ action; \
+ } \
+ } else if (_gnutls_kx_is_dhe(kx)) { \
+ if (group == NULL || !group->prime) { \
+ if (!check_server_dh_params(session, cred_type, kx)) { \
+ action; \
+ } \
+ } \
} \
KX_SRP_CHECKS(kx, action); \
- if (!check_server_dh_params(session, cred_type, kx)) { \
- action; \
- } \
}
-const gnutls_cipher_suite_entry_st *
+int
_gnutls_figure_common_ciphersuite(gnutls_session_t session,
- const ciphersuite_list_st *peer_clist)
+ const ciphersuite_list_st *peer_clist,
+ const gnutls_cipher_suite_entry_st **ce)
{
unsigned int i, j;
int ret;
const version_entry_st *version = get_version(session);
unsigned int is_dtls = IS_DTLS(session), kx, cred_type;
+ unsigned int no_cert_found = 0;
+ const gnutls_group_entry_st *group;
if (version == NULL) {
- gnutls_assert();
- return NULL;
+ return gnutls_assert_val(GNUTLS_E_NO_CIPHER_SUITES);
}
+ group = _gnutls_id_to_group(_gnutls_session_group_get(session));
+
if (session->internals.priorities->server_precedence == 0) {
for (i = 0; i < peer_clist->size; i++) {
_gnutls_debug_log("checking %.2x.%.2x (%s) for compatibility\n",
for (j = 0; j < session->internals.priorities->cs.size; j++) {
if (session->internals.priorities->cs.entry[j] == peer_clist->entry[i]) {
- KX_CHECKS(kx, cred_type, continue);
+ KX_CHECKS(kx, group, cred_type, continue);
if (cred_type == GNUTLS_CRD_CERTIFICATE) {
ret = _gnutls_server_select_cert(session, peer_clist->entry[i]);
if (ret < 0) {
/* couldn't select cert with this ciphersuite */
gnutls_assert();
+ no_cert_found = 1;
break;
}
}
- return peer_clist->entry[i];
+ *ce = peer_clist->entry[i];
+ return 0;
}
}
}
kx = peer_clist->entry[i]->kx_algorithm;
cred_type = _gnutls_map_kx_get_cred(kx, 1);
- KX_CHECKS(kx, cred_type, break);
+ KX_CHECKS(kx, group, cred_type, break);
if (cred_type == GNUTLS_CRD_CERTIFICATE) {
ret = _gnutls_server_select_cert(session, peer_clist->entry[i]);
if (ret < 0) {
/* couldn't select cert with this ciphersuite */
gnutls_assert();
+ no_cert_found = 1;
break;
}
}
- return peer_clist->entry[i];
+ *ce = peer_clist->entry[i];
+ return 0;
}
}
}
}
/* nothing in common */
- gnutls_assert();
- return NULL;
+
+ /* RFC7919 requires that we reply with insufficient security if we have
+ * negotiated an FFDHE group, but cannot find a common ciphersuite. However,
+ * we must also distinguish between not matching a ciphersuite due to an
+ * incompatible certificate which we traditionally return GNUTLS_E_INSUFFICIENT_SECURITY.
+ */
+ if (!no_cert_found && session->internals.have_ffdhe && session->internals.priorities->groups.have_ffdhe)
+ return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_SECURITY);
+ else
+ return gnutls_assert_val(GNUTLS_E_NO_CIPHER_SUITES);
}
#define CLIENT_VERSION_CHECK(minver, maxver, e) \
.name = "SECP192R1",
.oid = "1.2.840.10045.3.1.1",
.id = GNUTLS_ECC_CURVE_SECP192R1,
- .tls_id = 19,
.pk = GNUTLS_PK_ECDSA,
.size = 24,
},
.name = "SECP224R1",
.oid = "1.3.132.0.33",
.id = GNUTLS_ECC_CURVE_SECP224R1,
- .tls_id = 21,
.pk = GNUTLS_PK_ECDSA,
.size = 28,
},
.name = "SECP256R1",
.oid = "1.2.840.10045.3.1.7",
.id = GNUTLS_ECC_CURVE_SECP256R1,
- .tls_id = 23,
.pk = GNUTLS_PK_ECDSA,
.size = 32,
},
.name = "SECP384R1",
.oid = "1.3.132.0.34",
.id = GNUTLS_ECC_CURVE_SECP384R1,
- .tls_id = 24,
.pk = GNUTLS_PK_ECDSA,
.size = 48,
},
.name = "SECP521R1",
.oid = "1.3.132.0.35",
.id = GNUTLS_ECC_CURVE_SECP521R1,
- .tls_id = 25,
.pk = GNUTLS_PK_ECDSA,
.size = 66,
},
{
.name = "X25519",
.id = GNUTLS_ECC_CURVE_X25519,
- .tls_id = 29,
.pk = GNUTLS_PK_ECDH_X25519,
.size = 32,
},
for(p = ecc_curves; p->name != NULL; p++) { b ; } }
-/* Returns the TLS id of the given curve
- */
-int _gnutls_tls_id_to_ecc_curve(int num)
-{
- gnutls_ecc_curve_t ret = GNUTLS_ECC_CURVE_INVALID;
-
- GNUTLS_ECC_CURVE_LOOP(
- if (p->tls_id == num && _gnutls_pk_curve_exists(p->id)) {
- ret = p->id;
- break;
- }
- );
-
- return ret;
-}
-
/**
* gnutls_ecc_curve_list:
*
return supported_curves;
}
-/* Maps numbers to TLS NamedCurve IDs (RFC4492).
- * Returns a negative number on error.
- */
-int _gnutls_ecc_curve_get_tls_id(gnutls_ecc_curve_t supported_ecc)
-{
- int ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
-
- GNUTLS_ECC_CURVE_LOOP(
- if (p->id == supported_ecc) {
- ret = p->tls_id;
- break;
- }
- );
-
- return ret;
-}
-
/**
* gnutls_oid_to_ecc_curve:
* @oid: is a curve's OID
--- /dev/null
+/*
+ * Copyright (C) 2017 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+#include "gnutls_int.h"
+#include <algorithms.h>
+#include "errors.h"
+#include <x509/common.h>
+#include <pk.h>
+
+/* Supported ECC curves
+ */
+
+static const gnutls_group_entry_st supported_groups[] = {
+ {
+ .name = "SECP192R1",
+ .id = GNUTLS_GROUP_SECP192R1,
+ .curve = GNUTLS_ECC_CURVE_SECP192R1,
+ .tls_id = 19,
+ .pk = GNUTLS_PK_ECDSA,
+ },
+ {
+ .name = "SECP224R1",
+ .id = GNUTLS_GROUP_SECP224R1,
+ .curve = GNUTLS_ECC_CURVE_SECP224R1,
+ .tls_id = 21,
+ .pk = GNUTLS_PK_ECDSA,
+ },
+ {
+ .name = "SECP256R1",
+ .id = GNUTLS_GROUP_SECP256R1,
+ .curve = GNUTLS_ECC_CURVE_SECP256R1,
+ .tls_id = 23,
+ .pk = GNUTLS_PK_ECDSA,
+ },
+ {
+ .name = "SECP384R1",
+ .id = GNUTLS_GROUP_SECP384R1,
+ .curve = GNUTLS_ECC_CURVE_SECP384R1,
+ .tls_id = 24,
+ .pk = GNUTLS_PK_ECDSA,
+ },
+ {
+ .name = "SECP521R1",
+ .id = GNUTLS_GROUP_SECP521R1,
+ .curve = GNUTLS_ECC_CURVE_SECP521R1,
+ .tls_id = 25,
+ .pk = GNUTLS_PK_ECDSA,
+ },
+ {
+ .name = "X25519",
+ .id = GNUTLS_GROUP_X25519,
+ .curve = GNUTLS_ECC_CURVE_X25519,
+ .tls_id = 29,
+ .pk = GNUTLS_PK_ECDH_X25519
+ },
+#ifdef ENABLE_DHE
+ {
+ .name = "FFDHE2048",
+ .id = GNUTLS_GROUP_FFDHE2048,
+ .generator = &gnutls_ffdhe_2048_group_generator,
+ .prime = &gnutls_ffdhe_2048_group_prime,
+ .q_bits = &gnutls_ffdhe_2048_key_bits,
+ .pk = GNUTLS_PK_DH,
+ .tls_id = 0x100
+ },
+ {
+ .name = "FFDHE3072",
+ .id = GNUTLS_GROUP_FFDHE3072,
+ .generator = &gnutls_ffdhe_3072_group_generator,
+ .prime = &gnutls_ffdhe_3072_group_prime,
+ .q_bits = &gnutls_ffdhe_3072_key_bits,
+ .pk = GNUTLS_PK_DH,
+ .tls_id = 0x101
+ },
+ {
+ .name = "FFDHE4096",
+ .id = GNUTLS_GROUP_FFDHE4096,
+ .generator = &gnutls_ffdhe_4096_group_generator,
+ .prime = &gnutls_ffdhe_4096_group_prime,
+ .q_bits = &gnutls_ffdhe_4096_key_bits,
+ .pk = GNUTLS_PK_DH,
+ .tls_id = 0x102
+ },
+ {
+ .name = "FFDHE8192",
+ .id = GNUTLS_GROUP_FFDHE8192,
+ .generator = &gnutls_ffdhe_8192_group_generator,
+ .prime = &gnutls_ffdhe_8192_group_prime,
+ .q_bits = &gnutls_ffdhe_8192_key_bits,
+ .pk = GNUTLS_PK_DH,
+ .tls_id = 0x104
+ },
+#endif
+ {0, 0, 0}
+};
+
+#define GNUTLS_GROUP_LOOP(b) \
+ { const gnutls_group_entry_st *p; \
+ for(p = supported_groups; p->name != NULL; p++) { b ; } }
+
+
+/* Returns the TLS id of the given curve
+ */
+const gnutls_group_entry_st * _gnutls_tls_id_to_group(unsigned num)
+{
+ GNUTLS_GROUP_LOOP(
+ if (p->tls_id == num &&
+ (p->curve == 0 || _gnutls_pk_curve_exists(p->curve))) {
+ return p;
+ }
+ );
+
+ return NULL;
+}
+
+const gnutls_group_entry_st * _gnutls_id_to_group(unsigned id)
+{
+ if (id == 0)
+ return NULL;
+
+ GNUTLS_GROUP_LOOP(
+ if (p->id == id &&
+ (p->curve == 0 || _gnutls_pk_curve_exists(p->curve))) {
+ return p;
+ }
+ );
+
+ return NULL;
+}
+
+/**
+ * gnutls_group_list:
+ *
+ * Get the list of supported elliptic curves.
+ *
+ * This function is not thread safe.
+ *
+ * Returns: Return a (0)-terminated list of #gnutls_group_t
+ * integers indicating the available groups.
+ *
+ * Since: 3.6.0
+ **/
+const gnutls_group_t *gnutls_group_list(void)
+{
+ static gnutls_group_t groups[MAX_ALGOS] = { 0 };
+
+ if (groups[0] == 0) {
+ int i = 0;
+
+ GNUTLS_GROUP_LOOP(
+ if (p->curve == 0 || _gnutls_pk_curve_exists(p->curve))
+ groups[i++] = p->id;
+ );
+ groups[i++] = 0;
+ }
+
+ return groups;
+}
+
+/**
+ * gnutls_group_get_id:
+ * @name: is a group name
+ *
+ * The names are compared in a case insensitive way.
+ *
+ * Returns: return a #gnutls_group_t value corresponding to
+ * the specified group, or %GNUTLS_GROUP_INVALID on error.
+ *
+ * Since: 3.6.0
+ **/
+gnutls_group_t gnutls_group_get_id(const char *name)
+{
+ gnutls_group_t ret = GNUTLS_GROUP_INVALID;
+
+ GNUTLS_GROUP_LOOP(
+ if (strcasecmp(p->name, name) == 0 && (
+ p->curve == 0 ||_gnutls_pk_curve_exists(p->curve))) {
+ ret = p->id;
+ break;
+ }
+ );
+
+ return ret;
+}
+
+/**
+ * gnutls_group_get_name:
+ * @group: is an element from %gnutls_group_t
+ *
+ * Convert a #gnutls_group_t value to a string.
+ *
+ * Returns: a string that contains the name of the specified
+ * group or %NULL.
+ *
+ * Since: 3.6.0
+ **/
+const char *gnutls_group_get_name(gnutls_group_t group)
+{
+ GNUTLS_GROUP_LOOP(
+ if (p->id == group) {
+ return p->name;
+ }
+ );
+
+ return NULL;
+}
GNUTLS_KX_ALG_LOOP(ret = p->false_start; needs_dh = p->needs_dh_params);
if (ret != 0) {
+ const gnutls_group_entry_st *e;
+
+ e = _gnutls_id_to_group(session->security_parameters.group);
+
#if defined(ENABLE_DHE) || defined(ENABLE_ANON)
if (needs_dh != 0) {
bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, GNUTLS_SEC_PARAM_HIGH);
/* check whether sizes are sufficient */
- if (gnutls_dh_get_prime_bits(session) < bits)
+ if (e && e->prime) {
+ if (e->prime->size*8 < (unsigned)bits)
+ ret = 0;
+ } else if (gnutls_dh_get_prime_bits(session) < bits)
ret = 0;
} else
#endif
if (algorithm == GNUTLS_KX_ECDHE_RSA || algorithm == GNUTLS_KX_ECDHE_ECDSA) {
bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_EC, GNUTLS_SEC_PARAM_HIGH);
- if (gnutls_ecc_curve_get_size(session->security_parameters.ecc_curve) * 8 < bits)
+ if (e != NULL && gnutls_ecc_curve_get_size(e->curve) * 8 < bits)
ret = 0;
}
}
}
res->dh_params = dh_params;
+ res->dh_sec_param = gnutls_pk_bits_to_sec_param(GNUTLS_PK_DH, _gnutls_mpi_get_nbits(dh_params->params[0]));
}
/**
gnutls_anon_set_server_known_dh_params(gnutls_anon_server_credentials_t res,
gnutls_sec_param_t sec_param)
{
- int ret;
-
- if (res->deinit_dh_params) {
- res->deinit_dh_params = 0;
- gnutls_dh_params_deinit(res->dh_params);
- res->dh_params = NULL;
- }
-
- ret = _gnutls_set_cred_dh_params(&res->dh_params, sec_param);
- if (ret < 0)
- return gnutls_assert_val(ret);
-
- res->deinit_dh_params = 1;
+ res->dh_sec_param = sec_param;
return 0;
}
/*
* Copyright (C) 2000-2012 Free Software Foundation, Inc.
+ * Copyright (C) 2017 Red Hat, Inc.
*
* Author: Nikos Mavrogiannopoulos
*
static int
gen_anon_server_kx(gnutls_session_t session, gnutls_buffer_st * data)
{
- bigint_t g, p;
- const bigint_t *mpis;
int ret;
- gnutls_dh_params_t dh_params;
gnutls_anon_server_credentials_t cred;
cred = (gnutls_anon_server_credentials_t)
return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
}
- dh_params =
- _gnutls_get_dh_params(cred->dh_params, cred->params_func,
- session);
- mpis = _gnutls_dh_params_to_mpi(dh_params);
- if (mpis == NULL) {
- gnutls_assert();
- return GNUTLS_E_NO_TEMPORARY_DH_PARAMS;
- }
-
- p = mpis[0];
- g = mpis[1];
-
if ((ret =
_gnutls_auth_info_set(session, GNUTLS_CRD_ANON,
sizeof(anon_auth_info_st), 1)) < 0) {
return ret;
}
- _gnutls_dh_set_group(session, g, p);
-
- ret = _gnutls_set_dh_pk_params(session, g, p, dh_params->q_bits);
- if (ret < 0)
+ ret = _gnutls_figure_dh_params(session, cred->dh_params, cred->params_func, cred->dh_sec_param);
+ if (ret < 0) {
return gnutls_assert_val(ret);
+ }
ret =
_gnutls_dh_common_print_server_kx(session, data);
proc_anon_client_kx(gnutls_session_t session, uint8_t * data,
size_t _data_size)
{
- gnutls_anon_server_credentials_t cred;
- int ret;
- bigint_t p, g;
- gnutls_dh_params_t dh_params;
- const bigint_t *mpis;
-
- cred = (gnutls_anon_server_credentials_t)
- _gnutls_get_cred(session, GNUTLS_CRD_ANON);
- if (cred == NULL) {
- gnutls_assert();
- return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
- }
-
- dh_params =
- _gnutls_get_dh_params(cred->dh_params, cred->params_func,
- session);
- mpis = _gnutls_dh_params_to_mpi(dh_params);
- if (mpis == NULL) {
- gnutls_assert();
- return GNUTLS_E_NO_TEMPORARY_DH_PARAMS;
- }
-
- p = mpis[0];
- g = mpis[1];
-
- ret =
- _gnutls_proc_dh_common_client_kx(session, data, _data_size, g,
- p, NULL);
-
- return ret;
+ return
+ _gnutls_proc_dh_common_client_kx(session, data, _data_size, NULL);
}
typedef struct gnutls_anon_server_credentials_st {
gnutls_dh_params_t dh_params;
unsigned deinit_dh_params;
+ gnutls_sec_param_t dh_sec_param;
/* this callback is used to retrieve the DH or RSA
* parameters.
ret =
_gnutls_ecdh_common_print_server_kx(session, data,
- _gnutls_session_ecc_curve_get
+ _gnutls_session_group_get
(session));
if (ret < 0) {
gnutls_assert();
return _gnutls_proc_ecdh_common_client_kx(session, data,
_data_size,
- _gnutls_session_ecc_curve_get
+ _gnutls_session_group_get
(session), NULL);
}
typedef struct gnutls_certificate_credentials_st {
gnutls_dh_params_t dh_params;
unsigned deinit_dh_params; /* if the internal values are set */
+ gnutls_sec_param_t dh_sec_param; /* used in RFC7919 negotiation */
/* this callback is used to retrieve the DH or RSA
* parameters.
int
_gnutls_proc_dh_common_client_kx(gnutls_session_t session,
uint8_t * data, size_t _data_size,
- bigint_t g, bigint_t p,
gnutls_datum_t * psk_key)
{
uint16_t n_Y;
return ret;
}
-int _gnutls_set_dh_pk_params(gnutls_session_t session, bigint_t g, bigint_t p,
- unsigned q_bits)
-{
- /* just in case we are resuming a session */
- gnutls_pk_params_release(&session->key.dh_params);
-
- gnutls_pk_params_init(&session->key.dh_params);
-
- session->key.dh_params.params[DH_G] = _gnutls_mpi_copy(g);
- if (session->key.dh_params.params[DH_G] == NULL)
- return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
-
- session->key.dh_params.params[DH_P] = _gnutls_mpi_copy(p);
- if (session->key.dh_params.params[DH_P] == NULL) {
- _gnutls_mpi_release(&session->key.dh_params.params[DH_G]);
- return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
- }
-
- session->key.dh_params.params_nr = 3; /* include empty q */
- session->key.dh_params.algo = GNUTLS_PK_DH;
- session->key.dh_params.flags = q_bits;
-
- return 0;
-}
-
/* Returns the bytes parsed */
int
_gnutls_proc_dh_common_server_kx(gnutls_session_t session,
uint8_t *data_g;
uint8_t *data_Y;
int i, bits, ret, p_bits;
+ unsigned j;
ssize_t data_size = _data_size;
+ unsigned used_ffdhe = 0;
/* just in case we are resuming a session */
gnutls_pk_params_release(&session->key.dh_params);
return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
}
+ /* if we are doing RFC7919 */
+ if (session->internals.priorities->groups.have_ffdhe != 0) {
+ /* verify whether the received parameters match the advertised, otherwise
+ * log that. */
+ for (j=0;j<session->internals.priorities->groups.size;j++) {
+ if (session->internals.priorities->groups.entry[j]->generator &&
+ session->internals.priorities->groups.entry[j]->generator->size == n_g &&
+ session->internals.priorities->groups.entry[j]->prime->size == n_p &&
+ memcmp(session->internals.priorities->groups.entry[j]->generator->data,
+ data_g, n_g) == 0 &&
+ memcmp(session->internals.priorities->groups.entry[j]->prime->data,
+ data_p, n_p) == 0) {
+
+ used_ffdhe = 1;
+ _gnutls_session_group_set(session, session->internals.priorities->groups.entry[j]);
+ session->key.dh_params.flags = *session->internals.priorities->groups.entry[j]->q_bits;
+ break;
+ }
+ }
+
+ if (!used_ffdhe) {
+ _gnutls_audit_log(session, "FFDHE groups advertised, but server didn't support it; falling back to server's choice\n");
+ }
+ }
+
if (_gnutls_mpi_init_scan_nz(&session->key.dh_params.params[DH_G], data_g, _n_g) != 0) {
gnutls_assert();
return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
session->key.dh_params.params_nr = 3; /* include empty q */
session->key.dh_params.algo = GNUTLS_PK_DH;
- bits = _gnutls_dh_get_min_prime_bits(session);
- if (bits < 0) {
- gnutls_assert();
- return bits;
- }
-
- p_bits = _gnutls_mpi_get_nbits(session->key.dh_params.params[DH_P]);
- if (p_bits < bits) {
- /* the prime used by the peer is not acceptable
- */
- gnutls_assert();
- _gnutls_debug_log
- ("Received a prime of %u bits, limit is %u\n",
- (unsigned) _gnutls_mpi_get_nbits(session->key.dh_params.params[DH_P]),
- (unsigned) bits);
- return GNUTLS_E_DH_PRIME_UNACCEPTABLE;
- }
-
- if (p_bits >= DEFAULT_MAX_VERIFY_BITS) {
- gnutls_assert();
- _gnutls_debug_log
- ("Received a prime of %u bits, limit is %u\n",
- (unsigned) p_bits,
- (unsigned) DEFAULT_MAX_VERIFY_BITS);
- return GNUTLS_E_DH_PRIME_UNACCEPTABLE;
+ if (used_ffdhe == 0) {
+ bits = _gnutls_dh_get_min_prime_bits(session);
+ if (bits < 0) {
+ gnutls_assert();
+ return bits;
+ }
+
+ p_bits = _gnutls_mpi_get_nbits(session->key.dh_params.params[DH_P]);
+ if (p_bits < bits) {
+ /* the prime used by the peer is not acceptable
+ */
+ gnutls_assert();
+ _gnutls_debug_log
+ ("Received a prime of %u bits, limit is %u\n",
+ (unsigned) _gnutls_mpi_get_nbits(session->key.dh_params.params[DH_P]),
+ (unsigned) bits);
+ return GNUTLS_E_DH_PRIME_UNACCEPTABLE;
+ }
+
+ if (p_bits >= DEFAULT_MAX_VERIFY_BITS) {
+ gnutls_assert();
+ _gnutls_debug_log
+ ("Received a prime of %u bits, limit is %u\n",
+ (unsigned) p_bits,
+ (unsigned) DEFAULT_MAX_VERIFY_BITS);
+ return GNUTLS_E_DH_PRIME_UNACCEPTABLE;
+ }
}
- _gnutls_dh_set_group(session, session->key.dh_params.params[DH_G],
+ _gnutls_dh_save_group(session, session->key.dh_params.params[DH_G],
session->key.dh_params.params[DH_P]);
_gnutls_dh_set_peer_public(session, session->key.client_Y);
} dh_info_st;
void _gnutls_free_dh_info(dh_info_st * dh);
-int _gnutls_set_dh_pk_params(gnutls_session_t session, bigint_t g, bigint_t p,
- unsigned q_bits);
+
int _gnutls_gen_dh_common_client_kx_int(gnutls_session_t,
gnutls_buffer_st *,
gnutls_datum_t * pskkey);
int _gnutls_gen_dh_common_client_kx(gnutls_session_t, gnutls_buffer_st *);
int _gnutls_proc_dh_common_client_kx(gnutls_session_t session,
uint8_t * data, size_t _data_size,
- bigint_t p, bigint_t g,
gnutls_datum_t * psk_key);
int _gnutls_dh_common_print_server_kx(gnutls_session_t,
gnutls_buffer_st * data);
/*
* Copyright (C) 2000-2012 Free Software Foundation, Inc.
+ * Copyright (C) 2017 Red Hat, Inc.
*
* Author: Nikos Mavrogiannopoulos
*
static int
gen_dhe_server_kx(gnutls_session_t session, gnutls_buffer_st * data)
{
- bigint_t g, p;
- const bigint_t *mpis;
int ret = 0;
gnutls_certificate_credentials_t cred;
- gnutls_dh_params_t dh_params;
cred = (gnutls_certificate_credentials_t)
_gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
}
-
if ((ret = _gnutls_auth_info_set(session, GNUTLS_CRD_CERTIFICATE,
sizeof(cert_auth_info_st),
1)) < 0) {
return ret;
}
- dh_params =
- _gnutls_get_dh_params(cred->dh_params, cred->params_func,
- session);
- mpis = _gnutls_dh_params_to_mpi(dh_params);
- if (mpis == NULL) {
- gnutls_assert();
- return GNUTLS_E_NO_TEMPORARY_DH_PARAMS;
- }
-
- p = mpis[0];
- g = mpis[1];
-
- _gnutls_dh_set_group(session, g, p);
-
- ret = _gnutls_set_dh_pk_params(session, g, p, dh_params->q_bits);
- if (ret < 0)
+ ret =
+ _gnutls_figure_dh_params(session, cred->dh_params, cred->params_func, cred->dh_sec_param);
+ if (ret < 0) {
return gnutls_assert_val(ret);
+ }
ret =
_gnutls_dh_common_print_server_kx(session, data);
proc_dhe_client_kx(gnutls_session_t session, uint8_t * data,
size_t _data_size)
{
- gnutls_certificate_credentials_t cred;
- bigint_t p, g;
- const bigint_t *mpis;
- gnutls_dh_params_t dh_params;
-
- cred = (gnutls_certificate_credentials_t)
- _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
- if (cred == NULL) {
- gnutls_assert();
- return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
- }
-
- dh_params =
- _gnutls_get_dh_params(cred->dh_params, cred->params_func,
- session);
- mpis = _gnutls_dh_params_to_mpi(dh_params);
- if (mpis == NULL)
- return gnutls_assert_val(GNUTLS_E_NO_TEMPORARY_DH_PARAMS);
-
- p = mpis[0];
- g = mpis[1];
-
return _gnutls_proc_dh_common_client_kx(session, data, _data_size,
- g, p, NULL);
+ NULL);
}
/*
* Copyright (C) 2005-2012 Free Software Foundation, Inc.
+ * Copyright (C) 2017 Red Hat, Inc.
*
* Author: Nikos Mavrogiannopoulos
*
static int
gen_dhe_psk_server_kx(gnutls_session_t session, gnutls_buffer_st * data)
{
- bigint_t g, p;
- const bigint_t *mpis;
int ret;
- gnutls_dh_params_t dh_params;
gnutls_psk_server_credentials_t cred;
gnutls_datum_t hint = {NULL, 0};
return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
}
- dh_params =
- _gnutls_get_dh_params(cred->dh_params, cred->params_func,
- session);
- mpis = _gnutls_dh_params_to_mpi(dh_params);
- if (mpis == NULL) {
- gnutls_assert();
- return GNUTLS_E_NO_TEMPORARY_DH_PARAMS;
- }
-
- p = mpis[0];
- g = mpis[1];
-
if ((ret =
_gnutls_auth_info_set(session, GNUTLS_CRD_PSK,
sizeof(psk_auth_info_st), 1)) < 0) {
return ret;
}
- _gnutls_dh_set_group(session, g, p);
+ ret =
+ _gnutls_figure_dh_params(session, cred->dh_params, cred->params_func, cred->dh_sec_param);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
if (cred->hint) {
hint.data = (uint8_t *) cred->hint;
if (ret < 0)
return gnutls_assert_val(ret);
- ret = _gnutls_set_dh_pk_params(session, g, p, dh_params->q_bits);
- if (ret < 0)
- return gnutls_assert_val(ret);
-
ret =
_gnutls_dh_common_print_server_kx(session, data);
if (ret < 0)
return gnutls_assert_val(ret);
ret = _gnutls_ecdh_common_print_server_kx(session, data,
- _gnutls_session_ecc_curve_get
+ _gnutls_session_group_get
(session));
if (ret < 0)
gnutls_assert();
size_t _data_size)
{
int ret;
- bigint_t p, g;
- gnutls_dh_params_t dh_params;
- const bigint_t *mpis;
gnutls_datum_t psk_key;
gnutls_psk_server_credentials_t cred;
psk_auth_info_t info;
return ret;
}
- dh_params =
- _gnutls_get_dh_params(cred->dh_params, cred->params_func,
- session);
- mpis = _gnutls_dh_params_to_mpi(dh_params);
- if (mpis == NULL) {
- gnutls_assert();
- return GNUTLS_E_NO_TEMPORARY_DH_PARAMS;
- }
-
- p = mpis[0];
- g = mpis[1];
-
DECR_LEN(data_size, 2);
username.size = _gnutls_read_uint16(&data[0]);
return gnutls_assert_val(ret);
ret = _gnutls_proc_dh_common_client_kx(session, data, data_size,
- g, p, &psk_key);
+ &psk_key);
_gnutls_free_key_datum(&psk_key);
return gnutls_assert_val(ret);
ret = _gnutls_proc_ecdh_common_client_kx(session, data, data_size,
- _gnutls_session_ecc_curve_get
+ _gnutls_session_group_get
(session), &psk_key);
_gnutls_free_key_datum(&psk_key);
/*
* Copyright (C) 2011-2012 Free Software Foundation, Inc.
+ * Copyright (C) 2017 Red Hat, Inc.
*
* Author: Nikos Mavrogiannopoulos
*
int _gnutls_proc_ecdh_common_client_kx(gnutls_session_t session,
uint8_t * data, size_t _data_size,
- gnutls_ecc_curve_t curve,
+ gnutls_group_t group,
gnutls_datum_t * psk_key)
{
ssize_t data_size = _data_size;
int ret, i = 0;
unsigned point_size;
- const gnutls_ecc_curve_entry_st *ecurve = _gnutls_ecc_curve_get_params(curve);
+ const gnutls_ecc_curve_entry_st *ecurve =
+ _gnutls_group_get_curve_params((gnutls_ecc_curve_t)group);
- if (curve == GNUTLS_ECC_CURVE_INVALID || ecurve == NULL)
+ if (group == 0 || ecurve == NULL)
return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES);
DECR_LEN(data_size, 1);
return _gnutls_proc_ecdh_common_client_kx(session, data,
_data_size,
- _gnutls_session_ecc_curve_get
+ _gnutls_session_group_get
(session), NULL);
}
{
int ret;
gnutls_datum_t out;
- int curve = _gnutls_session_ecc_curve_get(session);
- const gnutls_ecc_curve_entry_st *ecurve = _gnutls_ecc_curve_get_params(curve);
+ gnutls_group_t group = _gnutls_session_group_get(session);
+ const gnutls_ecc_curve_entry_st *ecurve =
+ _gnutls_group_get_curve_params((gnutls_ecc_curve_t)group);
int pk;
if (ecurve == NULL)
/* generate temporal key */
ret =
- _gnutls_pk_generate_keys(pk, curve,
+ _gnutls_pk_generate_keys(pk, (gnutls_ecc_curve_t)group,
&session->key.ecdh_params, 1);
if (ret < 0)
return gnutls_assert_val(ret);
if (pk == GNUTLS_PK_EC) {
ret =
- _gnutls_ecc_ansi_x962_export(curve,
+ _gnutls_ecc_ansi_x962_export(ecurve->id,
session->key.ecdh_params.
params[ECC_X] /* x */ ,
session->key.ecdh_params.
{
int i, ret;
unsigned point_size;
- gnutls_ecc_curve_t curve;
+ const gnutls_group_entry_st *group;
ssize_t data_size = _data_size;
const gnutls_ecc_curve_entry_st *ecurve;
return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES);
DECR_LEN(data_size, 2);
- curve = _gnutls_tls_id_to_ecc_curve(_gnutls_read_uint16(&data[i]));
- if (curve == GNUTLS_ECC_CURVE_INVALID) {
- _gnutls_debug_log("received curve %u.%u\n", (unsigned)data[i], (unsigned)data[i+1]);
+ group = _gnutls_tls_id_to_group(_gnutls_read_uint16(&data[i]));
+ if (group == NULL || group->curve == 0) {
+ _gnutls_debug_log("received unknown curve %u.%u\n", (unsigned)data[i], (unsigned)data[i+1]);
+ return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
} else {
- _gnutls_debug_log("received curve %s\n", gnutls_ecc_curve_get_name(curve));
+ _gnutls_debug_log("received curve %s\n", group->name);
}
i += 2;
- ret = _gnutls_session_supports_ecc_curve(session, curve);
+ ret = _gnutls_session_supports_group(session, group->id);
if (ret < 0)
return gnutls_assert_val(ret);
- ecurve = _gnutls_ecc_curve_get_params(curve);
+ ecurve = _gnutls_ecc_curve_get_params(group->curve);
if (ecurve == NULL) {
- gnutls_assert();
return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
}
- _gnutls_session_ecc_curve_set(session, curve);
+ _gnutls_session_group_set(session, group);
DECR_LEN(data_size, 1);
point_size = data[i];
* be inserted */
int _gnutls_ecdh_common_print_server_kx(gnutls_session_t session,
gnutls_buffer_st * data,
- gnutls_ecc_curve_t curve)
+ gnutls_group_t group)
{
uint8_t p;
- int ret, pk;
+ int ret;
gnutls_datum_t out;
+ const gnutls_group_entry_st *e;
- if (curve == GNUTLS_ECC_CURVE_INVALID)
+ e = _gnutls_id_to_group(group);
+ if (e == NULL || e->curve == 0)
return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES);
/* just in case we are resuming a session */
ret =
_gnutls_buffer_append_prefix(data, 16,
- _gnutls_ecc_curve_get_tls_id
- (curve));
+ e->tls_id);
if (ret < 0)
return gnutls_assert_val(ret);
- pk = gnutls_ecc_curve_get_pk(curve);
/* generate temporal key */
ret =
- _gnutls_pk_generate_keys(pk, curve,
+ _gnutls_pk_generate_keys(e->pk, group,
&session->key.ecdh_params, 1);
if (ret < 0)
return gnutls_assert_val(ret);
- if (pk == GNUTLS_PK_EC) {
+ if (e->pk == GNUTLS_PK_EC) {
ret =
- _gnutls_ecc_ansi_x962_export(curve,
+ _gnutls_ecc_ansi_x962_export(e->curve,
session->key.ecdh_params.
params[ECC_X] /* x */ ,
session->key.ecdh_params.
if (ret < 0)
return gnutls_assert_val(ret);
- } else if (pk == GNUTLS_PK_ECDH_X25519) {
+ } else if (e->pk == GNUTLS_PK_ECDH_X25519) {
ret =
_gnutls_buffer_append_data_prefix(data, 8,
session->key.ecdh_params.raw_pub.data,
if (ret < 0)
return gnutls_assert_val(ret);
} else {
- return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
+ return gnutls_assert_val(GNUTLS_E_ECC_NO_SUPPORTED_CURVES);
}
ret =
_gnutls_ecdh_common_print_server_kx(session, data,
- _gnutls_session_ecc_curve_get
+ _gnutls_session_group_get
(session));
if (ret < 0) {
gnutls_assert();
/*
* Copyright (C) 2011-2012 Free Software Foundation, Inc.
+ * Copyright (C) 2017 Red Hat, Inc.
*
* Author: Nikos Mavrogiannopoulos
*
int
_gnutls_proc_ecdh_common_client_kx(gnutls_session_t session,
uint8_t * data, size_t _data_size,
- gnutls_ecc_curve_t curve,
+ gnutls_group_t group,
gnutls_datum_t * psk_key);
int _gnutls_ecdh_common_print_server_kx(gnutls_session_t,
gnutls_buffer_st * data,
- gnutls_ecc_curve_t curve);
+ gnutls_group_t group);
int _gnutls_proc_ecdh_common_server_kx(gnutls_session_t session,
uint8_t * data, size_t _data_size);
/* For DHE_PSK */
gnutls_dh_params_t dh_params;
unsigned int deinit_dh_params;
+ gnutls_sec_param_t dh_sec_param;
/* this callback is used to retrieve the DH or RSA
* parameters.
*/
}
res->dh_params = dh_params;
+ res->dh_sec_param = gnutls_pk_bits_to_sec_param(GNUTLS_PK_DH, _gnutls_mpi_get_nbits(dh_params->params[0]));
}
gnutls_certificate_set_known_dh_params(gnutls_certificate_credentials_t res,
gnutls_sec_param_t sec_param)
{
- int ret;
-
- if (res->deinit_dh_params) {
- res->deinit_dh_params = 0;
- gnutls_dh_params_deinit(res->dh_params);
- res->dh_params = NULL;
- }
-
- ret = _gnutls_set_cred_dh_params(&res->dh_params, sec_param);
- if (ret < 0)
- return gnutls_assert_val(ret);
-
- res->deinit_dh_params = 1;
+ res->dh_sec_param = sec_param;
return 0;
}
};
const unsigned int gnutls_ffdhe_8192_key_bits = 512;
-
-int _gnutls_set_cred_dh_params(gnutls_dh_params_t *cparams, gnutls_sec_param_t sec_param)
-{
- gnutls_dh_params_t tmp_params;
- const gnutls_datum_t *p, *g;
- unsigned key_bits, est_bits;
- unsigned bits;
- int ret;
-
- bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, sec_param);
-
- if (bits <= 2048) {
- p = &gnutls_ffdhe_2048_group_prime;
- g = &gnutls_ffdhe_2048_group_generator;
- key_bits = gnutls_ffdhe_2048_key_bits;
- } else if (bits <= 3072) {
- p = &gnutls_ffdhe_3072_group_prime;
- g = &gnutls_ffdhe_3072_group_generator;
- key_bits = gnutls_ffdhe_3072_key_bits;
- } else if (bits <= 4096) {
- p = &gnutls_ffdhe_4096_group_prime;
- g = &gnutls_ffdhe_4096_group_generator;
- key_bits = gnutls_ffdhe_4096_key_bits;
- } else {
- p = &gnutls_ffdhe_8192_group_prime;
- g = &gnutls_ffdhe_8192_group_generator;
- key_bits = gnutls_ffdhe_8192_key_bits;
- }
-
- /* if our estimation of subgroup bits is better/larger than
- * the one provided by the rfc7919, use that one */
- est_bits = _gnutls_pk_bits_to_subgroup_bits(bits);
- if (key_bits < est_bits)
- key_bits = est_bits;
-
- ret = gnutls_dh_params_init(&tmp_params);
- if (ret < 0)
- return gnutls_assert_val(ret);
-
- ret = gnutls_dh_params_import_raw2(tmp_params, p, g, key_bits);
- if (ret < 0) {
- gnutls_dh_params_deinit(tmp_params);
- return gnutls_assert_val(ret);
- }
-
- *cparams = tmp_params;
-
- return 0;
-}
#endif
#include "x509/x509_int.h"
#include <mpi.h>
#include "debug.h"
+#include "state.h"
-/*-
- * _gnutls_get_dh_params - Returns the DH parameters pointer
- * @dh_params: is an DH parameters type, or NULL.
- * @func: is a callback function to receive the parameters or NULL.
- * @session: a gnutls session.
- *
- * This function will return the dh parameters pointer.
- -*/
-gnutls_dh_params_t
-_gnutls_get_dh_params(gnutls_dh_params_t dh_params,
- gnutls_params_function * func,
- gnutls_session_t session)
+static
+int set_dh_pk_params(gnutls_session_t session, bigint_t g, bigint_t p,
+ unsigned q_bits)
+{
+ /* just in case we are resuming a session */
+ gnutls_pk_params_release(&session->key.dh_params);
+
+ gnutls_pk_params_init(&session->key.dh_params);
+
+ session->key.dh_params.params[DH_G] = _gnutls_mpi_copy(g);
+ if (session->key.dh_params.params[DH_G] == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ session->key.dh_params.params[DH_P] = _gnutls_mpi_copy(p);
+ if (session->key.dh_params.params[DH_P] == NULL) {
+ _gnutls_mpi_release(&session->key.dh_params.params[DH_G]);
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+ }
+
+ session->key.dh_params.params_nr = 3; /* include empty q */
+ session->key.dh_params.algo = GNUTLS_PK_DH;
+ session->key.dh_params.flags = q_bits;
+
+ return 0;
+}
+
+/* Use all available information to decide the DH parameters to use,
+ * that being the negotiated RFC7919 group, the callback, and the
+ * provided parameters structure.
+ */
+int
+_gnutls_figure_dh_params(gnutls_session_t session, gnutls_dh_params_t dh_params,
+ gnutls_params_function * func, gnutls_sec_param_t sec_param)
{
gnutls_params_st params;
+ bigint_t p, g;
+ unsigned free_pg = 0;
int ret;
+ unsigned q_bits = 0, i;
+
+ params.deinit = 0;
+
+ /* if client advertised RFC7919 */
+ if (session->internals.have_ffdhe) {
+ for (i=0;i<session->internals.priorities->groups.size;i++) {
+ if (session->internals.priorities->groups.entry[i]->id == session->security_parameters.group) {
+ ret = _gnutls_mpi_init_scan_nz(&p,
+ session->internals.priorities->groups.entry[i]->prime->data,
+ session->internals.priorities->groups.entry[i]->prime->size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ free_pg = 1;
+
+ ret = _gnutls_mpi_init_scan_nz(&g,
+ session->internals.priorities->groups.entry[i]->generator->data,
+ session->internals.priorities->groups.entry[i]->generator->size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ q_bits = *session->internals.priorities->groups.entry[i]->q_bits;
+ goto finished;
+ }
+ }
+
+ /* didn't find anything, that shouldn't have occurred
+ * as we received that extension */
+ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+ } else if (sec_param) {
+ unsigned bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, sec_param)/8;
+
+ for (i=0;i<session->internals.priorities->groups.size;i++) {
+ if (!session->internals.priorities->groups.entry[i]->prime)
+ continue;
+
+ if (bits <= session->internals.priorities->groups.entry[i]->prime->size) {
+ ret = _gnutls_mpi_init_scan_nz(&p,
+ session->internals.priorities->groups.entry[i]->prime->data,
+ session->internals.priorities->groups.entry[i]->prime->size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ free_pg = 1;
+
+ ret = _gnutls_mpi_init_scan_nz(&g,
+ session->internals.priorities->groups.entry[i]->generator->data,
+ session->internals.priorities->groups.entry[i]->generator->size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ q_bits = *session->internals.priorities->groups.entry[i]->q_bits;
+ goto finished;
+ }
+ }
- /* if cached return the cached */
- if (session->internals.params.dh_params)
- return session->internals.params.dh_params;
+ }
if (dh_params) {
- session->internals.params.dh_params = dh_params;
+ p = dh_params->params[0];
+ g = dh_params->params[1];
+ q_bits = dh_params->q_bits;
} else if (func) {
ret = func(session, GNUTLS_PARAMS_DH, ¶ms);
if (ret == 0 && params.type == GNUTLS_PARAMS_DH) {
- session->internals.params.dh_params =
- params.params.dh;
- session->internals.params.free_dh_params =
- params.deinit;
- }
+ p = params.params.dh->params[0];
+ g = params.params.dh->params[1];
+ q_bits = params.params.dh->q_bits;
+ } else
+ return gnutls_assert_val(GNUTLS_E_NO_TEMPORARY_DH_PARAMS);
+ } else
+ return gnutls_assert_val(GNUTLS_E_NO_TEMPORARY_DH_PARAMS);
+
+ finished:
+ _gnutls_dh_save_group(session, g, p);
+
+ ret = set_dh_pk_params(session, g, p, q_bits);
+ if (ret < 0) {
+ gnutls_assert();
}
- return session->internals.params.dh_params;
+ cleanup:
+ if (free_pg) {
+ _gnutls_mpi_release(&p);
+ _gnutls_mpi_release(&g);
+ }
+ if (params.deinit && params.type == GNUTLS_PARAMS_DH)
+ gnutls_dh_params_deinit(params.params.dh);
+
+ return ret;
+
}
/* returns the prime and the generator of DH params.
{
int ret;
gnutls_pk_params_st params;
-
+
gnutls_pk_params_init(¶ms);
-
+
ret = _gnutls_pk_generate_params(GNUTLS_PK_DH, bits, ¶ms);
if (ret < 0)
return gnutls_assert_val(ret);
dparams->q_bits = _gnutls_mpi_get_nbits(params.params[DSA_Q]);
_gnutls_mpi_release(¶ms.params[DSA_Q]);
-
+
return 0;
}
const bigint_t *_gnutls_dh_params_to_mpi(gnutls_dh_params_t);
-gnutls_dh_params_t
-_gnutls_get_dh_params(gnutls_dh_params_t dh_params,
- gnutls_params_function * func,
- gnutls_session_t session);
+int
+_gnutls_figure_dh_params(gnutls_session_t session, gnutls_dh_params_t dh_params,
+ gnutls_params_function * func, gnutls_sec_param_t sec_param);
int _gnutls_set_cred_dh_params(gnutls_dh_params_t *cparams, gnutls_sec_param_t sec_param);
#include <state.h>
#include <num.h>
#include <algorithms.h>
+#include "auth/psk.h"
+#include "auth/cert.h"
+#include "auth/anon.h"
static int _gnutls_supported_ecc_recv_params(gnutls_session_t session,
const uint8_t * data,
.deinit_func = NULL
};
+static unsigned get_min_dh(gnutls_session_t session)
+{
+ gnutls_certificate_credentials_t cert_cred;
+ gnutls_psk_server_credentials_t psk_cred;
+ gnutls_anon_server_credentials_t anon_cred;
+ unsigned level = 0;
+
+ cert_cred = (gnutls_certificate_credentials_t)_gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
+ psk_cred = (gnutls_psk_server_credentials_t)_gnutls_get_cred(session, GNUTLS_CRD_PSK);
+ anon_cred = (gnutls_anon_server_credentials_t)_gnutls_get_cred(session, GNUTLS_CRD_ANON);
+
+ if (cert_cred) {
+ level = cert_cred->dh_sec_param;
+ } else if (psk_cred) {
+ level = psk_cred->dh_sec_param;
+ } else if (anon_cred) {
+ level = anon_cred->dh_sec_param;
+ }
+
+ if (level)
+ return gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, level);
+
+ return 0;
+}
+
/*
* In case of a server: if a SUPPORTED_ECC extension type is received then it stores
* into the session security parameters the new value. The server may use gnutls_session_certificate_type_get(),
_gnutls_supported_ecc_recv_params(gnutls_session_t session,
const uint8_t * data, size_t _data_size)
{
- int new_type = -1, ret, i;
+ int ret, i;
ssize_t data_size = _data_size;
uint16_t len;
const uint8_t *p = data;
+ const gnutls_group_entry_st *group = NULL;
+ unsigned have_ffdhe = 0;
+ unsigned tls_id;
+ unsigned min_dh;
if (session->security_parameters.entity == GNUTLS_CLIENT) {
/* A client shouldn't receive this extension, but of course
DECR_LEN(data_size, len);
+ /* we figure what is the minimum DH allowed for this session, if any */
+ min_dh = get_min_dh(session);
+
+ /* This is being processed prior to a ciphersuite being selected */
for (i = 0; i < len; i += 2) {
- new_type =
- _gnutls_tls_id_to_ecc_curve(_gnutls_read_uint16
- (&p[i]));
- if (new_type < 0)
+ if (have_ffdhe == 0 && p[i] == 0x01) {
+ have_ffdhe = 1;
+ }
+ tls_id = _gnutls_read_uint16(&p[i]);
+ group = _gnutls_tls_id_to_group(tls_id);
+
+ _gnutls_handshake_log("EXT[%p]: Received group %s (0x%x)\n", session, group?group->name:"unknown", tls_id);
+ if (group == NULL)
+ continue;
+
+ /* if a DH group and less than expected ignore */
+ if (min_dh > 0 && group->prime && group->prime->size*8 < min_dh)
continue;
- /* Check if we support this supported_ecc */
+ /* Check if we support this group */
if ((ret =
- _gnutls_session_supports_ecc_curve(session,
- new_type))
+ _gnutls_session_supports_group(session,
+ group->id))
< 0) {
+ group = NULL;
continue;
- } else
+ } else {
break;
- /* new_type is ok */
+ }
}
- if (new_type < 0) {
- gnutls_assert();
- return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
- }
+ session->internals.have_ffdhe = have_ffdhe;
- if ((ret =
- _gnutls_session_supports_ecc_curve(session,
- new_type)) < 0) {
- /* The peer has requested unsupported ecc
+ if (group == NULL) {
+ gnutls_assert();
+ /* The peer has requested unsupported group
* types. Instead of failing, procceed normally.
* (the ciphersuite selection would fail, or a
* non certificate ciphersuite will be selected).
return gnutls_assert_val(0);
}
- _gnutls_session_ecc_curve_set(session, new_type);
+ _gnutls_session_group_set(session, group);
}
return 0;
}
-
/* returns data_size or a negative number on failure
*/
static int
/* this extension is only being sent on client side */
if (session->security_parameters.entity == GNUTLS_CLIENT) {
- if (session->internals.priorities->supported_ecc.
- algorithms > 0) {
-
- len =
- session->internals.priorities->supported_ecc.
- algorithms;
-
- /* this is a vector!
- */
+ len = session->internals.priorities->groups.size;
+ if (len > 0) {
ret =
_gnutls_buffer_append_prefix(extdata, 16,
len * 2);
return gnutls_assert_val(ret);
for (i = 0; i < len; i++) {
- p = _gnutls_ecc_curve_get_tls_id(session->
- internals.
- priorities->supported_ecc.
- priority
- [i]);
+ p = session->internals.priorities->groups.entry[i]->tls_id;
+
+ _gnutls_handshake_log("EXT[%p]: sent group %s (0x%x)\n", session,
+ session->internals.priorities->groups.entry[i]->name, (unsigned)p);
+
ret =
_gnutls_buffer_append_prefix(extdata,
16, p);
&& !_gnutls_session_is_ecc(session))
return 0;
- if (session->internals.priorities->supported_ecc.algorithms > 0) {
+ if (session->internals.priorities->groups.size > 0) {
ret = _gnutls_buffer_append_data(extdata, p, 2);
if (ret < 0)
return gnutls_assert_val(ret);
* session. A negative error value is returned otherwise.
*/
int
-_gnutls_session_supports_ecc_curve(gnutls_session_t session,
- unsigned int ecc_type)
+_gnutls_session_supports_group(gnutls_session_t session,
+ unsigned int group)
{
unsigned i;
- if (session->internals.priorities->supported_ecc.algorithms > 0) {
- for (i = 0;
- i <
- session->internals.priorities->supported_ecc.
- algorithms; i++) {
- if (session->internals.priorities->supported_ecc.
- priority[i] == ecc_type)
- return 0;
- }
+ for (i = 0; i < session->internals.priorities->groups.size; i++) {
+ if (session->internals.priorities->groups.entry[i]->id == group)
+ return 0;
}
return GNUTLS_E_ECC_UNSUPPORTED_CURVE;
extern const extension_entry_st ext_mod_supported_ecc_pf;
int
-_gnutls_session_supports_ecc_curve(gnutls_session_t session,
- unsigned int ecc_type);
+_gnutls_session_supports_group(gnutls_session_t session,
+ unsigned int group);
#endif
/*
* Copyright (C) 2000-2016 Free Software Foundation, Inc.
- * Copyright (C) 2015-2016 Red Hat, Inc.
+ * Copyright (C) 2015-2017 Red Hat, Inc.
*
* Author: Nikos Mavrogiannopoulos
*
_INSECURE
} hash_security_level_t;
+typedef struct gnutls_group_entry_st {
+ const char *name;
+ gnutls_group_t id;
+ const gnutls_datum_t *prime;
+ const gnutls_datum_t *generator;
+ const unsigned *q_bits;
+ gnutls_ecc_curve_t curve;
+ gnutls_pk_algorithm_t pk;
+ unsigned tls_id; /* The RFC4492 namedCurve ID or TLS 1.3 group ID */
+} gnutls_group_entry_st;
+
/* This structure is used both for MACs and digests
*/
typedef struct mac_entry_st {
uint16_t max_record_recv_size;
/* holds the negotiated certificate type */
gnutls_certificate_type_t cert_type;
- gnutls_ecc_curve_t ecc_curve; /* holds the first supported ECC curve requested by client */
+
+ gnutls_group_t group; /* holds the EC curve / DH group */
/* Holds the signature algorithm used in this session - If any */
gnutls_sign_algorithm_t server_sign_algo;
unsigned int size;
} ciphersuite_list_st;
+typedef struct group_list_st {
+ const gnutls_group_entry_st *entry[MAX_ALGOS];
+ unsigned int size;
+ bool have_ffdhe;
+} group_list_st;
+
typedef struct sign_algo_list_st {
const struct gnutls_sign_entry_st *entry[MAX_ALGOS];
unsigned int size;
struct gnutls_priority_st {
priority_st protocol;
priority_st cert_type;
- priority_st supported_ecc;
/* The following are not necessary to be stored in
* the structure; however they are required by the
priority_st _mac;
priority_st _kx;
priority_st _sign_algo;
+ priority_st _supported_ecc;
+
+ /* the supported groups */
+ group_list_st groups;
/* the supported signature algorithms */
sign_algo_list_st sigalg;
*/
} dh_params_st;
-typedef struct {
- gnutls_dh_params_t dh_params;
- int free_dh_params;
-} internal_params_st;
-
/* DTLS session state
*/
typedef struct {
*/
uint8_t rsa_pms_version[2];
- /* Here we cache the DH or RSA parameters got from the
- * credentials structure, or from a callback. That is to
- * minimize external calls.
- */
- internal_params_st params;
-
/* To avoid using global variables, and especially on Windows where
* the application may use a different errno variable than GnuTLS,
* it is possible to use gnutls_transport_set_errno to set a
* receive size */
unsigned max_recv_size;
+ bool have_ffdhe;
+
/* If you add anything here, check _gnutls_handshake_internal_state_clear().
*/
} internals_st;
}
}
- selected = _gnutls_figure_common_ciphersuite(session, &peer_clist);
- if (selected == NULL) {
- return gnutls_assert_val(GNUTLS_E_NO_CIPHER_SUITES);
+ ret = _gnutls_figure_common_ciphersuite(session, &peer_clist, &selected);
+ if (ret < 0) {
+ return gnutls_assert_val(ret);
}
_gnutls_handshake_log
GNUTLS_ECC_CURVE_MAX = GNUTLS_ECC_CURVE_ED25519
} gnutls_ecc_curve_t;
+/**
+ * gnutls_group_t:
+ * @GNUTLS_GROUP_INVALID: Indicates unknown/invalid group
+ * @GNUTLS_GROUP_SECP192R1: the SECP192R1 curve group (legacy, only for TLS 1.2 compatibility)
+ * @GNUTLS_GROUP_SECP224R1: the SECP224R1 curve group (legacy, only for TLS 1.2 compatibility)
+ * @GNUTLS_GROUP_SECP256R1: the SECP256R1 curve group
+ * @GNUTLS_GROUP_SECP384R1: the SECP384R1 curve group
+ * @GNUTLS_GROUP_SECP521R1: the SECP521R1 curve group
+ * @GNUTLS_GROUP_X25519: the X25519 curve group
+ * @GNUTLS_GROUP_FFDHE2048: the FFDHE2048 group
+ * @GNUTLS_GROUP_FFDHE3072: the FFDHE3072 group
+ * @GNUTLS_GROUP_FFDHE4096: the FFDHE4096 group
+ * @GNUTLS_GROUP_FFDHE8192: the FFDHE8192 group
+ *
+ * Enumeration of supported groups. It is intended to be backwards
+ * compatible with the enumerations in %gnutls_ecc_curve_t for the groups
+ * which are valid elliptic curves.
+ */
+typedef enum {
+ GNUTLS_GROUP_INVALID = 0,
+ GNUTLS_GROUP_SECP192R1 = GNUTLS_ECC_CURVE_SECP192R1,
+ GNUTLS_GROUP_SECP224R1 = GNUTLS_ECC_CURVE_SECP224R1,
+ GNUTLS_GROUP_SECP256R1 = GNUTLS_ECC_CURVE_SECP256R1,
+ GNUTLS_GROUP_SECP384R1 = GNUTLS_ECC_CURVE_SECP384R1,
+ GNUTLS_GROUP_SECP521R1 = GNUTLS_ECC_CURVE_SECP521R1,
+ GNUTLS_GROUP_X25519 = GNUTLS_ECC_CURVE_X25519,
+
+ GNUTLS_GROUP_FFDHE2048 = 256,
+ GNUTLS_GROUP_FFDHE3072,
+ GNUTLS_GROUP_FFDHE4096,
+ GNUTLS_GROUP_FFDHE8192,
+ GNUTLS_GROUP_MAX = GNUTLS_GROUP_FFDHE8192,
+} gnutls_group_t;
+
/* macros to allow specifying a specific curve in gnutls_privkey_generate()
* and gnutls_x509_privkey_generate() */
#define GNUTLS_CURVE_TO_BITS(curve) (unsigned int)(((unsigned int)1<<31)|((unsigned int)(curve)))
const char *
gnutls_ecc_curve_get_oid(gnutls_ecc_curve_t curve) __GNUTLS_CONST__;
+const char *
+ gnutls_group_get_name(gnutls_group_t curve) __GNUTLS_CONST__;
+
int
gnutls_ecc_curve_get_size(gnutls_ecc_curve_t curve) __GNUTLS_CONST__;
gnutls_ecc_curve_t gnutls_ecc_curve_get(gnutls_session_t session);
+gnutls_group_t gnutls_group_get(gnutls_session_t session);
+
/* get information on the current session */
gnutls_cipher_algorithm_t gnutls_cipher_get(gnutls_session_t session);
gnutls_kx_algorithm_t gnutls_kx_get(gnutls_session_t session);
gnutls_sign_get_id(const char *name) __GNUTLS_CONST__;
gnutls_ecc_curve_t gnutls_ecc_curve_get_id(const char *name) __GNUTLS_CONST__;
gnutls_pk_algorithm_t gnutls_ecc_curve_get_pk(gnutls_ecc_curve_t curve) __GNUTLS_CONST__;
+gnutls_group_t gnutls_group_get_id(const char *name);
gnutls_digest_algorithm_t
gnutls_oid_to_digest(const char *oid) __GNUTLS_CONST__;
/* list supported algorithms */
const gnutls_ecc_curve_t *
gnutls_ecc_curve_list(void) __GNUTLS_PURE__;
+const gnutls_group_t *
+ gnutls_group_list(void) __GNUTLS_PURE__;
const gnutls_cipher_algorithm_t *
gnutls_cipher_list(void) __GNUTLS_PURE__;
const gnutls_mac_algorithm_t *
const unsigned int **list);
int gnutls_priority_ecc_curve_list(gnutls_priority_t pcache,
const unsigned int **list);
+int
+gnutls_priority_group_list(gnutls_priority_t pcache,
+ const unsigned int **list);
int gnutls_priority_kx_list(gnutls_priority_t pcache,
const unsigned int **list);
gnutls_privkey_sign_hash2;
gnutls_privkey_sign_data2;
gnutls_sign_is_secure2;
+ gnutls_group_get_name;
+ gnutls_group_get_id;
+ gnutls_group_list;
+ gnutls_group_get;
+ gnutls_priority_group_list;
local:
*;
};
}
}
-static const int _supported_ecc_normal[] = {
- GNUTLS_ECC_CURVE_SECP256R1,
- GNUTLS_ECC_CURVE_SECP384R1,
- GNUTLS_ECC_CURVE_SECP521R1,
- GNUTLS_ECC_CURVE_X25519, /* draft-ietf-tls-rfc4492bis */
+static const int _supported_groups_normal[] = {
+ GNUTLS_GROUP_SECP256R1,
+ GNUTLS_GROUP_SECP384R1,
+ GNUTLS_GROUP_SECP521R1,
+ GNUTLS_GROUP_X25519, /* draft-ietf-tls-rfc4492bis */
+ GNUTLS_GROUP_FFDHE2048,
+ GNUTLS_GROUP_FFDHE3072,
+ GNUTLS_GROUP_FFDHE4096,
+ GNUTLS_GROUP_FFDHE8192,
0
};
-static const int* supported_ecc_normal = _supported_ecc_normal;
-
-static const int _supported_ecc_secure128[] = {
- GNUTLS_ECC_CURVE_SECP256R1,
- GNUTLS_ECC_CURVE_SECP384R1,
- GNUTLS_ECC_CURVE_SECP521R1,
- GNUTLS_ECC_CURVE_X25519, /* draft-ietf-tls-rfc4492bis */
+static const int* supported_groups_normal = _supported_groups_normal;
+
+static const int _supported_groups_secure128[] = {
+ GNUTLS_GROUP_SECP256R1,
+ GNUTLS_GROUP_SECP384R1,
+ GNUTLS_GROUP_SECP521R1,
+ GNUTLS_GROUP_X25519, /* draft-ietf-tls-rfc4492bis */
+ GNUTLS_GROUP_FFDHE2048,
+ GNUTLS_GROUP_FFDHE3072,
+ GNUTLS_GROUP_FFDHE4096,
+ GNUTLS_GROUP_FFDHE8192,
0
};
-static const int* supported_ecc_secure128 = _supported_ecc_secure128;
+static const int* supported_groups_secure128 = _supported_groups_secure128;
-static const int _supported_ecc_suiteb128[] = {
- GNUTLS_ECC_CURVE_SECP256R1,
- GNUTLS_ECC_CURVE_SECP384R1,
+static const int _supported_groups_suiteb128[] = {
+ GNUTLS_GROUP_SECP256R1,
+ GNUTLS_GROUP_SECP384R1,
0
};
-static const int* supported_ecc_suiteb128 = _supported_ecc_suiteb128;
+static const int* supported_groups_suiteb128 = _supported_groups_suiteb128;
-static const int _supported_ecc_suiteb192[] = {
- GNUTLS_ECC_CURVE_SECP384R1,
+static const int _supported_groups_suiteb192[] = {
+ GNUTLS_GROUP_SECP384R1,
0
};
-static const int* supported_ecc_suiteb192 = _supported_ecc_suiteb192;
+static const int* supported_groups_suiteb192 = _supported_groups_suiteb192;
-static const int _supported_ecc_secure192[] = {
- GNUTLS_ECC_CURVE_SECP384R1,
- GNUTLS_ECC_CURVE_SECP521R1,
+static const int _supported_groups_secure192[] = {
+ GNUTLS_GROUP_SECP384R1,
+ GNUTLS_GROUP_SECP521R1,
+ GNUTLS_GROUP_FFDHE8192,
0
};
-static const int* supported_ecc_secure192 = _supported_ecc_secure192;
+static const int* supported_groups_secure192 = _supported_groups_secure192;
static const int protocol_priority[] = {
GNUTLS_TLS1_2,
const int **mac_list;
const int **kx_list;
const int **sign_list;
- const int **ecc_list;
+ const int **group_list;
unsigned profile;
int sec_param;
bool no_tickets;
.mac_list = &mac_priority_normal,
.kx_list = &kx_priority_secure,
.sign_list = &sign_priority_default,
- .ecc_list = &supported_ecc_normal,
+ .group_list = &supported_groups_normal,
.profile = GNUTLS_PROFILE_LOW,
.sec_param = GNUTLS_SEC_PARAM_WEAK
},
.mac_list = &mac_priority_secure128,
.kx_list = &kx_priority_pfs,
.sign_list = &sign_priority_default,
- .ecc_list = &supported_ecc_normal,
+ .group_list = &supported_groups_normal,
.profile = GNUTLS_PROFILE_LOW,
.sec_param = GNUTLS_SEC_PARAM_WEAK,
.no_tickets = 1
.mac_list = &mac_priority_secure128,
.kx_list = &kx_priority_secure,
.sign_list = &sign_priority_secure128,
- .ecc_list = &supported_ecc_secure128,
+ .group_list = &supported_groups_secure128,
/* The profile should have been HIGH but if we don't allow
* SHA-1 (80-bits) as signature algorithm we are not able
* to connect anywhere with this level */
.mac_list = &mac_priority_secure192,
.kx_list = &kx_priority_secure,
.sign_list = &sign_priority_secure192,
- .ecc_list = &supported_ecc_secure192,
+ .group_list = &supported_groups_secure192,
.profile = GNUTLS_PROFILE_HIGH,
.sec_param = GNUTLS_SEC_PARAM_HIGH
},
.mac_list = &mac_priority_suiteb,
.kx_list = &kx_priority_suiteb,
.sign_list = &sign_priority_suiteb128,
- .ecc_list = &supported_ecc_suiteb128,
+ .group_list = &supported_groups_suiteb128,
.profile = GNUTLS_PROFILE_SUITEB128,
.sec_param = GNUTLS_SEC_PARAM_HIGH
},
.mac_list = &mac_priority_suiteb,
.kx_list = &kx_priority_suiteb,
.sign_list = &sign_priority_suiteb192,
- .ecc_list = &supported_ecc_suiteb192,
+ .group_list = &supported_groups_suiteb192,
.profile = GNUTLS_PROFILE_SUITEB192,
.sec_param = GNUTLS_SEC_PARAM_ULTRA
},
.mac_list = &mac_priority_normal,
.kx_list = &kx_priority_secure,
.sign_list = &sign_priority_default,
- .ecc_list = &supported_ecc_normal,
+ .group_list = &supported_groups_normal,
.sec_param = GNUTLS_SEC_PARAM_VERY_WEAK
},
{.name = LEVEL_PERFORMANCE,
.mac_list = &mac_priority_normal,
.kx_list = &kx_priority_performance,
.sign_list = &sign_priority_default,
- .ecc_list = &supported_ecc_normal,
+ .group_list = &supported_groups_normal,
.profile = GNUTLS_PROFILE_LOW,
.sec_param = GNUTLS_SEC_PARAM_WEAK
},
func(&priority_cache->_kx, *pgroups[i].kx_list);
func(&priority_cache->_mac, *pgroups[i].mac_list);
func(&priority_cache->_sign_algo, *pgroups[i].sign_list);
- func(&priority_cache->supported_ecc, *pgroups[i].ecc_list);
+ func(&priority_cache->_supported_ecc, *pgroups[i].group_list);
if (pgroups[i].profile != 0) {
SET_PROFILE(pgroups[i].profile); /* set certificate level */
return ret;
}
+static void add_ec(gnutls_priority_t priority_cache)
+{
+ const gnutls_group_entry_st *ge;
+ unsigned i;
+
+ for (i = 0; i < priority_cache->_supported_ecc.algorithms; i++) {
+ ge = _gnutls_id_to_group(priority_cache->_supported_ecc.priority[i]);
+ if (ge != NULL && priority_cache->groups.size < sizeof(priority_cache->groups.entry)/sizeof(priority_cache->groups.entry[0])) {
+ /* do not add groups which do not correspond to enabled ciphersuites */
+ if (!ge->curve)
+ continue;
+ priority_cache->groups.entry[priority_cache->groups.size++] = ge;
+ }
+ }
+}
+
+static void add_dh(gnutls_priority_t priority_cache)
+{
+ const gnutls_group_entry_st *ge;
+ unsigned i;
+
+ for (i = 0; i < priority_cache->_supported_ecc.algorithms; i++) {
+ ge = _gnutls_id_to_group(priority_cache->_supported_ecc.priority[i]);
+ if (ge != NULL && priority_cache->groups.size < sizeof(priority_cache->groups.entry)/sizeof(priority_cache->groups.entry[0])) {
+ /* do not add groups which do not correspond to enabled ciphersuites */
+ if (!ge->prime)
+ continue;
+ priority_cache->groups.entry[priority_cache->groups.size++] = ge;
+ priority_cache->groups.have_ffdhe = 1;
+ }
+ }
+}
+
static void set_ciphersuite_list(gnutls_priority_t priority_cache)
{
unsigned i, j, z;
const gnutls_cipher_suite_entry_st *ce;
const gnutls_sign_entry_st *se;
+ unsigned have_ec = 0;
+ unsigned have_dh = 0;
+ unsigned ecc_first = 0;
priority_cache->cs.size = 0;
+ priority_cache->sigalg.size = 0;
+ priority_cache->groups.size = 0;
+ priority_cache->groups.have_ffdhe = 0;
for (i = 0; i < priority_cache->_kx.algorithms; i++) {
for (j=0;j<priority_cache->_cipher.algorithms;j++) {
if (ce != NULL && priority_cache->cs.size < MAX_CIPHERSUITE_SIZE) {
priority_cache->cs.entry[priority_cache->cs.size++] = ce;
+ if (!have_ec && _gnutls_kx_is_ecc(ce->kx_algorithm)) {
+ have_ec = 1;
+ if (have_dh == 0)
+ ecc_first = 1;
+ }
+ if (!have_dh && _gnutls_kx_is_dhe(ce->kx_algorithm))
+ have_dh = 1;
}
}
}
}
}
- _gnutls_debug_log("added %d ciphersuites and %d sig algos into priority list\n",
- priority_cache->cs.size, priority_cache->sigalg.size);
+ if (ecc_first) {
+ if (have_ec)
+ add_ec(priority_cache);
+ if (have_dh)
+ add_dh(priority_cache);
+ } else {
+ if (have_dh)
+ add_dh(priority_cache);
+ if (have_ec)
+ add_ec(priority_cache);
+ }
+
+ _gnutls_debug_log("added %d ciphersuites, %d sig algos and %d groups into priority list\n",
+ priority_cache->cs.size, priority_cache->sigalg.size,
+ priority_cache->groups.size);
}
/**
cert_type_priority_default);
_set_priority(&(*priority_cache)->_sign_algo,
sign_priority_default);
- _set_priority(&(*priority_cache)->supported_ecc,
- supported_ecc_normal);
+ _set_priority(&(*priority_cache)->_supported_ecc,
+ supported_groups_normal);
i = 0;
} else {
ikeyword_set = 1;
(&broken_list[i][1], "CURVE-ALL",
9) == 0) {
bulk_fn(&(*priority_cache)->
- supported_ecc,
- supported_ecc_normal);
+ _supported_ecc,
+ supported_groups_normal);
} else {
if ((algo =
gnutls_ecc_curve_get_id
(&broken_list[i][7])) !=
GNUTLS_ECC_CURVE_INVALID)
fn(&(*priority_cache)->
- supported_ecc, algo);
+ _supported_ecc, algo);
+ else
+ goto error;
+ }
+ } else if (strncasecmp
+ (&broken_list[i][1], "GROUP-", 6) == 0) {
+ if (strncasecmp
+ (&broken_list[i][1], "GROUP-ALL",
+ 9) == 0) {
+ bulk_fn(&(*priority_cache)->
+ _supported_ecc,
+ supported_groups_normal);
+ } else {
+ if ((algo =
+ gnutls_group_get_id
+ (&broken_list[i][7])) !=
+ GNUTLS_GROUP_INVALID)
+ fn(&(*priority_cache)->
+ _supported_ecc, algo);
else
goto error;
}
gnutls_priority_ecc_curve_list(gnutls_priority_t pcache,
const unsigned int **list)
{
- if (pcache->supported_ecc.algorithms == 0)
+ if (pcache->_supported_ecc.algorithms == 0)
+ return 0;
+
+ *list = pcache->_supported_ecc.priority;
+ return pcache->_supported_ecc.algorithms;
+}
+
+/**
+ * gnutls_priority_group_list:
+ * @pcache: is a #gnutls_prioritity_t type.
+ * @list: will point to an integer list
+ *
+ * Get a list of available groups in the priority
+ * structure.
+ *
+ * Returns: the number of items, or an error code.
+ *
+ * Since: 3.6.0
+ **/
+int
+gnutls_priority_group_list(gnutls_priority_t pcache,
+ const unsigned int **list)
+{
+ if (pcache->_supported_ecc.algorithms == 0)
return 0;
- *list = pcache->supported_ecc.priority;
- return pcache->supported_ecc.algorithms;
+ *list = pcache->_supported_ecc.priority;
+ return pcache->_supported_ecc.algorithms;
}
/**
gnutls_psk_set_server_dh_params(gnutls_psk_server_credentials_t res,
gnutls_dh_params_t dh_params)
{
+ if (res->deinit_dh_params) {
+ res->deinit_dh_params = 0;
+ gnutls_dh_params_deinit(res->dh_params);
+ res->dh_params = NULL;
+ }
+
res->dh_params = dh_params;
+ res->dh_sec_param = gnutls_pk_bits_to_sec_param(GNUTLS_PK_DH, _gnutls_mpi_get_nbits(dh_params->params[0]));
}
/**
gnutls_psk_set_server_known_dh_params(gnutls_psk_server_credentials_t res,
gnutls_sec_param_t sec_param)
{
- int ret;
-
- if (res->deinit_dh_params) {
- res->deinit_dh_params = 0;
- gnutls_dh_params_deinit(res->dh_params);
- res->dh_params = NULL;
- }
-
- ret = _gnutls_set_cred_dh_params(&res->dh_params, sec_param);
- if (ret < 0)
- return gnutls_assert_val(ret);
-
- res->deinit_dh_params = 1;
+ res->dh_sec_param = sec_param;
return 0;
}
/*
* Copyright (C) 2000-2016 Free Software Foundation, Inc.
- * Copyright (C) 2016 Red Hat, Inc.
+ * Copyright (C) 2017 Red Hat, Inc.
*
* Author: Nikos Mavrogiannopoulos
*
#include "debug.h"
#include <session_pack.h>
#include <datum.h>
+#include "state.h"
/**
* gnutls_session_get_data:
unsigned type;
char kx_name[64];
char proto_name[32];
- const char *curve_name = NULL;
+ char _group_name[24];
+ const char *group_name = NULL;
unsigned dh_bits = 0;
unsigned mac_id;
unsigned sign_algo;
return NULL;
kx = session->security_parameters.kx_algorithm;
-
- if (kx == GNUTLS_KX_ANON_ECDH || kx == GNUTLS_KX_ECDHE_PSK ||
- kx == GNUTLS_KX_ECDHE_RSA || kx == GNUTLS_KX_ECDHE_ECDSA) {
- curve_name =
- gnutls_ecc_curve_get_name(gnutls_ecc_curve_get
- (session));
+ group_name = gnutls_group_get_name(_gnutls_session_group_get(session));
#if defined(ENABLE_DHE) || defined(ENABLE_ANON)
- } else if (kx == GNUTLS_KX_ANON_DH || kx == GNUTLS_KX_DHE_PSK
- || kx == GNUTLS_KX_DHE_RSA || kx == GNUTLS_KX_DHE_DSS) {
+ if (group_name == NULL && _gnutls_kx_is_dhe(kx)) {
dh_bits = gnutls_dh_get_prime_bits(session);
-#endif
+ snprintf(_group_name, sizeof(_group_name), "CUSTOM%u", dh_bits);
+ group_name = _group_name;
}
+#endif
/* Key exchange - Signature algorithm */
/* DHE-3072 - RSA-PSS-2048 */
kx == GNUTLS_KX_ECDHE_PSK) {
if (sign_str)
snprintf(kx_name, sizeof(kx_name), "(ECDHE-%s)-(%s)",
- curve_name, sign_str);
+ group_name, sign_str);
else
snprintf(kx_name, sizeof(kx_name), "(ECDHE-%s)",
- curve_name);
+ group_name);
} else if (kx == GNUTLS_KX_DHE_DSS || kx == GNUTLS_KX_DHE_RSA ||
kx == GNUTLS_KX_DHE_PSK) {
if (sign_str)
- snprintf(kx_name, sizeof(kx_name), "(DHE-%u)-(%s)", dh_bits, sign_str);
+ snprintf(kx_name, sizeof(kx_name), "(DHE-%s)-(%s)", group_name, sign_str);
else
- snprintf(kx_name, sizeof(kx_name), "(DHE-%u)", dh_bits);
+ snprintf(kx_name, sizeof(kx_name), "(DHE-%s)", group_name);
} else if (kx == GNUTLS_KX_RSA) {
/* Possible enhancement: include the certificate bits */
snprintf(kx_name, sizeof(kx_name), "(RSA)");
BUFFER_APPEND_NUM(ps,
session->security_parameters.
max_record_recv_size);
- BUFFER_APPEND_NUM(ps, session->security_parameters.ecc_curve);
+ BUFFER_APPEND_NUM(ps, session->security_parameters.group);
BUFFER_APPEND_NUM(ps,
session->security_parameters.server_sign_algo);
BUFFER_POP_NUM(ps,
session->internals.resumed_security_parameters.
- ecc_curve);
+ group);
BUFFER_POP_NUM(ps,
session->internals.resumed_security_parameters.
server_sign_algo);
session->internals.resumed_security_parameters.timestamp =
gnutls_time(0);
- session->internals.resumed_security_parameters.ecc_curve =
- GNUTLS_ECC_CURVE_INVALID;
+ session->internals.resumed_security_parameters.group = 0;
session->internals.premaster_set = 1;
_gnutls_rsa_pms_set_version(gnutls_session_t session,
unsigned char major, unsigned char minor);
-void
-_gnutls_session_ecc_curve_set(gnutls_session_t session,
- gnutls_ecc_curve_t c)
-{
- _gnutls_handshake_log("HSK[%p]: Selected ECC curve %s (%d)\n",
- session, gnutls_ecc_curve_get_name(c), c);
- session->security_parameters.ecc_curve = c;
-}
-
/**
* gnutls_cipher_get:
* @session: is a #gnutls_session_t type.
_gnutls_free_temp_key_datum(&session->key.key);
}
-/* this function deinitializes all the internal parameters stored
- * in a session struct.
- */
-inline static void deinit_internal_params(gnutls_session_t session)
-{
-#if defined(ENABLE_DHE) || defined(ENABLE_ANON)
- if (session->internals.params.free_dh_params)
- gnutls_dh_params_deinit(session->internals.params.
- dh_params);
-#endif
-
- _gnutls_handshake_hash_buffers_clear(session);
-
- memset(&session->internals.params, 0,
- sizeof(session->internals.params));
-}
-
/* An internal version of _gnutls_handshake_internal_state_clear(),
* it will not attempt to deallocate, only initialize */
static void handshake_internal_state_clear1(gnutls_session_t session)
session->internals.handshake_suspicious_loops = 0;
session->internals.dtls.hsk_read_seq = 0;
session->internals.dtls.hsk_write_seq = 0;
+
+ session->internals.have_ffdhe = 0;
}
/* This function will clear all the variables in internals
{
handshake_internal_state_clear1(session);
- deinit_internal_params(session);
+ _gnutls_handshake_hash_buffers_clear(session);
deinit_keys(session);
_gnutls_epoch_gc(session);
/* Sets the prime and the generator in the auth info structure.
*/
int
-_gnutls_dh_set_group(gnutls_session_t session, bigint_t gen,
+_gnutls_dh_save_group(gnutls_session_t session, bigint_t gen,
bigint_t prime)
{
dh_info_st *dh;
**/
gnutls_ecc_curve_t gnutls_ecc_curve_get(gnutls_session_t session)
{
- return _gnutls_session_ecc_curve_get(session);
+ const gnutls_group_entry_st *e;
+
+ e = _gnutls_id_to_group(_gnutls_session_group_get(session));
+ if (e == NULL || e->curve == 0)
+ return 0;
+ return e->curve;
+}
+
+/**
+ * gnutls_group_get:
+ * @session: is a #gnutls_session_t type.
+ *
+ * Returns the currently used group for key exchange. Only valid
+ * when using an elliptic curve or DH ciphersuite.
+ *
+ * Returns: the currently used group, a #gnutls_group_t
+ * type.
+ *
+ * Since: 3.6.0
+ **/
+gnutls_group_t gnutls_group_get(gnutls_session_t session)
+{
+ const gnutls_group_entry_st *e;
+
+ e = _gnutls_id_to_group(_gnutls_session_group_get(session));
+ if (e == NULL)
+ return 0;
+ return e->id;
}
/**
#include "gnutls_int.h"
inline static gnutls_ecc_curve_t
-_gnutls_session_ecc_curve_get(gnutls_session_t session)
+_gnutls_session_group_get(gnutls_session_t session)
{
- return session->security_parameters.ecc_curve;
+ return session->security_parameters.group;
}
int _gnutls_session_is_ecc(gnutls_session_t session);
-void
-_gnutls_session_ecc_curve_set(gnutls_session_t session,
- gnutls_ecc_curve_t c);
+inline static void
+_gnutls_session_group_set(gnutls_session_t session,
+ const gnutls_group_entry_st *e)
+{
+ _gnutls_handshake_log("HSK[%p]: Selected group %s (%d)\n",
+ session, e->name, e->id);
+ session->security_parameters.group = e->id;
+}
+
void
_gnutls_record_set_default_version(gnutls_session_t session,
int _gnutls_dh_set_secret_bits(gnutls_session_t session, unsigned bits);
int _gnutls_dh_set_peer_public(gnutls_session_t session, bigint_t public);
-int _gnutls_dh_set_group(gnutls_session_t session, bigint_t gen,
+int _gnutls_dh_save_group(gnutls_session_t session, bigint_t gen,
bigint_t prime);
static inline int _gnutls_dh_get_min_prime_bits(gnutls_session_t session)