Annotation of embedaddon/dhcp/minires/ns_verify.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (c) 2004,2007,2009 by Internet Systems Consortium, Inc. ("ISC")
        !             3:  * Copyright (c) 1999-2003 by Internet Software Consortium
        !             4:  *
        !             5:  * Permission to use, copy, modify, and distribute this software for any
        !             6:  * purpose with or without fee is hereby granted, provided that the above
        !             7:  * copyright notice and this permission notice appear in all copies.
        !             8:  *
        !             9:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
        !            10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            11:  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
        !            12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
        !            15:  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            16:  *
        !            17:  *   Internet Systems Consortium, Inc.
        !            18:  *   950 Charter Street
        !            19:  *   Redwood City, CA 94063
        !            20:  *   <info@isc.org>
        !            21:  *   https://www.isc.org/
        !            22:  */
        !            23: 
        !            24: #ifndef lint
        !            25: static const char rcsid[] = "$Id: ns_verify.c,v 1.9.310.2 2009-07-24 22:04:52 sar Exp $";
        !            26: #endif
        !            27: 
        !            28: /* Import. */
        !            29: 
        !            30: #include <sys/types.h>
        !            31: #include <sys/param.h>
        !            32: 
        !            33: #include <netinet/in.h>
        !            34: #include <arpa/inet.h>
        !            35: #include <sys/socket.h>
        !            36: 
        !            37: #include <errno.h>
        !            38: #include <netdb.h>
        !            39: #include <stdio.h>
        !            40: #include <stdlib.h>
        !            41: #include <string.h>
        !            42: #include <unistd.h>
        !            43: #include <time.h>
        !            44: 
        !            45: #define time(x)                trace_mr_time (x)
        !            46: 
        !            47: #include "minires/minires.h"
        !            48: #include "arpa/nameser.h"
        !            49: #include <isc-dhcp/dst.h>
        !            50: 
        !            51: time_t trace_mr_time (time_t *);
        !            52: 
        !            53: /* Private. */
        !            54: 
        !            55: #define BOUNDS_CHECK(ptr, count) \
        !            56:        do { \
        !            57:                if ((ptr) + (count) > eom) { \
        !            58:                        return (NS_TSIG_ERROR_FORMERR); \
        !            59:                } \
        !            60:        } while (0)
        !            61: 
        !            62: /* Public. */
        !            63: 
        !            64: u_char *
        !            65: ns_find_tsig(u_char *msg, u_char *eom) {
        !            66:        HEADER *hp = (HEADER *)msg;
        !            67:        int n, type;
        !            68:        u_char *cp = msg, *start;
        !            69:        isc_result_t status;
        !            70: 
        !            71:        if (msg == NULL || eom == NULL || msg > eom)
        !            72:                return (NULL);
        !            73: 
        !            74:        if (cp + HFIXEDSZ >= eom)
        !            75:                return (NULL);
        !            76: 
        !            77:        if (hp->arcount == 0)
        !            78:                return (NULL);
        !            79: 
        !            80:        cp += HFIXEDSZ;
        !            81: 
        !            82:        status = ns_skiprr(cp, eom, ns_s_qd, ntohs(hp->qdcount), &n);
        !            83:        if (status != ISC_R_SUCCESS)
        !            84:                return (NULL);
        !            85:        cp += n;
        !            86: 
        !            87:        status = ns_skiprr(cp, eom, ns_s_an, ntohs(hp->ancount), &n);
        !            88:        if (status != ISC_R_SUCCESS)
        !            89:                return (NULL);
        !            90:        cp += n;
        !            91: 
        !            92:        status = ns_skiprr(cp, eom, ns_s_ns, ntohs(hp->nscount), &n);
        !            93:        if (status != ISC_R_SUCCESS)
        !            94:                return (NULL);
        !            95:        cp += n;
        !            96: 
        !            97:        status = ns_skiprr(cp, eom, ns_s_ar, ntohs(hp->arcount) - 1, &n);
        !            98:        if (status != ISC_R_SUCCESS)
        !            99:                return (NULL);
        !           100:        cp += n;
        !           101: 
        !           102:        start = cp;
        !           103:        n = dn_skipname(cp, eom);
        !           104:        if (n < 0)
        !           105:                return (NULL);
        !           106:        cp += n;
        !           107:        if (cp + INT16SZ >= eom)
        !           108:                return (NULL);
        !           109: 
        !           110:        GETSHORT(type, cp);
        !           111:        if (type != ns_t_tsig)
        !           112:                return (NULL);
        !           113:        return (start);
        !           114: }
        !           115: 
        !           116: /* ns_verify
        !           117:  * Parameters:
        !           118:  *     statp           res stuff
        !           119:  *     msg             received message
        !           120:  *     msglen          length of message
        !           121:  *     key             tsig key used for verifying.
        !           122:  *     querysig        (response), the signature in the query
        !           123:  *     querysiglen     (response), the length of the signature in the query
        !           124:  *     sig             (query), a buffer to hold the signature
        !           125:  *     siglen          (query), input - length of signature buffer
        !           126:  *                              output - length of signature
        !           127:  *
        !           128:  * Errors:
        !           129:  *     - bad input (-1)
        !           130:  *     - invalid dns message (NS_TSIG_ERROR_FORMERR)
        !           131:  *     - TSIG is not present (NS_TSIG_ERROR_NO_TSIG)
        !           132:  *     - key doesn't match (-ns_r_badkey)
        !           133:  *     - TSIG verification fails with BADKEY (-ns_r_badkey)
        !           134:  *     - TSIG verification fails with BADSIG (-ns_r_badsig)
        !           135:  *     - TSIG verification fails with BADTIME (-ns_r_badtime)
        !           136:  *     - TSIG verification succeeds, error set to BAKEY (ns_r_badkey)
        !           137:  *     - TSIG verification succeeds, error set to BADSIG (ns_r_badsig)
        !           138:  *     - TSIG verification succeeds, error set to BADTIME (ns_r_badtime)
        !           139:  */
        !           140: isc_result_t
        !           141: ns_verify(u_char *msg, unsigned *msglen, void *k,
        !           142:          const u_char *querysig, unsigned querysiglen,
        !           143:          u_char *sig, unsigned *siglen, time_t *timesigned, int nostrip)
        !           144: {
        !           145:        HEADER *hp = (HEADER *)msg;
        !           146:        DST_KEY *key = (DST_KEY *)k;
        !           147:        u_char *cp = msg, *eom;
        !           148:        char name[MAXDNAME], alg[MAXDNAME];
        !           149:        u_char *recstart, *rdatastart;
        !           150:        u_char *sigstart, *otherstart;
        !           151:        unsigned n;
        !           152:        int error;
        !           153:        u_int16_t type, length;
        !           154:        u_int16_t fudge, sigfieldlen, id, otherfieldlen;
        !           155: 
        !           156:        dst_init();
        !           157:        if (msg == NULL || msglen == NULL || *msglen < 0)
        !           158:                return ISC_R_INVALIDARG;
        !           159: 
        !           160:        eom = msg + *msglen;
        !           161: 
        !           162:        recstart = ns_find_tsig(msg, eom);
        !           163:        if (recstart == NULL)
        !           164:                return ISC_R_NO_TSIG;
        !           165: 
        !           166:        cp = recstart;
        !           167: 
        !           168:        /* Read the key name. */
        !           169:        n = dn_expand(msg, eom, cp, name, MAXDNAME);
        !           170:        if (n < 0)
        !           171:                return ISC_R_FORMERR;
        !           172:        cp += n;
        !           173: 
        !           174:        /* Read the type. */
        !           175:        BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ);
        !           176:        GETSHORT(type, cp);
        !           177:        if (type != ns_t_tsig)
        !           178:                return ISC_R_NO_TSIG;
        !           179: 
        !           180:        /* Skip the class and TTL, save the length. */
        !           181:        cp += INT16SZ + INT32SZ;
        !           182:        GETSHORT(length, cp);
        !           183:        if (eom - cp != length)
        !           184:                return ISC_R_FORMERR;
        !           185: 
        !           186:        /* Read the algorithm name. */
        !           187:        rdatastart = cp;
        !           188:        n = dn_expand(msg, eom, cp, alg, MAXDNAME);
        !           189:        if (n < 0)
        !           190:                return ISC_R_FORMERR;
        !           191:        if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1)
        !           192:                return ISC_R_INVALIDKEY;
        !           193:        cp += n;
        !           194: 
        !           195:        /* Read the time signed and fudge. */
        !           196:        BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ);
        !           197:        cp += INT16SZ;
        !           198:        GETLONG((*timesigned), cp);
        !           199:        GETSHORT(fudge, cp);
        !           200: 
        !           201:        /* Read the signature. */
        !           202:        BOUNDS_CHECK(cp, INT16SZ);
        !           203:        GETSHORT(sigfieldlen, cp);
        !           204:        BOUNDS_CHECK(cp, sigfieldlen);
        !           205:        sigstart = cp;
        !           206:        cp += sigfieldlen;
        !           207: 
        !           208:        /* Read the original id and error. */
        !           209:        BOUNDS_CHECK(cp, 2*INT16SZ);
        !           210:        GETSHORT(id, cp);
        !           211:        GETSHORT(error, cp);
        !           212: 
        !           213:        /* Parse the other data. */
        !           214:        BOUNDS_CHECK(cp, INT16SZ);
        !           215:        GETSHORT(otherfieldlen, cp);
        !           216:        BOUNDS_CHECK(cp, otherfieldlen);
        !           217:        otherstart = cp;
        !           218:        cp += otherfieldlen;
        !           219: 
        !           220:        if (cp != eom)
        !           221:                return ISC_R_FORMERR;
        !           222: 
        !           223:        /* Verify that the key used is OK. */
        !           224:        if (key != NULL) {
        !           225:                if (key->dk_alg != KEY_HMAC_MD5)
        !           226:                        return ISC_R_INVALIDKEY;
        !           227:                if (error != ns_r_badsig && error != ns_r_badkey) {
        !           228:                        if (ns_samename(key->dk_key_name, name) != 1)
        !           229:                                return ISC_R_INVALIDKEY;
        !           230:                }
        !           231:        }
        !           232: 
        !           233:        hp->arcount = htons(ntohs(hp->arcount) - 1);
        !           234: 
        !           235:        /*
        !           236:         * Do the verification.
        !           237:         */
        !           238: 
        !           239:        if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) {
        !           240:                void *ctx;
        !           241:                u_char buf[MAXDNAME];
        !           242: 
        !           243:                /* Digest the query signature, if this is a response. */
        !           244:                dst_verify_data(SIG_MODE_INIT, key, &ctx, NULL, 0, NULL, 0);
        !           245:                if (querysiglen > 0 && querysig != NULL) {
        !           246:                        u_int16_t len_n = htons(querysiglen);
        !           247:                        dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
        !           248:                                        (u_char *)&len_n, INT16SZ, NULL, 0);
        !           249:                        dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
        !           250:                                        querysig, querysiglen, NULL, 0);
        !           251:                }
        !           252:                
        !           253:                /* Digest the message. */
        !           254:                dst_verify_data(SIG_MODE_UPDATE, key, &ctx, msg,
        !           255:                                (unsigned)(recstart - msg), NULL, 0);
        !           256: 
        !           257:                /* Digest the key name. */
        !           258:                n = ns_name_ntol(recstart, buf, sizeof(buf));
        !           259:                dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
        !           260: 
        !           261:                /* Digest the class and TTL. */
        !           262:                dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
        !           263:                                recstart + dn_skipname(recstart, eom) + INT16SZ,
        !           264:                                INT16SZ + INT32SZ, NULL, 0);
        !           265: 
        !           266:                /* Digest the algorithm. */
        !           267:                n = ns_name_ntol(rdatastart, buf, sizeof(buf));
        !           268:                dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
        !           269: 
        !           270:                /* Digest the time signed and fudge. */
        !           271:                dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
        !           272:                                rdatastart + dn_skipname(rdatastart, eom),
        !           273:                                INT16SZ + INT32SZ + INT16SZ, NULL, 0);
        !           274: 
        !           275:                /* Digest the error and other data. */
        !           276:                dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
        !           277:                                otherstart - INT16SZ - INT16SZ,
        !           278:                                (unsigned)otherfieldlen + INT16SZ + INT16SZ,
        !           279:                                NULL, 0);
        !           280: 
        !           281:                n = dst_verify_data(SIG_MODE_FINAL, key, &ctx, NULL, 0,
        !           282:                                    sigstart, sigfieldlen);
        !           283: 
        !           284:                if (n < 0)
        !           285:                        return ISC_R_BADSIG;
        !           286: 
        !           287:                if (sig != NULL && siglen != NULL) {
        !           288:                        if (*siglen < sigfieldlen)
        !           289:                                return ISC_R_NOSPACE;
        !           290:                        memcpy(sig, sigstart, sigfieldlen);
        !           291:                        *siglen = sigfieldlen;
        !           292:                }
        !           293:        } else {
        !           294:                if (sigfieldlen > 0)
        !           295:                        return ISC_R_FORMERR;
        !           296:                if (sig != NULL && siglen != NULL)
        !           297:                        *siglen = 0;
        !           298:        }
        !           299: 
        !           300:        /* Reset the counter, since we still need to check for badtime. */
        !           301:        hp->arcount = htons(ntohs(hp->arcount) + 1);
        !           302: 
        !           303:        /* Verify the time. */
        !           304:        if (abs((*timesigned) - time(NULL)) > fudge)
        !           305:                return ISC_R_BADTIME;
        !           306: 
        !           307:        if (nostrip == 0) {
        !           308:                *msglen = recstart - msg;
        !           309:                hp->arcount = htons(ntohs(hp->arcount) - 1);
        !           310:        }
        !           311: 
        !           312:        if (error != NOERROR)
        !           313:                return ns_rcode_to_isc (error);
        !           314: 
        !           315:        return ISC_R_SUCCESS;
        !           316: }
        !           317: 
        !           318: #if 0
        !           319: isc_result_t
        !           320: ns_verify_tcp_init(void *k, const u_char *querysig, unsigned querysiglen,
        !           321:                   ns_tcp_tsig_state *state)
        !           322: {
        !           323:        dst_init();
        !           324:        if (state == NULL || k == NULL || querysig == NULL || querysiglen < 0)
        !           325:                return ISC_R_INVALIDARG;
        !           326:        state->counter = -1;
        !           327:        state->key = k;
        !           328:        if (state->key->dk_alg != KEY_HMAC_MD5)
        !           329:                return ISC_R_BADKEY;
        !           330:        if (querysiglen > sizeof(state->sig))
        !           331:                return ISC_R_NOSPACE;
        !           332:        memcpy(state->sig, querysig, querysiglen);
        !           333:        state->siglen = querysiglen;
        !           334:        return ISC_R_SUCCESS;
        !           335: }
        !           336: 
        !           337: isc_result_t
        !           338: ns_verify_tcp(u_char *msg, unsigned *msglen, ns_tcp_tsig_state *state,
        !           339:              int required)
        !           340: {
        !           341:        HEADER *hp = (HEADER *)msg;
        !           342:        u_char *recstart, *rdatastart, *sigstart;
        !           343:        unsigned sigfieldlen, otherfieldlen;
        !           344:        u_char *cp, *eom = msg + *msglen, *cp2;
        !           345:        char name[MAXDNAME], alg[MAXDNAME];
        !           346:        u_char buf[MAXDNAME];
        !           347:        int n, type, length, fudge, id, error;
        !           348:        time_t timesigned;
        !           349: 
        !           350:        if (msg == NULL || msglen == NULL || state == NULL)
        !           351:                return ISC_R_INVALIDARG;
        !           352: 
        !           353:        state->counter++;
        !           354:        if (state->counter == 0)
        !           355:                return (ns_verify(msg, msglen, state->key,
        !           356:                                  state->sig, state->siglen,
        !           357:                                  state->sig, &state->siglen, &timesigned, 0));
        !           358: 
        !           359:        if (state->siglen > 0) {
        !           360:                u_int16_t siglen_n = htons(state->siglen);
        !           361: 
        !           362:                dst_verify_data(SIG_MODE_INIT, state->key, &state->ctx,
        !           363:                                NULL, 0, NULL, 0);
        !           364:                dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
        !           365:                                (u_char *)&siglen_n, INT16SZ, NULL, 0);
        !           366:                dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
        !           367:                                state->sig, state->siglen, NULL, 0);
        !           368:                state->siglen = 0;
        !           369:        }
        !           370: 
        !           371:        cp = recstart = ns_find_tsig(msg, eom);
        !           372: 
        !           373:        if (recstart == NULL) {
        !           374:                if (required)
        !           375:                        return ISC_R_NO_TSIG;
        !           376:                dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
        !           377:                                msg, *msglen, NULL, 0);
        !           378:                return ISC_R_SUCCESS;
        !           379:        }
        !           380: 
        !           381:        hp->arcount = htons(ntohs(hp->arcount) - 1);
        !           382:        dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
        !           383:                        msg, (unsigned)(recstart - msg), NULL, 0);
        !           384:        
        !           385:        /* Read the key name. */
        !           386:        n = dn_expand(msg, eom, cp, name, MAXDNAME);
        !           387:        if (n < 0)
        !           388:                return ISC_R_FORMERR;
        !           389:        cp += n;
        !           390: 
        !           391:        /* Read the type. */
        !           392:        BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ);
        !           393:        GETSHORT(type, cp);
        !           394:        if (type != ns_t_tsig)
        !           395:                return ISC_R_NO_TSIG;
        !           396: 
        !           397:        /* Skip the class and TTL, save the length. */
        !           398:        cp += INT16SZ + INT32SZ;
        !           399:        GETSHORT(length, cp);
        !           400:        if (eom - cp != length)
        !           401:                return ISC_R_FORMERR;
        !           402: 
        !           403:        /* Read the algorithm name. */
        !           404:        rdatastart = cp;
        !           405:        n = dn_expand(msg, eom, cp, alg, MAXDNAME);
        !           406:        if (n < 0)
        !           407:                return ISC_R_FORMERR;
        !           408:        if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1)
        !           409:                return ISC_R_BADKEY;
        !           410:        cp += n;
        !           411: 
        !           412:        /* Verify that the key used is OK. */
        !           413:        if ((ns_samename(state->key->dk_key_name, name) != 1 ||
        !           414:             state->key->dk_alg != KEY_HMAC_MD5))
        !           415:                return ISC_R_BADKEY;
        !           416: 
        !           417:        /* Read the time signed and fudge. */
        !           418:        BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ);
        !           419:        cp += INT16SZ;
        !           420:        GETLONG(timesigned, cp);
        !           421:        GETSHORT(fudge, cp);
        !           422: 
        !           423:        /* Read the signature. */
        !           424:        BOUNDS_CHECK(cp, INT16SZ);
        !           425:        GETSHORT(sigfieldlen, cp);
        !           426:        BOUNDS_CHECK(cp, sigfieldlen);
        !           427:        sigstart = cp;
        !           428:        cp += sigfieldlen;
        !           429: 
        !           430:        /* Read the original id and error. */
        !           431:        BOUNDS_CHECK(cp, 2*INT16SZ);
        !           432:        GETSHORT(id, cp);
        !           433:        GETSHORT(error, cp);
        !           434: 
        !           435:        /* Parse the other data. */
        !           436:        BOUNDS_CHECK(cp, INT16SZ);
        !           437:        GETSHORT(otherfieldlen, cp);
        !           438:        BOUNDS_CHECK(cp, otherfieldlen);
        !           439:        cp += otherfieldlen;
        !           440: 
        !           441:        if (cp != eom)
        !           442:                return ISC_R_FORMERR;
        !           443: 
        !           444:        /*
        !           445:         * Do the verification.
        !           446:         */
        !           447: 
        !           448:        /* Digest the time signed and fudge. */
        !           449:        cp2 = buf;
        !           450:        PUTSHORT(0, cp2);       /* Top 16 bits of time. */
        !           451:        PUTLONG(timesigned, cp2);
        !           452:        PUTSHORT(NS_TSIG_FUDGE, cp2);
        !           453: 
        !           454:        dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
        !           455:                        buf, (unsigned)(cp2 - buf), NULL, 0);
        !           456: 
        !           457:        n = dst_verify_data(SIG_MODE_FINAL, state->key, &state->ctx, NULL, 0,
        !           458:                            sigstart, sigfieldlen);
        !           459:        if (n < 0)
        !           460:                return ISC_R_BADSIG;
        !           461: 
        !           462:        if (sigfieldlen > sizeof(state->sig))
        !           463:                return ISC_R_BADSIG;
        !           464: 
        !           465:        if (sigfieldlen > sizeof(state->sig))
        !           466:                return ISC_R_NOSPACE;
        !           467: 
        !           468:        memcpy(state->sig, sigstart, sigfieldlen);
        !           469:        state->siglen = sigfieldlen;
        !           470: 
        !           471:        /* Verify the time. */
        !           472:        if (abs(timesigned - time(NULL)) > fudge)
        !           473:                return ISC_R_BADTIME;
        !           474: 
        !           475:        *msglen = recstart - msg;
        !           476: 
        !           477:        if (error != NOERROR)
        !           478:                return ns_rcode_to_isc (error);
        !           479: 
        !           480:        return ISC_R_SUCCESS;
        !           481: }
        !           482: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>