File gnutls-increase-TLS-PSK-username-limit.patch of Package gnutls.33311

From f032324af70b8420f7b550f3277efd4a9cd2b2dd Mon Sep 17 00:00:00 2001
From: Zoltan Fridrich <zfridric@redhat.com>
Date: Tue, 10 May 2022 15:20:45 +0200
Subject: [PATCH] Increase the limit of TLS PSK usernames from 128 to 65535
 characters

Co-authored-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Zoltan Fridrich <zfridric@redhat.com>
---
 NEWS                     |  3 ++
 lib/auth.c               | 19 +++++++++++
 lib/auth/dhe_psk.c       | 51 ++++++++++++++---------------
 lib/auth/psk.c           | 64 ++++++++++++++-----------------------
 lib/auth/psk.h           | 35 ++++++++++++++------
 lib/auth/rsa_psk.c       |  4 ++-
 lib/auth/srp_kx.c        | 15 +++++----
 lib/auth/srp_kx.h        |  3 +-
 lib/ext/pre_shared_key.c | 16 ++++++++--
 lib/ext/srp.c            |  5 ---
 lib/gnutls_int.h         | 10 ++++--
 lib/handshake-checks.c   | 22 +++++++++----
 lib/psk.c                |  8 +----
 lib/session_pack.c       | 69 ++++++++++++++++++++++------------------
 lib/state.c              |  2 ++
 15 files changed, 187 insertions(+), 139 deletions(-)

Index: gnutls-3.7.3/lib/auth.c
===================================================================
--- gnutls-3.7.3.orig/lib/auth.c
+++ gnutls-3.7.3/lib/auth.c
@@ -28,6 +28,7 @@
 #include "algorithms.h"
 #include <auth/cert.h>
 #include <auth/psk.h>
+#include <auth/srp_kx.h>
 #include <auth/anon.h>
 #include <datum.h>
 
