[BACK]Return to dns.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Annotation of src/usr.bin/ssh/dns.c, Revision 1.1

1.1     ! jakob       1: /*     $OpenBSD: dns.c,v 1.1 2003/05/12 16:40:33 jakob 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:  * 3. The name of the authors may not be used to endorse or promote products
        !            16:  *    derived from this software without specific prior written permission.
        !            17:  *
        !            18:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            19:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            20:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            21:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            22:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
        !            23:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
        !            24:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
        !            25:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            26:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
        !            27:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            28:  */
        !            29:
        !            30:
        !            31: #include "includes.h"
        !            32:
        !            33: #ifdef DNS
        !            34: #include <openssl/bn.h>
        !            35: #ifdef LWRES
        !            36: #include <lwres/netdb.h>
        !            37: #include <dns/result.h>
        !            38: #else /* LWRES */
        !            39: #include <netdb.h>
        !            40: #endif /* LWRES */
        !            41:
        !            42: #include "xmalloc.h"
        !            43: #include "key.h"
        !            44: #include "dns.h"
        !            45: #include "log.h"
        !            46: #include "uuencode.h"
        !            47:
        !            48: extern char *__progname;
        !            49: RCSID("$OpenBSD: dns.c,v 1.1 2003/05/12 16:40:33 jakob Exp $");
        !            50:
        !            51: #ifndef LWRES
        !            52: static const char *errset_text[] = {
        !            53:        "success",              /* 0 ERRSET_SUCCESS */
        !            54:        "out of memory",        /* 1 ERRSET_NOMEMORY */
        !            55:        "general failure",      /* 2 ERRSET_FAIL */
        !            56:        "invalid parameter",    /* 3 ERRSET_INVAL */
        !            57:        "name does not exist",  /* 4 ERRSET_NONAME */
        !            58:        "data does not exist",  /* 5 ERRSET_NODATA */
        !            59: };
        !            60:
        !            61: static const char *
        !            62: dns_result_totext(unsigned int error)
        !            63: {
        !            64:        switch (error) {
        !            65:        case ERRSET_SUCCESS:
        !            66:                return errset_text[ERRSET_SUCCESS];
        !            67:        case ERRSET_NOMEMORY:
        !            68:                return errset_text[ERRSET_NOMEMORY];
        !            69:        case ERRSET_FAIL:
        !            70:                return errset_text[ERRSET_FAIL];
        !            71:        case ERRSET_INVAL:
        !            72:                return errset_text[ERRSET_INVAL];
        !            73:        case ERRSET_NONAME:
        !            74:                return errset_text[ERRSET_NONAME];
        !            75:        case ERRSET_NODATA:
        !            76:                return errset_text[ERRSET_NODATA];
        !            77:        default:
        !            78:                return "unknown error";
        !            79:        }
        !            80: }
        !            81: #endif /* LWRES */
        !            82:
        !            83:
        !            84: /*
        !            85:  * Read SSHFP parameters from key buffer.
        !            86:  */
        !            87: static int
        !            88: dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type,
        !            89:     u_char **digest, u_int *digest_len, Key *key)
        !            90: {
        !            91:        int success = 0;
        !            92:
        !            93:        switch (key->type) {
        !            94:        case KEY_RSA:
        !            95:                *algorithm = DNS_KEY_RSA;
        !            96:                break;
        !            97:        case KEY_DSA:
        !            98:                *algorithm = DNS_KEY_DSA;
        !            99:                break;
        !           100:        default:
        !           101:                *algorithm = DNS_KEY_RESERVED;
        !           102:        }
        !           103:
        !           104:        if (*algorithm) {
        !           105:                *digest_type = DNS_HASH_SHA1;
        !           106:                *digest = key_fingerprint_raw(key, SSH_FP_SHA1, digest_len);
        !           107:                success = 1;
        !           108:        } else {
        !           109:                *digest_type = DNS_HASH_RESERVED;
        !           110:                *digest = NULL;
        !           111:                *digest_len = 0;
        !           112:                success = 0;
        !           113:        }
        !           114:
        !           115:        return success;
        !           116: }
        !           117:
        !           118: /*
        !           119:  * Read SSHFP parameters from rdata buffer.
        !           120:  */
        !           121: static int
        !           122: dns_read_rdata(u_int8_t *algorithm, u_int8_t *digest_type,
        !           123:     u_char **digest, u_int *digest_len, u_char *rdata, int rdata_len)
        !           124: {
        !           125:        int success = 0;
        !           126:
        !           127:        *algorithm = DNS_KEY_RESERVED;
        !           128:        *digest_type = DNS_HASH_RESERVED;
        !           129:
        !           130:        if (rdata_len >= 2) {
        !           131:                *algorithm = rdata[0];
        !           132:                *digest_type = rdata[1];
        !           133:                *digest_len = rdata_len - 2;
        !           134:
        !           135:                if (*digest_len > 0) {
        !           136:                        *digest = (u_char *) xmalloc(*digest_len);
        !           137:                        memcpy(*digest, rdata + 2, *digest_len);
        !           138:                } else {
        !           139:                        *digest = NULL;
        !           140:                }
        !           141:
        !           142:                success = 1;
        !           143:        }
        !           144:
        !           145:        return success;
        !           146: }
        !           147:
        !           148:
        !           149: /*
        !           150:  * Verify the given hostname, address and host key using DNS.
        !           151:  * Returns 0 if key verifies or -1 if key does NOT verify
        !           152:  */
        !           153: int
        !           154: verify_host_key_dns(const char *hostname, struct sockaddr *address,
        !           155:     Key *hostkey)
        !           156: {
        !           157:        int counter;
        !           158:        int result;
        !           159:        struct rrsetinfo *keys = NULL;
        !           160:        int failures = 0;
        !           161:
        !           162:        u_int8_t hostkey_algorithm;
        !           163:        u_int8_t hostkey_digest_type;
        !           164:        u_char *hostkey_digest;
        !           165:        u_int hostkey_digest_len;
        !           166:
        !           167:        u_int8_t dnskey_algorithm;
        !           168:        u_int8_t dnskey_digest_type;
        !           169:        u_char *dnskey_digest;
        !           170:        u_int dnskey_digest_len;
        !           171:
        !           172:
        !           173:        debug3("verify_hostkey_dns");
        !           174:        if (hostkey == NULL)
        !           175:                fatal("No key to look up!");
        !           176:
        !           177:        result = getrrsetbyname(hostname, DNS_RDATACLASS_IN,
        !           178:            DNS_RDATATYPE_SSHFP, 0, &keys);
        !           179:        if (result) {
        !           180:                verbose("DNS lookup error: %s", dns_result_totext(result));
        !           181:                return DNS_VERIFY_ERROR;
        !           182:        }
        !           183:
        !           184: #ifdef DNSSEC
        !           185:        /* Only accept validated answers */
        !           186:        if (!keys->rri_flags & RRSET_VALIDATED) {
        !           187:                error("Ignored unvalidated fingerprint from DNS.");
        !           188:                return DNS_VERIFY_ERROR;
        !           189:        }
        !           190: #endif
        !           191:
        !           192:        debug("found %d fingerprints in DNS", keys->rri_nrdatas);
        !           193:
        !           194:        /* Initialize host key parameters */
        !           195:        if (!dns_read_key(&hostkey_algorithm, &hostkey_digest_type,
        !           196:            &hostkey_digest, &hostkey_digest_len, hostkey)) {
        !           197:                error("Error calculating host key fingerprint.");
        !           198:                return DNS_VERIFY_ERROR;
        !           199:        }
        !           200:
        !           201:        for (counter = 0 ; counter < keys->rri_nrdatas ; counter++)  {
        !           202:                /*
        !           203:                 * Extract the key from the answer. Ignore any badly
        !           204:                 * formatted keys.
        !           205:                 */
        !           206:                if (!dns_read_rdata(&dnskey_algorithm, &dnskey_digest_type,
        !           207:                    &dnskey_digest, &dnskey_digest_len,
        !           208:                    keys->rri_rdatas[counter].rdi_data,
        !           209:                    keys->rri_rdatas[counter].rdi_length)) {
        !           210:                        verbose("Error parsing fingerprint from DNS.");
        !           211:                        continue;
        !           212:                }
        !           213:
        !           214:                /* Check if the current key is the same as the given key */
        !           215:                if (hostkey_algorithm == dnskey_algorithm &&
        !           216:                    hostkey_digest_type == dnskey_digest_type) {
        !           217:
        !           218:                        if (hostkey_digest_len == dnskey_digest_len &&
        !           219:                            memcmp(hostkey_digest, dnskey_digest,
        !           220:                            hostkey_digest_len) == 0) {
        !           221:
        !           222:                                /* Matching algoritm and digest. */
        !           223:                                freerrset(keys);
        !           224: #ifdef DNSSEC
        !           225:                                debug("matching host key fingerprint found in DNS");
        !           226:                                return DNS_VERIFY_OK;
        !           227: #else
        !           228:                                logit("Matching host key fingerprint found in DNS.");
        !           229:                                return DNS_VERIFY_ERROR;
        !           230: #endif
        !           231:                        } else {
        !           232:                                /* Correct algorithm but bad digest */
        !           233:                                debug("verify_hostkey_dns: failed");
        !           234:                                failures++;
        !           235:                        }
        !           236:                }
        !           237:        }
        !           238:
        !           239:        freerrset(keys);
        !           240:
        !           241:        if (failures) {
        !           242:                error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
        !           243:                error("@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @");
        !           244:                error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
        !           245:                error("IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!");
        !           246:                error("Someone could be eavesdropping on you right now (man-in-the-middle attack)!");
        !           247:                error("It is also possible that the %s host key has just been changed.",
        !           248:                    key_type(hostkey));
        !           249:                error("Please contact your system administrator.");
        !           250:                return DNS_VERIFY_FAILED;
        !           251:        }
        !           252:
        !           253:        debug("fingerprints found in DNS, but none of them matched");
        !           254:
        !           255:        return DNS_VERIFY_ERROR;
        !           256: }
        !           257:
        !           258:
        !           259: /*
        !           260:  * Export the fingerprint of a key as a DNS resource record
        !           261:  */
        !           262: int
        !           263: export_dns_rr(const char *hostname, Key *key, FILE *f, int generic)
        !           264: {
        !           265:        u_int8_t rdata_pubkey_algorithm = 0;
        !           266:        u_int8_t rdata_digest_type = DNS_HASH_SHA1;
        !           267:        u_char *rdata_digest;
        !           268:        u_int rdata_digest_len;
        !           269:
        !           270:        int i;
        !           271:        int success = 0;
        !           272:
        !           273:        if (dns_read_key(&rdata_pubkey_algorithm, &rdata_digest_type,
        !           274:                         &rdata_digest, &rdata_digest_len, key)) {
        !           275:
        !           276:                if (generic)
        !           277:                        fprintf(f, "%s IN TYPE%d \\# %d %02x %02x ", hostname,
        !           278:                            DNS_RDATATYPE_SSHFP, 2 + rdata_digest_len,
        !           279:                            rdata_pubkey_algorithm, rdata_digest_type);
        !           280:                else
        !           281:                        fprintf(f, "%s IN SSHFP %d %d ", hostname,
        !           282:                            rdata_pubkey_algorithm, rdata_digest_type);
        !           283:
        !           284:                for (i = 0; i < rdata_digest_len; i++)
        !           285:                        fprintf(f, "%02x", rdata_digest[i]);
        !           286:                fprintf(f, "\n");
        !           287:                success = 1;
        !           288:        } else {
        !           289:                error("dns_export_rr: unsupported algorithm");
        !           290:        }
        !           291:
        !           292:        return success;
        !           293: }
        !           294:
        !           295: #endif /* DNS */