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;
}