From 1c5609b103eb8a5e47488306e9b34ff2021b41fa Mon Sep 17 00:00:00 2001
From: tb <>
Date: Wed, 17 Aug 2022 18:45:25 +0000
Subject: Refactor tls1_get_supported_group()

This splits tls1_get_supported_group() into a few helper functions to
be able to count shared groups and to return the n-th shared group since
someone thought it is a great idea to expose that in a single API and
some others thought it is useful to add this info to log noise.

This is all made a bit more complicated thanks to the security level
having its tentacles everywhere and because a user-provided security
callback can influence the list of groups shared by the peers.

ok jsing
---
 src/lib/libssl/ssl_locl.h |   6 ++-
 src/lib/libssl/t1_lib.c   | 123 +++++++++++++++++++++++++++++++++++-----------
 2 files changed, 99 insertions(+), 30 deletions(-)

(limited to 'src')

diff --git a/src/lib/libssl/ssl_locl.h b/src/lib/libssl/ssl_locl.h
index 6e4eb403cd..35fa4c693c 100644
--- a/src/lib/libssl/ssl_locl.h
+++ b/src/lib/libssl/ssl_locl.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssl_locl.h,v 1.420 2022/08/17 18:42:13 tb Exp $ */
+/* $OpenBSD: ssl_locl.h,v 1.421 2022/08/17 18:45:25 tb Exp $ */
 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
  * All rights reserved.
  *
@@ -1527,7 +1527,9 @@ int tls1_ec_group_id2nid(uint16_t group_id, int *out_nid);
 int tls1_ec_group_id2bits(uint16_t group_id, int *out_bits);
 int tls1_ec_nid2group_id(int nid, uint16_t *out_group_id);
 int tls1_check_group(SSL *s, uint16_t group_id);
-int tls1_get_supported_group(SSL *s, int *group_nid);
+int tls1_count_shared_groups(const SSL *ssl, size_t *out_count);
+int tls1_get_shared_group_by_index(const SSL *ssl, size_t n, int *out_nid);
+int tls1_get_supported_group(const SSL *s, int *out_nid);
 
 int ssl_check_clienthello_tlsext_early(SSL *s);
 int ssl_check_clienthello_tlsext_late(SSL *s);
diff --git a/src/lib/libssl/t1_lib.c b/src/lib/libssl/t1_lib.c
index 049a55288d..355c9827ef 100644
--- a/src/lib/libssl/t1_lib.c
+++ b/src/lib/libssl/t1_lib.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: t1_lib.c,v 1.194 2022/08/17 18:42:13 tb Exp $ */
+/* $OpenBSD: t1_lib.c,v 1.195 2022/08/17 18:45:25 tb Exp $ */
 /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
  * All rights reserved.
  *
@@ -441,6 +441,100 @@ tls1_get_group_list(const SSL *s, int client_groups, const uint16_t **pgroups,
 	}
 }
 
+static int
+tls1_get_group_lists(const SSL *ssl, const uint16_t **pref, size_t *preflen,
+    const uint16_t **supp, size_t *supplen)
+{
+	unsigned long server_pref;
+
+	/* Cannot do anything on the client side. */
+	if (!ssl->server)
+		return 0;
+
+	server_pref = (ssl->internal->options & SSL_OP_CIPHER_SERVER_PREFERENCE);
+	tls1_get_group_list(ssl, (server_pref == 0), pref, preflen);
+	tls1_get_group_list(ssl, (server_pref != 0), supp, supplen);
+
+	return 1;
+}
+
+static int
+tls1_group_id_present(uint16_t group_id, const uint16_t *list, size_t list_len)
+{
+	size_t i;
+
+	for (i = 0; i < list_len; i++) {
+		if (group_id == list[i])
+			return 1;
+	}
+
+	return 0;
+}
+
+int
+tls1_count_shared_groups(const SSL *ssl, size_t *out_count)
+{
+	size_t count, preflen, supplen, i;
+	const uint16_t *pref, *supp;
+
+	if (!tls1_get_group_lists(ssl, &pref, &preflen, &supp, &supplen))
+		return 0;
+
+	count = 0;
+	for (i = 0; i < preflen; i++) {
+		if (!tls1_group_id_present(pref[i], supp, supplen))
+			continue;
+
+		if (!ssl_security_shared_group(ssl, pref[i]))
+			continue;
+
+		count++;
+	}
+
+	*out_count = count;
+
+	return 1;
+}
+
+static int
+tls1_group_by_index(const SSL *ssl, size_t n, int *out_nid,
+    int (*ssl_security_fn)(const SSL *, uint16_t))
+{
+	size_t count, preflen, supplen, i;
+	const uint16_t *pref, *supp;
+
+	if (!tls1_get_group_lists(ssl, &pref, &preflen, &supp, &supplen))
+		return 0;
+
+	count = 0;
+	for (i = 0; i < preflen; i++) {
+		if (!tls1_group_id_present(pref[i], supp, supplen))
+			continue;
+
+		if (!ssl_security_fn(ssl, pref[i]))
+			continue;
+
+		if (count++ == n)
+			return tls1_ec_group_id2nid(pref[i], out_nid);
+	}
+
+	return 0;
+}
+
+int
+tls1_get_shared_group_by_index(const SSL *ssl, size_t index, int *out_nid)
+{
+	return tls1_group_by_index(ssl, index, out_nid,
+	    ssl_security_shared_group);
+}
+
+int
+tls1_get_supported_group(const SSL *ssl, int *out_nid)
+{
+	return tls1_group_by_index(ssl, 0, out_nid,
+	    ssl_security_supported_group);
+}
+
 int
 tls1_set_groups(uint16_t **out_group_ids, size_t *out_group_ids_len,
     const int *groups, size_t ngroups)
@@ -530,33 +624,6 @@ tls1_check_group(SSL *s, uint16_t group_id)
 	return 0;
 }
 
-int
-tls1_get_supported_group(SSL *s, int *out_nid)
-{
-	size_t preflen, supplen, i, j;
-	const uint16_t *pref, *supp;
-	unsigned long server_pref;
-
-	/* Cannot do anything on the client side. */
-	if (s->server == 0)
-		return 0;
-
-	/* Return first preference supported group. */
-	server_pref = (s->internal->options & SSL_OP_CIPHER_SERVER_PREFERENCE);
-	tls1_get_group_list(s, (server_pref == 0), &pref, &preflen);
-	tls1_get_group_list(s, (server_pref != 0), &supp, &supplen);
-
-	for (i = 0; i < preflen; i++) {
-		if (!ssl_security_supported_group(s, pref[i]))
-			continue;
-		for (j = 0; j < supplen; j++) {
-			if (pref[i] == supp[j])
-				return tls1_ec_group_id2nid(pref[i], out_nid);
-		}
-	}
-	return 0;
-}
-
 /* For an EC key set TLS ID and required compression based on parameters. */
 static int
 tls1_set_ec_id(uint16_t *group_id, uint8_t *comp_id, EC_KEY *ec)
-- 
cgit v1.2.3-55-g6feb