options: Add option to set server accepted pubkey types
The added option SSH_BIND_OPTIONS_PUBKEY_ACCEPTED_KEY_TYPES allows restricting the allowed public key types accepted by the server for authentication. Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com> Reviewed-by: Jakub Jelen <jjelen@redhat.com>
Этот коммит содержится в:
родитель
bc95a51710
Коммит
f4363f5655
@ -48,6 +48,7 @@ struct ssh_bind_struct {
|
||||
int toaccept;
|
||||
bool config_processed;
|
||||
char *config_dir;
|
||||
char *pubkey_accepted_key_types;
|
||||
};
|
||||
|
||||
struct ssh_poll_handle_struct *ssh_bind_get_poll(struct ssh_bind_struct
|
||||
|
@ -53,6 +53,7 @@ enum ssh_bind_options_e {
|
||||
SSH_BIND_OPTIONS_HMAC_C_S,
|
||||
SSH_BIND_OPTIONS_HMAC_S_C,
|
||||
SSH_BIND_OPTIONS_CONFIG_DIR,
|
||||
SSH_BIND_OPTIONS_PUBKEY_ACCEPTED_KEY_TYPES,
|
||||
};
|
||||
|
||||
typedef struct ssh_bind_struct* ssh_bind;
|
||||
|
25
src/bind.c
25
src/bind.c
@ -38,6 +38,7 @@
|
||||
#include "libssh/buffer.h"
|
||||
#include "libssh/socket.h"
|
||||
#include "libssh/session.h"
|
||||
#include "libssh/token.h"
|
||||
|
||||
/**
|
||||
* @addtogroup libssh_server
|
||||
@ -402,6 +403,7 @@ void ssh_bind_free(ssh_bind sshbind){
|
||||
SAFE_FREE(sshbind->banner);
|
||||
SAFE_FREE(sshbind->bindaddr);
|
||||
SAFE_FREE(sshbind->config_dir);
|
||||
SAFE_FREE(sshbind->pubkey_accepted_key_types);
|
||||
|
||||
SAFE_FREE(sshbind->dsakey);
|
||||
SAFE_FREE(sshbind->rsakey);
|
||||
@ -456,6 +458,29 @@ int ssh_bind_accept_fd(ssh_bind sshbind, ssh_session session, socket_t fd){
|
||||
}
|
||||
}
|
||||
|
||||
if (sshbind->pubkey_accepted_key_types != NULL) {
|
||||
if (session->opts.pubkey_accepted_types == NULL) {
|
||||
session->opts.pubkey_accepted_types = strdup(sshbind->pubkey_accepted_key_types);
|
||||
if (session->opts.pubkey_accepted_types == NULL) {
|
||||
ssh_set_error_oom(sshbind);
|
||||
return SSH_ERROR;
|
||||
}
|
||||
} else {
|
||||
char *p;
|
||||
/* If something was set to the session prior to calling this
|
||||
* function, keep only what is allowed by the options set in
|
||||
* sshbind */
|
||||
p = ssh_find_all_matching(sshbind->pubkey_accepted_key_types,
|
||||
session->opts.pubkey_accepted_types);
|
||||
if (p == NULL) {
|
||||
return SSH_ERROR;
|
||||
}
|
||||
|
||||
SAFE_FREE(session->opts.pubkey_accepted_types);
|
||||
session->opts.pubkey_accepted_types = p;
|
||||
}
|
||||
}
|
||||
|
||||
session->common.log_verbosity = sshbind->common.log_verbosity;
|
||||
if(sshbind->banner != NULL)
|
||||
session->opts.custombanner = strdup(sshbind->banner);
|
||||
|
@ -868,11 +868,28 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_request){
|
||||
msg->auth_request.pubkey,
|
||||
&sig);
|
||||
if (rc == SSH_OK) {
|
||||
rc = ssh_pki_signature_verify(session,
|
||||
sig,
|
||||
msg->auth_request.pubkey,
|
||||
ssh_buffer_get(digest),
|
||||
ssh_buffer_get_len(digest));
|
||||
/* Check if the signature from client matches server preferences */
|
||||
if (session->opts.pubkey_accepted_types) {
|
||||
if (!ssh_match_group(session->opts.pubkey_accepted_types,
|
||||
sig->type_c))
|
||||
{
|
||||
ssh_set_error(session,
|
||||
SSH_FATAL,
|
||||
"Public key from client (%s) doesn't match server "
|
||||
"preference (%s)",
|
||||
sig->type_c,
|
||||
session->opts.pubkey_accepted_types);
|
||||
rc = SSH_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (rc == SSH_OK) {
|
||||
rc = ssh_pki_signature_verify(session,
|
||||
sig,
|
||||
msg->auth_request.pubkey,
|
||||
ssh_buffer_get(digest),
|
||||
ssh_buffer_get_len(digest));
|
||||
}
|
||||
}
|
||||
ssh_string_free(sig_blob);
|
||||
ssh_buffer_free(digest);
|
||||
|
@ -1608,6 +1608,10 @@ static int ssh_bind_set_algo(ssh_bind sshbind,
|
||||
* paths of configuration files to
|
||||
* ssh_bind_options_parse_config().
|
||||
*
|
||||
* - SSH_BIND_OPTIONS_PUBKEY_ACCEPTED_KEY_TYPES:
|
||||
* Set the public key algorithm accepted by the server
|
||||
* (const char *, comma-separated list).
|
||||
*
|
||||
* @param value The value to set. This is a generic pointer and the
|
||||
* datatype which should be used is described at the
|
||||
* corresponding value of type above.
|
||||
@ -1912,6 +1916,24 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SSH_BIND_OPTIONS_PUBKEY_ACCEPTED_KEY_TYPES:
|
||||
v = value;
|
||||
if (v == NULL || v[0] == '\0') {
|
||||
ssh_set_error_invalid(sshbind);
|
||||
return -1;
|
||||
} else {
|
||||
p = ssh_keep_known_algos(SSH_HOSTKEYS, v);
|
||||
if (p == NULL) {
|
||||
ssh_set_error(sshbind, SSH_REQUEST_DENIED,
|
||||
"Setting method: no known public key algorithm (%s)",
|
||||
v);
|
||||
return -1;
|
||||
}
|
||||
|
||||
SAFE_FREE(sshbind->pubkey_accepted_key_types);
|
||||
sshbind->pubkey_accepted_key_types = p;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ssh_set_error(sshbind, SSH_REQUEST_DENIED, "Unknown ssh option %d", type);
|
||||
return -1;
|
||||
|
13
src/server.c
13
src/server.c
@ -180,11 +180,14 @@ static int ssh_server_send_extensions(ssh_session session) {
|
||||
const char *hostkey_algorithms;
|
||||
|
||||
SSH_LOG(SSH_LOG_PACKET, "Sending SSH_MSG_EXT_INFO");
|
||||
/*
|
||||
* We can list here all the default hostkey methods, since
|
||||
* they already contain the SHA2 extension algorithms
|
||||
*/
|
||||
hostkey_algorithms = ssh_kex_get_default_methods(SSH_HOSTKEYS);
|
||||
|
||||
if (session->opts.pubkey_accepted_types) {
|
||||
hostkey_algorithms = session->opts.pubkey_accepted_types;
|
||||
} else {
|
||||
/* There are no restrictions to the accepted public keys */
|
||||
hostkey_algorithms = ssh_kex_get_default_methods(SSH_HOSTKEYS);
|
||||
}
|
||||
|
||||
rc = ssh_buffer_pack(session->out_buffer,
|
||||
"bdss",
|
||||
SSH2_MSG_EXT_INFO,
|
||||
|
@ -1358,6 +1358,60 @@ static void torture_bind_options_config_dir(void **state)
|
||||
assert_string_equal(bind->config_dir, replacement_dir);
|
||||
}
|
||||
|
||||
static void torture_bind_options_set_pubkey_accepted_key_types(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_PUBKEY_ACCEPTED_KEY_TYPES,
|
||||
"ssh-ed25519,ecdsa-sha2-nistp384,ssh-rsa");
|
||||
assert_int_equal(rc, 0);
|
||||
assert_non_null(bind->pubkey_accepted_key_types);
|
||||
assert_string_equal(bind->pubkey_accepted_key_types,
|
||||
"ssh-ed25519,ecdsa-sha2-nistp384,ssh-rsa");
|
||||
|
||||
SAFE_FREE(bind->pubkey_accepted_key_types);
|
||||
|
||||
/* Test with some unknown type */
|
||||
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_PUBKEY_ACCEPTED_KEY_TYPES,
|
||||
"ssh-ed25519,ecdsa-sha2-nistp384,unknown-type,ssh-rsa");
|
||||
assert_int_equal(rc, 0);
|
||||
assert_non_null(bind->pubkey_accepted_key_types);
|
||||
assert_string_equal(bind->pubkey_accepted_key_types,
|
||||
"ssh-ed25519,ecdsa-sha2-nistp384,ssh-rsa");
|
||||
|
||||
SAFE_FREE(bind->pubkey_accepted_key_types);
|
||||
|
||||
/* Test with only unknown type */
|
||||
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_PUBKEY_ACCEPTED_KEY_TYPES,
|
||||
"unknown-type");
|
||||
assert_int_equal(rc, -1);
|
||||
assert_null(bind->pubkey_accepted_key_types);
|
||||
|
||||
/* Test with something set and then try unknown type */
|
||||
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_PUBKEY_ACCEPTED_KEY_TYPES,
|
||||
"ssh-ed25519,ecdsa-sha2-nistp384,ssh-rsa");
|
||||
assert_int_equal(rc, 0);
|
||||
assert_non_null(bind->pubkey_accepted_key_types);
|
||||
assert_string_equal(bind->pubkey_accepted_key_types,
|
||||
"ssh-ed25519,ecdsa-sha2-nistp384,ssh-rsa");
|
||||
rc = ssh_bind_options_set(bind, SSH_BIND_OPTIONS_PUBKEY_ACCEPTED_KEY_TYPES,
|
||||
"unknown-type");
|
||||
assert_int_equal(rc, -1);
|
||||
|
||||
/* Check that nothing changed */
|
||||
assert_non_null(bind->pubkey_accepted_key_types);
|
||||
assert_string_equal(bind->pubkey_accepted_key_types,
|
||||
"ssh-ed25519,ecdsa-sha2-nistp384,ssh-rsa");
|
||||
}
|
||||
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
@ -1387,7 +1441,7 @@ int torture_run_tests(void) {
|
||||
cmocka_unit_test_setup_teardown(torture_options_copy, setup, teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_options_config_host, setup, teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_options_config_match,
|
||||
setup, teardown)
|
||||
setup, teardown),
|
||||
};
|
||||
|
||||
#ifdef WITH_SERVER
|
||||
@ -1428,6 +1482,8 @@ int torture_run_tests(void) {
|
||||
sshbind_setup, sshbind_teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_bind_options_config_dir,
|
||||
sshbind_setup, sshbind_teardown),
|
||||
cmocka_unit_test_setup_teardown(torture_bind_options_set_pubkey_accepted_key_types,
|
||||
sshbind_setup, sshbind_teardown),
|
||||
};
|
||||
#endif /* WITH_SERVER */
|
||||
|
||||
|
Загрузка…
x
Ссылка в новой задаче
Block a user