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;
|
int toaccept;
|
||||||
bool config_processed;
|
bool config_processed;
|
||||||
char *config_dir;
|
char *config_dir;
|
||||||
|
char *pubkey_accepted_key_types;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ssh_poll_handle_struct *ssh_bind_get_poll(struct ssh_bind_struct
|
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_C_S,
|
||||||
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,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct ssh_bind_struct* ssh_bind;
|
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/buffer.h"
|
||||||
#include "libssh/socket.h"
|
#include "libssh/socket.h"
|
||||||
#include "libssh/session.h"
|
#include "libssh/session.h"
|
||||||
|
#include "libssh/token.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @addtogroup libssh_server
|
* @addtogroup libssh_server
|
||||||
@ -402,6 +403,7 @@ void ssh_bind_free(ssh_bind sshbind){
|
|||||||
SAFE_FREE(sshbind->banner);
|
SAFE_FREE(sshbind->banner);
|
||||||
SAFE_FREE(sshbind->bindaddr);
|
SAFE_FREE(sshbind->bindaddr);
|
||||||
SAFE_FREE(sshbind->config_dir);
|
SAFE_FREE(sshbind->config_dir);
|
||||||
|
SAFE_FREE(sshbind->pubkey_accepted_key_types);
|
||||||
|
|
||||||
SAFE_FREE(sshbind->dsakey);
|
SAFE_FREE(sshbind->dsakey);
|
||||||
SAFE_FREE(sshbind->rsakey);
|
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;
|
session->common.log_verbosity = sshbind->common.log_verbosity;
|
||||||
if(sshbind->banner != NULL)
|
if(sshbind->banner != NULL)
|
||||||
session->opts.custombanner = strdup(sshbind->banner);
|
session->opts.custombanner = strdup(sshbind->banner);
|
||||||
|
@ -868,11 +868,28 @@ SSH_PACKET_CALLBACK(ssh_packet_userauth_request){
|
|||||||
msg->auth_request.pubkey,
|
msg->auth_request.pubkey,
|
||||||
&sig);
|
&sig);
|
||||||
if (rc == SSH_OK) {
|
if (rc == SSH_OK) {
|
||||||
rc = ssh_pki_signature_verify(session,
|
/* Check if the signature from client matches server preferences */
|
||||||
sig,
|
if (session->opts.pubkey_accepted_types) {
|
||||||
msg->auth_request.pubkey,
|
if (!ssh_match_group(session->opts.pubkey_accepted_types,
|
||||||
ssh_buffer_get(digest),
|
sig->type_c))
|
||||||
ssh_buffer_get_len(digest));
|
{
|
||||||
|
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_string_free(sig_blob);
|
||||||
ssh_buffer_free(digest);
|
ssh_buffer_free(digest);
|
||||||
|
@ -1608,6 +1608,10 @@ static int ssh_bind_set_algo(ssh_bind sshbind,
|
|||||||
* paths of configuration files to
|
* paths of configuration files to
|
||||||
* ssh_bind_options_parse_config().
|
* 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
|
* @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.
|
||||||
@ -1912,6 +1916,24 @@ int ssh_bind_options_set(ssh_bind sshbind, enum ssh_bind_options_e type,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
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:
|
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;
|
||||||
|
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;
|
const char *hostkey_algorithms;
|
||||||
|
|
||||||
SSH_LOG(SSH_LOG_PACKET, "Sending SSH_MSG_EXT_INFO");
|
SSH_LOG(SSH_LOG_PACKET, "Sending SSH_MSG_EXT_INFO");
|
||||||
/*
|
|
||||||
* We can list here all the default hostkey methods, since
|
if (session->opts.pubkey_accepted_types) {
|
||||||
* they already contain the SHA2 extension algorithms
|
hostkey_algorithms = session->opts.pubkey_accepted_types;
|
||||||
*/
|
} else {
|
||||||
hostkey_algorithms = ssh_kex_get_default_methods(SSH_HOSTKEYS);
|
/* 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,
|
rc = ssh_buffer_pack(session->out_buffer,
|
||||||
"bdss",
|
"bdss",
|
||||||
SSH2_MSG_EXT_INFO,
|
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);
|
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 */
|
#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_copy, setup, teardown),
|
||||||
cmocka_unit_test_setup_teardown(torture_options_config_host, setup, teardown),
|
cmocka_unit_test_setup_teardown(torture_options_config_host, setup, teardown),
|
||||||
cmocka_unit_test_setup_teardown(torture_options_config_match,
|
cmocka_unit_test_setup_teardown(torture_options_config_match,
|
||||||
setup, teardown)
|
setup, teardown),
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef WITH_SERVER
|
#ifdef WITH_SERVER
|
||||||
@ -1428,6 +1482,8 @@ int torture_run_tests(void) {
|
|||||||
sshbind_setup, sshbind_teardown),
|
sshbind_setup, sshbind_teardown),
|
||||||
cmocka_unit_test_setup_teardown(torture_bind_options_config_dir,
|
cmocka_unit_test_setup_teardown(torture_bind_options_config_dir,
|
||||||
sshbind_setup, sshbind_teardown),
|
sshbind_setup, sshbind_teardown),
|
||||||
|
cmocka_unit_test_setup_teardown(torture_bind_options_set_pubkey_accepted_key_types,
|
||||||
|
sshbind_setup, sshbind_teardown),
|
||||||
};
|
};
|
||||||
#endif /* WITH_SERVER */
|
#endif /* WITH_SERVER */
|
||||||
|
|
||||||
|
Загрузка…
x
Ссылка в новой задаче
Block a user