summaryrefslogtreecommitdiff
path: root/lib/psk.c
diff options
context:
space:
mode:
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
*