@@ -327,6 +328,16 @@ void _gnutls_free_auth_info(gnutls_sessi
 
 	switch (session->key.auth_info_type) {
 	case GNUTLS_CRD_SRP:
+		{
+			srp_server_auth_info_t info =
+			    _gnutls_get_auth_info(session, GNUTLS_CRD_SRP);
+
+			if (info == NULL)
+				break;
+
+			gnutls_free(info->username);
+			info->username = NULL;
+		}
 		break;
 #ifdef ENABLE_ANON
 	case GNUTLS_CRD_ANON:
@@ -350,6 +361,14 @@ void _gnutls_free_auth_info(gnutls_sessi
 			if (info == NULL)
 				break;
 
+			gnutls_free(info->username);
+			info->username = NULL;
+			info->username_len = 0;
+
+			gnutls_free(info->hint);
+			info->hint = NULL;
+			info->hint_len = 0;
+
 #ifdef ENABLE_DHE
 			dh_info = &info->dh;
 			_gnutls_free_dh_info(dh_info);
Index: gnutls-3.7.3/lib/auth/dhe_psk.c
===================================================================
--- gnutls-3.7.3.orig/lib/auth/dhe_psk.c
+++ gnutls-3.7.3/lib/auth/dhe_psk.c
@@ -316,7 +316,9 @@ proc_dhe_psk_client_kx(gnutls_session_t
 		return GNUTLS_E_ILLEGAL_SRP_USERNAME;
 	}
 
-	_gnutls_copy_psk_username(info, &username);
+	ret = _gnutls_copy_psk_username(info, username);
+	if (ret < 0)
+		return gnutls_assert_val(ret);
 
 	/* Adjust the data */
 	data += username.size + 2;
@@ -382,7 +384,9 @@ proc_ecdhe_psk_client_kx(gnutls_session_
 		return GNUTLS_E_ILLEGAL_SRP_USERNAME;
 	}
 
-	_gnutls_copy_psk_username(info, &username);
+	ret = _gnutls_copy_psk_username(info, username);
+	if (ret < 0)
+		return gnutls_assert_val(ret);
 
 	/* Adjust the data */
 	data += username.size + 2;
@@ -403,29 +407,6 @@ proc_ecdhe_psk_client_kx(gnutls_session_
 	return ret;
 }
 
-static int copy_hint(gnutls_session_t session, gnutls_datum_t *hint)
-{
-	psk_auth_info_t info;
-
-	/* copy the hint to the auth info structures
-	 */
-	info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
-	if (info == NULL) {
-		gnutls_assert();
-		return GNUTLS_E_INTERNAL_ERROR;
-	}
-
-	if (hint->size > MAX_USERNAME_SIZE) {
-		gnutls_assert();
-		return GNUTLS_E_ILLEGAL_SRP_USERNAME;
-	}
-
-	memcpy(info->hint, hint->data, hint->size);
-	info->hint[hint->size] = 0;
-
-	return 0;
-}
-
 static int
 proc_dhe_psk_server_kx(gnutls_session_t session, uint8_t * data,
 		       size_t _data_size)
@@ -433,6 +414,7 @@ proc_dhe_psk_server_kx(gnutls_session_t
 
 	int ret;
 	ssize_t data_size = _data_size;
+	psk_auth_info_t info;
 	gnutls_datum_t hint;
 
 	/* set auth_info */
@@ -457,7 +439,14 @@ proc_dhe_psk_server_kx(gnutls_session_t
 		return ret;
 	}
 
-	ret = copy_hint(session, &hint);
+	info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
+	if (info == NULL)
+		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+
+	if (hint.size > MAX_USERNAME_SIZE)
+		return gnutls_assert_val(GNUTLS_E_ILLEGAL_SRP_USERNAME);
+
+	ret = _gnutls_copy_psk_hint(info, hint);
 	if (ret < 0) {
 		gnutls_assert();
 		return ret;
@@ -473,6 +462,7 @@ proc_ecdhe_psk_server_kx(gnutls_session_
 
 	int ret;
 	ssize_t data_size = _data_size;
+	psk_auth_info_t info;
 	gnutls_datum_t hint;
 
 	/* set auth_info */
@@ -497,7 +487,14 @@ proc_ecdhe_psk_server_kx(gnutls_session_
 		return ret;
 	}
 
-	ret = copy_hint(session, &hint);
+	info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
+	if (info == NULL)
+		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+
+	if (hint.size > MAX_USERNAME_SIZE)
+		return gnutls_assert_val(GNUTLS_E_ILLEGAL_SRP_USERNAME);
+
+	ret = _gnutls_copy_psk_hint(info, hint);
 	if (ret < 0) {
 		gnutls_assert();
 		return ret;
Index: gnutls-3.7.3/lib/auth/psk.c
===================================================================
--- gnutls-3.7.3.orig/lib/auth/psk.c
+++ gnutls-3.7.3/lib/auth/psk.c
@@ -162,15 +162,18 @@ _gnutls_gen_psk_client_kx(gnutls_session
 		gnutls_assert();
 	}
 
-	if (username.size > sizeof(info->username)-1) {
+	if (username.size > MAX_USERNAME_SIZE) {
 		gnutls_assert();
 		ret = GNUTLS_E_ILLEGAL_SRP_USERNAME;
 		goto cleanup;
 	}
 
 	assert(username.data != NULL);
-	_gnutls_copy_psk_username(info, &username);
-
+	ret = _gnutls_copy_psk_username(info, username);
+	if (ret < 0) {
+		gnutls_assert();
+		goto cleanup;
+	}
 
       cleanup:
 	if (free) {
@@ -230,7 +233,9 @@ _gnutls_proc_psk_client_kx(gnutls_sessio
 		return GNUTLS_E_ILLEGAL_SRP_USERNAME;
 	}
 
-	_gnutls_copy_psk_username(info, &username);
+	ret = _gnutls_copy_psk_username(info, username);
+	if (ret < 0)
+		return gnutls_assert_val(ret);
 
 	ret =
 	    _gnutls_psk_pwd_find_entry(session, info->username, info->username_len, &psk_key);
@@ -291,59 +296,38 @@ _gnutls_gen_psk_server_kx(gnutls_session
 						 hint.size);
 }
 
-
-/* just read the hint from the server key exchange.
- */
+/* Read the hint from the server key exchange */
 static int
-_gnutls_proc_psk_server_kx(gnutls_session_t session, uint8_t * data,
-			   size_t _data_size)
+_gnutls_proc_psk_server_kx(gnutls_session_t session, uint8_t * data, size_t _data_size)
 {
-	ssize_t data_size = _data_size;
 	int ret;
-	gnutls_datum_t hint;
+	ssize_t data_size = _data_size;
 	gnutls_psk_client_credentials_t cred;
 	psk_auth_info_t info;
+	gnutls_datum_t hint;
 
-	cred = (gnutls_psk_client_credentials_t)
-	    _gnutls_get_cred(session, GNUTLS_CRD_PSK);
-
-	if (cred == NULL) {
-		gnutls_assert();
-		return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
-	}
+	cred = (gnutls_psk_client_credentials_t) _gnutls_get_cred(session, GNUTLS_CRD_PSK);
+	if (cred == NULL)
+		return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
 
-	if ((ret =
-	     _gnutls_auth_info_init(session, GNUTLS_CRD_PSK,
-				   sizeof(psk_auth_info_st), 1)) < 0) {
-		gnutls_assert();
-		return ret;
-	}
+	ret = _gnutls_auth_info_init(session, GNUTLS_CRD_PSK, sizeof(psk_auth_info_st), 1);
+	if (ret < 0)
+		return gnutls_assert_val(ret);
 
 	DECR_LENGTH_RET(data_size, 2, 0);
 	hint.size = _gnutls_read_uint16(&data[0]);
 
 	DECR_LEN(data_size, hint.size);
-
 	hint.data = &data[2];
 
-	/* copy the hint to the auth info structures
-	 */
 	info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
-	if (info == NULL) {
-		gnutls_assert();
-		return GNUTLS_E_INTERNAL_ERROR;
-	}
-
-	if (hint.size > sizeof(info->hint)-1) {
-		gnutls_assert();
-		return GNUTLS_E_ILLEGAL_SRP_USERNAME;
-	}
+	if (info == NULL)
+		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
 
-	memcpy(info->hint, hint.data, hint.size);
-	info->hint[hint.size] = 0;
-
-	ret = 0;
+	if (hint.size > MAX_USERNAME_SIZE)
+		return gnutls_assert_val(GNUTLS_E_ILLEGAL_SRP_USERNAME);
 
+        ret = _gnutls_copy_psk_hint(info, hint);
 	return ret;
 }
 
Index: gnutls-3.7.3/lib/auth/psk.h
===================================================================
--- gnutls-3.7.3.orig/lib/auth/psk.h
+++ gnutls-3.7.3/lib/auth/psk.h
@@ -26,6 +26,12 @@
 #include <auth.h>
 #include <auth/dh_common.h>
 
+#define _gnutls_copy_psk_username(info, datum) \
+	_gnutls_copy_psk_string(&(info)->username, &(info)->username_len, (datum))
+
+#define _gnutls_copy_psk_hint(info, datum) \
+	_gnutls_copy_psk_string(&(info)->hint, &(info)->hint_len, (datum))
+
 typedef struct gnutls_psk_client_credentials_st {
 	gnutls_datum_t username;
 	gnutls_datum_t key;
@@ -58,23 +64,34 @@ typedef struct gnutls_psk_server_credent
 	const mac_entry_st *binder_algo;
 } psk_server_cred_st;
 
-/* these structures should not use allocated data */
 typedef struct psk_auth_info_st {
-	char username[MAX_USERNAME_SIZE + 1];
+	char *username;
 	uint16_t username_len;
 	dh_info_st dh;
-	char hint[MAX_USERNAME_SIZE + 1];
+	char *hint;
+	uint16_t hint_len;
 } *psk_auth_info_t;
 
 typedef struct psk_auth_info_st psk_auth_info_st;
 
-inline static
-void _gnutls_copy_psk_username(psk_auth_info_t info, const gnutls_datum_t *username)
+inline static int
+_gnutls_copy_psk_string(char **dest, uint16_t *dest_len, const gnutls_datum_t str)
 {
-	assert(sizeof(info->username) > username->size);
-	memcpy(info->username, username->data, username->size);
-	info->username[username->size] = 0;
-	info->username_len = username->size;
+	char *_tmp;
+
+	assert(MAX_USERNAME_SIZE >= str.size);
+
+	_tmp = gnutls_malloc(str.size + 1);
+	if (_tmp == NULL)
+		return GNUTLS_E_MEMORY_ERROR;
+	memcpy(_tmp, str.data, str.size);
+	_tmp[str.size] = '\0';
+
+	gnutls_free(*dest);
+	*dest = _tmp;
+	*dest_len = str.size;
+
+	return GNUTLS_E_SUCCESS;
 }
 
 #ifdef ENABLE_PSK
Index: gnutls-3.7.3/lib/auth/rsa_psk.c
===================================================================
--- gnutls-3.7.3.orig/lib/auth/rsa_psk.c
+++ gnutls-3.7.3/lib/auth/rsa_psk.c
@@ -310,7 +310,9 @@ _gnutls_proc_rsa_psk_client_kx(gnutls_se
 		return GNUTLS_E_ILLEGAL_SRP_USERNAME;
 	}
 
-	_gnutls_copy_psk_username(info, &username);
+	ret = _gnutls_copy_psk_username(info, username);
+	if (ret < 0)
+		gnutls_assert_val(ret);
 
 	/* Adjust data so it points to EncryptedPreMasterSecret */
 	data += username.size + 2;
Index: gnutls-3.7.3/lib/auth/srp_kx.c
===================================================================
--- gnutls-3.7.3.orig/lib/auth/srp_kx.c
+++ gnutls-3.7.3/lib/auth/srp_kx.c
@@ -119,10 +119,9 @@ _gnutls_gen_srp_server_kx(gnutls_session
 			  gnutls_buffer_st * data)
 {
 	int ret;
-	char *username;
 	SRP_PWD_ENTRY *pwd_entry;
 	srp_server_auth_info_t info;
-	size_t tmp_size;
+	size_t tmp_size, username_length;
 	gnutls_ext_priv_data_t epriv;
 	srp_ext_st *priv;
 	unsigned init_pos;
@@ -148,12 +147,16 @@ _gnutls_gen_srp_server_kx(gnutls_session
 	if (info == NULL)
 		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
 
-	username = info->username;
-
-	_gnutls_str_cpy(username, MAX_USERNAME_SIZE, priv->username);
-
-	ret = _gnutls_srp_pwd_read_entry(session, username, &pwd_entry);
+	username_length = strlen(priv->username);
+	if (username_length > MAX_USERNAME_SIZE)
+		return gnutls_assert_val(GNUTLS_E_ILLEGAL_SRP_USERNAME);
+
+	gnutls_free(info->username);
+	info->username = gnutls_strdup(priv->username);
+	if (info->username == NULL)
+		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
 
+	ret = _gnutls_srp_pwd_read_entry(session, priv->username, &pwd_entry);
 	if (ret < 0) {
 		gnutls_assert();
 		return ret;
Index: gnutls-3.7.3/lib/auth/srp_kx.h
===================================================================
--- gnutls-3.7.3.orig/lib/auth/srp_kx.h
+++ gnutls-3.7.3/lib/auth/srp_kx.h
@@ -46,9 +46,8 @@ typedef struct gnutls_srp_server_credent
 	unsigned int fake_salt_length;
 } srp_server_cred_st;
 
-/* these structures should not use allocated data */
 typedef struct srp_server_auth_info_st {
-	char username[MAX_USERNAME_SIZE + 1];
+	char *username;
 } *srp_server_auth_info_t;
 
 #ifdef ENABLE_SRP
Index: gnutls-3.7.3/lib/ext/pre_shared_key.c
===================================================================
--- gnutls-3.7.3.orig/lib/ext/pre_shared_key.c
+++ gnutls-3.7.3/lib/ext/pre_shared_key.c
@@ -392,7 +392,12 @@ client_send_params(gnutls_session_t sess
 		info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
 		assert(info != NULL);
 
-		_gnutls_copy_psk_username(info, &username);
+		ret = _gnutls_copy_psk_username(info, username);
+		if (ret < 0) {
+			gnutls_assert();
+			goto cleanup;
+		}
+
 
 		if ((ret = _gnutls_buffer_append_data_prefix(extdata, 16,
 							     username.data,
@@ -674,7 +679,7 @@ static int server_recv_params(gnutls_ses
 	/* save the username in psk_auth_info to make it available
 	 * using gnutls_psk_server_get_username() */
 	if (!resuming) {
-		assert(psk.identity.size < sizeof(info->username));
+		assert(psk.identity.size <= MAX_USERNAME_SIZE);
 
 		ret = _gnutls_auth_info_init(session, GNUTLS_CRD_PSK, sizeof(psk_auth_info_st), 1);
 		if (ret < 0) {
@@ -685,7 +690,12 @@ static int server_recv_params(gnutls_ses
 		info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
 		assert(info != NULL);
 
-		_gnutls_copy_psk_username(info, &psk.identity);
+		ret = _gnutls_copy_psk_username(info, psk.identity);
+		if (ret < 0) {
+			gnutls_assert();
+			goto fail;
+		}
+
 		_gnutls_handshake_log("EXT[%p]: selected PSK identity: %s (%d)\n", session, info->username, psk_index);
 
 		/* We currently only support early data in resuming connection,
Index: gnutls-3.7.3/lib/ext/srp.c
===================================================================
--- gnutls-3.7.3.orig/lib/ext/srp.c
+++ gnutls-3.7.3/lib/ext/srp.c
@@ -73,11 +73,6 @@ _gnutls_srp_recv_params(gnutls_session_t
 			len = data[0];
 			DECR_LEN(data_size, len);
 
-			if (MAX_USERNAME_SIZE < len) {
-				gnutls_assert();
-				return GNUTLS_E_ILLEGAL_SRP_USERNAME;
-			}
-
 			priv = gnutls_calloc(1, sizeof(*priv));
 			if (priv == NULL) {
 				gnutls_assert();
Index: gnutls-3.7.3/lib/gnutls_int.h
===================================================================
--- gnutls-3.7.3.orig/lib/gnutls_int.h
+++ gnutls-3.7.3/lib/gnutls_int.h
@@ -108,7 +108,10 @@ typedef int ssize_t;
 
 #define MAX_CIPHER_IV_SIZE 16
 
-#define MAX_USERNAME_SIZE 128
+/* Maximum size of 2^16-1 has been chosen so that usernames can hold
+ * PSK identities as defined in RFC 4279 section 2 and RFC 8446 section 4.2.11
+ */
+#define MAX_USERNAME_SIZE 65535
 #define MAX_SERVER_NAME_SIZE 256
 
 #define AEAD_EXPLICIT_DATA_SIZE 8
@@ -1438,7 +1441,10 @@ typedef struct {
 	bool cert_hash_set;
 
 	/* The saved username from PSK or SRP auth */
-	char saved_username[MAX_USERNAME_SIZE+1];
+	char *saved_username;
+	/* Length of the saved username without the NULL terminating byte.
+	 * Must be set to -1 when saved username is NULL
+	 */
 	int saved_username_size;
 
 	/* Needed for TCP Fast Open (TFO), set by gnutls_transport_set_fastopen() */
Index: gnutls-3.7.3/lib/handshake-checks.c
===================================================================
--- gnutls-3.7.3.orig/lib/handshake-checks.c
+++ gnutls-3.7.3/lib/handshake-checks.c
@@ -75,17 +75,27 @@ int _gnutls_check_id_for_change(gnutls_s
 		if (username == NULL)
 			return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
 
-		if (session->internals.saved_username_size != -1) {
+		if (session->internals.saved_username &&
+		    session->internals.saved_username_size != -1) {
 			if (session->internals.saved_username_size == username_length &&
-			    strncmp(session->internals.saved_username, username, username_length) != 0) {
+			    strncmp(session->internals.saved_username, username, username_length)) {
 				_gnutls_debug_log("Session's PSK username changed during rehandshake; aborting!\n");
 				return gnutls_assert_val(GNUTLS_E_SESSION_USER_ID_CHANGED);
 			}
-		} else {
-			memcpy(session->internals.saved_username, username, username_length);
-			session->internals.saved_username[username_length] = 0;
+		} else if (session->internals.saved_username == NULL &&
+			   session->internals.saved_username_size == -1) {
+			if (username_length > MAX_USERNAME_SIZE)
+				return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+			char *tmp = gnutls_malloc(username_length + 1);
+			if (tmp == NULL)
+				return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+			memcpy(tmp, username, username_length);
+			tmp[username_length] = '\0';
+			session->internals.saved_username = tmp;
 			session->internals.saved_username_size = username_length;
-		}
+		} else
+			return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+
 	}
 
 	return 0;
Index: gnutls-3.7.3/lib/psk.c
===================================================================
--- gnutls-3.7.3.orig/lib/psk.c
+++ gnutls-3.7.3/lib/psk.c
@@ -544,13 +544,7 @@ const char *gnutls_psk_client_get_hint(g
 	CHECK_AUTH_TYPE(GNUTLS_CRD_PSK, NULL);
 
 	info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
-	if (info == NULL)
-		return NULL;
-
-	if (info->hint[0] != 0)
-		return info->hint;
-
-	return NULL;
+	return info ? info->hint : NULL;
 }
 
 /**
Index: gnutls-3.7.3/lib/session_pack.c
===================================================================
--- gnutls-3.7.3.orig/lib/session_pack.c
+++ gnutls-3.7.3/lib/session_pack.c
@@ -600,8 +600,13 @@ pack_srp_auth_info(gnutls_session_t sess
 	const char *username = NULL;
 
 	if (info) {
-		username = info->username;
-		len = strlen(info->username) + 1;	/* include the terminating null */
+		if (info->username) {
+			username = info->username;
+			len = strlen(info->username) + 1; /* include the terminating null */
+		} else {
+			username = "\0";
+			len = 1;
+		}
 	} else
 		len = 0;
 
@@ -627,26 +632,27 @@ unpack_srp_auth_info(gnutls_session_t se
 	srp_server_auth_info_t info;
 
 	BUFFER_POP_NUM(ps, username_size);
-	if (username_size > sizeof(info->username)) {
-		gnutls_assert();
-		return GNUTLS_E_INTERNAL_ERROR;
-	}
+	if (username_size > MAX_USERNAME_SIZE + 1)
+		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
 
-	ret =
-	    _gnutls_auth_info_init(session, GNUTLS_CRD_SRP,
-				  sizeof(srp_server_auth_info_st), 1);
-	if (ret < 0) {
-		gnutls_assert();
-		return ret;
-	}
+	ret = _gnutls_auth_info_init(session, GNUTLS_CRD_SRP,
+				     sizeof(srp_server_auth_info_st), 1);
+	if (ret < 0)
+		return gnutls_assert_val(ret);
 
 	info = _gnutls_get_auth_info(session, GNUTLS_CRD_SRP);
 	if (info == NULL)
 		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
 
+	gnutls_free(info->username);
+	if (username_size == 0) {
+		info->username = NULL;
+	} else {
+		info->username = gnutls_malloc(username_size);
+		if (info->username == NULL)
+			return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+	}
 	BUFFER_POP(ps, info->username, username_size);
-	if (username_size == 0)
-		info->username[0] = 0;
 
 	ret = 0;
 
@@ -777,14 +783,14 @@ pack_psk_auth_info(gnutls_session_t sess
 		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
 
 	username_len = info->username_len;
-	hint_len = strlen(info->hint) + 1;	/* include the terminating null */
+	hint_len = info->hint_len + 1; /* include the terminating null */
 
 	size_offset = ps->length;
 	BUFFER_APPEND_NUM(ps, 0);
 	cur_size = ps->length;
 
 	BUFFER_APPEND_PFX4(ps, info->username, username_len);
-	BUFFER_APPEND_PFX4(ps, info->hint, hint_len);
+	BUFFER_APPEND_PFX4(ps, info->hint ? info->hint : "\0", hint_len);
 
 	BUFFER_APPEND_NUM(ps, info->dh.secret_bits);
 	BUFFER_APPEND_PFX4(ps, info->dh.prime.data, info->dh.prime.size);
@@ -824,27 +830,28 @@ unpack_psk_auth_info(gnutls_session_t se
 		return GNUTLS_E_INVALID_REQUEST;
 
 	BUFFER_POP_NUM(ps, username_size);
-	if (username_size > (sizeof(info->username) - 1)) {
-		gnutls_assert();
-		return GNUTLS_E_INTERNAL_ERROR;
-	}
+	if (username_size > MAX_USERNAME_SIZE)
+		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
 
+	gnutls_free(info->username);
+	info->username = gnutls_malloc(username_size + 1);
+	if (info->username == NULL)
+		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
 	BUFFER_POP(ps, info->username, username_size);
-	if (username_size == 0)
-		info->username[0] = 0;
-
-	/* append a null terminator and set length */
 	info->username[username_size] = 0;
 	info->username_len = username_size;
 
+	/* hint_size includes the terminating null */
 	BUFFER_POP_NUM(ps, hint_size);
-	if (hint_size > sizeof(info->hint)) {
-		gnutls_assert();
-		return GNUTLS_E_INTERNAL_ERROR;
-	}
+	if (hint_size > MAX_USERNAME_SIZE + 1)
+		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+
+	gnutls_free(info->hint);
+	info->hint = gnutls_malloc(hint_size);
+	if (info->hint == NULL)
+		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
 	BUFFER_POP(ps, info->hint, hint_size);
-	if (hint_size == 0)
-		info->hint[0] = 0;
+	info->hint_len = hint_size - 1;
 
 	BUFFER_POP_NUM(ps, info->dh.secret_bits);
 
Index: gnutls-3.7.3/lib/state.c
===================================================================
--- gnutls-3.7.3.orig/lib/state.c
+++ gnutls-3.7.3/lib/state.c
@@ -662,6 +662,7 @@ int gnutls_init(gnutls_session_t * sessi
 	(*session)->internals.pull_func = system_read;
 	(*session)->internals.errno_func = system_errno;
 
+	(*session)->internals.saved_username = NULL;
 	(*session)->internals.saved_username_size = -1;
 
 	/* heartbeat timeouts */
@@ -753,6 +754,7 @@ void gnutls_deinit(gnutls_session_t sess
 	gnutls_free(session->internals.rexts);
 	gnutls_free(session->internals.post_handshake_cr_context.data);
 
+	gnutls_free(session->internals.saved_username);
 	gnutls_free(session->internals.rsup);
 
 	gnutls_credentials_clear(session);
openSUSE Build Service is sponsored by