diff options
author | Ander Juaristi <a@juaristi.eus> | 2020-03-02 16:37:10 +0100 |
---|---|---|
committer | Ander Juaristi <a@juaristi.eus> | 2020-03-23 17:00:58 +0100 |
commit | d00638997fa269a975095d852633b48b2b64fbf9 (patch) | |
tree | 2e59386d821c9e4ab07122f6189d1b8f04658452 | |
parent | 5aff47e3dad565172f0268e0b685282f816bd1b9 (diff) | |
download | gnutls-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>
-rw-r--r-- | devel/symbols.last | 4 | ||||
-rw-r--r-- | doc/Makefile.am | 8 | ||||
-rw-r--r-- | doc/manpages/Makefile.am | 4 | ||||
-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 | 71 | ||||
-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/handshake-checks.c | 11 | ||||
-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/str.h | 7 | ||||
-rw-r--r-- | lib/x509/email-verify.c | 11 | ||||
-rw-r--r-- | lib/x509/hostname-verify.c | 11 | ||||
-rw-r--r-- | tests/Makefile.am | 2 | ||||
-rw-r--r-- | tests/psk-file.c | 241 | ||||
-rw-r--r-- | tests/psk.passwd | 3 | ||||
-rw-r--r-- | tests/pskself2.c | 347 |
22 files changed, 854 insertions, 132 deletions
diff --git a/devel/symbols.last b/devel/symbols.last index 70ef6b3f18..a3a11ab7c2 100644 --- a/devel/symbols.last +++ b/devel/symbols.last @@ -651,11 +651,15 @@ gnutls_psk_allocate_server_credentials@GNUTLS_3_4 gnutls_psk_client_get_hint@GNUTLS_3_4 gnutls_psk_free_client_credentials@GNUTLS_3_4 gnutls_psk_free_server_credentials@GNUTLS_3_4 +gnutls_psk_server_get_username2@GNUTLS_3_6_13 gnutls_psk_server_get_username@GNUTLS_3_4 +gnutls_psk_set_client_credentials2@GNUTLS_3_6_13 gnutls_psk_set_client_credentials@GNUTLS_3_4 +gnutls_psk_set_client_credentials_function2@GNUTLS_3_6_13 gnutls_psk_set_client_credentials_function@GNUTLS_3_4 gnutls_psk_set_params_function@GNUTLS_3_4 gnutls_psk_set_server_credentials_file@GNUTLS_3_4 +gnutls_psk_set_server_credentials_function2@GNUTLS_3_6_13 gnutls_psk_set_server_credentials_function@GNUTLS_3_4 gnutls_psk_set_server_credentials_hint@GNUTLS_3_4 gnutls_psk_set_server_dh_params@GNUTLS_3_4 diff --git a/doc/Makefile.am b/doc/Makefile.am index dd962d6a78..9c72b01281 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -1727,16 +1727,24 @@ FUNCS += functions/gnutls_psk_free_server_credentials FUNCS += functions/gnutls_psk_free_server_credentials.short FUNCS += functions/gnutls_psk_server_get_username FUNCS += functions/gnutls_psk_server_get_username.short +FUNCS += functions/gnutls_psk_server_get_username2 +FUNCS += functions/gnutls_psk_server_get_username2.short FUNCS += functions/gnutls_psk_set_client_credentials FUNCS += functions/gnutls_psk_set_client_credentials.short +FUNCS += functions/gnutls_psk_set_client_credentials2 +FUNCS += functions/gnutls_psk_set_client_credentials2.short FUNCS += functions/gnutls_psk_set_client_credentials_function FUNCS += functions/gnutls_psk_set_client_credentials_function.short +FUNCS += functions/gnutls_psk_set_client_credentials_function2 +FUNCS += functions/gnutls_psk_set_client_credentials_function2.short FUNCS += functions/gnutls_psk_set_params_function FUNCS += functions/gnutls_psk_set_params_function.short FUNCS += functions/gnutls_psk_set_server_credentials_file FUNCS += functions/gnutls_psk_set_server_credentials_file.short FUNCS += functions/gnutls_psk_set_server_credentials_function FUNCS += functions/gnutls_psk_set_server_credentials_function.short +FUNCS += functions/gnutls_psk_set_server_credentials_function2 +FUNCS += functions/gnutls_psk_set_server_credentials_function2.short FUNCS += functions/gnutls_psk_set_server_credentials_hint FUNCS += functions/gnutls_psk_set_server_credentials_hint.short FUNCS += functions/gnutls_psk_set_server_dh_params diff --git a/doc/manpages/Makefile.am b/doc/manpages/Makefile.am index 6d381d8bd0..60c937da83 100644 --- a/doc/manpages/Makefile.am +++ b/doc/manpages/Makefile.am @@ -665,11 +665,15 @@ APIMANS += gnutls_psk_client_get_hint.3 APIMANS += gnutls_psk_free_client_credentials.3 APIMANS += gnutls_psk_free_server_credentials.3 APIMANS += gnutls_psk_server_get_username.3 +APIMANS += gnutls_psk_server_get_username2.3 APIMANS += gnutls_psk_set_client_credentials.3 +APIMANS += gnutls_psk_set_client_credentials2.3 APIMANS += gnutls_psk_set_client_credentials_function.3 +APIMANS += gnutls_psk_set_client_credentials_function2.3 APIMANS += gnutls_psk_set_params_function.3 APIMANS += gnutls_psk_set_server_credentials_file.3 APIMANS += gnutls_psk_set_server_credentials_function.3 +APIMANS += gnutls_psk_set_server_credentials_function2.3 APIMANS += gnutls_psk_set_server_credentials_hint.3 APIMANS += gnutls_psk_set_server_dh_params.3 APIMANS += gnutls_psk_set_server_known_dh_params.3 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..4bdb4e02c4 100644 --- a/lib/auth/psk_passwd.c +++ b/lib/auth/psk_passwd.c @@ -73,7 +73,51 @@ 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 (line[0] == '#') { + 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 +149,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 +174,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 +208,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 +248,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 +258,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/handshake-checks.c b/lib/handshake-checks.c index 56abc5bba6..f8079dae36 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; + size_t 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,6 +68,7 @@ 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 } @@ -73,15 +76,13 @@ int _gnutls_check_id_for_change(gnutls_session_t session) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); if (session->internals.saved_username_set) { - if (strcmp(session->internals.saved_username, username) != 0) { + if (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; + memcpy(session->internals.saved_username, username, username_length); + session->internals.saved_username[username_length] = 0; session->internals.saved_username_set = 1; } } 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(); @@ -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; diff --git a/tests/Makefile.am b/tests/Makefile.am index 5c89f77c11..c79dcce7e5 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -426,7 +426,7 @@ openssl_LDADD = ../extra/libgnutls-openssl.la $(LDADD) endif if HAVE_FORK -ctests += x509self x509dn anonself pskself dhepskself \ +ctests += x509self x509dn anonself pskself pskself2 dhepskself \ setcredcrash tls12-resume-x509 tls12-resume-psk tls12-resume-anon \ tls13-resume-x509 tls13-resume-psk tls13-early-data tls13-early-data-neg \ resume-with-record-size-limit diff --git a/tests/psk-file.c b/tests/psk-file.c index 22e744f1a7..703043ec40 100644 --- a/tests/psk-file.c +++ b/tests/psk-file.c @@ -54,6 +54,36 @@ int main(int argc, char **argv) #include "utils.h" +static char hexchar(unsigned int val) +{ + if (val < 10) + return '0' + val; + if (val < 16) + return 'a' + val - 10; + abort(); +} + +static bool hex_encode(const void *buf, size_t bufsize, char *dest, size_t destsize) +{ + size_t used = 0; + + if (destsize < 1) + return false; + + while (used < bufsize) { + unsigned int c = ((const unsigned char *)buf)[used]; + if (destsize < 3) + return false; + *(dest++) = hexchar(c >> 4); + *(dest++) = hexchar(c & 0xF); + used++; + destsize -= 2; + } + *dest = '\0'; + + return used + 1; +} + /* A very basic TLS client, with PSK authentication. */ @@ -67,8 +97,8 @@ static void tls_log_func(int level, const char *str) #define MAX_BUF 1024 #define MSG "Hello TLS" -static void client(int sd, const char *prio, const char *user, const gnutls_datum_t *key, - unsigned expect_hint, int expect_fail, int exp_kx) +static void client(int sd, const char *prio, const gnutls_datum_t *user, const gnutls_datum_t *key, + unsigned expect_hint, int expect_fail, int exp_kx, unsigned binary_user) { int ret, ii, kx; gnutls_session_t session; @@ -84,8 +114,13 @@ static void client(int sd, const char *prio, const char *user, const gnutls_datu side = "client"; gnutls_psk_allocate_client_credentials(&pskcred); - gnutls_psk_set_client_credentials(pskcred, user, key, - GNUTLS_PSK_KEY_HEX); + + if (binary_user) { + gnutls_psk_set_client_credentials2(pskcred, user, key, GNUTLS_PSK_KEY_HEX); + } else { + gnutls_psk_set_client_credentials(pskcred, (const char *) user->data, key, + GNUTLS_PSK_KEY_HEX); + } assert(gnutls_init(&session, GNUTLS_CLIENT|GNUTLS_KEY_SHARE_TOP)>=0); @@ -173,13 +208,14 @@ static void client(int sd, const char *prio, const char *user, const gnutls_datu #define MAX_BUF 1024 -static void server(int sd, const char *prio, const char *user, bool no_cred, - int expect_fail, int exp_kx) +static void server(int sd, const char *prio, const gnutls_datum_t *user, bool no_cred, + int expect_fail, int exp_kx, unsigned binary_user) { gnutls_psk_server_credentials_t server_pskcred; int ret, kx; gnutls_session_t session; const char *pskid; + gnutls_datum_t pskid_binary; char buffer[MAX_BUF + 1]; char *psk_file = getenv("PSK_FILE"); char *desc; @@ -219,7 +255,7 @@ static void server(int sd, const char *prio, const char *user, bool no_cred, gnutls_alert_send_appropriate(session, ret); /* We have to make sure that we do not close connection till - * test client reads our fatal alert, otherwise it migh exit + * test client reads our fatal alert, otherwise it might exit * with GNUTLS_E_PUSH_ERROR instead */ gnutls_session_force_valid(session); while ((gnutls_record_recv_seq(session, buf, sizeof(buf), seq)) >= 0) @@ -281,10 +317,24 @@ static void server(int sd, const char *prio, const char *user, bool no_cred, fail("server: expected failure but connection succeeded!\n"); if (!no_cred) { - pskid = gnutls_psk_server_get_username(session); - if (pskid == NULL || strcmp(pskid, user) != 0) { - fail("server: username (%s), does not match expected (%s)\n", - pskid, user); + if (binary_user) { + char pskid_bin[1024], userdata_bin[1024]; + + if (gnutls_psk_server_get_username2(session, &pskid_binary)) + fail("server: Could not get binary pskid\n"); + + if (memcmp(pskid_binary.data, user->data, user->size) != 0) { + hex_encode(user->data, user->size, userdata_bin, sizeof(userdata_bin)); + hex_encode(pskid_binary.data, pskid_binary.size, pskid_bin, sizeof(pskid_bin)); + fail("server: binary username (%s) does not match expected (%s)\n", + pskid_bin, userdata_bin); + } + } else { + pskid = gnutls_psk_server_get_username(session); + if (pskid == NULL || strcmp(pskid, (const char *) user->data) != 0) { + fail("server: username (%s), does not match expected (%s)\n", + pskid, (const char *) user->data); + } } } @@ -306,9 +356,20 @@ static void server(int sd, const char *prio, const char *user, bool no_cred, success("server: finished\n"); } +static void print_user(const char *caption, const char *prio, const gnutls_datum_t *user, unsigned binary_user) +{ + char hexuser[100]; + + if (binary_user) { + hex_encode(user->data, user->size, hexuser, sizeof(hexuser)); + success("%s %s (user:%s)\n", caption, prio, hexuser); + } else + success("%s %s (user:%s)\n", caption, prio, (const char *) user->data); +} + static -void run_test3(const char *prio, const char *sprio, const char *user, const gnutls_datum_t *key, bool no_cred, - unsigned expect_hint, int exp_kx, int expect_fail_cli, int expect_fail_serv) +void run_test3(const char *prio, const char *sprio, const gnutls_datum_t *user, const gnutls_datum_t *key, bool no_cred, + unsigned expect_hint, int exp_kx, int expect_fail_cli, int expect_fail_serv, unsigned binary_user) { pid_t child; int err; @@ -316,11 +377,10 @@ void run_test3(const char *prio, const char *sprio, const char *user, const gnut signal(SIGPIPE, SIG_IGN); - if (expect_fail_serv || expect_fail_cli) { - success("ntest %s (user:%s)\n", prio, user); - } else { - success("test %s (user:%s)\n", prio, user); - } + if (expect_fail_serv || expect_fail_cli) + print_user("ntest", prio, user, binary_user); + else + print_user("test", prio, user, binary_user); err = socketpair(AF_UNIX, SOCK_STREAM, 0, sockets); if (err == -1) { @@ -340,86 +400,155 @@ void run_test3(const char *prio, const char *sprio, const char *user, const gnut close(sockets[1]); int status; /* parent */ - server(sockets[0], sprio?sprio:prio, user, no_cred, expect_fail_serv, exp_kx); + server(sockets[0], sprio?sprio:prio, user, no_cred, expect_fail_serv, exp_kx, binary_user); wait(&status); check_wait_status(status); } else { close(sockets[0]); - client(sockets[1], prio, user, key, expect_hint, expect_fail_cli, exp_kx); + client(sockets[1], prio, user, key, expect_hint, expect_fail_cli, exp_kx, binary_user); exit(0); } } static -void run_test2(const char *prio, const char *sprio, const char *user, const gnutls_datum_t *key, - unsigned expect_hint, int exp_kx, int expect_fail_cli, int expect_fail_serv) +void run_test2(const char *prio, const char *sprio, const gnutls_datum_t *user, const gnutls_datum_t *key, + unsigned expect_hint, int exp_kx, int expect_fail_cli, int expect_fail_serv, unsigned binary_user) { - run_test3(prio, sprio, user, key, 0, expect_hint, exp_kx, expect_fail_cli, expect_fail_serv); + run_test3(prio, sprio, user, key, 0, expect_hint, exp_kx, expect_fail_cli, expect_fail_serv, binary_user); } static -void run_test_ok(const char *prio, const char *user, const gnutls_datum_t *key, unsigned expect_hint, int expect_fail) +void run_test_ok(const char *prio, const gnutls_datum_t *user, const gnutls_datum_t *key, unsigned expect_hint, int expect_fail, unsigned binary_user) { - run_test2(prio, NULL, user, key, expect_hint, GNUTLS_KX_PSK, expect_fail, expect_fail); + run_test2(prio, NULL, user, key, expect_hint, GNUTLS_KX_PSK, expect_fail, expect_fail, binary_user); } static -void run_ectest_ok(const char *prio, const char *user, const gnutls_datum_t *key, unsigned expect_hint, int expect_fail) +void run_ectest_ok(const char *prio, const gnutls_datum_t *user, const gnutls_datum_t *key, unsigned expect_hint, int expect_fail, unsigned binary_user) { - run_test2(prio, NULL, user, key, expect_hint, GNUTLS_KX_ECDHE_PSK, expect_fail, expect_fail); + run_test2(prio, NULL, user, key, expect_hint, GNUTLS_KX_ECDHE_PSK, expect_fail, expect_fail, binary_user); } static -void run_dhtest_ok(const char *prio, const char *user, const gnutls_datum_t *key, unsigned expect_hint, int expect_fail) +void run_dhtest_ok(const char *prio, const gnutls_datum_t *user, const gnutls_datum_t *key, unsigned expect_hint, int expect_fail, unsigned binary_user) { - run_test2(prio, NULL, user, key, expect_hint, GNUTLS_KX_DHE_PSK, expect_fail, expect_fail); + run_test2(prio, NULL, user, key, expect_hint, GNUTLS_KX_DHE_PSK, expect_fail, expect_fail, binary_user); } void doit(void) { + char hexuser[] = { 0xde, 0xad, 0xbe, 0xef }, + nulluser1[] = { 0 }, + nulluser2[] = { 0, 0, 0xaa, 0 }; + const gnutls_datum_t user_jas = { (void *) "jas", strlen("jas") }; + const gnutls_datum_t user_unknown = { (void *) "unknown", strlen("unknown") }; + const gnutls_datum_t user_nonhex = { (void *) "non-hex", strlen("non-hex") }; + const gnutls_datum_t user_hex = { (void *) hexuser, sizeof(hexuser) }; + const gnutls_datum_t user_null_1 = { (void *) nulluser1, sizeof(nulluser1) }; + const gnutls_datum_t user_null_2 = { (void *) nulluser2, sizeof(nulluser2) }; const gnutls_datum_t key = { (void *) "9e32cf7786321a828ef7668f09fb35db", 32 }; const gnutls_datum_t wrong_key = { (void *) "9e31cf7786321a828ef7668f09fb35db", 32 }; - run_test_ok("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+PSK", "jas", &key, 1, 0); - run_dhtest_ok("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+DHE-PSK", "jas", &key, 1, 0); - run_ectest_ok("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+ECDHE-PSK", "jas", &key, 1, 0); - run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+PSK", NULL, "unknown", &key, 1, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_DECRYPTION_FAILED); - run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+PSK", NULL, "jas", &wrong_key, 1, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_DECRYPTION_FAILED); - run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+PSK", NULL, "non-hex", &key, 1, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_KEYFILE_ERROR); - - run_test_ok("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+PSK", "jas", &key, 1, 0); - run_test_ok("NORMAL:-KX-ALL:+PSK", "jas", &key, 0, 0); - run_test2("NORMAL:+PSK", NULL, "unknown", &key, 1, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); - run_test2("NORMAL:+PSK", NULL, "jas", &wrong_key, 1, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); - run_test2("NORMAL:-KX-ALL:+PSK", NULL, "non-hex", &key, 1, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_KEYFILE_ERROR); - - run_dhtest_ok("NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:-GROUP-EC-ALL", "jas", &key, 0, 0); - run_test_ok("NORMAL:-VERS-ALL:+VERS-TLS1.3:+PSK", "jas", &key, 0, 0); + run_test_ok("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+PSK", &user_jas, &key, 1, 0, 0); + run_test_ok("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+PSK", &user_hex, &key, 1, 0, 1); + run_test_ok("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+PSK", &user_null_1, &key, 1, 0, 1); + run_test_ok("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+PSK", &user_null_2, &key, 1, 0, 1); + run_dhtest_ok("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+DHE-PSK", &user_jas, &key, 1, 0, 0); + run_dhtest_ok("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+DHE-PSK", &user_hex, &key, 1, 0, 1); + run_dhtest_ok("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+DHE-PSK", &user_null_1, &key, 1, 0, 1); + run_dhtest_ok("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+DHE-PSK", &user_null_2, &key, 1, 0, 1); + run_ectest_ok("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+ECDHE-PSK", &user_jas, &key, 1, 0, 0); + run_ectest_ok("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+ECDHE-PSK", &user_hex, &key, 1, 0, 1); + run_ectest_ok("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+ECDHE-PSK", &user_null_1, &key, 1, 0, 1); + run_ectest_ok("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+ECDHE-PSK", &user_null_2, &key, 1, 0, 1); + run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+PSK", NULL, &user_unknown, &key, 1, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_DECRYPTION_FAILED, 0); + run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+PSK", NULL, &user_jas, &wrong_key, 1, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_DECRYPTION_FAILED, 0); + run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+PSK", NULL, &user_nonhex, &key, 1, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_KEYFILE_ERROR, 0); + run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+PSK", NULL, &user_hex, &wrong_key, 1, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_DECRYPTION_FAILED, 1); + run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+PSK", NULL, &user_null_1, &wrong_key, 1, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_DECRYPTION_FAILED, 1); + run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+PSK", NULL, &user_null_2, &wrong_key, 1, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_DECRYPTION_FAILED, 1); + + run_test_ok("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+PSK", &user_jas, &key, 1, 0, 0); + run_test_ok("NORMAL:-KX-ALL:+PSK", &user_jas, &key, 0, 0, 0); + run_test_ok("NORMAL:-KX-ALL:+PSK", &user_hex, &key, 0, 0, 1); + run_test_ok("NORMAL:-KX-ALL:+PSK", &user_null_1, &key, 0, 0, 1); + run_test_ok("NORMAL:-KX-ALL:+PSK", &user_null_2, &key, 0, 0, 1); + run_test2("NORMAL:+PSK", NULL, &user_unknown, &key, 1, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER, 0); + run_test2("NORMAL:+PSK", NULL, &user_jas, &wrong_key, 1, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER, 0); + run_test2("NORMAL:+PSK", NULL, &user_hex, &wrong_key, 1, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER, 1); + run_test2("NORMAL:+PSK", NULL, &user_null_1, &wrong_key, 1, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER, 1); + run_test2("NORMAL:+PSK", NULL, &user_null_2, &wrong_key, 1, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER, 1); + run_test2("NORMAL:-KX-ALL:+PSK", NULL, &user_nonhex, &key, 1, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_KEYFILE_ERROR, 0); + + run_dhtest_ok("NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:-GROUP-EC-ALL", &user_jas, &key, 0, 0, 0); + run_dhtest_ok("NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:-GROUP-EC-ALL", &user_hex, &key, 0, 0, 1); + run_dhtest_ok("NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:-GROUP-EC-ALL", &user_null_1, &key, 0, 0, 1); + run_dhtest_ok("NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:-GROUP-EC-ALL", &user_null_2, &key, 0, 0, 1); + run_test_ok("NORMAL:-VERS-ALL:+VERS-TLS1.3:+PSK", &user_jas, &key, 0, 0, 0); + run_test_ok("NORMAL:-VERS-ALL:+VERS-TLS1.3:+PSK", &user_hex, &key, 0, 0, 1); + run_test_ok("NORMAL:-VERS-ALL:+VERS-TLS1.3:+PSK", &user_null_1, &key, 0, 0, 1); + run_test_ok("NORMAL:-VERS-ALL:+VERS-TLS1.3:+PSK", &user_null_2, &key, 0, 0, 1); /* test priorities of DHE-PSK and PSK */ - run_ectest_ok("NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+DHE-PSK:+PSK:-GROUP-DH-ALL", "jas", &key, 0, 0); - run_test_ok("NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+PSK:+DHE-PSK:-GROUP-DH-ALL", "jas", &key, 0, 0); + run_ectest_ok("NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+DHE-PSK:+PSK:-GROUP-DH-ALL", &user_jas, &key, 0, 0, 0); + run_ectest_ok("NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+DHE-PSK:+PSK:-GROUP-DH-ALL", &user_hex, &key, 0, 0, 1); + run_ectest_ok("NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+DHE-PSK:+PSK:-GROUP-DH-ALL", &user_null_1, &key, 0, 0, 1); + run_ectest_ok("NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+DHE-PSK:+PSK:-GROUP-DH-ALL", &user_null_2, &key, 0, 0, 1); + run_test_ok("NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+PSK:+DHE-PSK:-GROUP-DH-ALL", &user_jas, &key, 0, 0, 0); + run_test_ok("NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+PSK:+DHE-PSK:-GROUP-DH-ALL", &user_hex, &key, 0, 0, 1); + run_test_ok("NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+PSK:+DHE-PSK:-GROUP-DH-ALL", &user_null_1, &key, 0, 0, 1); + run_test_ok("NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+PSK:+DHE-PSK:-GROUP-DH-ALL", &user_null_2, &key, 0, 0, 1); run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+DHE-PSK:+PSK:-GROUP-DH-ALL", "NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+PSK:+DHE-PSK:%SERVER_PRECEDENCE:-GROUP-DH-ALL", - "jas", &key, 0, GNUTLS_KX_PSK, 0, 0); + &user_jas, &key, 0, GNUTLS_KX_PSK, 0, 0, 0); + run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+DHE-PSK:+PSK:-GROUP-DH-ALL", + "NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+PSK:+DHE-PSK:%SERVER_PRECEDENCE:-GROUP-DH-ALL", + &user_hex, &key, 0, GNUTLS_KX_PSK, 0, 0, 1); + run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+DHE-PSK:+PSK:-GROUP-DH-ALL", + "NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+PSK:+DHE-PSK:%SERVER_PRECEDENCE:-GROUP-DH-ALL", + &user_null_1, &key, 0, GNUTLS_KX_PSK, 0, 0, 1); + run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+DHE-PSK:+PSK:-GROUP-DH-ALL", + "NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-128-GCM:+PSK:+DHE-PSK:%SERVER_PRECEDENCE:-GROUP-DH-ALL", + &user_null_2, &key, 0, GNUTLS_KX_PSK, 0, 0, 1); /* try with PRF that doesn't match binder (SHA256) */ - run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-256-GCM:+PSK:+DHE-PSK", NULL, "jas", &key, 0, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_NO_CIPHER_SUITES); + run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-256-GCM:+PSK:+DHE-PSK", NULL, &user_jas, &key, 0, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_NO_CIPHER_SUITES, 0); + run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-256-GCM:+PSK:+DHE-PSK", NULL, &user_hex, &key, 0, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_NO_CIPHER_SUITES, 1); + run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-256-GCM:+PSK:+DHE-PSK", NULL, &user_null_1, &key, 0, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_NO_CIPHER_SUITES, 1); + run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.3:-CIPHER-ALL:+AES-256-GCM:+PSK:+DHE-PSK", NULL, &user_null_2, &key, 0, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_NO_CIPHER_SUITES, 1); /* try with no groups and PSK */ - run_test_ok("NORMAL:-VERS-ALL:+VERS-TLS1.3:+PSK:-GROUP-ALL", "jas", &key, 0, 0); + run_test_ok("NORMAL:-VERS-ALL:+VERS-TLS1.3:+PSK:-GROUP-ALL", &user_jas, &key, 0, 0, 0); + run_test_ok("NORMAL:-VERS-ALL:+VERS-TLS1.3:+PSK:-GROUP-ALL", &user_hex, &key, 0, 0, 1); + run_test_ok("NORMAL:-VERS-ALL:+VERS-TLS1.3:+PSK:-GROUP-ALL", &user_null_1, &key, 0, 0, 1); + run_test_ok("NORMAL:-VERS-ALL:+VERS-TLS1.3:+PSK:-GROUP-ALL", &user_null_2, &key, 0, 0, 1); /* try without any groups but DHE-PSK */ - run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:-GROUP-ALL", "NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:+PSK", "jas", &key, 0, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_NO_COMMON_KEY_SHARE); - run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:-GROUP-ALL", "NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:+PSK:-GROUP-ALL", "jas", &key, 0, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_NO_COMMON_KEY_SHARE); + run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:-GROUP-ALL", "NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:+PSK", &user_jas, &key, 0, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_NO_COMMON_KEY_SHARE, 0); + run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:-GROUP-ALL", "NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:+PSK:-GROUP-ALL", &user_jas, &key, 0, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_NO_COMMON_KEY_SHARE, 0); + run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:-GROUP-ALL", "NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:+PSK", &user_hex, &key, 0, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_NO_COMMON_KEY_SHARE, 1); + run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:-GROUP-ALL", "NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:+PSK:-GROUP-ALL", &user_hex, &key, 0, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_NO_COMMON_KEY_SHARE, 1); + run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:-GROUP-ALL", "NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:+PSK", &user_null_1, &key, 0, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_NO_COMMON_KEY_SHARE, 1); + run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:-GROUP-ALL", "NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:+PSK:-GROUP-ALL", &user_null_1, &key, 0, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_NO_COMMON_KEY_SHARE, 1); + run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:-GROUP-ALL", "NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:+PSK", &user_null_2, &key, 0, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_NO_COMMON_KEY_SHARE, 1); + run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:-GROUP-ALL", "NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:+PSK:-GROUP-ALL", &user_null_2, &key, 0, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_NO_COMMON_KEY_SHARE, 1); /* if user invalid we continue without PSK */ - run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.3:+PSK:+DHE-PSK", NULL, "non-hex", &key, 0, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_KEYFILE_ERROR); - run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.3:+PSK:+DHE-PSK", NULL, "unknown", &key, 0, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); - run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.3:+PSK:+DHE-PSK", NULL, "jas", &wrong_key, 0, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER); + run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.3:+PSK:+DHE-PSK", NULL, &user_nonhex, &key, 0, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_KEYFILE_ERROR, 0); + run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.3:+PSK:+DHE-PSK", NULL, &user_unknown, &key, 0, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER, 0); + run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.3:+PSK:+DHE-PSK", NULL, &user_jas, &wrong_key, 0, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER, 0); + run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.3:+PSK:+DHE-PSK", NULL, &user_hex, &wrong_key, 0, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER, 1); + run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.3:+PSK:+DHE-PSK", NULL, &user_null_1, &wrong_key, 0, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER, 1); + run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.3:+PSK:+DHE-PSK", NULL, &user_null_2, &wrong_key, 0, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER, 1); /* try with HelloRetryRequest and PSK */ - run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:-GROUP-ALL:+GROUP-FFDHE2048:+GROUP-FFDHE4096", "NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:-GROUP-ALL:+GROUP-FFDHE4096", "jas", &key, 0, GNUTLS_KX_DHE_PSK, 0, 0); + run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:-GROUP-ALL:+GROUP-FFDHE2048:+GROUP-FFDHE4096", "NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:-GROUP-ALL:+GROUP-FFDHE4096", &user_jas, &key, 0, GNUTLS_KX_DHE_PSK, 0, 0, 0); + run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:-GROUP-ALL:+GROUP-FFDHE2048:+GROUP-FFDHE4096", "NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:-GROUP-ALL:+GROUP-FFDHE4096", &user_hex, &key, 0, GNUTLS_KX_DHE_PSK, 0, 0, 1); + run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:-GROUP-ALL:+GROUP-FFDHE2048:+GROUP-FFDHE4096", "NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:-GROUP-ALL:+GROUP-FFDHE4096", &user_null_1, &key, 0, GNUTLS_KX_DHE_PSK, 0, 0, 1); + run_test2("NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:-GROUP-ALL:+GROUP-FFDHE2048:+GROUP-FFDHE4096", "NORMAL:-VERS-ALL:+VERS-TLS1.3:+DHE-PSK:-GROUP-ALL:+GROUP-FFDHE4096", &user_null_2, &key, 0, GNUTLS_KX_DHE_PSK, 0, 0, 1); /* try without server credentials */ - run_test3("NORMAL:-VERS-ALL:+VERS-TLS1.3:+PSK:+DHE-PSK", NULL, "jas", &key, 1, 0, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_INSUFFICIENT_CREDENTIALS); + run_test3("NORMAL:-VERS-ALL:+VERS-TLS1.3:+PSK:+DHE-PSK", NULL, &user_jas, &key, 1, 0, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_INSUFFICIENT_CREDENTIALS, 0); + run_test3("NORMAL:-VERS-ALL:+VERS-TLS1.3:+PSK:+DHE-PSK", NULL, &user_hex, &key, 1, 0, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_INSUFFICIENT_CREDENTIALS, 1); + run_test3("NORMAL:-VERS-ALL:+VERS-TLS1.3:+PSK:+DHE-PSK", NULL, &user_null_1, &key, 1, 0, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_INSUFFICIENT_CREDENTIALS, 1); + run_test3("NORMAL:-VERS-ALL:+VERS-TLS1.3:+PSK:+DHE-PSK", NULL, &user_null_2, &key, 1, 0, 0, GNUTLS_E_FATAL_ALERT_RECEIVED, GNUTLS_E_INSUFFICIENT_CREDENTIALS, 1); } #endif /* _WIN32 */ diff --git a/tests/psk.passwd b/tests/psk.passwd index 3dd998e2dc..db1edbd24f 100644 --- a/tests/psk.passwd +++ b/tests/psk.passwd @@ -1,2 +1,5 @@ jas:9e32cf7786321a828ef7668f09fb35db non-hex:9e32cf7786321a828ef7668f09fb35dbxx +#deadbeef:9e32cf7786321a828ef7668f09fb35db +#00:9e32cf7786321a828ef7668f09fb35db +#0000aa00:9e32cf7786321a828ef7668f09fb35db diff --git a/tests/pskself2.c b/tests/pskself2.c new file mode 100644 index 0000000000..81286a035b --- /dev/null +++ b/tests/pskself2.c @@ -0,0 +1,347 @@ +/* + * Copyright (C) 2004-2012 Free Software Foundation, Inc. + * Copyright (C) 2013 Adam Sampson <ats@offog.org> + * Copyright (C) 2019 Free Software Foundation, Inc. + * + * Author: Simon Josefsson, Ander Juaristi + * + * This file is part of GnuTLS. + * + * GnuTLS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuTLS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GnuTLS; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* Parts copied from pskself.c. */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> + +#if defined(_WIN32) + +/* socketpair isn't supported on Win32. */ +int main(int argc, char **argv) +{ + exit(77); +} + +#else + +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#if !defined(_WIN32) +#include <sys/wait.h> +#endif +#include <unistd.h> +#include <gnutls/gnutls.h> + +#include "utils.h" +#include "extras/hex.h" + +/* A very basic TLS client, with PSK authentication. + */ + +const char *side = ""; + +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "%s|<%d>| %s", side, level, str); +} + +#define MAX_BUF 1024 +#define MSG "Hello TLS" + +static void client(int sd, const char *prio, unsigned exp_hint) +{ + int ret, ii; + gnutls_session_t session; + char buffer[MAX_BUF + 1]; + gnutls_psk_client_credentials_t pskcred; + /* Need to enable anonymous KX specifically. */ + const gnutls_datum_t key = { (void *) "DEADBEEF", 8 }; + gnutls_datum_t user; + const char *hint; + + global_init(); + gnutls_global_set_log_function(tls_log_func); + if (debug) + gnutls_global_set_log_level(4711); + + side = "client"; + + user.data = gnutls_malloc(4); + user.data[0] = 0xCA; + user.data[1] = 0xFE; + user.data[2] = 0xCA; + user.data[3] = 0xFE; + user.size = 4; + + gnutls_psk_allocate_client_credentials(&pskcred); + ret = gnutls_psk_set_client_credentials2(pskcred, &user, &key, + GNUTLS_PSK_KEY_HEX); + if (ret < 0) { + fail("client: Could not set PSK\n"); + gnutls_perror(ret); + goto end; + } + + /* Initialize TLS session + */ + gnutls_init(&session, GNUTLS_CLIENT); + + /* Use default priorities */ + gnutls_priority_set_direct(session, prio, NULL); + + /* put the anonymous credentials to the current session + */ + gnutls_credentials_set(session, GNUTLS_CRD_PSK, pskcred); + + gnutls_transport_set_int(session, sd); + + /* Perform the TLS handshake + */ + ret = gnutls_handshake(session); + + if (ret < 0) { + fail("client: Handshake failed\n"); + gnutls_perror(ret); + goto end; + } else { + if (debug) + success("client: Handshake was completed\n"); + } + + /* check the hint */ + if (exp_hint) { + hint = gnutls_psk_client_get_hint(session); + if (hint == NULL || strcmp(hint, "hint") != 0) { + fail("client: hint is not the expected: %s\n", gnutls_psk_client_get_hint(session)); + goto end; + } + } + + gnutls_record_send(session, MSG, strlen(MSG)); + + ret = gnutls_record_recv(session, buffer, MAX_BUF); + if (ret == 0) { + if (debug) + success + ("client: Peer has closed the TLS connection\n"); + goto end; + } else if (ret < 0) { + fail("client: Error: %s\n", gnutls_strerror(ret)); + goto end; + } + + if (debug) { + printf("- Received %d bytes: ", ret); + for (ii = 0; ii < ret; ii++) { + fputc(buffer[ii], stdout); + } + fputs("\n", stdout); + } + + gnutls_bye(session, GNUTLS_SHUT_RDWR); + + end: + + close(sd); + + gnutls_deinit(session); + + gnutls_free(user.data); + gnutls_psk_free_client_credentials(pskcred); + + gnutls_global_deinit(); +} + +/* This is a sample TLS 1.0 echo server, for PSK authentication. + */ + +#define MAX_BUF 1024 + +/* These are global */ + +static int +pskfunc(gnutls_session_t session, const gnutls_datum_t *username, + gnutls_datum_t * key) +{ + if (debug) + printf("psk: Got username with length %d\n", username->size); + + key->data = gnutls_malloc(4); + key->data[0] = 0xDE; + key->data[1] = 0xAD; + key->data[2] = 0xBE; + key->data[3] = 0xEF; + key->size = 4; + + return 0; +} + + +static void server(int sd, const char *prio) +{ + gnutls_psk_server_credentials_t server_pskcred; + int ret; + gnutls_session_t session; + gnutls_datum_t psk_username; + char buffer[MAX_BUF + 1], expected_psk_username[] = { 0xDE, 0xAD, 0xBE, 0xEF }; + + /* this must be called once in the program + */ + global_init(); + gnutls_global_set_log_function(tls_log_func); + if (debug) + gnutls_global_set_log_level(4711); + + side = "server"; + + + gnutls_psk_allocate_server_credentials(&server_pskcred); + gnutls_psk_set_server_credentials_hint(server_pskcred, "hint"); + gnutls_psk_set_server_credentials_function2(server_pskcred, pskfunc); + + gnutls_init(&session, GNUTLS_SERVER); + + /* avoid calling all the priority functions, since the defaults + * are adequate. + */ + gnutls_priority_set_direct(session, prio, NULL); + + gnutls_credentials_set(session, GNUTLS_CRD_PSK, server_pskcred); + + gnutls_transport_set_int(session, sd); + ret = gnutls_handshake(session); + if (ret < 0) { + close(sd); + gnutls_deinit(session); + fail("server: Handshake has failed (%s)\n\n", + gnutls_strerror(ret)); + return; + } + + if (debug) { + success("server: Handshake was completed\n"); + + if (gnutls_psk_server_get_username(session)) + fail("server: gnutls_psk_server_get_username() should have returned NULL\n"); + if (gnutls_psk_server_get_username2(session, &psk_username) < 0) + fail("server: Could not get PSK username\n"); + + if (psk_username.size != 4 || memcmp(psk_username.data, expected_psk_username, 4)) + fail("server: Unexpected PSK username\n"); + + success("server: PSK username length: %d\n", psk_username.size); + } + + /* see the Getting peer's information example */ + /* print_info(session); */ + + for (;;) { + memset(buffer, 0, MAX_BUF + 1); + gnutls_record_set_timeout(session, 10000); + ret = gnutls_record_recv(session, buffer, MAX_BUF); + + if (ret == 0) { + if (debug) + success("server: Peer has closed the GnuTLS connection\n"); + break; + } else if (ret < 0) { + fail("server: Received corrupted data(%d). Closing...\n", ret); + break; + } else if (ret > 0) { + /* echo data back to the client + */ + gnutls_record_send(session, buffer, + strlen(buffer)); + } + } + /* do not wait for the peer to close the connection. + */ + gnutls_bye(session, GNUTLS_SHUT_WR); + + close(sd); + gnutls_deinit(session); + + gnutls_psk_free_server_credentials(server_pskcred); + + gnutls_global_deinit(); + + if (debug) + success("server: finished\n"); +} + +static +void run_test(const char *prio, unsigned exp_hint) +{ + pid_t child; + int err; + int sockets[2]; + + success("trying with %s\n", prio); + + err = socketpair(AF_UNIX, SOCK_STREAM, 0, sockets); + if (err == -1) { + perror("socketpair"); + fail("socketpair failed\n"); + return; + } + + child = fork(); + if (child < 0) { + perror("fork"); + fail("fork"); + return; + } + + if (child) { + int status; + /* parent */ + close(sockets[1]); + server(sockets[0], prio); + wait(&status); + check_wait_status(status); + } else { + close(sockets[0]); + client(sockets[1], prio, exp_hint); + exit(0); + } +} + +void doit(void) +{ + run_test("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+PSK", 1); + run_test("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+ECDHE-PSK", 1); + run_test("NORMAL:-VERS-ALL:+VERS-TLS1.2:-KX-ALL:+DHE-PSK", 1); + + run_test("NORMAL:-VERS-ALL:+VERS-TLS1.2:+PSK", 0); + run_test("NORMAL:-VERS-ALL:+VERS-TLS1.2:-GROUP-ALL:+GROUP-FFDHE2048:+DHE-PSK", 0); + run_test("NORMAL:-VERS-ALL:+VERS-TLS1.2:-GROUP-ALL:+GROUP-SECP256R1:+ECDHE-PSK", 0); + run_test("NORMAL:-VERS-ALL:+VERS-TLS1.3:+PSK", 0); + run_test("NORMAL:-VERS-ALL:+VERS-TLS1.3:-GROUP-ALL:+GROUP-FFDHE2048:+DHE-PSK", 0); + run_test("NORMAL:-VERS-ALL:+VERS-TLS1.3:-GROUP-ALL:+GROUP-SECP256R1:+ECDHE-PSK", 0); + /* the following should work once we support PSK without DH */ + run_test("NORMAL:-VERS-ALL:+VERS-TLS1.3:-GROUP-ALL:+PSK", 0); + + run_test("NORMAL:-KX-ALL:+PSK", 0); + run_test("NORMAL:-KX-ALL:+ECDHE-PSK", 0); + run_test("NORMAL:-KX-ALL:+DHE-PSK", 0); +} + +#endif /* _WIN32 */ |