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>
(cherry picked from commit 65a38759ca)
This commit is contained in:
Anderson Toshiyuki Sasaki
2019-07-02 13:48:17 +02:00
parent aaa978ad06
commit fa3caa61fd
3 changed files with 170 additions and 0 deletions

View File

@@ -42,6 +42,7 @@
#include "libssh/pki.h"
#include "libssh/dh.h"
#include "libssh/knownhosts.h"
#include "libssh/token.h"
/**
* @addtogroup libssh_session
@@ -451,6 +452,146 @@ error:
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
*