1
0
mirror of https://git.libssh.org/projects/libssh.git synced 2025-11-29 01:03:57 +03:00

options: Added an option to set server HostKey algorithms

The added option SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS allows restricting
the signature algorithms to offer to the client for host authentication.
The list set is used as a filter of allowed algorithms.

First a list of possible signature algorithms to offer is created from
the keys set and then such list is filtered against the allowed
algorithms.

Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com>
Reviewed-by: Jakub Jelen <jjelen@redhat.com>
This commit is contained in:
Anderson Toshiyuki Sasaki
2019-05-17 11:38:43 +02:00
committed by Andreas Schneider
parent 8f6e6f774e
commit 250a0be0f9
4 changed files with 161 additions and 64 deletions

View File

@@ -54,6 +54,7 @@ enum ssh_bind_options_e {
SSH_BIND_OPTIONS_HMAC_S_C, SSH_BIND_OPTIONS_HMAC_S_C,
SSH_BIND_OPTIONS_CONFIG_DIR, SSH_BIND_OPTIONS_CONFIG_DIR,
SSH_BIND_OPTIONS_PUBKEY_ACCEPTED_KEY_TYPES, SSH_BIND_OPTIONS_PUBKEY_ACCEPTED_KEY_TYPES,
SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS,
}; };
typedef struct ssh_bind_struct* ssh_bind; typedef struct ssh_bind_struct* ssh_bind;

View File

@@ -1612,6 +1612,15 @@ static int ssh_bind_set_algo(ssh_bind sshbind,
* Set the public key algorithm accepted by the server * Set the public key algorithm accepted by the server
* (const char *, comma-separated list). * (const char *, comma-separated list).
* *
* - SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS:
* Set the list of allowed hostkey signatures algorithms
* to offer to the client, ordered by preference. This
* list is used as a filter when creating the list of
* algorithms to offer to the client: first the list of
* possible algorithms is created from the list of keys
* set and then filtered against this list.
* (const char *, comma-separated list).
*
* @param value The value to set. This is a generic pointer and the * @param value The value to set. This is a generic pointer and the
* datatype which should be used is described at the * datatype which should be used is described at the
* corresponding value of type above. * corresponding value of type above.
@@ -1934,6 +1943,18 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
sshbind->pubkey_accepted_key_types = p; sshbind->pubkey_accepted_key_types = p;
} }
break; break;
case SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS:
v = value;
if (v == NULL || v[0] == '\0') {
ssh_set_error_invalid(sshbind);
return -1;
} else {
rc = ssh_bind_set_algo(sshbind, SSH_HOSTKEYS, v);
if (rc < 0) {
return -1;
}
}
break;
default: default:
ssh_set_error(sshbind, SSH_REQUEST_DENIED, "Unknown ssh option %d", type); ssh_set_error(sshbind, SSH_REQUEST_DENIED, "Unknown ssh option %d", type);
return -1; return -1;

View File

