1
0
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:
Anderson Toshiyuki Sasaki
2019-07-02 13:48:17 +02:00
parent 548753b338
commit 65a38759ca
3 changed files with 170 additions and 0 deletions

View File

@ -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,

View File

@ -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
* *

View File

@ -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,