summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2017-10-06 09:05:20 +0200
committerNikos Mavrogiannopoulos <nmav@redhat.com>2018-02-19 15:29:35 +0100
commitcc8a6733f254f81a91f03aa836dfd91a22f4fc3a (patch)
tree270ec63e282d96bf79b82f44e7495296f74d1d04
parent5931542314efea4d0c4642bf117810b5fa6f22d0 (diff)
downloadgnutls-cc8a6733f254f81a91f03aa836dfd91a22f4fc3a.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 84452a999b..3e26ddb8fe 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