feat: add null hostkey for server

fix: skip gssapi tests in fips mode

fix: skip gssapi_key_exchange_null test on ubuntu and tumbleweed

fix: return early when rc != 0 to show error

tests: replace int asserts by ssh return code asserts

fix: add fatal error when hostkeys are not found and gssapi kex is not enabled

ci: add comment linking gssapi null kex bug in ubuntu and tumbleweed

fix: don't specify hostkeys in config instead of deleting files

tests: assert kex method was null

refactor: remove redundant include

refactor: better error message

fix: check null before accessing in gssapi.c

fix: allow setting no hostkeys
Signed-off-by: Gauravsingh Sisodia <xaerru@gmail.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Reviewed-by: Andreas Schneider <asn@cryptomilk.org>
This commit is contained in:
Gauravsingh Sisodia
2024-08-29 14:03:12 +00:00
committed by Jakub Jelen
parent fd1c3e8878
commit c1aab9903f
21 changed files with 579 additions and 117 deletions

View File

@@ -83,6 +83,11 @@ workflow:
.tumbleweed:
extends: .tests
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$TUMBLEWEED_BUILD
script:
# torture_gssapi_key_exchange_null is excluded because of a bug (https://issues.redhat.com/browse/RHEL-55740)
- cmake $CMAKE_OPTIONS $CMAKE_ADDITIONAL_OPTIONS .. &&
make -j$(nproc) &&
ctest --output-on-failure -E "^torture_gssapi_key_exchange_null$"
.centos:
extends: .tests
@@ -504,6 +509,11 @@ fedora/abidiff:
ubuntu/openssl_3.0.x/x86_64:
image: $CI_REGISTRY/$BUILD_IMAGES_PROJECT:$UBUNTU_BUILD
extends: .tests
script:
# torture_gssapi_key_exchange_null is excluded because of a bug (https://issues.redhat.com/browse/RHEL-55740)
- cmake $CMAKE_OPTIONS $CMAKE_ADDITIONAL_OPTIONS .. &&
make -j$(nproc) &&
ctest --output-on-failure -E "^torture_gssapi_key_exchange_null$"
###############################################################################

View File

