]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
key share: added flags to gnutls_init() to modify its default behavior
authorNikos Mavrogiannopoulos <nmav@redhat.com>
Fri, 6 Oct 2017 07:05:20 +0000 (09:05 +0200)
committerNikos Mavrogiannopoulos <nmav@redhat.com>
Mon, 19 Feb 2018 14:29:35 +0000 (15:29 +0100)
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>
lib/ext/key_share.c
lib/includes/gnutls/gnutls.h.in

index 411b10e9bf339c1a24d90ab938ddeba154c2b723..2b31c95b4a0ce95f2ca782a9b3704ffa6d03bad5 100644 (file)
@@ -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 */
index 84452a999bf2c9379b6a37000c971b47c02b2daa..3e26ddb8fea0baa3acd55c77f428f971d512499e 100644 (file)
@@ -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