diff options
Diffstat (limited to 'lib/psk.c')
-rw-r--r-- | lib/psk.c | 179 |
1 files changed, 175 insertions, 4 deletions
@@ -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 * |