let ssh-keygen and ssh-keyscan accept -Ohashalg=sha1|sha256 when
authordjm <djm@openbsd.org>
Fri, 10 Feb 2023 04:56:30 +0000 (04:56 +0000)
committerdjm <djm@openbsd.org>
Fri, 10 Feb 2023 04:56:30 +0000 (04:56 +0000)
outputting SSHFP fingerprints to allow algorithm selection.
bz3493 ok dtucker@

usr.bin/ssh/dns.c
usr.bin/ssh/dns.h
usr.bin/ssh/ssh-keygen.1
usr.bin/ssh/ssh-keygen.c
usr.bin/ssh/ssh-keyscan.1
usr.bin/ssh/ssh-keyscan.c

index 3218abc..89872e0 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: dns.c,v 1.42 2022/02/01 23:32:51 djm Exp $ */
+/* $OpenBSD: dns.c,v 1.43 2023/02/10 04:56:30 djm Exp $ */
 
 /*
  * Copyright (c) 2003 Wesley Griffin. All rights reserved.
@@ -299,7 +299,8 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address,
  * Export the fingerprint of a key as a DNS resource record
  */
 int
-export_dns_rr(const char *hostname, struct sshkey *key, FILE *f, int generic)
+export_dns_rr(const char *hostname, struct sshkey *key, FILE *f, int generic,
+    int alg)
 {
        u_int8_t rdata_pubkey_algorithm = 0;
        u_int8_t rdata_digest_type = SSHFP_HASH_RESERVED;
@@ -309,6 +310,8 @@ export_dns_rr(const char *hostname, struct sshkey *key, FILE *f, int generic)
        int success = 0;
 
        for (dtype = SSHFP_HASH_SHA1; dtype < SSHFP_HASH_MAX; dtype++) {
+               if (alg != -1 && dtype != alg)
+                       continue;
                rdata_digest_type = dtype;
                if (dns_read_key(&rdata_pubkey_algorithm, &rdata_digest_type,
                    &rdata_digest, &rdata_digest_len, key)) {
index c9b61c4..864ab7d 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: dns.h,v 1.19 2021/07/19 03:13:28 dtucker Exp $ */
+/* $OpenBSD: dns.h,v 1.20 2023/02/10 04:56:30 djm Exp $ */
 
 /*
  * Copyright (c) 2003 Wesley Griffin. All rights reserved.
@@ -54,6 +54,6 @@ enum sshfp_hashes {
 
 int    verify_host_key_dns(const char *, struct sockaddr *,
     struct sshkey *, int *);
-int    export_dns_rr(const char *, struct sshkey *, FILE *, int);
+int    export_dns_rr(const char *, struct sshkey *, FILE *, int, int);
 
 #endif /* DNS_H */
index 8b1f617..715c9cc 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: ssh-keygen.1,v 1.226 2022/09/10 08:50:53 jsg Exp $
+.\"    $OpenBSD: ssh-keygen.1,v 1.227 2023/02/10 04:56:30 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: September 10 2022 $
+.Dd $Mdocdate: February 10 2023 $
 .Dt SSH-KEYGEN 1
 .Os
 .Sh NAME
@@ -518,6 +518,21 @@ suffixed with a Z character, which causes them to be interpreted in the
 UTC time zone.
 .El
 .Pp
+When generating SSHFP DNS records from public keys using the
+.Fl r
+flag, the following options are accepted:
+.Bl -tag -width Ds
+.It Cm hashalg Ns = Ns Ar algorithm
+Selects a hash algorithm to use when printing SSHFP records using the
+.Fl D
+flag.
+Valid algorithms are
+.Dq sha1
+and
+.Dq sha256.
+The default is to print both.
+.El
+.Pp
 The
 .Fl O
 option may be specified multiple times.
index 869b675..78a858b 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-keygen.c,v 1.461 2022/12/04 23:50:49 cheloha Exp $ */
+/* $OpenBSD: ssh-keygen.c,v 1.462 2023/02/10 04:56:30 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -1456,13 +1456,23 @@ do_change_passphrase(struct passwd *pw)
  */
 static int
 do_print_resource_record(struct passwd *pw, char *fname, char *hname,
-    int print_generic)
+    int print_generic, char * const *opts, size_t nopts)
 {
        struct sshkey *public;
        char *comment = NULL;
        struct stat st;
-       int r;
+       int r, hash = -1;
+       size_t i;
 
+       for (i = 0; i < nopts; i++) {
+               if (strncasecmp(opts[i], "hashalg=", 8) == 0) {
+                       if ((hash = ssh_digest_alg_by_name(opts[i] + 8)) == -1)
+                               fatal("Unsupported hash algorithm");
+               } else {
+                       error("Invalid option \"%s\"", opts[i]);
+                       return SSH_ERR_INVALID_ARGUMENT;
+               }
+       }
        if (fname == NULL)
                fatal_f("no filename");
        if (stat(fname, &st) == -1) {
@@ -1472,7 +1482,7 @@ do_print_resource_record(struct passwd *pw, char *fname, char *hname,
        }
        if ((r = sshkey_load_public(fname, &public, &comment)) != 0)
                fatal_r(r, "Failed to read v2 public key from \"%s\"", fname);
-       export_dns_rr(hname, public, stdout, print_generic);
+       export_dns_rr(hname, public, stdout, print_generic, hash);
        sshkey_free(public);
        free(comment);
        return 1;
@@ -3699,7 +3709,7 @@ main(int argc, char **argv)
 
                if (have_identity) {
                        n = do_print_resource_record(pw, identity_file,
-                           rr_hostname, print_generic);
+                           rr_hostname, print_generic, opts, nopts);
                        if (n == 0)
                                fatal("%s: %s", identity_file, strerror(errno));
                        exit(0);
@@ -3707,19 +3717,19 @@ main(int argc, char **argv)
 
                        n += do_print_resource_record(pw,
                            _PATH_HOST_RSA_KEY_FILE, rr_hostname,
-                           print_generic);
+                           print_generic, opts, nopts);
                        n += do_print_resource_record(pw,
                            _PATH_HOST_DSA_KEY_FILE, rr_hostname,
-                           print_generic);
+                           print_generic, opts, nopts);
                        n += do_print_resource_record(pw,
                            _PATH_HOST_ECDSA_KEY_FILE, rr_hostname,
-                           print_generic);
+                           print_generic, opts, nopts);
                        n += do_print_resource_record(pw,
                            _PATH_HOST_ED25519_KEY_FILE, rr_hostname,
-                           print_generic);
+                           print_generic, opts, nopts);
                        n += do_print_resource_record(pw,
                            _PATH_HOST_XMSS_KEY_FILE, rr_hostname,
-                           print_generic);
+                           print_generic, opts, nopts);
                        if (n == 0)
                                fatal("no keys found.");
                        exit(0);
