xref: /onnv-gate/usr/src/lib/libresolv2/common/nameser/ns_verify.c (revision 11038:74b12212b8a2)
10Sstevel@tonic-gate /*
2*11038SRao.Shoaib@Sun.COM  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
30Sstevel@tonic-gate  * Copyright (c) 1999 by Internet Software Consortium, Inc.
40Sstevel@tonic-gate  *
50Sstevel@tonic-gate  * Permission to use, copy, modify, and distribute this software for any
60Sstevel@tonic-gate  * purpose with or without fee is hereby granted, provided that the above
70Sstevel@tonic-gate  * copyright notice and this permission notice appear in all copies.
80Sstevel@tonic-gate  *
9*11038SRao.Shoaib@Sun.COM  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10*11038SRao.Shoaib@Sun.COM  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11*11038SRao.Shoaib@Sun.COM  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
12*11038SRao.Shoaib@Sun.COM  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13*11038SRao.Shoaib@Sun.COM  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14*11038SRao.Shoaib@Sun.COM  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15*11038SRao.Shoaib@Sun.COM  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
160Sstevel@tonic-gate  */
170Sstevel@tonic-gate 
180Sstevel@tonic-gate #ifndef lint
19*11038SRao.Shoaib@Sun.COM static const char rcsid[] = "$Id: ns_verify.c,v 1.5 2006/03/09 23:57:56 marka Exp $";
200Sstevel@tonic-gate #endif
210Sstevel@tonic-gate 
220Sstevel@tonic-gate /* Import. */
230Sstevel@tonic-gate 
240Sstevel@tonic-gate #include "port_before.h"
250Sstevel@tonic-gate #include "fd_setsize.h"
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #include <sys/types.h>
280Sstevel@tonic-gate #include <sys/param.h>
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #include <netinet/in.h>
310Sstevel@tonic-gate #include <arpa/nameser.h>
320Sstevel@tonic-gate #include <arpa/inet.h>
330Sstevel@tonic-gate 
340Sstevel@tonic-gate #include <errno.h>
350Sstevel@tonic-gate #include <netdb.h>
360Sstevel@tonic-gate #include <resolv.h>
370Sstevel@tonic-gate #include <stdio.h>
380Sstevel@tonic-gate #include <stdlib.h>
390Sstevel@tonic-gate #include <string.h>
400Sstevel@tonic-gate #include <time.h>
410Sstevel@tonic-gate #include <unistd.h>
420Sstevel@tonic-gate 
430Sstevel@tonic-gate #include <isc/dst.h>
440Sstevel@tonic-gate 
450Sstevel@tonic-gate #include "port_after.h"
460Sstevel@tonic-gate 
470Sstevel@tonic-gate /* Private. */
480Sstevel@tonic-gate 
490Sstevel@tonic-gate #define BOUNDS_CHECK(ptr, count) \
500Sstevel@tonic-gate 	do { \
510Sstevel@tonic-gate 		if ((ptr) + (count) > eom) { \
520Sstevel@tonic-gate 			return (NS_TSIG_ERROR_FORMERR); \
530Sstevel@tonic-gate 		} \
540Sstevel@tonic-gate 	} while (0)
550Sstevel@tonic-gate 
560Sstevel@tonic-gate /* Public. */
570Sstevel@tonic-gate 
580Sstevel@tonic-gate u_char *
ns_find_tsig(u_char * msg,u_char * eom)590Sstevel@tonic-gate ns_find_tsig(u_char *msg, u_char *eom) {
600Sstevel@tonic-gate 	HEADER *hp = (HEADER *)msg;
610Sstevel@tonic-gate 	int n, type;
620Sstevel@tonic-gate 	u_char *cp = msg, *start;
630Sstevel@tonic-gate 
640Sstevel@tonic-gate 	if (msg == NULL || eom == NULL || msg > eom)
650Sstevel@tonic-gate 		return (NULL);
660Sstevel@tonic-gate 
670Sstevel@tonic-gate 	if (cp + HFIXEDSZ >= eom)
680Sstevel@tonic-gate 		return (NULL);
690Sstevel@tonic-gate 
700Sstevel@tonic-gate 	if (hp->arcount == 0)
710Sstevel@tonic-gate 		return (NULL);
720Sstevel@tonic-gate 
730Sstevel@tonic-gate 	cp += HFIXEDSZ;
740Sstevel@tonic-gate 
750Sstevel@tonic-gate 	n = ns_skiprr(cp, eom, ns_s_qd, ntohs(hp->qdcount));
760Sstevel@tonic-gate 	if (n < 0)
770Sstevel@tonic-gate 		return (NULL);
780Sstevel@tonic-gate 	cp += n;
790Sstevel@tonic-gate 
800Sstevel@tonic-gate 	n = ns_skiprr(cp, eom, ns_s_an, ntohs(hp->ancount));
810Sstevel@tonic-gate 	if (n < 0)
820Sstevel@tonic-gate 		return (NULL);
830Sstevel@tonic-gate 	cp += n;
840Sstevel@tonic-gate 
850Sstevel@tonic-gate 	n = ns_skiprr(cp, eom, ns_s_ns, ntohs(hp->nscount));
860Sstevel@tonic-gate 	if (n < 0)
870Sstevel@tonic-gate 		return (NULL);
880Sstevel@tonic-gate 	cp += n;
890Sstevel@tonic-gate 
900Sstevel@tonic-gate 	n = ns_skiprr(cp, eom, ns_s_ar, ntohs(hp->arcount) - 1);
910Sstevel@tonic-gate 	if (n < 0)
920Sstevel@tonic-gate 		return (NULL);
930Sstevel@tonic-gate 	cp += n;
940Sstevel@tonic-gate 
950Sstevel@tonic-gate 	start = cp;
960Sstevel@tonic-gate 	n = dn_skipname(cp, eom);
970Sstevel@tonic-gate 	if (n < 0)
980Sstevel@tonic-gate 		return (NULL);
990Sstevel@tonic-gate 	cp += n;
1000Sstevel@tonic-gate 	if (cp + INT16SZ >= eom)
1010Sstevel@tonic-gate 		return (NULL);
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate 	GETSHORT(type, cp);
1040Sstevel@tonic-gate 	if (type != ns_t_tsig)
1050Sstevel@tonic-gate 		return (NULL);
1060Sstevel@tonic-gate 	return (start);
1070Sstevel@tonic-gate }
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate /* ns_verify
110*11038SRao.Shoaib@Sun.COM  *
1110Sstevel@tonic-gate  * Parameters:
112*11038SRao.Shoaib@Sun.COM  *\li	statp		res stuff
113*11038SRao.Shoaib@Sun.COM  *\li	msg		received message
114*11038SRao.Shoaib@Sun.COM  *\li	msglen		length of message
115*11038SRao.Shoaib@Sun.COM  *\li	key		tsig key used for verifying.
116*11038SRao.Shoaib@Sun.COM  *\li	querysig	(response), the signature in the query
117*11038SRao.Shoaib@Sun.COM  *\li	querysiglen	(response), the length of the signature in the query
118*11038SRao.Shoaib@Sun.COM  *\li	sig		(query), a buffer to hold the signature
119*11038SRao.Shoaib@Sun.COM  *\li	siglen		(query), input - length of signature buffer
1200Sstevel@tonic-gate  *				 output - length of signature
1210Sstevel@tonic-gate  *
1220Sstevel@tonic-gate  * Errors:
123*11038SRao.Shoaib@Sun.COM  *\li	- bad input (-1)
124*11038SRao.Shoaib@Sun.COM  *\li	- invalid dns message (NS_TSIG_ERROR_FORMERR)
125*11038SRao.Shoaib@Sun.COM  *\li	- TSIG is not present (NS_TSIG_ERROR_NO_TSIG)
126*11038SRao.Shoaib@Sun.COM  *\li	- key doesn't match (-ns_r_badkey)
127*11038SRao.Shoaib@Sun.COM  *\li	- TSIG verification fails with BADKEY (-ns_r_badkey)
128*11038SRao.Shoaib@Sun.COM  *\li	- TSIG verification fails with BADSIG (-ns_r_badsig)
129*11038SRao.Shoaib@Sun.COM  *\li	- TSIG verification fails with BADTIME (-ns_r_badtime)
130*11038SRao.Shoaib@Sun.COM  *\li	- TSIG verification succeeds, error set to BAKEY (ns_r_badkey)
131*11038SRao.Shoaib@Sun.COM  *\li	- TSIG verification succeeds, error set to BADSIG (ns_r_badsig)
132*11038SRao.Shoaib@Sun.COM  *\li	- TSIG verification succeeds, error set to BADTIME (ns_r_badtime)
1330Sstevel@tonic-gate  */
1340Sstevel@tonic-gate int
ns_verify(u_char * msg,int * msglen,void * k,const u_char * querysig,int querysiglen,u_char * sig,int * siglen,time_t * timesigned,int nostrip)1350Sstevel@tonic-gate ns_verify(u_char *msg, int *msglen, void *k,
1360Sstevel@tonic-gate 	  const u_char *querysig, int querysiglen, u_char *sig, int *siglen,
1370Sstevel@tonic-gate 	  time_t *timesigned, int nostrip)
1380Sstevel@tonic-gate {
1390Sstevel@tonic-gate 	HEADER *hp = (HEADER *)msg;
1400Sstevel@tonic-gate 	DST_KEY *key = (DST_KEY *)k;
1410Sstevel@tonic-gate 	u_char *cp = msg, *eom;
1420Sstevel@tonic-gate 	char name[MAXDNAME], alg[MAXDNAME];
1430Sstevel@tonic-gate 	u_char *recstart, *rdatastart;
1440Sstevel@tonic-gate 	u_char *sigstart, *otherstart;
1450Sstevel@tonic-gate 	int n;
1460Sstevel@tonic-gate 	int error;
1470Sstevel@tonic-gate 	u_int16_t type, length;
148*11038SRao.Shoaib@Sun.COM 	u_int16_t fudge, sigfieldlen, otherfieldlen;
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate 	dst_init();
1510Sstevel@tonic-gate 	if (msg == NULL || msglen == NULL || *msglen < 0)
1520Sstevel@tonic-gate 		return (-1);
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate 	eom = msg + *msglen;
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate 	recstart = ns_find_tsig(msg, eom);
1570Sstevel@tonic-gate 	if (recstart == NULL)
1580Sstevel@tonic-gate 		return (NS_TSIG_ERROR_NO_TSIG);
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 	cp = recstart;
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate 	/* Read the key name. */
1630Sstevel@tonic-gate 	n = dn_expand(msg, eom, cp, name, MAXDNAME);
1640Sstevel@tonic-gate 	if (n < 0)
1650Sstevel@tonic-gate 		return (NS_TSIG_ERROR_FORMERR);
1660Sstevel@tonic-gate 	cp += n;
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate 	/* Read the type. */
1690Sstevel@tonic-gate 	BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ);
1700Sstevel@tonic-gate 	GETSHORT(type, cp);
1710Sstevel@tonic-gate 	if (type != ns_t_tsig)
1720Sstevel@tonic-gate 		return (NS_TSIG_ERROR_NO_TSIG);
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate 	/* Skip the class and TTL, save the length. */
1750Sstevel@tonic-gate 	cp += INT16SZ + INT32SZ;
1760Sstevel@tonic-gate 	GETSHORT(length, cp);
1770Sstevel@tonic-gate 	if (eom - cp != length)
1780Sstevel@tonic-gate 		return (NS_TSIG_ERROR_FORMERR);
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 	/* Read the algorithm name. */
1810Sstevel@tonic-gate 	rdatastart = cp;
1820Sstevel@tonic-gate 	n = dn_expand(msg, eom, cp, alg, MAXDNAME);
1830Sstevel@tonic-gate 	if (n < 0)
1840Sstevel@tonic-gate 		return (NS_TSIG_ERROR_FORMERR);
1850Sstevel@tonic-gate 	if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1)
1860Sstevel@tonic-gate 		return (-ns_r_badkey);
1870Sstevel@tonic-gate 	cp += n;
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 	/* Read the time signed and fudge. */
1900Sstevel@tonic-gate 	BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ);
1910Sstevel@tonic-gate 	cp += INT16SZ;
1920Sstevel@tonic-gate 	GETLONG((*timesigned), cp);
1930Sstevel@tonic-gate 	GETSHORT(fudge, cp);
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 	/* Read the signature. */
1960Sstevel@tonic-gate 	BOUNDS_CHECK(cp, INT16SZ);
1970Sstevel@tonic-gate 	GETSHORT(sigfieldlen, cp);
1980Sstevel@tonic-gate 	BOUNDS_CHECK(cp, sigfieldlen);
1990Sstevel@tonic-gate 	sigstart = cp;
2000Sstevel@tonic-gate 	cp += sigfieldlen;
2010Sstevel@tonic-gate 
202*11038SRao.Shoaib@Sun.COM 	/* Skip id and read error. */
2030Sstevel@tonic-gate 	BOUNDS_CHECK(cp, 2*INT16SZ);
204*11038SRao.Shoaib@Sun.COM 	cp += INT16SZ;
2050Sstevel@tonic-gate 	GETSHORT(error, cp);
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate 	/* Parse the other data. */
2080Sstevel@tonic-gate 	BOUNDS_CHECK(cp, INT16SZ);
2090Sstevel@tonic-gate 	GETSHORT(otherfieldlen, cp);
2100Sstevel@tonic-gate 	BOUNDS_CHECK(cp, otherfieldlen);
2110Sstevel@tonic-gate 	otherstart = cp;
2120Sstevel@tonic-gate 	cp += otherfieldlen;
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate 	if (cp != eom)
2150Sstevel@tonic-gate 		return (NS_TSIG_ERROR_FORMERR);
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 	/* Verify that the key used is OK. */
2180Sstevel@tonic-gate 	if (key != NULL) {
2190Sstevel@tonic-gate 		if (key->dk_alg != KEY_HMAC_MD5)
2200Sstevel@tonic-gate 			return (-ns_r_badkey);
2210Sstevel@tonic-gate 		if (error != ns_r_badsig && error != ns_r_badkey) {
2220Sstevel@tonic-gate 			if (ns_samename(key->dk_key_name, name) != 1)
2230Sstevel@tonic-gate 				return (-ns_r_badkey);
2240Sstevel@tonic-gate 		}
2250Sstevel@tonic-gate 	}
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 	hp->arcount = htons(ntohs(hp->arcount) - 1);
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate 	/*
2300Sstevel@tonic-gate 	 * Do the verification.
2310Sstevel@tonic-gate 	 */
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 	if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) {
2340Sstevel@tonic-gate 		void *ctx;
2350Sstevel@tonic-gate 		u_char buf[MAXDNAME];
2360Sstevel@tonic-gate 		u_char buf2[MAXDNAME];
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 		/* Digest the query signature, if this is a response. */
2390Sstevel@tonic-gate 		dst_verify_data(SIG_MODE_INIT, key, &ctx, NULL, 0, NULL, 0);
2400Sstevel@tonic-gate 		if (querysiglen > 0 && querysig != NULL) {
2410Sstevel@tonic-gate 			u_int16_t len_n = htons(querysiglen);
2420Sstevel@tonic-gate 			dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
2430Sstevel@tonic-gate 					(u_char *)&len_n, INT16SZ, NULL, 0);
2440Sstevel@tonic-gate 			dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
2450Sstevel@tonic-gate 					querysig, querysiglen, NULL, 0);
2460Sstevel@tonic-gate 		}
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate  		/* Digest the message. */
2490Sstevel@tonic-gate 		dst_verify_data(SIG_MODE_UPDATE, key, &ctx, msg, recstart - msg,
2500Sstevel@tonic-gate 				NULL, 0);
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 		/* Digest the key name. */
2530Sstevel@tonic-gate 		n = ns_name_pton(name, buf2, sizeof(buf2));
2540Sstevel@tonic-gate 		if (n < 0)
2550Sstevel@tonic-gate 			return (-1);
2560Sstevel@tonic-gate 		n = ns_name_ntol(buf2, buf, sizeof(buf));
2570Sstevel@tonic-gate 		if (n < 0)
2580Sstevel@tonic-gate 			return (-1);
2590Sstevel@tonic-gate 		dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 		/* Digest the class and TTL. */
2620Sstevel@tonic-gate 		dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
2630Sstevel@tonic-gate 				recstart + dn_skipname(recstart, eom) + INT16SZ,
2640Sstevel@tonic-gate 				INT16SZ + INT32SZ, NULL, 0);
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 		/* Digest the algorithm. */
2670Sstevel@tonic-gate 		n = ns_name_pton(alg, buf2, sizeof(buf2));
2680Sstevel@tonic-gate 		if (n < 0)
2690Sstevel@tonic-gate 			return (-1);
2700Sstevel@tonic-gate 		n = ns_name_ntol(buf2, buf, sizeof(buf));
2710Sstevel@tonic-gate 		if (n < 0)
2720Sstevel@tonic-gate 			return (-1);
2730Sstevel@tonic-gate 		dst_verify_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 		/* Digest the time signed and fudge. */
2760Sstevel@tonic-gate 		dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
2770Sstevel@tonic-gate 				rdatastart + dn_skipname(rdatastart, eom),
2780Sstevel@tonic-gate 				INT16SZ + INT32SZ + INT16SZ, NULL, 0);
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 		/* Digest the error and other data. */
2810Sstevel@tonic-gate 		dst_verify_data(SIG_MODE_UPDATE, key, &ctx,
2820Sstevel@tonic-gate 				otherstart - INT16SZ - INT16SZ,
2830Sstevel@tonic-gate 				otherfieldlen + INT16SZ + INT16SZ, NULL, 0);
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 		n = dst_verify_data(SIG_MODE_FINAL, key, &ctx, NULL, 0,
2860Sstevel@tonic-gate 				    sigstart, sigfieldlen);
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 		if (n < 0)
2890Sstevel@tonic-gate 			return (-ns_r_badsig);
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 		if (sig != NULL && siglen != NULL) {
2920Sstevel@tonic-gate 			if (*siglen < sigfieldlen)
2930Sstevel@tonic-gate 				return (NS_TSIG_ERROR_NO_SPACE);
2940Sstevel@tonic-gate 			memcpy(sig, sigstart, sigfieldlen);
2950Sstevel@tonic-gate 			*siglen = sigfieldlen;
2960Sstevel@tonic-gate 		}
2970Sstevel@tonic-gate 	} else {
2980Sstevel@tonic-gate 		if (sigfieldlen > 0)
2990Sstevel@tonic-gate 			return (NS_TSIG_ERROR_FORMERR);
3000Sstevel@tonic-gate 		if (sig != NULL && siglen != NULL)
3010Sstevel@tonic-gate 			*siglen = 0;
3020Sstevel@tonic-gate 	}
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	/* Reset the counter, since we still need to check for badtime. */
3050Sstevel@tonic-gate 	hp->arcount = htons(ntohs(hp->arcount) + 1);
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 	/* Verify the time. */
3080Sstevel@tonic-gate 	if (abs((*timesigned) - time(NULL)) > fudge)
3090Sstevel@tonic-gate 		return (-ns_r_badtime);
3100Sstevel@tonic-gate 
3110Sstevel@tonic-gate 	if (nostrip == 0) {
3120Sstevel@tonic-gate 		*msglen = recstart - msg;
3130Sstevel@tonic-gate 		hp->arcount = htons(ntohs(hp->arcount) - 1);
3140Sstevel@tonic-gate 	}
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 	if (error != NOERROR)
3170Sstevel@tonic-gate 		return (error);
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 	return (0);
3200Sstevel@tonic-gate }
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate int
ns_verify_tcp_init(void * k,const u_char * querysig,int querysiglen,ns_tcp_tsig_state * state)3230Sstevel@tonic-gate ns_verify_tcp_init(void *k, const u_char *querysig, int querysiglen,
3240Sstevel@tonic-gate 		   ns_tcp_tsig_state *state)
3250Sstevel@tonic-gate {
3260Sstevel@tonic-gate 	dst_init();
3270Sstevel@tonic-gate 	if (state == NULL || k == NULL || querysig == NULL || querysiglen < 0)
3280Sstevel@tonic-gate 		return (-1);
3290Sstevel@tonic-gate 	state->counter = -1;
3300Sstevel@tonic-gate 	state->key = k;
3310Sstevel@tonic-gate 	if (state->key->dk_alg != KEY_HMAC_MD5)
3320Sstevel@tonic-gate 		return (-ns_r_badkey);
3330Sstevel@tonic-gate 	if (querysiglen > (int)sizeof(state->sig))
3340Sstevel@tonic-gate 		return (-1);
3350Sstevel@tonic-gate 	memcpy(state->sig, querysig, querysiglen);
3360Sstevel@tonic-gate 	state->siglen = querysiglen;
3370Sstevel@tonic-gate 	return (0);
3380Sstevel@tonic-gate }
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate int
ns_verify_tcp(u_char * msg,int * msglen,ns_tcp_tsig_state * state,int required)3410Sstevel@tonic-gate ns_verify_tcp(u_char *msg, int *msglen, ns_tcp_tsig_state *state,
3420Sstevel@tonic-gate 	      int required)
3430Sstevel@tonic-gate {
3440Sstevel@tonic-gate 	HEADER *hp = (HEADER *)msg;
345*11038SRao.Shoaib@Sun.COM 	u_char *recstart, *sigstart;
3460Sstevel@tonic-gate 	unsigned int sigfieldlen, otherfieldlen;
347*11038SRao.Shoaib@Sun.COM 	u_char *cp, *eom, *cp2;
3480Sstevel@tonic-gate 	char name[MAXDNAME], alg[MAXDNAME];
3490Sstevel@tonic-gate 	u_char buf[MAXDNAME];
350*11038SRao.Shoaib@Sun.COM 	int n, type, length, fudge, error;
3510Sstevel@tonic-gate 	time_t timesigned;
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 	if (msg == NULL || msglen == NULL || state == NULL)
3540Sstevel@tonic-gate 		return (-1);
3550Sstevel@tonic-gate 
356*11038SRao.Shoaib@Sun.COM 	eom = msg + *msglen;
357*11038SRao.Shoaib@Sun.COM 
3580Sstevel@tonic-gate 	state->counter++;
3590Sstevel@tonic-gate 	if (state->counter == 0)
3600Sstevel@tonic-gate 		return (ns_verify(msg, msglen, state->key,
3610Sstevel@tonic-gate 				  state->sig, state->siglen,
3620Sstevel@tonic-gate 				  state->sig, &state->siglen, &timesigned, 0));
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 	if (state->siglen > 0) {
3650Sstevel@tonic-gate 		u_int16_t siglen_n = htons(state->siglen);
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 		dst_verify_data(SIG_MODE_INIT, state->key, &state->ctx,
3680Sstevel@tonic-gate 				NULL, 0, NULL, 0);
3690Sstevel@tonic-gate 		dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
3700Sstevel@tonic-gate 				(u_char *)&siglen_n, INT16SZ, NULL, 0);
3710Sstevel@tonic-gate 		dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
3720Sstevel@tonic-gate 				state->sig, state->siglen, NULL, 0);
3730Sstevel@tonic-gate 		state->siglen = 0;
3740Sstevel@tonic-gate 	}
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 	cp = recstart = ns_find_tsig(msg, eom);
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 	if (recstart == NULL) {
3790Sstevel@tonic-gate 		if (required)
3800Sstevel@tonic-gate 			return (NS_TSIG_ERROR_NO_TSIG);
3810Sstevel@tonic-gate 		dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
3820Sstevel@tonic-gate 				msg, *msglen, NULL, 0);
3830Sstevel@tonic-gate 		return (0);
3840Sstevel@tonic-gate 	}
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate 	hp->arcount = htons(ntohs(hp->arcount) - 1);
3870Sstevel@tonic-gate 	dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
3880Sstevel@tonic-gate 			msg, recstart - msg, NULL, 0);
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate 	/* Read the key name. */
3910Sstevel@tonic-gate 	n = dn_expand(msg, eom, cp, name, MAXDNAME);
3920Sstevel@tonic-gate 	if (n < 0)
3930Sstevel@tonic-gate 		return (NS_TSIG_ERROR_FORMERR);
3940Sstevel@tonic-gate 	cp += n;
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	/* Read the type. */
3970Sstevel@tonic-gate 	BOUNDS_CHECK(cp, 2*INT16SZ + INT32SZ + INT16SZ);
3980Sstevel@tonic-gate 	GETSHORT(type, cp);
3990Sstevel@tonic-gate 	if (type != ns_t_tsig)
4000Sstevel@tonic-gate 		return (NS_TSIG_ERROR_NO_TSIG);
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 	/* Skip the class and TTL, save the length. */
4030Sstevel@tonic-gate 	cp += INT16SZ + INT32SZ;
4040Sstevel@tonic-gate 	GETSHORT(length, cp);
4050Sstevel@tonic-gate 	if (eom - cp != length)
4060Sstevel@tonic-gate 		return (NS_TSIG_ERROR_FORMERR);
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	/* Read the algorithm name. */
4090Sstevel@tonic-gate 	n = dn_expand(msg, eom, cp, alg, MAXDNAME);
4100Sstevel@tonic-gate 	if (n < 0)
4110Sstevel@tonic-gate 		return (NS_TSIG_ERROR_FORMERR);
4120Sstevel@tonic-gate 	if (ns_samename(alg, NS_TSIG_ALG_HMAC_MD5) != 1)
4130Sstevel@tonic-gate 		return (-ns_r_badkey);
4140Sstevel@tonic-gate 	cp += n;
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 	/* Verify that the key used is OK. */
4170Sstevel@tonic-gate 	if ((ns_samename(state->key->dk_key_name, name) != 1 ||
4180Sstevel@tonic-gate 	     state->key->dk_alg != KEY_HMAC_MD5))
4190Sstevel@tonic-gate 		return (-ns_r_badkey);
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 	/* Read the time signed and fudge. */
4220Sstevel@tonic-gate 	BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ);
4230Sstevel@tonic-gate 	cp += INT16SZ;
4240Sstevel@tonic-gate 	GETLONG(timesigned, cp);
4250Sstevel@tonic-gate 	GETSHORT(fudge, cp);
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 	/* Read the signature. */
4280Sstevel@tonic-gate 	BOUNDS_CHECK(cp, INT16SZ);
4290Sstevel@tonic-gate 	GETSHORT(sigfieldlen, cp);
4300Sstevel@tonic-gate 	BOUNDS_CHECK(cp, sigfieldlen);
4310Sstevel@tonic-gate 	sigstart = cp;
4320Sstevel@tonic-gate 	cp += sigfieldlen;
4330Sstevel@tonic-gate 
434*11038SRao.Shoaib@Sun.COM 	/* Skip id and read error. */
4350Sstevel@tonic-gate 	BOUNDS_CHECK(cp, 2*INT16SZ);
436*11038SRao.Shoaib@Sun.COM 	cp += INT16SZ;
4370Sstevel@tonic-gate 	GETSHORT(error, cp);
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	/* Parse the other data. */
4400Sstevel@tonic-gate 	BOUNDS_CHECK(cp, INT16SZ);
4410Sstevel@tonic-gate 	GETSHORT(otherfieldlen, cp);
4420Sstevel@tonic-gate 	BOUNDS_CHECK(cp, otherfieldlen);
4430Sstevel@tonic-gate 	cp += otherfieldlen;
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 	if (cp != eom)
4460Sstevel@tonic-gate 		return (NS_TSIG_ERROR_FORMERR);
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate 	/*
4490Sstevel@tonic-gate 	 * Do the verification.
4500Sstevel@tonic-gate 	 */
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 	/* Digest the time signed and fudge. */
4530Sstevel@tonic-gate 	cp2 = buf;
454*11038SRao.Shoaib@Sun.COM 	PUTSHORT(0, cp2);       /*%< Top 16 bits of time. */
4550Sstevel@tonic-gate 	PUTLONG(timesigned, cp2);
4560Sstevel@tonic-gate 	PUTSHORT(NS_TSIG_FUDGE, cp2);
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	dst_verify_data(SIG_MODE_UPDATE, state->key, &state->ctx,
4590Sstevel@tonic-gate 			buf, cp2 - buf, NULL, 0);
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate 	n = dst_verify_data(SIG_MODE_FINAL, state->key, &state->ctx, NULL, 0,
4620Sstevel@tonic-gate 			    sigstart, sigfieldlen);
4630Sstevel@tonic-gate 	if (n < 0)
4640Sstevel@tonic-gate 		return (-ns_r_badsig);
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 	if (sigfieldlen > sizeof(state->sig))
4670Sstevel@tonic-gate 		return (NS_TSIG_ERROR_NO_SPACE);
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 	memcpy(state->sig, sigstart, sigfieldlen);
4700Sstevel@tonic-gate 	state->siglen = sigfieldlen;
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate 	/* Verify the time. */
4730Sstevel@tonic-gate 	if (abs(timesigned - time(NULL)) > fudge)
4740Sstevel@tonic-gate 		return (-ns_r_badtime);
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate 	*msglen = recstart - msg;
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 	if (error != NOERROR)
4790Sstevel@tonic-gate 		return (error);
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 	return (0);
4820Sstevel@tonic-gate }
483*11038SRao.Shoaib@Sun.COM 
484*11038SRao.Shoaib@Sun.COM /*! \file */
485