vishalmishra434 / rpms / openssh

Forked from rpms/openssh a month ago
Clone
Blob Blame History Raw
diff -up openssh-6.7p1/auth2-hostbased.c.fingerprint openssh-6.7p1/auth2-hostbased.c
--- openssh-6.7p1/auth2-hostbased.c.fingerprint	2014-07-18 06:11:25.000000000 +0200
+++ openssh-6.7p1/auth2-hostbased.c	2014-12-22 13:10:57.961878113 +0100
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-hostbased.c,v 1.18 2014/07/15 15:54:14 millert Exp $ */
+/* $OpenBSD: auth2-hostbased.c,v 1.19 2014/12/21 22:27:56 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -208,13 +208,14 @@ hostbased_key_allowed(struct passwd *pw,
 	if (host_status == HOST_OK) {
 		if (key_is_cert(key)) {
 			fp = key_fingerprint(key->cert->signature_key,
-			    SSH_FP_MD5, SSH_FP_HEX);
+			    options.fingerprint_hash, SSH_FP_DEFAULT);
 			verbose("Accepted certificate ID \"%s\" signed by "
 			    "%s CA %s from %s@%s", key->cert->key_id,
 			    key_type(key->cert->signature_key), fp,
 			    cuser, lookup);
 		} else {
-			fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+			fp = key_fingerprint(key, options.fingerprint_hash,
+			    SSH_FP_DEFAULT);
 			verbose("Accepted %s public key %s from %s@%s",
 			    key_type(key), fp, cuser, lookup);
 		}
diff -up openssh-6.7p1/auth2-pubkey.c.fingerprint openssh-6.7p1/auth2-pubkey.c
--- openssh-6.7p1/auth2-pubkey.c.fingerprint	2014-07-18 06:11:25.000000000 +0200
+++ openssh-6.7p1/auth2-pubkey.c	2014-12-22 13:13:56.446258343 +0100
@@ -213,7 +213,7 @@ pubkey_auth_info(Authctxt *authctxt, con
 
 	if (key_is_cert(key)) {
 		fp = key_fingerprint(key->cert->signature_key,
-		    SSH_FP_MD5, SSH_FP_HEX);
+		    options.fingerprint_hash, SSH_FP_DEFAULT);
 		auth_info(authctxt, "%s ID %s (serial %llu) CA %s %s%s%s", 
 		    key_type(key), key->cert->key_id,
 		    (unsigned long long)key->cert->serial,
@@ -221,7 +221,8 @@ pubkey_auth_info(Authctxt *authctxt, con
 		    extra == NULL ? "" : ", ", extra == NULL ? "" : extra);
 		free(fp);
 	} else {
-		fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+		fp = key_fingerprint(key, options.fingerprint_hash,
+		    SSH_FP_DEFAULT);
 		auth_info(authctxt, "%s %s%s%s", key_type(key), fp,
 		    extra == NULL ? "" : ", ", extra == NULL ? "" : extra);
 		free(fp);
@@ -365,8 +366,8 @@ check_authkeys_file(FILE *f, char *file,
 				continue;
 			if (!key_is_cert_authority)
 				continue;
-			fp = key_fingerprint(found, SSH_FP_MD5,
-			    SSH_FP_HEX);
+			fp = key_fingerprint(found, options.fingerprint_hash,
+			    SSH_FP_DEFAULT);
 			debug("matching CA found: file %s, line %lu, %s %s",
 			    file, linenum, key_type(found), fp);
 			/*
@@ -406,7 +407,8 @@ check_authkeys_file(FILE *f, char *file,
 			if (key_is_cert_authority)
 				continue;
 			found_key = 1;
-			fp = key_fingerprint(found, SSH_FP_MD5, SSH_FP_HEX);
+			fp = key_fingerprint(found, options.fingerprint_hash,
+			    SSH_FP_DEFAULT);
 			debug("matching key found: file %s, line %lu %s %s",
 			    file, linenum, key_type(found), fp);
 			free(fp);
@@ -432,7 +434,7 @@ user_cert_trusted_ca(struct passwd *pw,
 		return 0;
 
 	ca_fp = key_fingerprint(key->cert->signature_key,
-	    SSH_FP_MD5, SSH_FP_HEX);
+	    options.fingerprint_hash, SSH_FP_DEFAULT);
 
 	if (key_in_file(key->cert->signature_key,
 	    options.trusted_user_ca_keys, 1) != 1) {
diff -up openssh-6.7p1/auth.c.fingerprint openssh-6.7p1/auth.c
--- openssh-6.7p1/auth.c.fingerprint	2014-12-22 13:10:57.961878113 +0100
+++ openssh-6.7p1/auth.c	2014-12-22 13:27:18.105463774 +0100
@@ -702,7 +702,7 @@ auth_key_is_revoked(Key *key)
 	case 1:
  revoked:
 		/* Key revoked */
-		key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+		key_fp = key_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT);
 		error("WARNING: authentication attempt with a revoked "
 		    "%s key %s ", key_type(key), key_fp);
 		free(key_fp);
diff -up openssh-6.7p1/auth-rsa.c.fingerprint openssh-6.7p1/auth-rsa.c
--- openssh-6.7p1/auth-rsa.c.fingerprint	2014-07-18 06:11:25.000000000 +0200
+++ openssh-6.7p1/auth-rsa.c	2014-12-22 13:10:57.960878116 +0100
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth-rsa.c,v 1.88 2014/07/15 15:54:14 millert Exp $ */
+/* $OpenBSD: auth-rsa.c,v 1.89 2014/12/21 22:27:56 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -236,7 +236,8 @@ rsa_key_allowed_in_file(struct passwd *p
 			    "actual %d vs. announced %d.",
 			    file, linenum, BN_num_bits(key->rsa->n), bits);
 
-		fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+		fp = key_fingerprint(key, options.fingerprint_hash,
+		    SSH_FP_DEFAULT);
 		debug("matching key found: file %s, line %lu %s %s",
 		    file, linenum, key_type(key), fp);
 		free(fp);
diff -up openssh-6.7p1/digest.h.fingerprint openssh-6.7p1/digest.h
--- openssh-6.7p1/digest.h.fingerprint	2014-07-03 13:25:04.000000000 +0200
+++ openssh-6.7p1/digest.h	2014-12-22 13:10:57.961878113 +0100
@@ -1,4 +1,4 @@
-/* $OpenBSD: digest.h,v 1.6 2014/07/03 04:36:45 djm Exp $ */
+/* $OpenBSD: digest.h,v 1.7 2014/12/21 22:27:56 djm Exp $ */
 /*
  * Copyright (c) 2013 Damien Miller <djm@mindrot.org>
  *
@@ -33,6 +33,12 @@
 struct sshbuf;
 struct ssh_digest_ctx;
 
+/* Looks up a digest algorithm by name */
+int ssh_digest_alg_by_name(const char *name);
+
+/* Returns the algorithm name for a digest identifier */
+const char *ssh_digest_alg_name(int alg);
+
 /* Returns the algorithm's digest length in bytes or 0 for invalid algorithm */
 size_t ssh_digest_bytes(int alg);
 
