summaryrefslogtreecommitdiff
path: root/lib/ext/ecc.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ext/ecc.c')
-rw-r--r--lib/ext/ecc.c78
1 files changed, 61 insertions, 17 deletions
diff --git a/lib/ext/ecc.c b/lib/ext/ecc.c
index 58cf3d86b2..50cd862211 100644
--- a/lib/ext/ecc.c
+++ b/lib/ext/ecc.c
@@ -115,7 +115,7 @@ static int
_gnutls_supported_ecc_recv_params(gnutls_session_t session,
const uint8_t * data, size_t _data_size)
{
- int ret, i;
+ int i;
ssize_t data_size = _data_size;
uint16_t len;
const uint8_t *p = data;
@@ -123,6 +123,9 @@ _gnutls_supported_ecc_recv_params(gnutls_session_t session,
unsigned have_ffdhe = 0;
unsigned tls_id;
unsigned min_dh;
+ unsigned j;
+ int serv_ec_idx, serv_dh_idx; /* index in server's priority listing */
+ int cli_ec_pos, cli_dh_pos; /* position in listing sent by client */
if (session->security_parameters.entity == GNUTLS_CLIENT) {
/* A client shouldn't receive this extension in TLS1.2. It is
@@ -148,11 +151,15 @@ _gnutls_supported_ecc_recv_params(gnutls_session_t session,
/* 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 */
+ serv_ec_idx = serv_dh_idx = -1;
+ cli_ec_pos = cli_dh_pos = -1;
+
+ /* This extension is being processed prior to a ciphersuite being selected,
+ * so we cannot rely on ciphersuite information. */
for (i = 0; i < len; i += 2) {
- if (have_ffdhe == 0 && p[i] == 0x01) {
+ 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);
@@ -160,25 +167,62 @@ _gnutls_supported_ecc_recv_params(gnutls_session_t session,
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 group */
- if ((ret =
- _gnutls_session_supports_group(session,
- group->id))
- < 0) {
- group = NULL;
- continue;
- } else {
- if (group->pk == GNUTLS_PK_DH && session->internals.cand_dh_group == NULL)
- session->internals.cand_dh_group = group;
- else if (group->pk != GNUTLS_PK_DH && session->internals.cand_ec_group == NULL)
- session->internals.cand_ec_group = group;
+ /* we simulate _gnutls_session_supports_group, but we prioritize if
+ * %SERVER_PRECEDENCE is given */
+ for (j = 0; j < session->internals.priorities->groups.size; j++) {
+ if (session->internals.priorities->groups.entry[j]->id == group->id) {
+ if (session->internals.priorities->server_precedence) {
+ if (group->pk == GNUTLS_PK_DH) {
+ if (serv_dh_idx != -1 && (int)j > serv_dh_idx)
+ break;
+ serv_dh_idx = j;
+ cli_dh_pos = i;
+ } else {
+ if (serv_ec_idx != -1 && (int)j > serv_ec_idx)
+ break;
+ serv_ec_idx = j;
+ cli_ec_pos = i;
+ }
+ } else {
+ if (group->pk == GNUTLS_PK_DH) {
+ if (cli_dh_pos != -1)
+ break;
+ cli_dh_pos = i;
+ serv_dh_idx = j;
+ } else {
+ if (cli_ec_pos != -1)
+ break;
+ cli_ec_pos = i;
+ serv_ec_idx = j;
+ }
+ }
+ break;
+ }
}
}
+ /* serv_dh/ec_pos contain the index of the groups we want to use.
+ */
+ if (serv_dh_idx != -1) {
+ session->internals.cand_dh_group = session->internals.priorities->groups.entry[serv_dh_idx];
+ session->internals.cand_group = session->internals.cand_dh_group;
+ }
+
+ if (serv_ec_idx != -1) {
+ session->internals.cand_ec_group = session->internals.priorities->groups.entry[serv_ec_idx];
+ if (session->internals.cand_group == NULL ||
+ (session->internals.priorities->server_precedence && serv_ec_idx < serv_dh_idx) ||
+ (!session->internals.priorities->server_precedence && cli_ec_pos < cli_dh_pos)) {
+ session->internals.cand_group = session->internals.cand_ec_group;
+ }
+ }
+
+ if (session->internals.cand_group)
+ _gnutls_handshake_log("EXT[%p]: Selected group %s\n", session, session->internals.cand_group->name);
+
if (have_ffdhe)
session->internals.hsk_flags |= HSK_HAVE_FFDHE;
}