summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/ext/key_share.c49
-rw-r--r--lib/includes/gnutls/gnutls.h.in18
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