diff -up openssh-6.7p1/digest-libc.c.fingerprint openssh-6.7p1/digest-libc.c
--- openssh-6.7p1/digest-libc.c.fingerprint	2014-07-02 07:28:03.000000000 +0200
+++ openssh-6.7p1/digest-libc.c	2014-12-22 13:10:57.961878113 +0100
@@ -1,4 +1,4 @@
-/* $OpenBSD: digest-libc.c,v 1.3 2014/06/24 01:13:21 djm Exp $ */
+/* $OpenBSD: digest-libc.c,v 1.4 2014/12/21 22:27:56 djm Exp $ */
 /*
  * Copyright (c) 2013 Damien Miller <djm@mindrot.org>
  * Copyright (c) 2014 Markus Friedl.  All rights reserved.
@@ -126,6 +126,26 @@ ssh_digest_by_alg(int alg)
 	return &(digests[alg]);
 }
 
+int
+ssh_digest_alg_by_name(const char *name)
+{
+	int alg;
+
+	for (alg = 0; alg < SSH_DIGEST_MAX; alg++) {
+		if (strcasecmp(name, digests[alg].name) == 0)
+			return digests[alg].id;
+	}
+	return -1;
+}
+
+const char *
+ssh_digest_alg_name(int alg)
+{
+	const struct ssh_digest *digest = ssh_digest_by_alg(alg);
+
+	return digest == NULL ? NULL : digest->name;
+}
+
 size_t
 ssh_digest_bytes(int alg)
 {
diff -up openssh-6.7p1/digest-openssl.c.fingerprint openssh-6.7p1/digest-openssl.c
--- openssh-6.7p1/digest-openssl.c.fingerprint	2014-07-17 01:01:26.000000000 +0200
+++ openssh-6.7p1/digest-openssl.c	2014-12-22 13:10:57.961878113 +0100
@@ -1,4 +1,4 @@
-/* $OpenBSD: digest-openssl.c,v 1.4 2014/07/03 03:26:43 djm Exp $ */
+/* $OpenBSD: digest-openssl.c,v 1.5 2014/12/21 22:27:56 djm Exp $ */
 /*
  * Copyright (c) 2013 Damien Miller <djm@mindrot.org>
  *
@@ -74,6 +74,26 @@ ssh_digest_by_alg(int alg)
 	return &(digests[alg]);
 }
 
+int
+ssh_digest_alg_by_name(const char *name)
+{
+	int alg;
+
+	for (alg = 0; digests[alg].id != -1; alg++) {
+		if (strcasecmp(name, digests[alg].name) == 0)
+			return digests[alg].id;
+	}
+	return -1;
+}
+
+const char *
+ssh_digest_alg_name(int alg)
+{
+	const struct ssh_digest *digest = ssh_digest_by_alg(alg);
+
+	return digest == NULL ? NULL : digest->name;
+}
+
 size_t
 ssh_digest_bytes(int alg)
 {
diff -up openssh-6.7p1/dns.c.fingerprint openssh-6.7p1/dns.c
--- openssh-6.7p1/dns.c.fingerprint	2014-07-02 07:28:03.000000000 +0200
+++ openssh-6.7p1/dns.c	2014-12-22 13:10:57.962878109 +0100
@@ -1,4 +1,4 @@
-/* $OpenBSD: dns.c,v 1.31 2014/06/24 01:13:21 djm Exp $ */
+/* $OpenBSD: dns.c,v 1.32 2014/12/21 22:27:56 djm Exp $ */
 
 /*
  * Copyright (c) 2003 Wesley Griffin. All rights reserved.
@@ -41,6 +41,7 @@
 #include "key.h"
 #include "dns.h"
 #include "log.h"
+#include "digest.h"
 
 static const char *errset_text[] = {
 	"success",		/* 0 ERRSET_SUCCESS */
