OSDN Git Service

Specialize for gce targets in openssh am: eab54b0935
[android-x86/external-openssh.git] / dns.c
diff --git a/dns.c b/dns.c
index 87c131f..f18d692 100644 (file)
--- a/dns.c
+++ b/dns.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dns.c,v 1.27 2010/08/31 11:54:45 djm Exp $ */
+/* $OpenBSD: dns.c,v 1.35 2015/08/20 22:32:42 deraadt Exp $ */
 
 /*
  * Copyright (c) 2003 Wesley Griffin. All rights reserved.
 #include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
 
 #include "xmalloc.h"
-#include "key.h"
+#include "sshkey.h"
+#include "ssherr.h"
 #include "dns.h"
 #include "log.h"
+#include "digest.h"
 
 static const char *errset_text[] = {
        "success",              /* 0 ERRSET_SUCCESS */
@@ -75,30 +79,55 @@ dns_result_totext(unsigned int res)
  */
 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, size_t *digest_len, struct sshkey *key)
 {
-       int success = 0;
+       int r, success = 0;
+       int fp_alg = -1;
 
        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;
-       /* XXX KEY_ECDSA */
        default:
                *algorithm = SSHFP_KEY_RESERVED; /* 0 */
+               *digest_type = SSHFP_HASH_RESERVED; /* 0 */
        }
 
-       if (*algorithm) {
-               *digest_type = SSHFP_HASH_SHA1;
-               *digest = key_fingerprint_raw(key, SSH_FP_SHA1, digest_len);
-               if (*digest == NULL)
-                       fatal("dns_read_key: null from key_fingerprint_raw()");
+       switch (*digest_type) {
+       case SSHFP_HASH_SHA1:
+               fp_alg = SSH_DIGEST_SHA1;
+               break;
+       case SSHFP_HASH_SHA256:
+               fp_alg = SSH_DIGEST_SHA256;
+               break;
+       default:
+               *digest_type = SSHFP_HASH_RESERVED; /* 0 */
+       }
+
+       if (*algorithm && *digest_type) {
+               if ((r = sshkey_fingerprint_raw(key, fp_alg, digest,
+                   digest_len)) != 0)
+                       fatal("%s: sshkey_fingerprint_raw: %s", __func__,
+                          ssh_err(r));
                success = 1;
        } else {
-               *digest_type = SSHFP_HASH_RESERVED;
                *digest = NULL;
                *digest_len = 0;
                success = 0;
@@ -112,7 +141,7 @@ dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type,
  */
 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)
+    u_char **digest, size_t *digest_len, u_char *rdata, int rdata_len)
 {
        int success = 0;
 
@@ -125,7 +154,7 @@ dns_read_rdata(u_int8_t *algorithm, u_int8_t *digest_type,
                *digest_len = rdata_len - 2;
 
                if (*digest_len > 0) {
-                       *digest = (u_char *) xmalloc(*digest_len);
+                       *digest = xmalloc(*digest_len);
                        memcpy(*digest, rdata + 2, *digest_len);
                } else {
                        *digest = (u_char *)xstrdup("");
@@ -173,21 +202,21 @@ is_numeric_hostname(const char *hostname)
  */
 int
 verify_host_key_dns(const char *hostname, struct sockaddr *address,
-    Key *hostkey, int *flags)
+    struct sshkey *hostkey, int *flags)
 {
        u_int counter;
        int result;
        struct rrsetinfo *fingerprints = NULL;
 
        u_int8_t hostkey_algorithm;
-       u_int8_t hostkey_digest_type;
+       u_int8_t hostkey_digest_type = SSHFP_HASH_RESERVED;
        u_char *hostkey_digest;
-       u_int hostkey_digest_len;
+       size_t hostkey_digest_len;
 
        u_int8_t dnskey_algorithm;
        u_int8_t dnskey_digest_type;
        u_char *dnskey_digest;
-       u_int dnskey_digest_len;
+       size_t dnskey_digest_len;
 
        *flags = 0;
 
@@ -200,13 +229,14 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address,
                return -1;
        }
 
-#ifndef ANDROID
+#if !defined(ANDROID)
        result = getrrsetbyname(hostname, DNS_RDATACLASS_IN,
            DNS_RDATATYPE_SSHFP, 0, &fingerprints);
 #else
-       /* unsupported in android */
+       /* unsupported in Android. */
        result = -1;
 #endif
+
        if (result) {
                verbose("DNS lookup error: %s", dns_result_totext(result));
                return -1;
@@ -221,11 +251,11 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address,
                    fingerprints->rri_nrdatas);
        }
 
-       /* Initialize host key parameters */
+       /* 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.");
-#ifndef ANDROID
+#if !defined(ANDROID)
                freerrset(fingerprints);
 #endif
                return -1;
@@ -247,22 +277,35 @@ verify_host_key_dns(const char *hostname, struct sockaddr *address,
                        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.");
+#if !defined(ANDROID)
+                               freerrset(fingerprints);
+#endif
+                               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 &&
-                           memcmp(hostkey_digest, dnskey_digest,
-                           hostkey_digest_len) == 0) {
-
+                           timingsafe_bcmp(hostkey_digest, dnskey_digest,
+                           hostkey_digest_len) == 0)
                                *flags |= DNS_VERIFY_MATCH;
-                       }
                }
-               xfree(dnskey_digest);
+               free(dnskey_digest);
        }
 
-       xfree(hostkey_digest); /* from key_fingerprint_raw() */
-#ifndef ANDROID
+       free(hostkey_digest); /* from sshkey_fingerprint_raw() */
+#if !defined(ANDROID)
        freerrset(fingerprints);
 #endif
 
@@ -281,34 +324,39 @@ 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, Key *key, FILE *f, int generic)
+export_dns_rr(const char *hostname, struct sshkey *key, FILE *f, int generic)
 {
        u_int8_t rdata_pubkey_algorithm = 0;
-       u_int8_t rdata_digest_type = SSHFP_HASH_SHA1;
+       u_int8_t rdata_digest_type = SSHFP_HASH_RESERVED;
+       u_int8_t dtype;
        u_char *rdata_digest;
-       u_int rdata_digest_len;
-
-       u_int i;
+       size_t i, rdata_digest_len;
        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 (dtype = SSHFP_HASH_SHA1; dtype < SSHFP_HASH_MAX; dtype++) {
+               rdata_digest_type = dtype;
+               if (dns_read_key(&rdata_pubkey_algorithm, &rdata_digest_type,
+                   &rdata_digest, &rdata_digest_len, key)) {
+                       if (generic) {
+                               fprintf(f, "%s IN TYPE%d \\# %zu %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");
+                       free(rdata_digest); /* from sshkey_fingerprint_raw() */
+                       success = 1;
+               }
+       }
 
-               for (i = 0; i < rdata_digest_len; i++)
-                       fprintf(f, "%02x", rdata_digest[i]);
-               fprintf(f, "\n");
-               xfree(rdata_digest); /* from key_fingerprint_raw() */
-               success = 1;
-       } else {
-               error("export_dns_rr: unsupported algorithm");
+       /* No SSHFP record was generated at all */
+       if (success == 0) {
+               error("%s: unsupported algorithm and/or digest_type", __func__);
        }
 
        return success;