summaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
authorJakob Schlyter <jakob@cvs.openbsd.org>2003-05-14 18:16:22 +0000
committerJakob Schlyter <jakob@cvs.openbsd.org>2003-05-14 18:16:22 +0000
commit1fd330c17b51f238b370cc946778efdc7e540c10 (patch)
treeb5093ce890dde7f5f94048d1ba8f0e7519562a02 /usr.bin
parentb7933e83cfa90e04f57d135bd8e47a6ad325977d (diff)
add experimental support for verifying hos keys using DNS as described
in draft-ietf-secsh-dns-xx.txt. more information in README.dns. ok markus@ and henning@
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/ssh/Makefile.inc4
-rw-r--r--usr.bin/ssh/README.dns55
-rw-r--r--usr.bin/ssh/dns.c295
-rw-r--r--usr.bin/ssh/dns.h59
-rw-r--r--usr.bin/ssh/key.c4
-rw-r--r--usr.bin/ssh/key.h3
-rw-r--r--usr.bin/ssh/lib/Makefile4
-rw-r--r--usr.bin/ssh/readconf.c12
-rw-r--r--usr.bin/ssh/readconf.h3
-rw-r--r--usr.bin/ssh/ssh-keygen.111
-rw-r--r--usr.bin/ssh/ssh-keygen.c55
-rw-r--r--usr.bin/ssh/ssh_config.57
-rw-r--r--usr.bin/ssh/sshconnect.c23
13 files changed, 521 insertions, 14 deletions
diff --git a/usr.bin/ssh/Makefile.inc b/usr.bin/ssh/Makefile.inc
index c68f59a74e9..764b0617e83 100644
--- a/usr.bin/ssh/Makefile.inc
+++ b/usr.bin/ssh/Makefile.inc
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile.inc,v 1.23 2002/03/06 00:23:27 markus Exp $
+# $OpenBSD: Makefile.inc,v 1.24 2003/05/14 18:16:20 jakob Exp $
CFLAGS+= -I${.CURDIR}/..
@@ -15,6 +15,8 @@ CDIAGFLAGS+= -Wunused
#CFLAGS+= -DSMARTCARD
#LDADD+= -lsectok
+#CFLAGS+= -DDNS
+
.include <bsd.obj.mk>
.if exists(${.CURDIR}/../lib/${__objdir})
diff --git a/usr.bin/ssh/README.dns b/usr.bin/ssh/README.dns
new file mode 100644
index 00000000000..d6889b9a5f8
--- /dev/null
+++ b/usr.bin/ssh/README.dns
@@ -0,0 +1,55 @@
+How to verify host keys using OpenSSH and DNS
+---------------------------------------------
+
+OpenSSH contains experimental support for verifying host keys using DNS
+as described in draft-ietf-secsh-dns-xx.txt. The document contains
+very brief instructions on how to test this feature. Configuring DNS
+and DNSSEC is out of the scope of this document.
+
+
+(1) Enable DNS fingerprint support in OpenSSH
+
+Edit /usr/src/usr.bin/ssh/Makefile.inc and uncomment the line containing
+
+ CFLAGS+= -DDNS
+
+
+(2) Generate and publish the DNS RR
+
+To create a DNS resource record (RR) containing a fingerprint of the
+public host key, use the following command:
+
+ ssh-keygen -r hostname -f keyfile -g
+
+where "hostname" is your fully qualified hostname and "keyfile" is the
+file containing the public host key file. If you have multiple keys,
+you should generate one RR for each key.
+
+In the example above, ssh-keygen will print the fingerprint in a
+generic DNS RR format parsable by most modern name server
+implementations. If your nameserver has support for the SSHFP RR, as
+defined by the draft, you can omit the -g flag and ssh-keygen will
+print a standard RR.
+
+To publish the fingerprint using the DNS you must add the generated RR
+to your DNS zone file and sign your zone.
+
+
+(3) Enable the ssh client to verify host keys using DNS
+
+To enable the ssh client to verify host keys using DNS, you have to
+add the following option to the ssh configuration file
+($HOME/.ssh/config or /etc/ssh/ssh_config):
+
+ VerifyHostKeyDNS yes
+
+Upon connection the client will try to look up the fingerprint RR
+using DNS. If the fingerprint received from the DNS server matches
+the remote host key, the user will be notified.
+
+
+ Jakob Schlyter
+ Wesley Griffin
+
+
+$OpenBSD: README.dns,v 1.1 2003/05/14 18:16:20 jakob Exp $
diff --git a/usr.bin/ssh/dns.c b/usr.bin/ssh/dns.c
new file mode 100644
index 00000000000..a97210d6ff5
--- /dev/null
+++ b/usr.bin/ssh/dns.c
@@ -0,0 +1,295 @@
+/* $OpenBSD: dns.c,v 1.1 2003/05/14 18:16:20 jakob Exp $ */
+
+/*
+ * Copyright (c) 2003 Wesley Griffin. All rights reserved.
+ * Copyright (c) 2003 Jakob Schlyter. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the authors may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "includes.h"
+
+#ifdef DNS
+#include <openssl/bn.h>
+#ifdef LWRES
+#include <lwres/netdb.h>
+#include <dns/result.h>
+#else /* LWRES */
+#include <netdb.h>
+#endif /* LWRES */
+
+#include "xmalloc.h"
+#include "key.h"
+#include "dns.h"
+#include "log.h"
+#include "uuencode.h"
+
+extern char *__progname;
+RCSID("$OpenBSD: dns.c,v 1.1 2003/05/14 18:16:20 jakob Exp $");
+
+#ifndef LWRES
+static const char *errset_text[] = {
+ "success", /* 0 ERRSET_SUCCESS */
+ "out of memory", /* 1 ERRSET_NOMEMORY */
+ "general failure", /* 2 ERRSET_FAIL */
+ "invalid parameter", /* 3 ERRSET_INVAL */
+ "name does not exist", /* 4 ERRSET_NONAME */
+ "data does not exist", /* 5 ERRSET_NODATA */
+};
+
+static const char *
+dns_result_totext(unsigned int error)
+{
+ switch (error) {
+ case ERRSET_SUCCESS:
+ return errset_text[ERRSET_SUCCESS];
+ case ERRSET_NOMEMORY:
+ return errset_text[ERRSET_NOMEMORY];
+ case ERRSET_FAIL:
+ return errset_text[ERRSET_FAIL];
+ case ERRSET_INVAL:
+ return errset_text[ERRSET_INVAL];
+ case ERRSET_NONAME:
+ return errset_text[ERRSET_NONAME];
+ case ERRSET_NODATA:
+ return errset_text[ERRSET_NODATA];
+ default:
+ return "unknown error";
+ }
+}
+#endif /* LWRES */
+
+
+/*
+ * Read SSHFP parameters from key buffer.
+ */
+static int
+dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type,
+ u_char **digest, u_int *digest_len, Key *key)
+{
+ int success = 0;
+
+ switch (key->type) {
+ case KEY_RSA:
+ *algorithm = DNS_KEY_RSA;
+ break;
+ case KEY_DSA:
+ *algorithm = DNS_KEY_DSA;
+ break;
+ default:
+ *algorithm = DNS_KEY_RESERVED;
+ }
+
+ if (*algorithm) {
+ *digest_type = DNS_HASH_SHA1;
+ *digest = key_fingerprint_raw(key, SSH_FP_SHA1, digest_len);
+ success = 1;
+ } else {
+ *digest_type = DNS_HASH_RESERVED;
+ *digest = NULL;
+ *digest_len = 0;
+ success = 0;
+ }
+
+ return success;
+}
+
+/*
+ * Read SSHFP parameters from rdata buffer.
+ */
+static int
+dns_read_rdata(u_int8_t *algorithm, u_int8_t *digest_type,
+ u_char **digest, u_int *digest_len, u_char *rdata, int rdata_len)
+{
+ int success = 0;
+
+ *algorithm = DNS_KEY_RESERVED;
+ *digest_type = DNS_HASH_RESERVED;
+
+ if (rdata_len >= 2) {
+ *algorithm = rdata[0];
+ *digest_type = rdata[1];
+ *digest_len = rdata_len - 2;
+
+ if (*digest_len > 0) {
+ *digest = (u_char *) xmalloc(*digest_len);
+ memcpy(*digest, rdata + 2, *digest_len);
+ } else {
+ *digest = NULL;
+ }
+
+ success = 1;
+ }
+
+ return success;
+}
+
+
+/*
+ * Verify the given hostname, address and host key using DNS.
+ * Returns 0 if key verifies or -1 if key does NOT verify
+ */
+int
+verify_host_key_dns(const char *hostname, struct sockaddr *address,
+ Key *hostkey)
+{
+ int counter;
+ int result;
+ struct rrsetinfo *keys = NULL;
+ int failures = 0;
+
+ u_int8_t hostkey_algorithm;
+ u_int8_t hostkey_digest_type;
+ u_char *hostkey_digest;
+ u_int hostkey_digest_len;
+
+ u_int8_t dnskey_algorithm;
+ u_int8_t dnskey_digest_type;
+ u_char *dnskey_digest;
+ u_int dnskey_digest_len;
+
+
+ debug3("verify_hostkey_dns");
+ if (hostkey == NULL)
+ fatal("No key to look up!");
+
+ result = getrrsetbyname(hostname, DNS_RDATACLASS_IN,
+ DNS_RDATATYPE_SSHFP, 0, &keys);
+ if (result) {
+ verbose("DNS lookup error: %s", dns_result_totext(result));
+ return DNS_VERIFY_ERROR;
+ }
+
+#ifdef DNSSEC
+ /* Only accept validated answers */
+ if (!keys->rri_flags & RRSET_VALIDATED) {
+ error("Ignored unvalidated fingerprint from DNS.");
+ return DNS_VERIFY_ERROR;
+ }
+#endif
+
+ debug("found %d fingerprints in DNS", keys->rri_nrdatas);
+
+ /* Initialize host key parameters */
+ if (!dns_read_key(&hostkey_algorithm, &hostkey_digest_type,
+ &hostkey_digest, &hostkey_digest_len, hostkey)) {
+ error("Error calculating host key fingerprint.");
+ return DNS_VERIFY_ERROR;
+ }
+
+ for (counter = 0 ; counter < keys->rri_nrdatas ; counter++) {
+ /*
+ * Extract the key from the answer. Ignore any badly
+ * formatted keys.
+ */
+ if (!dns_read_rdata(&dnskey_algorithm, &dnskey_digest_type,
+ &dnskey_digest, &dnskey_digest_len,
+ keys->rri_rdatas[counter].rdi_data,
+ keys->rri_rdatas[counter].rdi_length)) {
+ verbose("Error parsing fingerprint from DNS.");
+ continue;
+ }
+
+ /* Check if the current key is the same as the given key */
+ if (hostkey_algorithm == dnskey_algorithm &&
+ hostkey_digest_type == dnskey_digest_type) {
+
+ if (hostkey_digest_len == dnskey_digest_len &&
+ memcmp(hostkey_digest, dnskey_digest,
+ hostkey_digest_len) == 0) {
+
+ /* Matching algoritm and digest. */
+ freerrset(keys);
+#ifdef DNSSEC
+ debug("matching host key fingerprint found in DNS");
+ return DNS_VERIFY_OK;
+#else
+ logit("Matching host key fingerprint found in DNS.");
+ return DNS_VERIFY_ERROR;
+#endif
+ } else {
+ /* Correct algorithm but bad digest */
+ debug("verify_hostkey_dns: failed");
+ failures++;
+ }
+ }
+ }
+
+ freerrset(keys);
+
+ if (failures) {
+ error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
+ error("@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @");
+ error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
+ error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!");
+ error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!");
+ error("It is also possible that the %s host key has just been changed.",
+ key_type(hostkey));
+ error("Please contact your system administrator.");
+ return DNS_VERIFY_FAILED;
+ }
+
+ debug("fingerprints found in DNS, but none of them matched");
+
+ return DNS_VERIFY_ERROR;
+}
+
+
+/*
+ * Export the fingerprint of a key as a DNS resource record
+ */
+int
+export_dns_rr(const char *hostname, Key *key, FILE *f, int generic)
+{
+ u_int8_t rdata_pubkey_algorithm = 0;
+ u_int8_t rdata_digest_type = DNS_HASH_SHA1;
+ u_char *rdata_digest;
+ u_int rdata_digest_len;
+
+ int i;
+ int success = 0;
+
+ if (dns_read_key(&rdata_pubkey_algorithm, &rdata_digest_type,
+ &rdata_digest, &rdata_digest_len, key)) {
+
+ if (generic)
+ fprintf(f, "%s IN TYPE%d \\# %d %02x %02x ", hostname,
+ DNS_RDATATYPE_SSHFP, 2 + rdata_digest_len,
+ rdata_pubkey_algorithm, rdata_digest_type);
+ else
+ fprintf(f, "%s IN SSHFP %d %d ", hostname,
+ rdata_pubkey_algorithm, rdata_digest_type);
+
+ for (i = 0; i < rdata_digest_len; i++)
+ fprintf(f, "%02x", rdata_digest[i]);
+ fprintf(f, "\n");
+ success = 1;
+ } else {
+ error("dns_export_rr: unsupported algorithm");
+ }
+
+ return success;
+}
+
+#endif /* DNS */
diff --git a/usr.bin/ssh/dns.h b/usr.bin/ssh/dns.h
new file mode 100644
index 00000000000..b31a106a403
--- /dev/null
+++ b/usr.bin/ssh/dns.h
@@ -0,0 +1,59 @@
+/* $OpenBSD: dns.h,v 1.1 2003/05/14 18:16:20 jakob Exp $ */
+
+/*
+ * Copyright (c) 2003 Wesley Griffin. All rights reserved.
+ * Copyright (c) 2003 Jakob Schlyter. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "includes.h"
+
+#ifdef DNS
+#ifndef DNS_H
+#define DNS_H
+
+enum dns_types {
+ DNS_KEY_RESERVED,
+ DNS_KEY_RSA,
+ DNS_KEY_DSA
+};
+
+enum dns_hashes {
+ DNS_HASH_RESERVED,
+ DNS_HASH_SHA1
+};
+
+#define DNS_RDATACLASS_IN 1
+#define DNS_RDATATYPE_SSHFP 44
+
+#define DNS_VERIFY_FAILED -1
+#define DNS_VERIFY_OK 0
+#define DNS_VERIFY_ERROR 1
+
+int verify_host_key_dns(const char *, struct sockaddr *, Key *);
+int export_dns_rr(const char *, Key *, FILE *, int);
+
+#endif /* DNS_H */
+#endif /* DNS */
diff --git a/usr.bin/ssh/key.c b/usr.bin/ssh/key.c
index 060b63745a3..d918cfd0a3b 100644
--- a/usr.bin/ssh/key.c
+++ b/usr.bin/ssh/key.c
@@ -32,7 +32,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
-RCSID("$OpenBSD: key.c,v 1.51 2003/02/12 09:33:04 markus Exp $");
+RCSID("$OpenBSD: key.c,v 1.52 2003/05/14 18:16:20 jakob Exp $");
#include <openssl/evp.h>
@@ -169,7 +169,7 @@ key_equal(Key *a, Key *b)
return 0;
}
-static u_char *
+u_char*
key_fingerprint_raw(Key *k, enum fp_type dgst_type, u_int *dgst_raw_length)
{
const EVP_MD *md = NULL;
diff --git a/usr.bin/ssh/key.h b/usr.bin/ssh/key.h
index 725c7a04a7b..a7b6afe86df 100644
--- a/usr.bin/ssh/key.h
+++ b/usr.bin/ssh/key.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: key.h,v 1.20 2003/02/12 09:33:04 markus Exp $ */
+/* $OpenBSD: key.h,v 1.21 2003/05/14 18:16:20 jakob Exp $ */
/*
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@@ -61,6 +61,7 @@ void key_free(Key *);
Key *key_demote(Key *);
int key_equal(Key *, Key *);
char *key_fingerprint(Key *, enum fp_type, enum fp_rep);
+u_char *key_fingerprint_raw(Key *, enum fp_type, u_int *);
char *key_type(Key *);
int key_write(Key *, FILE *);
int key_read(Key *, char **);
diff --git a/usr.bin/ssh/lib/Makefile b/usr.bin/ssh/lib/Makefile
index a6495134c0c..91c214ad4e8 100644
--- a/usr.bin/ssh/lib/Makefile
+++ b/usr.bin/ssh/lib/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.40 2003/04/09 08:24:24 hin Exp $
+# $OpenBSD: Makefile,v 1.41 2003/05/14 18:16:21 jakob Exp $
.PATH: ${.CURDIR}/..
@@ -9,7 +9,7 @@ SRCS= authfd.c authfile.c bufaux.c buffer.c canohost.c channels.c \
rsa.c tildexpand.c ttymodes.c xmalloc.c atomicio.c \
key.c dispatch.c kex.c mac.c uuencode.c misc.c \
rijndael.c ssh-dss.c ssh-rsa.c dh.c kexdh.c kexgex.c \
- kexdhc.c kexgexc.c scard.c msg.c progressmeter.c
+ kexdhc.c kexgexc.c scard.c msg.c progressmeter.c dns.c
DEBUGLIBS= no
NOPROFILE= yes
diff --git a/usr.bin/ssh/readconf.c b/usr.bin/ssh/readconf.c
index 871415952f3..357ddc0bbcf 100644
--- a/usr.bin/ssh/readconf.c
+++ b/usr.bin/ssh/readconf.c
@@ -12,7 +12,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: readconf.c,v 1.106 2003/04/09 12:00:37 djm Exp $");
+RCSID("$OpenBSD: readconf.c,v 1.107 2003/05/14 18:16:20 jakob Exp $");
#include "ssh.h"
#include "xmalloc.h"
@@ -114,7 +114,7 @@ typedef enum {
oDynamicForward, oPreferredAuthentications, oHostbasedAuthentication,
oHostKeyAlgorithms, oBindAddress, oSmartcardDevice,
oClearAllForwardings, oNoHostAuthenticationForLocalhost,
- oEnableSSHKeysign, oRekeyLimit,
+ oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS,
oDeprecated
} OpCodes;
@@ -187,6 +187,7 @@ static struct {
{ "smartcarddevice", oSmartcardDevice },
{ "clearallforwardings", oClearAllForwardings },
{ "enablesshkeysign", oEnableSSHKeysign },
+ { "verifyhostkeydns", oVerifyHostKeyDNS },
{ "nohostauthenticationforlocalhost", oNoHostAuthenticationForLocalhost },
{ "rekeylimit", oRekeyLimit },
{ NULL, oBadOption }
@@ -390,6 +391,10 @@ parse_flag:
intptr = &options->check_host_ip;
goto parse_flag;
+ case oVerifyHostKeyDNS:
+ intptr = &options->verify_host_key_dns;
+ goto parse_flag;
+
case oStrictHostKeyChecking:
intptr = &options->strict_host_key_checking;
arg = strdelim(&s);
@@ -827,6 +832,7 @@ initialize_options(Options * options)
options->enable_ssh_keysign = - 1;
options->no_host_authentication_for_localhost = - 1;
options->rekey_limit = - 1;
+ options->verify_host_key_dns = -1;
}
/*
@@ -945,6 +951,8 @@ fill_default_options(Options * options)
options->enable_ssh_keysign = 0;
if (options->rekey_limit == -1)
options->rekey_limit = 0;
+ if (options->verify_host_key_dns == -1)
+ options->verify_host_key_dns = 0;
/* options->proxy_command should not be set by default */
/* options->user will be set in the main program if appropriate */
/* options->hostname will be set in the main program if appropriate */
diff --git a/usr.bin/ssh/readconf.h b/usr.bin/ssh/readconf.h
index d35472117f6..d141b8c00f1 100644
--- a/usr.bin/ssh/readconf.h
+++ b/usr.bin/ssh/readconf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: readconf.h,v 1.47 2003/04/02 09:48:07 markus Exp $ */
+/* $OpenBSD: readconf.h,v 1.48 2003/05/14 18:16:20 jakob Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -86,6 +86,7 @@ typedef struct {
char *preferred_authentications;
char *bind_address; /* local socket address for connection to sshd */
char *smartcard_device; /* Smartcard reader device */
+ int verify_host_key_dns; /* Verify host key using DNS */
int num_identity_files; /* Number of files for RSA/DSA identities. */
char *identity_files[SSH_MAX_IDENTITY_FILES];
diff --git a/usr.bin/ssh/ssh-keygen.1 b/usr.bin/ssh/ssh-keygen.1
index 000e8ff2a46..613d71a0772 100644
--- a/usr.bin/ssh/ssh-keygen.1
+++ b/usr.bin/ssh/ssh-keygen.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: ssh-keygen.1,v 1.56 2003/03/28 10:11:43 jmc Exp $
+.\" $OpenBSD: ssh-keygen.1,v 1.57 2003/05/14 18:16:20 jakob Exp $
.\"
.\" -*- nroff -*-
.\"
@@ -83,6 +83,10 @@
.Nm ssh-keygen
.Fl U Ar reader
.Op Fl f Ar input_keyfile
+.Nm ssh-keygen
+.Fl r Ar hostname
+.Op Fl f Ar input_keyfile
+.Op Fl g
.Sh DESCRIPTION
.Nm
generates, manages and converts authentication keys for
@@ -163,6 +167,8 @@ print the key in a
to stdout.
This option allows exporting keys for use by several commercial
SSH implementations.
+.It Fl g
+Use generic DNS resource record format.
.It Fl f Ar filename
Specifies the filename of the key file.
.It Fl i
@@ -218,6 +224,9 @@ Provides the (old) passphrase.
.It Fl U Ar reader
Upload an existing RSA private key into the smartcard in
.Ar reader .
+.It Fl r Ar hostname
+Print DNS resource record with the specified
+.Ar hostname .
.El
.Sh FILES
.Bl -tag -width Ds
diff --git a/usr.bin/ssh/ssh-keygen.c b/usr.bin/ssh/ssh-keygen.c
index 67c5173c156..00042219727 100644
--- a/usr.bin/ssh/ssh-keygen.c
+++ b/usr.bin/ssh/ssh-keygen.c
@@ -12,7 +12,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: ssh-keygen.c,v 1.104 2003/05/11 16:56:48 markus Exp $");
+RCSID("$OpenBSD: ssh-keygen.c,v 1.105 2003/05/14 18:16:20 jakob Exp $");
#include <openssl/evp.h>
#include <openssl/pem.h>
@@ -70,6 +70,7 @@ char *identity_comment = NULL;
int convert_to_ssh2 = 0;
int convert_from_ssh2 = 0;
int print_public = 0;
+int print_generic = 0;
char *key_type_name = NULL;
@@ -616,6 +617,38 @@ do_change_passphrase(struct passwd *pw)
exit(0);
}
+#ifdef DNS
+/*
+ * Print the SSHFP RR.
+ */
+static void
+do_print_resource_record(struct passwd *pw, char *hostname)
+{
+ Key *public;
+ char *comment = NULL;
+ struct stat st;
+
+ if (!have_identity)
+ ask_filename(pw, "Enter file in which the key is");
+ if (stat(identity_file, &st) < 0) {
+ perror(identity_file);
+ exit(1);
+ }
+ public = key_load_public(identity_file, &comment);
+ if (public != NULL) {
+ export_dns_rr(hostname, public, stdout, print_generic);
+ key_free(public);
+ xfree(comment);
+ exit(0);
+ }
+ if (comment)
+ xfree(comment);
+
+ printf("failed to read v2 public key from %s.\n", identity_file);
+ exit(1);
+}
+#endif /* DNS */
+
/*
* Change the comment of a private key file.
*/
@@ -722,6 +755,7 @@ usage(void)
fprintf(stderr, " -c Change comment in private and public key files.\n");
fprintf(stderr, " -e Convert OpenSSH to IETF SECSH key file.\n");
fprintf(stderr, " -f filename Filename of the key file.\n");
+ fprintf(stderr, " -g Use generic DNS resource record format.\n");
fprintf(stderr, " -i Convert IETF SECSH to OpenSSH key file.\n");
fprintf(stderr, " -l Show fingerprint of key file.\n");
fprintf(stderr, " -p Change passphrase of private key file.\n");
@@ -732,6 +766,9 @@ usage(void)
fprintf(stderr, " -C comment Provide new comment.\n");
fprintf(stderr, " -N phrase Provide new passphrase.\n");
fprintf(stderr, " -P phrase Provide old passphrase.\n");
+#ifdef DNS
+ fprintf(stderr, " -r hostname Print DNS resource record.\n");
+#endif /* DNS */
#ifdef SMARTCARD
fprintf(stderr, " -D reader Download public key from smartcard.\n");
fprintf(stderr, " -U reader Upload private key to smartcard.\n");
@@ -748,6 +785,7 @@ main(int ac, char **av)
{
char dotsshdir[MAXPATHLEN], comment[1024], *passphrase1, *passphrase2;
char *reader_id = NULL;
+ char *resource_record_hostname = NULL;
Key *private, *public;
struct passwd *pw;
struct stat st;
@@ -770,7 +808,7 @@ main(int ac, char **av)
exit(1);
}
- while ((opt = getopt(ac, av, "deiqpclBRxXyb:f:t:U:D:P:N:C:")) != -1) {
+ while ((opt = getopt(ac, av, "degiqpclBRxXyb:f:t:U:D:P:N:C:r:")) != -1) {
switch (opt) {
case 'b':
bits = atoi(optarg);
@@ -795,6 +833,9 @@ main(int ac, char **av)
strlcpy(identity_file, optarg, sizeof(identity_file));
have_identity = 1;
break;
+ case 'g':
+ print_generic = 1;
+ break;
case 'P':
identity_passphrase = optarg;
break;
@@ -835,6 +876,9 @@ main(int ac, char **av)
case 'U':
reader_id = optarg;
break;
+ case 'r':
+ resource_record_hostname = optarg;
+ break;
case '?':
default:
usage();
@@ -860,6 +904,13 @@ main(int ac, char **av)
do_convert_from_ssh2(pw);
if (print_public)
do_print_public(pw);
+ if (resource_record_hostname != NULL) {
+#ifdef DNS
+ do_print_resource_record(pw, resource_record_hostname);
+#else /* DNS */
+ fatal("no DNS support.");
+#endif /* DNS */
+ }
if (reader_id != NULL) {
#ifdef SMARTCARD
if (download)
diff --git a/usr.bin/ssh/ssh_config.5 b/usr.bin/ssh/ssh_config.5
index 44208b431f5..2f33aa3f3fd 100644
--- a/usr.bin/ssh/ssh_config.5
+++ b/usr.bin/ssh/ssh_config.5
@@ -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.
.\"
-.\" $OpenBSD: ssh_config.5,v 1.7 2003/03/28 10:11:43 jmc Exp $
+.\" $OpenBSD: ssh_config.5,v 1.8 2003/05/14 18:16:20 jakob Exp $
.Dd September 25, 1999
.Dt SSH_CONFIG 5
.Os
@@ -618,6 +618,11 @@ having to remember to give the user name on the command line.
Specifies a file to use for the user
host key database instead of
.Pa $HOME/.ssh/known_hosts .
+.It Cm VerifyHostKeyDNS
+Specifies whether to verify the remote key using DNS and SSHFP resource
+records.
+The default is
+.Dq no .
.It Cm XAuthLocation
Specifies the full pathname of the
.Xr xauth 1
diff --git a/usr.bin/ssh/sshconnect.c b/usr.bin/ssh/sshconnect.c
index f5d84761506..20d4c1d0d45 100644
--- a/usr.bin/ssh/sshconnect.c
+++ b/usr.bin/ssh/sshconnect.c
@@ -13,7 +13,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: sshconnect.c,v 1.139 2003/04/14 14:17:50 markus Exp $");
+RCSID("$OpenBSD: sshconnect.c,v 1.140 2003/05/14 18:16:21 jakob Exp $");
#include <openssl/bn.h>
@@ -33,6 +33,10 @@ RCSID("$OpenBSD: sshconnect.c,v 1.139 2003/04/14 14:17:50 markus Exp $");
#include "misc.h"
#include "readpass.h"
+#ifdef DNS
+#include "dns.h"
+#endif
+
char *client_version_string = NULL;
char *server_version_string = NULL;
@@ -789,11 +793,28 @@ fail:
return -1;
}
+/* returns 0 if key verifies or -1 if key does NOT verify */
int
verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
{
struct stat st;
+#ifdef DNS
+ if (options.verify_host_key_dns) {
+ switch(verify_host_key_dns(host, hostaddr, host_key)) {
+ case DNS_VERIFY_OK:
+ return 0;
+ case DNS_VERIFY_FAILED:
+ return -1;
+ case DNS_VERIFY_ERROR:
+ break;
+ default:
+ debug3("bad return value from verify_host_key_dns");
+ break;
+ }
+ }
+#endif /* DNS */
+
/* return ok if the key can be found in an old keyfile */
if (stat(options.system_hostfile2, &st) == 0 ||
stat(options.user_hostfile2, &st) == 0) {