]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
psk: Allow non-NULL PSK usernames
authorAnder Juaristi <a@juaristi.eus>
Mon, 2 Mar 2020 15:37:10 +0000 (16:37 +0100)
committerAnder Juaristi <a@juaristi.eus>
Mon, 23 Mar 2020 16:00:58 +0000 (17:00 +0100)
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>
22 files changed:
devel/symbols.last
doc/Makefile.am
doc/manpages/Makefile.am
lib/auth/dhe_psk.c
lib/auth/psk.c
lib/auth/psk.h
lib/auth/psk_passwd.c
lib/auth/psk_passwd.h
lib/auth/rsa_psk.c
lib/ext/pre_shared_key.c
lib/handshake-checks.c
lib/includes/gnutls/gnutls.h.in
lib/libgnutls.map
lib/psk.c
lib/session_pack.c
lib/str.h
lib/x509/email-verify.c
lib/x509/hostname-verify.c
tests/Makefile.am
tests/psk-file.c
tests/psk.passwd
tests/pskself2.c [new file with mode: 0644]

index 70ef6b3f1800eb493f2b434fc7a5b4345f2e30d6..a3a11ab7c212fed6b4bac178de2fb2c6e81c3e47 100644 (file)
@@ -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
index dd962d6a7852582ec069af0df04e7e429851ecc5..9c72b012812665f435c7441bfa5777a2efc1c46a 100644 (file)
@@ -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
index 6d381d8bd09206826a285194cf7fa014aae92e8c..60c937da83acebaf647d0d6830e1658ac3e123db 100644 (file)
@@ -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
index 6d66a6bb8b1ce5cf7773c160c817c95981c91dae..a98ef9c9ef4fa4cc26f27451ab2ee2e5b1428696 100644 (file)
@@ -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);
 
index 769510af4f53ae3c6d45e1dca415b9adf617d89b..6f220b63823c723e94a68ee689aa55eceee6d695 100644 (file)
@@ -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);
 
index 1592035bb1f0dc194167c0fffbbcfc78c2898bf8..b0e511f7fef263efc85612002e243709ed8c37d3 100644 (file)
@@ -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 */
index ec46ed3bf7f0333ac376c81ab2f5919f2ab34a36..4bdb4e02c48dfb521b3034fd359660a4f3335ab7 100644 (file)
@@ -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
index da4c90c0647886e5d646024ef2fab55994419a88..3d351f22c778915234143f3ac8b8695b8a6e902c 100644 (file)
@@ -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,
index 387bfd403e4c86a7653df0723dd103b65cd2eb5a..1a9dab56128c48c7c9831f3c412fa4e10500778b 100644 (file)
@@ -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;
index 8a39cda153e92a1b10f18e6dc7c11944d4e0ae18..fef67d341c1d2c3799235066ff79661ee6ca64fa 100644 (file)
@@ -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) {
index 56abc5bba68efc593800322655a3b3d013fbbc95..f8079dae366e3c4d4a49ec011f7da5699355058b 100644 (file)
@@ -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;
                }
        }
index b0832a9bddd19af21313030e902129edcc72f8e8..9fb6afa156cdbe3fe9c4662329c799d843febde0 100644 (file)
@@ -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);
index 3cc321beb839ffb6bceb88db230fc069cc67f0b2..7c3187541d48eadb965e5dae8c1e50ac95885371 100644 (file)
@@ -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 {
index ebb3f246ffdc1965d8996ab463197046356e6b8d..aa5220c27cbbc01a2a42247c100ab6861fa7045d 100644 (file)
--- a/lib/psk.c
+++ b/lib/psk.c
@@ -24,6 +24,7 @@
 
 #include "gnutls_int.h"
 #include "errors.h"
+#include <str.h>
 #include <auth/psk.h>
 #include <state.h>
 
@@ -95,16 +96,47 @@ gnutls_psk_set_client_credentials(gnutls_psk_client_credentials_t res,
                                  const char *username,
                                  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.
@@ -280,8 +322,62 @@ gnutls_psk_set_server_credentials_function(gnutls_psk_server_credentials_t
                                           cred,
                                           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;
 }
 
 /**
@@ -310,8 +406,41 @@ gnutls_psk_set_client_credentials_function(gnutls_psk_client_credentials_t
                                           cred,
                                           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,12 +470,47 @@ 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
index e5c21f24b5a6bac7e2e5762ec64eeb9709f2f495..a6d11c4cfc26e50155a87623073a4406061fb958 100644 (file)
@@ -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();
index 854cca12a62d03b1e1bcc3e95d18f65a4bd3526b..65d42081e8d00e71b6c484907892990366333309 100644 (file)
--- a/lib/str.h
+++ b/lib/str.h
@@ -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);
 
index 4eee0699bc3251e7237a1d502fa225abcfb8e512..053e51287229f1da28f318977fb36bf50aa3422d 100644 (file)
 #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;
index 967d9b821ac6bcb3ca79bf38ef535a72b4af815a..6ef8ba0303d4a21126c823c11fc32f03e1a8c7a8 100644 (file)
@@ -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;
index 5c89f77c1174f033dd49575ef0a15ec9e47246df..c79dcce7e5244cc4b0011bb9d047bc33093f3a47 100644 (file)
@@ -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
index 22e744f1a7793ab5f7478f029476814df0fa1942..703043ec40f7ea5e8f6af6c746132a16698f77a2 100644 (file)
@@ -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 */
index 3dd998e2dc5b543b2efbc8e5ecb30c11a704b499..db1edbd24f8e20b446978a1249ea13923171385a 100644 (file)
@@ -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 (file)
index 0000000..81286a0
--- /dev/null
@@ -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 */