Ensure that all returned SSHFP records for the specified host name and
authordtucker <dtucker@openbsd.org>
Mon, 19 Jul 2021 03:13:28 +0000 (03:13 +0000)
committerdtucker <dtucker@openbsd.org>
Mon, 19 Jul 2021 03:13:28 +0000 (03:13 +0000)
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@.

usr.bin/ssh/dns.c
usr.bin/ssh/dns.h

index 7c68b36..8e393fa 100644 (file)
@@ -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.
@@ -73,6 +73,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,
@@ -84,32 +85,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) {
@@ -131,7 +121,6 @@ dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type,
        } else {
                *digest = NULL;
                *digest_len = 0;
-               success = 0;
        }
 
        return success;
@@ -210,7 +199,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;
 
@@ -246,14 +234,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;
 
@@ -269,35 +249,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");
index 91f3c63..c9b61c4 100644 (file)
@@ -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 *);