]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
key_share: detect overlap of PK types in hybrid groups
authorDaiki Ueno <ueno@gnu.org>
Fri, 1 Nov 2024 01:50:56 +0000 (10:50 +0900)
committerDaiki Ueno <ueno@gnu.org>
Fri, 1 Nov 2024 02:04:22 +0000 (11:04 +0900)
The client limits sending the key_share extension to at most one from
each public key type. To support hybrid groups, the logic needs to be
extedended to check all siblings.

Signed-off-by: Daiki Ueno <ueno@gnu.org>
lib/algorithms.h
lib/ext/key_share.c
lib/ext/supported_groups.c

index 4eb48e9cdde57fc18a52df7ac2b7de21012ae928..2e1b694c64dd1aa7be3e9d1bb92b961d253eb9a4 100644 (file)
@@ -49,6 +49,9 @@
         ((x) == GNUTLS_PK_EDDSA_ED25519) || ((x) == GNUTLS_PK_ECDH_X448) || \
         ((x) == GNUTLS_PK_EDDSA_ED448))
 
+#define IS_ECDHX(x) \
+       (((x) == GNUTLS_PK_ECDH_X25519) || ((x) == GNUTLS_PK_ECDH_X448))
+
 #define IS_KEM(x) \
        (((x) == GNUTLS_PK_MLKEM768) || ((x) == GNUTLS_PK_EXP_KYBER768))
 
index caf823d35eaad9ea025a11202969e73b979dc74f..57452115733ae0631535b73215610ef6580436cb 100644 (file)
@@ -911,7 +911,8 @@ static int key_share_recv_params(gnutls_session_t session, const uint8_t *data,
                                _gnutls_handshake_log(
                                        "EXT[%p]: received share for %s which is disabled\n",
                                        session, group->name);
-                               return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+                               return gnutls_assert_val(
+                                       GNUTLS_E_ECC_UNSUPPORTED_CURVE);
                        }
 
                        _gnutls_session_group_set(session, group);
@@ -942,7 +943,8 @@ static int key_share_recv_params(gnutls_session_t session, const uint8_t *data,
                        _gnutls_handshake_log(
                                "EXT[%p]: received share for %s which is disabled\n",
                                session, group->name);
-                       return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE);
+                       return gnutls_assert_val(
+                               GNUTLS_E_ECC_UNSUPPORTED_CURVE);
                }
 
                _gnutls_session_group_set(session, group);
@@ -956,15 +958,23 @@ static int key_share_recv_params(gnutls_session_t session, const uint8_t *data,
        return 0;
 }
 
-static inline bool pk_type_is_ecdhx(gnutls_pk_algorithm_t pk)
+static inline bool pk_types_overlap(const gnutls_group_entry_st *a,
+                                   const gnutls_group_entry_st *b)
 {
-       return pk == GNUTLS_PK_ECDH_X25519 || pk == GNUTLS_PK_ECDH_X448;
-}
+       const gnutls_group_entry_st *pa;
 
-static inline bool pk_type_equal(gnutls_pk_algorithm_t a,
-                                gnutls_pk_algorithm_t b)
-{
-       return a == b || (pk_type_is_ecdhx(a) && pk_type_is_ecdhx(b));
+       for (pa = a; pa != NULL; pa = pa->next) {
+               const gnutls_group_entry_st *pb;
+
+               for (pb = b; pb != NULL; pb = pb->next) {
+                       if (pa->pk == pb->pk ||
+                           (IS_ECDHX(pa->pk) && IS_ECDHX(pb->pk)) ||
+                           (IS_KEM(pa->pk) && IS_KEM(pb->pk)))
+                               return true;
+               }
+       }
+
+       return false;
 }
 
 /* returns data_size or a negative number on failure
@@ -1009,7 +1019,9 @@ static int key_share_send_params(gnutls_session_t session,
                        if (ret < 0)
                                return gnutls_assert_val(ret);
                } else {
-                       gnutls_pk_algorithm_t selected_groups[3];
+                       const gnutls_group_entry_st *selected_groups[3] = {
+                               NULL,
+                       };
                        unsigned max_groups = 2; /* GNUTLS_KEY_SHARE_TOP2 */
 
                        if (session->internals.flags & GNUTLS_KEY_SHARE_TOP)
@@ -1033,8 +1045,9 @@ static int key_share_send_params(gnutls_session_t session,
                                                .entry[i];
 
                                for (j = 0; j < generated; j++) {
-                                       if (pk_type_equal(group->pk,
-                                                         selected_groups[j])) {
+                                       if (pk_types_overlap(
+                                                   group,
+                                                   selected_groups[j])) {
                                                break;
                                        }
                                }
@@ -1042,7 +1055,7 @@ static int key_share_send_params(gnutls_session_t session,
                                        continue;
                                }
 
-                               selected_groups[generated] = group->pk;
+                               selected_groups[generated] = group;
 
                                ret = client_gen_key_share(session, group,
                                                           extdata);
index ebad0068f6241735f5eeb4cdb623feb13e349c38..254ec4882a515c18a5cd265ac05191b57ea4ab97 100644 (file)
@@ -309,7 +309,8 @@ static int _gnutls_supported_groups_send_params(gnutls_session_t session,
 /* Returns 0 if the given ECC curve is allowed in the current
  * session. A negative error value is returned otherwise.
  */
-bool _gnutls_session_supports_group(gnutls_session_t session, unsigned int group)
+bool _gnutls_session_supports_group(gnutls_session_t session,
+                                   unsigned int group)
 {
        unsigned i;