- djm@cvs.openbsd.org 2010/11/29 23:45:51
[auth.c hostfile.c hostfile.h ssh.c ssh_config.5 sshconnect.c]
[sshconnect.h sshconnect2.c]
automatically order the hostkeys requested by the client based on
which hostkeys are already recorded in known_hosts. This avoids
hostkey warnings when connecting to servers with new ECDSA keys
that are preferred by default; with markus@
diff --git a/sshconnect2.c b/sshconnect2.c
index 6fe356c..3cb9b10 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshconnect2.c,v 1.185 2010/09/22 05:01:29 djm Exp $ */
+/* $OpenBSD: sshconnect2.c,v 1.186 2010/11/29 23:45:51 djm Exp $ */
/*
* Copyright (c) 2000 Markus Friedl. All rights reserved.
* Copyright (c) 2008 Damien Miller. All rights reserved.
@@ -69,6 +69,7 @@
#include "msg.h"
#include "pathnames.h"
#include "uidswap.h"
+#include "hostfile.h"
#include "schnorr.h"
#include "jpake.h"
@@ -101,8 +102,60 @@
return 0;
}
+static char *
+order_hostkeyalgs(char *host, struct sockaddr *hostaddr, u_short port)
+{
+ char *oavail, *avail, *first, *last, *alg, *hostname, *ret;
+ size_t maxlen;
+ struct hostkeys *hostkeys;
+ int ktype;
+
+ /* Find all hostkeys for this hostname */
+ get_hostfile_hostname_ipaddr(host, hostaddr, port, &hostname, NULL);
+ hostkeys = init_hostkeys();
+ load_hostkeys(hostkeys, hostname, options.user_hostfile2);
+ load_hostkeys(hostkeys, hostname, options.system_hostfile2);
+ load_hostkeys(hostkeys, hostname, options.user_hostfile);
+ load_hostkeys(hostkeys, hostname, options.system_hostfile);
+
+ oavail = avail = xstrdup(KEX_DEFAULT_PK_ALG);
+ maxlen = strlen(avail) + 1;
+ first = xmalloc(maxlen);
+ last = xmalloc(maxlen);
+ *first = *last = '\0';
+
+#define ALG_APPEND(to, from) \
+ do { \
+ if (*to != '\0') \
+ strlcat(to, ",", maxlen); \
+ strlcat(to, from, maxlen); \
+ } while (0)
+
+ while ((alg = strsep(&avail, ",")) && *alg != '\0') {
+ if ((ktype = key_type_from_name(alg)) == KEY_UNSPEC)
+ fatal("%s: unknown alg %s", __func__, alg);
+ if (lookup_key_in_hostkeys_by_type(hostkeys,
+ key_type_plain(ktype), NULL))
+ ALG_APPEND(first, alg);
+ else
+ ALG_APPEND(last, alg);
+ }
+#undef ALG_APPEND
+ xasprintf(&ret, "%s%s%s", first, *first == '\0' ? "" : ",", last);
+ if (*first != '\0')
+ debug3("%s: prefer hostkeyalgs: %s", __func__, first);
+
+ xfree(first);
+ xfree(last);
+ xfree(hostname);
+ xfree(oavail);
+ free_hostkeys(hostkeys);
+
+ return ret;
+}
+
void
-ssh_kex2(char *host, struct sockaddr *hostaddr)
+ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port)
{
Kex *kex;
@@ -135,6 +188,11 @@
if (options.hostkeyalgorithms != NULL)
myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
options.hostkeyalgorithms;
+ else {
+ /* Prefer algorithms that we already have keys for */
+ myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] =
+ order_hostkeyalgs(host, hostaddr, port);
+ }
if (options.kex_algorithms != NULL)
myproposal[PROPOSAL_KEX_ALGS] = options.kex_algorithms;