5b55d09
diff -up openssh/clientloop.c.fingerprint openssh/clientloop.c
5b55d09
--- openssh/clientloop.c.fingerprint	2017-09-26 15:21:22.582477729 +0200
5b55d09
+++ openssh/clientloop.c	2017-09-26 15:21:22.620477932 +0200
5b55d09
@@ -1854,7 +1854,7 @@ update_known_hosts(struct hostkeys_updat
4df30a2
 		if (ctx->keys_seen[i] != 2)
4df30a2
 			continue;
4df30a2
 		if ((fp = sshkey_fingerprint(ctx->keys[i],
4df30a2
-		    options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
4df30a2
+		    options.fingerprint_hash[0], SSH_FP_DEFAULT)) == NULL)
4df30a2
 			fatal("%s: sshkey_fingerprint failed", __func__);
4df30a2
 		do_log2(loglevel, "Learned new hostkey: %s %s",
4df30a2
 		    sshkey_type(ctx->keys[i]), fp);
5b55d09
@@ -1862,7 +1862,7 @@ update_known_hosts(struct hostkeys_updat
4df30a2
 	}
4df30a2
 	for (i = 0; i < ctx->nold; i++) {
4df30a2
 		if ((fp = sshkey_fingerprint(ctx->old_keys[i],
4df30a2
-		    options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
4df30a2
+		    options.fingerprint_hash[0], SSH_FP_DEFAULT)) == NULL)
4df30a2
 			fatal("%s: sshkey_fingerprint failed", __func__);
4df30a2
 		do_log2(loglevel, "Deprecating obsolete hostkey: %s %s",
4df30a2
 		    sshkey_type(ctx->old_keys[i]), fp);
5b55d09
@@ -1905,7 +1905,7 @@ update_known_hosts(struct hostkeys_updat
4df30a2
 	    (r = hostfile_replace_entries(options.user_hostfiles[0],
4df30a2
 	    ctx->host_str, ctx->ip_str, ctx->keys, ctx->nkeys,
4df30a2
 	    options.hash_known_hosts, 0,
4df30a2
-	    options.fingerprint_hash)) != 0)
4df30a2
+	    options.fingerprint_hash[0])) != 0)
4df30a2
 		error("%s: hostfile_replace_entries failed: %s",
4df30a2
 		    __func__, ssh_err(r));
4df30a2
 }
5b55d09
@@ -2038,7 +2038,7 @@ client_input_hostkeys(void)
4df30a2
 			error("%s: parse key: %s", __func__, ssh_err(r));
4df30a2
 			goto out;
4df30a2
 		}
4df30a2
-		fp = sshkey_fingerprint(key, options.fingerprint_hash,
4df30a2
+		fp = sshkey_fingerprint(key, options.fingerprint_hash[0],
4df30a2
 		    SSH_FP_DEFAULT);
4df30a2
 		debug3("%s: received %s key %s", __func__,
4df30a2
 		    sshkey_type(key), fp);
5b55d09
diff -up openssh/readconf.c.fingerprint openssh/readconf.c
5b55d09
--- openssh/readconf.c.fingerprint	2017-09-26 15:21:22.618477921 +0200
5b55d09
+++ openssh/readconf.c	2017-09-26 15:21:22.621477937 +0200
5b55d09
@@ -1681,16 +1681,18 @@ parse_keytypes:
4df30a2
 		goto parse_string;
4df30a2
 
4df30a2
 	case oFingerprintHash:
4df30a2
-		intptr = &options->fingerprint_hash;
4df30a2
-		arg = strdelim(&s);
4df30a2
-		if (!arg || *arg == '\0')
4df30a2
-			fatal("%.200s line %d: Missing argument.",
4df30a2
-			    filename, linenum);
4df30a2
-		if ((value = ssh_digest_alg_by_name(arg)) == -1)
4df30a2
-			fatal("%.200s line %d: Invalid hash algorithm \"%s\".",
4df30a2
-			    filename, linenum, arg);
4df30a2
-		if (*activep && *intptr == -1)
4df30a2
-			*intptr = value;
4df30a2
+		if (*activep && options->num_fingerprint_hash == 0)
4df30a2
+			while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
4df30a2
+				value = ssh_digest_alg_by_name(arg);
4df30a2
+				if (value == -1)
4df30a2
+					fatal("%s line %d: unknown fingerprints algorithm specs: %s.",
4df30a2
+						filename, linenum, arg);
4df30a2
+				if (options->num_fingerprint_hash >= SSH_DIGEST_MAX)
4df30a2
+					fatal("%s line %d: too many fingerprints algorithm specs.",
4df30a2
+						filename, linenum);
4df30a2
+				options->fingerprint_hash[
4df30a2
+					options->num_fingerprint_hash++] = value;
4df30a2
+			}
4df30a2
 		break;