@@ -2456,7 +2456,7 @@ pending:
}
/**
* @brief Try to authenticate through the "gssapi-with-keyex" method.
* @brief Try to authenticate through the "gssapi-keyex" method.
*
* @param[in] session The ssh session to use.
*
@@ -2503,7 +2503,7 @@ int ssh_userauth_gssapi_keyex(ssh_session session)
} else if (rc == SSH_ERROR) {
return SSH_AUTH_ERROR;
}
SSH_LOG(SSH_LOG_DEBUG, "Authenticating with gssapi-with-keyex");
SSH_LOG(SSH_LOG_DEBUG, "Authenticating with gssapi-keyex");
session->auth.current_method = SSH_AUTH_METHOD_GSSAPI_KEYEX;
session->auth.state = SSH_AUTH_STATE_NONE;

View File

@@ -245,8 +245,13 @@ int ssh_bind_listen(ssh_bind sshbind)
sshbind->ecdsa == NULL &&
sshbind->ed25519 == NULL) {
rc = ssh_bind_import_keys(sshbind);
if (rc != SSH_OK) {
return SSH_ERROR;
if (rc == SSH_ERROR) {
if (!sshbind->gssapi_key_exchange) {
ssh_set_error(sshbind, SSH_FATAL,
"No hostkeys found");
return SSH_ERROR;
}
SSH_LOG(SSH_LOG_DEBUG, "No hostkeys found: Using \"null\" hostkey algorithm");
}
}
@@ -467,6 +472,7 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd)
session->opts.gssapi_key_exchange = sshbind->gssapi_key_exchange;
if (sshbind->gssapi_key_exchange_algs != NULL) {
SAFE_FREE(session->opts.gssapi_key_exchange_algs);
session->opts.gssapi_key_exchange_algs = strdup(sshbind->gssapi_key_exchange_algs);
if (session->opts.gssapi_key_exchange_algs == NULL) {
ssh_set_error_oom(sshbind);
@@ -519,8 +525,13 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd)
sshbind->ecdsa == NULL &&
sshbind->ed25519 == NULL) {
rc = ssh_bind_import_keys(sshbind);
if (rc != SSH_OK) {
return SSH_ERROR;
if (rc == SSH_ERROR) {
if (!sshbind->gssapi_key_exchange) {
ssh_set_error(sshbind, SSH_FATAL,
"No hostkeys found");
return SSH_ERROR;
}
SSH_LOG(SSH_LOG_DEBUG, "No hostkeys found: Using \"null\" hostkey algorithm");
}
}

View File

@@ -338,11 +338,6 @@ int ssh_server_gss_dh_process_init(ssh_session session, ssh_buffer packet)
goto error;
}
rc = ssh_get_key_params(session, &privkey, &digest);
if (rc != SSH_OK) {
goto error;
}
rc = ssh_dh_compute_shared_secret(crypto->dh_ctx,
DH_SERVER_KEYPAIR, DH_CLIENT_KEYPAIR,
&crypto->shared_secret);
@@ -351,32 +346,39 @@ int ssh_server_gss_dh_process_init(ssh_session session, ssh_buffer packet)
ssh_set_error(session, SSH_FATAL, "Could not generate shared secret");
goto error;
}
/* Also imports next_crypto->server_pubkey
* Can give error when using null hostkey */
ssh_get_key_params(session, &privkey, &digest);
rc = ssh_make_sessionid(session);
if (rc != SSH_OK) {
ssh_set_error(session, SSH_FATAL, "Could not create a session id");
goto error;
}
rc = ssh_dh_get_next_server_publickey_blob(session, &server_pubkey_blob);
if (rc != SSH_OK) {
goto error;
}
rc = ssh_buffer_pack(session->out_buffer,
"bS",
SSH2_MSG_KEXGSS_HOSTKEY,
server_pubkey_blob);
if(rc != SSH_OK) {
ssh_set_error_oom(session);
ssh_buffer_reinit(session->out_buffer);
goto error;
}
if (strncmp(crypto->kex_methods[SSH_HOSTKEYS], "null", 4) != 0) {
rc = ssh_dh_get_next_server_publickey_blob(session, &server_pubkey_blob);
if (rc != SSH_OK) {
goto error;
}
rc = ssh_buffer_pack(session->out_buffer,
"bS",
SSH2_MSG_KEXGSS_HOSTKEY,
server_pubkey_blob);
if(rc != SSH_OK) {
ssh_set_error_oom(session);
ssh_buffer_reinit(session->out_buffer);
goto error;
}
rc = ssh_packet_send(session);
if (rc == SSH_ERROR) {
goto error;
rc = ssh_packet_send(session);
if (rc == SSH_ERROR) {
goto error;
}
SSH_LOG(SSH_LOG_DEBUG, "Sent SSH2_MSG_KEXGSS_HOSTKEY");
SSH_STRING_FREE(server_pubkey_blob);
}
SSH_LOG(SSH_LOG_DEBUG, "Sent SSH2_MSG_KEXGSS_HOSTKEY");
SSH_STRING_FREE(server_pubkey_blob);
rc = ssh_dh_keypair_get_keys(crypto->dh_ctx, DH_SERVER_KEYPAIR,
NULL, &server_pubkey);

View File

@@ -727,6 +727,10 @@ ssh_gssapi_check_client_config(ssh_session session)
for (i = 0; i < supported->count; ++i){
gssapi = calloc(1, sizeof(struct ssh_gssapi_struct));
if (gssapi == NULL) {
ssh_set_error_oom(session);
return SSH_ERROR;
}
gssapi->server_creds = GSS_C_NO_CREDENTIAL;
gssapi->client_creds = GSS_C_NO_CREDENTIAL;
gssapi->ctx = GSS_C_NO_CONTEXT;
@@ -786,7 +790,7 @@ ssh_gssapi_check_client_config(ssh_session session)
SSH_LOG(SSH_LOG_DEBUG, "Supported mech %zu: %s", i, ptr);
free(ptr);
/* If any one is configured then return successfully */
/* If atleast one mechanism is configured then return successfully */
ret = SSH_OK;
end:

View File

@@ -811,7 +811,7 @@ int ssh_set_client_kex(ssh_session session)
return SSH_ERROR;
}
#ifdef WITH_GSSAPI
if (session->opts.gssapi_key_exchange) {
if (session->opts.gssapi_key_exchange && !ssh_fips_mode()) {
char *gssapi_algs = NULL;
ok = ssh_gssapi_init(session);
@@ -825,7 +825,7 @@ int ssh_set_client_kex(ssh_session session)
return SSH_ERROR;
}
gssapi_algs = ssh_gssapi_kex_mechs(session, session->opts.gssapi_key_exchange_algs ? session->opts.gssapi_key_exchange_algs : GSSAPI_KEY_EXCHANGE_SUPPORTED);
gssapi_algs = ssh_gssapi_kex_mechs(session, session->opts.gssapi_key_exchange_algs);
if (gssapi_algs == NULL) {
return SSH_ERROR;
}
@@ -1488,15 +1488,15 @@ int ssh_make_sessionid(ssh_session session)
goto error;
}
if (server_pubkey_blob == NULL && session->opts.gssapi_key_exchange) {
ssh_string_free(server_pubkey_blob);
server_pubkey_blob = ssh_string_new(0);
}
if (session->server) {
if (server_pubkey_blob == NULL && ssh_kex_is_gss(session->next_crypto)) {
ssh_string_free(server_pubkey_blob);
if (server_pubkey_blob == NULL) {
if ((session->server && ssh_kex_is_gss(session->next_crypto)) ||
session->opts.gssapi_key_exchange) {
server_pubkey_blob = ssh_string_new(0);
if (server_pubkey_blob == NULL) {
ssh_set_error_oom(session);
rc = SSH_ERROR;
goto error;
}
}
}

View File

@@ -566,7 +566,7 @@ int ssh_options_set_algo(ssh_session session,
* to the server (int, 0 = false).
*
* - SSH_OPTIONS_GSSAPI_KEY_EXCHANGE
* Set to true to do GSSAPI key exchange (bool).
* Set to true to allow GSSAPI key exchange (bool).
*
* - SSH_OPTIONS_GSSAPI_KEY_EXCHANGE_ALGS
* Set the GSSAPI key exchange method to be used (const char *,
@@ -1285,6 +1285,7 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
"GSSAPI key exchange algorithms not supported or invalid");
return -1;
}
SAFE_FREE(session->opts.gssapi_key_exchange_algs);
session->opts.gssapi_key_exchange_algs = ret;
}
break;

View File

@@ -141,10 +141,6 @@ int server_set_kex(ssh_session session)
",%s", ssh_key_type_to_char(keytype));
}
if (strlen(hostkeys) == 0) {
return -1;
}
if (session->opts.wanted_methods[SSH_HOSTKEYS]) {
allowed = session->opts.wanted_methods[SSH_HOSTKEYS];
} else {
@@ -155,33 +151,34 @@ int server_set_kex(ssh_session session)
}
}
/* It is expected for the list of allowed hostkeys to be ordered by
* preference */
kept = ssh_find_all_matching(hostkeys[0] == ',' ? hostkeys + 1 : hostkeys,
allowed);
if (kept == NULL) {
/* Nothing was allowed */
return -1;
}
if (strlen(hostkeys) != 0) {
/* It is expected for the list of allowed hostkeys to be ordered by
* preference */
kept = ssh_find_all_matching(hostkeys[0] == ',' ? hostkeys + 1 : hostkeys,
allowed);
if (kept == NULL) {
/* Nothing was allowed */
return -1;
}
rc = ssh_options_set_algo(session,
SSH_HOSTKEYS,
kept,
&session->opts.wanted_methods[SSH_HOSTKEYS]);
SAFE_FREE(kept);
if (rc < 0) {
return -1;
rc = ssh_options_set_algo(session,
SSH_HOSTKEYS,
kept,
&session->opts.wanted_methods[SSH_HOSTKEYS]);
SAFE_FREE(kept);
if (rc < 0) {
return -1;
}
}
#ifdef WITH_GSSAPI
if (session->opts.gssapi_key_exchange) {
if (session->opts.gssapi_key_exchange && !ssh_fips_mode()) {
ok = ssh_gssapi_init(session);
if (ok != SSH_OK) {
ssh_set_error_oom(session);
return SSH_ERROR;
}
gssapi_algs = ssh_gssapi_kex_mechs(session, session->opts.gssapi_key_exchange_algs ? session->opts.gssapi_key_exchange_algs : GSSAPI_KEY_EXCHANGE_SUPPORTED);
gssapi_algs = ssh_gssapi_kex_mechs(session, session->opts.gssapi_key_exchange_algs);
if (gssapi_algs == NULL) {
return SSH_ERROR;
}
@@ -191,6 +188,10 @@ int server_set_kex(ssh_session session)
session->opts.wanted_methods[SSH_KEX] =
ssh_prefix_without_duplicates(ssh_kex_get_default_methods(SSH_KEX), gssapi_algs);
if (strlen(hostkeys) == 0) {
session->opts.wanted_methods[SSH_HOSTKEYS] = strdup("null");
}
SAFE_FREE(gssapi_algs);
}
#endif /* WITH_GSSAPI */

View File

@@ -160,6 +160,13 @@ ssh_session ssh_new(void)
goto err;
}
#ifdef WITH_GSSAPI
session->opts.gssapi_key_exchange_algs = strdup(GSSAPI_KEY_EXCHANGE_SUPPORTED);
if (session->opts.gssapi_key_exchange_algs == NULL) {
goto err;
}
#endif /* WITH_GSSAPI */
id = strdup("%d/id_ed25519");
if (id == NULL) {
goto err;

View File

@@ -272,5 +272,11 @@ torture_run_tests(void)
rc = cmocka_run_group_tests(tests, sshd_setup, sshd_teardown);
ssh_finalize();
return rc;
/* pthread_exit() won't return anything so error should be returned prior */
if (rc != 0) {
return rc;
}
/* Required for freeing memory allocated by GSSAPI */
pthread_exit(NULL);
}

View File

@@ -83,6 +83,11 @@ torture_gssapi_key_exchange(void **state)
int rc;
bool t = true;
/* Skip test if in FIPS mode */
if (ssh_fips_mode()) {
skip();
}
/* Valid */
torture_setup_kdc_server(
state,
@@ -97,7 +102,7 @@ torture_gssapi_key_exchange(void **state)
assert_ssh_return_code(s->ssh.session, rc);
rc = ssh_connect(session);
assert_int_equal(rc, 0);
assert_ssh_return_code(session, rc);
torture_teardown_kdc_server(state);
}
@@ -109,6 +114,11 @@ torture_gssapi_key_exchange_no_tgt(void **state)
int rc;
bool t = true;
/* Skip test if in FIPS mode */
if (ssh_fips_mode()) {
skip();
}
/* Don't run kinit */
torture_setup_kdc_server(
state,
@@ -124,7 +134,7 @@ torture_gssapi_key_exchange_no_tgt(void **state)
assert_ssh_return_code(s->ssh.session, rc);
rc = ssh_connect(session);
assert_int_equal(rc, 0);
assert_ssh_return_code(session, rc);
assert_int_not_equal(session->current_crypto->kex_type, SSH_GSS_KEX_DH_GROUP14_SHA256);
assert_int_not_equal(session->current_crypto->kex_type, SSH_GSS_KEX_DH_GROUP16_SHA512);
@@ -140,6 +150,11 @@ torture_gssapi_key_exchange_gss_group14_sha256(void **state)
int rc;
bool t = true;
/* Skip test if in FIPS mode */
if (ssh_fips_mode()) {
skip();
}
/* Valid */
torture_setup_kdc_server(
state,
@@ -157,7 +172,7 @@ torture_gssapi_key_exchange_gss_group14_sha256(void **state)
assert_ssh_return_code(s->ssh.session, rc);
rc = ssh_connect(session);
assert_int_equal(rc, 0);
assert_ssh_return_code(session, rc);
assert_int_equal(session->current_crypto->kex_type, SSH_GSS_KEX_DH_GROUP14_SHA256);
@@ -172,6 +187,11 @@ torture_gssapi_key_exchange_gss_group16_sha512(void **state)
int rc;
bool t = true;
/* Skip test if in FIPS mode */
if (ssh_fips_mode()) {
skip();
}
/* Valid */
torture_setup_kdc_server(
state,
@@ -189,7 +209,7 @@ torture_gssapi_key_exchange_gss_group16_sha512(void **state)
assert_ssh_return_code(s->ssh.session, rc);
rc = ssh_connect(session);
assert_int_equal(rc, 0);
assert_ssh_return_code(session, rc);
assert_true(session->current_crypto->kex_type == SSH_GSS_KEX_DH_GROUP16_SHA512);
@@ -204,6 +224,11 @@ torture_gssapi_key_exchange_auth(void **state)
int rc;
bool t = true;
/* Skip test if in FIPS mode */
if (ssh_fips_mode()) {
skip();
}
/* Valid */
torture_setup_kdc_server(
state,
@@ -218,7 +243,7 @@ torture_gssapi_key_exchange_auth(void **state)
assert_ssh_return_code(s->ssh.session, rc);
rc = ssh_connect(session);
assert_int_equal(rc, 0);
assert_ssh_return_code(session, rc);
rc = ssh_userauth_gssapi_keyex(session);
assert_int_equal(rc, SSH_AUTH_SUCCESS);
@@ -234,6 +259,11 @@ torture_gssapi_key_exchange_no_auth(void **state)
int rc;
bool f = false;
/* Skip test if in FIPS mode */
if (ssh_fips_mode()) {
skip();
}
/* Valid */
torture_setup_kdc_server(
state,
@@ -249,7 +279,7 @@ torture_gssapi_key_exchange_no_auth(void **state)
assert_ssh_return_code(s->ssh.session, rc);
rc = ssh_connect(session);
assert_int_equal(rc, 0);
assert_ssh_return_code(session, rc);
/* Still try to do "gssapi-keyex" auth */
rc = ssh_userauth_gssapi_keyex(session);
@@ -289,5 +319,11 @@ torture_run_tests(void)
rc = cmocka_run_group_tests(tests, sshd_setup, sshd_teardown);
ssh_finalize();
pthread_exit((void *)&rc);
/* pthread_exit() won't return anything so error should be returned prior */
if (rc != 0) {
return rc;
}
/* Required for freeing memory allocated by GSSAPI */
pthread_exit(NULL);
}

View File

@@ -19,21 +19,23 @@ sshd_setup(void **state)
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",
if (!ssh_fips_mode()) {
/* 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");
"echo bar | kinit alice");
torture_update_sshd_config(state,
"GSSAPIAuthentication yes\n"
"GSSAPIKeyExchange yes\n");
torture_update_sshd_config(state,
"GSSAPIAuthentication yes\n"
"GSSAPIKeyExchange yes\n");
torture_teardown_kdc_server(state);
torture_teardown_kdc_server(state);
}
return 0;
}
@@ -98,6 +100,11 @@ torture_gssapi_key_exchange_null(void **state)
int rc;
bool t = true;
/* Skip test if in FIPS mode */
if (ssh_fips_mode()) {
skip();
}
/* Valid */
torture_setup_kdc_server(
state,
@@ -112,7 +119,10 @@ torture_gssapi_key_exchange_null(void **state)
assert_ssh_return_code(s->ssh.session, rc);
rc = ssh_connect(session);
assert_int_equal(rc, 0);
assert_ssh_return_code(s->ssh.session, rc);
assert_string_equal(session->current_crypto->kex_methods[SSH_HOSTKEYS], "null");
torture_teardown_kdc_server(state);
}
@@ -132,5 +142,11 @@ torture_run_tests(void)
rc = cmocka_run_group_tests(tests, sshd_setup, sshd_teardown);
ssh_finalize();
pthread_exit((void *)&rc);
/* pthread_exit() won't return anything so error should be returned prior */
if (rc != 0) {
return rc;
}
/* Required for freeing memory allocated by GSSAPI */
pthread_exit(NULL);
}

View File

@@ -20,7 +20,8 @@ if (WITH_GSSAPI AND GSSAPI_FOUND AND GSSAPI_TESTING)
torture_gssapi_server_auth
torture_gssapi_server_auth_cb
torture_gssapi_server_delegation
torture_gssapi_server_key_exchange)
torture_gssapi_server_key_exchange
torture_gssapi_server_key_exchange_null)
endif()
include_directories(${libssh_SOURCE_DIR}/include

View File

@@ -145,9 +145,8 @@ int run_server(struct server_state_st *state)
}
if (state->host_key == NULL && state->rsa_key == NULL &&
state->ecdsa_key == NULL && state->ed25519_key) {
state->ecdsa_key == NULL && state->ed25519_key == NULL) {
fprintf(stderr, "Missing host key\n");
goto out;
}
sshbind = ssh_bind_new();
@@ -211,7 +210,7 @@ int run_server(struct server_state_st *state)
state->gssapi_key_exchange_algs);
if (rc != 0) {
fprintf(stderr,
"Error setting GSSAPI key exchange: %s\n",
"Error setting GSSAPI key exchange algorithms: %s\n",
ssh_get_error(sshbind));
goto out;
}

View File

@@ -452,5 +452,11 @@ torture_run_tests(void)
teardown_default_server);
ssh_finalize();
return rc;
/* pthread_exit() won't return anything so error should be returned prior */
if (rc != 0) {
return rc;
}
/* Required for freeing memory allocated by GSSAPI */
pthread_exit(NULL);
}

