Add FingerprintHash option to control algorithm used for key
authordjm <djm@openbsd.org>
Sun, 21 Dec 2014 22:27:55 +0000 (22:27 +0000)
committerdjm <djm@openbsd.org>
Sun, 21 Dec 2014 22:27:55 +0000 (22:27 +0000)
fingerprints. Default changes from MD5 to SHA256 and format
from hex to base64.

Feedback and ok naddy@ markus@

28 files changed:
usr.bin/ssh/auth-rsa.c
usr.bin/ssh/auth.c
usr.bin/ssh/auth2-hostbased.c
usr.bin/ssh/auth2-pubkey.c
usr.bin/ssh/digest-libc.c
usr.bin/ssh/digest-openssl.c
usr.bin/ssh/digest.h
usr.bin/ssh/dns.c
usr.bin/ssh/key.c
usr.bin/ssh/key.h
usr.bin/ssh/krl.c
usr.bin/ssh/readconf.c
usr.bin/ssh/readconf.h
usr.bin/ssh/servconf.c
usr.bin/ssh/servconf.h
usr.bin/ssh/ssh-add.1
usr.bin/ssh/ssh-add.c
usr.bin/ssh/ssh-agent.1
usr.bin/ssh/ssh-agent.c
usr.bin/ssh/ssh-keygen.1
usr.bin/ssh/ssh-keygen.c
usr.bin/ssh/ssh-keysign.c
usr.bin/ssh/ssh.1
usr.bin/ssh/sshconnect.c
usr.bin/ssh/sshconnect2.c
usr.bin/ssh/sshd_config.5
usr.bin/ssh/sshkey.c
usr.bin/ssh/sshkey.h

index d736d5a..76546b8 100644 (file)
@@ -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
@@ -233,7 +233,8 @@ rsa_key_allowed_in_file(struct passwd *pw, char *file,
                            "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);
index 4f823de..e27944d 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth.c,v 1.107 2014/12/04 02:24:32 djm Exp $ */
+/* $OpenBSD: auth.c,v 1.108 2014/12/21 22:27:56 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -552,7 +552,8 @@ auth_key_is_revoked(Key *key)
 
        if (options.revoked_keys_file == NULL)
                return 0;
-       if ((fp = sshkey_fingerprint(key, SSH_FP_MD5, SSH_FP_HEX)) == NULL) {
+       if ((fp = sshkey_fingerprint(key, options.fingerprint_hash,
+           SSH_FP_DEFAULT)) == NULL) {
                r = SSH_ERR_ALLOC_FAIL;
                error("%s: fingerprint key: %s", __func__, ssh_err(r));
                goto out;
index 17d382a..2bd8fcb 100644 (file)
@@ -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.
  *
@@ -207,13 +207,14 @@ hostbased_key_allowed(struct passwd *pw, const char *cuser, char *chost,
        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);
                }
index 69a319f..6fec8e5 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth2-pubkey.c,v 1.42 2014/12/04 02:24:32 djm Exp $ */
+/* $OpenBSD: auth2-pubkey.c,v 1.43 2014/12/21 22:27:56 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -210,7 +210,7 @@ pubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...)
 
        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,
@@ -218,7 +218,8 @@ pubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...)
                    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);
@@ -362,8 +363,8 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw)
                                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);
                        /*
@@ -403,7 +404,8 @@ check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw)
                        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);
@@ -429,7 +431,7 @@ user_cert_trusted_ca(struct passwd *pw, Key *key)
                return 0;
 
        ca_fp = key_fingerprint(key->cert->signature_key,
-           SSH_FP_MD5, SSH_FP_HEX);
+           options.fingerprint_hash, SSH_FP_DEFAULT);
 
        if (sshkey_in_file(key->cert->signature_key,
            options.trusted_user_ca_keys, 1, 0) != 0) {
index a922019..8291de4 100644 (file)
@@ -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.
@@ -124,6 +124,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)
 {
index e524a05..9346cb7 100644 (file)
@@ -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>
  *
@@ -59,6 +59,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)
 {
index 6afb197..3fe0734 100644 (file)
@@ -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>
  *
 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);
 
index 1918915..978046b 100644 (file)
@@ -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.
@@ -38,6 +38,7 @@
 #include "key.h"
 #include "dns.h"
 #include "log.h"
+#include "digest.h"
 
 static const char *errset_text[] = {
        "success",              /* 0 ERRSET_SUCCESS */
@@ -77,7 +78,7 @@ dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type,
     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:
@@ -107,17 +108,17 @@ dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type,
 
        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;
index d8703ad..2cc6949 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: key.c,v 1.123 2014/12/04 20:47:36 djm Exp $ */
+/* $OpenBSD: key.c,v 1.124 2014/12/21 22:27:56 djm Exp $ */
 /*
  * placed in the public domain
  */
@@ -38,8 +38,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;
@@ -47,7 +46,7 @@ key_fingerprint_raw(const Key *k, enum fp_type dgst_type,
 
        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);
index 24aa8da..2cf9bc2 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: key.h,v 1.43 2014/12/04 20:47:36 djm Exp $ */
+/* $OpenBSD: key.h,v 1.44 2014/12/21 22:27:56 djm Exp $ */
 
 /*
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
@@ -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 **);
 
index d8270ec..dae6aed 100644 (file)
@@ -14,7 +14,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $OpenBSD: krl.c,v 1.20 2014/12/04 01:49:59 djm Exp $ */
+/* $OpenBSD: krl.c,v 1.21 2014/12/21 22:27:56 djm Exp $ */
 
 #include <sys/types.h>
 #include <sys/param.h>
@@ -34,6 +34,7 @@
 #include "misc.h"
 #include "log.h"
 #include "ssherr.h"
+#include "digest.h"
 
 #include "krl.h"
 
@@ -409,7 +410,8 @@ ssh_krl_revoke_key_sha1(struct ssh_krl *krl, const struct sshkey *key)
        int r;
 
        debug3("%s: revoke type %s by sha1", __func__, sshkey_type(key));
-       if ((r = sshkey_fingerprint_raw(key, SSH_FP_SHA1, &blob, &len)) != 0)
+       if ((r = sshkey_fingerprint_raw(key, SSH_DIGEST_SHA1,
+           &blob, &len)) != 0)
                return r;
        return revoke_blob(&krl->revoked_sha1s, blob, len);
 }