4df30a2
 
4df30a2
 	case oUpdateHostkeys:
5b55d09
@@ -1917,7 +1919,7 @@ initialize_options(Options * options)
4df30a2
 	options->canonicalize_fallback_local = -1;
4df30a2
 	options->canonicalize_hostname = -1;
4df30a2
 	options->revoked_host_keys = NULL;
4df30a2
-	options->fingerprint_hash = -1;
4df30a2
+	options->num_fingerprint_hash = 0;
4df30a2
 	options->update_hostkeys = -1;
4df30a2
 	options->hostbased_key_types = NULL;
4df30a2
 	options->pubkey_key_types = NULL;
5b55d09
@@ -2096,8 +2098,10 @@ fill_default_options(Options * options)
4df30a2
 		options->canonicalize_fallback_local = 1;
4df30a2
 	if (options->canonicalize_hostname == -1)
4df30a2
 		options->canonicalize_hostname = SSH_CANONICALISE_NO;
4df30a2
-	if (options->fingerprint_hash == -1)
4df30a2
-		options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
4df30a2
+	if (options->num_fingerprint_hash == 0) {
4df30a2
+		options->fingerprint_hash[options->num_fingerprint_hash++] = SSH_DIGEST_SHA256;
4df30a2
+		options->fingerprint_hash[options->num_fingerprint_hash++] = SSH_DIGEST_MD5;
4df30a2
+	}
4df30a2
 	if (options->update_hostkeys == -1)
4df30a2
 		options->update_hostkeys = 0;