View File

@@ -476,5 +476,11 @@ torture_run_tests(void)
teardown_default_server);
ssh_finalize();
return rc;
/* pthread_exit() won't return anything so error should be returned prior */
if (rc != 0) {
return rc;
}
/* Required for freeing memory allocated by GSSAPI */
pthread_exit(NULL);
}

View File

@@ -372,5 +372,11 @@ torture_run_tests(void)
teardown_default_server);
ssh_finalize();
return rc;
/* pthread_exit() won't return anything so error should be returned prior */
if (rc != 0) {
return rc;
}
/* Required for freeing memory allocated by GSSAPI */
pthread_exit(NULL);
}

View File

@@ -286,6 +286,11 @@ torture_gssapi_server_key_exchange(void **state)
int rc;
bool t = true;
/* Skip test if in FIPS mode */
if (ssh_fips_mode()) {
skip();
}
assert_non_null(tss);
s = tss->state;
@@ -322,6 +327,11 @@ torture_gssapi_server_key_exchange_no_tgt(void **state)
int rc;
bool t = true;
/* Skip test if in FIPS mode */
if (ssh_fips_mode()) {
skip();
}
assert_non_null(tss);
s = tss->state;
@@ -345,7 +355,7 @@ torture_gssapi_server_key_exchange_no_tgt(void **state)
assert_ssh_return_code(s->ssh.session, rc);
rc = ssh_connect(session);
assert_int_equal(rc, 0);
assert_ssh_return_code(session, rc);
assert_int_not_equal(session->current_crypto->kex_type, SSH_GSS_KEX_DH_GROUP14_SHA256);
assert_int_not_equal(session->current_crypto->kex_type, SSH_GSS_KEX_DH_GROUP16_SHA512);
@@ -362,6 +372,11 @@ torture_gssapi_server_key_exchange_gss_group14_sha256(void **state)
int rc;
bool t = true;
/* Skip test if in FIPS mode */
if (ssh_fips_mode()) {
skip();
}
assert_non_null(tss);
s = tss->state;
@@ -387,7 +402,7 @@ torture_gssapi_server_key_exchange_gss_group14_sha256(void **state)
assert_ssh_return_code(s->ssh.session, rc);
rc = ssh_connect(session);
assert_int_equal(rc, 0);
assert_ssh_return_code(session, rc);
assert_int_equal(session->current_crypto->kex_type, SSH_GSS_KEX_DH_GROUP14_SHA256);
@@ -403,6 +418,11 @@ torture_gssapi_server_key_exchange_gss_group16_sha512(void **state)
int rc;
bool t = true;
/* Skip test if in FIPS mode */
if (ssh_fips_mode()) {
skip();
}
assert_non_null(tss);
s = tss->state;
@@ -428,7 +448,7 @@ torture_gssapi_server_key_exchange_gss_group16_sha512(void **state)
assert_ssh_return_code(s->ssh.session, rc);
rc = ssh_connect(session);
assert_int_equal(rc, 0);
assert_ssh_return_code(session, rc);
assert_int_equal(session->current_crypto->kex_type, SSH_GSS_KEX_DH_GROUP16_SHA512);
@@ -444,6 +464,11 @@ torture_gssapi_server_key_exchange_auth(void **state)
int rc;
bool t = true;
/* Skip test if in FIPS mode */
if (ssh_fips_mode()) {
skip();
}
assert_non_null(tss);
s = tss->state;
@@ -483,6 +508,11 @@ torture_gssapi_server_key_exchange_no_auth(void **state)
int rc;
bool f = false;
/* Skip test if in FIPS mode */
if (ssh_fips_mode()) {
skip();
}
assert_non_null(tss);
s = tss->state;
@@ -547,5 +577,11 @@ torture_run_tests(void)
teardown_default_server);
ssh_finalize();
pthread_exit((void *)&rc);
/* pthread_exit() won't return anything so error should be returned prior */
if (rc != 0) {
return rc;
}
/* Required for freeing memory allocated by GSSAPI */
pthread_exit(NULL);
}

