summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2017-06-27 15:36:04 +0200
committerNikos Mavrogiannopoulos <nmav@redhat.com>2017-08-01 09:34:02 +0200
commit2a552f2eb3c93e2c13c1eb8cd4f64317d8586e5f (patch)
tree5acdb04170e020d876c3671bff2dad6f013294c9
parentdffd5a166e7aa59e5966b3ad27949170bf1d8061 (diff)
downloadgnutls-2a552f2eb3c93e2c13c1eb8cd4f64317d8586e5f.tar.gz
TLS: introduced support for RFC7919 groups
That replaces the EC curve extension negotiation with the negotiated groups extensions, introduces handling for groups as priority strings, as well as using and checking of RFC7919 DH parameters once negotiated. Resolves: #37 Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
-rw-r--r--lib/alert.c1
-rw-r--r--lib/algorithms.h36
-rw-r--r--lib/algorithms/Makefile.am3
-rw-r--r--lib/algorithms/ciphersuites.c93
-rw-r--r--lib/algorithms/ecc.c39
-rw-r--r--lib/algorithms/groups.c225
-rw-r--r--lib/algorithms/kx.c11
-rw-r--r--lib/anon_cred.c15
-rw-r--r--lib/auth/anon.c55
-rw-r--r--lib/auth/anon.h1
-rw-r--r--lib/auth/anon_ecdh.c4
-rw-r--r--lib/auth/cert.h1
-rw-r--r--lib/auth/dh_common.c107
-rw-r--r--lib/auth/dh_common.h4
-rw-r--r--lib/auth/dhe.c49
-rw-r--r--lib/auth/dhe_psk.c48
-rw-r--r--lib/auth/ecdhe.c61
-rw-r--r--lib/auth/ecdhe.h5
-rw-r--r--lib/auth/psk.h1
-rw-r--r--lib/cert.c15
-rw-r--r--lib/dh-primes.c49
-rw-r--r--lib/dh.c152
-rw-r--r--lib/dh.h7
-rw-r--r--lib/ext/ecc.c119
-rw-r--r--lib/ext/ecc.h4
-rw-r--r--lib/gnutls_int.h40
-rw-r--r--lib/handshake.c6
-rw-r--r--lib/includes/gnutls/gnutls.h.in45
-rw-r--r--lib/libgnutls.map5
-rw-r--r--lib/priority.c197
-rw-r--r--lib/psk.c21
-rw-r--r--lib/session.c28
-rw-r--r--lib/session_pack.c7
-rw-r--r--lib/state.c61
-rw-r--r--lib/state.h18
35 files changed, 943 insertions, 590 deletions
diff --git a/lib/alert.c b/lib/alert.c
index 0aa3a69aa8..0e26297340 100644
--- a/lib/alert.c
+++ b/lib/alert.c
@@ -301,6 +301,7 @@ int gnutls_error_to_alert(int err, int *level)
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;
diff --git a/lib/algorithms.h b/lib/algorithms.h
index d8e4df92c6..ceb333ec2d 100644
--- a/lib/algorithms.h
+++ b/lib/algorithms.h
@@ -49,9 +49,10 @@ gnutls_protocol_t _gnutls_version_get(uint8_t major, uint8_t minor);
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)
@@ -335,22 +336,30 @@ unsigned int _gnutls_pk_bits_to_subgroup_bits(unsigned int pk_bits);
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
@@ -381,6 +390,15 @@ static inline int _gnutls_kx_is_ecc(gnutls_kx_algorithm_t kx)
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 ||
diff --git a/lib/algorithms/Makefile.am b/lib/algorithms/Makefile.am
index 3957323420..2f5607e5a8 100644
--- a/lib/algorithms/Makefile.am
+++ b/lib/algorithms/Makefile.am
@@ -35,4 +35,5 @@ endif
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
diff --git a/lib/algorithms/ciphersuites.c b/lib/algorithms/ciphersuites.c
index 6f5d34b022..ac7328a309 100644
--- a/lib/algorithms/ciphersuites.c
+++ b/lib/algorithms/ciphersuites.c
@@ -1203,12 +1203,19 @@ check_server_dh_params(gnutls_session_t session,
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) {
@@ -1216,11 +1223,8 @@ check_server_dh_params(gnutls_session_t session,
(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
@@ -1229,11 +1233,8 @@ check_server_dh_params(gnutls_session_t session,
(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
@@ -1242,25 +1243,15 @@ check_server_dh_params(gnutls_session_t session,
(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;
}
/**
@@ -1380,33 +1371,41 @@ const char *gnutls_cipher_suite_info(size_t idx,
} \
}
-#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",
@@ -1420,17 +1419,19 @@ _gnutls_figure_common_ciphersuite(gnutls_session_t session,
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;
}
}
}
@@ -1448,17 +1449,19 @@ _gnutls_figure_common_ciphersuite(gnutls_session_t session,
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;
}
}
}
@@ -1466,8 +1469,16 @@ _gnutls_figure_common_ciphersuite(gnutls_session_t session,
}
/* 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) \
diff --git a/lib/algorithms/ecc.c b/lib/algorithms/ecc.c
index 5a8d0d1ec0..a757feb7bb 100644
--- a/lib/algorithms/ecc.c
+++ b/lib/algorithms/ecc.c
@@ -34,7 +34,6 @@ static const gnutls_ecc_curve_entry_st ecc_curves[] = {
.name = "SECP192R1",
.oid = "1.2.840.10045.3.1.1",
.id = GNUTLS_ECC_CURVE_SECP192R1,
- .tls_id = 19,
.pk = GNUTLS_PK_ECDSA,
.size = 24,
},
@@ -42,7 +41,6 @@ static const gnutls_ecc_curve_entry_st ecc_curves[] = {
.name = "SECP224R1",
.oid = "1.3.132.0.33",
.id = GNUTLS_ECC_CURVE_SECP224R1,
- .tls_id = 21,
.pk = GNUTLS_PK_ECDSA,
.size = 28,
},
@@ -50,7 +48,6 @@ static const gnutls_ecc_curve_entry_st ecc_curves[] = {
.name = "SECP256R1",
.oid = "1.2.840.10045.3.1.7",
.id = GNUTLS_ECC_CURVE_SECP256R1,
- .tls_id = 23,
.pk = GNUTLS_PK_ECDSA,
.size = 32,
},
@@ -58,7 +55,6 @@ static const gnutls_ecc_curve_entry_st ecc_curves[] = {
.name = "SECP384R1",
.oid = "1.3.132.0.34",
.id = GNUTLS_ECC_CURVE_SECP384R1,
- .tls_id = 24,
.pk = GNUTLS_PK_ECDSA,
.size = 48,
},
@@ -66,14 +62,12 @@ static const gnutls_ecc_curve_entry_st ecc_curves[] = {
.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,
},
@@ -93,22 +87,6 @@ static const gnutls_ecc_curve_entry_st ecc_curves[] = {
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:
*
@@ -136,23 +114,6 @@ const gnutls_ecc_curve_t *gnutls_ecc_curve_list(void)
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
diff --git a/lib/algorithms/groups.c b/lib/algorithms/groups.c
new file mode 100644
index 0000000000..8bd94bb208
--- /dev/null
+++ b/lib/algorithms/groups.c
@@ -0,0 +1,225 @@
+/*
+ * 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;
+}
diff --git a/lib/algorithms/kx.c b/lib/algorithms/kx.c
index 276f56f118..309484054f 100644
--- a/lib/algorithms/kx.c
+++ b/lib/algorithms/kx.c
@@ -252,18 +252,25 @@ bool _gnutls_kx_allows_false_start(gnutls_session_t session)
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;
}
}
diff --git a/lib/anon_cred.c b/lib/anon_cred.c
index d8f2e846ff..fbf64fb3c3 100644
--- a/lib/anon_cred.c
+++ b/lib/anon_cred.c
@@ -120,6 +120,7 @@ gnutls_anon_set_server_dh_params(gnutls_anon_server_credentials_t res,
}
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]));
}
/**
@@ -141,19 +142,7 @@ int
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;
}
diff --git a/lib/auth/anon.c b/lib/auth/anon.c
index 24cfd74f0d..0cfa0efde8 100644
--- a/lib/auth/anon.c
+++ b/lib/auth/anon.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2000-2012 Free Software Foundation, Inc.
+ * Copyright (C) 2017 Red Hat, Inc.
*
* Author: Nikos Mavrogiannopoulos
*
@@ -62,10 +63,7 @@ const mod_auth_st anon_auth_struct = {
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)
@@ -75,18 +73,6 @@ gen_anon_server_kx(gnutls_session_t session, gnutls_buffer_st * data)
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) {
@@ -94,11 +80,10 @@ gen_anon_server_kx(gnutls_session_t session, gnutls_buffer_st * data)
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);
@@ -114,36 +99,8 @@ static int
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);
}
diff --git a/lib/auth/anon.h b/lib/auth/anon.h
index 02722c83e1..4b13359644 100644
--- a/lib/auth/anon.h
+++ b/lib/auth/anon.h
@@ -27,6 +27,7 @@
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.
diff --git a/lib/auth/anon_ecdh.c b/lib/auth/anon_ecdh.c
index 1f8a9b7a2b..368fda1573 100644
--- a/lib/auth/anon_ecdh.c
+++ b/lib/auth/anon_ecdh.c
@@ -82,7 +82,7 @@ gen_anon_ecdh_server_kx(gnutls_session_t session, gnutls_buffer_st * data)
ret =
_gnutls_ecdh_common_print_server_kx(session, data,
- _gnutls_session_ecc_curve_get
+ _gnutls_session_group_get
(session));
if (ret < 0) {
gnutls_assert();
@@ -107,7 +107,7 @@ proc_anon_ecdh_client_kx(gnutls_session_t session, uint8_t * data,
return _gnutls_proc_ecdh_common_client_kx(session, data,
_data_size,
- _gnutls_session_ecc_curve_get
+ _gnutls_session_group_get
(session), NULL);
}
diff --git a/lib/auth/cert.h b/lib/auth/cert.h
index c1844734d8..2d72762722 100644
--- a/lib/auth/cert.h
+++ b/lib/auth/cert.h
@@ -45,6 +45,7 @@ typedef struct {
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.
diff --git a/lib/auth/dh_common.c b/lib/auth/dh_common.c
index b80b329862..2452f5a34b 100644
--- a/lib/auth/dh_common.c
+++ b/lib/auth/dh_common.c
@@ -54,7 +54,6 @@ void _gnutls_free_dh_info(dh_info_st * dh)
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;
@@ -178,31 +177,6 @@ _gnutls_gen_dh_common_client_kx_int(gnutls_session_t session,
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,
@@ -214,7 +188,9 @@ _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);
@@ -255,6 +231,31 @@ _gnutls_proc_dh_common_server_kx(gnutls_session_t session,
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;
@@ -270,34 +271,36 @@ _gnutls_proc_dh_common_server_kx(gnutls_session_t session,
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);
diff --git a/lib/auth/dh_common.h b/lib/auth/dh_common.h
index 3bd8b8ae31..e50e3993c2 100644
--- a/lib/auth/dh_common.h
+++ b/lib/auth/dh_common.h
@@ -34,15 +34,13 @@ typedef struct {
} 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);
diff --git a/lib/auth/dhe.c b/lib/auth/dhe.c
index 31b4bc1158..8bf7b79459 100644
--- a/lib/auth/dhe.c
+++ b/lib/auth/dhe.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2000-2012 Free Software Foundation, Inc.
+ * Copyright (C) 2017 Red Hat, Inc.
*
* Author: Nikos Mavrogiannopoulos
*
@@ -84,11 +85,8 @@ const mod_auth_st dhe_dss_auth_struct = {
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);
@@ -97,7 +95,6 @@ gen_dhe_server_kx(gnutls_session_t session, gnutls_buffer_st * data)
return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
}
-
if ((ret = _gnutls_auth_info_set(session, GNUTLS_CRD_CERTIFICATE,
sizeof(cert_auth_info_st),
1)) < 0) {
@@ -105,23 +102,11 @@ gen_dhe_server_kx(gnutls_session_t session, gnutls_buffer_st * data)
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);
@@ -159,28 +144,6 @@ static int
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);
}
diff --git a/lib/auth/dhe_psk.c b/lib/auth/dhe_psk.c
index d4c6b6e0c5..2edec8d91b 100644
--- a/lib/auth/dhe_psk.c
+++ b/lib/auth/dhe_psk.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2005-2012 Free Software Foundation, Inc.
+ * Copyright (C) 2017 Red Hat, Inc.
*
* Author: Nikos Mavrogiannopoulos
*
@@ -184,10 +185,7 @@ gen_dhe_psk_client_kx(gnutls_session_t session, gnutls_buffer_st * data)
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};
@@ -198,18 +196,6 @@ gen_dhe_psk_server_kx(gnutls_session_t session, gnutls_buffer_st * data)
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) {
@@ -217,7 +203,12 @@ gen_dhe_psk_server_kx(gnutls_session_t session, gnutls_buffer_st * data)
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;
@@ -228,10 +219,6 @@ gen_dhe_psk_server_kx(gnutls_session_t session, gnutls_buffer_st * data)
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)
@@ -272,7 +259,7 @@ gen_ecdhe_psk_server_kx(gnutls_session_t session, gnutls_buffer_st * data)
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();
@@ -286,9 +273,6 @@ proc_dhe_psk_client_kx(gnutls_session_t session, uint8_t * data,
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;
@@ -310,18 +294,6 @@ proc_dhe_psk_client_kx(gnutls_session_t session, uint8_t * data,
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]);
@@ -354,7 +326,7 @@ proc_dhe_psk_client_kx(gnutls_session_t session, uint8_t * data,
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);
@@ -423,7 +395,7 @@ proc_ecdhe_psk_client_kx(gnutls_session_t session, uint8_t * data,
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);
diff --git a/lib/auth/ecdhe.c b/lib/auth/ecdhe.c
index 9a7f4f4ed6..6a54b00555 100644
--- a/lib/auth/ecdhe.c
+++ b/lib/auth/ecdhe.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2011-2012 Free Software Foundation, Inc.
+ * Copyright (C) 2017 Red Hat, Inc.
*
* Author: Nikos Mavrogiannopoulos
*
@@ -136,15 +137,16 @@ static int calc_ecdh_key(gnutls_session_t session,
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);
@@ -211,7 +213,7 @@ proc_ecdhe_client_kx(gnutls_session_t session,
return _gnutls_proc_ecdh_common_client_kx(session, data,
_data_size,
- _gnutls_session_ecc_curve_get
+ _gnutls_session_group_get
(session), NULL);
}
@@ -229,8 +231,9 @@ _gnutls_gen_ecdh_common_client_kx_int(gnutls_session_t session,
{
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)
@@ -240,14 +243,14 @@ _gnutls_gen_ecdh_common_client_kx_int(gnutls_session_t session,
/* 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.
@@ -316,7 +319,7 @@ _gnutls_proc_ecdh_common_server_kx(gnutls_session_t session,
{
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;
@@ -331,27 +334,27 @@ _gnutls_proc_ecdh_common_server_kx(gnutls_session_t session,
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];
@@ -393,13 +396,15 @@ _gnutls_proc_ecdh_common_server_kx(gnutls_session_t session,
* 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 */
@@ -416,23 +421,21 @@ int _gnutls_ecdh_common_print_server_kx(gnutls_session_t 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.
@@ -448,7 +451,7 @@ int _gnutls_ecdh_common_print_server_kx(gnutls_session_t session,
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,
@@ -456,7 +459,7 @@ int _gnutls_ecdh_common_print_server_kx(gnutls_session_t session,
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);
}
@@ -485,7 +488,7 @@ gen_ecdhe_server_kx(gnutls_session_t session, gnutls_buffer_st * data)
ret =
_gnutls_ecdh_common_print_server_kx(session, data,
- _gnutls_session_ecc_curve_get
+ _gnutls_session_group_get
(session));
if (ret < 0) {
gnutls_assert();
diff --git a/lib/auth/ecdhe.h b/lib/auth/ecdhe.h
index 063c6707c9..2917ea830b 100644
--- a/lib/auth/ecdhe.h
+++ b/lib/auth/ecdhe.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2011-2012 Free Software Foundation, Inc.
+ * Copyright (C) 2017 Red Hat, Inc.
*
* Author: Nikos Mavrogiannopoulos
*
@@ -37,12 +38,12 @@ _gnutls_gen_ecdh_common_client_kx_int(gnutls_session_t session,
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);
diff --git a/lib/auth/psk.h b/lib/auth/psk.h
index b2d8a76fdf..8cde1f7159 100644
--- a/lib/auth/psk.h
+++ b/lib/auth/psk.h
@@ -42,6 +42,7 @@ typedef struct gnutls_psk_server_credentials_st {
/* 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.
*/
diff --git a/lib/cert.c b/lib/cert.c
index c4af3c95e5..fd9066df9c 100644
--- a/lib/cert.c
+++ b/lib/cert.c
@@ -873,6 +873,7 @@ gnutls_certificate_set_dh_params(gnutls_certificate_credentials_t res,
}
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]));
}
@@ -895,19 +896,7 @@ int
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;
}
diff --git a/lib/dh-primes.c b/lib/dh-primes.c
index 50af25f9c2..3a1947634e 100644
--- a/lib/dh-primes.c
+++ b/lib/dh-primes.c
@@ -390,53 +390,4 @@ const gnutls_datum_t gnutls_ffdhe_8192_group_prime = {
};
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
diff --git a/lib/dh.c b/lib/dh.c
index 401525b0e3..bcf967abdd 100644
--- a/lib/dh.c
+++ b/lib/dh.c
@@ -32,40 +32,142 @@
#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, &params);
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.
@@ -287,9 +389,9 @@ gnutls_dh_params_generate2(gnutls_dh_params_t dparams, unsigned int bits)
{
int ret;
gnutls_pk_params_st params;
-
+
gnutls_pk_params_init(&params);
-
+
ret = _gnutls_pk_generate_params(GNUTLS_PK_DH, bits, &params);
if (ret < 0)
return gnutls_assert_val(ret);
@@ -299,7 +401,7 @@ gnutls_dh_params_generate2(gnutls_dh_params_t dparams, unsigned int bits)
dparams->q_bits = _gnutls_mpi_get_nbits(params.params[DSA_Q]);
_gnutls_mpi_release(&params.params[DSA_Q]);
-
+
return 0;
}
diff --git a/lib/dh.h b/lib/dh.h
index 5b15a93ef2..bd717b5a74 100644
--- a/lib/dh.h
+++ b/lib/dh.h
@@ -25,10 +25,9 @@
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);
diff --git a/lib/ext/ecc.c b/lib/ext/ecc.c
index e589fbc447..b010215a38 100644
--- a/lib/ext/ecc.c
+++ b/lib/ext/ecc.c
@@ -31,6 +31,9 @@
#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,
@@ -70,6 +73,31 @@ const extension_entry_st ext_mod_supported_ecc_pf = {
.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(),
@@ -82,10 +110,14 @@ static int
_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
@@ -108,33 +140,42 @@ _gnutls_supported_ecc_recv_params(gnutls_session_t session,
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).
@@ -142,13 +183,12 @@ _gnutls_supported_ecc_recv_params(gnutls_session_t session,
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
@@ -162,15 +202,8 @@ _gnutls_supported_ecc_send_params(gnutls_session_t session,
/* 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);
@@ -178,11 +211,11 @@ _gnutls_supported_ecc_send_params(gnutls_session_t session,
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);
@@ -264,7 +297,7 @@ _gnutls_supported_ecc_pf_send_params(gnutls_session_t session,
&& !_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);
@@ -279,20 +312,14 @@ _gnutls_supported_ecc_pf_send_params(gnutls_session_t session,
* 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;
diff --git a/lib/ext/ecc.h b/lib/ext/ecc.h
index bb86871f03..a3b4311f64 100644
--- a/lib/ext/ecc.h
+++ b/lib/ext/ecc.h
@@ -28,7 +28,7 @@ extern const extension_entry_st ext_mod_supported_ecc;
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
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index d624a05284..7e82f86b6b 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -1,6 +1,6 @@
/*
* 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
*
@@ -478,6 +478,17 @@ typedef enum hash_security_level_t {
_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 {
@@ -577,7 +588,8 @@ typedef struct {
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;
@@ -661,6 +673,12 @@ typedef struct ciphersuite_list_st {
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;
@@ -672,7 +690,6 @@ typedef struct sign_algo_list_st {
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
@@ -681,6 +698,10 @@ struct gnutls_priority_st {
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;
@@ -753,11 +774,6 @@ typedef struct gnutls_dh_params_int {
*/
} dh_params_st;
-typedef struct {
- gnutls_dh_params_t dh_params;
- int free_dh_params;
-} internal_params_st;
-
/* DTLS session state
*/
typedef struct {
@@ -974,12 +990,6 @@ 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
@@ -1104,6 +1114,8 @@ typedef struct {
* receive size */
unsigned max_recv_size;
+ bool have_ffdhe;
+
/* If you add anything here, check _gnutls_handshake_internal_state_clear().
*/
} internals_st;
diff --git a/lib/handshake.c b/lib/handshake.c
index 4b8599fbc0..bb538948ba 100644
--- a/lib/handshake.c
+++ b/lib/handshake.c
@@ -875,9 +875,9 @@ _gnutls_server_select_suite(gnutls_session_t session, uint8_t * data,
}
}
- 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
diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
index 35b2de3e91..ebee1b1478 100644
--- a/lib/includes/gnutls/gnutls.h.in
+++ b/lib/includes/gnutls/gnutls.h.in
@@ -836,6 +836,40 @@ typedef enum {
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)))
@@ -961,10 +995,15 @@ const char *
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);
@@ -1050,6 +1089,7 @@ gnutls_sign_algorithm_t
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__;
@@ -1065,6 +1105,8 @@ gnutls_ecc_curve_t
/* 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 *
@@ -1382,6 +1424,9 @@ int gnutls_priority_protocol_list(gnutls_priority_t pcache,
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);
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index 2a9d0af70a..aed995e2be 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -1165,6 +1165,11 @@ GNUTLS_3_4
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:
*;
};
diff --git a/lib/priority.c b/lib/priority.c
index 7a17964bad..831a82ac38 100644
--- a/lib/priority.c
+++ b/lib/priority.c
@@ -105,43 +105,52 @@ static void _clear_given_priorities(priority_st * st, const int *list)
}
}
-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,
@@ -609,7 +618,7 @@ struct priority_groups_st {
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;
@@ -622,7 +631,7 @@ static const struct priority_groups_st pgroups[] =
.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
},
@@ -631,7 +640,7 @@ static const struct priority_groups_st pgroups[] =
.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
@@ -642,7 +651,7 @@ static const struct priority_groups_st pgroups[] =
.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 */
@@ -655,7 +664,7 @@ static const struct priority_groups_st pgroups[] =
.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
},
@@ -665,7 +674,7 @@ static const struct priority_groups_st pgroups[] =
.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
},
@@ -675,7 +684,7 @@ static const struct priority_groups_st pgroups[] =
.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
},
@@ -684,7 +693,7 @@ static const struct priority_groups_st pgroups[] =
.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,
@@ -692,7 +701,7 @@ static const struct priority_groups_st pgroups[] =
.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
},
@@ -739,7 +748,7 @@ int check_level(const char *level, gnutls_priority_t priority_cache,
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 */
@@ -1124,13 +1133,52 @@ finish:
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++) {
@@ -1142,6 +1190,13 @@ static void set_ciphersuite_list(gnutls_priority_t priority_cache)
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;
}
}
}
@@ -1154,8 +1209,21 @@ static void set_ciphersuite_list(gnutls_priority_t priority_cache)
}
}
- _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);
}
/**
@@ -1303,8 +1371,8 @@ gnutls_priority_init(gnutls_priority_t * priority_cache,
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;
@@ -1390,15 +1458,33 @@ gnutls_priority_init(gnutls_priority_t * priority_cache,
(&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;
}
@@ -1613,11 +1699,34 @@ int
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;
}
/**
diff --git a/lib/psk.c b/lib/psk.c
index ba2e4874d3..b8c27ee3e0 100644
--- a/lib/psk.c
+++ b/lib/psk.c
@@ -376,7 +376,14 @@ void
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]));
}
/**
@@ -398,19 +405,7 @@ int
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;
}
diff --git a/lib/session.c b/lib/session.c
index bb2c8e9e4a..ee04782144 100644
--- a/lib/session.c
+++ b/lib/session.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2000-2016 Free Software Foundation, Inc.
- * Copyright (C) 2016 Red Hat, Inc.
+ * Copyright (C) 2017 Red Hat, Inc.
*
* Author: Nikos Mavrogiannopoulos
*
@@ -25,6 +25,7 @@
#include "debug.h"
#include <session_pack.h>
#include <datum.h>
+#include "state.h"
/**
* gnutls_session_get_data:
@@ -274,7 +275,8 @@ char *gnutls_session_get_desc(gnutls_session_t session)
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;
@@ -284,18 +286,14 @@ char *gnutls_session_get_desc(gnutls_session_t session)
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 */
@@ -310,16 +308,16 @@ char *gnutls_session_get_desc(gnutls_session_t session)
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)");
diff --git a/lib/session_pack.c b/lib/session_pack.c
index b8612c5a6b..ab5bd844ea 100644
--- a/lib/session_pack.c
+++ b/lib/session_pack.c
@@ -766,7 +766,7 @@ pack_security_parameters(gnutls_session_t session, gnutls_buffer_st * ps)
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);
@@ -853,7 +853,7 @@ unpack_security_parameters(gnutls_session_t session, gnutls_buffer_st * ps)
BUFFER_POP_NUM(ps,
session->internals.resumed_security_parameters.
- ecc_curve);
+ group);
BUFFER_POP_NUM(ps,
session->internals.resumed_security_parameters.
server_sign_algo);
@@ -966,8 +966,7 @@ gnutls_session_set_premaster(gnutls_session_t session, unsigned int entity,
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;
diff --git a/lib/state.c b/lib/state.c
index a36ed92d25..d110e1c37e 100644
--- a/lib/state.c
+++ b/lib/state.c
@@ -58,15 +58,6 @@ void
_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.
@@ -187,23 +178,6 @@ static void deinit_keys(gnutls_session_t session)
_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)
@@ -224,6 +198,8 @@ 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
@@ -234,7 +210,7 @@ void _gnutls_handshake_internal_state_clear(gnutls_session_t session)
{
handshake_internal_state_clear1(session);
- deinit_internal_params(session);
+ _gnutls_handshake_hash_buffers_clear(session);
deinit_keys(session);
_gnutls_epoch_gc(session);
@@ -530,7 +506,7 @@ int _gnutls_dh_set_secret_bits(gnutls_session_t session, unsigned bits)
/* 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;
@@ -976,7 +952,34 @@ gnutls_session_channel_binding(gnutls_session_t session,
**/
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;
}
/**
diff --git a/lib/state.h b/lib/state.h
index 154ce51259..5fec7f64bb 100644
--- a/lib/state.h
+++ b/lib/state.h
@@ -26,16 +26,22 @@
#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,
@@ -59,7 +65,7 @@ _gnutls_hello_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)