File gnutls-PSK-hash.patch of Package gnutls.42640

From e73b6bac7396db058ff408e6ae7e0b27cb432317 Mon Sep 17 00:00:00 2001
From: Hannes Reinecke <hare@suse.de>
Date: Fri, 14 Mar 2025 12:31:13 +0100
Subject: [PATCH] lib/psk: Add gnutls_psk_allocate_{client,server}_credentials2

Add new functions gnutls_psk_allocate_client_credentials2() and
gnutls_psk_allocate_server_credentials2() which allow to specify
the hash algorithm for the PSK. This fixes a bug in the current
implementation where the binder is always calculated with SHA256.

Signed-off-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Daiki Ueno <ueno@gnu.org>
---
 doc/Makefile.am                 |  4 +++
 doc/manpages/Makefile.am        |  2 ++
 lib/ext/pre_shared_key.c        | 13 ++++++++
 lib/includes/gnutls/gnutls.h.in |  5 +++
 lib/libgnutls.map               |  9 ++++++
 lib/psk.c                       | 56 ++++++++++++++++++++++++++++++---

Index: gnutls-3.8.3/doc/Makefile.am
===================================================================
--- gnutls-3.8.3.orig/doc/Makefile.am
+++ gnutls-3.8.3/doc/Makefile.am
@@ -1774,8 +1774,12 @@ FUNCS += functions/gnutls_protocol_set_e
 FUNCS += functions/gnutls_protocol_set_enabled.short
 FUNCS += functions/gnutls_psk_allocate_client_credentials
 FUNCS += functions/gnutls_psk_allocate_client_credentials.short
+FUNCS += functions/gnutls_psk_allocate_client_credentials2
+FUNCS += functions/gnutls_psk_allocate_client_credentials2.short
 FUNCS += functions/gnutls_psk_allocate_server_credentials
 FUNCS += functions/gnutls_psk_allocate_server_credentials.short
+FUNCS += functions/gnutls_psk_allocate_server_credentials2
+FUNCS += functions/gnutls_psk_allocate_server_credentials2.short
 FUNCS += functions/gnutls_psk_client_get_hint
 FUNCS += functions/gnutls_psk_client_get_hint.short
 FUNCS += functions/gnutls_psk_format_imported_identity
Index: gnutls-3.8.3/doc/manpages/Makefile.am
===================================================================
--- gnutls-3.8.3.orig/doc/manpages/Makefile.am
+++ gnutls-3.8.3/doc/manpages/Makefile.am
@@ -733,7 +733,9 @@ APIMANS += gnutls_protocol_get_version.3
 APIMANS += gnutls_protocol_list.3
 APIMANS += gnutls_protocol_set_enabled.3
 APIMANS += gnutls_psk_allocate_client_credentials.3
+APIMANS += gnutls_psk_allocate_client_credentials2.3
 APIMANS += gnutls_psk_allocate_server_credentials.3
+APIMANS += gnutls_psk_allocate_server_credentials2.3
 APIMANS += gnutls_psk_client_get_hint.3
 APIMANS += gnutls_psk_format_imported_identity.3
 APIMANS += gnutls_psk_free_client_credentials.3
