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:
committed by
Andreas Schneider
parent
8f6e6f774e
commit
250a0be0f9
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
146
src/server.c
146
src/server.c
@@ -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) {
|
||||||
|
|||||||
@@ -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 */
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user