summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2017-10-06 09:05:20 +0200
committerNikos Mavrogiannopoulos <nmav@redhat.com>2017-11-15 11:41:34 +0100
commit2d8a12b7fb089287d110ea64e5888fda4298548a (patch)
tree48b2ed6c166c91160eb175b6ddade9e2b348a07a
parentaba5201cb136b1576634491139efea9a3a7d1100 (diff)
downloadgnutls-2d8a12b7fb089287d110ea64e5888fda4298548a.tar.gz
key share: added flags to gnutls_init() to modify its default behavior
That way the application can adjust the range of keys generated during client hello attempting to guess the server's algorithm. Applications are intentionally not given the option to select the algorithm in the key share, but rather chose from the prioritized list of groups, to avoid a disconnect between the prioritized groups, and the key share sent. Relates #284 Signed-off-by: Nikos Mavrogiannopoulos <nmav@redhat.com>
-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