1295367Sdes/* $OpenBSD: dns.c,v 1.35 2015/08/20 22:32:42 deraadt Exp $ */ 2124208Sdes 3124208Sdes/* 4124208Sdes * Copyright (c) 2003 Wesley Griffin. All rights reserved. 5124208Sdes * Copyright (c) 2003 Jakob Schlyter. All rights reserved. 6124208Sdes * 7124208Sdes * Redistribution and use in source and binary forms, with or without 8124208Sdes * modification, are permitted provided that the following conditions 9124208Sdes * are met: 10124208Sdes * 1. Redistributions of source code must retain the above copyright 11124208Sdes * notice, this list of conditions and the following disclaimer. 12124208Sdes * 2. Redistributions in binary form must reproduce the above copyright 13124208Sdes * notice, this list of conditions and the following disclaimer in the 14124208Sdes * documentation and/or other materials provided with the distribution. 15124208Sdes * 16124208Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17124208Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18124208Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19124208Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20124208Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21124208Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22124208Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23124208Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24124208Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25124208Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26124208Sdes */ 27124208Sdes 28124208Sdes#include "includes.h" 29124208Sdes 30162852Sdes#include <sys/types.h> 31162852Sdes#include <sys/socket.h> 32162852Sdes 33124208Sdes#include <netdb.h> 34162852Sdes#include <stdarg.h> 35162852Sdes#include <stdio.h> 36162852Sdes#include <string.h> 37295367Sdes#include <stdarg.h> 38295367Sdes#include <stdlib.h> 39124208Sdes 40124208Sdes#include "xmalloc.h" 41295367Sdes#include "sshkey.h" 42295367Sdes#include "ssherr.h" 43124208Sdes#include "dns.h" 44124208Sdes#include "log.h" 45295367Sdes#include "digest.h" 46124208Sdes 47124208Sdesstatic const char *errset_text[] = { 48124208Sdes "success", /* 0 ERRSET_SUCCESS */ 49124208Sdes "out of memory", /* 1 ERRSET_NOMEMORY */ 50124208Sdes "general failure", /* 2 ERRSET_FAIL */ 51124208Sdes "invalid parameter", /* 3 ERRSET_INVAL */ 52124208Sdes "name does not exist", /* 4 ERRSET_NONAME */ 53124208Sdes "data does not exist", /* 5 ERRSET_NODATA */ 54124208Sdes}; 55124208Sdes 56124208Sdesstatic const char * 57137015Sdesdns_result_totext(unsigned int res) 58124208Sdes{ 59137015Sdes switch (res) { 60124208Sdes case ERRSET_SUCCESS: 61124208Sdes return errset_text[ERRSET_SUCCESS]; 62124208Sdes case ERRSET_NOMEMORY: 63124208Sdes return errset_text[ERRSET_NOMEMORY]; 64124208Sdes case ERRSET_FAIL: 65124208Sdes return errset_text[ERRSET_FAIL]; 66124208Sdes case ERRSET_INVAL: 67124208Sdes return errset_text[ERRSET_INVAL]; 68124208Sdes case ERRSET_NONAME: 69124208Sdes return errset_text[ERRSET_NONAME]; 70124208Sdes case ERRSET_NODATA: 71124208Sdes return errset_text[ERRSET_NODATA]; 72124208Sdes default: 73124208Sdes return "unknown error"; 74124208Sdes } 75124208Sdes} 76124208Sdes 77124208Sdes/* 78124208Sdes * Read SSHFP parameters from key buffer. 79124208Sdes */ 80124208Sdesstatic int 81124208Sdesdns_read_key(u_int8_t *algorithm, u_int8_t *digest_type, 82295367Sdes u_char **digest, size_t *digest_len, struct sshkey *key) 83124208Sdes{ 84295367Sdes int r, success = 0; 85295367Sdes int fp_alg = -1; 86124208Sdes 87124208Sdes switch (key->type) { 88124208Sdes case KEY_RSA: 89124208Sdes *algorithm = SSHFP_KEY_RSA; 90240075Sdes if (!*digest_type) 91240075Sdes *digest_type = SSHFP_HASH_SHA1; 92124208Sdes break; 93124208Sdes case KEY_DSA: 94124208Sdes *algorithm = SSHFP_KEY_DSA; 95240075Sdes if (!*digest_type) 96240075Sdes *digest_type = SSHFP_HASH_SHA1; 97124208Sdes break; 98240075Sdes case KEY_ECDSA: 99240075Sdes *algorithm = SSHFP_KEY_ECDSA; 100240075Sdes if (!*digest_type) 101240075Sdes *digest_type = SSHFP_HASH_SHA256; 102240075Sdes break; 103295367Sdes case KEY_ED25519: 104295367Sdes *algorithm = SSHFP_KEY_ED25519; 105295367Sdes if (!*digest_type) 106295367Sdes *digest_type = SSHFP_HASH_SHA256; 107295367Sdes break; 108124208Sdes default: 109157016Sdes *algorithm = SSHFP_KEY_RESERVED; /* 0 */ 110240075Sdes *digest_type = SSHFP_HASH_RESERVED; /* 0 */ 111124208Sdes } 112124208Sdes 113240075Sdes switch (*digest_type) { 114240075Sdes case SSHFP_HASH_SHA1: 115295367Sdes fp_alg = SSH_DIGEST_SHA1; 116240075Sdes break; 117240075Sdes case SSHFP_HASH_SHA256: 118295367Sdes fp_alg = SSH_DIGEST_SHA256; 119240075Sdes break; 120240075Sdes default: 121240075Sdes *digest_type = SSHFP_HASH_RESERVED; /* 0 */ 122240075Sdes } 123240075Sdes 124240075Sdes if (*algorithm && *digest_type) { 125295367Sdes if ((r = sshkey_fingerprint_raw(key, fp_alg, digest, 126295367Sdes digest_len)) != 0) 127295367Sdes fatal("%s: sshkey_fingerprint_raw: %s", __func__, 128295367Sdes ssh_err(r)); 129124208Sdes success = 1; 130124208Sdes } else { 131124208Sdes *digest = NULL; 132124208Sdes *digest_len = 0; 133124208Sdes success = 0; 134124208Sdes } 135124208Sdes 136124208Sdes return success; 137124208Sdes} 138124208Sdes 139124208Sdes/* 140124208Sdes * Read SSHFP parameters from rdata buffer. 141124208Sdes */ 142124208Sdesstatic int 143124208Sdesdns_read_rdata(u_int8_t *algorithm, u_int8_t *digest_type, 144295367Sdes u_char **digest, size_t *digest_len, u_char *rdata, int rdata_len) 145124208Sdes{ 146124208Sdes int success = 0; 147124208Sdes 148124208Sdes *algorithm = SSHFP_KEY_RESERVED; 149124208Sdes *digest_type = SSHFP_HASH_RESERVED; 150124208Sdes 151124208Sdes if (rdata_len >= 2) { 152124208Sdes *algorithm = rdata[0]; 153124208Sdes *digest_type = rdata[1]; 154124208Sdes *digest_len = rdata_len - 2; 155124208Sdes 156124208Sdes if (*digest_len > 0) { 157295367Sdes *digest = xmalloc(*digest_len); 158124208Sdes memcpy(*digest, rdata + 2, *digest_len); 159124208Sdes } else { 160162852Sdes *digest = (u_char *)xstrdup(""); 161124208Sdes } 162124208Sdes 163124208Sdes success = 1; 164124208Sdes } 165124208Sdes 166124208Sdes return success; 167124208Sdes} 168124208Sdes 169149749Sdes/* 170149749Sdes * Check if hostname is numerical. 171149749Sdes * Returns -1 if hostname is numeric, 0 otherwise 172149749Sdes */ 173149749Sdesstatic int 174149749Sdesis_numeric_hostname(const char *hostname) 175149749Sdes{ 176149749Sdes struct addrinfo hints, *ai; 177124208Sdes 178181111Sdes /* 179181111Sdes * We shouldn't ever get a null host but if we do then log an error 180181111Sdes * and return -1 which stops DNS key fingerprint processing. 181181111Sdes */ 182181111Sdes if (hostname == NULL) { 183181111Sdes error("is_numeric_hostname called with NULL hostname"); 184181111Sdes return -1; 185181111Sdes } 186181111Sdes 187149749Sdes memset(&hints, 0, sizeof(hints)); 188149749Sdes hints.ai_socktype = SOCK_DGRAM; 189149749Sdes hints.ai_flags = AI_NUMERICHOST; 190149749Sdes 191181111Sdes if (getaddrinfo(hostname, NULL, &hints, &ai) == 0) { 192149749Sdes freeaddrinfo(ai); 193149749Sdes return -1; 194149749Sdes } 195149749Sdes 196149749Sdes return 0; 197149749Sdes} 198149749Sdes 199124208Sdes/* 200124208Sdes * Verify the given hostname, address and host key using DNS. 201126274Sdes * Returns 0 if lookup succeeds, -1 otherwise 202124208Sdes */ 203124208Sdesint 204124208Sdesverify_host_key_dns(const char *hostname, struct sockaddr *address, 205295367Sdes struct sshkey *hostkey, int *flags) 206124208Sdes{ 207149749Sdes u_int counter; 208124208Sdes int result; 209124208Sdes struct rrsetinfo *fingerprints = NULL; 210124208Sdes 211124208Sdes u_int8_t hostkey_algorithm; 212240075Sdes u_int8_t hostkey_digest_type = SSHFP_HASH_RESERVED; 213124208Sdes u_char *hostkey_digest; 214295367Sdes size_t hostkey_digest_len; 215124208Sdes 216124208Sdes u_int8_t dnskey_algorithm; 217124208Sdes u_int8_t dnskey_digest_type; 218124208Sdes u_char *dnskey_digest; 219295367Sdes size_t dnskey_digest_len; 220124208Sdes 221126274Sdes *flags = 0; 222124208Sdes 223157016Sdes debug3("verify_host_key_dns"); 224124208Sdes if (hostkey == NULL) 225124208Sdes fatal("No key to look up!"); 226124208Sdes 227149749Sdes if (is_numeric_hostname(hostname)) { 228149749Sdes debug("skipped DNS lookup for numerical hostname"); 229149749Sdes return -1; 230149749Sdes } 231149749Sdes 232124208Sdes result = getrrsetbyname(hostname, DNS_RDATACLASS_IN, 233124208Sdes DNS_RDATATYPE_SSHFP, 0, &fingerprints); 234124208Sdes if (result) { 235124208Sdes verbose("DNS lookup error: %s", dns_result_totext(result)); 236126274Sdes return -1; 237124208Sdes } 238124208Sdes 239126274Sdes if (fingerprints->rri_flags & RRSET_VALIDATED) { 240126274Sdes *flags |= DNS_VERIFY_SECURE; 241126274Sdes debug("found %d secure fingerprints in DNS", 242126274Sdes fingerprints->rri_nrdatas); 243126274Sdes } else { 244126274Sdes debug("found %d insecure fingerprints in DNS", 245126274Sdes fingerprints->rri_nrdatas); 246124208Sdes } 247124208Sdes 248240075Sdes /* Initialize default host key parameters */ 249124208Sdes if (!dns_read_key(&hostkey_algorithm, &hostkey_digest_type, 250124208Sdes &hostkey_digest, &hostkey_digest_len, hostkey)) { 251124208Sdes error("Error calculating host key fingerprint."); 252124208Sdes freerrset(fingerprints); 253126274Sdes return -1; 254124208Sdes } 255124208Sdes 256126274Sdes if (fingerprints->rri_nrdatas) 257126274Sdes *flags |= DNS_VERIFY_FOUND; 258126274Sdes 259181111Sdes for (counter = 0; counter < fingerprints->rri_nrdatas; counter++) { 260124208Sdes /* 261124208Sdes * Extract the key from the answer. Ignore any badly 262124208Sdes * formatted fingerprints. 263124208Sdes */ 264124208Sdes if (!dns_read_rdata(&dnskey_algorithm, &dnskey_digest_type, 265124208Sdes &dnskey_digest, &dnskey_digest_len, 266124208Sdes fingerprints->rri_rdatas[counter].rdi_data, 267124208Sdes fingerprints->rri_rdatas[counter].rdi_length)) { 268124208Sdes verbose("Error parsing fingerprint from DNS."); 269124208Sdes continue; 270124208Sdes } 271124208Sdes 272240075Sdes if (hostkey_digest_type != dnskey_digest_type) { 273240075Sdes hostkey_digest_type = dnskey_digest_type; 274255767Sdes free(hostkey_digest); 275240075Sdes 276240075Sdes /* Initialize host key parameters */ 277240075Sdes if (!dns_read_key(&hostkey_algorithm, 278240075Sdes &hostkey_digest_type, &hostkey_digest, 279240075Sdes &hostkey_digest_len, hostkey)) { 280240075Sdes error("Error calculating key fingerprint."); 281240075Sdes freerrset(fingerprints); 282240075Sdes return -1; 283240075Sdes } 284240075Sdes } 285240075Sdes 286124208Sdes /* Check if the current key is the same as the given key */ 287124208Sdes if (hostkey_algorithm == dnskey_algorithm && 288124208Sdes hostkey_digest_type == dnskey_digest_type) { 289124208Sdes if (hostkey_digest_len == dnskey_digest_len && 290240075Sdes timingsafe_bcmp(hostkey_digest, dnskey_digest, 291240075Sdes hostkey_digest_len) == 0) 292126274Sdes *flags |= DNS_VERIFY_MATCH; 293124208Sdes } 294255767Sdes free(dnskey_digest); 295124208Sdes } 296124208Sdes 297295367Sdes free(hostkey_digest); /* from sshkey_fingerprint_raw() */ 298124208Sdes freerrset(fingerprints); 299124208Sdes 300126274Sdes if (*flags & DNS_VERIFY_FOUND) 301126274Sdes if (*flags & DNS_VERIFY_MATCH) 302126274Sdes debug("matching host key fingerprint found in DNS"); 303126274Sdes else 304126274Sdes debug("mismatching host key fingerprint found in DNS"); 305126274Sdes else 306126274Sdes debug("no host key fingerprint found in DNS"); 307124208Sdes 308126274Sdes return 0; 309124208Sdes} 310124208Sdes 311124208Sdes/* 312124208Sdes * Export the fingerprint of a key as a DNS resource record 313124208Sdes */ 314124208Sdesint 315295367Sdesexport_dns_rr(const char *hostname, struct sshkey *key, FILE *f, int generic) 316124208Sdes{ 317124208Sdes u_int8_t rdata_pubkey_algorithm = 0; 318240075Sdes u_int8_t rdata_digest_type = SSHFP_HASH_RESERVED; 319240075Sdes u_int8_t dtype; 320124208Sdes u_char *rdata_digest; 321295367Sdes size_t i, rdata_digest_len; 322124208Sdes int success = 0; 323124208Sdes 324240075Sdes for (dtype = SSHFP_HASH_SHA1; dtype < SSHFP_HASH_MAX; dtype++) { 325240075Sdes rdata_digest_type = dtype; 326240075Sdes if (dns_read_key(&rdata_pubkey_algorithm, &rdata_digest_type, 327240075Sdes &rdata_digest, &rdata_digest_len, key)) { 328240075Sdes if (generic) { 329295367Sdes fprintf(f, "%s IN TYPE%d \\# %zu %02x %02x ", 330240075Sdes hostname, DNS_RDATATYPE_SSHFP, 331240075Sdes 2 + rdata_digest_len, 332240075Sdes rdata_pubkey_algorithm, rdata_digest_type); 333240075Sdes } else { 334240075Sdes fprintf(f, "%s IN SSHFP %d %d ", hostname, 335240075Sdes rdata_pubkey_algorithm, rdata_digest_type); 336240075Sdes } 337240075Sdes for (i = 0; i < rdata_digest_len; i++) 338240075Sdes fprintf(f, "%02x", rdata_digest[i]); 339240075Sdes fprintf(f, "\n"); 340295367Sdes free(rdata_digest); /* from sshkey_fingerprint_raw() */ 341240075Sdes success = 1; 342240075Sdes } 343240075Sdes } 344124208Sdes 345240075Sdes /* No SSHFP record was generated at all */ 346240075Sdes if (success == 0) { 347240075Sdes error("%s: unsupported algorithm and/or digest_type", __func__); 348124208Sdes } 349124208Sdes 350124208Sdes return success; 351124208Sdes} 352