@@ -1149,7 +1151,7 @@ is_key_revoked(struct ssh_krl *krl, const struct sshkey *key)
 
        /* Check explicitly revoked hashes first */
        memset(&rb, 0, sizeof(rb));
-       if ((r = sshkey_fingerprint_raw(key, SSH_FP_SHA1,
+       if ((r = sshkey_fingerprint_raw(key, SSH_DIGEST_SHA1,
            &rb.blob, &rb.len)) != 0)
                return r;
        erb = RB_FIND(revoked_blob_tree, &krl->revoked_sha1s, &rb);
index 16e83f2..24ff6ad 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: readconf.c,v 1.223 2014/12/04 02:24:32 djm Exp $ */
+/* $OpenBSD: readconf.c,v 1.224 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
@@ -49,6 +49,7 @@
 #include "mac.h"
 #include "uidswap.h"
 #include "myproposal.h"
+#include "digest.h"
 
 /* Format of the configuration file:
 
@@ -144,6 +145,7 @@ typedef enum {
        oCanonicalDomains, oCanonicalizeHostname, oCanonicalizeMaxDots,
        oCanonicalizeFallbackLocal, oCanonicalizePermittedCNAMEs,
        oStreamLocalBindMask, oStreamLocalBindUnlink, oRevokedHostKeys,
+       oFingerprintHash,
        oIgnoredUnknownOption, oDeprecated, oUnsupported
 } OpCodes;
 
@@ -259,6 +261,7 @@ static struct {
        { "streamlocalbindmask", oStreamLocalBindMask },
        { "streamlocalbindunlink", oStreamLocalBindUnlink },
        { "revokedhostkeys", oRevokedHostKeys },
+       { "fingerprinthash", oFingerprintHash },
        { "ignoreunknown", oIgnoreUnknown },
 
        { NULL, oBadOption }
@@ -1448,6 +1451,18 @@ parse_int:
                charptr = &options->revoked_host_keys;
                goto parse_string;
 
+       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);
@@ -1625,6 +1640,7 @@ initialize_options(Options * options)
        options->canonicalize_fallback_local = -1;
        options->canonicalize_hostname = -1;
        options->revoked_host_keys = NULL;
+       options->fingerprint_hash = -1;
 }
 
 /*
@@ -1800,6 +1816,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)) { \
@@ -2057,6 +2076,8 @@ fmt_intarg(OpCodes code, int val)
                return fmt_multistate_int(val, multistate_requesttty);
        case oCanonicalizeHostname:
                return fmt_multistate_int(val, multistate_canonicalizehostname);
+       case oFingerprintHash:
+               return ssh_digest_alg_name(val);
        case oProtocol:
                switch (val) {
                case SSH_PROTO_1:
@@ -2191,6 +2212,7 @@ dump_client_config(Options *o, const char *host)
        dump_cfg_fmtint(oControlMaster, o->control_master);
        dump_cfg_fmtint(oEnableSSHKeysign, o->enable_ssh_keysign);
        dump_cfg_fmtint(oExitOnForwardFailure, o->exit_on_forward_failure);
+       dump_cfg_fmtint(oFingerprintHash, o->fingerprint_hash);
        dump_cfg_fmtint(oForwardAgent, o->forward_agent);
        dump_cfg_fmtint(oForwardX11, o->forward_x11);
        dump_cfg_fmtint(oForwardX11Trusted, o->forward_x11_trusted);
index 49858bf..11a7332 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: readconf.h,v 1.104 2014/12/04 02:24:32 djm Exp $ */
+/* $OpenBSD: readconf.h,v 1.105 2014/12/21 22:27:56 djm Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -146,6 +146,8 @@ typedef struct {
 
        char    *revoked_host_keys;
 
+       int     fingerprint_hash;
+
        char    *ignored_unknown; /* Pattern list of unknown tokens to ignore */
 }       Options;
 
index dc3543e..994b344 100644 (file)
@@ -1,5 +1,5 @@
 
-/* $OpenBSD: servconf.c,v 1.255 2014/11/24 03:39:22 jsg Exp $ */
+/* $OpenBSD: servconf.c,v 1.256 2014/12/21 22:27:56 djm Exp $ */
 /*
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
  *                    All rights reserved
@@ -50,6 +50,7 @@
 #include "hostfile.h"
 #include "auth.h"
 #include "myproposal.h"
+#include "digest.h"
 
 static void add_listen_addr(ServerOptions *, char *, int);
 static void add_one_listen_addr(ServerOptions *, char *, int);
@@ -148,6 +149,7 @@ initialize_server_options(ServerOptions *options)
        options->ip_qos_interactive = -1;
        options->ip_qos_bulk = -1;
        options->version_addendum = NULL;
+       options->fingerprint_hash = -1;
 }
 
 void
@@ -296,6 +298,8 @@ fill_default_server_options(ServerOptions *options)
                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;
@@ -332,7 +336,7 @@ typedef enum {
        sAuthorizedKeysCommand, sAuthorizedKeysCommandUser,
        sAuthenticationMethods, sHostKeyAgent, sPermitUserRC,
        sStreamLocalBindMask, sStreamLocalBindUnlink,
-       sAllowStreamLocalForwarding,
+       sAllowStreamLocalForwarding, sFingerprintHash,
        sDeprecated, sUnsupported
 } ServerOpCodes;
 
@@ -451,6 +455,7 @@ static struct {
        { "streamlocalbindmask", sStreamLocalBindMask, SSHCFG_ALL },
        { "streamlocalbindunlink", sStreamLocalBindUnlink, SSHCFG_ALL },
        { "allowstreamlocalforwarding", sAllowStreamLocalForwarding, SSHCFG_ALL },
+       { "fingerprinthash", sFingerprintHash, SSHCFG_GLOBAL },
        { NULL, sBadOption, 0 }
 };
 
@@ -1622,6 +1627,18 @@ process_server_config_line(ServerOptions *options, char *line,
                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);
@@ -1864,6 +1881,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:
@@ -2020,6 +2039,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);
index 2bca3cb..88a4bd4 100644 (file)
@@ -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>
@@ -183,6 +183,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 */
index 9da7a28..926456f 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: ssh-add.1,v 1.60 2014/08/30 15:33:50 sobrado Exp $
+.\"    $OpenBSD: ssh-add.1,v 1.61 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
@@ -35,7 +35,7 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd $Mdocdate: August 30 2014 $
+.Dd $Mdocdate: December 21 2014 $
 .Dt SSH-ADD 1
 .Os
 .Sh NAME
@@ -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 path,
 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 .
index fa224af..2b7fa11 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-add.c,v 1.114 2014/11/26 18:34:51 millert Exp $ */
+/* $OpenBSD: ssh-add.c,v 1.115 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
@@ -59,6 +59,7 @@
 #include "pathnames.h"
 #include "misc.h"
 #include "ssherr.h"
+#include "digest.h"
 
 /* argv0 */
 extern char *__progname;
@@ -73,6 +74,8 @@ static char *default_files[] = {
        NULL
 };
 
+static int fingerprint_hash = SSH_FP_HASH_DEFAULT;
+
 /* Default lifetime (0 == forever) */
 static int lifetime = 0;
 
@@ -334,8 +337,8 @@ list_identities(AuthenticationConnection *ac, int do_fp)
                    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);
@@ -402,6 +405,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");
@@ -422,6 +426,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();
@@ -437,21 +442,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;
@@ -459,9 +471,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;
@@ -482,6 +493,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) {
index b550653..6759afe 100644 (file)
@@ -1,4 +1,4 @@
-.\" $OpenBSD: ssh-agent.1,v 1.56 2014/08/30 15:33:50 sobrado Exp $
+.\" $OpenBSD: ssh-agent.1,v 1.57 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
@@ -34,7 +34,7 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd $Mdocdate: August 30 2014 $
+.Dd $Mdocdate: December 21 2014 $
 .Dt SSH-AGENT 1
 .Os
 .Sh NAME
@@ -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
index 0fb6ba6..ca00a99 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-agent.c,v 1.191 2014/11/18 20:54:28 krw Exp $ */
+/* $OpenBSD: ssh-agent.c,v 1.192 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
@@ -128,6 +128,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)
 {
@@ -189,7 +191,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;
@@ -1010,7 +1012,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);
 }
@@ -1043,8 +1045,13 @@ main(int ac, char **av)
        OpenSSL_add_all_algorithms();
 #endif
 
-       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();
index bf5f87b..b73c460 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: ssh-keygen.1,v 1.123 2014/08/30 15:33:50 sobrado Exp $
+.\"    $OpenBSD: ssh-keygen.1,v 1.124 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
@@ -35,7 +35,7 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd $Mdocdate: August 30 2014 $
+.Dd $Mdocdate: December 21 2014 $
 .Dt SSH-KEYGEN 1
 .Os
 .Sh NAME
@@ -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
index bddac02..3c54067 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-keygen.c,v 1.250 2014/08/21 01:08:52 doug Exp $ */
+/* $OpenBSD: ssh-keygen.c,v 1.251 2014/12/21 22:27:56 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -45,6 +45,7 @@
 #include "ssh2.h"
 #include "atomicio.h"
 #include "krl.h"
+#include "digest.h"
 
 #ifdef ENABLE_PKCS11
 #include "ssh-pkcs11.h"
@@ -86,6 +87,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;
@@ -737,11 +741,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);
@@ -750,7 +754,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]));
@@ -780,12 +784,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) {
@@ -795,7 +798,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)
@@ -861,7 +865,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)
@@ -979,13 +984,15 @@ printhost(FILE *f, const char *name, Key *public, int ca, int revoked, int hash)
 {
        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)
@@ -1894,9 +1901,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),
@@ -2175,7 +2182,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,
@@ -2240,9 +2247,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;
@@ -2253,6 +2261,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;
@@ -2684,8 +2697,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);
index 79127ad..7b119c9 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-keysign.c,v 1.43 2014/10/08 22:20:25 djm Exp $ */
+/* $OpenBSD: ssh-keysign.c,v 1.44 2014/12/21 22:27:56 djm Exp $ */
 /*
  * Copyright (c) 2002 Markus Friedl.  All rights reserved.
  *
@@ -235,7 +235,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);
        }
index 5120186..d489047 100644 (file)
@@ -33,8 +33,8 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.\" $OpenBSD: ssh.1,v 1.351 2014/10/09 06:21:31 jmc Exp $
-.Dd $Mdocdate: October 9 2014 $
+.\" $OpenBSD: ssh.1,v 1.352 2014/12/21 22:27:56 djm Exp $
+.Dd $Mdocdate: December 21 2014 $
 .Dt SSH 1
 .Os
 .Sh NAME
@@ -1091,7 +1091,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 .
index feab699..7aa789f 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshconnect.c,v 1.253 2014/12/11 08:20:09 djm Exp $ */
+/* $OpenBSD: sshconnect.c,v 1.254 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
@@ -892,9 +892,10 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
                                    "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);
@@ -933,9 +934,10 @@ check_host_key(char *hostname, struct sockaddr *hostaddr, u_short port,
                        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)
@@ -1200,7 +1202,7 @@ verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
        struct sshkey *plain = NULL;
 
        if ((fp = sshkey_fingerprint(host_key,
-           SSH_FP_MD5, SSH_FP_HEX)) == NULL) {
+           options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) {
                error("%s: fingerprint host key: %s", __func__, ssh_err(r));
                r = -1;
                goto out;
@@ -1361,8 +1363,10 @@ show_other_keys(struct hostkeys *hostkeys, Key *key)
                        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.",
@@ -1383,7 +1387,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!     @");
index 8b223c6..476cf44 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshconnect2.c,v 1.211 2014/12/11 05:13:28 djm Exp $ */
+/* $OpenBSD: sshconnect2.c,v 1.212 2014/12/21 22:27:56 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  * Copyright (c) 2008 Damien Miller.  All rights reserved.
@@ -576,7 +576,7 @@ input_userauth_pk_ok(int type, u_int32_t seq, void *ctxt)
                    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);
 
@@ -985,7 +985,7 @@ sign_and_send_pubkey(Authctxt *authctxt, Identity *id)
        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);
 
index d431ec5..f347658 100644 (file)
@@ -33,8 +33,8 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.\" $OpenBSD: sshd_config.5,v 1.182 2014/12/12 00:02:17 djm Exp $
-.Dd $Mdocdate: December 12 2014 $
+.\" $OpenBSD: sshd_config.5,v 1.183 2014/12/21 22:27:55 djm Exp $
+.Dd $Mdocdate: December 21 2014 $
 .Dt SSHD_CONFIG 5
 .Os
 .Sh NAME
@@ -486,6 +486,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 ,
index 87c9498..84e39a1 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshkey.c,v 1.6 2014/12/10 01:24:09 djm Exp $ */
+/* $OpenBSD: sshkey.c,v 1.7 2014/12/21 22:27:55 djm Exp $ */
 /*
  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
  * Copyright (c) 2008 Alexander von Gernler.  All rights reserved.
@@ -27,6 +27,7 @@
 
 #include <sys/param.h>
 #include <sys/types.h>
+#include <netinet/in.h>
 
 #include <openssl/evp.h>
 #include <openssl/err.h>
@@ -38,6 +39,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <util.h>
+#include <resolv.h>
 
 #include "ssh2.h"
 #include "ssherr.h"
@@ -826,29 +828,18 @@ sshkey_plain_to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp)
 }
 
 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;
        }
@@ -873,7 +864,7 @@ sshkey_fingerprint_raw(const struct sshkey *k, enum sshkey_fp_type dgst_type,
                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 */
@@ -882,7 +873,7 @@ sshkey_fingerprint_raw(const struct sshkey *k, enum sshkey_fp_type dgst_type,
                ret = NULL;
        }
        if (lenp != NULL)
-               *lenp = ssh_digest_bytes(hash_alg);
+               *lenp = ssh_digest_bytes(dgst_alg);
        r = 0;
  out:
        free(ret);
@@ -894,21 +885,45 @@ sshkey_fingerprint_raw(const struct sshkey *k, enum sshkey_fp_type dgst_type,
 }
 
 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;
+}
 