View File

@@ -0,0 +1,305 @@
#include "config.h"
#define LIBSSH_STATIC
#include <errno.h>
#include <pwd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "libssh/libssh.h"
#include "torture.h"
#include "test_server.h"
#include "default_cb.h"
struct test_server_st {
struct torture_state *state;
struct server_state_st *ss;
char *cwd;
};
static void
free_test_server_state(void **state)
{
struct test_server_st *tss = *state;
torture_free_state(tss->state);
SAFE_FREE(tss);
}
static void
setup_config(void **state)
{
struct torture_state *s = NULL;
struct server_state_st *ss = NULL;
struct test_server_st *tss = NULL;
char sshd_path[1024];
char log_file[1024];
char kdc_env[255] = {0};
int rc;
assert_non_null(state);
tss = (struct test_server_st *)calloc(1, sizeof(struct test_server_st));
assert_non_null(tss);
torture_setup_socket_dir((void **)&s);
assert_non_null(s->socket_dir);
assert_non_null(s->gss_dir);
torture_set_kdc_env_str(s->gss_dir, kdc_env, sizeof(kdc_env));
torture_set_env_from_str(kdc_env);
/* Set the default interface for the server */
setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "10", 1);
setenv("PAM_WRAPPER", "1", 1);
snprintf(sshd_path, sizeof(sshd_path), "%s/sshd", s->socket_dir);
rc = mkdir(sshd_path, 0755);
assert_return_code(rc, errno);
snprintf(log_file, sizeof(log_file), "%s/sshd/log", s->socket_dir);
/* Create default server state */
ss = (struct server_state_st *)calloc(1, sizeof(struct server_state_st));
assert_non_null(ss);
ss->address = strdup("127.0.0.10");
assert_non_null(ss->address);
ss->port = 22;
/* not to mix up the client and server messages */
ss->verbosity = torture_libssh_verbosity();
ss->log_file = strdup(log_file);
ss->auth_methods = SSH_AUTH_METHOD_GSSAPI_KEYEX;
#ifdef WITH_PCAP
ss->with_pcap = 1;
ss->pcap_file = strdup(s->pcap_file);
assert_non_null(ss->pcap_file);
#endif
/* TODO make configurable */
ss->max_tries = 3;
ss->error = 0;
/* Use the default session handling function */
ss->handle_session = default_handle_session_cb;
assert_non_null(ss->handle_session);
/* Do not use global configuration */
ss->parse_global_config = false;
/* Enable GSSAPI key exchange */
ss->gssapi_key_exchange = true;
ss->gssapi_key_exchange_algs = "gss-group14-sha256-,gss-group16-sha512-";
tss->state = s;
tss->ss = ss;
*state = tss;
}
static int
setup_default_server(void **state)
{
struct torture_state *s = NULL;
struct server_state_st *ss = NULL;
struct test_server_st *tss = NULL;
char pid_str[1024] = {0};
pid_t pid;
/*int rc;*/
setup_config(state);
tss = *state;
ss = tss->ss;
s = tss->state;
setenv("NSS_WRAPPER_HOSTNAME", "server.libssh.site", 1);
/* Start the server using the default values */
pid = fork_run_server(ss, free_test_server_state, &tss);
if (pid < 0) {
fail();
}
snprintf(pid_str, sizeof(pid_str), "%d", pid);
torture_write_file(s->srv_pidfile, (const char *)pid_str);
setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "21", 1);
unsetenv("PAM_WRAPPER");
/* Wait until the sshd is ready to accept connections */
/*rc = torture_wait_for_daemon(5);*/
/*assert_int_equal(rc, 0);*/
*state = tss;
return 0;
}
static int
teardown_default_server(void **state)
{
struct torture_state *s = NULL;
struct server_state_st *ss = NULL;
struct test_server_st *tss = NULL;
tss = *state;
assert_non_null(tss);
s = tss->state;
assert_non_null(s);
ss = tss->ss;
assert_non_null(ss);
/* This function can be reused */
torture_teardown_sshd_server((void **)&s);
free_server_state(tss->ss);
SAFE_FREE(tss->ss);
SAFE_FREE(tss);
return 0;
}
static int
session_setup(void **state)
{
struct test_server_st *tss = *state;
struct torture_state *s = NULL;
int verbosity = torture_libssh_verbosity();
char *cwd = NULL;
bool b = false;
int rc;
assert_non_null(tss);
/* Make sure we do not test the agent */
unsetenv("SSH_AUTH_SOCK");
cwd = torture_get_current_working_dir();
assert_non_null(cwd);
tss->cwd = cwd;
s = tss->state;
assert_non_null(s);
s->ssh.session = ssh_new();
assert_non_null(s->ssh.session);
rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity);
assert_ssh_return_code(s->ssh.session, rc);
rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER);
assert_ssh_return_code(s->ssh.session, rc);
rc = ssh_options_set(s->ssh.session,
SSH_OPTIONS_USER,
TORTURE_SSH_USER_ALICE);
assert_int_equal(rc, SSH_OK);
/* 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 test_server_st *tss = *state;
struct torture_state *s = NULL;
int rc = 0;
assert_non_null(tss);
s = tss->state;
assert_non_null(s);
ssh_disconnect(s->ssh.session);
ssh_free(s->ssh.session);
rc = torture_change_dir(tss->cwd);
assert_int_equal(rc, 0);
SAFE_FREE(tss->cwd);
return 0;
}
static void
torture_gssapi_server_key_exchange_null(void **state)
{
struct test_server_st *tss = *state;
struct torture_state *s = NULL;
ssh_session session;
int rc;
bool t = true;
/* Skip test if in FIPS mode */
if (ssh_fips_mode()) {
skip();
}
assert_non_null(tss);
s = tss->state;
assert_non_null(s);
session = s->ssh.session;
assert_non_null(session);
/* Valid */
torture_setup_kdc_server(
(void **)&s,
"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_ssh_return_code(s->ssh.session, rc);
assert_string_equal(session->current_crypto->kex_methods[SSH_HOSTKEYS], "null");
torture_teardown_kdc_server((void **)&s);
}
int
torture_run_tests(void)
{
int rc;
struct CMUnitTest tests[] = {
cmocka_unit_test_setup_teardown(torture_gssapi_server_key_exchange_null,
session_setup,
session_teardown),
};
ssh_init();
torture_filter_tests(tests);
rc = cmocka_run_group_tests(tests,
setup_default_server,
teardown_default_server);
ssh_finalize();
/* pthread_exit() won't return anything so error should be returned prior */
if (rc != 0) {
return rc;
}
/* Required for freeing memory allocated by GSSAPI */
pthread_exit(NULL);
}

