Annotation of embedaddon/dhcp/minires/ns_verify.c, revision 1.1.1.1.2.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
1.1.1.1.2.1! misho      25: static const char rcsid[] = "$Id: ns_verify.c,v 1.1.1.1 2012/10/09 09:06:54 misho Exp $";
1.1       misho      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();
1.1.1.1.2.1! misho     157:        if (msg == NULL || msglen == NULL)
1.1       misho     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);
1.1.1.1.2.1! misho     170:        if (n)
1.1       misho     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);
1.1.1.1.2.1! misho     189:        if (n)
1.1       misho     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: 
1.1.1.1   misho     213:         /* Let's silence set-but-unused compilation warning */
                    214:         IGNORE_UNUSED(id);
                    215: 
1.1       misho     216:        /* Parse the other data. */
                    217:        BOUNDS_CHECK(cp, INT16SZ);
                    218:        GETSHORT(otherfieldlen, cp);
                    219:        BOUNDS_CHECK(cp, otherfieldlen);
                    220:        otherstart = cp;
                    221:        cp += otherfieldlen;
                    222: 
                    223:        if (cp != eom)
                    224:                return ISC_R_FORMERR;
                    225: 
                    226:        /* Verify that the key used is OK. */
                    227:        if (key != NULL) {
                    228:                if (key->dk_alg != KEY_HMAC_MD5)
                    229:                        return ISC_R_INVALIDKEY;
                    230:                if (error != ns_r_badsig && error != ns_r_badkey) {
                    231:                        if (ns_samename(key->dk_key_name, name) != 1)
                    232:                                return ISC_R_INVALIDKEY;
                    233:                }
                    234:        }
                    235: 
                    236:        hp->arcount = htons(ntohs(hp->arcount) - 1);
                    237: 
                    238:        /*
                    239:         * Do the verification.
                    240:         */
                    241: 
                    242:        if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) {
                    243:                void *ctx;
                    244:                u_char buf[MAXDNAME];
                    245: 
                    246:                /* Digest the query signature, if this is a response. */
                    247:                dst_verify_data(SIG_MODE_INIT, key, &ctx, NULL, 0, NULL, 0);
                    248:                if (querysiglen > 0 && querysig != NULL) {
                    249:                        u_int16_t len_n = htons(querysiglen);
                    250:                        dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
                    251:                                        (u_char *)&len_n, INT16SZ, NULL, 0);
                    252:                        dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
                    253:                                        querysig, querysiglen, NULL, 0);
                    254:                }
                    255:                
                    256:                /* Digest the message. */
                    257:                dst_verify_data(SIG_MODE_UPDATE, key, &ctx, msg,
                    258:                                (unsigned)(recstart - msg), NULL, 0);
                    259: 
                    260:                /* Digest the key name. */
                    261:                n = ns_name_ntol(recstart, buf, sizeof(buf));
                    262:                dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
                    263: 
                    264:                /* Digest the class and TTL. */
                    265:                dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
                    266:                                recstart + dn_skipname(recstart, eom) + INT16SZ,
                    267:                                INT16SZ + INT32SZ, NULL, 0);
                    268: 
                    269:                /* Digest the algorithm. */
                    270:                n = ns_name_ntol(rdatastart, buf, sizeof(buf));
                    271:                dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
                    272: 
                    273:                /* Digest the time signed and fudge. */
                    274:                dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
                    275:                                rdatastart + dn_skipname(rdatastart, eom),
                    276:                                INT16SZ + INT32SZ + INT16SZ, NULL, 0);
                    277: 
                    278:                /* Digest the error and other data. */
                    279:                dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
                    280:                                otherstart - INT16SZ - INT16SZ,
                    281:                                (unsigned)otherfieldlen + INT16SZ + INT16SZ,
                    282:                                NULL, 0);
                    283: 
                    284:                n = dst_verify_data(SIG_MODE_FINAL, key, &ctx, NULL, 0,
                    285:                                    sigstart, sigfieldlen);
                    286: 
