- jakob@cvs.openbsd.org 2003/11/12 16:39:58
[dns.c dns.h readconf.c ssh_config.5 sshconnect.c]
update SSHFP validation. ok markus@
diff --git a/ChangeLog b/ChangeLog
index 40a3931..b5667e7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -31,6 +31,9 @@
- dtucker@cvs.openbsd.org 2003/11/12 10:12:15
[scp.c]
When called with -q, pass -q to ssh; suppresses SSH2 banner. ok markus@
+ - jakob@cvs.openbsd.org 2003/11/12 16:39:58
+ [dns.c dns.h readconf.c ssh_config.5 sshconnect.c]
+ update SSHFP validation. ok markus@
20031115
- (dtucker) [regress/agent-ptrace.sh] Test for GDB output from Solaris and
@@ -1451,4 +1454,4 @@
- Fix sshd BindAddress and -b options for systems using fake-getaddrinfo.
Report from murple@murple.net, diagnosis from dtucker@zip.com.au
-$Id: ChangeLog,v 1.3105 2003/11/17 10:19:05 djm Exp $
+$Id: ChangeLog,v 1.3106 2003/11/17 10:19:29 djm Exp $
diff --git a/dns.c b/dns.c
index 2fff1b8..2342b66 100644
--- a/dns.c
+++ b/dns.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dns.c,v 1.7 2003/10/14 19:42:10 jakob Exp $ */
+/* $OpenBSD: dns.c,v 1.8 2003/11/12 16:39:58 jakob Exp $ */
/*
* Copyright (c) 2003 Wesley Griffin. All rights reserved.
@@ -43,7 +43,7 @@
#include "uuencode.h"
extern char *__progname;
-RCSID("$OpenBSD: dns.c,v 1.7 2003/10/14 19:42:10 jakob Exp $");
+RCSID("$OpenBSD: dns.c,v 1.8 2003/11/12 16:39:58 jakob Exp $");
#ifndef LWRES
static const char *errset_text[] = {
@@ -83,7 +83,7 @@
*/
static int
dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type,
- u_char **digest, u_int *digest_len, Key *key)
+ u_char **digest, u_int *digest_len, const Key *key)
{
int success = 0;
@@ -145,16 +145,15 @@
/*
* Verify the given hostname, address and host key using DNS.
- * Returns 0 if key verifies or -1 if key does NOT verify
+ * Returns 0 if lookup succeeds, -1 otherwise
*/
int
verify_host_key_dns(const char *hostname, struct sockaddr *address,
- Key *hostkey)
+ const Key *hostkey, int *flags)
{
int counter;
int result;
struct rrsetinfo *fingerprints = NULL;
- int failures = 0;
u_int8_t hostkey_algorithm;
u_int8_t hostkey_digest_type;
@@ -166,6 +165,7 @@
u_char *dnskey_digest;
u_int dnskey_digest_len;
+ *flags = 0;
debug3("verify_hostkey_dns");
if (hostkey == NULL)
@@ -175,28 +175,29 @@
DNS_RDATATYPE_SSHFP, 0, &fingerprints);
if (result) {
verbose("DNS lookup error: %s", dns_result_totext(result));
- return DNS_VERIFY_ERROR;
+ return -1;
}
-#ifdef DNSSEC
- /* Only accept validated answers */
- if (!fingerprints->rri_flags & RRSET_VALIDATED) {
- error("Ignored unvalidated fingerprint from DNS.");
- freerrset(fingerprints);
- return DNS_VERIFY_ERROR;
+ if (fingerprints->rri_flags & RRSET_VALIDATED) {
+ *flags |= DNS_VERIFY_SECURE;
+ debug("found %d secure fingerprints in DNS",
+ fingerprints->rri_nrdatas);
+ } else {
+ debug("found %d insecure fingerprints in DNS",
+ fingerprints->rri_nrdatas);
}
-#endif
-
- debug("found %d fingerprints in DNS", fingerprints->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.");
freerrset(fingerprints);
- return DNS_VERIFY_ERROR;
+ return -1;
}
+ if (fingerprints->rri_nrdatas)
+ *flags |= DNS_VERIFY_FOUND;
+
for (counter = 0 ; counter < fingerprints->rri_nrdatas ; counter++) {
/*
* Extract the key from the answer. Ignore any badly
@@ -218,35 +219,22 @@
memcmp(hostkey_digest, dnskey_digest,
hostkey_digest_len) == 0) {
- /* Matching algoritm and digest. */
- freerrset(fingerprints);
- debug("matching host key fingerprint found in DNS");
- return DNS_VERIFY_OK;
- } else {
- /* Correct algorithm but bad digest */
- debug("verify_hostkey_dns: failed");
- failures++;
+ *flags |= DNS_VERIFY_MATCH;
}
}
}
freerrset(fingerprints);
- 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;
- }
+ if (*flags & DNS_VERIFY_FOUND)
+ if (*flags & DNS_VERIFY_MATCH)
+ debug("matching host key fingerprint found in DNS");
+ else
+ debug("mismatching host key fingerprint found in DNS");
+ else
+ debug("no host key fingerprint found in DNS");
- debug("fingerprints found in DNS, but none of them matched");
-
- return DNS_VERIFY_ERROR;
+ return 0;
}
@@ -254,7 +242,7 @@
* Export the fingerprint of a key as a DNS resource record
*/
int
-export_dns_rr(const char *hostname, Key *key, FILE *f, int generic)
+export_dns_rr(const char *hostname, const Key *key, FILE *f, int generic)
{
u_int8_t rdata_pubkey_algorithm = 0;
u_int8_t rdata_digest_type = SSHFP_HASH_SHA1;
diff --git a/dns.h b/dns.h
index 1eb07d9..c5da22e 100644
--- a/dns.h
+++ b/dns.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: dns.h,v 1.4 2003/10/14 19:42:10 jakob Exp $ */
+/* $OpenBSD: dns.h,v 1.5 2003/11/12 16:39:58 jakob Exp $ */
/*
* Copyright (c) 2003 Wesley Griffin. All rights reserved.
@@ -45,11 +45,12 @@
#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
+#define DNS_VERIFY_FOUND 0x00000001
+#define DNS_VERIFY_MATCH 0x00000002
+#define DNS_VERIFY_SECURE 0x00000004
-int verify_host_key_dns(const char *, struct sockaddr *, Key *);
-int export_dns_rr(const char *, Key *, FILE *, int);
+
+int verify_host_key_dns(const char *, struct sockaddr *, const Key *, int *);
+int export_dns_rr(const char *, const Key *, FILE *, int);
#endif /* DNS_H */
diff --git a/readconf.c b/readconf.c
index 86d28bc..da49a39 100644
--- a/readconf.c
+++ b/readconf.c
@@ -12,7 +12,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: readconf.c,v 1.124 2003/10/14 19:42:10 jakob Exp $");
+RCSID("$OpenBSD: readconf.c,v 1.125 2003/11/12 16:39:58 jakob Exp $");
#include "ssh.h"
#include "xmalloc.h"
@@ -401,10 +401,11 @@
case oVerifyHostKeyDNS:
intptr = &options->verify_host_key_dns;
- goto parse_flag;
+ goto parse_yesnoask;
case oStrictHostKeyChecking:
intptr = &options->strict_host_key_checking;
+parse_yesnoask:
arg = strdelim(&s);
if (!arg || *arg == '\0')
fatal("%.200s line %d: Missing yes/no/ask argument.",
diff --git a/ssh_config.5 b/ssh_config.5
index 9073ce5..55ca907 100644
--- a/ssh_config.5
+++ b/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.23 2003/10/12 13:12:13 jmc Exp $
+.\" $OpenBSD: ssh_config.5,v 1.24 2003/11/12 16:39:58 jakob Exp $
.Dd September 25, 1999
.Dt SSH_CONFIG 5
.Os
@@ -642,6 +642,23 @@
.It Cm VerifyHostKeyDNS
Specifies whether to verify the remote key using DNS and SSHFP resource
records.
+If this option is set to
+.Dq yes ,
+the client will implicitly trust keys that matches a secure fingerprint
+from DNS.
+Insecure fingerprints will be handled as if this option was set to
+.Dq ask .
+If this option is set to
+.Dq ask ,
+information on fingerprint match will be displayed, but the user will still
+need to confirm new host keys according to the
+.Cm StrictHostKeyChecking
+option.
+The argument must be
+.Dq yes ,
+.Dq no
+or
+.Dq ask .
The default is
.Dq no .
Note that this option applies to protocol version 2 only.
diff --git a/sshconnect.c b/sshconnect.c
index bf8c23d..5972e2b 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -13,7 +13,7 @@
*/
#include "includes.h"
-RCSID("$OpenBSD: sshconnect.c,v 1.152 2003/11/10 16:23:41 jakob Exp $");
+RCSID("$OpenBSD: sshconnect.c,v 1.153 2003/11/12 16:39:58 jakob Exp $");
#include <openssl/bn.h>
@@ -38,7 +38,7 @@
char *client_version_string = NULL;
char *server_version_string = NULL;
-int verified_host_key_dns = 0;
+int matching_host_key_dns = 0;
/* import */
extern Options options;
@@ -728,7 +728,7 @@
fp = key_fingerprint(host_key, SSH_FP_MD5, SSH_FP_HEX);
msg2[0] = '\0';
if (options.verify_host_key_dns) {
- if (verified_host_key_dns)
+ if (matching_host_key_dns)
snprintf(msg2, sizeof(msg2),
"Matching host key fingerprint"
" found in DNS.\n");
@@ -892,23 +892,25 @@
verify_host_key(char *host, struct sockaddr *hostaddr, Key *host_key)
{
struct stat st;
+ int flags = 0;
- if (options.verify_host_key_dns) {
- switch(verify_host_key_dns(host, hostaddr, host_key)) {
- case DNS_VERIFY_OK:
-#ifdef DNSSEC
- return 0;
-#else
- verified_host_key_dns = 1;
- break;
-#endif
- case DNS_VERIFY_FAILED:
- return -1;
- case DNS_VERIFY_ERROR:
- break;
- default:
- debug3("bad return value from verify_host_key_dns");
- break;
+ if (options.verify_host_key_dns &&
+ verify_host_key_dns(host, hostaddr, host_key, &flags) == 0) {
+
+ if (flags & DNS_VERIFY_FOUND) {
+
+ if (options.verify_host_key_dns == 1 &&
+ flags & DNS_VERIFY_MATCH &&
+ flags & DNS_VERIFY_SECURE)
+ return 0;
+
+ if (flags & DNS_VERIFY_MATCH) {
+ matching_host_key_dns = 1;
+ } else {
+ warn_changed_key(host_key);
+ error("Update the SSHFP RR in DNS with the new "
+ "host key to get rid of this message.");
+ }
}
}