[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.3

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

CVSweb <webmaster@jp.NetBSD.org>