Index: gnutls-3.8.3/lib/ext/pre_shared_key.c
===================================================================
--- gnutls-3.8.3.orig/lib/ext/pre_shared_key.c
+++ gnutls-3.8.3/lib/ext/pre_shared_key.c
@@ -827,7 +827,9 @@ static int server_recv_params(gnutls_ses
 	struct timespec ticket_creation_time = { 0, 0 };
 	enum binder_type binder_type;
 	bool refuse_early_data = false;
+	gnutls_mac_algorithm_t mac = GNUTLS_MAC_SHA384;
 
+retry_binder:
 	ret = _gnutls13_psk_ext_parser_init(&psk_parser, data, len);
 	if (ret < 0) {
 		/* No PSKs advertised by client */
@@ -885,6 +887,8 @@ static int server_recv_params(gnutls_ses
 			uint8_t ipsk[MAX_HASH_SIZE];
 
 			prf = pskcred->binder_algo;
+			if (prf->id == GNUTLS_MAC_UNKNOWN)
+				prf = _gnutls_mac_to_entry(mac);
 
 			/* this fails only on configuration errors; as such we always
 			 * return its error code in that case */
@@ -974,6 +978,15 @@ static int server_recv_params(gnutls_ses
 
 	if (_gnutls_mac_get_algo_len(prf) != binder_recvd.size ||
 	    gnutls_memcmp(binder_value, binder_recvd.data, binder_recvd.size)) {
+		/*
+		 * Older clients will always use SHA256 as binder algorithm
+		 * even for SHA384 PSKs, so we need to retry with SHA256
+		 * to calculate the correct binder value for those.
+		 */
+		if (prf->id == GNUTLS_MAC_UNKNOWN && mac == GNUTLS_MAC_SHA384) {
+			mac = GNUTLS_MAC_SHA256;
+			goto retry_binder;
+		}
 		gnutls_assert();
 		ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
 		goto fail;
Index: gnutls-3.8.3/lib/includes/gnutls/gnutls.h.in
===================================================================
--- gnutls-3.8.3.orig/lib/includes/gnutls/gnutls.h.in
+++ gnutls-3.8.3/lib/includes/gnutls/gnutls.h.in
@@ -2552,6 +2552,9 @@ typedef enum gnutls_psk_key_flags {
 
 void gnutls_psk_free_client_credentials(gnutls_psk_client_credentials_t sc);
 int gnutls_psk_allocate_client_credentials(gnutls_psk_client_credentials_t *sc);
+int gnutls_psk_allocate_client_credentials2(gnutls_psk_client_credentials_t *sc,
+					    gnutls_mac_algorithm_t mac);
+
 int gnutls_psk_set_client_credentials(gnutls_psk_client_credentials_t res,
 				      const char *username,
 				      const gnutls_datum_t *key,
@@ -2563,6 +2566,8 @@ int gnutls_psk_set_client_credentials2(g
 
 void gnutls_psk_free_server_credentials(gnutls_psk_server_credentials_t sc);
 int gnutls_psk_allocate_server_credentials(gnutls_psk_server_credentials_t *sc);
+int gnutls_psk_allocate_server_credentials2(gnutls_psk_server_credentials_t *sc,
+					    gnutls_mac_algorithm_t mac);
 int gnutls_psk_set_server_credentials_file(gnutls_psk_server_credentials_t res,
 					   const char *password_file);
 
Index: gnutls-3.8.3/lib/libgnutls.map
===================================================================
--- gnutls-3.8.3.orig/lib/libgnutls.map
+++ gnutls-3.8.3/lib/libgnutls.map
@@ -1432,6 +1432,15 @@ GNUTLS_3_8_2
 	*;
 } GNUTLS_3_8_1;
 
+GNUTLS_3_8_11
+{
+ global:
+	gnutls_psk_allocate_client_credentials2;
+	gnutls_psk_allocate_server_credentials2;
+ local:
+	*;
+} GNUTLS_3_8_2;
+
 GNUTLS_FIPS140_3_4 {
   global:
 	gnutls_cipher_self_test;
Index: gnutls-3.8.3/lib/psk.c
===================================================================
--- gnutls-3.8.3.orig/lib/psk.c
+++ gnutls-3.8.3/lib/psk.c
@@ -61,13 +61,34 @@ void gnutls_psk_free_client_credentials(
  **/
 int gnutls_psk_allocate_client_credentials(gnutls_psk_client_credentials_t *sc)
 {
+	/* TLS 1.3 - Default binder HMAC algorithm is SHA-256 */
+	return gnutls_psk_allocate_client_credentials2(sc, GNUTLS_MAC_SHA256);
+}
+
+/**
+ * gnutls_psk_allocate_client_credentials2:
+ * @sc: is a pointer to a #gnutls_psk_client_credentials_t type.
+ * @mac: encryption algorithm to use
+ *
+ * Allocate a gnutls_psk_client_credentials_t structure and initializes
+ * the HMAC binder algorithm to @mac.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
+ *   an error code is returned.
+ **/
+int gnutls_psk_allocate_client_credentials2(gnutls_psk_client_credentials_t *sc,
+					    gnutls_mac_algorithm_t mac)
+{
+	/* TLS 1.3 - Only SHA-256 and SHA-384 are allowed */
+	if (mac != GNUTLS_MAC_SHA256 && mac != GNUTLS_MAC_SHA384)
+		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
 	*sc = gnutls_calloc(1, sizeof(psk_client_credentials_st));
 
 	if (*sc == NULL)
 		return GNUTLS_E_MEMORY_ERROR;
 
-	/* TLS 1.3 - Default binder HMAC algorithm is SHA-256 */
-	(*sc)->binder_algo = _gnutls_mac_to_entry(GNUTLS_MAC_SHA256);
+	(*sc)->binder_algo = _gnutls_mac_to_entry(mac);
 	return 0;
 }
 
@@ -203,13 +224,40 @@ void gnutls_psk_free_server_credentials(
  **/
 int gnutls_psk_allocate_server_credentials(gnutls_psk_server_credentials_t *sc)
 {
+	/* TLS 1.3 - Default binder HMAC algorithm is SHA-256 */
+	return gnutls_psk_allocate_server_credentials2(sc, GNUTLS_MAC_SHA256);
+}
+
+/**
+ * gnutls_psk_allocate_server_credentials2:
+ * @sc: is a pointer to a #gnutls_psk_server_credentials_t type.
+ * @mac: encryption algorithm to use
+ *
+ * Allocate a gnutls_psk_server_credentials_t structure and initializes
+ * the HMAC binder algorithm to @mac. If @mac is set to GNUTLS_MAC_UNKNOWN
+ * both possible algorithms SHA384 and SHA256 are applied to find a matching
+ * binder value.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
+ *   an error code is returned.
+ **/
+int gnutls_psk_allocate_server_credentials2(gnutls_psk_server_credentials_t *sc,
+					    gnutls_mac_algorithm_t mac)
+{
+	/*
+	 * TLS 1.3 - Only SHA-256 and SHA-384 are allowed;
+	 * additionally allow GNUTLS_MAC_UNKNOWN for autodetection.
+	 */
+	if (mac != GNUTLS_MAC_SHA256 && mac != GNUTLS_MAC_SHA384 &&
+	    mac != GNUTLS_MAC_UNKNOWN)
+		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
 	*sc = gnutls_calloc(1, sizeof(psk_server_cred_st));
 
 	if (*sc == NULL)
 		return GNUTLS_E_MEMORY_ERROR;
 
-	/* TLS 1.3 - Default binder HMAC algorithm is SHA-256 */
-	(*sc)->binder_algo = _gnutls_mac_to_entry(GNUTLS_MAC_SHA256);
+	(*sc)->binder_algo = _gnutls_mac_to_entry(mac);
 	return 0;
 }
 
openSUSE Build Service is sponsored by