1.1.1.1.2.1! misho     287:                if (n)
1.1       misho     288:                        return ISC_R_BADSIG;
                    289: 
                    290:                if (sig != NULL && siglen != NULL) {
                    291:                        if (*siglen < sigfieldlen)
                    292:                                return ISC_R_NOSPACE;
                    293:                        memcpy(sig, sigstart, sigfieldlen);
                    294:                        *siglen = sigfieldlen;
                    295:                }
                    296:        } else {
                    297:                if (sigfieldlen > 0)
                    298:                        return ISC_R_FORMERR;
                    299:                if (sig != NULL && siglen != NULL)
                    300:                        *siglen = 0;
                    301:        }
                    302: 
                    303:        /* Reset the counter, since we still need to check for badtime. */
                    304:        hp->arcount = htons(ntohs(hp->arcount) + 1);
                    305: 
                    306:        /* Verify the time. */
                    307:        if (abs((*timesigned) - time(NULL)) > fudge)
                    308:                return ISC_R_BADTIME;
                    309: 
                    310:        if (nostrip == 0) {
                    311:                *msglen = recstart - msg;
                    312:                hp->arcount = htons(ntohs(hp->arcount) - 1);
                    313:        }
                    314: 
                    315:        if (error != NOERROR)
                    316:                return ns_rcode_to_isc (error);
                    317: 
                    318:        return ISC_R_SUCCESS;
                    319: }
                    320: 
                    321: #if 0
                    322: isc_result_t
                    323: ns_verify_tcp_init(void *k, const u_char *querysig, unsigned querysiglen,
                    324:                   ns_tcp_tsig_state *state)
                    325: {
                    326:        dst_init();
                    327:        if (state == NULL || k == NULL || querysig == NULL || querysiglen < 0)
                    328:                return ISC_R_INVALIDARG;
                    329:        state->counter = -1;
                    330:        state->key = k;
                    331:        if (state->key->dk_alg != KEY_HMAC_MD5)
                    332:                return ISC_R_BADKEY;
                    333:        if (querysiglen > sizeof(state->sig))
                    334:                return ISC_R_NOSPACE;
                    335:        memcpy(state->sig, querysig, querysiglen);
                    336:        state->siglen = querysiglen;
                    337:        return ISC_R_SUCCESS;
                    338: }
                    339: 
                    340: isc_result_t
                    341: ns_verify_tcp(u_char *msg, unsigned *msglen, ns_tcp_tsig_state *state,
                    342:              int required)
                    343: {
                    344:        HEADER *hp = (HEADER *)msg;
                    345:        u_char *recstart, *rdatastart, *sigstart;
                    346:        unsigned sigfieldlen, otherfieldlen;
                    347:        u_char *cp, *eom = msg + *msglen, *cp2;
                    348:        char name[MAXDNAME], alg[MAXDNAME];
                    349:        u_char buf[MAXDNAME];
                    350:        int n, type, length, fudge, id, error;
                    351:        time_t timesigned;
                    352: 
                    353:        if (msg == NULL || msglen == NULL || state == NULL)
                    354:                return ISC_R_INVALIDARG;
                    355: 
                    356:        state->counter++;
                    357:        if (state->counter == 0)
                    358:                return (ns_verify(msg, msglen, state->key,
                    359:                                  state->sig, state->siglen,
                    360:                                  state->sig, &state->siglen, &timesigned, 0));
                    361: 
                    362:        if (state->siglen > 0) {
                    363:                u_int16_t siglen_n = htons(state->siglen);
                    364: 
                    365:                dst_verify_data(SIG_MODE_INIT, state->key, &state->ctx,
                    366:                                NULL, 0, NULL, 0);
                    367:                dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
                    368:                                (u_char *)&siglen_n, INT16SZ, NULL, 0);
                    369:                dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
                    370:                                state->sig, state->siglen, NULL, 0);
                    371:                state->siglen = 0;
                    372:        }
                    373: 
                    374:        cp = recstart = ns_find_tsig(msg, eom);
                    375: 
                    376:        if (recstart == NULL) {
                    377:                if (required)
                    378:                        return ISC_R_NO_TSIG;
                    379:                dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
                    380:                                msg, *msglen, NULL, 0);
                    381:                return ISC_R_SUCCESS;
                    382:        }
                    383: 
                    384:        hp->arcount = htons(ntohs(hp->arcount) - 1);
                    385:        dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
                    386:                        msg, (unsigned)(recstart - msg), NULL, 0);
                    387:        
                    388:        /* Read the key name. */
                    389:        n = dn_expand(msg, eom, cp, name, MAXDNAME);
                    390:        if (n < 0)
                    391:                return ISC_R_FORMERR;
                    392:        cp += n;
                    393: 
                    394:        /* Read the type. */
                    395:        BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ);
                    396:        GETSHORT(type, cp);
                    397:        if (type != ns_t_tsig)
                    398:                return ISC_R_NO_TSIG;
                    399: 
                    400:        /* Skip the class and TTL, save the length. */
                    401:        cp += INT16SZ + INT32SZ;
                    402:        GETSHORT(length, cp);
                    403:        if (eom - cp != length)
                    404:                return ISC_R_FORMERR;
                    405: 
                    406:        /* Read the algorithm name. */
                    407:        rdatastart = cp;
                    408:        n = dn_expand(msg, eom, cp, alg, MAXDNAME);
                    409:        if (n < 0)
                    410:                return ISC_R_FORMERR;
                    411:        if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1)
                    412:                return ISC_R_BADKEY;
                    413:        cp += n;
                    414: 
                    415:        /* Verify that the key used is OK. */
                    416:        if ((ns_samename(state->key->dk_key_name, name) != 1 ||
                    417:             state->key->dk_alg != KEY_HMAC_MD5))
                    418:                return ISC_R_BADKEY;
                    419: 
                    420:        /* Read the time signed and fudge. */
                    421:        BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ);
                    422:        cp += INT16SZ;
                    423:        GETLONG(timesigned, cp);
                    424:        GETSHORT(fudge, cp);
                    425: 
                    426:        /* Read the signature. */
                    427:        BOUNDS_CHECK(cp, INT16SZ);
                    428:        GETSHORT(sigfieldlen, cp);
                    429:        BOUNDS_CHECK(cp, sigfieldlen);
                    430:        sigstart = cp;
                    431:        cp += sigfieldlen;
                    432: 
                    433:        /* Read the original id and error. */
                    434:        BOUNDS_CHECK(cp, 2*INT16SZ);
                    435:        GETSHORT(id, cp);
                    436:        GETSHORT(error, cp);
                    437: 
                    438:        /* Parse the other data. */
                    439:        BOUNDS_CHECK(cp, INT16SZ);
                    440:        GETSHORT(otherfieldlen, cp);
                    441:        BOUNDS_CHECK(cp, otherfieldlen);
                    442:        cp += otherfieldlen;
                    443: 
                    444:        if (cp != eom)
                    445:                return ISC_R_FORMERR;
                    446: 
                    447:        /*
                    448:         * Do the verification.
                    449:         */
                    450: 
                    451:        /* Digest the time signed and fudge. */
                    452:        cp2 = buf;
                    453:        PUTSHORT(0, cp2);       /* Top 16 bits of time. */
                    454:        PUTLONG(timesigned, cp2);
                    455:        PUTSHORT(NS_TSIG_FUDGE, cp2);
                    456: 
                    457:        dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
                    458:                        buf, (unsigned)(cp2 - buf), NULL, 0);
                    459: 
                    460:        n = dst_verify_data(SIG_MODE_FINAL, state->key, &state->ctx, NULL, 0,
                    461:                            sigstart, sigfieldlen);
                    462:        if (n < 0)
                    463:                return ISC_R_BADSIG;
                    464: 
                    465:        if (sigfieldlen > sizeof(state->sig))
                    466:                return ISC_R_BADSIG;
                    467: 
                    468:        if (sigfieldlen > sizeof(state->sig))
                    469:                return ISC_R_NOSPACE;
                    470: 
                    471:        memcpy(state->sig, sigstart, sigfieldlen);
                    472:        state->siglen = sigfieldlen;
                    473: 
                    474:        /* Verify the time. */
                    475:        if (abs(timesigned - time(NULL)) > fudge)
                    476:                return ISC_R_BADTIME;
                    477: 
                    478:        *msglen = recstart - msg;
                    479: 
                    480:        if (error != NOERROR)
                    481:                return ns_rcode_to_isc (error);
                    482: 
                    483:        return ISC_R_SUCCESS;
                    484: }
                    485: #endif

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