View File

@@ -29,6 +29,9 @@ int main(int argc, char **argv)
const char *hostkeys = NULL;
const char *kex = NULL;
int rc = 1;
#ifdef WITH_GSSAPI
bool t = true;
#endif /* WITH_GSSAPI */
bool process_config = false;
@@ -75,10 +78,12 @@ int main(int argc, char **argv)
goto out;
}
rc = ssh_options_set(session, SSH_OPTIONS_GSSAPI_KEY_EXCHANGE, "gss-group14-sha256-");
#ifdef WITH_GSSAPI
rc = ssh_options_set(session, SSH_OPTIONS_GSSAPI_KEY_EXCHANGE, &t);
if (rc < 0) {
goto out;
}
#endif /* WITH_GSSAPI */
rc = ssh_connect(session);
if (rc != SSH_OK) {

View File

@@ -819,9 +819,9 @@ torture_setup_create_sshd_config(void **state, bool pam, bool second_sshd)
"Port 22\n"
"ListenAddress %s\n"
"ListenAddress %s\n"
"HostKey %s\n" /* ed25519 HostKey */
"HostKey %s\n" /* RSA HostKey */
"HostKey %s\n" /* ECDSA HostKey */
"%s %s\n" /* ed25519 HostKey */
"%s %s\n" /* RSA HostKey */
"%s %s\n" /* ECDSA HostKey */
"\n"
"TrustedUserCAKeys %s\n"
"\n"
@@ -860,8 +860,8 @@ torture_setup_create_sshd_config(void **state, bool pam, bool second_sshd)
"Port 22\n"
"ListenAddress %s\n"
"ListenAddress %s\n"
"HostKey %s\n" /* RSA HostKey */
"HostKey %s\n" /* ECDSA HostKey */
"%s %s\n" /* RSA HostKey */
"%s %s\n" /* ECDSA HostKey */
"\n"
"TrustedUserCAKeys %s\n" /* Trusted CA */
"\n"
@@ -977,16 +977,6 @@ 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) {
@@ -1009,8 +999,22 @@ torture_setup_create_sshd_config(void **state, bool pam, bool second_sshd)
fips_config_string,
second_sshd ? TORTURE_SSHD_SRV1_IPV4 : TORTURE_SSHD_SRV_IPV4,
second_sshd ? TORTURE_SSHD_SRV1_IPV6 : TORTURE_SSHD_SRV_IPV6,
rsa_hostkey,
ecdsa_hostkey,
"HostKey", rsa_hostkey,
"HostKey", ecdsa_hostkey,
trusted_ca_pubkey,
sftp_server,
usepam,
additional_config,
second_sshd ? s->srv1_pidfile : s->srv_pidfile);
} else if (s->disable_hostkeys) {
snprintf(sshd_config,
sizeof(sshd_config),
config_string,
second_sshd ? TORTURE_SSHD_SRV1_IPV4 : TORTURE_SSHD_SRV_IPV4,
second_sshd ? TORTURE_SSHD_SRV1_IPV6 : TORTURE_SSHD_SRV_IPV6,
"", "",
"", "",
"", "",
trusted_ca_pubkey,
sftp_server,
usepam,
@@ -1022,9 +1026,9 @@ torture_setup_create_sshd_config(void **state, bool pam, bool second_sshd)
config_string,
second_sshd ? TORTURE_SSHD_SRV1_IPV4 : TORTURE_SSHD_SRV_IPV4,
second_sshd ? TORTURE_SSHD_SRV1_IPV6 : TORTURE_SSHD_SRV_IPV6,
ed25519_hostkey,
rsa_hostkey,
ecdsa_hostkey,
"HostKey", ed25519_hostkey,
"HostKey", rsa_hostkey,
"HostKey", ecdsa_hostkey,
trusted_ca_pubkey,
sftp_server,
usepam,