1
1

kwonhosts: Add functions to check if servers public key is known

Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
Этот коммит содержится в:
Andreas Schneider 2018-02-03 16:54:58 +01:00
родитель f23dbe6f42
Коммит a209f928d2
3 изменённых файлов: 181 добавлений и 1 удалений

Просмотреть файл

@ -540,9 +540,13 @@ LIBSSH_API enum ssh_known_hosts_e ssh_session_has_known_hosts_entry(ssh_session
LIBSSH_API int ssh_session_export_known_hosts_entry(ssh_session session,
char **pentry_string);
LIBSSH_API int ssh_session_update_known_hosts(ssh_session session);
LIBSSH_API enum ssh_known_hosts_e
ssh_session_get_known_hosts_entry(ssh_session session,
struct ssh_knownhosts_entry **pentry);
LIBSSH_API enum ssh_known_hosts_e ssh_session_is_known_server(ssh_session session);
/* LOGGING */
LIBSSH_API int ssh_set_log_level(int level);
LIBSSH_API int ssh_get_log_level(void);

Просмотреть файл

@ -32,6 +32,7 @@
#include <netinet/in.h>
#include "libssh/priv.h"
#include "libssh/dh.h"
#include "libssh/session.h"
#include "libssh/options.h"
#include "libssh/misc.h"
@ -634,3 +635,158 @@ int ssh_session_update_known_hosts(ssh_session session)
return SSH_OK;
}
static enum ssh_known_hosts_e
ssh_known_hosts_check_server_key(const char *hosts_entry,
const char *filename,
ssh_key server_key,
struct ssh_knownhosts_entry **pentry)
{
struct ssh_list *entry_list = NULL;
struct ssh_iterator *it = NULL;
enum ssh_known_hosts_e found = SSH_KNOWN_HOSTS_UNKNOWN;
int rc;
rc = ssh_known_hosts_read_entries(hosts_entry,
filename,
&entry_list);
if (rc != 0) {
return SSH_KNOWN_HOSTS_NOT_FOUND;
}
it = ssh_list_get_iterator(entry_list);
if (it == NULL) {
ssh_list_free(entry_list);
return SSH_KNOWN_HOSTS_UNKNOWN;
}
for (;it != NULL; it = it->next) {
struct ssh_knownhosts_entry *entry = NULL;
int cmp;
entry = ssh_iterator_value(struct ssh_knownhosts_entry *, it);
cmp = ssh_key_cmp(server_key, entry->publickey, SSH_KEY_CMP_PUBLIC);
if (cmp == 0) {
found = SSH_KNOWN_HOSTS_OK;
if (pentry != NULL) {
*pentry = entry;
ssh_list_remove(entry_list, it);
}
break;
}
if (ssh_key_type(server_key) == ssh_key_type(entry->publickey)) {
found = SSH_KNOWN_HOSTS_CHANGED;
} else {
found = SSH_KNOWN_HOSTS_OTHER;
}
}
for (it = ssh_list_get_iterator(entry_list);
it != NULL;
it = ssh_list_get_iterator(entry_list)) {
struct ssh_knownhosts_entry *entry = NULL;
entry = ssh_iterator_value(struct ssh_knownhosts_entry *, it);
ssh_knownhosts_entry_free(entry);
ssh_list_remove(entry_list, it);
}
ssh_list_free(entry_list);
return found;
}
/**
* @brief Get the known_hosts entry for the current connected session.
*
* @param[in] session The session to validate.
*
* @param[in] pentry A pointer to store the allocated known hosts entry.
*
* @returns SSH_KNOWN_HOSTS_OK: The server is known and has not changed.\n
* SSH_KNOWN_HOSTS_CHANGED: The server key has changed. Either you
* are under attack or the administrator
* changed the key. You HAVE to warn the
* user about a possible attack.\n
* SSH_KNOWN_HOSTS_OTHER: The server gave use a key of a type while
* we had an other type recorded. It is a
* possible attack.\n
* SSH_KNOWN_HOSTS_UNKNOWN: The server is unknown. User should
* confirm the public key hash is correct.\n
* SSH_KNOWN_HOSTS_NOT_FOUND: The known host file does not exist. The
* host is thus unknown. File will be
* created if host key is accepted.\n
* SSH_KNOWN_HOSTS_ERROR: There had been an eror checking the host.
*
* @see ssh_knownhosts_entry_free()
*/
enum ssh_known_hosts_e
ssh_session_get_known_hosts_entry(ssh_session session,
struct ssh_knownhosts_entry **pentry)
{
ssh_key server_pubkey = NULL;
char *host_port = NULL;
enum ssh_known_hosts_e found = SSH_KNOWN_HOSTS_UNKNOWN;
if (session->opts.knownhosts == NULL) {
if (ssh_options_apply(session) < 0) {
ssh_set_error(session,
SSH_REQUEST_DENIED,
"Can't find a known_hosts file");
return SSH_KNOWN_HOSTS_NOT_FOUND;
}
}
server_pubkey = ssh_dh_get_current_server_publickey(session);
if (server_pubkey == NULL) {
ssh_set_error(session,
SSH_FATAL,
"ssh_session_is_known_host called without a "
"server_key!");
return SSH_KNOWN_HOSTS_ERROR;
}
host_port = ssh_session_get_host_port(session);
if (host_port == NULL) {
return SSH_KNOWN_HOSTS_ERROR;
}
found = ssh_known_hosts_check_server_key(host_port,
session->opts.knownhosts,
server_pubkey,
pentry);
return found;
}
/**
* @brief Check if the servers public key for the connected session is known.
*
* This checks if we already know the public key of the server we want to
* connect to. This allows to detect if there is a MITM attach going on
* of if there have been changes on the server we don't know about.
*
* @param[in] session The SSH to validate.
*
* @returns SSH_KNOWN_HOSTS_OK: The server is known and has not changed.\n
* SSH_KNOWN_HOSTS_CHANGED: The server key has changed. Either you
* are under attack or the administrator
* changed the key. You HAVE to warn the
* user about a possible attack.\n
* SSH_KNOWN_HOSTS_OTHER: The server gave use a key of a type while
* we had an other type recorded. It is a
* possible attack.\n
* SSH_KNOWN_HOSTS_UNKNOWN: The server is unknown. User should
* confirm the public key hash is correct.\n
* SSH_KNOWN_HOSTS_NOT_FOUND: The known host file does not exist. The
* host is thus unknown. File will be
* created if host key is accepted.\n
* SSH_KNOWN_HOSTS_ERROR: There had been an eror checking the host.
*/
enum ssh_known_hosts_e ssh_session_is_known_server(ssh_session session)
{
return ssh_session_get_known_hosts_entry(session, NULL);
}

Просмотреть файл

@ -103,12 +103,32 @@ static void torture_knownhosts_export(void **state)
SAFE_FREE(entry);
}
static void torture_knownhosts_write_and_verify(void **state)
{
struct torture_state *s = *state;
ssh_session session = s->ssh.session;
enum ssh_known_hosts_e found;
int rc;
rc = ssh_connect(session);
assert_int_equal(rc, SSH_OK);
rc = ssh_session_update_known_hosts(session);
assert_int_equal(rc, SSH_OK);
found = ssh_session_is_known_server(session);
assert_int_equal(found, SSH_KNOWN_HOSTS_OK);
}
int torture_run_tests(void) {
int rc;
struct CMUnitTest tests[] = {
cmocka_unit_test_setup_teardown(torture_knownhosts_export,
session_setup,
session_teardown),
cmocka_unit_test_setup_teardown(torture_knownhosts_write_and_verify,
session_setup,
session_teardown),
};
ssh_init();