File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dhcp / minires / ns_verify.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Oct 9 09:06:54 2012 UTC (12 years, 6 months ago) by misho
Branches: dhcp, MAIN
CVS tags: v4_1_R7p0, v4_1_R7, v4_1_R4, HEAD
dhcp 4.1 r7

    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.1.1.1 2012/10/09 09:06:54 misho 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:         /* Let's silence set-but-unused compilation warning */
  214:         IGNORE_UNUSED(id);
  215: 
  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: 
  287: 		if (n < 0)
  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>