1*47dd1d1bSDag-Erling Smørgrav /* $OpenBSD: dns.c,v 1.38 2018/02/23 15:58:37 markus Exp $ */ 2d95e11bfSDag-Erling Smørgrav 3d95e11bfSDag-Erling Smørgrav /* 4d95e11bfSDag-Erling Smørgrav * Copyright (c) 2003 Wesley Griffin. All rights reserved. 5d95e11bfSDag-Erling Smørgrav * Copyright (c) 2003 Jakob Schlyter. All rights reserved. 6d95e11bfSDag-Erling Smørgrav * 7d95e11bfSDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without 8d95e11bfSDag-Erling Smørgrav * modification, are permitted provided that the following conditions 9d95e11bfSDag-Erling Smørgrav * are met: 10d95e11bfSDag-Erling Smørgrav * 1. Redistributions of source code must retain the above copyright 11d95e11bfSDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer. 12d95e11bfSDag-Erling Smørgrav * 2. Redistributions in binary form must reproduce the above copyright 13d95e11bfSDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer in the 14d95e11bfSDag-Erling Smørgrav * documentation and/or other materials provided with the distribution. 15d95e11bfSDag-Erling Smørgrav * 16d95e11bfSDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17d95e11bfSDag-Erling Smørgrav * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18d95e11bfSDag-Erling Smørgrav * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19d95e11bfSDag-Erling Smørgrav * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20d95e11bfSDag-Erling Smørgrav * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21d95e11bfSDag-Erling Smørgrav * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22d95e11bfSDag-Erling Smørgrav * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23d95e11bfSDag-Erling Smørgrav * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24d95e11bfSDag-Erling Smørgrav * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25d95e11bfSDag-Erling Smørgrav * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26d95e11bfSDag-Erling Smørgrav */ 27d95e11bfSDag-Erling Smørgrav 28d95e11bfSDag-Erling Smørgrav #include "includes.h" 29761efaa7SDag-Erling Smørgrav 30761efaa7SDag-Erling Smørgrav #include <sys/types.h> 31761efaa7SDag-Erling Smørgrav #include <sys/socket.h> 32d95e11bfSDag-Erling Smørgrav 33d95e11bfSDag-Erling Smørgrav #include <netdb.h> 34761efaa7SDag-Erling Smørgrav #include <stdarg.h> 35761efaa7SDag-Erling Smørgrav #include <stdio.h> 36761efaa7SDag-Erling Smørgrav #include <string.h> 37a0ee8cc6SDag-Erling Smørgrav #include <stdarg.h> 38a0ee8cc6SDag-Erling Smørgrav #include <stdlib.h> 39d95e11bfSDag-Erling Smørgrav 40d95e11bfSDag-Erling Smørgrav #include "xmalloc.h" 41bc5531deSDag-Erling Smørgrav #include "sshkey.h" 42bc5531deSDag-Erling Smørgrav #include "ssherr.h" 43d95e11bfSDag-Erling Smørgrav #include "dns.h" 44d95e11bfSDag-Erling Smørgrav #include "log.h" 45bc5531deSDag-Erling Smørgrav #include "digest.h" 46d95e11bfSDag-Erling Smørgrav 47d95e11bfSDag-Erling Smørgrav static const char *errset_text[] = { 48d95e11bfSDag-Erling Smørgrav "success", /* 0 ERRSET_SUCCESS */ 49d95e11bfSDag-Erling Smørgrav "out of memory", /* 1 ERRSET_NOMEMORY */ 50d95e11bfSDag-Erling Smørgrav "general failure", /* 2 ERRSET_FAIL */ 51d95e11bfSDag-Erling Smørgrav "invalid parameter", /* 3 ERRSET_INVAL */ 52d95e11bfSDag-Erling Smørgrav "name does not exist", /* 4 ERRSET_NONAME */ 53d95e11bfSDag-Erling Smørgrav "data does not exist", /* 5 ERRSET_NODATA */ 54d95e11bfSDag-Erling Smørgrav }; 55d95e11bfSDag-Erling Smørgrav 56d95e11bfSDag-Erling Smørgrav static const char * 57d74d50a8SDag-Erling Smørgrav dns_result_totext(unsigned int res) 58d95e11bfSDag-Erling Smørgrav { 59d74d50a8SDag-Erling Smørgrav switch (res) { 60d95e11bfSDag-Erling Smørgrav case ERRSET_SUCCESS: 61d95e11bfSDag-Erling Smørgrav return errset_text[ERRSET_SUCCESS]; 62d95e11bfSDag-Erling Smørgrav case ERRSET_NOMEMORY: 63d95e11bfSDag-Erling Smørgrav return errset_text[ERRSET_NOMEMORY]; 64d95e11bfSDag-Erling Smørgrav case ERRSET_FAIL: 65d95e11bfSDag-Erling Smørgrav return errset_text[ERRSET_FAIL]; 66d95e11bfSDag-Erling Smørgrav case ERRSET_INVAL: 67d95e11bfSDag-Erling Smørgrav return errset_text[ERRSET_INVAL]; 68d95e11bfSDag-Erling Smørgrav case ERRSET_NONAME: 69d95e11bfSDag-Erling Smørgrav return errset_text[ERRSET_NONAME]; 70d95e11bfSDag-Erling Smørgrav case ERRSET_NODATA: 71d95e11bfSDag-Erling Smørgrav return errset_text[ERRSET_NODATA]; 72d95e11bfSDag-Erling Smørgrav default: 73d95e11bfSDag-Erling Smørgrav return "unknown error"; 74d95e11bfSDag-Erling Smørgrav } 75d95e11bfSDag-Erling Smørgrav } 76d95e11bfSDag-Erling Smørgrav 77d95e11bfSDag-Erling Smørgrav /* 78d95e11bfSDag-Erling Smørgrav * Read SSHFP parameters from key buffer. 79d95e11bfSDag-Erling Smørgrav */ 80d95e11bfSDag-Erling Smørgrav static int 81d95e11bfSDag-Erling Smørgrav dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type, 82bc5531deSDag-Erling Smørgrav u_char **digest, size_t *digest_len, struct sshkey *key) 83d95e11bfSDag-Erling Smørgrav { 84bc5531deSDag-Erling Smørgrav int r, success = 0; 85bc5531deSDag-Erling Smørgrav int fp_alg = -1; 86d95e11bfSDag-Erling Smørgrav 87d95e11bfSDag-Erling Smørgrav switch (key->type) { 88d95e11bfSDag-Erling Smørgrav case KEY_RSA: 89d95e11bfSDag-Erling Smørgrav *algorithm = SSHFP_KEY_RSA; 90462c32cbSDag-Erling Smørgrav if (!*digest_type) 91462c32cbSDag-Erling Smørgrav *digest_type = SSHFP_HASH_SHA1; 92d95e11bfSDag-Erling Smørgrav break; 93d95e11bfSDag-Erling Smørgrav case KEY_DSA: 94d95e11bfSDag-Erling Smørgrav *algorithm = SSHFP_KEY_DSA; 95462c32cbSDag-Erling Smørgrav if (!*digest_type) 96462c32cbSDag-Erling Smørgrav *digest_type = SSHFP_HASH_SHA1; 97d95e11bfSDag-Erling Smørgrav break; 98462c32cbSDag-Erling Smørgrav case KEY_ECDSA: 99462c32cbSDag-Erling Smørgrav *algorithm = SSHFP_KEY_ECDSA; 100462c32cbSDag-Erling Smørgrav if (!*digest_type) 101462c32cbSDag-Erling Smørgrav *digest_type = SSHFP_HASH_SHA256; 102462c32cbSDag-Erling Smørgrav break; 103a0ee8cc6SDag-Erling Smørgrav case KEY_ED25519: 104a0ee8cc6SDag-Erling Smørgrav *algorithm = SSHFP_KEY_ED25519; 105a0ee8cc6SDag-Erling Smørgrav if (!*digest_type) 106a0ee8cc6SDag-Erling Smørgrav *digest_type = SSHFP_HASH_SHA256; 107a0ee8cc6SDag-Erling Smørgrav break; 108*47dd1d1bSDag-Erling Smørgrav case KEY_XMSS: 109*47dd1d1bSDag-Erling Smørgrav *algorithm = SSHFP_KEY_XMSS; 110*47dd1d1bSDag-Erling Smørgrav if (!*digest_type) 111*47dd1d1bSDag-Erling Smørgrav *digest_type = SSHFP_HASH_SHA256; 112*47dd1d1bSDag-Erling Smørgrav break; 113d95e11bfSDag-Erling Smørgrav default: 114021d409fSDag-Erling Smørgrav *algorithm = SSHFP_KEY_RESERVED; /* 0 */ 115462c32cbSDag-Erling Smørgrav *digest_type = SSHFP_HASH_RESERVED; /* 0 */ 116d95e11bfSDag-Erling Smørgrav } 117d95e11bfSDag-Erling Smørgrav 118462c32cbSDag-Erling Smørgrav switch (*digest_type) { 119462c32cbSDag-Erling Smørgrav case SSHFP_HASH_SHA1: 120bc5531deSDag-Erling Smørgrav fp_alg = SSH_DIGEST_SHA1; 121462c32cbSDag-Erling Smørgrav break; 122462c32cbSDag-Erling Smørgrav case SSHFP_HASH_SHA256: 123bc5531deSDag-Erling Smørgrav fp_alg = SSH_DIGEST_SHA256; 124462c32cbSDag-Erling Smørgrav break; 125462c32cbSDag-Erling Smørgrav default: 126462c32cbSDag-Erling Smørgrav *digest_type = SSHFP_HASH_RESERVED; /* 0 */ 127462c32cbSDag-Erling Smørgrav } 128462c32cbSDag-Erling Smørgrav 129462c32cbSDag-Erling Smørgrav if (*algorithm && *digest_type) { 130bc5531deSDag-Erling Smørgrav if ((r = sshkey_fingerprint_raw(key, fp_alg, digest, 131bc5531deSDag-Erling Smørgrav digest_len)) != 0) 132bc5531deSDag-Erling Smørgrav fatal("%s: sshkey_fingerprint_raw: %s", __func__, 133bc5531deSDag-Erling Smørgrav ssh_err(r)); 134d95e11bfSDag-Erling Smørgrav success = 1; 135d95e11bfSDag-Erling Smørgrav } else { 136d95e11bfSDag-Erling Smørgrav *digest = NULL; 137d95e11bfSDag-Erling Smørgrav *digest_len = 0; 138d95e11bfSDag-Erling Smørgrav success = 0; 139d95e11bfSDag-Erling Smørgrav } 140d95e11bfSDag-Erling Smørgrav 141d95e11bfSDag-Erling Smørgrav return success; 142d95e11bfSDag-Erling Smørgrav } 143d95e11bfSDag-Erling Smørgrav 144d95e11bfSDag-Erling Smørgrav /* 145d95e11bfSDag-Erling Smørgrav * Read SSHFP parameters from rdata buffer. 146d95e11bfSDag-Erling Smørgrav */ 147d95e11bfSDag-Erling Smørgrav static int 148d95e11bfSDag-Erling Smørgrav dns_read_rdata(u_int8_t *algorithm, u_int8_t *digest_type, 149bc5531deSDag-Erling Smørgrav u_char **digest, size_t *digest_len, u_char *rdata, int rdata_len) 150d95e11bfSDag-Erling Smørgrav { 151d95e11bfSDag-Erling Smørgrav int success = 0; 152d95e11bfSDag-Erling Smørgrav 153d95e11bfSDag-Erling Smørgrav *algorithm = SSHFP_KEY_RESERVED; 154d95e11bfSDag-Erling Smørgrav *digest_type = SSHFP_HASH_RESERVED; 155d95e11bfSDag-Erling Smørgrav 156d95e11bfSDag-Erling Smørgrav if (rdata_len >= 2) { 157d95e11bfSDag-Erling Smørgrav *algorithm = rdata[0]; 158d95e11bfSDag-Erling Smørgrav *digest_type = rdata[1]; 159d95e11bfSDag-Erling Smørgrav *digest_len = rdata_len - 2; 160d95e11bfSDag-Erling Smørgrav 161d95e11bfSDag-Erling Smørgrav if (*digest_len > 0) { 162fc1ba28aSDag-Erling Smørgrav *digest = xmalloc(*digest_len); 163d95e11bfSDag-Erling Smørgrav memcpy(*digest, rdata + 2, *digest_len); 164d95e11bfSDag-Erling Smørgrav } else { 165761efaa7SDag-Erling Smørgrav *digest = (u_char *)xstrdup(""); 166d95e11bfSDag-Erling Smørgrav } 167d95e11bfSDag-Erling Smørgrav 168d95e11bfSDag-Erling Smørgrav success = 1; 169d95e11bfSDag-Erling Smørgrav } 170d95e11bfSDag-Erling Smørgrav 171d95e11bfSDag-Erling Smørgrav return success; 172d95e11bfSDag-Erling Smørgrav } 173d95e11bfSDag-Erling Smørgrav 174043840dfSDag-Erling Smørgrav /* 175043840dfSDag-Erling Smørgrav * Check if hostname is numerical. 176043840dfSDag-Erling Smørgrav * Returns -1 if hostname is numeric, 0 otherwise 177043840dfSDag-Erling Smørgrav */ 178043840dfSDag-Erling Smørgrav static int 179043840dfSDag-Erling Smørgrav is_numeric_hostname(const char *hostname) 180043840dfSDag-Erling Smørgrav { 181043840dfSDag-Erling Smørgrav struct addrinfo hints, *ai; 182043840dfSDag-Erling Smørgrav 183d4af9e69SDag-Erling Smørgrav /* 184d4af9e69SDag-Erling Smørgrav * We shouldn't ever get a null host but if we do then log an error 185d4af9e69SDag-Erling Smørgrav * and return -1 which stops DNS key fingerprint processing. 186d4af9e69SDag-Erling Smørgrav */ 187d4af9e69SDag-Erling Smørgrav if (hostname == NULL) { 188d4af9e69SDag-Erling Smørgrav error("is_numeric_hostname called with NULL hostname"); 189d4af9e69SDag-Erling Smørgrav return -1; 190d4af9e69SDag-Erling Smørgrav } 191d4af9e69SDag-Erling Smørgrav 192043840dfSDag-Erling Smørgrav memset(&hints, 0, sizeof(hints)); 193043840dfSDag-Erling Smørgrav hints.ai_socktype = SOCK_DGRAM; 194043840dfSDag-Erling Smørgrav hints.ai_flags = AI_NUMERICHOST; 195043840dfSDag-Erling Smørgrav 196d4af9e69SDag-Erling Smørgrav if (getaddrinfo(hostname, NULL, &hints, &ai) == 0) { 197043840dfSDag-Erling Smørgrav freeaddrinfo(ai); 198043840dfSDag-Erling Smørgrav return -1; 199043840dfSDag-Erling Smørgrav } 200043840dfSDag-Erling Smørgrav 201043840dfSDag-Erling Smørgrav return 0; 202043840dfSDag-Erling Smørgrav } 203d95e11bfSDag-Erling Smørgrav 204d95e11bfSDag-Erling Smørgrav /* 205d95e11bfSDag-Erling Smørgrav * Verify the given hostname, address and host key using DNS. 206efcad6b7SDag-Erling Smørgrav * Returns 0 if lookup succeeds, -1 otherwise 207d95e11bfSDag-Erling Smørgrav */ 208d95e11bfSDag-Erling Smørgrav int 209d95e11bfSDag-Erling Smørgrav verify_host_key_dns(const char *hostname, struct sockaddr *address, 210bc5531deSDag-Erling Smørgrav struct sshkey *hostkey, int *flags) 211d95e11bfSDag-Erling Smørgrav { 212043840dfSDag-Erling Smørgrav u_int counter; 213d95e11bfSDag-Erling Smørgrav int result; 214d95e11bfSDag-Erling Smørgrav struct rrsetinfo *fingerprints = NULL; 215d95e11bfSDag-Erling Smørgrav 216d95e11bfSDag-Erling Smørgrav u_int8_t hostkey_algorithm; 217462c32cbSDag-Erling Smørgrav u_int8_t hostkey_digest_type = SSHFP_HASH_RESERVED; 218d95e11bfSDag-Erling Smørgrav u_char *hostkey_digest; 219bc5531deSDag-Erling Smørgrav size_t hostkey_digest_len; 220d95e11bfSDag-Erling Smørgrav 221d95e11bfSDag-Erling Smørgrav u_int8_t dnskey_algorithm; 222d95e11bfSDag-Erling Smørgrav u_int8_t dnskey_digest_type; 223d95e11bfSDag-Erling Smørgrav u_char *dnskey_digest; 224bc5531deSDag-Erling Smørgrav size_t dnskey_digest_len; 225d95e11bfSDag-Erling Smørgrav 226efcad6b7SDag-Erling Smørgrav *flags = 0; 227d95e11bfSDag-Erling Smørgrav 228021d409fSDag-Erling Smørgrav debug3("verify_host_key_dns"); 229d95e11bfSDag-Erling Smørgrav if (hostkey == NULL) 230d95e11bfSDag-Erling Smørgrav fatal("No key to look up!"); 231d95e11bfSDag-Erling Smørgrav 232043840dfSDag-Erling Smørgrav if (is_numeric_hostname(hostname)) { 233043840dfSDag-Erling Smørgrav debug("skipped DNS lookup for numerical hostname"); 234043840dfSDag-Erling Smørgrav return -1; 235043840dfSDag-Erling Smørgrav } 236043840dfSDag-Erling Smørgrav 237d95e11bfSDag-Erling Smørgrav result = getrrsetbyname(hostname, DNS_RDATACLASS_IN, 238d95e11bfSDag-Erling Smørgrav DNS_RDATATYPE_SSHFP, 0, &fingerprints); 239d95e11bfSDag-Erling Smørgrav if (result) { 240d95e11bfSDag-Erling Smørgrav verbose("DNS lookup error: %s", dns_result_totext(result)); 241efcad6b7SDag-Erling Smørgrav return -1; 242d95e11bfSDag-Erling Smørgrav } 243d95e11bfSDag-Erling Smørgrav 244efcad6b7SDag-Erling Smørgrav if (fingerprints->rri_flags & RRSET_VALIDATED) { 245efcad6b7SDag-Erling Smørgrav *flags |= DNS_VERIFY_SECURE; 246efcad6b7SDag-Erling Smørgrav debug("found %d secure fingerprints in DNS", 247efcad6b7SDag-Erling Smørgrav fingerprints->rri_nrdatas); 248efcad6b7SDag-Erling Smørgrav } else { 249efcad6b7SDag-Erling Smørgrav debug("found %d insecure fingerprints in DNS", 250efcad6b7SDag-Erling Smørgrav fingerprints->rri_nrdatas); 251d95e11bfSDag-Erling Smørgrav } 252d95e11bfSDag-Erling Smørgrav 253462c32cbSDag-Erling Smørgrav /* Initialize default host key parameters */ 254d95e11bfSDag-Erling Smørgrav if (!dns_read_key(&hostkey_algorithm, &hostkey_digest_type, 255d95e11bfSDag-Erling Smørgrav &hostkey_digest, &hostkey_digest_len, hostkey)) { 256d95e11bfSDag-Erling Smørgrav error("Error calculating host key fingerprint."); 257d95e11bfSDag-Erling Smørgrav freerrset(fingerprints); 258efcad6b7SDag-Erling Smørgrav return -1; 259d95e11bfSDag-Erling Smørgrav } 260d95e11bfSDag-Erling Smørgrav 261efcad6b7SDag-Erling Smørgrav if (fingerprints->rri_nrdatas) 262efcad6b7SDag-Erling Smørgrav *flags |= DNS_VERIFY_FOUND; 263efcad6b7SDag-Erling Smørgrav 264d95e11bfSDag-Erling Smørgrav for (counter = 0; counter < fingerprints->rri_nrdatas; counter++) { 265d95e11bfSDag-Erling Smørgrav /* 266d95e11bfSDag-Erling Smørgrav * Extract the key from the answer. Ignore any badly 267d95e11bfSDag-Erling Smørgrav * formatted fingerprints. 268d95e11bfSDag-Erling Smørgrav */ 269d95e11bfSDag-Erling Smørgrav if (!dns_read_rdata(&dnskey_algorithm, &dnskey_digest_type, 270d95e11bfSDag-Erling Smørgrav &dnskey_digest, &dnskey_digest_len, 271d95e11bfSDag-Erling Smørgrav fingerprints->rri_rdatas[counter].rdi_data, 272d95e11bfSDag-Erling Smørgrav fingerprints->rri_rdatas[counter].rdi_length)) { 273d95e11bfSDag-Erling Smørgrav verbose("Error parsing fingerprint from DNS."); 274d95e11bfSDag-Erling Smørgrav continue; 275d95e11bfSDag-Erling Smørgrav } 276d95e11bfSDag-Erling Smørgrav 277462c32cbSDag-Erling Smørgrav if (hostkey_digest_type != dnskey_digest_type) { 278462c32cbSDag-Erling Smørgrav hostkey_digest_type = dnskey_digest_type; 279e4a9863fSDag-Erling Smørgrav free(hostkey_digest); 280462c32cbSDag-Erling Smørgrav 281462c32cbSDag-Erling Smørgrav /* Initialize host key parameters */ 282462c32cbSDag-Erling Smørgrav if (!dns_read_key(&hostkey_algorithm, 283462c32cbSDag-Erling Smørgrav &hostkey_digest_type, &hostkey_digest, 284462c32cbSDag-Erling Smørgrav &hostkey_digest_len, hostkey)) { 285462c32cbSDag-Erling Smørgrav error("Error calculating key fingerprint."); 286462c32cbSDag-Erling Smørgrav freerrset(fingerprints); 287462c32cbSDag-Erling Smørgrav return -1; 288462c32cbSDag-Erling Smørgrav } 289462c32cbSDag-Erling Smørgrav } 290462c32cbSDag-Erling Smørgrav 291d95e11bfSDag-Erling Smørgrav /* Check if the current key is the same as the given key */ 292d95e11bfSDag-Erling Smørgrav if (hostkey_algorithm == dnskey_algorithm && 293d95e11bfSDag-Erling Smørgrav hostkey_digest_type == dnskey_digest_type) { 294d95e11bfSDag-Erling Smørgrav if (hostkey_digest_len == dnskey_digest_len && 295462c32cbSDag-Erling Smørgrav timingsafe_bcmp(hostkey_digest, dnskey_digest, 296462c32cbSDag-Erling Smørgrav hostkey_digest_len) == 0) 297efcad6b7SDag-Erling Smørgrav *flags |= DNS_VERIFY_MATCH; 298efcad6b7SDag-Erling Smørgrav } 299e4a9863fSDag-Erling Smørgrav free(dnskey_digest); 300efcad6b7SDag-Erling Smørgrav } 301efcad6b7SDag-Erling Smørgrav 302bc5531deSDag-Erling Smørgrav free(hostkey_digest); /* from sshkey_fingerprint_raw() */ 303d95e11bfSDag-Erling Smørgrav freerrset(fingerprints); 304efcad6b7SDag-Erling Smørgrav 305efcad6b7SDag-Erling Smørgrav if (*flags & DNS_VERIFY_FOUND) 306efcad6b7SDag-Erling Smørgrav if (*flags & DNS_VERIFY_MATCH) 307d95e11bfSDag-Erling Smørgrav debug("matching host key fingerprint found in DNS"); 308efcad6b7SDag-Erling Smørgrav else 309efcad6b7SDag-Erling Smørgrav debug("mismatching host key fingerprint found in DNS"); 310efcad6b7SDag-Erling Smørgrav else 311efcad6b7SDag-Erling Smørgrav debug("no host key fingerprint found in DNS"); 312d95e11bfSDag-Erling Smørgrav 313efcad6b7SDag-Erling Smørgrav return 0; 314d95e11bfSDag-Erling Smørgrav } 315d95e11bfSDag-Erling Smørgrav 316d95e11bfSDag-Erling Smørgrav /* 317d95e11bfSDag-Erling Smørgrav * Export the fingerprint of a key as a DNS resource record 318d95e11bfSDag-Erling Smørgrav */ 319d95e11bfSDag-Erling Smørgrav int 320bc5531deSDag-Erling Smørgrav export_dns_rr(const char *hostname, struct sshkey *key, FILE *f, int generic) 321d95e11bfSDag-Erling Smørgrav { 322d95e11bfSDag-Erling Smørgrav u_int8_t rdata_pubkey_algorithm = 0; 323462c32cbSDag-Erling Smørgrav u_int8_t rdata_digest_type = SSHFP_HASH_RESERVED; 324462c32cbSDag-Erling Smørgrav u_int8_t dtype; 325d95e11bfSDag-Erling Smørgrav u_char *rdata_digest; 326bc5531deSDag-Erling Smørgrav size_t i, rdata_digest_len; 327d95e11bfSDag-Erling Smørgrav int success = 0; 328d95e11bfSDag-Erling Smørgrav 329462c32cbSDag-Erling Smørgrav for (dtype = SSHFP_HASH_SHA1; dtype < SSHFP_HASH_MAX; dtype++) { 330462c32cbSDag-Erling Smørgrav rdata_digest_type = dtype; 331d95e11bfSDag-Erling Smørgrav if (dns_read_key(&rdata_pubkey_algorithm, &rdata_digest_type, 332d95e11bfSDag-Erling Smørgrav &rdata_digest, &rdata_digest_len, key)) { 333462c32cbSDag-Erling Smørgrav if (generic) { 334bc5531deSDag-Erling Smørgrav fprintf(f, "%s IN TYPE%d \\# %zu %02x %02x ", 335462c32cbSDag-Erling Smørgrav hostname, DNS_RDATATYPE_SSHFP, 336462c32cbSDag-Erling Smørgrav 2 + rdata_digest_len, 337d95e11bfSDag-Erling Smørgrav rdata_pubkey_algorithm, rdata_digest_type); 338462c32cbSDag-Erling Smørgrav } else { 339d95e11bfSDag-Erling Smørgrav fprintf(f, "%s IN SSHFP %d %d ", hostname, 340d95e11bfSDag-Erling Smørgrav rdata_pubkey_algorithm, rdata_digest_type); 341462c32cbSDag-Erling Smørgrav } 342d95e11bfSDag-Erling Smørgrav for (i = 0; i < rdata_digest_len; i++) 343d95e11bfSDag-Erling Smørgrav fprintf(f, "%02x", rdata_digest[i]); 344d95e11bfSDag-Erling Smørgrav fprintf(f, "\n"); 345bc5531deSDag-Erling Smørgrav free(rdata_digest); /* from sshkey_fingerprint_raw() */ 346d95e11bfSDag-Erling Smørgrav success = 1; 347462c32cbSDag-Erling Smørgrav } 348462c32cbSDag-Erling Smørgrav } 349462c32cbSDag-Erling Smørgrav 350462c32cbSDag-Erling Smørgrav /* No SSHFP record was generated at all */ 351462c32cbSDag-Erling Smørgrav if (success == 0) { 352462c32cbSDag-Erling Smørgrav error("%s: unsupported algorithm and/or digest_type", __func__); 353d95e11bfSDag-Erling Smørgrav } 354d95e11bfSDag-Erling Smørgrav 355d95e11bfSDag-Erling Smørgrav return success; 356d95e11bfSDag-Erling Smørgrav } 357