LCOV - code coverage report
Current view: top level - openssh-6.6p1 - dns.c (source / functions) Hit Total Coverage
Test: lcov_coverage_final.info Lines: 0 124 0.0 %
Date: 2014-08-01 Functions: 0 6 0.0 %
Branches: 0 76 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* $OpenBSD: dns.c,v 1.29 2013/05/17 00:13:13 djm Exp $ */
       2                 :            : 
       3                 :            : /*
       4                 :            :  * Copyright (c) 2003 Wesley Griffin. All rights reserved.
       5                 :            :  * Copyright (c) 2003 Jakob Schlyter. All rights reserved.
       6                 :            :  *
       7                 :            :  * Redistribution and use in source and binary forms, with or without
       8                 :            :  * modification, are permitted provided that the following conditions
       9                 :            :  * are met:
      10                 :            :  * 1. Redistributions of source code must retain the above copyright
      11                 :            :  *    notice, this list of conditions and the following disclaimer.
      12                 :            :  * 2. Redistributions in binary form must reproduce the above copyright
      13                 :            :  *    notice, this list of conditions and the following disclaimer in the
      14                 :            :  *    documentation and/or other materials provided with the distribution.
      15                 :            :  *
      16                 :            :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
      17                 :            :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      18                 :            :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      19                 :            :  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
      20                 :            :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      21                 :            :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      22                 :            :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      23                 :            :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      24                 :            :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      25                 :            :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      26                 :            :  */
      27                 :            : 
      28                 :            : #include "includes.h"
      29                 :            : 
      30                 :            : #include <sys/types.h>
      31                 :            : #include <sys/socket.h>
      32                 :            : 
      33                 :            : #include <netdb.h>
      34                 :            : #include <stdarg.h>
      35                 :            : #include <stdio.h>
      36                 :            : #include <string.h>
      37                 :            : 
      38                 :            : #include "xmalloc.h"
      39                 :            : #include "key.h"
      40                 :            : #include "dns.h"
      41                 :            : #include "log.h"
      42                 :            : 
      43                 :            : static const char *errset_text[] = {
      44                 :            :         "success",            /* 0 ERRSET_SUCCESS */
      45                 :            :         "out of memory",      /* 1 ERRSET_NOMEMORY */
      46                 :            :         "general failure",    /* 2 ERRSET_FAIL */
      47                 :            :         "invalid parameter",  /* 3 ERRSET_INVAL */
      48                 :            :         "name does not exist",        /* 4 ERRSET_NONAME */
      49                 :            :         "data does not exist",        /* 5 ERRSET_NODATA */
      50                 :            : };
      51                 :            : 
      52                 :            : static const char *
      53                 :          0 : dns_result_totext(unsigned int res)
      54                 :            : {
      55   [ #  #  #  #  :          0 :         switch (res) {
                #  #  # ]
      56                 :            :         case ERRSET_SUCCESS:
      57                 :          0 :                 return errset_text[ERRSET_SUCCESS];
      58                 :            :         case ERRSET_NOMEMORY:
      59                 :          0 :                 return errset_text[ERRSET_NOMEMORY];
      60                 :            :         case ERRSET_FAIL:
      61                 :          0 :                 return errset_text[ERRSET_FAIL];
      62                 :            :         case ERRSET_INVAL:
      63                 :          0 :                 return errset_text[ERRSET_INVAL];
      64                 :            :         case ERRSET_NONAME:
      65                 :          0 :                 return errset_text[ERRSET_NONAME];
      66                 :            :         case ERRSET_NODATA:
      67                 :          0 :                 return errset_text[ERRSET_NODATA];
      68                 :            :         default:
      69                 :            :                 return "unknown error";
      70                 :            :         }
      71                 :            : }
      72                 :            : 
      73                 :            : /*
      74                 :            :  * Read SSHFP parameters from key buffer.
      75                 :            :  */
      76                 :            : static int
      77                 :          0 : dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type,
      78                 :            :     u_char **digest, u_int *digest_len, Key *key)
      79                 :            : {
      80                 :          0 :         int success = 0;
      81                 :          0 :         enum fp_type fp_type = 0;
      82                 :            : 
      83   [ #  #  #  # ]:          0 :         switch (key->type) {
      84                 :            :         case KEY_RSA:
      85                 :          0 :                 *algorithm = SSHFP_KEY_RSA;
      86         [ #  # ]:          0 :                 if (!*digest_type)
      87                 :          0 :                         *digest_type = SSHFP_HASH_SHA1;
      88                 :            :                 break;
      89                 :            :         case KEY_DSA:
      90                 :          0 :                 *algorithm = SSHFP_KEY_DSA;
      91         [ #  # ]:          0 :                 if (!*digest_type)
      92                 :          0 :                         *digest_type = SSHFP_HASH_SHA1;
      93                 :            :                 break;
      94                 :            :         case KEY_ECDSA:
      95                 :          0 :                 *algorithm = SSHFP_KEY_ECDSA;
      96         [ #  # ]:          0 :                 if (!*digest_type)
      97                 :          0 :                         *digest_type = SSHFP_HASH_SHA256;
      98                 :            :                 break;
      99                 :            :         default:
     100                 :          0 :                 *algorithm = SSHFP_KEY_RESERVED; /* 0 */
     101                 :          0 :                 *digest_type = SSHFP_HASH_RESERVED; /* 0 */
     102                 :            :         }
     103                 :            : 
     104      [ #  #  # ]:          0 :         switch (*digest_type) {
     105                 :            :         case SSHFP_HASH_SHA1:
     106                 :            :                 fp_type = SSH_FP_SHA1;
     107                 :            :                 break;
     108                 :            :         case SSHFP_HASH_SHA256:
     109                 :          0 :                 fp_type = SSH_FP_SHA256;
     110                 :          0 :                 break;
     111                 :            :         default:
     112                 :          0 :                 *digest_type = SSHFP_HASH_RESERVED; /* 0 */
     113                 :            :         }
     114                 :            : 
     115 [ #  # ][ #  # ]:          0 :         if (*algorithm && *digest_type) {
     116                 :          0 :                 *digest = key_fingerprint_raw(key, fp_type, digest_len);
     117         [ #  # ]:          0 :                 if (*digest == NULL)
     118                 :          0 :                         fatal("dns_read_key: null from key_fingerprint_raw()");
     119                 :            :                 success = 1;
     120                 :            :         } else {
     121                 :          0 :                 *digest = NULL;
     122                 :          0 :                 *digest_len = 0;
     123                 :          0 :                 success = 0;
     124                 :            :         }
     125                 :            : 
     126                 :          0 :         return success;
     127                 :            : }
     128                 :            : 
     129                 :            : /*
     130                 :            :  * Read SSHFP parameters from rdata buffer.
     131                 :            :  */
     132                 :            : static int
     133                 :          0 : dns_read_rdata(u_int8_t *algorithm, u_int8_t *digest_type,
     134                 :            :     u_char **digest, u_int *digest_len, u_char *rdata, int rdata_len)
     135                 :            : {
     136                 :          0 :         int success = 0;
     137                 :            : 
     138                 :          0 :         *algorithm = SSHFP_KEY_RESERVED;
     139                 :          0 :         *digest_type = SSHFP_HASH_RESERVED;
     140                 :            : 
     141         [ #  # ]:          0 :         if (rdata_len >= 2) {
     142                 :          0 :                 *algorithm = rdata[0];
     143                 :          0 :                 *digest_type = rdata[1];
     144                 :          0 :                 *digest_len = rdata_len - 2;
     145                 :            : 
     146         [ #  # ]:          0 :                 if (*digest_len > 0) {
     147                 :          0 :                         *digest = (u_char *) xmalloc(*digest_len);
     148                 :          0 :                         memcpy(*digest, rdata + 2, *digest_len);
     149                 :            :                 } else {
     150                 :          0 :                         *digest = (u_char *)xstrdup("");
     151                 :            :                 }
     152                 :            : 
     153                 :            :                 success = 1;
     154                 :            :         }
     155                 :            : 
     156                 :          0 :         return success;
     157                 :            : }
     158                 :            : 
     159                 :            : /*
     160                 :            :  * Check if hostname is numerical.
     161                 :            :  * Returns -1 if hostname is numeric, 0 otherwise
     162                 :            :  */
     163                 :            : static int
     164                 :          0 : is_numeric_hostname(const char *hostname)
     165                 :            : {
     166                 :            :         struct addrinfo hints, *ai;
     167                 :            : 
     168                 :            :         /*
     169                 :            :          * We shouldn't ever get a null host but if we do then log an error
     170                 :            :          * and return -1 which stops DNS key fingerprint processing.
     171                 :            :          */
     172         [ #  # ]:          0 :         if (hostname == NULL) {
     173                 :          0 :                 error("is_numeric_hostname called with NULL hostname");
     174                 :          0 :                 return -1;
     175                 :            :         }
     176                 :            : 
     177                 :            :         memset(&hints, 0, sizeof(hints));
     178                 :          0 :         hints.ai_socktype = SOCK_DGRAM;
     179                 :          0 :         hints.ai_flags = AI_NUMERICHOST;
     180                 :            : 
     181         [ #  # ]:          0 :         if (getaddrinfo(hostname, NULL, &hints, &ai) == 0) {
     182                 :          0 :                 freeaddrinfo(ai);
     183                 :          0 :                 return -1;
     184                 :            :         }
     185                 :            : 
     186                 :            :         return 0;
     187                 :            : }
     188                 :            : 
     189                 :            : /*
     190                 :            :  * Verify the given hostname, address and host key using DNS.
     191                 :            :  * Returns 0 if lookup succeeds, -1 otherwise
     192                 :            :  */
     193                 :            : int
     194                 :          0 : verify_host_key_dns(const char *hostname, struct sockaddr *address,
     195                 :            :     Key *hostkey, int *flags)
     196                 :            : {
     197                 :            :         u_int counter;
     198                 :            :         int result;
     199                 :          0 :         struct rrsetinfo *fingerprints = NULL;
     200                 :            : 
     201                 :            :         u_int8_t hostkey_algorithm;
     202                 :          0 :         u_int8_t hostkey_digest_type = SSHFP_HASH_RESERVED;
     203                 :            :         u_char *hostkey_digest;
     204                 :            :         u_int hostkey_digest_len;
     205                 :            : 
     206                 :            :         u_int8_t dnskey_algorithm;
     207                 :            :         u_int8_t dnskey_digest_type;
     208                 :            :         u_char *dnskey_digest;
     209                 :            :         u_int dnskey_digest_len;
     210                 :            : 
     211                 :          0 :         *flags = 0;
     212                 :            : 
     213                 :          0 :         debug3("verify_host_key_dns");
     214         [ #  # ]:          0 :         if (hostkey == NULL)
     215                 :          0 :                 fatal("No key to look up!");
     216                 :            : 
     217         [ #  # ]:          0 :         if (is_numeric_hostname(hostname)) {
     218                 :          0 :                 debug("skipped DNS lookup for numerical hostname");
     219                 :          0 :                 return -1;
     220                 :            :         }
     221                 :            : 
     222                 :          0 :         result = getrrsetbyname(hostname, DNS_RDATACLASS_IN,
     223                 :            :             DNS_RDATATYPE_SSHFP, 0, &fingerprints);
     224         [ #  # ]:          0 :         if (result) {
     225                 :          0 :                 verbose("DNS lookup error: %s", dns_result_totext(result));
     226                 :          0 :                 return -1;
     227                 :            :         }
     228                 :            : 
     229         [ #  # ]:          0 :         if (fingerprints->rri_flags & RRSET_VALIDATED) {
     230                 :          0 :                 *flags |= DNS_VERIFY_SECURE;
     231                 :          0 :                 debug("found %d secure fingerprints in DNS",
     232                 :            :                     fingerprints->rri_nrdatas);
     233                 :            :         } else {
     234                 :          0 :                 debug("found %d insecure fingerprints in DNS",
     235                 :            :                     fingerprints->rri_nrdatas);
     236                 :            :         }
     237                 :            : 
     238                 :            :         /* Initialize default host key parameters */
     239         [ #  # ]:          0 :         if (!dns_read_key(&hostkey_algorithm, &hostkey_digest_type,
     240                 :            :             &hostkey_digest, &hostkey_digest_len, hostkey)) {
     241                 :          0 :                 error("Error calculating host key fingerprint.");
     242                 :          0 :                 freerrset(fingerprints);
     243                 :          0 :                 return -1;
     244                 :            :         }
     245                 :            : 
     246         [ #  # ]:          0 :         if (fingerprints->rri_nrdatas)
     247                 :          0 :                 *flags |= DNS_VERIFY_FOUND;
     248                 :            : 
     249         [ #  # ]:          0 :         for (counter = 0; counter < fingerprints->rri_nrdatas; counter++) {
     250                 :            :                 /*
     251                 :            :                  * Extract the key from the answer. Ignore any badly
     252                 :            :                  * formatted fingerprints.
     253                 :            :                  */
     254         [ #  # ]:          0 :                 if (!dns_read_rdata(&dnskey_algorithm, &dnskey_digest_type,
     255                 :            :                     &dnskey_digest, &dnskey_digest_len,
     256                 :          0 :                     fingerprints->rri_rdatas[counter].rdi_data,
     257                 :          0 :                     fingerprints->rri_rdatas[counter].rdi_length)) {
     258                 :          0 :                         verbose("Error parsing fingerprint from DNS.");
     259                 :          0 :                         continue;
     260                 :            :                 }
     261                 :            : 
     262         [ #  # ]:          0 :                 if (hostkey_digest_type != dnskey_digest_type) {
     263                 :          0 :                         hostkey_digest_type = dnskey_digest_type;
     264                 :          0 :                         free(hostkey_digest);
     265                 :            : 
     266                 :            :                         /* Initialize host key parameters */
     267         [ #  # ]:          0 :                         if (!dns_read_key(&hostkey_algorithm,
     268                 :            :                             &hostkey_digest_type, &hostkey_digest,
     269                 :            :                             &hostkey_digest_len, hostkey)) {
     270                 :          0 :                                 error("Error calculating key fingerprint.");
     271                 :          0 :                                 freerrset(fingerprints);
     272                 :          0 :                                 return -1;
     273                 :            :                         }
     274                 :            :                 }
     275                 :            : 
     276                 :            :                 /* Check if the current key is the same as the given key */
     277 [ #  # ][ #  # ]:          0 :                 if (hostkey_algorithm == dnskey_algorithm &&
     278                 :          0 :                     hostkey_digest_type == dnskey_digest_type) {
     279   [ #  #  #  # ]:          0 :                         if (hostkey_digest_len == dnskey_digest_len &&
     280                 :          0 :                             timingsafe_bcmp(hostkey_digest, dnskey_digest,
     281                 :            :                             hostkey_digest_len) == 0)
     282                 :          0 :                                 *flags |= DNS_VERIFY_MATCH;
     283                 :            :                 }
     284                 :          0 :                 free(dnskey_digest);
     285                 :            :         }
     286                 :            : 
     287                 :          0 :         free(hostkey_digest); /* from key_fingerprint_raw() */
     288                 :          0 :         freerrset(fingerprints);
     289                 :            : 
     290         [ #  # ]:          0 :         if (*flags & DNS_VERIFY_FOUND)
     291         [ #  # ]:          0 :                 if (*flags & DNS_VERIFY_MATCH)
     292                 :          0 :                         debug("matching host key fingerprint found in DNS");
     293                 :            :                 else
     294                 :          0 :                         debug("mismatching host key fingerprint found in DNS");
     295                 :            :         else
     296                 :          0 :                 debug("no host key fingerprint found in DNS");
     297                 :            : 
     298                 :            :         return 0;
     299                 :            : }
     300                 :            : 
     301                 :            : /*
     302                 :            :  * Export the fingerprint of a key as a DNS resource record
     303                 :            :  */
     304                 :            : int
     305                 :          0 : export_dns_rr(const char *hostname, Key *key, FILE *f, int generic)
     306                 :            : {
     307                 :          0 :         u_int8_t rdata_pubkey_algorithm = 0;
     308                 :          0 :         u_int8_t rdata_digest_type = SSHFP_HASH_RESERVED;
     309                 :            :         u_int8_t dtype;
     310                 :            :         u_char *rdata_digest;
     311                 :            :         u_int i, rdata_digest_len;
     312                 :          0 :         int success = 0;
     313                 :            : 
     314         [ #  # ]:          0 :         for (dtype = SSHFP_HASH_SHA1; dtype < SSHFP_HASH_MAX; dtype++) {
     315                 :          0 :                 rdata_digest_type = dtype;
     316         [ #  # ]:          0 :                 if (dns_read_key(&rdata_pubkey_algorithm, &rdata_digest_type,
     317                 :            :                     &rdata_digest, &rdata_digest_len, key)) {
     318         [ #  # ]:          0 :                         if (generic) {
     319                 :          0 :                                 fprintf(f, "%s IN TYPE%d \\# %d %02x %02x ",
     320                 :            :                                     hostname, DNS_RDATATYPE_SSHFP,
     321                 :            :                                     2 + rdata_digest_len,
     322                 :            :                                     rdata_pubkey_algorithm, rdata_digest_type);
     323                 :            :                         } else {
     324                 :          0 :                                 fprintf(f, "%s IN SSHFP %d %d ", hostname,
     325                 :            :                                     rdata_pubkey_algorithm, rdata_digest_type);
     326                 :            :                         }
     327         [ #  # ]:          0 :                         for (i = 0; i < rdata_digest_len; i++)
     328                 :          0 :                                 fprintf(f, "%02x", rdata_digest[i]);
     329                 :            :                         fprintf(f, "\n");
     330                 :          0 :                         free(rdata_digest); /* from key_fingerprint_raw() */
     331                 :          0 :                         success = 1;
     332                 :            :                 }
     333                 :            :         }
     334                 :            : 
     335                 :            :         /* No SSHFP record was generated at all */
     336         [ #  # ]:          0 :         if (success == 0) {
     337                 :          0 :                 error("%s: unsupported algorithm and/or digest_type", __func__);
     338                 :            :         }
     339                 :            : 
     340                 :          0 :         return success;
     341                 :            : }

Generated by: LCOV version 1.9