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

@@ -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;