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, ×igned, 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>