@@ -59,6 +59,7 @@
#include "libssh/messages.h" #include "libssh/messages.h"
#include "libssh/options.h" #include "libssh/options.h"
#include "libssh/curve25519.h" #include "libssh/curve25519.h"
#include "libssh/token.h"
#define set_status(session, status) do {\ #define set_status(session, status) do {\
if (session->common.callbacks && session->common.callbacks->connect_status_function) \ if (session->common.callbacks && session->common.callbacks->connect_status_function) \
@@ -82,82 +83,99 @@
int server_set_kex(ssh_session session) int server_set_kex(ssh_session session)
{ {
struct ssh_kex_struct *server = &session->next_crypto->server_kex; struct ssh_kex_struct *server = &session->next_crypto->server_kex;
int i, j, rc; int i, j, rc;
const char *wanted; const char *wanted, *allowed;
char hostkeys[128] = {0}; char *kept;
enum ssh_keytypes_e keytype; char hostkeys[128] = {0};
size_t len; enum ssh_keytypes_e keytype;
int ok; size_t len;
int ok;
ZERO_STRUCTP(server); ZERO_STRUCTP(server);
ok = ssh_get_random(server->cookie, 16, 0); ok = ssh_get_random(server->cookie, 16, 0);
if (!ok) { if (!ok) {
ssh_set_error(session, SSH_FATAL, "PRNG error"); ssh_set_error(session, SSH_FATAL, "PRNG error");
return -1; return -1;
} }
if (session->srv.ed25519_key != NULL) { if (session->srv.ed25519_key != NULL) {
snprintf(hostkeys, snprintf(hostkeys,
sizeof(hostkeys), sizeof(hostkeys),
"%s", "%s",
ssh_key_type_to_char(ssh_key_type(session->srv.ed25519_key))); ssh_key_type_to_char(ssh_key_type(session->srv.ed25519_key)));
} }
#ifdef HAVE_ECC #ifdef HAVE_ECC
if (session->srv.ecdsa_key != NULL) { if (session->srv.ecdsa_key != NULL) {
len = strlen(hostkeys); len = strlen(hostkeys);
snprintf(hostkeys + len, sizeof(hostkeys) - len, snprintf(hostkeys + len, sizeof(hostkeys) - len,
",%s", session->srv.ecdsa_key->type_c); ",%s", session->srv.ecdsa_key->type_c);
} }
#endif #endif
#ifdef HAVE_DSA #ifdef HAVE_DSA
if (session->srv.dsa_key != NULL) { if (session->srv.dsa_key != NULL) {
len = strlen(hostkeys); len = strlen(hostkeys);
keytype = ssh_key_type(session->srv.dsa_key); keytype = ssh_key_type(session->srv.dsa_key);
snprintf(hostkeys + len, sizeof(hostkeys) - len, snprintf(hostkeys + len, sizeof(hostkeys) - len,
",%s", ssh_key_type_to_char(keytype)); ",%s", ssh_key_type_to_char(keytype));
} }
#endif #endif
if (session->srv.rsa_key != NULL) { if (session->srv.rsa_key != NULL) {
/* We support also the SHA2 variants */ /* We support also the SHA2 variants */
len = strlen(hostkeys); len = strlen(hostkeys);
snprintf(hostkeys + len, sizeof(hostkeys) - len, snprintf(hostkeys + len, sizeof(hostkeys) - len,
",rsa-sha2-512,rsa-sha2-256"); ",rsa-sha2-512,rsa-sha2-256");
len = strlen(hostkeys); len = strlen(hostkeys);
keytype = ssh_key_type(session->srv.rsa_key); keytype = ssh_key_type(session->srv.rsa_key);
snprintf(hostkeys + len, sizeof(hostkeys) - len, snprintf(hostkeys + len, sizeof(hostkeys) - len,
",%s", ssh_key_type_to_char(keytype)); ",%s", ssh_key_type_to_char(keytype));
}
if (strlen(hostkeys) == 0) {
return -1;
}
rc = ssh_options_set_algo(session,
SSH_HOSTKEYS,
hostkeys[0] == ',' ? hostkeys + 1 : hostkeys);
if (rc < 0) {
return -1;
}
for (i = 0; i < 10; i++) {
if ((wanted = session->opts.wanted_methods[i]) == NULL) {
wanted = ssh_kex_get_supported_method(i);
} }
server->methods[i] = strdup(wanted);
if (server->methods[i] == NULL) {
for (j = 0; j < i; j++) {
SAFE_FREE(server->methods[j]);
}
return -1;
}
}
return 0; if (strlen(hostkeys) == 0) {
return -1;
}
if (session->opts.wanted_methods[SSH_HOSTKEYS]) {
allowed = session->opts.wanted_methods[SSH_HOSTKEYS];
} else {
allowed = ssh_kex_get_supported_method(SSH_HOSTKEYS);
}
/* 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);
SAFE_FREE(kept);
if (rc < 0) {
return -1;
}
for (i = 0; i < 10; i++) {
if ((wanted = session->opts.wanted_methods[i]) == NULL) {
wanted = ssh_kex_get_supported_method(i);
}
server->methods[i] = strdup(wanted);
if (server->methods[i] == NULL) {
for (j = 0; j < i; j++) {
SAFE_FREE(server->methods[j]);
}
return -1;
}
}
return 0;
} }
int ssh_server_init_kex(ssh_session session) { int ssh_server_init_kex(ssh_session session) {

View File

@@ -1413,6 +1413,61 @@ static void torture_bind_options_set_pubkey_accepted_key_types(void **state)
"ssh-ed25519,ecdsa-sha2-nistp384,ssh-rsa"); "ssh-ed25519,ecdsa-sha2-nistp384,ssh-rsa");
} }
static void torture_bind_options_set_hostkey_algorithms(void **state)
{
struct bind_st *test_state;
ssh_bind bind;
int rc;
assert_non_null(state);
test_state = *((struct bind_st **)state);
assert_non_null(test_state);
assert_non_null(test_state->bind);
bind = test_state->bind;
/* Test known Pubkey Types */
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS,
"ssh-ed25519,ecdsa-sha2-nistp384,ssh-rsa");
assert_int_equal(rc, 0);
assert_non_null(bind->wanted_methods[SSH_HOSTKEYS]);
assert_string_equal(bind->wanted_methods[SSH_HOSTKEYS],
"ssh-ed25519,ecdsa-sha2-nistp384,ssh-rsa");
SAFE_FREE(bind->wanted_methods[SSH_HOSTKEYS]);
/* Test with some unknown type */
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS,
"ssh-ed25519,ecdsa-sha2-nistp384,unknown-type,ssh-rsa");
assert_int_equal(rc, 0);
assert_non_null(bind->wanted_methods[SSH_HOSTKEYS]);
assert_string_equal(bind->wanted_methods[SSH_HOSTKEYS],
"ssh-ed25519,ecdsa-sha2-nistp384,ssh-rsa");
SAFE_FREE(bind->wanted_methods[SSH_HOSTKEYS]);
/* Test with only unknown type */
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS,
"unknown-type");
assert_int_equal(rc, -1);
assert_null(bind->wanted_methods[SSH_HOSTKEYS]);
/* Test with something set and then try unknown type */
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS,
"ssh-ed25519,ecdsa-sha2-nistp384,ssh-rsa");
assert_int_equal(rc, 0);
assert_non_null(bind->wanted_methods[SSH_HOSTKEYS]);
assert_string_equal(bind->wanted_methods[SSH_HOSTKEYS],
"ssh-ed25519,ecdsa-sha2-nistp384,ssh-rsa");
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_HOSTKEY_ALGORITHMS,
"unknown-type");
assert_int_equal(rc, -1);
/* Check that nothing changed */
assert_non_null(bind->wanted_methods[SSH_HOSTKEYS]);
assert_string_equal(bind->wanted_methods[SSH_HOSTKEYS],
"ssh-ed25519,ecdsa-sha2-nistp384,ssh-rsa");
}
#endif /* WITH_SERVER */ #endif /* WITH_SERVER */
@@ -1484,6 +1539,8 @@ int torture_run_tests(void) {
sshbind_setup, sshbind_teardown), sshbind_setup, sshbind_teardown),
cmocka_unit_test_setup_teardown(torture_bind_options_set_pubkey_accepted_key_types, cmocka_unit_test_setup_teardown(torture_bind_options_set_pubkey_accepted_key_types,
sshbind_setup, sshbind_teardown), sshbind_setup, sshbind_teardown),
cmocka_unit_test_setup_teardown(torture_bind_options_set_hostkey_algorithms,
sshbind_setup, sshbind_teardown),
}; };
#endif /* WITH_SERVER */ #endif /* WITH_SERVER */