diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/auth/dhe_psk.c | 10 | ||||
-rw-r--r-- | lib/auth/psk.c | 8 | ||||
-rw-r--r-- | lib/auth/psk.h | 17 | ||||
-rw-r--r-- | lib/auth/psk_passwd.c | 72 | ||||
-rw-r--r-- | lib/auth/psk_passwd.h | 3 | ||||
-rw-r--r-- | lib/auth/rsa_psk.c | 5 | ||||
-rw-r--r-- | lib/ext/pre_shared_key.c | 14 | ||||
-rw-r--r-- | lib/gnutls_int.h | 2 | ||||
-rw-r--r-- | lib/handshake-checks.c | 16 | ||||
-rw-r--r-- | lib/includes/gnutls/gnutls.h.in | 18 | ||||
-rw-r--r-- | lib/libgnutls.map | 4 | ||||
-rw-r--r-- | lib/psk.c | 179 | ||||
-rw-r--r-- | lib/session_pack.c | 8 | ||||
-rw-r--r-- | lib/state.c | 2 | ||||
-rw-r--r-- | lib/str.h | 7 | ||||
-rw-r--r-- | lib/x509/email-verify.c | 11 | ||||
-rw-r--r-- | lib/x509/hostname-verify.c | 11 |
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 { @@ -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; @@ -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; |