[BACK]Return to ns_verify.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libresolv

Annotation of src/lib/libresolv/ns_verify.c, Revision 1.2

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

CVSweb <webmaster@jp.NetBSD.org>