summaryrefslogtreecommitdiff
path: root/lib/psk.c
diff options
context:
space:
mode:
authorAnder Juaristi <a@juaristi.eus>2020-03-02 16:37:10 +0100
committerAnder Juaristi <a@juaristi.eus>2020-03-23 17:00:58 +0100
commitd00638997fa269a975095d852633b48b2b64fbf9 (patch)
tree2e59386d821c9e4ab07122f6189d1b8f04658452 /lib/psk.c
parent5aff47e3dad565172f0268e0b685282f816bd1b9 (diff)
downloadgnutls-d00638997fa269a975095d852633b48b2b64fbf9.tar.gz
psk: Allow non-NULL PSK usernames
This commit closes #586. Two new functions are introduced: gnutls_psk_server_get_username2() and gnutls_psk_set_client_username2(), which are identical in behavior to those named similarly (without the final '2'), but allow arbitrary gnutls datums (not strings) to be used as usernames. Two new callback functions are also introduced, with their respective setters: gnutls_psk_set_server_credentials_function2() and gnutls_psk_set_client_credentials_function2(). In addition, the password file format is extended so that non-string usernames can be specified. A leading '#' character tells GnuTLS that the username should be interpreted as a raw byte string (encoded in HEX). Example: #deadbeef:9e32cf7786321a828ef7668f09fb35db Signed-off-by: Ander Juaristi's avatarAnder Juaristi <a@juaristi.eus>
Diffstat (limited to 'lib/psk.c')
-rw-r--r--lib/psk.c179
1 files changed, 175 insertions, 4 deletions
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
*