4df30a2
 	if (kex_assemble_names(KEX_CLIENT_ENCRYPT, &options->ciphers) != 0 ||
5b55d09
@@ -2474,6 +2478,17 @@ dump_cfg_strarray(OpCodes code, u_int co
4df30a2
 }
4df30a2
 
4df30a2
 static void
4df30a2
+dump_cfg_fmtarray(OpCodes code, u_int count, int *vals)
4df30a2
+{
4df30a2
+	u_int i;
4df30a2
+
4df30a2
+	printf("%s", lookup_opcode_name(code));
4df30a2
+	for (i = 0; i < count; i++)
4df30a2
+		printf(" %s", fmt_intarg(code, vals[i]));
4df30a2
+	printf("\n");
4df30a2
+}
4df30a2
+
4df30a2
+static void
4df30a2
 dump_cfg_strarray_oneline(OpCodes code, u_int count, char **vals)
4df30a2
 {
4df30a2
 	u_int i;
5b55d09
@@ -2549,7 +2564,6 @@ dump_client_config(Options *o, const cha
4df30a2
 	dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign);
5878ebb
 	dump_cfg_fmtint(oClearAllForwardings, o->clear_forwardings);
4df30a2
 	dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure);
4df30a2
-	dump_cfg_fmtint(oFingerprintHash, o->fingerprint_hash);
4df30a2
 	dump_cfg_fmtint(oForwardAgent, o->forward_agent);
4df30a2
 	dump_cfg_fmtint(oForwardX11, o->forward_x11);
4df30a2
 	dump_cfg_fmtint(oForwardX11Trusted, o->forward_x11_trusted);
5b55d09
@@ -2618,6 +2632,7 @@ dump_client_config(Options *o, const cha
4df30a2
 	dump_cfg_strarray_oneline(oGlobalKnownHostsFile, o->num_system_hostfiles, o->system_hostfiles);
4df30a2
 	dump_cfg_strarray_oneline(oUserKnownHostsFile, o->num_user_hostfiles, o->user_hostfiles);
4df30a2
 	dump_cfg_strarray(oSendEnv, o->num_send_env, o->send_env);
4df30a2
+	dump_cfg_fmtarray(oFingerprintHash, o->num_fingerprint_hash, o->fingerprint_hash);
4df30a2
 
4df30a2
 	/* Special cases */
4df30a2
 
5b55d09
diff -up openssh/readconf.h.fingerprint openssh/readconf.h
5b55d09
--- openssh/readconf.h.fingerprint	2017-09-26 15:21:22.618477921 +0200
5b55d09
+++ openssh/readconf.h	2017-09-26 15:21:22.621477937 +0200
4df30a2
@@ -21,6 +21,7 @@
4df30a2
 #define MAX_SEND_ENV		256
4df30a2
 #define SSH_MAX_HOSTS_FILES	32
4df30a2
 #define MAX_CANON_DOMAINS	32
4df30a2
+#define MAX_SSH_DIGESTS	32
4df30a2
 #define PATH_MAX_SUN		(sizeof((struct sockaddr_un *)0)->sun_path)
4df30a2
 
4df30a2
 struct allowed_cname {
5b55d09
@@ -157,7 +158,8 @@ typedef struct {
4df30a2
 
4df30a2
 	char	*revoked_host_keys;
4df30a2
 
4df30a2
-	int	 fingerprint_hash;
4df30a2
+	int num_fingerprint_hash;
4df30a2
+	int 	fingerprint_hash[MAX_SSH_DIGESTS];
4df30a2
 
4df30a2
 	int	 update_hostkeys; /* one of SSH_UPDATE_HOSTKEYS_* */
4df30a2
 
5b55d09
diff -up openssh/ssh_config.5.fingerprint openssh/ssh_config.5
5b55d09
--- openssh/ssh_config.5.fingerprint	2017-09-26 15:21:22.618477921 +0200
5b55d09
+++ openssh/ssh_config.5	2017-09-26 15:21:22.621477937 +0200
5b55d09
@@ -624,12 +624,13 @@ or
6cf9b8e
 .Cm no
6cf9b8e
 (the default).
4df30a2
 .It Cm FingerprintHash
4df30a2
-Specifies the hash algorithm used when displaying key fingerprints.
4df30a2
+Specifies the hash algorithms used when displaying key fingerprints.
4df30a2
 Valid options are:
6cf9b8e
 .Cm md5
4df30a2
 and
6cf9b8e
-.Cm sha256
6cf9b8e
-(the default).
6cf9b8e
+.Cm sha256 .
6cf9b8e
+The default is
6cf9b8e
+.Cm "sha256 md5".
4df30a2
 .It Cm ForwardAgent
4df30a2
 Specifies whether the connection to the authentication agent (if any)
4df30a2
 will be forwarded to the remote machine.
5b55d09
diff -up openssh/sshconnect2.c.fingerprint openssh/sshconnect2.c
5b55d09
--- openssh/sshconnect2.c.fingerprint	2017-09-26 15:21:22.619477926 +0200
5b55d09
+++ openssh/sshconnect2.c	2017-09-26 15:21:50.677628003 +0200
5b55d09
@@ -679,7 +679,7 @@ input_userauth_pk_ok(int type, u_int32_t
6cf9b8e
 		    key->type, pktype);
6cf9b8e
 		goto done;
6cf9b8e
 	}
6cf9b8e
-	if ((fp = sshkey_fingerprint(key, options.fingerprint_hash,
6cf9b8e
+	if ((fp = sshkey_fingerprint(key, options.fingerprint_hash[0],
6cf9b8e
 	    SSH_FP_DEFAULT)) == NULL)
6cf9b8e
 		goto done;
6cf9b8e
 	debug2("input_userauth_pk_ok: fp %s", fp);
5b55d09
@@ -1198,7 +1198,7 @@ sign_and_send_pubkey(Authctxt *authctxt,
6cf9b8e
 	int matched, ret = -1, have_sig = 1;
6cf9b8e
 	char *fp;
6cf9b8e
 
6cf9b8e
-	if ((fp = sshkey_fingerprint(id->key, options.fingerprint_hash,
6cf9b8e
+	if ((fp = sshkey_fingerprint(id->key, options.fingerprint_hash[0],
6cf9b8e
 	    SSH_FP_DEFAULT)) == NULL)
6cf9b8e
 		return 0;
6cf9b8e
 	debug3("%s: %s %s", __func__, key_type(id->key), fp);
5b55d09
@@ -1620,7 +1620,7 @@ userauth_pubkey(Authctxt *authctxt)
5b55d09
 		if (id->key != NULL) {
5b55d09
 			if (try_identity(id)) {
5b55d09
 				if ((fp = sshkey_fingerprint(id->key,
5b55d09
-				    options.fingerprint_hash,
5b55d09
+				    options.fingerprint_hash[0],
5b55d09
 				    SSH_FP_DEFAULT)) == NULL) {
5b55d09
 					error("%s: sshkey_fingerprint failed",
5b55d09
 					    __func__);
5b55d09
@@ -1914,7 +1914,7 @@ userauth_hostbased(Authctxt *authctxt)
6cf9b8e
 		goto out;
6cf9b8e
 	}
6cf9b8e
 
6cf9b8e
-	if ((fp = sshkey_fingerprint(private, options.fingerprint_hash,
6cf9b8e
+	if ((fp = sshkey_fingerprint(private, options.fingerprint_hash[0],
6cf9b8e
 	    SSH_FP_DEFAULT)) == NULL) {
6cf9b8e
 		error("%s: sshkey_fingerprint failed", __func__);
6cf9b8e
 		goto out;
5b55d09
diff -up openssh/sshconnect.c.fingerprint openssh/sshconnect.c
5b55d09
--- openssh/sshconnect.c.fingerprint	2017-09-25 01:48:10.000000000 +0200
5b55d09
+++ openssh/sshconnect.c	2017-09-26 15:21:22.622477943 +0200
5b55d09
@@ -861,9 +861,9 @@ check_host_key(char *hostname, struct so
4df30a2
 				    "of known hosts.", type, ip);
4df30a2
 		} else if (options.visual_host_key) {
4df30a2
 			fp = sshkey_fingerprint(host_key,
4df30a2
-			    options.fingerprint_hash, SSH_FP_DEFAULT);
4df30a2
+			    options.fingerprint_hash[0], SSH_FP_DEFAULT);
4df30a2
 			ra = sshkey_fingerprint(host_key,
4df30a2
-			    options.fingerprint_hash, SSH_FP_RANDOMART);
4df30a2
+			    options.fingerprint_hash[0], SSH_FP_RANDOMART);
4df30a2
 			if (fp == NULL || ra == NULL)
4df30a2
 				fatal("%s: sshkey_fingerprint fail", __func__);
13073f8
 			logit("Host key fingerprint is %s\n%s", fp, ra);
5b55d09
@@ -907,12 +907,6 @@ check_host_key(char *hostname, struct so
4df30a2
 			else
4df30a2
 				snprintf(msg1, sizeof(msg1), ".");
4df30a2
 			/* The default */
4df30a2
-			fp = sshkey_fingerprint(host_key,
4df30a2
-			    options.fingerprint_hash, SSH_FP_DEFAULT);
4df30a2
-			ra = sshkey_fingerprint(host_key,
4df30a2
-			    options.fingerprint_hash, SSH_FP_RANDOMART);
4df30a2
-			if (fp == NULL || ra == NULL)
4df30a2
-				fatal("%s: sshkey_fingerprint fail", __func__);
4df30a2
 			msg2[0] = '\0';
4df30a2
 			if (options.verify_host_key_dns) {
4df30a2
 				if (matching_host_key_dns)
5b55d09
@@ -926,16 +920,28 @@ check_host_key(char *hostname, struct so
4df30a2
 			}
4df30a2
 			snprintf(msg, sizeof(msg),
4df30a2
 			    "The authenticity of host '%.200s (%s)' can't be "
4df30a2
-			    "established%s\n"
4df30a2
-			    "%s key fingerprint is %s.%s%s\n%s"
4df30a2
+			    "established%s\n", host, ip, msg1);
6cf9b8e
+			for (i = 0; i < (u_int) options.num_fingerprint_hash; i++) {
4df30a2
+				fp = sshkey_fingerprint(host_key,
4df30a2
+				    options.fingerprint_hash[i], SSH_FP_DEFAULT);
4df30a2
+				ra = sshkey_fingerprint(host_key,
4df30a2
+				    options.fingerprint_hash[i], SSH_FP_RANDOMART);
4df30a2
+				if (fp == NULL || ra == NULL)
4df30a2
+					fatal("%s: sshkey_fingerprint fail", __func__);
4df30a2
+				len = strlen(msg);
4df30a2
+				snprintf(msg+len, sizeof(msg)-len,
4df30a2
+				    "%s key fingerprint is %s.%s%s\n%s",
4df30a2
+				    type, fp,
4df30a2
+				    options.visual_host_key ? "\n" : "",
4df30a2
+				    options.visual_host_key ? ra : "",
4df30a2
+				    msg2);
4df30a2
+				free(ra);
4df30a2
+				free(fp);
4df30a2
+			}
4df30a2
+			len = strlen(msg);
4df30a2
+			snprintf(msg+len, sizeof(msg)-len,
4df30a2
 			    "Are you sure you want to continue connecting "
4df30a2
-			    "(yes/no)? ",
4df30a2
-			    host, ip, msg1, type, fp,
4df30a2
-			    options.visual_host_key ? "\n" : "",
4df30a2
-			    options.visual_host_key ? ra : "",
4df30a2
-			    msg2);
4df30a2
-			free(ra);
4df30a2
-			free(fp);
4df30a2
+			    "(yes/no)? ");
4df30a2
 			if (!confirm(msg))
4df30a2
 				goto fail;
4df30a2
 			hostkey_trusted = 1; /* user explicitly confirmed */
5b55d09
@@ -1192,7 +1198,7 @@ verify_host_key(char *host, struct socka
4df30a2
 	struct sshkey *plain = NULL;
4df30a2
 
4df30a2
 	if ((fp = sshkey_fingerprint(host_key,
4df30a2
-	    options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) {
4df30a2
+	    options.fingerprint_hash[0], SSH_FP_DEFAULT)) == NULL) {
4df30a2
 		error("%s: fingerprint host key: %s", __func__, ssh_err(r));
4df30a2
 		r = -1;
4df30a2
 		goto out;
5b55d09
@@ -1200,7 +1206,7 @@ verify_host_key(char *host, struct socka
6cf9b8e
 
6cf9b8e
 	if (sshkey_is_cert(host_key)) {
6cf9b8e
 		if ((cafp = sshkey_fingerprint(host_key->cert->signature_key,
6cf9b8e
-		    options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) {
6cf9b8e
+		    options.fingerprint_hash[0], SSH_FP_DEFAULT)) == NULL) {
6cf9b8e
 			error("%s: fingerprint CA key: %s",
6cf9b8e
 			    __func__, ssh_err(r));
6cf9b8e
 			r = -1;
5b55d09
@@ -1369,9 +1375,9 @@ show_other_keys(struct hostkeys *hostkey
4df30a2
 		if (!lookup_key_in_hostkeys_by_type(hostkeys, type[i], &found))
4df30a2
 			continue;
4df30a2
 		fp = sshkey_fingerprint(found->key,
4df30a2
-		    options.fingerprint_hash, SSH_FP_DEFAULT);
4df30a2
+		    options.fingerprint_hash[0], SSH_FP_DEFAULT);
4df30a2
 		ra = sshkey_fingerprint(found->key,
4df30a2
-		    options.fingerprint_hash, SSH_FP_RANDOMART);
4df30a2
+		    options.fingerprint_hash[0], SSH_FP_RANDOMART);
4df30a2
 		if (fp == NULL || ra == NULL)
4df30a2
 			fatal("%s: sshkey_fingerprint fail", __func__);
4df30a2
 		logit("WARNING: %s key found for host %s\n"
5b55d09
@@ -1394,7 +1400,7 @@ warn_changed_key(struct sshkey *host_key
4df30a2
 {
4df30a2
 	char *fp;
4df30a2
 
4df30a2
-	fp = sshkey_fingerprint(host_key, options.fingerprint_hash,
4df30a2
+	fp = sshkey_fingerprint(host_key, options.fingerprint_hash[0],
4df30a2
 	    SSH_FP_DEFAULT);
4df30a2
 	if (fp == NULL)
4df30a2
 		fatal("%s: sshkey_fingerprint fail", __func__);
5b55d09
diff -up openssh/ssh-keysign.c.fingerprint openssh/ssh-keysign.c
5b55d09
--- openssh/ssh-keysign.c.fingerprint	2017-09-25 01:48:10.000000000 +0200
5b55d09
+++ openssh/ssh-keysign.c	2017-09-26 15:21:22.622477943 +0200
6cf9b8e
@@ -285,7 +285,7 @@ main(int argc, char **argv)
c4c52b0
 		}
c4c52b0
 	}
c4c52b0
 	if (!found) {
c4c52b0
-		if ((fp = sshkey_fingerprint(key, options.fingerprint_hash,
c4c52b0
+		if ((fp = sshkey_fingerprint(key, options.fingerprint_hash[0],
c4c52b0
 		    SSH_FP_DEFAULT)) == NULL)
13073f8
 			fatal("%s: sshkey_fingerprint failed", __progname);
c4c52b0
 		fatal("no matching hostkey found for key %s %s",