rcolebaugh / rpms / openssh

Forked from rpms/openssh 2 years ago
Clone
f806d6
diff -up openssh-8.0p1/hostfile.c.cve-2020-14145 openssh-8.0p1/hostfile.c
f806d6
--- openssh-8.0p1/hostfile.c.cve-2020-14145	2019-04-18 00:52:57.000000000 +0200
f806d6
+++ openssh-8.0p1/hostfile.c	2021-05-17 16:53:38.694577251 +0200
f806d6
@@ -409,6 +409,18 @@ lookup_key_in_hostkeys_by_type(struct ho
f806d6
 	    found) == HOST_FOUND);
f806d6
 }
f806d6
 
f806d6
+int
f806d6
+lookup_marker_in_hostkeys(struct hostkeys *hostkeys, int want_marker)
f806d6
+{
f806d6
+	u_int i;
f806d6
+
f806d6
+	for (i = 0; i < hostkeys->num_entries; i++) {
f806d6
+		if (hostkeys->entries[i].marker == (HostkeyMarker)want_marker)
f806d6
+			return 1;
f806d6
+	}
f806d6
+	return 0;
f806d6
+}
f806d6
+
f806d6
 static int
f806d6
 write_host_entry(FILE *f, const char *host, const char *ip,
f806d6
     const struct sshkey *key, int store_hash)
f806d6
diff -up openssh-8.0p1/hostfile.h.cve-2020-14145 openssh-8.0p1/hostfile.h
f806d6
--- openssh-8.0p1/hostfile.h.cve-2020-14145	2019-04-18 00:52:57.000000000 +0200
f806d6
+++ openssh-8.0p1/hostfile.h	2021-05-17 16:53:38.694577251 +0200
f806d6
@@ -39,6 +39,7 @@ HostStatus check_key_in_hostkeys(struct
f806d6
     const struct hostkey_entry **);
f806d6
 int	 lookup_key_in_hostkeys_by_type(struct hostkeys *, int,
f806d6
     const struct hostkey_entry **);
f806d6
+int	 lookup_marker_in_hostkeys(struct hostkeys *, int);
f806d6
 
f806d6
 int	 hostfile_read_key(char **, u_int *, struct sshkey *);
f806d6
 int	 add_host_to_hostfile(const char *, const char *,
f806d6
diff -up openssh-8.0p1/sshconnect2.c.cve-2020-14145 openssh-8.0p1/sshconnect2.c
f806d6
--- openssh-8.0p1/sshconnect2.c.cve-2020-14145	2021-05-17 16:53:38.610576561 +0200
f806d6
+++ openssh-8.0p1/sshconnect2.c	2021-05-17 16:54:58.169230103 +0200
f806d6
@@ -98,12 +98,25 @@ verify_host_key_callback(struct sshkey *
f806d6
 	return 0;
f806d6
 }
f806d6
 
f806d6
+/* Returns the first item from a comma-separated algorithm list */
f806d6
+static char *
f806d6
+first_alg(const char *algs)
f806d6
+{
f806d6
+	char *ret, *cp;
f806d6
+
f806d6
+	ret = xstrdup(algs);
f806d6
+	if ((cp = strchr(ret, ',')) != NULL)
f806d6
+		*cp = '\0';
f806d6
+	return ret;
f806d6
+}
f806d6
+
f806d6
 static char *
f806d6
 order_hostkeyalgs(char *host, struct sockaddr *hostaddr, u_short port)
f806d6
 {
f806d6
-	char *oavail, *avail, *first, *last, *alg, *hostname, *ret;
f806d6
+	char *oavail = NULL, *avail = NULL, *first = NULL, *last = NULL;
f806d6
+	char *alg = NULL, *hostname = NULL, *ret = NULL, *best = NULL;
f806d6
 	size_t maxlen;
f806d6
-	struct hostkeys *hostkeys;
f806d6
+	struct hostkeys *hostkeys = NULL;
f806d6
 	int ktype;
f806d6
 	u_int i;
f806d6
 
f806d6
@@ -115,6 +128,26 @@ order_hostkeyalgs(char *host, struct soc
f806d6
 	for (i = 0; i < options.num_system_hostfiles; i++)
f806d6
 		load_hostkeys(hostkeys, hostname, options.system_hostfiles[i]);
f806d6
 
f806d6
+	/*
f806d6
+	 * If a plain public key exists that matches the type of the best
f806d6
+	 * preference HostkeyAlgorithms, then use the whole list as is.
f806d6
+	 * Note that we ignore whether the best preference algorithm is a
f806d6
+	 * certificate type, as sshconnect.c will downgrade certs to
f806d6
+	 * plain keys if necessary.
f806d6
+	 */
f806d6
+	best = first_alg(options.hostkeyalgorithms);
f806d6
+	if (lookup_key_in_hostkeys_by_type(hostkeys,
f806d6
+	    sshkey_type_plain(sshkey_type_from_name(best)), NULL)) {
f806d6
+		debug3("%s: have matching best-preference key type %s, "
f806d6
+		    "using HostkeyAlgorithms verbatim", __func__, best);
f806d6
+		ret = xstrdup(options.hostkeyalgorithms);
f806d6
+		goto out;
f806d6
+	}
f806d6
+
f806d6
+	/*
f806d6
+	 * Otherwise, prefer the host key algorithms that match known keys
f806d6
+	 * while keeping the ordering of HostkeyAlgorithms as much as possible.
f806d6
+	 */
f806d6
 	oavail = avail = xstrdup(KEX_DEFAULT_PK_ALG);
f806d6
 	maxlen = strlen(avail) + 1;
f806d6
 	first = xmalloc(maxlen);
f806d6
@@ -131,11 +164,23 @@ order_hostkeyalgs(char *host, struct soc
f806d6
 	while ((alg = strsep(&avail, ",")) && *alg != '\0') {
f806d6
 		if ((ktype = sshkey_type_from_name(alg)) == KEY_UNSPEC)
f806d6
 			fatal("%s: unknown alg %s", __func__, alg);
f806d6
+		/*
f806d6
+		 * If we have a @cert-authority marker in known_hosts then
f806d6
+		 * prefer all certificate algorithms.
f806d6
+		 */
f806d6
+		if (sshkey_type_is_cert(ktype) &&
f806d6
+		    lookup_marker_in_hostkeys(hostkeys, MRK_CA)) {
f806d6
+			ALG_APPEND(first, alg);
f806d6
+			continue;
f806d6
+		}
f806d6
+		/* If the key appears in known_hosts then prefer it */
f806d6
 		if (lookup_key_in_hostkeys_by_type(hostkeys,
f806d6
-		    sshkey_type_plain(ktype), NULL))
f806d6
+		    sshkey_type_plain(ktype), NULL)) {
f806d6
 			ALG_APPEND(first, alg);
f806d6
-		else
f806d6
-			ALG_APPEND(last, alg);
f806d6
+			continue;
f806d6
+		}
f806d6
+		/* Otherwise, put it last */
f806d6
+		ALG_APPEND(last, alg);
f806d6
 	}
f806d6
 #undef ALG_APPEND
f806d6
 	xasprintf(&ret, "%s%s%s", first,
f806d6
@@ -143,6 +188,8 @@ order_hostkeyalgs(char *host, struct soc
f806d6
 	if (*first != '\0')
f806d6
 		debug3("%s: prefer hostkeyalgs: %s", __func__, first);
f806d6
 
f806d6
+ out:
f806d6
+	free(best);
f806d6
 	free(first);
f806d6
 	free(last);
f806d6
 	free(hostname);