]> git.ipfire.org Git - thirdparty/openssh-portable.git/commitdiff
upstream: Ensure that all returned SSHFP records for the specified host
authordtucker@openbsd.org <dtucker@openbsd.org>
Mon, 19 Jul 2021 03:13:28 +0000 (03:13 +0000)
committerDarren Tucker <dtucker@dtucker.net>
Mon, 19 Jul 2021 03:46:13 +0000 (13:46 +1000)
name and hostkey type match instead of only one.  While there, simplify the
code somewhat and add some debugging.  Based on discussion in bz#3322, ok
djm@.

OpenBSD-Commit-ID: 0a6a0a476eb7f9dfe8fe2c05a1a395e3e9b22ee4

dns.c
dns.h

diff --git a/dns.c b/dns.c
index e8589f68d4a1aae3e963102e990fd5a04a4cba58..1cfc38e7cc43680193eb5b57fdb779ec06fb8153 100644 (file)
--- a/dns.c
+++ b/dns.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dns.c,v 1.40 2021/07/05 01:16:46 dtucker Exp $ */
+/* $OpenBSD: dns.c,v 1.41 2021/07/19 03:13:28 dtucker Exp $ */
 
 /*
  * Copyright (c) 2003 Wesley Griffin. All rights reserved.
@@ -75,6 +75,7 @@ dns_result_totext(unsigned int res)
 
 /*
  * Read SSHFP parameters from key buffer.
+ * Caller must free digest which is allocated by sshkey_fingerprint_raw().
  */
 static int
 dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type,
@@ -86,32 +87,21 @@ dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type,
        switch (key->type) {
        case KEY_RSA:
                *algorithm = SSHFP_KEY_RSA;
-               if (!*digest_type)
-                       *digest_type = SSHFP_HASH_SHA1;
                break;
        case KEY_DSA:
                *algorithm = SSHFP_KEY_DSA;
-               if (!*digest_type)
-                       *digest_type = SSHFP_HASH_SHA1;
                break;
        case KEY_ECDSA:
                *algorithm = SSHFP_KEY_ECDSA;
-               if (!*digest_type)
-                       *digest_type = SSHFP_HASH_SHA256;
                break;
        case KEY_ED25519:
                *algorithm = SSHFP_KEY_ED25519;
-               if (!*digest_type)
-                       *digest_type = SSHFP_HASH_SHA256;
                break;
        case KEY_XMSS:
                *algorithm = SSHFP_KEY_XMSS;
-               if (!*digest_type)
-                       *digest_type = SSHFP_HASH_SHA256;
                break;
        default:
                *algorithm = SSHFP_KEY_RESERVED; /* 0 */
-               *digest_type = SSHFP_HASH_RESERVED; /* 0 */
        }
 
        switch (*digest_type) {
@@ -133,7 +123,6 @@ dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type,
        } else {
                *digest = NULL;
                *digest_len = 0;
-               success = 0;
        }
 
        return success;
@@ -212,7 +201,6 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address,
        struct rrsetinfo *fingerprints = NULL;
 
        u_int8_t hostkey_algorithm;
-       u_int8_t hostkey_digest_type = SSHFP_HASH_RESERVED;
        u_char *hostkey_digest;
        size_t hostkey_digest_len;
 
@@ -248,14 +236,6 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address,
                    fingerprints->rri_nrdatas);
        }
 
-       /* Initialize default 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 -1;
-       }
-
        if (fingerprints->rri_nrdatas)
                *flags |= DNS_VERIFY_FOUND;
 
@@ -271,35 +251,41 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address,
                        verbose("Error parsing fingerprint from DNS.");
                        continue;
                }
-
-               if (hostkey_digest_type != dnskey_digest_type) {
-                       hostkey_digest_type = dnskey_digest_type;
-                       free(hostkey_digest);
-
-                       /* Initialize host key parameters */
-                       if (!dns_read_key(&hostkey_algorithm,
-                           &hostkey_digest_type, &hostkey_digest,
-                           &hostkey_digest_len, hostkey)) {
-                               error("Error calculating key fingerprint.");
-                               freerrset(fingerprints);
-                               return -1;
-                       }
+               debug3_f("checking SSHFP type %d fptype %d", dnskey_algorithm,
+                   dnskey_digest_type);
+
+               /* Calculate host key fingerprint. */
+               if (!dns_read_key(&hostkey_algorithm, &dnskey_digest_type,
+                   &hostkey_digest, &hostkey_digest_len, hostkey)) {
+                       error("Error calculating key fingerprint.");
+                       freerrset(fingerprints);
+                       return -1;
                }
 
                /* 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 &&
-                           timingsafe_bcmp(hostkey_digest, dnskey_digest,
-                           hostkey_digest_len) == 0)
+                   hostkey_digest_len == dnskey_digest_len) {
+                       if (timingsafe_bcmp(hostkey_digest, dnskey_digest,
+                           hostkey_digest_len) == 0) {
+                               debug_f("matched SSHFP type %d fptype %d",
+                                   dnskey_algorithm, dnskey_digest_type);
                                *flags |= DNS_VERIFY_MATCH;
+                       } else {
+                               debug_f("failed SSHFP type %d fptype %d",
+                                   dnskey_algorithm, dnskey_digest_type);
+                               *flags |= DNS_VERIFY_FAILED;
+                       }
                }
                free(dnskey_digest);
+               free(hostkey_digest); /* from sshkey_fingerprint_raw() */
        }
 
-       free(hostkey_digest); /* from sshkey_fingerprint_raw() */
        freerrset(fingerprints);
 
+       /* If any fingerprint failed to validate, return failure. */
+       if (*flags & DNS_VERIFY_FAILED)
+               *flags &= ~DNS_VERIFY_MATCH;
+
        if (*flags & DNS_VERIFY_FOUND)
                if (*flags & DNS_VERIFY_MATCH)
                        debug("matching host key fingerprint found in DNS");
diff --git a/dns.h b/dns.h
index 91f3c632dd1bbfd2a14de184cc7fac266721092c..c9b61c4f28f89659a34ba1b6ee903e9e2d91fb7d 100644 (file)
--- a/dns.h
+++ b/dns.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: dns.h,v 1.18 2018/02/23 15:58:37 markus Exp $ */
+/* $OpenBSD: dns.h,v 1.19 2021/07/19 03:13:28 dtucker Exp $ */
 
 /*
  * Copyright (c) 2003 Wesley Griffin. All rights reserved.
@@ -50,6 +50,7 @@ enum sshfp_hashes {
 #define DNS_VERIFY_FOUND       0x00000001
 #define DNS_VERIFY_MATCH       0x00000002
 #define DNS_VERIFY_SECURE      0x00000004
+#define DNS_VERIFY_FAILED      0x00000008
 
 int    verify_host_key_dns(const char *, struct sockaddr *,
     struct sshkey *, int *);