17c478bd9Sstevel@tonic-gate /*
29525b14bSRao Shoaib  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
37c478bd9Sstevel@tonic-gate  * Copyright (c) 1999 by Internet Software Consortium, Inc.
47c478bd9Sstevel@tonic-gate  *
57c478bd9Sstevel@tonic-gate  * Permission to use, copy, modify, and distribute this software for any
67c478bd9Sstevel@tonic-gate  * purpose with or without fee is hereby granted, provided that the above
77c478bd9Sstevel@tonic-gate  * copyright notice and this permission notice appear in all copies.
87c478bd9Sstevel@tonic-gate  *
99525b14bSRao Shoaib  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
109525b14bSRao Shoaib  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
119525b14bSRao Shoaib  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
129525b14bSRao Shoaib  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
139525b14bSRao Shoaib  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
149525b14bSRao Shoaib  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
159525b14bSRao Shoaib  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
167c478bd9Sstevel@tonic-gate  */
177c478bd9Sstevel@tonic-gate 
187c478bd9Sstevel@tonic-gate #include "port_before.h"
197c478bd9Sstevel@tonic-gate #include "fd_setsize.h"
207c478bd9Sstevel@tonic-gate 
217c478bd9Sstevel@tonic-gate #include <sys/types.h>
227c478bd9Sstevel@tonic-gate #include <sys/param.h>
237c478bd9Sstevel@tonic-gate 
247c478bd9Sstevel@tonic-gate #include <netinet/in.h>
257c478bd9Sstevel@tonic-gate #include <arpa/nameser.h>
267c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate #include <errno.h>
297c478bd9Sstevel@tonic-gate #include <netdb.h>
307c478bd9Sstevel@tonic-gate #include <resolv.h>
317c478bd9Sstevel@tonic-gate #include <stdio.h>
327c478bd9Sstevel@tonic-gate #include <stdlib.h>
337c478bd9Sstevel@tonic-gate #include <string.h>
347c478bd9Sstevel@tonic-gate #include <time.h>
357c478bd9Sstevel@tonic-gate #include <unistd.h>
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #include <isc/dst.h>
387c478bd9Sstevel@tonic-gate #include <isc/assertions.h>
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate #include "port_after.h"
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate #define BOUNDS_CHECK(ptr, count) \
437c478bd9Sstevel@tonic-gate 	do { \
447c478bd9Sstevel@tonic-gate 		if ((ptr) + (count) > eob) { \
457c478bd9Sstevel@tonic-gate 			errno = EMSGSIZE; \
467c478bd9Sstevel@tonic-gate 			return(NS_TSIG_ERROR_NO_SPACE); \
477c478bd9Sstevel@tonic-gate 		} \
487c478bd9Sstevel@tonic-gate 	} while (0)
497c478bd9Sstevel@tonic-gate 
509525b14bSRao Shoaib /*%
519525b14bSRao Shoaib  *  ns_sign
529525b14bSRao Shoaib  *
537c478bd9Sstevel@tonic-gate  * Parameters:
549525b14bSRao Shoaib  *\li	msg		message to be sent
559525b14bSRao Shoaib  *\li	msglen		input - length of message
567c478bd9Sstevel@tonic-gate  *			output - length of signed message
579525b14bSRao Shoaib  *\li	msgsize		length of buffer containing message
589525b14bSRao Shoaib  *\li	error		value to put in the error field
599525b14bSRao Shoaib  *\li	key		tsig key used for signing
609525b14bSRao Shoaib  *\li	querysig	(response), the signature in the query
619525b14bSRao Shoaib  *\li	querysiglen	(response), the length of the signature in the query
629525b14bSRao Shoaib  *\li	sig		a buffer to hold the generated signature
639525b14bSRao Shoaib  *\li	siglen		input - length of signature buffer
647c478bd9Sstevel@tonic-gate  *			output - length of signature
657c478bd9Sstevel@tonic-gate  *
667c478bd9Sstevel@tonic-gate  * Errors:
679525b14bSRao Shoaib  *\li	- bad input data (-1)
689525b14bSRao Shoaib  *\li	- bad key / sign failed (-BADKEY)
699525b14bSRao Shoaib  *\li	- not enough space (NS_TSIG_ERROR_NO_SPACE)
707c478bd9Sstevel@tonic-gate  */
717c478bd9Sstevel@tonic-gate int
ns_sign(u_char * msg,int * msglen,int msgsize,int error,void * k,const u_char * querysig,int querysiglen,u_char * sig,int * siglen,time_t in_timesigned)727c478bd9Sstevel@tonic-gate ns_sign(u_char *msg, int *msglen, int msgsize, int error, void *k,
737c478bd9Sstevel@tonic-gate 	const u_char *querysig, int querysiglen, u_char *sig, int *siglen,
747c478bd9Sstevel@tonic-gate 	time_t in_timesigned)
757c478bd9Sstevel@tonic-gate {
767c478bd9Sstevel@tonic-gate 	return(ns_sign2(msg, msglen, msgsize, error, k,
777c478bd9Sstevel@tonic-gate 			querysig, querysiglen, sig, siglen,
787c478bd9Sstevel@tonic-gate 			in_timesigned, NULL, NULL));
797c478bd9Sstevel@tonic-gate }
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate int
ns_sign2(u_char * msg,int * msglen,int msgsize,int error,void * k,const u_char * querysig,int querysiglen,u_char * sig,int * siglen,time_t in_timesigned,u_char ** dnptrs,u_char ** lastdnptr)827c478bd9Sstevel@tonic-gate ns_sign2(u_char *msg, int *msglen, int msgsize, int error, void *k,
837c478bd9Sstevel@tonic-gate 	 const u_char *querysig, int querysiglen, u_char *sig, int *siglen,
847c478bd9Sstevel@tonic-gate 	 time_t in_timesigned, u_char **dnptrs, u_char **lastdnptr)
857c478bd9Sstevel@tonic-gate {
867c478bd9Sstevel@tonic-gate 	HEADER *hp = (HEADER *)msg;
877c478bd9Sstevel@tonic-gate 	DST_KEY *key = (DST_KEY *)k;
889525b14bSRao Shoaib 	u_char *cp, *eob;
897c478bd9Sstevel@tonic-gate 	u_char *lenp;
907c478bd9Sstevel@tonic-gate 	u_char *alg;
917c478bd9Sstevel@tonic-gate 	int n;
927c478bd9Sstevel@tonic-gate 	time_t timesigned;
939525b14bSRao Shoaib         u_char name[NS_MAXCDNAME];
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate 	dst_init();
967c478bd9Sstevel@tonic-gate 	if (msg == NULL || msglen == NULL || sig == NULL || siglen == NULL)
977c478bd9Sstevel@tonic-gate 		return (-1);
987c478bd9Sstevel@tonic-gate 
999525b14bSRao Shoaib 	cp = msg + *msglen;
1009525b14bSRao Shoaib 	eob = msg + msgsize;
1019525b14bSRao Shoaib 
1027c478bd9Sstevel@tonic-gate 	/* Name. */
1037c478bd9Sstevel@tonic-gate 	if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) {
1047c478bd9Sstevel@tonic-gate 		n = ns_name_pton(key->dk_key_name, name, sizeof name);
1057c478bd9Sstevel@tonic-gate 		if (n != -1)
1067c478bd9Sstevel@tonic-gate 			n = ns_name_pack(name, cp, eob - cp,
1079525b14bSRao Shoaib 					 (const u_char **)dnptrs,
1089525b14bSRao Shoaib 					 (const u_char **)lastdnptr);
1097c478bd9Sstevel@tonic-gate 
1107c478bd9Sstevel@tonic-gate 	} else {
1117c478bd9Sstevel@tonic-gate 		n = ns_name_pton("", name, sizeof name);
1127c478bd9Sstevel@tonic-gate 		if (n != -1)
1137c478bd9Sstevel@tonic-gate 			n = ns_name_pack(name, cp, eob - cp, NULL, NULL);
1147c478bd9Sstevel@tonic-gate 	}
1157c478bd9Sstevel@tonic-gate 	if (n < 0)
1167c478bd9Sstevel@tonic-gate 		return (NS_TSIG_ERROR_NO_SPACE);
1177c478bd9Sstevel@tonic-gate 	cp += n;
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate 	/* Type, class, ttl, length (not filled in yet). */
1207c478bd9Sstevel@tonic-gate 	BOUNDS_CHECK(cp, INT16SZ + INT16SZ + INT32SZ + INT16SZ);
1217c478bd9Sstevel@tonic-gate 	PUTSHORT(ns_t_tsig, cp);
1227c478bd9Sstevel@tonic-gate 	PUTSHORT(ns_c_any, cp);
1239525b14bSRao Shoaib 	PUTLONG(0, cp);		/*%< TTL */
1247c478bd9Sstevel@tonic-gate 	lenp = cp;
1257c478bd9Sstevel@tonic-gate 	cp += 2;
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate 	/* Alg. */
1287c478bd9Sstevel@tonic-gate 	if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) {
1297c478bd9Sstevel@tonic-gate 		if (key->dk_alg != KEY_HMAC_MD5)
1307c478bd9Sstevel@tonic-gate 			return (-ns_r_badkey);
1317c478bd9Sstevel@tonic-gate 		n = dn_comp(NS_TSIG_ALG_HMAC_MD5, cp, eob - cp, NULL, NULL);
1327c478bd9Sstevel@tonic-gate 	}
1337c478bd9Sstevel@tonic-gate 	else
1347c478bd9Sstevel@tonic-gate 		n = dn_comp("", cp, eob - cp, NULL, NULL);
1357c478bd9Sstevel@tonic-gate 	if (n < 0)
1367c478bd9Sstevel@tonic-gate 		return (NS_TSIG_ERROR_NO_SPACE);
1377c478bd9Sstevel@tonic-gate 	alg = cp;
1387c478bd9Sstevel@tonic-gate 	cp += n;
139*55fea89dSDan Cross 
1407c478bd9Sstevel@tonic-gate 	/* Time. */
1417c478bd9Sstevel@tonic-gate 	BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ);
1427c478bd9Sstevel@tonic-gate 	PUTSHORT(0, cp);
1437c478bd9Sstevel@tonic-gate 	timesigned = time(NULL);
1447c478bd9Sstevel@tonic-gate 	if (error != ns_r_badtime)
1457c478bd9Sstevel@tonic-gate 		PUTLONG(timesigned, cp);
1467c478bd9Sstevel@tonic-gate 	else
1477c478bd9Sstevel@tonic-gate 		PUTLONG(in_timesigned, cp);
1487c478bd9Sstevel@tonic-gate 	PUTSHORT(NS_TSIG_FUDGE, cp);
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 	/* Compute the signature. */
1517c478bd9Sstevel@tonic-gate 	if (key != NULL && error != ns_r_badsig && error != ns_r_badkey) {
1527c478bd9Sstevel@tonic-gate 		void *ctx;
1537c478bd9Sstevel@tonic-gate 		u_char buf[NS_MAXCDNAME], *cp2;
1547c478bd9Sstevel@tonic-gate 		int n;
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 		dst_sign_data(SIG_MODE_INIT, key, &ctx, NULL, 0, NULL, 0);
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 		/* Digest the query signature, if this is a response. */
1597c478bd9Sstevel@tonic-gate 		if (querysiglen > 0 && querysig != NULL) {
1607c478bd9Sstevel@tonic-gate 			u_int16_t len_n = htons(querysiglen);
1617c478bd9Sstevel@tonic-gate 			dst_sign_data(SIG_MODE_UPDATE, key, &ctx,
1627c478bd9Sstevel@tonic-gate 				      (u_char *)&len_n, INT16SZ, NULL, 0);
1637c478bd9Sstevel@tonic-gate 			dst_sign_data(SIG_MODE_UPDATE, key, &ctx,
1647c478bd9Sstevel@tonic-gate 				      querysig, querysiglen, NULL, 0);
1657c478bd9Sstevel@tonic-gate 		}
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 		/* Digest the message. */
1687c478bd9Sstevel@tonic-gate 		dst_sign_data(SIG_MODE_UPDATE, key, &ctx, msg, *msglen,
1697c478bd9Sstevel@tonic-gate 			      NULL, 0);
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 		/* Digest the key name. */
1727c478bd9Sstevel@tonic-gate 		n = ns_name_ntol(name, buf, sizeof(buf));
1737c478bd9Sstevel@tonic-gate 		INSIST(n > 0);
1747c478bd9Sstevel@tonic-gate 		dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 		/* Digest the class and TTL. */
1777c478bd9Sstevel@tonic-gate 		cp2 = buf;
1787c478bd9Sstevel@tonic-gate 		PUTSHORT(ns_c_any, cp2);
1797c478bd9Sstevel@tonic-gate 		PUTLONG(0, cp2);
1807c478bd9Sstevel@tonic-gate 		dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, cp2-buf,
1817c478bd9Sstevel@tonic-gate 			      NULL, 0);
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 		/* Digest the algorithm. */
1847c478bd9Sstevel@tonic-gate 		n = ns_name_ntol(alg, buf, sizeof(buf));
1857c478bd9Sstevel@tonic-gate 		INSIST(n > 0);
1867c478bd9Sstevel@tonic-gate 		dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, n, NULL, 0);
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 		/* Digest the time signed, fudge, error, and other data */
1897c478bd9Sstevel@tonic-gate 		cp2 = buf;
1909525b14bSRao Shoaib 		PUTSHORT(0, cp2);	/*%< Top 16 bits of time */
1917c478bd9Sstevel@tonic-gate 		if (error != ns_r_badtime)
1927c478bd9Sstevel@tonic-gate 			PUTLONG(timesigned, cp2);
1937c478bd9Sstevel@tonic-gate 		else
1947c478bd9Sstevel@tonic-gate 			PUTLONG(in_timesigned, cp2);
1957c478bd9Sstevel@tonic-gate 		PUTSHORT(NS_TSIG_FUDGE, cp2);
1969525b14bSRao Shoaib 		PUTSHORT(error, cp2);	/*%< Error */
1977c478bd9Sstevel@tonic-gate 		if (error != ns_r_badtime)
1989525b14bSRao Shoaib 			PUTSHORT(0, cp2);	/*%< Other data length */
1997c478bd9Sstevel@tonic-gate 		else {
2009525b14bSRao Shoaib 			PUTSHORT(INT16SZ+INT32SZ, cp2);	/*%< Other data length */
2019525b14bSRao Shoaib 			PUTSHORT(0, cp2);	/*%< Top 16 bits of time */
2027c478bd9Sstevel@tonic-gate 			PUTLONG(timesigned, cp2);
2037c478bd9Sstevel@tonic-gate 		}
2047c478bd9Sstevel@tonic-gate 		dst_sign_data(SIG_MODE_UPDATE, key, &ctx, buf, cp2-buf,
2057c478bd9Sstevel@tonic-gate 			      NULL, 0);
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 		n = dst_sign_data(SIG_MODE_FINAL, key, &ctx, NULL, 0,
2087c478bd9Sstevel@tonic-gate 				  sig, *siglen);
2097c478bd9Sstevel@tonic-gate 		if (n < 0)
2107c478bd9Sstevel@tonic-gate 			return (-ns_r_badkey);
2117c478bd9Sstevel@tonic-gate 		*siglen = n;
2127c478bd9Sstevel@tonic-gate 	} else
2137c478bd9Sstevel@tonic-gate 		*siglen = 0;
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 	/* Add the signature. */
2167c478bd9Sstevel@tonic-gate 	BOUNDS_CHECK(cp, INT16SZ + (*siglen));
2177c478bd9Sstevel@tonic-gate 	PUTSHORT(*siglen, cp);
2187c478bd9Sstevel@tonic-gate 	memcpy(cp, sig, *siglen);
2197c478bd9Sstevel@tonic-gate 	cp += (*siglen);
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 	/* The original message ID & error. */
2227c478bd9Sstevel@tonic-gate 	BOUNDS_CHECK(cp, INT16SZ + INT16SZ);
2239525b14bSRao Shoaib 	PUTSHORT(ntohs(hp->id), cp);	/*%< already in network order */
2247c478bd9Sstevel@tonic-gate 	PUTSHORT(error, cp);
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 	/* Other data. */
2277c478bd9Sstevel@tonic-gate 	BOUNDS_CHECK(cp, INT16SZ);
2287c478bd9Sstevel@tonic-gate 	if (error != ns_r_badtime)
2299525b14bSRao Shoaib 		PUTSHORT(0, cp);	/*%< Other data length */
2307c478bd9Sstevel@tonic-gate 	else {
2319525b14bSRao Shoaib 		PUTSHORT(INT16SZ+INT32SZ, cp);	/*%< Other data length */
2327c478bd9Sstevel@tonic-gate 		BOUNDS_CHECK(cp, INT32SZ+INT16SZ);
2339525b14bSRao Shoaib 		PUTSHORT(0, cp);	/*%< Top 16 bits of time */
2347c478bd9Sstevel@tonic-gate 		PUTLONG(timesigned, cp);
2357c478bd9Sstevel@tonic-gate 	}
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 	/* Go back and fill in the length. */
2387c478bd9Sstevel@tonic-gate 	PUTSHORT(cp - lenp - INT16SZ, lenp);
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	hp->arcount = htons(ntohs(hp->arcount) + 1);
2417c478bd9Sstevel@tonic-gate 	*msglen = (cp - msg);
2427c478bd9Sstevel@tonic-gate 	return (0);
2437c478bd9Sstevel@tonic-gate }
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate int
ns_sign_tcp_init(void * k,const u_char * querysig,int querysiglen,ns_tcp_tsig_state * state)2467c478bd9Sstevel@tonic-gate ns_sign_tcp_init(void *k, const u_char *querysig, int querysiglen,
2477c478bd9Sstevel@tonic-gate 		 ns_tcp_tsig_state *state)
2487c478bd9Sstevel@tonic-gate {
2497c478bd9Sstevel@tonic-gate 	dst_init();
2507c478bd9Sstevel@tonic-gate 	if (state == NULL || k == NULL || querysig == NULL || querysiglen < 0)
2517c478bd9Sstevel@tonic-gate 		return (-1);
2527c478bd9Sstevel@tonic-gate 	state->counter = -1;
2537c478bd9Sstevel@tonic-gate 	state->key = k;
2547c478bd9Sstevel@tonic-gate 	if (state->key->dk_alg != KEY_HMAC_MD5)
2557c478bd9Sstevel@tonic-gate 		return (-ns_r_badkey);
2567c478bd9Sstevel@tonic-gate 	if (querysiglen > (int)sizeof(state->sig))
2577c478bd9Sstevel@tonic-gate 		return (-1);
2587c478bd9Sstevel@tonic-gate 	memcpy(state->sig, querysig, querysiglen);
2597c478bd9Sstevel@tonic-gate 	state->siglen = querysiglen;
2607c478bd9Sstevel@tonic-gate 	return (0);
2617c478bd9Sstevel@tonic-gate }
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate int
ns_sign_tcp(u_char * msg,int * msglen,int msgsize,int error,ns_tcp_tsig_state * state,int done)2647c478bd9Sstevel@tonic-gate ns_sign_tcp(u_char *msg, int *msglen, int msgsize, int error,
2657c478bd9Sstevel@tonic-gate 	    ns_tcp_tsig_state *state, int done)
2667c478bd9Sstevel@tonic-gate {
2677c478bd9Sstevel@tonic-gate 	return (ns_sign_tcp2(msg, msglen, msgsize, error, state,
2687c478bd9Sstevel@tonic-gate 			     done, NULL, NULL));
2697c478bd9Sstevel@tonic-gate }
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate int
ns_sign_tcp2(u_char * msg,int * msglen,int msgsize,int error,ns_tcp_tsig_state * state,int done,u_char ** dnptrs,u_char ** lastdnptr)2727c478bd9Sstevel@tonic-gate ns_sign_tcp2(u_char *msg, int *msglen, int msgsize, int error,
2737c478bd9Sstevel@tonic-gate 	     ns_tcp_tsig_state *state, int done,
2747c478bd9Sstevel@tonic-gate 	     u_char **dnptrs, u_char **lastdnptr)
2757c478bd9Sstevel@tonic-gate {
2767c478bd9Sstevel@tonic-gate 	u_char *cp, *eob, *lenp;
2777c478bd9Sstevel@tonic-gate 	u_char buf[MAXDNAME], *cp2;
2787c478bd9Sstevel@tonic-gate 	HEADER *hp = (HEADER *)msg;
2797c478bd9Sstevel@tonic-gate 	time_t timesigned;
2807c478bd9Sstevel@tonic-gate 	int n;
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 	if (msg == NULL || msglen == NULL || state == NULL)
2837c478bd9Sstevel@tonic-gate 		return (-1);
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 	state->counter++;
2867c478bd9Sstevel@tonic-gate 	if (state->counter == 0)
2877c478bd9Sstevel@tonic-gate 		return (ns_sign2(msg, msglen, msgsize, error, state->key,
2887c478bd9Sstevel@tonic-gate 				 state->sig, state->siglen,
2897c478bd9Sstevel@tonic-gate 				 state->sig, &state->siglen, 0,
2907c478bd9Sstevel@tonic-gate 				 dnptrs, lastdnptr));
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	if (state->siglen > 0) {
2937c478bd9Sstevel@tonic-gate 		u_int16_t siglen_n = htons(state->siglen);
2947c478bd9Sstevel@tonic-gate 		dst_sign_data(SIG_MODE_INIT, state->key, &state->ctx,
2957c478bd9Sstevel@tonic-gate 			      NULL, 0, NULL, 0);
2967c478bd9Sstevel@tonic-gate 		dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx,
2977c478bd9Sstevel@tonic-gate 			      (u_char *)&siglen_n, INT16SZ, NULL, 0);
2987c478bd9Sstevel@tonic-gate 		dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx,
2997c478bd9Sstevel@tonic-gate 			      state->sig, state->siglen, NULL, 0);
3007c478bd9Sstevel@tonic-gate 		state->siglen = 0;
3017c478bd9Sstevel@tonic-gate 	}
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx, msg, *msglen,
3047c478bd9Sstevel@tonic-gate 		      NULL, 0);
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	if (done == 0 && (state->counter % 100 != 0))
3077c478bd9Sstevel@tonic-gate 		return (0);
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	cp = msg + *msglen;
3107c478bd9Sstevel@tonic-gate 	eob = msg + msgsize;
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	/* Name. */
3137c478bd9Sstevel@tonic-gate 	n = dn_comp(state->key->dk_key_name, cp, eob - cp, dnptrs, lastdnptr);
3147c478bd9Sstevel@tonic-gate 	if (n < 0)
3157c478bd9Sstevel@tonic-gate 		return (NS_TSIG_ERROR_NO_SPACE);
3167c478bd9Sstevel@tonic-gate 	cp += n;
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 	/* Type, class, ttl, length (not filled in yet). */
3197c478bd9Sstevel@tonic-gate 	BOUNDS_CHECK(cp, INT16SZ + INT16SZ + INT32SZ + INT16SZ);
3207c478bd9Sstevel@tonic-gate 	PUTSHORT(ns_t_tsig, cp);
3217c478bd9Sstevel@tonic-gate 	PUTSHORT(ns_c_any, cp);
3229525b14bSRao Shoaib 	PUTLONG(0, cp);		/*%< TTL */
3237c478bd9Sstevel@tonic-gate 	lenp = cp;
3247c478bd9Sstevel@tonic-gate 	cp += 2;
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 	/* Alg. */
3277c478bd9Sstevel@tonic-gate 	n = dn_comp(NS_TSIG_ALG_HMAC_MD5, cp, eob - cp, NULL, NULL);
3287c478bd9Sstevel@tonic-gate 	if (n < 0)
3297c478bd9Sstevel@tonic-gate 		return (NS_TSIG_ERROR_NO_SPACE);
3307c478bd9Sstevel@tonic-gate 	cp += n;
331*55fea89dSDan Cross 
3327c478bd9Sstevel@tonic-gate 	/* Time. */
3337c478bd9Sstevel@tonic-gate 	BOUNDS_CHECK(cp, INT16SZ + INT32SZ + INT16SZ);
3347c478bd9Sstevel@tonic-gate 	PUTSHORT(0, cp);
3357c478bd9Sstevel@tonic-gate 	timesigned = time(NULL);
3367c478bd9Sstevel@tonic-gate 	PUTLONG(timesigned, cp);
3377c478bd9Sstevel@tonic-gate 	PUTSHORT(NS_TSIG_FUDGE, cp);
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	/*
3407c478bd9Sstevel@tonic-gate 	 * Compute the signature.
3417c478bd9Sstevel@tonic-gate 	 */
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	/* Digest the time signed and fudge. */
3447c478bd9Sstevel@tonic-gate 	cp2 = buf;
3459525b14bSRao Shoaib 	PUTSHORT(0, cp2);	/*%< Top 16 bits of time */
3467c478bd9Sstevel@tonic-gate 	PUTLONG(timesigned, cp2);
3477c478bd9Sstevel@tonic-gate 	PUTSHORT(NS_TSIG_FUDGE, cp2);
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 	dst_sign_data(SIG_MODE_UPDATE, state->key, &state->ctx,
3507c478bd9Sstevel@tonic-gate 		      buf, cp2 - buf, NULL, 0);
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	n = dst_sign_data(SIG_MODE_FINAL, state->key, &state->ctx, NULL, 0,
3537c478bd9Sstevel@tonic-gate 			  state->sig, sizeof(state->sig));
3547c478bd9Sstevel@tonic-gate 	if (n < 0)
3557c478bd9Sstevel@tonic-gate 		return (-ns_r_badkey);
3567c478bd9Sstevel@tonic-gate 	state->siglen = n;
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 	/* Add the signature. */
3597c478bd9Sstevel@tonic-gate 	BOUNDS_CHECK(cp, INT16SZ + state->siglen);
3607c478bd9Sstevel@tonic-gate 	PUTSHORT(state->siglen, cp);
3617c478bd9Sstevel@tonic-gate 	memcpy(cp, state->sig, state->siglen);
3627c478bd9Sstevel@tonic-gate 	cp += state->siglen;
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	/* The original message ID & error. */
3657c478bd9Sstevel@tonic-gate 	BOUNDS_CHECK(cp, INT16SZ + INT16SZ);
3669525b14bSRao Shoaib 	PUTSHORT(ntohs(hp->id), cp);	/*%< already in network order */
3677c478bd9Sstevel@tonic-gate 	PUTSHORT(error, cp);
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	/* Other data. */
3707c478bd9Sstevel@tonic-gate 	BOUNDS_CHECK(cp, INT16SZ);
3717c478bd9Sstevel@tonic-gate 	PUTSHORT(0, cp);
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	/* Go back and fill in the length. */
3747c478bd9Sstevel@tonic-gate 	PUTSHORT(cp - lenp - INT16SZ, lenp);
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 	hp->arcount = htons(ntohs(hp->arcount) + 1);
3777c478bd9Sstevel@tonic-gate 	*msglen = (cp - msg);
3787c478bd9Sstevel@tonic-gate 	return (0);
3797c478bd9Sstevel@tonic-gate }
3809525b14bSRao Shoaib 
3819525b14bSRao Shoaib /*! \file */
382