mirror of
https://git.libssh.org/projects/libssh.git
synced 2025-07-31 00:03:07 +03:00
knownhosts: Introduced ssh_known_hosts_get_algorithms_names()
The added internal function obtain a newly allocated string containing a list of the signature types that can be generated by the keys present in the known_hosts files, separated by commas. Signed-off-by: Anderson Toshiyuki Sasaki <ansasaki@redhat.com> Reviewed-by: Jakub Jelen <jjelen@redhat.com>
This commit is contained in:
@ -23,6 +23,7 @@
|
|||||||
#define SSH_KNOWNHOSTS_H_
|
#define SSH_KNOWNHOSTS_H_
|
||||||
|
|
||||||
struct ssh_list *ssh_known_hosts_get_algorithms(ssh_session session);
|
struct ssh_list *ssh_known_hosts_get_algorithms(ssh_session session);
|
||||||
|
char *ssh_known_hosts_get_algorithms_names(ssh_session session);
|
||||||
enum ssh_known_hosts_e
|
enum ssh_known_hosts_e
|
||||||
ssh_session_get_known_hosts_entry_file(ssh_session session,
|
ssh_session_get_known_hosts_entry_file(ssh_session session,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
|
141
src/knownhosts.c
141
src/knownhosts.c
@ -42,6 +42,7 @@
|
|||||||
#include "libssh/pki.h"
|
#include "libssh/pki.h"
|
||||||
#include "libssh/dh.h"
|
#include "libssh/dh.h"
|
||||||
#include "libssh/knownhosts.h"
|
#include "libssh/knownhosts.h"
|
||||||
|
#include "libssh/token.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @addtogroup libssh_session
|
* @addtogroup libssh_session
|
||||||
@ -451,6 +452,146 @@ error:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*
|
||||||
|
* @brief Returns a static string containing a list of the signature types the
|
||||||
|
* given key type can generate.
|
||||||
|
*
|
||||||
|
* @returns A static cstring containing the signature types the key is able to
|
||||||
|
* generate separated by commas; NULL in case of error
|
||||||
|
*/
|
||||||
|
static const char *ssh_known_host_sigs_from_hostkey_type(enum ssh_keytypes_e type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case SSH_KEYTYPE_RSA:
|
||||||
|
return "rsa-sha2-512,rsa-sha2-256,ssh-rsa";
|
||||||
|
case SSH_KEYTYPE_ED25519:
|
||||||
|
return "ssh-ed25519";
|
||||||
|
#ifdef HAVE_DSA
|
||||||
|
case SSH_KEYTYPE_DSS:
|
||||||
|
return "ssh-dss";
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_ECDH
|
||||||
|
case SSH_KEYTYPE_ECDSA_P256:
|
||||||
|
return "ecdsa-sha2-nistp256";
|
||||||
|
case SSH_KEYTYPE_ECDSA_P384:
|
||||||
|
return "ecdsa-sha2-nistp384";
|
||||||
|
case SSH_KEYTYPE_ECDSA_P521:
|
||||||
|
return "ecdsa-sha2-nistp521";
|
||||||
|
#endif
|
||||||
|
case SSH_KEYTYPE_UNKNOWN:
|
||||||
|
default:
|
||||||
|
SSH_LOG(SSH_LOG_WARN, "The given type %d is not a base private key type "
|
||||||
|
"or is unsupported", type);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* @brief Get the host keys algorithms identifiers from the known_hosts files
|
||||||
|
*
|
||||||
|
* This expands the signatures types that can be generated from the keys types
|
||||||
|
* present in the known_hosts files
|
||||||
|
*
|
||||||
|
* @param[in] session The ssh session to use.
|
||||||
|
*
|
||||||
|
* @return A newly allocated cstring containing a list of signature algorithms
|
||||||
|
* that can be generated by the host using the keys listed in the known_hosts
|
||||||
|
* files, NULL on error.
|
||||||
|
*/
|
||||||
|
char *ssh_known_hosts_get_algorithms_names(ssh_session session)
|
||||||
|
{
|
||||||
|
char methods_buffer[256 + 1] = {0};
|
||||||
|
struct ssh_list *entry_list = NULL;
|
||||||
|
struct ssh_iterator *it = NULL;
|
||||||
|
char *host_port = NULL;
|
||||||
|
size_t count;
|
||||||
|
bool needcomma = false;
|
||||||
|
char *names;
|
||||||
|
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (session->opts.knownhosts == NULL ||
|
||||||
|
session->opts.global_knownhosts == NULL) {
|
||||||
|
if (ssh_options_apply(session) < 0) {
|
||||||
|
ssh_set_error(session,
|
||||||
|
SSH_REQUEST_DENIED,
|
||||||
|
"Can't find a known_hosts file");
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
host_port = ssh_session_get_host_port(session);
|
||||||
|
if (host_port == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = ssh_known_hosts_read_entries(host_port,
|
||||||
|
session->opts.knownhosts,
|
||||||
|
&entry_list);
|
||||||
|
if (rc != 0) {
|
||||||
|
SAFE_FREE(host_port);
|
||||||
|
ssh_list_free(entry_list);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = ssh_known_hosts_read_entries(host_port,
|
||||||
|
session->opts.global_knownhosts,
|
||||||
|
&entry_list);
|
||||||
|
SAFE_FREE(host_port);
|
||||||
|
if (rc != 0) {
|
||||||
|
ssh_list_free(entry_list);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry_list == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
count = ssh_list_count(entry_list);
|
||||||
|
if (count == 0) {
|
||||||
|
ssh_list_free(entry_list);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (it = ssh_list_get_iterator(entry_list);
|
||||||
|
it != NULL;
|
||||||
|
it = ssh_list_get_iterator(entry_list))
|
||||||
|
{
|
||||||
|
struct ssh_knownhosts_entry *entry = NULL;
|
||||||
|
const char *algo = NULL;
|
||||||
|
|
||||||
|
entry = ssh_iterator_value(struct ssh_knownhosts_entry *, it);
|
||||||
|
algo = ssh_known_host_sigs_from_hostkey_type(entry->publickey->type);
|
||||||
|
if (algo == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needcomma) {
|
||||||
|
strncat(methods_buffer,
|
||||||
|
",",
|
||||||
|
sizeof(methods_buffer) - strlen(methods_buffer) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
strncat(methods_buffer,
|
||||||
|
algo,
|
||||||
|
sizeof(methods_buffer) - strlen(methods_buffer) - 1);
|
||||||
|
needcomma = true;
|
||||||
|
|
||||||
|
ssh_knownhosts_entry_free(entry);
|
||||||
|
ssh_list_remove(entry_list, it);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssh_list_free(entry_list);
|
||||||
|
|
||||||
|
names = ssh_remove_duplicates(methods_buffer);
|
||||||
|
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Parse a line from a known_hosts entry into a structure
|
* @brief Parse a line from a known_hosts entry into a structure
|
||||||
*
|
*
|
||||||
|
@ -369,6 +369,31 @@ static void torture_knownhosts_read_file(void **state)
|
|||||||
ssh_list_free(entry_list);
|
ssh_list_free(entry_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void torture_knownhosts_get_algorithms_names(void **state)
|
||||||
|
{
|
||||||
|
const char *knownhosts_file = *state;
|
||||||
|
ssh_session session;
|
||||||
|
const char *expect = "ssh-ed25519,rsa-sha2-512,rsa-sha2-256,ssh-rsa";
|
||||||
|
char *names = NULL;
|
||||||
|
bool process_config = false;
|
||||||
|
|
||||||
|
session = ssh_new();
|
||||||
|
assert_non_null(session);
|
||||||
|
|
||||||
|
/* This makes sure the global configuration file is not processed */
|
||||||
|
ssh_options_set(session, SSH_OPTIONS_PROCESS_CONFIG, &process_config);
|
||||||
|
|
||||||
|
ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
|
||||||
|
ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS, knownhosts_file);
|
||||||
|
|
||||||
|
names = ssh_known_hosts_get_algorithms_names(session);
|
||||||
|
assert_non_null(names);
|
||||||
|
assert_string_equal(names, expect);
|
||||||
|
|
||||||
|
SAFE_FREE(names);
|
||||||
|
ssh_free(session);
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef _WIN32 /* There is no /dev/null on Windows */
|
#ifndef _WIN32 /* There is no /dev/null on Windows */
|
||||||
static void torture_knownhosts_host_exists(void **state)
|
static void torture_knownhosts_host_exists(void **state)
|
||||||
{
|
{
|
||||||
@ -510,6 +535,9 @@ int torture_run_tests(void) {
|
|||||||
cmocka_unit_test_setup_teardown(torture_knownhosts_read_file,
|
cmocka_unit_test_setup_teardown(torture_knownhosts_read_file,
|
||||||
setup_knownhosts_file_duplicate,
|
setup_knownhosts_file_duplicate,
|
||||||
teardown_knownhosts_file),
|
teardown_knownhosts_file),
|
||||||
|
cmocka_unit_test_setup_teardown(torture_knownhosts_get_algorithms_names,
|
||||||
|
setup_knownhosts_file,
|
||||||
|
teardown_knownhosts_file),
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
cmocka_unit_test_setup_teardown(torture_knownhosts_host_exists,
|
cmocka_unit_test_setup_teardown(torture_knownhosts_host_exists,
|
||||||
setup_knownhosts_file,
|
setup_knownhosts_file,
|
||||||
|
Reference in New Issue
Block a user