diff --git a/src/kex.c b/src/kex.c index 1050d43b..da7767c7 100644 --- a/src/kex.c +++ b/src/kex.c @@ -796,6 +796,8 @@ int ssh_set_client_kex(ssh_session session) const char *wanted = NULL; int ok; int i; + bool gssapi_null_alg = false; + char *hostkeys = NULL; /* Skip if already set, for example for the rekey or when we do the guessing * it could have been already used to make some protocol decisions. */ @@ -831,6 +833,9 @@ int ssh_set_client_kex(ssh_session session) /* Prefix the default algorithms with gsskex algs */ session->opts.wanted_methods[SSH_KEX] = ssh_prefix_without_duplicates(default_methods[SSH_KEX], gssapi_algs); + + gssapi_null_alg = true; + SAFE_FREE(gssapi_algs); } #endif @@ -847,6 +852,15 @@ int ssh_set_client_kex(ssh_session session) ssh_set_error_oom(session); return SSH_ERROR; } + if (gssapi_null_alg) { + hostkeys = ssh_append_without_duplicates(client->methods[i], "null"); + if (hostkeys == NULL) { + ssh_set_error_oom(session); + return SSH_ERROR; + } + SAFE_FREE(client->methods[i]); + client->methods[i] = hostkeys; + } continue; } diff --git a/tests/client/CMakeLists.txt b/tests/client/CMakeLists.txt index 02a5a69e..52e8d8a5 100644 --- a/tests/client/CMakeLists.txt +++ b/tests/client/CMakeLists.txt @@ -46,7 +46,8 @@ if (WITH_GSSAPI AND GSSAPI_FOUND AND GSSAPI_TESTING) set(LIBSSH_CLIENT_TESTS ${LIBSSH_CLIENT_TESTS} torture_gssapi_auth - torture_gssapi_key_exchange) + torture_gssapi_key_exchange + torture_gssapi_key_exchange_null) endif() if (DEFAULT_C_NO_DEPRECATION_FLAGS) diff --git a/tests/client/torture_gssapi_key_exchange_null.c b/tests/client/torture_gssapi_key_exchange_null.c new file mode 100644 index 00000000..874a85e8 --- /dev/null +++ b/tests/client/torture_gssapi_key_exchange_null.c @@ -0,0 +1,136 @@ +#include "config.h" + +#define LIBSSH_STATIC + +#include "torture.h" +#include + +#include +#include +#include +#include + +static int +sshd_setup(void **state) +{ + struct torture_state *s = NULL; + torture_setup_sshd_server(state, false); + + s = *state; + s->disable_hostkeys = true; + + /* Temporary kerberos server */ + torture_setup_kdc_server( + state, + "kadmin.local addprinc -randkey host/server.libssh.site \n" + "kadmin.local ktadd -k $(dirname $0)/d/ssh.keytab host/server.libssh.site \n" + "kadmin.local addprinc -pw bar alice \n" + "kadmin.local list_principals", + + "echo bar | kinit alice"); + + torture_update_sshd_config(state, + "GSSAPIAuthentication yes\n" + "GSSAPIKeyExchange yes\n"); + + torture_teardown_kdc_server(state); + return 0; +} + +static int +sshd_teardown(void **state) +{ + assert_non_null(state); + + torture_teardown_sshd_server(state); + + return 0; +} + +static int +session_setup(void **state) +{ + struct torture_state *s = *state; + int verbosity = torture_libssh_verbosity(); + struct passwd *pwd = NULL; + int rc; + bool b = false; + + pwd = getpwnam("bob"); + assert_non_null(pwd); + + rc = setuid(pwd->pw_uid); + assert_return_code(rc, errno); + + s->ssh.session = ssh_new(); + assert_non_null(s->ssh.session); + + ssh_options_set(s->ssh.session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity); + ssh_options_set(s->ssh.session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER); + + ssh_options_set(s->ssh.session, SSH_OPTIONS_USER, TORTURE_SSH_USER_ALICE); + + /* Make sure no other configuration options from system will get used */ + rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_PROCESS_CONFIG, &b); + assert_ssh_return_code(s->ssh.session, rc); + + return 0; +} + +static int +session_teardown(void **state) +{ + struct torture_state *s = *state; + + assert_non_null(s); + + ssh_disconnect(s->ssh.session); + ssh_free(s->ssh.session); + + return 0; +} + +static void +torture_gssapi_key_exchange_null(void **state) +{ + struct torture_state *s = *state; + ssh_session session = s->ssh.session; + int rc; + bool t = true; + + /* Valid */ + torture_setup_kdc_server( + state, + "kadmin.local addprinc -randkey host/server.libssh.site \n" + "kadmin.local ktadd -k $(dirname $0)/d/ssh.keytab host/server.libssh.site \n" + "kadmin.local addprinc -pw bar alice \n" + "kadmin.local list_principals", + + "echo bar | kinit alice"); + + rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_GSSAPI_KEY_EXCHANGE, &t); + assert_ssh_return_code(s->ssh.session, rc); + + rc = ssh_connect(session); + assert_int_equal(rc, 0); + torture_teardown_kdc_server(state); +} + +int +torture_run_tests(void) +{ + int rc; + struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(torture_gssapi_key_exchange_null, + session_setup, + session_teardown), + }; + + ssh_init(); + + torture_filter_tests(tests); + rc = cmocka_run_group_tests(tests, sshd_setup, sshd_teardown); + ssh_finalize(); + + pthread_exit((void *)&rc); +} diff --git a/tests/ssh_ping.c b/tests/ssh_ping.c index 81b7ca78..9b53c7b3 100644 --- a/tests/ssh_ping.c +++ b/tests/ssh_ping.c @@ -75,6 +75,11 @@ int main(int argc, char **argv) goto out; } + rc = ssh_options_set(session, SSH_OPTIONS_GSSAPI_KEY_EXCHANGE, "gss-group14-sha256-"); + if (rc < 0) { + goto out; + } + rc = ssh_connect(session); if (rc != SSH_OK) { fprintf(stderr, "Connection failed : %s\n", ssh_get_error(session)); diff --git a/tests/torture.c b/tests/torture.c index 6c377957..a474fcce 100644 --- a/tests/torture.c +++ b/tests/torture.c @@ -657,6 +657,8 @@ void torture_setup_socket_dir(void **state) snprintf(s->srv_config, len, "%s/%s", p, TORTURE_SSHD_CONFIG); + s->disable_hostkeys = false; + setenv("SOCKET_WRAPPER_DIR", p, 1); setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "170", 1); env = getenv("TORTURE_GENERATE_PCAP"); @@ -975,6 +977,16 @@ torture_setup_create_sshd_config(void **state, bool pam, bool second_sshd) torture_get_testkey(SSH_KEYTYPE_ECDSA_P521, 0)); torture_write_file(trusted_ca_pubkey, torture_rsa_certauth_pub); } + if (s->disable_hostkeys) { + char ss[1000] = {0}; + rc = snprintf(ss, sizeof(ss), "rm %s/sshd/ssh_host_ecdsa_key %s/sshd/ssh_host_ed25519_key %s/sshd/ssh_host_rsa_key", s->socket_dir, s->socket_dir, s->socket_dir); + if (rc < 0 || rc >= (int)sizeof(ss)) { + fail_msg("snprintf failed"); + } + + rc = system(ss); + assert_int_equal(rc, SSH_OK); + } sftp_server = getenv("TORTURE_SFTP_SERVER"); if (sftp_server == NULL) { diff --git a/tests/torture.h b/tests/torture.h index 17120f5d..7bedd975 100644 --- a/tests/torture.h +++ b/tests/torture.h @@ -80,6 +80,7 @@ struct torture_state { char *srv1_pidfile; char *srv1_config; bool srv_pam; + bool disable_hostkeys; char *srv_additional_config; struct { ssh_session session;