-       /* Remove the trailing ':' character */
-       retval[(dgst_raw_len * 3) - 1] = '\0';
+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;
+
+       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;
 }
 
@@ -994,7 +1009,7 @@ fingerprint_bubblebabble(u_char *dgst_raw, size_t dgst_raw_len)
 #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)
 {
        /*
@@ -1002,9 +1017,9 @@ fingerprint_randomart(u_char *dgst_raw, size_t dgst_raw_len,
         * 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;
@@ -1049,8 +1064,12 @@ fingerprint_randomart(u_char *dgst_raw, size_t dgst_raw_len,
                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;
@@ -1059,7 +1078,7 @@ fingerprint_randomart(u_char *dgst_raw, size_t dgst_raw_len,
                *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';
@@ -1075,7 +1094,11 @@ fingerprint_randomart(u_char *dgst_raw, size_t dgst_raw_len,
 
        /* 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++ = '+';
 
@@ -1083,24 +1106,39 @@ fingerprint_randomart(u_char *dgst_raw, size_t dgst_raw_len,
 }
 
 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);
index 4127db2..7f595c1 100644 (file)
@@ -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.
@@ -61,16 +61,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
 };
@@ -118,9 +116,9 @@ int          sshkey_equal_public(const struct sshkey *,
     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 *);