aboutsummaryrefslogtreecommitdiff
path: root/src/knownhosts.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/knownhosts.c')
-rw-r--r--src/knownhosts.c119
1 files changed, 76 insertions, 43 deletions
diff --git a/src/knownhosts.c b/src/knownhosts.c
index fed75f90..c073b266 100644
--- a/src/knownhosts.c
+++ b/src/knownhosts.c
@@ -44,6 +44,10 @@
#include "libssh/knownhosts.h"
#include "libssh/token.h"
+#ifndef MAX_LINE_SIZE
+#define MAX_LINE_SIZE 8192
+#endif
+
/**
* @addtogroup libssh_session
*
@@ -54,8 +58,9 @@ static int hash_hostname(const char *name,
unsigned char *salt,
unsigned int salt_size,
unsigned char **hash,
- unsigned int *hash_size)
+ size_t *hash_size)
{
+ int rc;
HMACCTX mac_ctx;
mac_ctx = hmac_init(salt, salt_size, SSH_HMAC_SHA1);
@@ -63,8 +68,13 @@ static int hash_hostname(const char *name,
return SSH_ERROR;
}
- hmac_update(mac_ctx, name, strlen(name));
- hmac_final(mac_ctx, *hash, hash_size);
+ rc = hmac_update(mac_ctx, name, strlen(name));
+ if (rc != 1)
+ return SSH_ERROR;
+
+ rc = hmac_final(mac_ctx, *hash, hash_size);
+ if (rc != 1)
+ return SSH_ERROR;
return SSH_OK;
}
@@ -77,7 +87,7 @@ static int match_hashed_hostname(const char *host, const char *hashed_host)
ssh_buffer hash = NULL;
unsigned char hashed_buf[256] = {0};
unsigned char *hashed_buf_ptr = hashed_buf;
- unsigned int hashed_buf_size = sizeof(hashed_buf);
+ size_t hashed_buf_size = sizeof(hashed_buf);
int cmp;
int rc;
int match = 0;
@@ -216,7 +226,7 @@ static int ssh_known_hosts_read_entries(const char *match,
const char *filename,
struct ssh_list **entries)
{
- char line[8192];
+ char line[MAX_LINE_SIZE];
size_t lineno = 0;
size_t len = 0;
FILE *fp;
@@ -224,8 +234,9 @@ static int ssh_known_hosts_read_entries(const char *match,
fp = fopen(filename, "r");
if (fp == NULL) {
- SSH_LOG(SSH_LOG_WARN, "Failed to open the known_hosts file '%s': %s",
- filename, strerror(errno));
+ char err_msg[SSH_ERRNO_MSG_MAX] = {0};
+ SSH_LOG(SSH_LOG_TRACE, "Failed to open the known_hosts file '%s': %s",
+ filename, ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
/* The missing file is not an error here */
return SSH_OK;
}
@@ -372,6 +383,7 @@ struct ssh_list *ssh_known_hosts_get_algorithms(ssh_session session)
list = ssh_list_new();
if (list == NULL) {
+ ssh_set_error_oom(session);
SAFE_FREE(host_port);
return NULL;
}
@@ -468,24 +480,33 @@ static const char *ssh_known_host_sigs_from_hostkey_type(enum ssh_keytypes_e typ
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_SK_ED25519:
+ return "sk-ssh-ed25519@openssh.com";
+#ifdef HAVE_ECC
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";
+ case SSH_KEYTYPE_SK_ECDSA:
+ return "sk-ecdsa-sha2-nistp256@openssh.com";
+#else
+ case SSH_KEYTYPE_ECDSA_P256:
+ case SSH_KEYTYPE_ECDSA_P384:
+ case SSH_KEYTYPE_ECDSA_P521:
+ SSH_LOG(SSH_LOG_WARN, "ECDSA keys are not supported by this build");
+ break;
#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;
+ SSH_LOG(SSH_LOG_TRACE,
+ "The given type %d is not a base private key type "
+ "or is unsupported",
+ type);
}
+
+ return NULL;
}
/**
@@ -567,6 +588,8 @@ char *ssh_known_hosts_get_algorithms_names(ssh_session session)
entry = ssh_iterator_value(struct ssh_knownhosts_entry *, it);
algo = ssh_known_host_sigs_from_hostkey_type(entry->publickey->type);
if (algo == NULL) {
+ ssh_knownhosts_entry_free(entry);
+ ssh_list_remove(entry_list, it);
continue;
}
@@ -595,7 +618,7 @@ char *ssh_known_hosts_get_algorithms_names(ssh_session session)
/**
* @brief Parse a line from a known_hosts entry into a structure
*
- * This parses an known_hosts entry into a structure with the key in a libssh
+ * This parses a known_hosts entry into a structure with the key in a libssh
* consumeable form. You can use the PKI key function to further work with it.
*
* @param[in] hostname The hostname to match the line to
@@ -603,7 +626,7 @@ char *ssh_known_hosts_get_algorithms_names(ssh_session session)
* @param[in] line The line to compare and parse if we have a hostname
* match.
*
- * @param[in] entry A pointer to store the the allocated known_hosts
+ * @param[in] entry A pointer to store the allocated known_hosts
* entry structure. The user needs to free the memory
* using SSH_KNOWNHOSTS_ENTRY_FREE().
*
@@ -616,6 +639,7 @@ int ssh_known_hosts_parse_line(const char *hostname,
struct ssh_knownhosts_entry *e = NULL;
char *known_host = NULL;
char *p;
+ char *save_tok = NULL;
enum ssh_keytypes_e key_type;
int match = 0;
int rc = SSH_OK;
@@ -626,7 +650,7 @@ int ssh_known_hosts_parse_line(const char *hostname,
}
/* match pattern for hostname or hashed hostname */
- p = strtok(known_host, " ");
+ p = strtok_r(known_host, " ", &save_tok);
if (p == NULL ) {
free(known_host);
return SSH_ERROR;
@@ -647,14 +671,16 @@ int ssh_known_hosts_parse_line(const char *hostname,
match = match_hashed_hostname(hostname, p);
}
- for (q = strtok(p, ",");
+ save_tok = NULL;
+
+ for (q = strtok_r(p, ",", &save_tok);
q != NULL;
- q = strtok(NULL, ",")) {
+ q = strtok_r(NULL, ",", &save_tok)) {
int cmp;
if (q[0] == '[' && hostname[0] != '[') {
/* Corner case: We have standard port so we do not have
- * hostname in square braces. But the patern is enclosed
+ * hostname in square braces. But the pattern is enclosed
* in braces with, possibly standard or wildcard, port.
* We need to test against [host]:port pair here.
*/
@@ -697,7 +723,9 @@ int ssh_known_hosts_parse_line(const char *hostname,
goto out;
}
- p = strtok(known_host, " ");
+ save_tok = NULL;
+
+ p = strtok_r(known_host, " ", &save_tok);
if (p == NULL ) {
rc = SSH_ERROR;
goto out;
@@ -710,7 +738,7 @@ int ssh_known_hosts_parse_line(const char *hostname,
}
/* pubkey type */
- p = strtok(NULL, " ");
+ p = strtok_r(NULL, " ", &save_tok);
if (p == NULL) {
rc = SSH_ERROR;
goto out;
@@ -718,13 +746,13 @@ int ssh_known_hosts_parse_line(const char *hostname,
key_type = ssh_key_type_from_name(p);
if (key_type == SSH_KEYTYPE_UNKNOWN) {
- SSH_LOG(SSH_LOG_WARN, "key type '%s' unknown!", p);
+ SSH_LOG(SSH_LOG_TRACE, "key type '%s' unknown!", p);
rc = SSH_ERROR;
goto out;
}
/* public key */
- p = strtok(NULL, " ");
+ p = strtok_r(NULL, " ", &save_tok);
if (p == NULL) {
rc = SSH_ERROR;
goto out;
@@ -734,7 +762,7 @@ int ssh_known_hosts_parse_line(const char *hostname,
key_type,
&e->publickey);
if (rc != SSH_OK) {
- SSH_LOG(SSH_LOG_WARN,
+ SSH_LOG(SSH_LOG_TRACE,
"Failed to parse %s key for entry: %s!",
ssh_key_type_to_char(key_type),
e->unparsed);
@@ -742,7 +770,7 @@ int ssh_known_hosts_parse_line(const char *hostname,
}
/* comment */
- p = strtok(NULL, " ");
+ p = strtok_r(NULL, " ", &save_tok);
if (p != NULL) {
p = strstr(line, p);
if (p != NULL) {
@@ -765,12 +793,12 @@ out:
}
/**
- * @brief Check if the set hostname and port matches an entry in known_hosts.
+ * @brief Check if the set hostname and port match an entry in known_hosts.
*
- * This check if the set hostname and port has an entry in the known_hosts file.
+ * This check if the set hostname and port have an entry in the known_hosts file.
* You need to set at least the hostname using ssh_options_set().
*
- * @param[in] session The session with with the values set to check.
+ * @param[in] session The session with the values set to check.
*
* @return A ssh_known_hosts_e return value.
*/
@@ -805,7 +833,7 @@ enum ssh_known_hosts_e ssh_session_has_known_hosts_entry(ssh_session session)
if (session->opts.knownhosts != NULL) {
known_hosts_found = ssh_file_readaccess_ok(session->opts.knownhosts);
if (!known_hosts_found) {
- SSH_LOG(SSH_LOG_WARN, "Cannot access file %s",
+ SSH_LOG(SSH_LOG_TRACE, "Cannot access file %s",
session->opts.knownhosts);
}
}
@@ -814,7 +842,7 @@ enum ssh_known_hosts_e ssh_session_has_known_hosts_entry(ssh_session session)
global_known_hosts_found =
ssh_file_readaccess_ok(session->opts.global_knownhosts);
if (!global_known_hosts_found) {
- SSH_LOG(SSH_LOG_WARN, "Cannot access file %s",
+ SSH_LOG(SSH_LOG_TRACE, "Cannot access file %s",
session->opts.global_knownhosts);
}
}
@@ -883,18 +911,18 @@ enum ssh_known_hosts_e ssh_session_has_known_hosts_entry(ssh_session session)
*
* @param[in] session The session with information to export.
*
- * @param[in] pentry_string A pointer to a string to store the alloocated
+ * @param[in] pentry_string A pointer to a string to store the allocated
* line of the entry. The user must free it using
* ssh_string_free_char().
*
- * @return SSH_OK on succcess, SSH_ERROR otherwise.
+ * @return SSH_OK on success, SSH_ERROR otherwise.
*/
int ssh_session_export_known_hosts_entry(ssh_session session,
char **pentry_string)
{
ssh_key server_pubkey = NULL;
char *host = NULL;
- char entry_buf[4096] = {0};
+ char entry_buf[MAX_LINE_SIZE] = {0};
char *b64_key = NULL;
int rc;
@@ -952,7 +980,7 @@ int ssh_session_export_known_hosts_entry(ssh_session session,
}
/**
- * @brief Add the current connected server to the user known_hosts file.
+ * @brief Adds the currently connected server to the user known_hosts file.
*
* This adds the currently connected server to the known_hosts file by
* appending a new line at the end. The global known_hosts file is considered
@@ -970,6 +998,7 @@ int ssh_session_update_known_hosts(ssh_session session)
size_t nwritten;
size_t len;
int rc;
+ char err_msg[SSH_ERRNO_MSG_MAX] = {0};
if (session->opts.knownhosts == NULL) {
rc = ssh_options_apply(session);
@@ -985,7 +1014,8 @@ int ssh_session_update_known_hosts(ssh_session session)
if (errno == ENOENT) {
dir = ssh_dirname(session->opts.knownhosts);
if (dir == NULL) {
- ssh_set_error(session, SSH_FATAL, "%s", strerror(errno));
+ ssh_set_error(session, SSH_FATAL, "%s",
+ ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
return SSH_ERROR;
}
@@ -993,7 +1023,8 @@ int ssh_session_update_known_hosts(ssh_session session)
if (rc < 0) {
ssh_set_error(session, SSH_FATAL,
"Cannot create %s directory: %s",
- dir, strerror(errno));
+ dir,
+ ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
SAFE_FREE(dir);
return SSH_ERROR;
}
@@ -1005,7 +1036,8 @@ int ssh_session_update_known_hosts(ssh_session session)
ssh_set_error(session, SSH_FATAL,
"Couldn't open known_hosts file %s"
" for appending: %s",
- session->opts.knownhosts, strerror(errno));
+ session->opts.knownhosts,
+ ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
return SSH_ERROR;
}
} else {
@@ -1028,7 +1060,8 @@ int ssh_session_update_known_hosts(ssh_session session)
if (nwritten != len || ferror(fp)) {
ssh_set_error(session, SSH_FATAL,
"Couldn't append to known_hosts file %s: %s",
- session->opts.knownhosts, strerror(errno));
+ session->opts.knownhosts,
+ ssh_strerror(errno, err_msg, SSH_ERRNO_MSG_MAX));
fclose(fp);
return SSH_ERROR;
}
@@ -1103,7 +1136,7 @@ ssh_known_hosts_check_server_key(const char *hosts_entry,
}
/**
- * @brief Get the known_hosts entry for the current connected session.
+ * @brief Get the known_hosts entry for the currently connected session.
*
* @param[in] session The session to validate.
*
@@ -1122,7 +1155,7 @@ ssh_known_hosts_check_server_key(const char *hosts_entry,
* 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.
+ * SSH_KNOWN_HOSTS_ERROR: There had been an error checking the host.
*
* @see ssh_knownhosts_entry_free()
*/
@@ -1191,7 +1224,7 @@ ssh_session_get_known_hosts_entry(ssh_session session,
* 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.
+ * SSH_KNOWN_HOSTS_ERROR: There had been an error checking the host.
*
* @see ssh_knownhosts_entry_free()
*/