summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Huss <eric@huss.org>2023-02-04 12:17:03 -0800
committerEdward Thomson <ethomson@edwardthomson.com>2023-02-14 09:39:08 +0000
commit1dfdf4b8b9ad7b960f96cafcf7bc140c54a38a98 (patch)
treed8d3f549fd80b34b19c228d732943eda6ceb4122
parentbef34cb2139be3beedf3a1c11cdd664fea09b8ad (diff)
downloadlibgit2-1dfdf4b8b9ad7b960f96cafcf7bc140c54a38a98.tar.gz
Set all SSH hostkey preferences that are available
-rw-r--r--src/libgit2/transports/ssh.c85
1 files changed, 42 insertions, 43 deletions
diff --git a/src/libgit2/transports/ssh.c b/src/libgit2/transports/ssh.c
index a7cdf1d0d..e90ab07e8 100644
--- a/src/libgit2/transports/ssh.c
+++ b/src/libgit2/transports/ssh.c
@@ -467,28 +467,26 @@ out:
return error;
}
-static const char *hostkey_type_to_string(int type)
+static void add_hostkey_pref_if_avail(
+ LIBSSH2_KNOWNHOSTS *known_hosts,
+ const char *hostname,
+ int port,
+ git_str *prefs,
+ int type,
+ const char *type_name)
{
- switch (type) {
- case LIBSSH2_KNOWNHOST_KEY_SSHRSA:
- return "ssh-rsa";
- case LIBSSH2_KNOWNHOST_KEY_SSHDSS:
- return "ssh-dss";
-#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_256
- case LIBSSH2_KNOWNHOST_KEY_ECDSA_256:
- return "ecdsa-sha2-nistp256";
- case LIBSSH2_KNOWNHOST_KEY_ECDSA_384:
- return "ecdsa-sha2-nistp384";
- case LIBSSH2_KNOWNHOST_KEY_ECDSA_521:
- return "ecdsa-sha2-nistp521";
-#endif
-#ifdef LIBSSH2_KNOWNHOST_KEY_ED25519
- case LIBSSH2_KNOWNHOST_KEY_ED25519:
- return "ssh-ed25519";
-#endif
- }
+ struct libssh2_knownhost *host = NULL;
+ const char key = '\0';
+ int mask = LIBSSH2_KNOWNHOST_TYPE_PLAIN | LIBSSH2_KNOWNHOST_KEYENC_RAW | type;
+ int error;
- return NULL;
+ error = libssh2_knownhost_checkp(known_hosts, hostname, port, &key, 1, mask, &host);
+ if (error == LIBSSH2_KNOWNHOST_CHECK_MISMATCH) {
+ if (git_str_len(prefs) > 0) {
+ git_str_putc(prefs, ',');
+ }
+ git_str_puts(prefs, type_name);
+ }
}
/*
@@ -496,27 +494,27 @@ static const char *hostkey_type_to_string(int type)
* look it up with a nonsense key and using that mismatch to figure out what key
* we do have stored for the host.
*
- * Returns the string to pass to libssh2_session_method_pref or NULL if we were
- * unable to find anything or an error happened.
+ * Populates prefs with the string to pass to libssh2_session_method_pref.
*/
-static const char *find_hostkey_preference(LIBSSH2_KNOWNHOSTS *known_hosts, const char *hostname, int port)
+static void find_hostkey_preference(
+ LIBSSH2_KNOWNHOSTS *known_hosts,
+ const char *hostname,
+ int port,
+ git_str *prefs)
{
- struct libssh2_knownhost *host = NULL;
- /* Specify no key type so we don't filter on that */
- int type = LIBSSH2_KNOWNHOST_TYPE_PLAIN | LIBSSH2_KNOWNHOST_KEYENC_RAW;
- const char key = '\0';
- int error;
-
/*
- * In case of mismatch, we can find the type of key from known_hosts in
- * the returned host's information as it means that an entry was found
- * but our nonsense key obviously didn't match.
+ * The order here is important as it indicates the priority of what will
+ * be preferred.
*/
- error = libssh2_knownhost_checkp(known_hosts, hostname, port, &key, 1, type, &host);
- if (error == LIBSSH2_KNOWNHOST_CHECK_MISMATCH)
- return hostkey_type_to_string(host->typemask & LIBSSH2_KNOWNHOST_KEY_MASK);
-
- return NULL;
+#ifdef LIBSSH2_KNOWNHOST_KEY_ED25519
+ add_hostkey_pref_if_avail(known_hosts, hostname, port, prefs, LIBSSH2_KNOWNHOST_KEY_ED25519, "ssh-ed25519");
+#endif
+#ifdef LIBSSH2_KNOWNHOST_KEY_ECDSA_256
+ add_hostkey_pref_if_avail(known_hosts, hostname, port, prefs, LIBSSH2_KNOWNHOST_KEY_ECDSA_256, "ecdsa-sha2-nistp256");
+ add_hostkey_pref_if_avail(known_hosts, hostname, port, prefs, LIBSSH2_KNOWNHOST_KEY_ECDSA_384, "ecdsa-sha2-nistp384");
+ add_hostkey_pref_if_avail(known_hosts, hostname, port, prefs, LIBSSH2_KNOWNHOST_KEY_ECDSA_521, "ecdsa-sha2-nistp521");
+#endif
+ add_hostkey_pref_if_avail(known_hosts, hostname, port, prefs, LIBSSH2_KNOWNHOST_KEY_SSHRSA, "ssh-rsa");
}
static int _git_ssh_session_create(
@@ -526,11 +524,11 @@ static int _git_ssh_session_create(
int port,
git_stream *io)
{
- int rc = 0;
+ git_socket_stream *socket = GIT_CONTAINER_OF(io, git_socket_stream, parent);
LIBSSH2_SESSION *s;
LIBSSH2_KNOWNHOSTS *known_hosts;
- git_socket_stream *socket = GIT_CONTAINER_OF(io, git_socket_stream, parent);
- const char *keytype = NULL;
+ git_str prefs = GIT_STR_INIT;
+ int rc = 0;
GIT_ASSERT_ARG(session);
GIT_ASSERT_ARG(hosts);
@@ -547,16 +545,17 @@ static int _git_ssh_session_create(
return -1;
}
- if ((keytype = find_hostkey_preference(known_hosts, hostname, port)) != NULL) {
+ find_hostkey_preference(known_hosts, hostname, port, &prefs);
+ if (git_str_len(&prefs) > 0) {
do {
- rc = libssh2_session_method_pref(s, LIBSSH2_METHOD_HOSTKEY, keytype);
+ rc = libssh2_session_method_pref(s, LIBSSH2_METHOD_HOSTKEY, git_str_cstr(&prefs));
} while (LIBSSH2_ERROR_EAGAIN == rc || LIBSSH2_ERROR_TIMEOUT == rc);
if (rc != LIBSSH2_ERROR_NONE) {
ssh_error(s, "failed to set hostkey preference");
goto on_error;
}
}
-
+ git_str_dispose(&prefs);
do {
rc = libssh2_session_handshake(s, socket->s);