summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2020-03-24 08:26:01 +0000
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2020-03-24 08:26:01 +0000
commitff6eebd6592e8d77e4af6ff6e53f257bc8905844 (patch)
tree2dead8ee49ca683fdcd7c273387b5676e5cbf572 /lib
parent783fa7f82ee1d7db52b27c1ed24141d861e36110 (diff)
parentded59e682aeef30c7ae172cc22700f8f92faeb76 (diff)
downloadgnutls-ff6eebd6592e8d77e4af6ff6e53f257bc8905844.tar.gz
Merge branch 'ajuaristi-issue-586' into 'master'
support non-NULL-terminated PSKs Closes #586 See merge request gnutls/gnutls!917
Diffstat (limited to 'lib')
-rw-r--r--lib/auth/dhe_psk.c10
-rw-r--r--lib/auth/psk.c8
-rw-r--r--lib/auth/psk.h17
-rw-r--r--lib/auth/psk_passwd.c72
-rw-r--r--lib/auth/psk_passwd.h3
-rw-r--r--lib/auth/rsa_psk.c5
-rw-r--r--lib/ext/pre_shared_key.c14
-rw-r--r--lib/gnutls_int.h2
-rw-r--r--lib/handshake-checks.c16
-rw-r--r--lib/includes/gnutls/gnutls.h.in18
-rw-r--r--lib/libgnutls.map4
-rw-r--r--lib/psk.c179
-rw-r--r--lib/session_pack.c8
-rw-r--r--lib/state.c2
-rw-r--r--lib/str.h7
-rw-r--r--lib/x509/email-verify.c11
-rw-r--r--lib/x509/hostname-verify.c11
17 files changed, 309 insertions, 78 deletions
diff --git a/lib/auth/dhe_psk.c b/lib/auth/dhe_psk.c
index 6d66a6bb8b..a98ef9c9ef 100644
--- a/lib/auth/dhe_psk.c
+++ b/lib/auth/dhe_psk.c
@@ -316,14 +316,13 @@ proc_dhe_psk_client_kx(gnutls_session_t session, uint8_t * data,
return GNUTLS_E_ILLEGAL_SRP_USERNAME;
}
- memcpy(info->username, username.data, username.size);
- info->username[username.size] = 0;
+ _gnutls_copy_psk_username(info, &username);
/* Adjust the data */
data += username.size + 2;
ret =
- _gnutls_psk_pwd_find_entry(session, info->username, &psk_key);
+ _gnutls_psk_pwd_find_entry(session, info->username, info->username_len, &psk_key);
if (ret < 0)
return gnutls_assert_val(ret);
@@ -383,8 +382,7 @@ proc_ecdhe_psk_client_kx(gnutls_session_t session, uint8_t * data,
return GNUTLS_E_ILLEGAL_SRP_USERNAME;
}
- memcpy(info->username, username.data, username.size);
- info->username[username.size] = 0;
+ _gnutls_copy_psk_username(info, &username);
/* Adjust the data */
data += username.size + 2;
@@ -392,7 +390,7 @@ proc_ecdhe_psk_client_kx(gnutls_session_t session, uint8_t * data,
/* should never fail. It will always return a key even if it is
* a random one */
ret =
- _gnutls_psk_pwd_find_entry(session, info->username, &psk_key);
+ _gnutls_psk_pwd_find_entry(session, info->username, info->username_len, &psk_key);
if (ret < 0)
return gnutls_assert_val(ret);
diff --git a/lib/auth/psk.c b/lib/auth/psk.c
index 769510af4f..6f220b6382 100644
--- a/lib/auth/psk.c
+++ b/lib/auth/psk.c
@@ -169,8 +169,7 @@ _gnutls_gen_psk_client_kx(gnutls_session_t session,
}
assert(username.data != NULL);
- memcpy(info->username, username.data, username.size);
- info->username[username.size] = 0;
+ _gnutls_copy_psk_username(info, &username);
cleanup:
@@ -231,11 +230,10 @@ _gnutls_proc_psk_client_kx(gnutls_session_t session, uint8_t * data,
return GNUTLS_E_ILLEGAL_SRP_USERNAME;
}
- memcpy(info->username, username.data, username.size);
- info->username[username.size] = 0;
+ _gnutls_copy_psk_username(info, &username);
ret =
- _gnutls_psk_pwd_find_entry(session, info->username, &psk_key);
+ _gnutls_psk_pwd_find_entry(session, info->username, info->username_len, &psk_key);
if (ret < 0)
return gnutls_assert_val(ret);
diff --git a/lib/auth/psk.h b/lib/auth/psk.h
index 1592035bb1..b0e511f7fe 100644
--- a/lib/auth/psk.h
+++ b/lib/auth/psk.h
@@ -29,7 +29,8 @@
typedef struct gnutls_psk_client_credentials_st {
gnutls_datum_t username;
gnutls_datum_t key;
- gnutls_psk_client_credentials_function *get_function;
+ gnutls_psk_client_credentials_function2 *get_function;
+ gnutls_psk_client_credentials_function *get_function_legacy;
/* TLS 1.3 - The HMAC algorithm to use to compute the binder values */
const mac_entry_st *binder_algo;
} psk_client_credentials_st;
@@ -39,7 +40,8 @@ typedef struct gnutls_psk_server_credentials_st {
/* callback function, instead of reading the
* password files.
*/
- gnutls_psk_server_credentials_function *pwd_callback;
+ gnutls_psk_server_credentials_function2 *pwd_callback;
+ gnutls_psk_server_credentials_function *pwd_callback_legacy;
/* For DHE_PSK */
gnutls_dh_params_t dh_params;
@@ -59,12 +61,22 @@ typedef struct gnutls_psk_server_credentials_st {
/* these structures should not use allocated data */
typedef struct psk_auth_info_st {
char username[MAX_USERNAME_SIZE + 1];
+ uint16_t username_len;
dh_info_st dh;
char hint[MAX_USERNAME_SIZE + 1];
} *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)
+{
+ assert(sizeof(info->username) > username->size);
+ memcpy(info->username, username->data, username->size);
+ info->username[username->size] = 0;
+ info->username_len = username->size;
+}
+
#ifdef ENABLE_PSK
int
@@ -74,7 +86,6 @@ int _gnutls_gen_psk_server_kx(gnutls_session_t session,
gnutls_buffer_st * data);
int _gnutls_gen_psk_client_kx(gnutls_session_t, gnutls_buffer_st *);
-
#else
#define _gnutls_set_psk_session_key(x,y,z) GNUTLS_E_UNIMPLEMENTED_FEATURE
#endif /* ENABLE_PSK */
diff --git a/lib/auth/psk_passwd.c b/lib/auth/psk_passwd.c
index ec46ed3bf7..a0427914f9 100644
--- a/lib/auth/psk_passwd.c
+++ b/lib/auth/psk_passwd.c
@@ -73,7 +73,52 @@ static int pwd_put_values(gnutls_datum_t * psk, char *str)
}
return 0;
+}
+
+static bool username_matches(const gnutls_datum_t *username,
+ const char *line, size_t line_size)
+{
+ int retval;
+ unsigned i;
+ gnutls_datum_t hexline, hex_username = { NULL, 0 };
+
+ /*
+ * Guard against weird behavior - we don't check 'line',
+ * as it's returned by getline(), which will never return NULL
+ * if successful.
+ */
+ if (username->data == NULL)
+ return false;
+
+ if (line_size == 0)
+ return (username->size == 0);
+
+ /* move to first ':' */
+ i = 0;
+ while ((i < line_size) && (line[i] != '\0')
+ && (line[i] != ':')) {
+ i++;
+ }
+
+ /* if format is in hex, e.g. #FAFAFA */
+ if (line[0] == '#' && line_size > 1) {
+ hexline.data = (void *) &line[1];
+ hexline.size = i - 1;
+ if ((retval = gnutls_hex_decode2(&hexline, &hex_username)) < 0)
+ return gnutls_assert_val(0);
+
+ if (hex_username.size == username->size)
+ retval = memcmp(username->data, hex_username.data, username->size);
+ else
+ retval = -1;
+
+ _gnutls_free_datum(&hex_username);
+ } else {
+ retval = strncmp((const char *) username->data, line, MAX(i, username->size));
+ }
+
+ return (retval == 0);
}
@@ -105,15 +150,19 @@ static int _randomize_psk(gnutls_datum_t * psk)
* If the user doesn't exist a random password is returned instead.
*/
int
-_gnutls_psk_pwd_find_entry(gnutls_session_t session, char *username,
+_gnutls_psk_pwd_find_entry(gnutls_session_t session,
+ const char *username, uint16_t username_len,
gnutls_datum_t * psk)
{
gnutls_psk_server_credentials_t cred;
FILE *fd;
char *line = NULL;
size_t line_size = 0;
- unsigned i, len;
int ret;
+ gnutls_datum_t username_datum = {
+ .data = (unsigned char *) username,
+ .size = username_len
+ };
cred = (gnutls_psk_server_credentials_t)
_gnutls_get_cred(session, GNUTLS_CRD_PSK);
@@ -126,7 +175,7 @@ _gnutls_psk_pwd_find_entry(gnutls_session_t session, char *username,
* set, use it.
*/
if (cred->pwd_callback != NULL) {
- ret = cred->pwd_callback(session, username, psk);
+ ret = cred->pwd_callback(session, &username_datum, psk);
if (ret == 1) { /* the user does not exist */
ret = _randomize_psk(psk);
@@ -160,16 +209,8 @@ _gnutls_psk_pwd_find_entry(gnutls_session_t session, char *username,
return GNUTLS_E_SRP_PWD_ERROR;
}
- len = strlen(username);
while (getline(&line, &line_size, fd) > 0) {
- /* move to first ':' */
- i = 0;
- while ((i < line_size) && (line[i] != '\0')
- && (line[i] != ':')) {
- i++;
- }
-
- if (strncmp(username, line, MAX(i, len)) == 0) {
+ if (username_matches(&username_datum, line, line_size)) {
ret = pwd_put_values(psk, line);
if (ret < 0) {
gnutls_assert();
@@ -208,7 +249,6 @@ int _gnutls_find_psk_key(gnutls_session_t session,
gnutls_datum_t * username, gnutls_datum_t * key,
int *free)
{
- char *user_p;
int ret;
*free = 0;
@@ -219,13 +259,11 @@ int _gnutls_find_psk_key(gnutls_session_t session,
key->data = cred->key.data;
key->size = cred->key.size;
} else if (cred->get_function != NULL) {
- ret = cred->get_function(session, &user_p, key);
+ ret = cred->get_function(session, username, key);
+
if (ret)
return gnutls_assert_val(ret);
- username->data = (uint8_t *) user_p;
- username->size = strlen(user_p);
-
*free = 1;
} else
return
diff --git a/lib/auth/psk_passwd.h b/lib/auth/psk_passwd.h
index da4c90c064..3d351f22c7 100644
--- a/lib/auth/psk_passwd.h
+++ b/lib/auth/psk_passwd.h
@@ -24,7 +24,8 @@
#define GNUTLS_LIB_AUTH_PSK_PASSWD_H
/* this is locally allocated. It should be freed using the provided function */
-int _gnutls_psk_pwd_find_entry(gnutls_session_t, char *username,
+int _gnutls_psk_pwd_find_entry(gnutls_session_t,
+ const char *username, uint16_t username_len,
gnutls_datum_t * key);
int _gnutls_find_psk_key(gnutls_session_t session,
diff --git a/lib/auth/rsa_psk.c b/lib/auth/rsa_psk.c
index 387bfd403e..1a9dab5612 100644
--- a/lib/auth/rsa_psk.c
+++ b/lib/auth/rsa_psk.c
@@ -310,8 +310,7 @@ _gnutls_proc_rsa_psk_client_kx(gnutls_session_t session, uint8_t * data,
return GNUTLS_E_ILLEGAL_SRP_USERNAME;
}
- memcpy(info->username, username.data, username.size);
- info->username[username.size] = 0;
+ _gnutls_copy_psk_username(info, &username);
/* Adjust data so it points to EncryptedPreMasterSecret */
data += username.size + 2;
@@ -397,7 +396,7 @@ _gnutls_proc_rsa_psk_client_kx(gnutls_session_t session, uint8_t * data,
/* find the key of this username
*/
ret =
- _gnutls_psk_pwd_find_entry(session, info->username, &pwd_psk);
+ _gnutls_psk_pwd_find_entry(session, info->username, strlen(info->username), &pwd_psk);
if (ret < 0) {
gnutls_assert();
goto cleanup;
diff --git a/lib/ext/pre_shared_key.c b/lib/ext/pre_shared_key.c
index 8a39cda153..fef67d341c 100644
--- a/lib/ext/pre_shared_key.c
+++ b/lib/ext/pre_shared_key.c
@@ -394,8 +394,7 @@ client_send_params(gnutls_session_t session,
info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
assert(info != NULL);
- memcpy(info->username, username.data, username.size);
- info->username[username.size] = 0;
+ _gnutls_copy_psk_username(info, &username);
if ((ret = _gnutls_buffer_append_data_prefix(extdata, 16,
username.data,
@@ -609,17 +608,11 @@ static int server_recv_params(gnutls_session_t session,
} else if (pskcred &&
psk.ob_ticket_age == 0 &&
psk.identity.size > 0 && psk.identity.size <= MAX_USERNAME_SIZE) {
- /* _gnutls_psk_pwd_find_entry() expects 0-terminated identities */
- char identity_str[MAX_USERNAME_SIZE + 1];
-
prf = pskcred->binder_algo;
- memcpy(identity_str, psk.identity.data, psk.identity.size);
- identity_str[psk.identity.size] = 0;
-
/* this fails only on configuration errors; as such we always
* return its error code in that case */
- ret = _gnutls_psk_pwd_find_entry(session, identity_str, &key);
+ ret = _gnutls_psk_pwd_find_entry(session, (char *) psk.identity.data, psk.identity.size, &key);
if (ret < 0)
return gnutls_assert_val(ret);
@@ -684,8 +677,7 @@ static int server_recv_params(gnutls_session_t session,
info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
assert(info != NULL);
- memcpy(info->username, psk.identity.data, psk.identity.size);
- info->username[psk.identity.size] = 0;
+ _gnutls_copy_psk_username(info, &psk.identity);
_gnutls_handshake_log("EXT[%p]: selected PSK identity: %s (%d)\n", session, info->username, psk_index);
} else {
if (session->internals.hsk_flags & HSK_EARLY_DATA_ACCEPTED) {
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index 4ea8159979..9959c82202 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -1445,7 +1445,7 @@ typedef struct {
/* The saved username from PSK or SRP auth */
char saved_username[MAX_USERNAME_SIZE+1];
- bool saved_username_set;
+ int saved_username_size;
/* Needed for TCP Fast Open (TFO), set by gnutls_transport_set_fastopen() */
tfo_st tfo;
diff --git a/lib/handshake-checks.c b/lib/handshake-checks.c
index 56abc5bba6..b07b9680cb 100644
--- a/lib/handshake-checks.c
+++ b/lib/handshake-checks.c
@@ -50,6 +50,7 @@ int _gnutls_check_id_for_change(gnutls_session_t session)
cred_type = gnutls_auth_get_type(session);
if (cred_type == GNUTLS_CRD_PSK || cred_type == GNUTLS_CRD_SRP) {
const char *username = NULL;
+ int username_length;
if (cred_type == GNUTLS_CRD_PSK) {
psk_auth_info_t ai;
@@ -59,6 +60,7 @@ int _gnutls_check_id_for_change(gnutls_session_t session)
return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
username = ai->username;
+ username_length = ai->username_len;
#ifdef ENABLE_SRP
} else {
srp_server_auth_info_t ai = _gnutls_get_auth_info(session, GNUTLS_CRD_SRP);
@@ -66,23 +68,23 @@ int _gnutls_check_id_for_change(gnutls_session_t session)
return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
username = ai->username;
+ username_length = strlen(ai->username);
#endif
}
if (username == NULL)
return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
- if (session->internals.saved_username_set) {
- if (strcmp(session->internals.saved_username, username) != 0) {
+ if (session->internals.saved_username_size != -1) {
+ if (session->internals.saved_username_size == username_length &&
+ strncmp(session->internals.saved_username, username, username_length) != 0) {
_gnutls_debug_log("Session's PSK username changed during rehandshake; aborting!\n");
return gnutls_assert_val(GNUTLS_E_SESSION_USER_ID_CHANGED);
}
} else {
- size_t len = strlen(username);
-
- memcpy(session->internals.saved_username, username, len);
- session->internals.saved_username[len] = 0;
- session->internals.saved_username_set = 1;
+ memcpy(session->internals.saved_username, username, username_length);
+ session->internals.saved_username[username_length] = 0;
+ session->internals.saved_username_size = username_length;
}
}
diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
index b0832a9bdd..9fb6afa156 100644
--- a/lib/includes/gnutls/gnutls.h.in
+++ b/lib/includes/gnutls/gnutls.h.in
@@ -2595,6 +2595,10 @@ int gnutls_psk_set_client_credentials(gnutls_psk_client_credentials_t res,
const char *username,
const gnutls_datum_t * key,
gnutls_psk_key_flags flags);
+int gnutls_psk_set_client_credentials2(gnutls_psk_client_credentials_t res,
+ const gnutls_datum_t *username,
+ const gnutls_datum_t *key,
+ gnutls_psk_key_flags flags);
void
gnutls_psk_free_server_credentials(gnutls_psk_server_credentials_t sc);
@@ -2609,25 +2613,39 @@ gnutls_psk_set_server_credentials_hint(gnutls_psk_server_credentials_t
res, const char *hint);
const char *gnutls_psk_server_get_username(gnutls_session_t session);
+int gnutls_psk_server_get_username2(gnutls_session_t session,
+ gnutls_datum_t *out);
const char *gnutls_psk_client_get_hint(gnutls_session_t session);
typedef int gnutls_psk_server_credentials_function(gnutls_session_t,
const char *username,
gnutls_datum_t * key);
+typedef int gnutls_psk_server_credentials_function2(gnutls_session_t,
+ const gnutls_datum_t *username,
+ gnutls_datum_t *key);
void
gnutls_psk_set_server_credentials_function(gnutls_psk_server_credentials_t
cred,
gnutls_psk_server_credentials_function
* func);
+void
+gnutls_psk_set_server_credentials_function2(gnutls_psk_server_credentials_t cred,
+ gnutls_psk_server_credentials_function2 *func);
typedef int gnutls_psk_client_credentials_function(gnutls_session_t,
char **username,
gnutls_datum_t * key);
+typedef int gnutls_psk_client_credentials_function2(gnutls_session_t,
+ gnutls_datum_t *username,
+ gnutls_datum_t *key);
void
gnutls_psk_set_client_credentials_function(gnutls_psk_client_credentials_t
cred,
gnutls_psk_client_credentials_function
* func);
+void
+gnutls_psk_set_client_credentials_function2(gnutls_psk_client_credentials_t cred,
+ gnutls_psk_client_credentials_function2 *func);
int gnutls_hex_encode(const gnutls_datum_t * data, char *result,
size_t * result_size);
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index 3cc321beb8..7c3187541d 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -1317,6 +1317,10 @@ GNUTLS_3_6_13
gnutls_pbkdf2;
gnutls_session_set_keylog_function;
gnutls_prf_hash_get;
+ gnutls_psk_server_get_username2;
+ gnutls_psk_set_server_credentials_function2;
+ gnutls_psk_set_client_credentials2;
+ gnutls_psk_set_client_credentials_function2;
} GNUTLS_3_6_12;
GNUTLS_FIPS140_3_4 {
diff --git a/lib/psk.c b/lib/psk.c
index ebb3f246ff..aa5220c27c 100644
--- a/lib/psk.c
+++ b/lib/psk.c
@@ -24,6 +24,7 @@
#include "gnutls_int.h"
#include "errors.h"
+#include <str.h>
#include <auth/psk.h>
#include <state.h>
@@ -96,15 +97,46 @@ gnutls_psk_set_client_credentials(gnutls_psk_client_credentials_t res,
const gnutls_datum_t * key,
gnutls_psk_key_flags flags)
{
+ gnutls_datum_t dat;
+
+ if (username == NULL)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ dat.data = (unsigned char *) username;
+ dat.size = strlen(username);
+
+ return gnutls_psk_set_client_credentials2(res, &dat, key, flags);
+}
+
+/**
+ * gnutls_psk_set_client_credentials2:
+ * @res: is a #gnutls_psk_client_credentials_t type.
+ * @username: is the userid
+ * @key: is the user's key
+ * @flags: indicate the format of the key, either
+ * %GNUTLS_PSK_KEY_RAW or %GNUTLS_PSK_KEY_HEX.
+ *
+ * This function is identical to gnutls_psk_set_client_credentials(),
+ * except that it allows a non-null-terminated username to be introduced.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise
+ * an error code is returned.
+ */
+int
+gnutls_psk_set_client_credentials2(gnutls_psk_client_credentials_t res,
+ const gnutls_datum_t *username,
+ const gnutls_datum_t *key,
+ gnutls_psk_key_flags flags)
+{
int ret;
- if (username == NULL || key == NULL || key->data == NULL) {
+ if (username == NULL || username->data == NULL || key == NULL || key->data == NULL) {
gnutls_assert();
return GNUTLS_E_INVALID_REQUEST;
}
ret =
- _gnutls_set_datum(&res->username, username, strlen(username));
+ _gnutls_set_datum(&res->username, username->data, username->size);
if (ret < 0)
return ret;
@@ -255,6 +287,16 @@ gnutls_psk_set_server_credentials_hint(gnutls_psk_server_credentials_t res,
return 0;
}
+static int call_server_callback_legacy(gnutls_session_t session,
+ const gnutls_datum_t *username,
+ gnutls_datum_t *key)
+{
+ gnutls_psk_server_credentials_t cred =
+ (gnutls_psk_server_credentials_t)
+ _gnutls_get_cred(session, GNUTLS_CRD_PSK);
+ return cred->pwd_callback_legacy(session, (const char *) username->data, key);
+}
+
/**
* gnutls_psk_set_server_credentials_function:
* @cred: is a #gnutls_psk_server_credentials_t type.
@@ -281,7 +323,61 @@ gnutls_psk_set_server_credentials_function(gnutls_psk_server_credentials_t
gnutls_psk_server_credentials_function
* func)
{
+ cred->pwd_callback_legacy = func;
+ cred->pwd_callback = call_server_callback_legacy;
+}
+
+/**
+ * gnutls_psk_set_server_credentials_function2:
+ * @cred: is a #gnutls_psk_server_credentials_t type.
+ * @func: is the callback function
+ *
+ * This function can be used to set a callback to retrieve the user's PSK credentials.
+ * The callback's function form is:
+ * int (*callback)(gnutls_session_t, const gnutls_datum_t* username,
+ * gnutls_datum_t* key);
+ *
+ * This callback function has the same semantics as that of gnutls_psk_set_server_credentials_function(),
+ * but it allows non-string usernames to be used.
+ *
+ * @username contains the actual username.
+ * The @key must be filled in using the gnutls_malloc().
+ *
+ * In case the callback returned a negative number then gnutls will
+ * assume that the username does not exist.
+ *
+ * The callback function will only be called once per handshake. The
+ * callback function should return 0 on success, while -1 indicates
+ * an error.
+ **/
+void
+gnutls_psk_set_server_credentials_function2(gnutls_psk_server_credentials_t cred,
+ gnutls_psk_server_credentials_function2 func)
+{
cred->pwd_callback = func;
+ cred->pwd_callback_legacy = NULL;
+}
+
+static int call_client_callback_legacy(gnutls_session_t session,
+ gnutls_datum_t *username,
+ gnutls_datum_t *key)
+{
+ int ret;
+ char *user_p;
+ gnutls_psk_client_credentials_t cred =
+ (gnutls_psk_client_credentials_t)
+ _gnutls_get_cred(session, GNUTLS_CRD_PSK);
+
+ ret = cred->get_function_legacy(session, &user_p, key);
+
+ if (ret)
+ goto end;
+
+ username->data = (uint8_t *) user_p;
+ username->size = strlen(user_p);
+
+end:
+ return ret;
}
/**
@@ -311,7 +407,40 @@ gnutls_psk_set_client_credentials_function(gnutls_psk_client_credentials_t
gnutls_psk_client_credentials_function
* func)
{
+ cred->get_function = call_client_callback_legacy;
+ cred->get_function_legacy = func;
+}
+
+/**
+ * gnutls_psk_set_client_credentials_function2:
+ * @cred: is a #gnutls_psk_server_credentials_t type.
+ * @func: is the callback function
+ *
+ * This function can be used to set a callback to retrieve the username and
+ * password for client PSK authentication.
+ * The callback's function form is:
+ * int (*callback)(gnutls_session_t, gnutls_datum_t* username,
+ * gnutls_datum_t* key);
+ *
+ * This callback function has the same semantics as that of gnutls_psk_set_client_credentials_function(),
+ * but it allows non-string usernames to be used.
+ *
+ * The @username and @key->data must be allocated using gnutls_malloc().
+ * The @username should be an ASCII string or UTF-8
+ * string. In case of a UTF-8 string it is recommended to be following
+ * the PRECIS framework for usernames (rfc8265).
+ *
+ * The callback function will be called once per handshake.
+ *
+ * The callback function should return 0 on success.
+ * -1 indicates an error.
+ **/
+void
+gnutls_psk_set_client_credentials_function2(gnutls_psk_client_credentials_t cred,
+ gnutls_psk_client_credentials_function2 *func)
+{
cred->get_function = func;
+ cred->get_function_legacy = NULL;
}
@@ -322,7 +451,14 @@ gnutls_psk_set_client_credentials_function(gnutls_psk_client_credentials_t
* This should only be called in case of PSK authentication and in
* case of a server.
*
- * Returns: the username of the peer, or %NULL in case of an error.
+ * The returned pointer should be considered constant (do not free) and valid
+ * for the lifetime of the session.
+ *
+ * This function will return %NULL if the username has embedded NULL bytes.
+ * In that case, gnutls_psk_server_get_username2() should be used to retrieve the username.
+ *
+ * Returns: the username of the peer, or %NULL in case of an error,
+ * or if the username has embedded NULLs.
**/
const char *gnutls_psk_server_get_username(gnutls_session_t session)
{
@@ -334,13 +470,48 @@ const char *gnutls_psk_server_get_username(gnutls_session_t session)
if (info == NULL)
return NULL;
- if (info->username[0] != 0)
+ if (info->username[0] != 0 && !_gnutls_has_embedded_null(info->username, info->username_len))
return info->username;
return NULL;
}
/**
+ * gnutls_psk_server_get_username2:
+ * @session: is a gnutls session
+ * @username: a datum that will be filled in by this function
+ *
+ * Return a pointer to the username of the peer in the supplied datum. Does not
+ * need to be null-terminated.
+ *
+ * This should only be called in case of PSK authentication and in
+ * case of a server.
+ *
+ * The returned pointer should be considered constant (do not free) and valid
+ * for the lifetime of the session.
+ *
+ * Returns: %GNUTLS_E_SUCCESS, or a negative value in case of an error.
+ **/
+int gnutls_psk_server_get_username2(gnutls_session_t session, gnutls_datum_t *username)
+{
+ psk_auth_info_t info;
+
+ CHECK_AUTH_TYPE(GNUTLS_CRD_PSK, GNUTLS_E_INVALID_REQUEST);
+
+ info = _gnutls_get_auth_info(session, GNUTLS_CRD_PSK);
+ if (info == NULL)
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+
+ if (info->username_len > 0) {
+ username->data = (unsigned char *) info->username;
+ username->size = info->username_len;
+ return 0;
+ }
+
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+}
+
+/**
* gnutls_psk_client_get_hint:
* @session: is a gnutls session
*
diff --git a/lib/session_pack.c b/lib/session_pack.c
index e5c21f24b5..a6d11c4cfc 100644
--- a/lib/session_pack.c
+++ b/lib/session_pack.c
@@ -776,7 +776,7 @@ pack_psk_auth_info(gnutls_session_t session, gnutls_buffer_st * ps)
if (info == NULL)
return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
- username_len = strlen(info->username) + 1; /* include the terminating null */
+ username_len = info->username_len;
hint_len = strlen(info->hint) + 1; /* include the terminating null */
size_offset = ps->length;
@@ -824,7 +824,7 @@ unpack_psk_auth_info(gnutls_session_t session, gnutls_buffer_st * ps)
return GNUTLS_E_INVALID_REQUEST;
BUFFER_POP_NUM(ps, username_size);
- if (username_size > sizeof(info->username)) {
+ if (username_size > (sizeof(info->username) - 1)) {
gnutls_assert();
return GNUTLS_E_INTERNAL_ERROR;
}
@@ -833,6 +833,10 @@ unpack_psk_auth_info(gnutls_session_t session, gnutls_buffer_st * ps)
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;
+
BUFFER_POP_NUM(ps, hint_size);
if (hint_size > sizeof(info->hint)) {
gnutls_assert();
diff --git a/lib/state.c b/lib/state.c
index d4d5254228..0e1d155442 100644
--- a/lib/state.c
+++ b/lib/state.c
@@ -584,6 +584,8 @@ int gnutls_init(gnutls_session_t * session, unsigned int flags)
(*session)->internals.pull_func = system_read;
(*session)->internals.errno_func = system_errno;
+ (*session)->internals.saved_username_size = -1;
+
/* heartbeat timeouts */
(*session)->internals.hb_retrans_timeout_ms = 1000;
(*session)->internals.hb_total_timeout_ms = 60000;
diff --git a/lib/str.h b/lib/str.h
index 854cca12a6..65d42081e8 100644
--- a/lib/str.h
+++ b/lib/str.h
@@ -70,6 +70,13 @@ inline static unsigned _gnutls_dnsname_is_valid(const char *str, unsigned size)
return 1;
}
+inline static bool _gnutls_has_embedded_null(const char *str, unsigned size)
+{
+ if (strlen(str) != size)
+ return true;
+ return false;
+}
+
void _gnutls_str_cpy(char *dest, size_t dest_tot_size, const char *src);
void _gnutls_str_cat(char *dest, size_t dest_tot_size, const char *src);
diff --git a/lib/x509/email-verify.c b/lib/x509/email-verify.c
index 4eee0699bc..053e512872 100644
--- a/lib/x509/email-verify.c
+++ b/lib/x509/email-verify.c
@@ -26,13 +26,6 @@
#include "errors.h"
#include <system.h>
-static int has_embedded_null(const char *str, unsigned size)
-{
- if (strlen(str) != size)
- return 1;
- return 0;
-}
-
/**
* gnutls_x509_crt_check_email:
* @cert: should contain an gnutls_x509_crt_t type
@@ -88,7 +81,7 @@ gnutls_x509_crt_check_email(gnutls_x509_crt_t cert,
if (ret == GNUTLS_SAN_RFC822NAME) {
found_rfc822name = 1;
- if (has_embedded_null(rfc822name, rfc822namesize)) {
+ if (_gnutls_has_embedded_null(rfc822name, rfc822namesize)) {
_gnutls_debug_log("certificate has %s with embedded null in rfc822name\n", rfc822name);
continue;
}
@@ -130,7 +123,7 @@ gnutls_x509_crt_check_email(gnutls_x509_crt_t cert,
goto cleanup;
}
- if (has_embedded_null(rfc822name, rfc822namesize)) {
+ if (_gnutls_has_embedded_null(rfc822name, rfc822namesize)) {
_gnutls_debug_log("certificate has EMAIL %s with embedded null in name\n", rfc822name);
ret = 0;
goto cleanup;
diff --git a/lib/x509/hostname-verify.c b/lib/x509/hostname-verify.c
index 967d9b821a..6ef8ba0303 100644
--- a/lib/x509/hostname-verify.c
+++ b/lib/x509/hostname-verify.c
@@ -86,13 +86,6 @@ check_ip(gnutls_x509_crt_t cert, const void *ip, unsigned ip_size)
return 0;
}
-static int has_embedded_null(const char *str, unsigned size)
-{
- if (strlen(str) != size)
- return 1;
- return 0;
-}
-
/**
* gnutls_x509_crt_check_ip:
* @cert: should contain an gnutls_x509_crt_t type
@@ -227,7 +220,7 @@ gnutls_x509_crt_check_hostname2(gnutls_x509_crt_t cert,
if (ret == GNUTLS_SAN_DNSNAME) {
found_dnsname = 1;
- if (has_embedded_null(dnsname, dnsnamesize)) {
+ if (_gnutls_has_embedded_null(dnsname, dnsnamesize)) {
_gnutls_debug_log("certificate has %s with embedded null in name\n", dnsname);
continue;
}
@@ -275,7 +268,7 @@ gnutls_x509_crt_check_hostname2(gnutls_x509_crt_t cert,
goto cleanup;
}
- if (has_embedded_null(dnsname, dnsnamesize)) {
+ if (_gnutls_has_embedded_null(dnsname, dnsnamesize)) {
_gnutls_debug_log("certificate has CN %s with embedded null in name\n", dnsname);
ret = 0;
goto cleanup;