index ca4feea..6fb0c6f 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: ssh-keyscan.1,v 1.47 2022/10/28 02:29:34 djm Exp $
+.\"    $OpenBSD: ssh-keyscan.1,v 1.48 2023/02/10 04:56:30 djm Exp $
 .\"
 .\" Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
 .\"
@@ -6,7 +6,7 @@
 .\" permitted provided that due credit is given to the author and the
 .\" OpenBSD project by leaving this copyright notice intact.
 .\"
-.Dd $Mdocdate: October 28 2022 $
+.Dd $Mdocdate: February 10 2023 $
 .Dt SSH-KEYSCAN 1
 .Os
 .Sh NAME
@@ -16,6 +16,7 @@
 .Nm ssh-keyscan
 .Op Fl 46cDHv
 .Op Fl f Ar file
+.Op Fl O Ar option
 .Op Fl p Ar port
 .Op Fl T Ar timeout
 .Op Fl t Ar type
@@ -97,6 +98,20 @@ and
 .Xr sshd 8 ,
 but they do not reveal identifying information should the file's contents
 be disclosed.
+.It Fl O Ar option
+Specify a key/value option.
+At present, only a single option is supported:
+.Bl -tag -width Ds
+.It Cm hashalg Ns = Ns Ar algorithm
+Selects a hash algorithm to use when printing SSHFP records using the
+.Fl D
+flag.
+Valid algorithms are
+.Dq sha1
+and
+.Dq sha256.
+The default is to print both.
+.El
 .It Fl p Ar port
 Connect to
 .Ar port
index e79851e..670f630 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-keyscan.c,v 1.149 2022/12/26 19:16:03 jmc Exp $ */
+/* $OpenBSD: ssh-keyscan.c,v 1.150 2023/02/10 04:56:30 djm Exp $ */
 /*
  * Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
  *
@@ -32,6 +32,7 @@
 #include "sshbuf.h"
 #include "sshkey.h"
 #include "cipher.h"
+#include "digest.h"
 #include "kex.h"
 #include "compat.h"
 #include "myproposal.h"
@@ -72,6 +73,8 @@ int print_sshfp = 0;          /* Print SSHFP records instead of known_hosts */
 
 int found_one = 0;             /* Successfully found a key */
 
+int hashalg = -1;              /* Hash for SSHFP records or -1 for all */
+
 #define MAXMAXFD 256
 
 /* The number of seconds after which to give up on a TCP connection */
@@ -294,7 +297,7 @@ keyprint_one(const char *host, struct sshkey *key)
        found_one = 1;
 
        if (print_sshfp) {
-               export_dns_rr(host, key, stdout, 0);
+               export_dns_rr(host, key, stdout, 0, hashalg);
                return;
        }
 
@@ -678,9 +681,8 @@ static void
 usage(void)
 {
        fprintf(stderr,
-           "usage: %s [-46cDHv] [-f file] [-p port] [-T timeout] [-t type]\n"
-           "\t\t   [host | addrlist namelist]\n",
-           __progname);
+           "usage: ssh-keyscan [-46cDHv] [-f file] [-p port] [-T timeout] [-t type]\n"
+           "                   [-O option] [host | addrlist namelist]\n");
        exit(1);
 }
 
@@ -704,7 +706,7 @@ main(int argc, char **argv)
        if (argc <= 1)
                usage();
 
-       while ((opt = getopt(argc, argv, "cDHv46p:T:t:f:")) != -1) {
+       while ((opt = getopt(argc, argv, "cDHv46O:p:T:t:f:")) != -1) {
                switch (opt) {
                case 'H':
                        hash_hosts = 1;
@@ -744,6 +746,14 @@ main(int argc, char **argv)
                                optarg = NULL;
                        argv[fopt_count++] = optarg;
                        break;
+               case 'O':
+                       /* Maybe other misc options in the future too */
+                       if (strncmp(optarg, "hashalg=", 8) != 0)
+                               fatal("Unsupported -O option");
+                       if ((hashalg = ssh_digest_alg_by_name(
+                           optarg + 8)) == -1)
+                               fatal("Unsupported hash algorithm");
+                       break;
                case 't':
                        get_keytypes = 0;
                        tname = strtok(optarg, ",");