[openssh] use upstream FigerPrintHash for fingerprint - 56d1c83cdd1ac76f1c6bd41e01e80dad834f3994

Petr Lautrbach plautrba at fedoraproject.org
Tue Jan 20 12:29:46 UTC 2015


commit b457c98becf1a64b7531a88f0c2486074eca1432
Author: Petr Lautrbach <plautrba at redhat.com>
Date:   Mon Dec 22 13:29:43 2014 +0100

    use upstream FigerPrintHash for fingerprint - 56d1c83cdd1ac76f1c6bd41e01e80dad834f3994

 openssh-6.7p1-fingerprint.patch | 1289 +++++++++++++++++++++++++++++++++++++++
 openssh.spec                    |    2 +-
 2 files changed, 1290 insertions(+), 1 deletions(-)
---
diff --git a/openssh-6.7p1-fingerprint.patch b/openssh-6.7p1-fingerprint.patch
new file mode 100644
index 0000000..da798dd
--- /dev/null
+++ b/openssh-6.7p1-fingerprint.patch
@@ -0,0 +1,1289 @@
+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 at cs.hut.fi>
+  * Copyright (c) 1995 Tatu Ylonen <ylo at 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 at 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 at 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 at 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 at 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);
+ 	}
diff --git a/openssh.spec b/openssh.spec
index 2be8093..28abea8 100644
--- a/openssh.spec
+++ b/openssh.spec
@@ -95,7 +95,7 @@ Patch0: openssh-5.9p1-wIm.patch
 #?
 Patch100: openssh-6.6.1p1-coverity.patch
 #https://bugzilla.mindrot.org/show_bug.cgi?id=1872
-Patch101: openssh-6.6p1-fingerprint.patch
+Patch101: openssh-6.7p1-fingerprint.patch
 #https://bugzilla.mindrot.org/show_bug.cgi?id=1894
 #https://bugzilla.redhat.com/show_bug.cgi?id=735889
 Patch102: openssh-5.8p1-getaddrinfo.patch


More information about the scm-commits mailing list