@@ -80,7 +81,7 @@ dns_read_key(u_int8_t *algorithm, u_int8
     u_char **digest, u_int *digest_len, Key *key)
 {
 	int success = 0;
-	enum fp_type fp_type = 0;
+	int fp_alg = -1;
 
 	switch (key->type) {
 	case KEY_RSA:
@@ -110,17 +111,17 @@ dns_read_key(u_int8_t *algorithm, u_int8
 
 	switch (*digest_type) {
 	case SSHFP_HASH_SHA1:
-		fp_type = SSH_FP_SHA1;
+		fp_alg = SSH_DIGEST_SHA1;
 		break;
 	case SSHFP_HASH_SHA256:
-		fp_type = SSH_FP_SHA256;
+		fp_alg = SSH_DIGEST_SHA256;
 		break;
 	default:
 		*digest_type = SSHFP_HASH_RESERVED; /* 0 */
 	}
 
 	if (*algorithm && *digest_type) {
-		*digest = key_fingerprint_raw(key, fp_type, digest_len);
+		*digest = key_fingerprint_raw(key, fp_alg, digest_len);
 		if (*digest == NULL)
 			fatal("dns_read_key: null from key_fingerprint_raw()");
 		success = 1;
diff -up openssh-6.7p1/key.c.fingerprint openssh-6.7p1/key.c
--- openssh-6.7p1/key.c.fingerprint	2014-07-23 01:40:47.000000000 +0200
+++ openssh-6.7p1/key.c	2014-12-22 13:10:57.962878109 +0100
@@ -40,8 +40,7 @@ key_new_private(int type)
 }
 
 u_char*
-key_fingerprint_raw(const Key *k, enum fp_type dgst_type,
-    u_int *dgst_raw_length)
+key_fingerprint_raw(const Key *k, int dgst_alg, u_int *dgst_raw_length)
 {
 	u_char *ret = NULL;
 	size_t dlen;
@@ -49,7 +48,7 @@ key_fingerprint_raw(const Key *k, enum f
 
 	if (dgst_raw_length != NULL)
 		*dgst_raw_length = 0;
-	if ((r = sshkey_fingerprint_raw(k, dgst_type, &ret, &dlen)) != 0)
+	if ((r = sshkey_fingerprint_raw(k, dgst_alg, &ret, &dlen)) != 0)
 		fatal("%s: %s", __func__, ssh_err(r));
 	if (dlen > INT_MAX)
 		fatal("%s: giant len %zu", __func__, dlen);
diff -up openssh-6.7p1/key.h.fingerprint openssh-6.7p1/key.h
--- openssh-6.7p1/key.h.fingerprint	2014-08-21 02:48:41.000000000 +0200
+++ openssh-6.7p1/key.h	2014-12-22 13:10:57.962878109 +0100
@@ -67,7 +67,7 @@ void	 key_add_private(Key *);
 Key	*key_new_private(int);
 void	 key_free(Key *);
 Key	*key_demote(const Key *);
-u_char	*key_fingerprint_raw(const Key *, enum fp_type, u_int *);
+u_char	*key_fingerprint_raw(const Key *, int, u_int *);
 int	 key_write(const Key *, FILE *);
 int	 key_read(Key *, char **);
 
diff -up openssh-6.7p1/krl.c.fingerprint openssh-6.7p1/krl.c
--- openssh-6.7p1/krl.c.fingerprint	2014-12-22 13:10:57.962878109 +0100
+++ openssh-6.7p1/krl.c	2014-12-22 13:24:45.969002948 +0100
@@ -36,6 +36,7 @@
 #include "misc.h"
 #include "log.h"
 #include "xmalloc.h"
+#include "digest.h"
 
 #include "krl.h"
 
@@ -406,7 +407,7 @@ ssh_krl_revoke_key_sha1(struct ssh_krl *
 	u_int len;
 
 	debug3("%s: revoke type %s by sha1", __func__, key_type(key));
-	if ((blob = key_fingerprint_raw(key, SSH_FP_SHA1, &len)) == NULL)
+	if ((blob = key_fingerprint_raw(key, SSH_DIGEST_SHA1, &len)) == NULL)
 		return -1;
 	return revoke_blob(&krl->revoked_sha1s, blob, len);
 }
@@ -1119,7 +1120,7 @@ is_key_revoked(struct ssh_krl *krl, cons
 
 	/* Check explicitly revoked hashes first */
 	memset(&rb, 0, sizeof(rb));
-	if ((rb.blob = key_fingerprint_raw(key, SSH_FP_SHA1, &rb.len)) == NULL)
+	if ((rb.blob = key_fingerprint_raw(key, SSH_DIGEST_SHA1, &rb.len)) == NULL)
 		return -1;
 	erb = RB_FIND(revoked_blob_tree, &krl->revoked_sha1s, &rb);
 	free(rb.blob);
diff -up openssh-6.7p1/readconf.c.fingerprint openssh-6.7p1/readconf.c
--- openssh-6.7p1/readconf.c.fingerprint	2014-07-18 06:11:26.000000000 +0200
+++ openssh-6.7p1/readconf.c	2014-12-22 13:20:33.488879658 +0100
@@ -56,6 +56,7 @@
 #include "kex.h"
 #include "mac.h"
 #include "uidswap.h"
+#include "digest.h"
 
 /* Format of the configuration file:
 
@@ -151,6 +152,7 @@ typedef enum {
 	oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
 	oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
 	oStreamLocalBindMask, oStreamLocalBindUnlink,
+	oFingerprintHash,
 	oIgnoredUnknownOption, oDeprecated, oUnsupported
 } OpCodes;
 
@@ -265,6 +267,7 @@ static struct {
 	{ "canonicalizepermittedcnames", oCanonicalizePermittedCNAMEs },
 	{ "streamlocalbindmask", oStreamLocalBindMask },
 	{ "streamlocalbindunlink", oStreamLocalBindUnlink },
+	{ "fingerprinthash", oFingerprintHash },
 	{ "ignoreunknown", oIgnoreUnknown },
 
 	{ NULL, oBadOption }
@@ -1097,6 +1100,9 @@ parse_int:
 			options->hostkeyalgorithms = xstrdup(arg);
 		break;
 
+	case oFingerprintHash:
+		return ssh_digest_alg_name(val);
+
 	case oProtocol:
 		intptr = &options->protocol;
 		arg = strdelim(&s);
@@ -1433,6 +1439,18 @@ parse_int:
 		intptr = &options->fwd_opts.streamlocal_bind_unlink;
 		goto parse_flag;
 
+	case oFingerprintHash:
+		arg = strdelim(&s);
+		if (!arg || *arg == '\0')
+			fatal("%.200s line %d: Missing argument.",
+			    filename, linenum);
+		if ((value = ssh_digest_alg_by_name(arg)) == -1)
+			fatal("%.200s line %d: Invalid hash algorithm \"%s\".",
+			    filename, linenum, arg);
+		if (*activep)
+			options->fingerprint_hash = value;
+		break;
+
 	case oDeprecated:
 		debug("%s line %d: Deprecated option \"%s\"",
 		    filename, linenum, keyword);
@@ -1609,6 +1627,7 @@ initialize_options(Options * options)
 	options->canonicalize_max_dots = -1;
 	options->canonicalize_fallback_local = -1;
 	options->canonicalize_hostname = -1;
+	options->fingerprint_hash = -1;
 }
 
 /*
@@ -1786,6 +1805,9 @@ fill_default_options(Options * options)
 		options->canonicalize_fallback_local = 1;
 	if (options->canonicalize_hostname == -1)
 		options->canonicalize_hostname = SSH_CANONICALISE_NO;
+	if (options->fingerprint_hash == -1)
+		options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
+
 #define CLEAR_ON_NONE(v) \
 	do { \
 		if (option_clear_or_none(v)) { \
diff -up openssh-6.7p1/readconf.h.fingerprint openssh-6.7p1/readconf.h
--- openssh-6.7p1/readconf.h.fingerprint	2014-12-22 13:10:57.963878106 +0100
+++ openssh-6.7p1/readconf.h	2014-12-22 13:14:24.075162395 +0100
@@ -144,6 +144,8 @@ typedef struct {
 	int	num_permitted_cnames;
 	struct allowed_cname permitted_cnames[MAX_CANON_DOMAINS];
 
+	int	fingerprint_hash;
+
 	char	*ignored_unknown; /* Pattern list of unknown tokens to ignore */
 }       Options;
 
diff -up openssh-6.7p1/servconf.c.fingerprint openssh-6.7p1/servconf.c
--- openssh-6.7p1/servconf.c.fingerprint	2014-07-18 06:11:26.000000000 +0200
+++ openssh-6.7p1/servconf.c	2014-12-22 13:25:22.626875655 +0100
@@ -54,6 +54,7 @@
 #include "packet.h"
 #include "hostfile.h"
 #include "auth.h"
+#include "digest.h"
 
 static void add_listen_addr(ServerOptions *, char *, int);
 static void add_one_listen_addr(ServerOptions *, char *, int);
@@ -157,6 +158,7 @@ initialize_server_options(ServerOptions
 	options->ip_qos_interactive = -1;
 	options->ip_qos_bulk = -1;
 	options->version_addendum = NULL;
+	options->fingerprint_hash = -1;
 }
 
 void
@@ -312,6 +314,8 @@ fill_default_server_options(ServerOption
 		options->fwd_opts.streamlocal_bind_mask = 0177;
 	if (options->fwd_opts.streamlocal_bind_unlink == -1)
 		options->fwd_opts.streamlocal_bind_unlink = 0;
+	if (options->fingerprint_hash == -1)
+		options->fingerprint_hash = SSH_FP_HASH_DEFAULT;
 	/* Turn privilege separation on by default */
 	if (use_privsep == -1)
 		use_privsep = PRIVSEP_NOSANDBOX;
@@ -361,7 +365,7 @@ typedef enum {
 	sAuthorizedKeysCommand, sAuthorizedKeysCommandUser,
 	sAuthenticationMethods, sHostKeyAgent, sPermitUserRC,
 	sStreamLocalBindMask, sStreamLocalBindUnlink,
-	sAllowStreamLocalForwarding,
+	sAllowStreamLocalForwarding, sFingerprintHash,
 	sDeprecated, sUnsupported
 } ServerOpCodes;
 
@@ -492,6 +496,7 @@ static struct {
 	{ "streamlocalbindmask", sStreamLocalBindMask, SSHCFG_ALL },
 	{ "streamlocalbindunlink", sStreamLocalBindUnlink, SSHCFG_ALL },
 	{ "allowstreamlocalforwarding", sAllowStreamLocalForwarding, SSHCFG_ALL },
+	{ "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL },
 	{ NULL, sBadOption, 0 }
 };
 
@@ -1663,6 +1668,18 @@ process_server_config_line(ServerOptions
 		intptr = &options->fwd_opts.streamlocal_bind_unlink;
 		goto parse_flag;
 
+	case sFingerprintHash:
+		arg = strdelim(&cp);
+		if (!arg || *arg == '\0')
+			fatal("%.200s line %d: Missing argument.",
+			    filename, linenum);
+		if ((value = ssh_digest_alg_by_name(arg)) == -1)
+			fatal("%.200s line %d: Invalid hash algorithm \"%s\".",
+			    filename, linenum, arg);
+		if (*activep)
+			options->fingerprint_hash = value;
+		break;
+
 	case sDeprecated:
 		logit("%s line %d: Deprecated option %s",
 		    filename, linenum, arg);
@@ -1905,6 +1922,8 @@ fmt_intarg(ServerOpCodes code, int val)
 		return fmt_multistate_int(val, multistate_tcpfwd);
 	case sAllowStreamLocalForwarding:
 		return fmt_multistate_int(val, multistate_tcpfwd);
+	case sFingerprintHash:
+		return ssh_digest_alg_name(val);
 	case sProtocol:
 		switch (val) {
 		case SSH_PROTO_1:
@@ -2066,6 +2085,7 @@ dump_config(ServerOptions *o)
 	dump_cfg_fmtint(sAllowTcpForwarding, o->allow_tcp_forwarding);
 	dump_cfg_fmtint(sAllowStreamLocalForwarding, o->allow_streamlocal_forwarding);
 	dump_cfg_fmtint(sUsePrivilegeSeparation, use_privsep);
+	dump_cfg_fmtint(sFingerprintHash, o->fingerprint_hash);
 
 	/* string arguments */
 	dump_cfg_string(sPidFile, o->pid_file);
diff -up openssh-6.7p1/servconf.h.fingerprint openssh-6.7p1/servconf.h
--- openssh-6.7p1/servconf.h.fingerprint	2014-07-18 06:11:26.000000000 +0200
+++ openssh-6.7p1/servconf.h	2014-12-22 13:10:57.964878102 +0100
@@ -1,4 +1,4 @@
-/* $OpenBSD: servconf.h,v 1.114 2014/07/15 15:54:14 millert Exp $ */
+/* $OpenBSD: servconf.h,v 1.115 2014/12/21 22:27:56 djm Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -185,6 +185,8 @@ typedef struct {
 
 	u_int	num_auth_methods;
 	char   *auth_methods[MAX_AUTH_METHODS];
+
+	int	fingerprint_hash;
 }       ServerOptions;
 
 /* Information about the incoming connection as used by Match */
diff -up openssh-6.7p1/ssh.1.fingerprint openssh-6.7p1/ssh.1
--- openssh-6.7p1/ssh.1.fingerprint	2014-07-30 04:32:28.000000000 +0200
+++ openssh-6.7p1/ssh.1	2014-12-22 13:10:57.967878092 +0100
@@ -1083,7 +1083,7 @@ Fingerprints can be determined using
 If the fingerprint is already known, it can be matched
 and the key can be accepted or rejected.
 Because of the difficulty of comparing host keys
-just by looking at hex strings,
+just by looking at fingerprint strings,
 there is also support to compare host keys visually,
 using
 .Em random art .
diff -up openssh-6.7p1/ssh-add.1.fingerprint openssh-6.7p1/ssh-add.1
--- openssh-6.7p1/ssh-add.1.fingerprint	2013-12-18 07:46:28.000000000 +0100
+++ openssh-6.7p1/ssh-add.1	2014-12-22 13:10:57.964878102 +0100
@@ -44,6 +44,7 @@
 .Sh SYNOPSIS
 .Nm ssh-add
 .Op Fl cDdkLlXx
+.Op Fl E Ar fingerprint_hash
 .Op Fl t Ar life
 .Op Ar
 .Nm ssh-add
@@ -108,6 +109,14 @@ If no public key is found at a given pat
 will append
 .Pa .pub
 and retry.
+.It Fl E Ar fingerprint_hash
+Specifies the hash algorithm used when displaying key fingerprints.
+Valid options are:
+.Dq md5
+and
+.Dq sha256 .
+The default is
+.Dq sha256 .
 .It Fl e Ar pkcs11
 Remove keys provided by the PKCS#11 shared library
 .Ar pkcs11 .
diff -up openssh-6.7p1/ssh-add.c.fingerprint openssh-6.7p1/ssh-add.c
--- openssh-6.7p1/ssh-add.c.fingerprint	2014-07-11 01:19:05.000000000 +0200
+++ openssh-6.7p1/ssh-add.c	2014-12-22 13:10:57.965878099 +0100
@@ -63,6 +63,7 @@
 #include "pathnames.h"
 #include "misc.h"
 #include "ssherr.h"
+#include "digest.h"
 
 /* argv0 */
 extern char *__progname;
@@ -79,6 +80,8 @@ static char *default_files[] = {
 	NULL
 };
 
+static int fingerprint_hash = SSH_FP_HASH_DEFAULT;
+
 /* Default lifetime (0 == forever) */
 static int lifetime = 0;
 
@@ -340,8 +343,8 @@ list_identities(AuthenticationConnection
 		    key = ssh_get_next_identity(ac, &comment, version)) {
 			had_identities = 1;
 			if (do_fp) {
-				fp = key_fingerprint(key, SSH_FP_MD5,
-				    SSH_FP_HEX);
+				fp = key_fingerprint(key, fingerprint_hash,
+				    SSH_FP_DEFAULT);
 				printf("%d %s %s (%s)\n",
 				    key_size(key), fp, comment, key_type(key));
 				free(fp);
@@ -408,6 +411,7 @@ usage(void)
 	fprintf(stderr, "usage: %s [options] [file ...]\n", __progname);
 	fprintf(stderr, "Options:\n");
 	fprintf(stderr, "  -l          List fingerprints of all identities.\n");
+	fprintf(stderr, "  -E hash     Specify hash algorithm used for fingerprints.\n");
 	fprintf(stderr, "  -L          List public key parameters of all identities.\n");
 	fprintf(stderr, "  -k          Load only keys and not certificates.\n");
 	fprintf(stderr, "  -c          Require confirmation to sign using identities\n");
@@ -428,6 +432,7 @@ main(int argc, char **argv)
 	AuthenticationConnection *ac = NULL;
 	char *pkcs11provider = NULL;
 	int i, ch, deleting = 0, ret = 0, key_only = 0;
+	int xflag = 0, lflag = 0, Dflag = 0;
 
 	/* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
 	sanitise_stdfd();
@@ -446,21 +451,28 @@ main(int argc, char **argv)
 		    "Could not open a connection to your authentication agent.\n");
 		exit(2);
 	}
-	while ((ch = getopt(argc, argv, "klLcdDxXe:s:t:")) != -1) {
+	while ((ch = getopt(argc, argv, "klLcdDxXE:e:s:t:")) != -1) {
 		switch (ch) {
+		case 'E':
+			fingerprint_hash = ssh_digest_alg_by_name(optarg);
+			if (fingerprint_hash == -1)
+				fatal("Invalid hash algorithm \"%s\"", optarg);
+			break;
 		case 'k':
 			key_only = 1;
 			break;
 		case 'l':
 		case 'L':
-			if (list_identities(ac, ch == 'l' ? 1 : 0) == -1)
-				ret = 1;
-			goto done;
+			if (lflag != 0)
+				fatal("-%c flag already specified", lflag);
+			lflag = ch;
+			break;
 		case 'x':
 		case 'X':
-			if (lock_agent(ac, ch == 'x' ? 1 : 0) == -1)
-				ret = 1;
-			goto done;
+			if (xflag != 0)
+				fatal("-%c flag already specified", xflag);
+			xflag = ch;
+			break;
 		case 'c':
 			confirm = 1;
 			break;
@@ -468,9 +480,8 @@ main(int argc, char **argv)
 			deleting = 1;
 			break;
 		case 'D':
-			if (delete_all(ac) == -1)
-				ret = 1;
-			goto done;
+			Dflag = 1;
+			break;
 		case 's':
 			pkcs11provider = optarg;
 			break;
@@ -491,6 +502,23 @@ main(int argc, char **argv)
 			goto done;
 		}
 	}
+
+	if ((xflag != 0) + (lflag != 0) + (Dflag != 0) > 1)
+		fatal("Invalid combination of actions");
+	else if (xflag) {
+		if (lock_agent(ac, xflag == 'x' ? 1 : 0) == -1)
+			ret = 1;
+		goto done;
+	} else if (lflag) {
+		if (list_identities(ac, lflag == 'l' ? 1 : 0) == -1)
+			ret = 1;
+		goto done;
+	} else if (Dflag) {
+		if (delete_all(ac) == -1)
+			ret = 1;
+		goto done;
+	}
+
 	argc -= optind;
 	argv += optind;
 	if (pkcs11provider != NULL) {
diff -up openssh-6.7p1/ssh-agent.1.fingerprint openssh-6.7p1/ssh-agent.1
--- openssh-6.7p1/ssh-agent.1.fingerprint	2014-04-20 05:25:09.000000000 +0200
+++ openssh-6.7p1/ssh-agent.1	2014-12-22 13:10:57.965878099 +0100
@@ -45,6 +45,7 @@
 .Op Fl c | s
 .Op Fl d
 .Op Fl a Ar bind_address
+.Op Fl E Ar fingerprint_hash
 .Op Fl t Ar life
 .Op Ar command Op Ar arg ...
 .Nm ssh-agent
@@ -96,6 +97,14 @@ Debug mode.
 When this option is specified
 .Nm
 will not fork.
+.It Fl E Ar fingerprint_hash
+Specifies the hash algorithm used when displaying key fingerprints.
+Valid options are:
+.Dq md5
+and
+.Dq sha256 .
+The default is
+.Dq sha256 .
 .It Fl k
 Kill the current agent (given by the
 .Ev SSH_AGENT_PID
diff -up openssh-6.7p1/ssh-agent.c.fingerprint openssh-6.7p1/ssh-agent.c
--- openssh-6.7p1/ssh-agent.c.fingerprint	2014-07-30 04:32:46.000000000 +0200
+++ openssh-6.7p1/ssh-agent.c	2014-12-22 13:10:57.965878099 +0100
@@ -142,6 +142,8 @@ extern char *__progname;
 /* Default lifetime in seconds (0 == forever) */
 static long lifetime = 0;
 
+static int fingerprint_hash = SSH_FP_HASH_DEFAULT;
+
 static void
 close_socket(SocketEntry *e)
 {
@@ -203,7 +205,7 @@ confirm_key(Identity *id)
 	char *p;
 	int ret = -1;
 
-	p = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX);
+	p = key_fingerprint(id->key, fingerprint_hash, SSH_FP_DEFAULT);
 	if (ask_permission("Allow use of key %s?\nKey fingerprint %s.",
 	    id->comment, p))
 		ret = 0;
@@ -1026,7 +1028,7 @@ usage(void)
 {
 	fprintf(stderr,
 	    "usage: ssh-agent [-c | -s] [-d] [-a bind_address] [-t life]\n"
-	    "                 [command [arg ...]]\n"
+	    "                 [-E fingerprint_hash] [command [arg ...]]\n"
 	    "       ssh-agent [-c | -s] -k\n");
 	exit(1);
 }
@@ -1069,8 +1071,13 @@ main(int ac, char **av)
 	__progname = ssh_get_progname(av[0]);
 	seed_rng();
 
-	while ((ch = getopt(ac, av, "cdksa:t:")) != -1) {
+	while ((ch = getopt(ac, av, "cdksE:a:t:")) != -1) {
 		switch (ch) {
+		case 'E':
+			fingerprint_hash = ssh_digest_alg_by_name(optarg);
+			if (fingerprint_hash == -1)
+				fatal("Invalid hash algorithm \"%s\"", optarg);
+			break;
 		case 'c':
 			if (s_flag)
 				usage();
diff -up openssh-6.7p1/sshconnect2.c.fingerprint openssh-6.7p1/sshconnect2.c
--- openssh-6.7p1/sshconnect2.c.fingerprint	2014-07-18 06:11:27.000000000 +0200
+++ openssh-6.7p1/sshconnect2.c	2014-12-22 13:10:57.968878088 +0100
@@ -582,7 +582,7 @@ input_userauth_pk_ok(int type, u_int32_t
 		    key->type, pktype);
 		goto done;
 	}
-	fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+	fp = key_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT);
 	debug2("input_userauth_pk_ok: fp %s", fp);
 	free(fp);
 
@@ -991,7 +991,7 @@ sign_and_send_pubkey(Authctxt *authctxt,
 	int have_sig = 1;
 	char *fp;
 
-	fp = key_fingerprint(id->key, SSH_FP_MD5, SSH_FP_HEX);
+	fp = key_fingerprint(id->key, options.fingerprint_hash, SSH_FP_DEFAULT);
 	debug3("sign_and_send_pubkey: %s %s", key_type(id->key), fp);
 	free(fp);
 
diff -up openssh-6.7p1/sshconnect.c.fingerprint openssh-6.7p1/sshconnect.c
--- openssh-6.7p1/sshconnect.c.fingerprint	2014-07-18 06:11:26.000000000 +0200
+++ openssh-6.7p1/sshconnect.c	2014-12-22 13:15:28.371939131 +0100
@@ -915,9 +915,10 @@ check_host_key(char *hostname, struct so
 				    "key for IP address '%.128s' to the list "
 				    "of known hosts.", type, ip);
 		} else if (options.visual_host_key) {
-			fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
-			ra = key_fingerprint(host_key, SSH_FP_MD5,
-			    SSH_FP_RANDOMART);
+			fp = key_fingerprint(host_key,
+			    options.fingerprint_hash, SSH_FP_DEFAULT);
+			ra = key_fingerprint(host_key,
+			    options.fingerprint_hash, SSH_FP_RANDOMART);
 			logit("Host key fingerprint is %s\n%s\n", fp, ra);
 			free(ra);
 			free(fp);
@@ -956,9 +957,10 @@ check_host_key(char *hostname, struct so
 			else
 				snprintf(msg1, sizeof(msg1), ".");
 			/* The default */
-			fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
-			ra = key_fingerprint(host_key, SSH_FP_MD5,
-			    SSH_FP_RANDOMART);
+			fp = key_fingerprint(host_key,
+			    options.fingerprint_hash, SSH_FP_DEFAULT);
+			ra = key_fingerprint(host_key,
+			    options.fingerprint_hash, SSH_FP_RANDOMART);
 			msg2[0] = '\0';
 			if (options.verify_host_key_dns) {
 				if (matching_host_key_dns)
@@ -1222,7 +1224,7 @@ verify_host_key(char *host, struct socka
 	char *fp;
 	Key *plain = NULL;
 
-	fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
+	fp = key_fingerprint(host_key, options.fingerprint_hash, SSH_FP_DEFAULT);
 	debug("Server host key: %s %s", key_type(host_key), fp);
 	free(fp);
 
@@ -1356,8 +1358,10 @@ show_other_keys(struct hostkeys *hostkey
 			continue;
 		if (!lookup_key_in_hostkeys_by_type(hostkeys, type[i], &found))
 			continue;
-		fp = key_fingerprint(found->key, SSH_FP_MD5, SSH_FP_HEX);
-		ra = key_fingerprint(found->key, SSH_FP_MD5, SSH_FP_RANDOMART);
+		fp = key_fingerprint(found->key,
+		    options.fingerprint_hash, SSH_FP_DEFAULT);
+		ra = key_fingerprint(found->key,
+		    options.fingerprint_hash, SSH_FP_RANDOMART);
 		logit("WARNING: %s key found for host %s\n"
 		    "in %s:%lu\n"
 		    "%s key fingerprint %s.",
@@ -1378,7 +1382,8 @@ warn_changed_key(Key *host_key)
 {
 	char *fp;
 
-	fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
+	fp = key_fingerprint(host_key, options.fingerprint_hash,
+	    SSH_FP_DEFAULT);
 
 	error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
 	error("@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @");
diff -up openssh-6.7p1/sshd_config.5.fingerprint openssh-6.7p1/sshd_config.5
--- openssh-6.7p1/sshd_config.5.fingerprint	2014-10-03 01:24:57.000000000 +0200
+++ openssh-6.7p1/sshd_config.5	2014-12-22 13:10:57.968878088 +0100
@@ -483,6 +483,15 @@ and finally
 See PATTERNS in
 .Xr ssh_config 5
 for more information on patterns.
+.It Cm FingerprintHash
+Specifies the hash algorithm used when logging key fingerprints.
+Valid options are:
+.Dq md5
+and
+.Dq sha256 .
+The default is
+.Dq sha256 .
+.Pp
 .It Cm ForceCommand
 Forces the execution of the command specified by
 .Cm ForceCommand ,
diff -up openssh-6.7p1/sshkey.c.fingerprint openssh-6.7p1/sshkey.c
--- openssh-6.7p1/sshkey.c.fingerprint	2014-07-21 17:07:11.000000000 +0200
+++ openssh-6.7p1/sshkey.c	2014-12-22 13:10:57.969878085 +0100
@@ -29,6 +29,7 @@
 
 #include <sys/param.h>
 #include <sys/types.h>
+#include <netinet/in.h>
 
 #include <openssl/evp.h>
 #include <openssl/err.h>
@@ -852,29 +853,18 @@ sshkey_plain_to_blob(const struct sshkey
 }
 
 int
-sshkey_fingerprint_raw(const struct sshkey *k, enum sshkey_fp_type dgst_type,
+sshkey_fingerprint_raw(const struct sshkey *k, int dgst_alg,
     u_char **retp, size_t *lenp)
 {
 	u_char *blob = NULL, *ret = NULL;
 	size_t blob_len = 0;
-	int hash_alg = -1, r = SSH_ERR_INTERNAL_ERROR;
+	int r = SSH_ERR_INTERNAL_ERROR;
 
 	if (retp != NULL)
 		*retp = NULL;
 	if (lenp != NULL)
 		*lenp = 0;
-
-	switch (dgst_type) {
-	case SSH_FP_MD5:
-		hash_alg = SSH_DIGEST_MD5;
-		break;
-	case SSH_FP_SHA1:
-		hash_alg = SSH_DIGEST_SHA1;
-		break;
-	case SSH_FP_SHA256:
-		hash_alg = SSH_DIGEST_SHA256;
-		break;
-	default:
+	if (ssh_digest_bytes(dgst_alg) == 0) {
 		r = SSH_ERR_INVALID_ARGUMENT;
 		goto out;
 	}
@@ -899,7 +889,7 @@ sshkey_fingerprint_raw(const struct sshk
 		r = SSH_ERR_ALLOC_FAIL;
 		goto out;
 	}
-	if ((r = ssh_digest_memory(hash_alg, blob, blob_len,
+	if ((r = ssh_digest_memory(dgst_alg, blob, blob_len,
 	    ret, SSH_DIGEST_MAX_LENGTH)) != 0)
 		goto out;
 	/* success */
@@ -908,7 +898,7 @@ sshkey_fingerprint_raw(const struct sshk
 		ret = NULL;
 	}
 	if (lenp != NULL)
-		*lenp = ssh_digest_bytes(hash_alg);
+		*lenp = ssh_digest_bytes(dgst_alg);
 	r = 0;
  out:
 	free(ret);
@@ -920,21 +910,45 @@ sshkey_fingerprint_raw(const struct sshk
 }
 
 static char *
-fingerprint_hex(u_char *dgst_raw, size_t dgst_raw_len)
+fingerprint_b64(const char *alg, u_char *dgst_raw, size_t dgst_raw_len)
 {
-	char *retval;
-	size_t i;
+	char *ret;
+	size_t plen = strlen(alg) + 1;
+	size_t rlen = ((dgst_raw_len + 2) / 3) * 4 + plen + 1;
+	int r;
 
-	if ((retval = calloc(1, dgst_raw_len * 3 + 1)) == NULL)
+	if (dgst_raw_len > 65536 || (ret = calloc(1, rlen)) == NULL)
+		return NULL;
+	strlcpy(ret, alg, rlen);
+	strlcat(ret, ":", rlen);
+	if (dgst_raw_len == 0)
+		return ret;
+	if ((r = b64_ntop(dgst_raw, dgst_raw_len,
+	    ret + plen, rlen - plen)) == -1) {
+		explicit_bzero(ret, rlen);
+		free(ret);
 		return NULL;
-	for (i = 0; i < dgst_raw_len; i++) {
-		char hex[4];
-		snprintf(hex, sizeof(hex), "%02x:", dgst_raw[i]);
-		strlcat(retval, hex, dgst_raw_len * 3 + 1);
 	}
+	/* Trim padding characters from end */
+	ret[strcspn(ret, "=")] = '\0';
+	return ret;
+}
+
+static char *
+fingerprint_hex(const char *alg, u_char *dgst_raw, size_t dgst_raw_len)
+{
+	char *retval, hex[5];
+	size_t i, rlen = dgst_raw_len * 3 + strlen(alg) + 2;
 
-	/* Remove the trailing ':' character */
-	retval[(dgst_raw_len * 3) - 1] = '\0';
+	if (dgst_raw_len > 65536 || (retval = calloc(1, rlen)) == NULL)
+		return NULL;
+	strlcpy(retval, alg, rlen);
+	strlcat(retval, ":", rlen);
+	for (i = 0; i < dgst_raw_len; i++) {
+		snprintf(hex, sizeof(hex), "%s%02x",
+		    i > 0 ? ":" : "", dgst_raw[i]);
+		strlcat(retval, hex, rlen);
+	}
 	return retval;
 }
 
@@ -1020,7 +1034,7 @@ fingerprint_bubblebabble(u_char *dgst_ra
 #define	FLDSIZE_Y	(FLDBASE + 1)
 #define	FLDSIZE_X	(FLDBASE * 2 + 1)
 static char *
-fingerprint_randomart(u_char *dgst_raw, size_t dgst_raw_len,
+fingerprint_randomart(const char *alg, u_char *dgst_raw, size_t dgst_raw_len,
     const struct sshkey *k)
 {
 	/*
@@ -1028,9 +1042,9 @@ fingerprint_randomart(u_char *dgst_raw,
 	 * intersects with itself.  Matter of taste.
 	 */
 	char	*augmentation_string = " .o+=*BOX@%&#/^SE";
-	char	*retval, *p, title[FLDSIZE_X];
+	char	*retval, *p, title[FLDSIZE_X], hash[FLDSIZE_X];
 	u_char	 field[FLDSIZE_X][FLDSIZE_Y];
-	size_t	 i, tlen;
+	size_t	 i, tlen, hlen;
 	u_int	 b;
 	int	 x, y, r;
 	size_t	 len = strlen(augmentation_string) - 1;
@@ -1075,8 +1089,12 @@ fingerprint_randomart(u_char *dgst_raw,
 		sshkey_type(k), sshkey_size(k));
 	/* If [type size] won't fit, then try [type]; fits "[ED25519-CERT]" */
 	if (r < 0 || r > (int)sizeof(title))
-		snprintf(title, sizeof(title), "[%s]", sshkey_type(k));
-	tlen = strlen(title);
+		r = snprintf(title, sizeof(title), "[%s]", sshkey_type(k));
+	tlen = (r <= 0) ? 0 : strlen(title);
+
+	/* assemble hash ID. */
+	r = snprintf(hash, sizeof(hash), "[%s]", alg);
+	hlen = (r <= 0) ? 0 : strlen(hash);
 
 	/* output upper border */
 	p = retval;
@@ -1085,7 +1103,7 @@ fingerprint_randomart(u_char *dgst_raw,
 		*p++ = '-';
 	memcpy(p, title, tlen);
 	p += tlen;
-	for (i = p - retval - 1; i < FLDSIZE_X; i++)
+	for (i += tlen; i < FLDSIZE_X; i++)
 		*p++ = '-';
 	*p++ = '+';
 	*p++ = '\n';
@@ -1101,7 +1119,11 @@ fingerprint_randomart(u_char *dgst_raw,
 
 	/* output lower border */
 	*p++ = '+';
-	for (i = 0; i < FLDSIZE_X; i++)
+	for (i = 0; i < (FLDSIZE_X - hlen) / 2; i++)
+		*p++ = '-';
+	memcpy(p, hash, hlen);
+	p += hlen;
+	for (i += hlen; i < FLDSIZE_X; i++)
 		*p++ = '-';
 	*p++ = '+';
 
@@ -1109,24 +1131,39 @@ fingerprint_randomart(u_char *dgst_raw,
 }
 
 char *
-sshkey_fingerprint(const struct sshkey *k, enum sshkey_fp_type dgst_type,
+sshkey_fingerprint(const struct sshkey *k, int dgst_alg,
     enum sshkey_fp_rep dgst_rep)
 {
 	char *retval = NULL;
 	u_char *dgst_raw;
 	size_t dgst_raw_len;
 
-	if (sshkey_fingerprint_raw(k, dgst_type, &dgst_raw, &dgst_raw_len) != 0)
+	if (sshkey_fingerprint_raw(k, dgst_alg, &dgst_raw, &dgst_raw_len) != 0)
 		return NULL;
 	switch (dgst_rep) {
+	case SSH_FP_DEFAULT:
+		if (dgst_alg == SSH_DIGEST_MD5) {
+			retval = fingerprint_hex(ssh_digest_alg_name(dgst_alg),
+			    dgst_raw, dgst_raw_len);
+		} else {
+			retval = fingerprint_b64(ssh_digest_alg_name(dgst_alg),
+			    dgst_raw, dgst_raw_len);
+		}
+		break;
 	case SSH_FP_HEX:
-		retval = fingerprint_hex(dgst_raw, dgst_raw_len);
+		retval = fingerprint_hex(ssh_digest_alg_name(dgst_alg),
+		    dgst_raw, dgst_raw_len);
+		break;
+	case SSH_FP_BASE64:
+		retval = fingerprint_b64(ssh_digest_alg_name(dgst_alg),
+		    dgst_raw, dgst_raw_len);
 		break;
 	case SSH_FP_BUBBLEBABBLE:
 		retval = fingerprint_bubblebabble(dgst_raw, dgst_raw_len);
 		break;
 	case SSH_FP_RANDOMART:
-		retval = fingerprint_randomart(dgst_raw, dgst_raw_len, k);
+		retval = fingerprint_randomart(ssh_digest_alg_name(dgst_alg),
+		    dgst_raw, dgst_raw_len, k);
 		break;
 	default:
 		explicit_bzero(dgst_raw, dgst_raw_len);
diff -up openssh-6.7p1/ssh-keygen.1.fingerprint openssh-6.7p1/ssh-keygen.1
--- openssh-6.7p1/ssh-keygen.1.fingerprint	2014-04-20 05:23:04.000000000 +0200
+++ openssh-6.7p1/ssh-keygen.1	2014-12-22 13:10:57.966878095 +0100
@@ -73,6 +73,7 @@
 .Op Fl f Ar keyfile
 .Nm ssh-keygen
 .Fl l
+.Op Fl E Ar fingerprint_hash
 .Op Fl f Ar input_keyfile
 .Nm ssh-keygen
 .Fl B
@@ -269,6 +270,14 @@ When used in combination with
 this option indicates that a CA key resides in a PKCS#11 token (see the
 .Sx CERTIFICATES
 section for details).
+.It Fl E Ar fingerprint_hash
+Specifies the hash algorithm used when displaying key fingerprints.
+Valid options are:
+.Dq md5
+and
+.Dq sha256 .
+The default is
+.Dq sha256 .
 .It Fl e
 This option will read a private or public OpenSSH key file and
 print to stdout the key in one of the formats specified by the
diff -up openssh-6.7p1/ssh-keygen.c.fingerprint openssh-6.7p1/ssh-keygen.c
--- openssh-6.7p1/ssh-keygen.c.fingerprint	2014-07-03 13:24:41.000000000 +0200
+++ openssh-6.7p1/ssh-keygen.c	2014-12-22 13:10:57.966878095 +0100
@@ -53,6 +53,7 @@
 #include "ssh-pkcs11.h"
 #include "atomicio.h"
 #include "krl.h"
+#include "digest.h"
 
 /* Number of bits in the RSA/DSA key.  This value can be set on the command line. */
 #define DEFAULT_BITS		2048
@@ -90,6 +91,9 @@ int show_cert = 0;
 int print_fingerprint = 0;
 int print_bubblebabble = 0;
 
+/* Hash algorithm to use for fingerprints. */
+int fingerprint_hash = SSH_FP_HASH_DEFAULT;
+
 /* The identity file name, given on the command line or entered by the user. */
 char identity_file[1024];
 int have_identity = 0;
@@ -749,11 +753,11 @@ do_download(struct passwd *pw)
 	Key **keys = NULL;
 	int i, nkeys;
 	enum fp_rep rep;
-	enum fp_type fptype;
+	int fptype;
 	char *fp, *ra;
 
-	fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
-	rep =    print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
+	fptype = print_bubblebabble ? SSH_DIGEST_SHA1 : fingerprint_hash;
+	rep =    print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_DEFAULT;
 
 	pkcs11_init(0);
 	nkeys = pkcs11_add_provider(pkcs11provider, NULL, &keys);
@@ -762,7 +766,7 @@ do_download(struct passwd *pw)
 	for (i = 0; i < nkeys; i++) {
 		if (print_fingerprint) {
 			fp = key_fingerprint(keys[i], fptype, rep);
-			ra = key_fingerprint(keys[i], SSH_FP_MD5,
+			ra = key_fingerprint(keys[i], fingerprint_hash,
 			    SSH_FP_RANDOMART);
 			printf("%u %s %s (PKCS11 key)\n", key_size(keys[i]),
 			    fp, key_type(keys[i]));
@@ -792,12 +796,11 @@ do_fingerprint(struct passwd *pw)
 	char *comment = NULL, *cp, *ep, line[16*1024], *fp, *ra;
 	int i, skip = 0, num = 0, invalid = 1;
 	enum fp_rep rep;
-	enum fp_type fptype;
+	int fptype;
 	struct stat st;
 
-	fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
-	rep =    print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
-
+	fptype = print_bubblebabble ? SSH_DIGEST_SHA1 : fingerprint_hash;
+	rep =    print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_DEFAULT;
 	if (!have_identity)
 		ask_filename(pw, "Enter file in which the key is");
 	if (stat(identity_file, &st) < 0) {
@@ -807,7 +810,8 @@ do_fingerprint(struct passwd *pw)
 	public = key_load_public(identity_file, &comment);
 	if (public != NULL) {
 		fp = key_fingerprint(public, fptype, rep);
-		ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART);
+		ra = key_fingerprint(public, fingerprint_hash,
+		    SSH_FP_RANDOMART);
 		printf("%u %s %s (%s)\n", key_size(public), fp, comment,
 		    key_type(public));
 		if (log_level >= SYSLOG_LEVEL_VERBOSE)
@@ -873,7 +877,8 @@ do_fingerprint(struct passwd *pw)
 		}
 		comment = *cp ? cp : comment;
 		fp = key_fingerprint(public, fptype, rep);
-		ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART);
+		ra = key_fingerprint(public, fingerprint_hash,
+		    SSH_FP_RANDOMART);
 		printf("%u %s %s (%s)\n", key_size(public), fp,
 		    comment ? comment : "no comment", key_type(public));
 		if (log_level >= SYSLOG_LEVEL_VERBOSE)
@@ -991,13 +996,15 @@ printhost(FILE *f, const char *name, Key
 {
 	if (print_fingerprint) {
 		enum fp_rep rep;
-		enum fp_type fptype;
+		int fptype;
 		char *fp, *ra;
 
-		fptype = print_bubblebabble ? SSH_FP_SHA1 : SSH_FP_MD5;
-		rep =    print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_HEX;
+		fptype = print_bubblebabble ?
+		    SSH_DIGEST_SHA1 : fingerprint_hash;
+		rep = print_bubblebabble ? SSH_FP_BUBBLEBABBLE : SSH_FP_DEFAULT;
 		fp = key_fingerprint(public, fptype, rep);
-		ra = key_fingerprint(public, SSH_FP_MD5, SSH_FP_RANDOMART);
+		ra = key_fingerprint(public, fingerprint_hash,
+		    SSH_FP_RANDOMART);
 		printf("%u %s %s (%s)\n", key_size(public), fp, name,
 		    key_type(public));
 		if (log_level >= SYSLOG_LEVEL_VERBOSE)
@@ -1906,9 +1913,9 @@ do_show_cert(struct passwd *pw)
 		fatal("%s is not a certificate", identity_file);
 	v00 = key->type == KEY_RSA_CERT_V00 || key->type == KEY_DSA_CERT_V00;
 
-	key_fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+	key_fp = key_fingerprint(key, fingerprint_hash, SSH_FP_DEFAULT);
 	ca_fp = key_fingerprint(key->cert->signature_key,
-	    SSH_FP_MD5, SSH_FP_HEX);
+	    fingerprint_hash, SSH_FP_DEFAULT);
 
 	printf("%s:\n", identity_file);
 	printf("        Type: %s %s certificate\n", key_ssh_name(key),
@@ -2187,7 +2194,7 @@ usage(void)
 	    "       ssh-keygen -e [-m key_format] [-f input_keyfile]\n"
 	    "       ssh-keygen -y [-f input_keyfile]\n"
 	    "       ssh-keygen -c [-P passphrase] [-C comment] [-f keyfile]\n"
-	    "       ssh-keygen -l [-f input_keyfile]\n"
+	    "       ssh-keygen -l [-E fingerprint_hash] [-f input_keyfile]\n"
 	    "       ssh-keygen -B [-f input_keyfile]\n");
 #ifdef ENABLE_PKCS11
 	fprintf(stderr,
@@ -2256,9 +2263,10 @@ main(int argc, char **argv)
 		exit(1);
 	}
 
-	/* Remaining characters: EUYdw */
+	/* Remaining characters: UYdw */
 	while ((opt = getopt(argc, argv, "ABHLQXceghiklopquvxy"
-	    "C:D:F:G:I:J:K:M:N:O:P:R:S:T:V:W:Z:a:b:f:g:j:m:n:r:s:t:z:")) != -1) {
+	    "C:D:E:F:G:I:J:K:M:N:O:P:R:S:T:V:W:Z:"
+	    "a:b:f:g:j:m:n:r:s:t:z:")) != -1) {
 		switch (opt) {
 		case 'A':
 			gen_all_hostkeys = 1;
@@ -2269,6 +2277,11 @@ main(int argc, char **argv)
 				fatal("Bits has bad value %s (%s)",
 					optarg, errstr);
 			break;
+		case 'E':
+			fingerprint_hash = ssh_digest_alg_by_name(optarg);
+			if (fingerprint_hash == -1)
+				fatal("Invalid hash algorithm \"%s\"", optarg);
+			break;
 		case 'F':
 			find_host = 1;
 			rr_hostname = optarg;
@@ -2700,8 +2713,9 @@ passphrase_again:
 	fclose(f);
 
 	if (!quiet) {
-		char *fp = key_fingerprint(public, SSH_FP_MD5, SSH_FP_HEX);
-		char *ra = key_fingerprint(public, SSH_FP_MD5,
+		char *fp = key_fingerprint(public, fingerprint_hash,
+		    SSH_FP_DEFAULT);
+		char *ra = key_fingerprint(public, fingerprint_hash,
 		    SSH_FP_RANDOMART);
 		printf("Your public key has been saved in %s.\n",
 		    identity_file);
diff -up openssh-6.7p1/sshkey.h.fingerprint openssh-6.7p1/sshkey.h
--- openssh-6.7p1/sshkey.h.fingerprint	2014-08-20 03:06:51.000000000 +0200
+++ openssh-6.7p1/sshkey.h	2014-12-22 13:10:57.969878085 +0100
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshkey.h,v 1.1 2014/06/24 01:16:58 djm Exp $ */
+/* $OpenBSD: sshkey.h,v 1.2 2014/12/21 22:27:55 djm Exp $ */
 
 /*
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
@@ -67,16 +67,14 @@ enum sshkey_types {
 	KEY_UNSPEC
 };
 
-/* Fingerprint hash algorithms */
-enum sshkey_fp_type {
-	SSH_FP_SHA1,
-	SSH_FP_MD5,
-	SSH_FP_SHA256
-};
+/* Default fingerprint hash */
+#define SSH_FP_HASH_DEFAULT	SSH_DIGEST_SHA256
 
 /* Fingerprint representation formats */
 enum sshkey_fp_rep {
+	SSH_FP_DEFAULT = 0,
 	SSH_FP_HEX,
+	SSH_FP_BASE64,
 	SSH_FP_BUBBLEBABBLE,
 	SSH_FP_RANDOMART
 };
@@ -124,9 +122,9 @@ int		 sshkey_equal_public(const struct s
     const struct sshkey *);
 int		 sshkey_equal(const struct sshkey *, const struct sshkey *);
 char		*sshkey_fingerprint(const struct sshkey *,
-    enum sshkey_fp_type, enum sshkey_fp_rep);
+    int, enum sshkey_fp_rep);
 int		 sshkey_fingerprint_raw(const struct sshkey *k,
-    enum sshkey_fp_type dgst_type, u_char **retp, size_t *lenp);
+    int, u_char **retp, size_t *lenp);
 const char	*sshkey_type(const struct sshkey *);
 const char	*sshkey_cert_type(const struct sshkey *);
 int		 sshkey_write(const struct sshkey *, FILE *);
diff -up openssh-6.7p1/ssh-keysign.c.fingerprint openssh-6.7p1/ssh-keysign.c
--- openssh-6.7p1/ssh-keysign.c.fingerprint	2014-05-15 06:24:10.000000000 +0200
+++ openssh-6.7p1/ssh-keysign.c	2014-12-22 13:10:57.967878092 +0100
@@ -246,7 +246,8 @@ main(int argc, char **argv)
 		}
 	}
 	if (!found) {
-		fp = key_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX);
+		fp = key_fingerprint(key, options.fingerprint_hash,
+		    SSH_FP_DEFAULT);
 		fatal("no matching hostkey found for key %s %s",
 		    key_type(key), fp);
 	}