diff options
-rw-r--r-- | lib/ext/key_share.c | 49 | ||||
-rw-r--r-- | lib/includes/gnutls/gnutls.h.in | 18 |
2 files changed, 46 insertions, 21 deletions
diff --git a/lib/ext/key_share.c b/lib/ext/key_share.c index 411b10e9bf..2b31c95b4a 100644 --- a/lib/ext/key_share.c +++ b/lib/ext/key_share.c @@ -627,7 +627,6 @@ key_share_recv_params(gnutls_session_t session, return 0; } -#define MAX_GROUPS 3 /* returns data_size or a negative number on failure */ static int @@ -638,7 +637,6 @@ key_share_send_params(gnutls_session_t session, int ret; unsigned char *lengthp; unsigned int cur_length; - gnutls_pk_algorithm_t selected_groups[MAX_GROUPS]; unsigned int generated = 0; const gnutls_group_entry_st *group; const version_entry_st *ver; @@ -669,29 +667,40 @@ key_share_send_params(gnutls_session_t session, return gnutls_assert_val(GNUTLS_E_NO_COMMON_KEY_SHARE); if (ret < 0) return gnutls_assert_val(ret); - } else - /* generate key shares for out top-3 groups - * if they are of different PK type. */ - for (i=0;i<session->internals.priorities->groups.size;i++) { - group = session->internals.priorities->groups.entry[i]; + } else { + gnutls_pk_algorithm_t selected_groups[3]; + unsigned max_groups = 2; /* GNUTLS_KEY_SHARE_TOP2 */ - if (generated == 1 && group->pk == selected_groups[0]) - continue; - else if (generated == 2 && (group->pk == selected_groups[1] || group->pk == selected_groups[0])) - continue; + if (session->internals.flags & GNUTLS_KEY_SHARE_TOP) + max_groups = 1; + else if (session->internals.flags & GNUTLS_KEY_SHARE_TOP3) + max_groups = 3; - selected_groups[generated] = group->pk; + assert(max_groups <= sizeof(selected_groups)/sizeof(selected_groups[0])); - ret = client_gen_key_share(session, group, extdata); - if (ret == GNUTLS_E_INT_RET_0) - continue; /* no key share for this algorithm */ - if (ret < 0) - return gnutls_assert_val(ret); + /* generate key shares for out top-(max_groups) groups + * if they are of different PK type. */ + for (i = 0; i < session->internals.priorities->groups.size; i++) { + group = session->internals.priorities->groups.entry[i]; + + if (generated == 1 && group->pk == selected_groups[0]) + continue; + else if (generated == 2 && (group->pk == selected_groups[1] || group->pk == selected_groups[0])) + continue; + + selected_groups[generated] = group->pk; - generated++; + ret = client_gen_key_share(session, group, extdata); + if (ret == GNUTLS_E_INT_RET_0) + continue; /* no key share for this algorithm */ + if (ret < 0) + return gnutls_assert_val(ret); - if (generated >= MAX_GROUPS) - break; + generated++; + + if (generated >= max_groups) + break; + } } /* copy actual length */ diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in index 0a9fbe07bd..ef37573265 100644 --- a/lib/includes/gnutls/gnutls.h.in +++ b/lib/includes/gnutls/gnutls.h.in @@ -361,10 +361,23 @@ typedef enum { * @GNUTLS_ENABLE_FALSE_START: Enable the TLS false start on client side if the negotiated ciphersuites allow it. This will enable sending data prior to the handshake being complete, and may introduce a risk of crypto failure when combined with certain key exchanged; for that GnuTLS may not enable that option in ciphersuites that are known to be not safe for false start. Since 3.5.0. * @GNUTLS_FORCE_CLIENT_CERT: When in client side and only a single cert is specified, send that certificate irrespective of the issuers expected by the server. Since 3.5.0. * @GNUTLS_NO_TICKETS: Flag to indicate that the session should not use resumption with session tickets. + * @GNUTLS_KEY_SHARE_TOP3: Generate key shared for the top-3 different groups which are enabled. + * That is, as each group is associated with a key type (EC, finite field, x25519), generate + * three keys using %GNUTLS_PK_DH, %GNUTLS_PK_EC, %GNUTLS_PK_ECDH_X25519 if all of them are enabled. + * @GNUTLS_KEY_SHARE_TOP2: Generate key shared for the top-2 different groups which are enabled. + * For example (ECDH + x25519). This is the default. + * @GNUTLS_KEY_SHARE_TOP: Generate key shared for the first group which is enabled. + * For example x25519. This option is the most performant for client (less CPU spent + * generating keys), but if the server doesn't support the advertized option it may + * result to more roundtrips needed to discover the server's choice. * * Enumeration of different flags for gnutls_init() function. All the flags * can be combined except @GNUTLS_SERVER and @GNUTLS_CLIENT which are mutually * exclusive. + * + * The key share options relate to the TLS 1.3 key share extension + * which is a speculative key generation expecting that the server + * would support the generated key. */ typedef enum { GNUTLS_SERVER = 1, @@ -377,7 +390,10 @@ typedef enum { GNUTLS_ALLOW_ID_CHANGE = (1<<7), GNUTLS_ENABLE_FALSE_START = (1<<8), GNUTLS_FORCE_CLIENT_CERT = (1<<9), - GNUTLS_NO_TICKETS = (1<<10) + GNUTLS_NO_TICKETS = (1<<10), + GNUTLS_KEY_SHARE_TOP = (1<<11), + GNUTLS_KEY_SHARE_TOP2 = (1<<12), + GNUTLS_KEY_SHARE_TOP3 = (1<<13) } gnutls_init_flags_t; /* compatibility defines (previous versions of gnutls |