1*bc5531deSDag-Erling Smørgrav /* $OpenBSD: dns.c,v 1.34 2015/01/28 22:36:00 djm 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" 41*bc5531deSDag-Erling Smørgrav #include "sshkey.h" 42*bc5531deSDag-Erling Smørgrav #include "ssherr.h" 43d95e11bfSDag-Erling Smørgrav #include "dns.h" 44d95e11bfSDag-Erling Smørgrav #include "log.h" 45*bc5531deSDag-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, 82*bc5531deSDag-Erling Smørgrav u_char **digest, size_t *digest_len, struct sshkey *key) 83d95e11bfSDag-Erling Smørgrav { 84*bc5531deSDag-Erling Smørgrav int r, success = 0; 85*bc5531deSDag-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; 108d95e11bfSDag-Erling Smørgrav default: 109021d409fSDag-Erling Smørgrav *algorithm = SSHFP_KEY_RESERVED; /* 0 */ 110462c32cbSDag-Erling Smørgrav *digest_type = SSHFP_HASH_RESERVED; /* 0 */ 111d95e11bfSDag-Erling Smørgrav } 112d95e11bfSDag-Erling Smørgrav 113462c32cbSDag-Erling Smørgrav switch (*digest_type) { 114462c32cbSDag-Erling Smørgrav case SSHFP_HASH_SHA1: 115*bc5531deSDag-Erling Smørgrav fp_alg = SSH_DIGEST_SHA1; 116462c32cbSDag-Erling Smørgrav break; 117462c32cbSDag-Erling Smørgrav case SSHFP_HASH_SHA256: 118*bc5531deSDag-Erling Smørgrav fp_alg = SSH_DIGEST_SHA256; 119462c32cbSDag-Erling Smørgrav break; 120462c32cbSDag-Erling Smørgrav default: 121462c32cbSDag-Erling Smørgrav *digest_type = SSHFP_HASH_RESERVED; /* 0 */ 122462c32cbSDag-Erling Smørgrav } 123462c32cbSDag-Erling Smørgrav 124462c32cbSDag-Erling Smørgrav if (*algorithm && *digest_type) { 125*bc5531deSDag-Erling Smørgrav if ((r = sshkey_fingerprint_raw(key, fp_alg, digest, 126*bc5531deSDag-Erling Smørgrav digest_len)) != 0) 127*bc5531deSDag-Erling Smørgrav fatal("%s: sshkey_fingerprint_raw: %s", __func__, 128*bc5531deSDag-Erling Smørgrav ssh_err(r)); 129d95e11bfSDag-Erling Smørgrav success = 1; 130d95e11bfSDag-Erling Smørgrav } else { 131d95e11bfSDag-Erling Smørgrav *digest = NULL; 132d95e11bfSDag-Erling Smørgrav *digest_len = 0; 133d95e11bfSDag-Erling Smørgrav success = 0; 134d95e11bfSDag-Erling Smørgrav } 135d95e11bfSDag-Erling Smørgrav 136d95e11bfSDag-Erling Smørgrav return success; 137d95e11bfSDag-Erling Smørgrav } 138d95e11bfSDag-Erling Smørgrav 139d95e11bfSDag-Erling Smørgrav /* 140d95e11bfSDag-Erling Smørgrav * Read SSHFP parameters from rdata buffer. 141d95e11bfSDag-Erling Smørgrav */ 142d95e11bfSDag-Erling Smørgrav static int 143d95e11bfSDag-Erling Smørgrav dns_read_rdata(u_int8_t *algorithm, u_int8_t *digest_type, 144*bc5531deSDag-Erling Smørgrav u_char **digest, size_t *digest_len, u_char *rdata, int rdata_len) 145d95e11bfSDag-Erling Smørgrav { 146d95e11bfSDag-Erling Smørgrav int success = 0; 147d95e11bfSDag-Erling Smørgrav 148d95e11bfSDag-Erling Smørgrav *algorithm = SSHFP_KEY_RESERVED; 149d95e11bfSDag-Erling Smørgrav *digest_type = SSHFP_HASH_RESERVED; 150d95e11bfSDag-Erling Smørgrav 151d95e11bfSDag-Erling Smørgrav if (rdata_len >= 2) { 152d95e11bfSDag-Erling Smørgrav *algorithm = rdata[0]; 153d95e11bfSDag-Erling Smørgrav *digest_type = rdata[1]; 154d95e11bfSDag-Erling Smørgrav *digest_len = rdata_len - 2; 155d95e11bfSDag-Erling Smørgrav 156d95e11bfSDag-Erling Smørgrav if (*digest_len > 0) { 157d95e11bfSDag-Erling Smørgrav *digest = (u_char *) xmalloc(*digest_len); 158d95e11bfSDag-Erling Smørgrav memcpy(*digest, rdata + 2, *digest_len); 159d95e11bfSDag-Erling Smørgrav } else { 160761efaa7SDag-Erling Smørgrav *digest = (u_char *)xstrdup(""); 161d95e11bfSDag-Erling Smørgrav } 162d95e11bfSDag-Erling Smørgrav 163d95e11bfSDag-Erling Smørgrav success = 1; 164d95e11bfSDag-Erling Smørgrav } 165d95e11bfSDag-Erling Smørgrav 166d95e11bfSDag-Erling Smørgrav return success; 167d95e11bfSDag-Erling Smørgrav } 168d95e11bfSDag-Erling Smørgrav 169043840dfSDag-Erling Smørgrav /* 170043840dfSDag-Erling Smørgrav * Check if hostname is numerical. 171043840dfSDag-Erling Smørgrav * Returns -1 if hostname is numeric, 0 otherwise 172043840dfSDag-Erling Smørgrav */ 173043840dfSDag-Erling Smørgrav static int 174043840dfSDag-Erling Smørgrav is_numeric_hostname(const char *hostname) 175043840dfSDag-Erling Smørgrav { 176043840dfSDag-Erling Smørgrav struct addrinfo hints, *ai; 177043840dfSDag-Erling Smørgrav 178d4af9e69SDag-Erling Smørgrav /* 179d4af9e69SDag-Erling Smørgrav * We shouldn't ever get a null host but if we do then log an error 180d4af9e69SDag-Erling Smørgrav * and return -1 which stops DNS key fingerprint processing. 181d4af9e69SDag-Erling Smørgrav */ 182d4af9e69SDag-Erling Smørgrav if (hostname == NULL) { 183d4af9e69SDag-Erling Smørgrav error("is_numeric_hostname called with NULL hostname"); 184d4af9e69SDag-Erling Smørgrav return -1; 185d4af9e69SDag-Erling Smørgrav } 186d4af9e69SDag-Erling Smørgrav 187043840dfSDag-Erling Smørgrav memset(&hints, 0, sizeof(hints)); 188043840dfSDag-Erling Smørgrav hints.ai_socktype = SOCK_DGRAM; 189043840dfSDag-Erling Smørgrav hints.ai_flags = AI_NUMERICHOST; 190043840dfSDag-Erling Smørgrav 191d4af9e69SDag-Erling Smørgrav if (getaddrinfo(hostname, NULL, &hints, &ai) == 0) { 192043840dfSDag-Erling Smørgrav freeaddrinfo(ai); 193043840dfSDag-Erling Smørgrav return -1; 194043840dfSDag-Erling Smørgrav } 195043840dfSDag-Erling Smørgrav 196043840dfSDag-Erling Smørgrav return 0; 197043840dfSDag-Erling Smørgrav } 198d95e11bfSDag-Erling Smørgrav 199d95e11bfSDag-Erling Smørgrav /* 200d95e11bfSDag-Erling Smørgrav * Verify the given hostname, address and host key using DNS. 201efcad6b7SDag-Erling Smørgrav * Returns 0 if lookup succeeds, -1 otherwise 202d95e11bfSDag-Erling Smørgrav */ 203d95e11bfSDag-Erling Smørgrav int 204d95e11bfSDag-Erling Smørgrav verify_host_key_dns(const char *hostname, struct sockaddr *address, 205*bc5531deSDag-Erling Smørgrav struct sshkey *hostkey, int *flags) 206d95e11bfSDag-Erling Smørgrav { 207043840dfSDag-Erling Smørgrav u_int counter; 208d95e11bfSDag-Erling Smørgrav int result; 209d95e11bfSDag-Erling Smørgrav struct rrsetinfo *fingerprints = NULL; 210d95e11bfSDag-Erling Smørgrav 211d95e11bfSDag-Erling Smørgrav u_int8_t hostkey_algorithm; 212462c32cbSDag-Erling Smørgrav u_int8_t hostkey_digest_type = SSHFP_HASH_RESERVED; 213d95e11bfSDag-Erling Smørgrav u_char *hostkey_digest; 214*bc5531deSDag-Erling Smørgrav size_t hostkey_digest_len; 215d95e11bfSDag-Erling Smørgrav 216d95e11bfSDag-Erling Smørgrav u_int8_t dnskey_algorithm; 217d95e11bfSDag-Erling Smørgrav u_int8_t dnskey_digest_type; 218d95e11bfSDag-Erling Smørgrav u_char *dnskey_digest; 219*bc5531deSDag-Erling Smørgrav size_t dnskey_digest_len; 220d95e11bfSDag-Erling Smørgrav 221efcad6b7SDag-Erling Smørgrav *flags = 0; 222d95e11bfSDag-Erling Smørgrav 223021d409fSDag-Erling Smørgrav debug3("verify_host_key_dns"); 224d95e11bfSDag-Erling Smørgrav if (hostkey == NULL) 225d95e11bfSDag-Erling Smørgrav fatal("No key to look up!"); 226d95e11bfSDag-Erling Smørgrav 227043840dfSDag-Erling Smørgrav if (is_numeric_hostname(hostname)) { 228043840dfSDag-Erling Smørgrav debug("skipped DNS lookup for numerical hostname"); 229043840dfSDag-Erling Smørgrav return -1; 230043840dfSDag-Erling Smørgrav } 231043840dfSDag-Erling Smørgrav 232d95e11bfSDag-Erling Smørgrav result = getrrsetbyname(hostname, DNS_RDATACLASS_IN, 233d95e11bfSDag-Erling Smørgrav DNS_RDATATYPE_SSHFP, 0, &fingerprints); 234d95e11bfSDag-Erling Smørgrav if (result) { 235d95e11bfSDag-Erling Smørgrav verbose("DNS lookup error: %s", dns_result_totext(result)); 236efcad6b7SDag-Erling Smørgrav return -1; 237d95e11bfSDag-Erling Smørgrav } 238d95e11bfSDag-Erling Smørgrav 239efcad6b7SDag-Erling Smørgrav if (fingerprints->rri_flags & RRSET_VALIDATED) { 240efcad6b7SDag-Erling Smørgrav *flags |= DNS_VERIFY_SECURE; 241efcad6b7SDag-Erling Smørgrav debug("found %d secure fingerprints in DNS", 242efcad6b7SDag-Erling Smørgrav fingerprints->rri_nrdatas); 243efcad6b7SDag-Erling Smørgrav } else { 244efcad6b7SDag-Erling Smørgrav debug("found %d insecure fingerprints in DNS", 245efcad6b7SDag-Erling Smørgrav fingerprints->rri_nrdatas); 246d95e11bfSDag-Erling Smørgrav } 247d95e11bfSDag-Erling Smørgrav 248462c32cbSDag-Erling Smørgrav /* Initialize default host key parameters */ 249d95e11bfSDag-Erling Smørgrav if (!dns_read_key(&hostkey_algorithm, &hostkey_digest_type, 250d95e11bfSDag-Erling Smørgrav &hostkey_digest, &hostkey_digest_len, hostkey)) { 251d95e11bfSDag-Erling Smørgrav error("Error calculating host key fingerprint."); 252d95e11bfSDag-Erling Smørgrav freerrset(fingerprints); 253efcad6b7SDag-Erling Smørgrav return -1; 254d95e11bfSDag-Erling Smørgrav } 255d95e11bfSDag-Erling Smørgrav 256efcad6b7SDag-Erling Smørgrav if (fingerprints->rri_nrdatas) 257efcad6b7SDag-Erling Smørgrav *flags |= DNS_VERIFY_FOUND; 258efcad6b7SDag-Erling Smørgrav 259d95e11bfSDag-Erling Smørgrav for (counter = 0; counter < fingerprints->rri_nrdatas; counter++) { 260d95e11bfSDag-Erling Smørgrav /* 261d95e11bfSDag-Erling Smørgrav * Extract the key from the answer. Ignore any badly 262d95e11bfSDag-Erling Smørgrav * formatted fingerprints. 263d95e11bfSDag-Erling Smørgrav */ 264d95e11bfSDag-Erling Smørgrav if (!dns_read_rdata(&dnskey_algorithm, &dnskey_digest_type, 265d95e11bfSDag-Erling Smørgrav &dnskey_digest, &dnskey_digest_len, 266d95e11bfSDag-Erling Smørgrav fingerprints->rri_rdatas[counter].rdi_data, 267d95e11bfSDag-Erling Smørgrav fingerprints->rri_rdatas[counter].rdi_length)) { 268d95e11bfSDag-Erling Smørgrav verbose("Error parsing fingerprint from DNS."); 269d95e11bfSDag-Erling Smørgrav continue; 270d95e11bfSDag-Erling Smørgrav } 271d95e11bfSDag-Erling Smørgrav 272462c32cbSDag-Erling Smørgrav if (hostkey_digest_type != dnskey_digest_type) { 273462c32cbSDag-Erling Smørgrav hostkey_digest_type = dnskey_digest_type; 274e4a9863fSDag-Erling Smørgrav free(hostkey_digest); 275462c32cbSDag-Erling Smørgrav 276462c32cbSDag-Erling Smørgrav /* Initialize host key parameters */ 277462c32cbSDag-Erling Smørgrav if (!dns_read_key(&hostkey_algorithm, 278462c32cbSDag-Erling Smørgrav &hostkey_digest_type, &hostkey_digest, 279462c32cbSDag-Erling Smørgrav &hostkey_digest_len, hostkey)) { 280462c32cbSDag-Erling Smørgrav error("Error calculating key fingerprint."); 281462c32cbSDag-Erling Smørgrav freerrset(fingerprints); 282462c32cbSDag-Erling Smørgrav return -1; 283462c32cbSDag-Erling Smørgrav } 284462c32cbSDag-Erling Smørgrav } 285462c32cbSDag-Erling Smørgrav 286d95e11bfSDag-Erling Smørgrav /* Check if the current key is the same as the given key */ 287d95e11bfSDag-Erling Smørgrav if (hostkey_algorithm == dnskey_algorithm && 288d95e11bfSDag-Erling Smørgrav hostkey_digest_type == dnskey_digest_type) { 289d95e11bfSDag-Erling Smørgrav if (hostkey_digest_len == dnskey_digest_len && 290462c32cbSDag-Erling Smørgrav timingsafe_bcmp(hostkey_digest, dnskey_digest, 291462c32cbSDag-Erling Smørgrav hostkey_digest_len) == 0) 292efcad6b7SDag-Erling Smørgrav *flags |= DNS_VERIFY_MATCH; 293efcad6b7SDag-Erling Smørgrav } 294e4a9863fSDag-Erling Smørgrav free(dnskey_digest); 295efcad6b7SDag-Erling Smørgrav } 296efcad6b7SDag-Erling Smørgrav 297*bc5531deSDag-Erling Smørgrav free(hostkey_digest); /* from sshkey_fingerprint_raw() */ 298d95e11bfSDag-Erling Smørgrav freerrset(fingerprints); 299efcad6b7SDag-Erling Smørgrav 300efcad6b7SDag-Erling Smørgrav if (*flags & DNS_VERIFY_FOUND) 301efcad6b7SDag-Erling Smørgrav if (*flags & DNS_VERIFY_MATCH) 302d95e11bfSDag-Erling Smørgrav debug("matching host key fingerprint found in DNS"); 303efcad6b7SDag-Erling Smørgrav else 304efcad6b7SDag-Erling Smørgrav debug("mismatching host key fingerprint found in DNS"); 305efcad6b7SDag-Erling Smørgrav else 306efcad6b7SDag-Erling Smørgrav debug("no host key fingerprint found in DNS"); 307d95e11bfSDag-Erling Smørgrav 308efcad6b7SDag-Erling Smørgrav return 0; 309d95e11bfSDag-Erling Smørgrav } 310d95e11bfSDag-Erling Smørgrav 311d95e11bfSDag-Erling Smørgrav /* 312d95e11bfSDag-Erling Smørgrav * Export the fingerprint of a key as a DNS resource record 313d95e11bfSDag-Erling Smørgrav */ 314d95e11bfSDag-Erling Smørgrav int 315*bc5531deSDag-Erling Smørgrav export_dns_rr(const char *hostname, struct sshkey *key, FILE *f, int generic) 316d95e11bfSDag-Erling Smørgrav { 317d95e11bfSDag-Erling Smørgrav u_int8_t rdata_pubkey_algorithm = 0; 318462c32cbSDag-Erling Smørgrav u_int8_t rdata_digest_type = SSHFP_HASH_RESERVED; 319462c32cbSDag-Erling Smørgrav u_int8_t dtype; 320d95e11bfSDag-Erling Smørgrav u_char *rdata_digest; 321*bc5531deSDag-Erling Smørgrav size_t i, rdata_digest_len; 322d95e11bfSDag-Erling Smørgrav int success = 0; 323d95e11bfSDag-Erling Smørgrav 324462c32cbSDag-Erling Smørgrav for (dtype = SSHFP_HASH_SHA1; dtype < SSHFP_HASH_MAX; dtype++) { 325462c32cbSDag-Erling Smørgrav rdata_digest_type = dtype; 326d95e11bfSDag-Erling Smørgrav if (dns_read_key(&rdata_pubkey_algorithm, &rdata_digest_type, 327d95e11bfSDag-Erling Smørgrav &rdata_digest, &rdata_digest_len, key)) { 328462c32cbSDag-Erling Smørgrav if (generic) { 329*bc5531deSDag-Erling Smørgrav fprintf(f, "%s IN TYPE%d \\# %zu %02x %02x ", 330462c32cbSDag-Erling Smørgrav hostname, DNS_RDATATYPE_SSHFP, 331462c32cbSDag-Erling Smørgrav 2 + rdata_digest_len, 332d95e11bfSDag-Erling Smørgrav rdata_pubkey_algorithm, rdata_digest_type); 333462c32cbSDag-Erling Smørgrav } else { 334d95e11bfSDag-Erling Smørgrav fprintf(f, "%s IN SSHFP %d %d ", hostname, 335d95e11bfSDag-Erling Smørgrav rdata_pubkey_algorithm, rdata_digest_type); 336462c32cbSDag-Erling Smørgrav } 337d95e11bfSDag-Erling Smørgrav for (i = 0; i < rdata_digest_len; i++) 338d95e11bfSDag-Erling Smørgrav fprintf(f, "%02x", rdata_digest[i]); 339d95e11bfSDag-Erling Smørgrav fprintf(f, "\n"); 340*bc5531deSDag-Erling Smørgrav free(rdata_digest); /* from sshkey_fingerprint_raw() */ 341d95e11bfSDag-Erling Smørgrav success = 1; 342462c32cbSDag-Erling Smørgrav } 343462c32cbSDag-Erling Smørgrav } 344462c32cbSDag-Erling Smørgrav 345462c32cbSDag-Erling Smørgrav /* No SSHFP record was generated at all */ 346462c32cbSDag-Erling Smørgrav if (success == 0) { 347462c32cbSDag-Erling Smørgrav error("%s: unsupported algorithm and/or digest_type", __func__); 348d95e11bfSDag-Erling Smørgrav } 349d95e11bfSDag-Erling Smørgrav 350d95e11bfSDag-Erling Smørgrav return success; 351d95e11bfSDag-Erling Smørgrav } 352