xref: /netbsd/external/mpl/bind/dist/lib/dns/tsig.c (revision e2b1b9c0)
1*e2b1b9c0Schristos /*	$NetBSD: tsig.c,v 1.1.1.1 2018/08/12 12:08:10 christos Exp $	*/
2*e2b1b9c0Schristos 
3*e2b1b9c0Schristos /*
4*e2b1b9c0Schristos  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5*e2b1b9c0Schristos  *
6*e2b1b9c0Schristos  * This Source Code Form is subject to the terms of the Mozilla Public
7*e2b1b9c0Schristos  * License, v. 2.0. If a copy of the MPL was not distributed with this
8*e2b1b9c0Schristos  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9*e2b1b9c0Schristos  *
10*e2b1b9c0Schristos  * See the COPYRIGHT file distributed with this work for additional
11*e2b1b9c0Schristos  * information regarding copyright ownership.
12*e2b1b9c0Schristos  */
13*e2b1b9c0Schristos 
14*e2b1b9c0Schristos /*! \file */
15*e2b1b9c0Schristos #include <config.h>
16*e2b1b9c0Schristos #include <stdlib.h>
17*e2b1b9c0Schristos 
18*e2b1b9c0Schristos #include <isc/buffer.h>
19*e2b1b9c0Schristos #include <isc/mem.h>
20*e2b1b9c0Schristos #include <isc/print.h>
21*e2b1b9c0Schristos #include <isc/refcount.h>
22*e2b1b9c0Schristos #include <isc/serial.h>
23*e2b1b9c0Schristos #include <isc/string.h>		/* Required for HP/UX (and others?) */
24*e2b1b9c0Schristos #include <isc/util.h>
25*e2b1b9c0Schristos #include <isc/time.h>
26*e2b1b9c0Schristos 
27*e2b1b9c0Schristos #include <pk11/site.h>
28*e2b1b9c0Schristos 
29*e2b1b9c0Schristos #include <dns/keyvalues.h>
30*e2b1b9c0Schristos #include <dns/log.h>
31*e2b1b9c0Schristos #include <dns/message.h>
32*e2b1b9c0Schristos #include <dns/fixedname.h>
33*e2b1b9c0Schristos #include <dns/rbt.h>
34*e2b1b9c0Schristos #include <dns/rdata.h>
35*e2b1b9c0Schristos #include <dns/rdatalist.h>
36*e2b1b9c0Schristos #include <dns/rdataset.h>
37*e2b1b9c0Schristos #include <dns/rdatastruct.h>
38*e2b1b9c0Schristos #include <dns/result.h>
39*e2b1b9c0Schristos #include <dns/tsig.h>
40*e2b1b9c0Schristos 
41*e2b1b9c0Schristos #include "tsig_p.h"
42*e2b1b9c0Schristos 
43*e2b1b9c0Schristos #include <dst/result.h>
44*e2b1b9c0Schristos 
45*e2b1b9c0Schristos #define TSIG_MAGIC		ISC_MAGIC('T', 'S', 'I', 'G')
46*e2b1b9c0Schristos #define VALID_TSIG_KEY(x)	ISC_MAGIC_VALID(x, TSIG_MAGIC)
47*e2b1b9c0Schristos 
48*e2b1b9c0Schristos #ifndef DNS_TSIG_MAXGENERATEDKEYS
49*e2b1b9c0Schristos #define DNS_TSIG_MAXGENERATEDKEYS 4096
50*e2b1b9c0Schristos #endif
51*e2b1b9c0Schristos 
52*e2b1b9c0Schristos #define is_response(msg) (msg->flags & DNS_MESSAGEFLAG_QR)
53*e2b1b9c0Schristos 
54*e2b1b9c0Schristos #define BADTIMELEN 6
55*e2b1b9c0Schristos 
56*e2b1b9c0Schristos #ifndef PK11_MD5_DISABLE
57*e2b1b9c0Schristos static unsigned char hmacmd5_ndata[] = "\010hmac-md5\007sig-alg\003reg\003int";
58*e2b1b9c0Schristos static unsigned char hmacmd5_offsets[] = { 0, 9, 17, 21, 25 };
59*e2b1b9c0Schristos 
60*e2b1b9c0Schristos static dns_name_t const hmacmd5 =
61*e2b1b9c0Schristos 	DNS_NAME_INITABSOLUTE(hmacmd5_ndata, hmacmd5_offsets);
62*e2b1b9c0Schristos LIBDNS_EXTERNAL_DATA const dns_name_t *dns_tsig_hmacmd5_name = &hmacmd5;
63*e2b1b9c0Schristos #endif
64*e2b1b9c0Schristos 
65*e2b1b9c0Schristos static unsigned char gsstsig_ndata[] = "\010gss-tsig";
66*e2b1b9c0Schristos static unsigned char gsstsig_offsets[] = { 0, 9 };
67*e2b1b9c0Schristos static dns_name_t const gsstsig =
68*e2b1b9c0Schristos 	DNS_NAME_INITABSOLUTE(gsstsig_ndata, gsstsig_offsets);
69*e2b1b9c0Schristos LIBDNS_EXTERNAL_DATA const dns_name_t *dns_tsig_gssapi_name = &gsstsig;
70*e2b1b9c0Schristos 
71*e2b1b9c0Schristos /*
72*e2b1b9c0Schristos  * Since Microsoft doesn't follow its own standard, we will use this
73*e2b1b9c0Schristos  * alternate name as a second guess.
74*e2b1b9c0Schristos  */
75*e2b1b9c0Schristos static unsigned char gsstsigms_ndata[] = "\003gss\011microsoft\003com";
76*e2b1b9c0Schristos static unsigned char gsstsigms_offsets[] = { 0, 4, 14, 18 };
77*e2b1b9c0Schristos static dns_name_t const gsstsigms =
78*e2b1b9c0Schristos 	DNS_NAME_INITABSOLUTE(gsstsigms_ndata, gsstsigms_offsets);
79*e2b1b9c0Schristos LIBDNS_EXTERNAL_DATA const dns_name_t *dns_tsig_gssapims_name = &gsstsigms;
80*e2b1b9c0Schristos 
81*e2b1b9c0Schristos static unsigned char hmacsha1_ndata[] = "\011hmac-sha1";
82*e2b1b9c0Schristos static unsigned char hmacsha1_offsets[] = { 0, 10 };
83*e2b1b9c0Schristos static dns_name_t const  hmacsha1 =
84*e2b1b9c0Schristos 	DNS_NAME_INITABSOLUTE(hmacsha1_ndata, hmacsha1_offsets);
85*e2b1b9c0Schristos LIBDNS_EXTERNAL_DATA const dns_name_t *dns_tsig_hmacsha1_name = &hmacsha1;
86*e2b1b9c0Schristos 
87*e2b1b9c0Schristos static unsigned char hmacsha224_ndata[] = "\013hmac-sha224";
88*e2b1b9c0Schristos static unsigned char hmacsha224_offsets[] = { 0, 12 };
89*e2b1b9c0Schristos static dns_name_t const hmacsha224 =
90*e2b1b9c0Schristos 	DNS_NAME_INITABSOLUTE(hmacsha224_ndata, hmacsha224_offsets);
91*e2b1b9c0Schristos LIBDNS_EXTERNAL_DATA const dns_name_t *dns_tsig_hmacsha224_name = &hmacsha224;
92*e2b1b9c0Schristos 
93*e2b1b9c0Schristos static unsigned char hmacsha256_ndata[] = "\013hmac-sha256";
94*e2b1b9c0Schristos static unsigned char hmacsha256_offsets[] = { 0, 12 };
95*e2b1b9c0Schristos static dns_name_t const hmacsha256 =
96*e2b1b9c0Schristos 	DNS_NAME_INITABSOLUTE(hmacsha256_ndata, hmacsha256_offsets);
97*e2b1b9c0Schristos LIBDNS_EXTERNAL_DATA const dns_name_t *dns_tsig_hmacsha256_name = &hmacsha256;
98*e2b1b9c0Schristos 
99*e2b1b9c0Schristos static unsigned char hmacsha384_ndata[] = "\013hmac-sha384";
100*e2b1b9c0Schristos static unsigned char hmacsha384_offsets[] = { 0, 12 };
101*e2b1b9c0Schristos static dns_name_t const hmacsha384 =
102*e2b1b9c0Schristos 	DNS_NAME_INITABSOLUTE(hmacsha384_ndata, hmacsha384_offsets);
103*e2b1b9c0Schristos LIBDNS_EXTERNAL_DATA const dns_name_t *dns_tsig_hmacsha384_name = &hmacsha384;
104*e2b1b9c0Schristos 
105*e2b1b9c0Schristos static unsigned char hmacsha512_ndata[] = "\013hmac-sha512";
106*e2b1b9c0Schristos static unsigned char hmacsha512_offsets[] = { 0, 12 };
107*e2b1b9c0Schristos static dns_name_t const hmacsha512 =
108*e2b1b9c0Schristos 	DNS_NAME_INITABSOLUTE(hmacsha512_ndata, hmacsha512_offsets);
109*e2b1b9c0Schristos LIBDNS_EXTERNAL_DATA const dns_name_t *dns_tsig_hmacsha512_name = &hmacsha512;
110*e2b1b9c0Schristos 
111*e2b1b9c0Schristos static const struct {
112*e2b1b9c0Schristos 	const dns_name_t *name;
113*e2b1b9c0Schristos 	unsigned int dstalg;
114*e2b1b9c0Schristos } known_algs[] = {
115*e2b1b9c0Schristos #ifndef PK11_MD5_DISABLE
116*e2b1b9c0Schristos 	{ &hmacmd5,	DST_ALG_HMACMD5		},
117*e2b1b9c0Schristos #endif
118*e2b1b9c0Schristos 	{ &gsstsig,	DST_ALG_GSSAPI	 	},
119*e2b1b9c0Schristos 	{ &gsstsigms,	DST_ALG_GSSAPI		},
120*e2b1b9c0Schristos 	{ &hmacsha1,	DST_ALG_HMACSHA1	},
121*e2b1b9c0Schristos 	{ &hmacsha224,	DST_ALG_HMACSHA224	},
122*e2b1b9c0Schristos 	{ &hmacsha256,	DST_ALG_HMACSHA256	},
123*e2b1b9c0Schristos 	{ &hmacsha384,	DST_ALG_HMACSHA384	},
124*e2b1b9c0Schristos 	{ &hmacsha512,	DST_ALG_HMACSHA512	}
125*e2b1b9c0Schristos };
126*e2b1b9c0Schristos 
127*e2b1b9c0Schristos static isc_result_t
128*e2b1b9c0Schristos tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg);
129*e2b1b9c0Schristos 
130*e2b1b9c0Schristos static void
131*e2b1b9c0Schristos tsig_log(dns_tsigkey_t *key, int level, const char *fmt, ...)
132*e2b1b9c0Schristos      ISC_FORMAT_PRINTF(3, 4);
133*e2b1b9c0Schristos 
134*e2b1b9c0Schristos static void
135*e2b1b9c0Schristos cleanup_ring(dns_tsig_keyring_t *ring);
136*e2b1b9c0Schristos static void
137*e2b1b9c0Schristos tsigkey_free(dns_tsigkey_t *key);
138*e2b1b9c0Schristos 
139*e2b1b9c0Schristos isc_boolean_t
140*e2b1b9c0Schristos dns__tsig_algvalid(unsigned int alg) {
141*e2b1b9c0Schristos #ifndef PK11_MD5_DISABLE
142*e2b1b9c0Schristos 	if (alg == DST_ALG_HMACMD5) {
143*e2b1b9c0Schristos 		return (ISC_TRUE);
144*e2b1b9c0Schristos 	}
145*e2b1b9c0Schristos #endif
146*e2b1b9c0Schristos 	return (ISC_TF(alg == DST_ALG_HMACSHA1 ||
147*e2b1b9c0Schristos 		       alg == DST_ALG_HMACSHA224 ||
148*e2b1b9c0Schristos 		       alg == DST_ALG_HMACSHA256 ||
149*e2b1b9c0Schristos 		       alg == DST_ALG_HMACSHA384 ||
150*e2b1b9c0Schristos 		       alg == DST_ALG_HMACSHA512));
151*e2b1b9c0Schristos }
152*e2b1b9c0Schristos 
153*e2b1b9c0Schristos static void
154*e2b1b9c0Schristos tsig_log(dns_tsigkey_t *key, int level, const char *fmt, ...) {
155*e2b1b9c0Schristos 	va_list ap;
156*e2b1b9c0Schristos 	char message[4096];
157*e2b1b9c0Schristos 	char namestr[DNS_NAME_FORMATSIZE];
158*e2b1b9c0Schristos 	char creatorstr[DNS_NAME_FORMATSIZE];
159*e2b1b9c0Schristos 
160*e2b1b9c0Schristos 	if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE)
161*e2b1b9c0Schristos 		return;
162*e2b1b9c0Schristos 	if (key != NULL) {
163*e2b1b9c0Schristos 		dns_name_format(&key->name, namestr, sizeof(namestr));
164*e2b1b9c0Schristos 	} else {
165*e2b1b9c0Schristos 		strlcpy(namestr, "<null>", sizeof(namestr));
166*e2b1b9c0Schristos 	}
167*e2b1b9c0Schristos 
168*e2b1b9c0Schristos 	if (key != NULL && key->generated && key->creator) {
169*e2b1b9c0Schristos 		dns_name_format(key->creator, creatorstr, sizeof(creatorstr));
170*e2b1b9c0Schristos 	} else {
171*e2b1b9c0Schristos 		strlcpy(creatorstr, "<null>", sizeof(creatorstr));
172*e2b1b9c0Schristos 	}
173*e2b1b9c0Schristos 
174*e2b1b9c0Schristos 	va_start(ap, fmt);
175*e2b1b9c0Schristos 	vsnprintf(message, sizeof(message), fmt, ap);
176*e2b1b9c0Schristos 	va_end(ap);
177*e2b1b9c0Schristos 	if (key != NULL && key->generated) {
178*e2b1b9c0Schristos 		isc_log_write(dns_lctx,
179*e2b1b9c0Schristos 			      DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_TSIG,
180*e2b1b9c0Schristos 			      level, "tsig key '%s' (%s): %s",
181*e2b1b9c0Schristos 			      namestr, creatorstr, message);
182*e2b1b9c0Schristos 	} else {
183*e2b1b9c0Schristos 		isc_log_write(dns_lctx,
184*e2b1b9c0Schristos 			      DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_TSIG,
185*e2b1b9c0Schristos 			      level, "tsig key '%s': %s", namestr, message);
186*e2b1b9c0Schristos 	}
187*e2b1b9c0Schristos }
188*e2b1b9c0Schristos 
189*e2b1b9c0Schristos static void
190*e2b1b9c0Schristos remove_fromring(dns_tsigkey_t *tkey) {
191*e2b1b9c0Schristos 	if (tkey->generated) {
192*e2b1b9c0Schristos 		ISC_LIST_UNLINK(tkey->ring->lru, tkey, link);
193*e2b1b9c0Schristos 		tkey->ring->generated--;
194*e2b1b9c0Schristos 	}
195*e2b1b9c0Schristos 	(void)dns_rbt_deletename(tkey->ring->keys, &tkey->name, ISC_FALSE);
196*e2b1b9c0Schristos }
197*e2b1b9c0Schristos 
198*e2b1b9c0Schristos static void
199*e2b1b9c0Schristos adjust_lru(dns_tsigkey_t *tkey) {
200*e2b1b9c0Schristos 	if (tkey->generated) {
201*e2b1b9c0Schristos 		RWLOCK(&tkey->ring->lock, isc_rwlocktype_write);
202*e2b1b9c0Schristos 		/*
203*e2b1b9c0Schristos 		 * We may have been removed from the LRU list between
204*e2b1b9c0Schristos 		 * removing the read lock and aquiring the write lock.
205*e2b1b9c0Schristos 		 */
206*e2b1b9c0Schristos 		if (ISC_LINK_LINKED(tkey, link) &&
207*e2b1b9c0Schristos 		    tkey->ring->lru.tail != tkey)
208*e2b1b9c0Schristos 		{
209*e2b1b9c0Schristos 			ISC_LIST_UNLINK(tkey->ring->lru, tkey, link);
210*e2b1b9c0Schristos 			ISC_LIST_APPEND(tkey->ring->lru, tkey, link);
211*e2b1b9c0Schristos 		}
212*e2b1b9c0Schristos 		RWUNLOCK(&tkey->ring->lock, isc_rwlocktype_write);
213*e2b1b9c0Schristos 	}
214*e2b1b9c0Schristos }
215*e2b1b9c0Schristos 
216*e2b1b9c0Schristos /*
217*e2b1b9c0Schristos  * A supplemental routine just to add a key to ring.  Note that reference
218*e2b1b9c0Schristos  * counter should be counted separately because we may be adding the key
219*e2b1b9c0Schristos  * as part of creation of the key, in which case the reference counter was
220*e2b1b9c0Schristos  * already initialized.  Also note we don't need RWLOCK for the reference
221*e2b1b9c0Schristos  * counter: it's protected by a separate lock.
222*e2b1b9c0Schristos  */
223*e2b1b9c0Schristos static isc_result_t
224*e2b1b9c0Schristos keyring_add(dns_tsig_keyring_t *ring, const dns_name_t *name,
225*e2b1b9c0Schristos 	    dns_tsigkey_t *tkey)
226*e2b1b9c0Schristos {
227*e2b1b9c0Schristos 	isc_result_t result;
228*e2b1b9c0Schristos 
229*e2b1b9c0Schristos 	RWLOCK(&ring->lock, isc_rwlocktype_write);
230*e2b1b9c0Schristos 	ring->writecount++;
231*e2b1b9c0Schristos 
232*e2b1b9c0Schristos 	/*
233*e2b1b9c0Schristos 	 * Do on the fly cleaning.  Find some nodes we might not
234*e2b1b9c0Schristos 	 * want around any more.
235*e2b1b9c0Schristos 	 */
236*e2b1b9c0Schristos 	if (ring->writecount > 10) {
237*e2b1b9c0Schristos 		cleanup_ring(ring);
238*e2b1b9c0Schristos 		ring->writecount = 0;
239*e2b1b9c0Schristos 	}
240*e2b1b9c0Schristos 
241*e2b1b9c0Schristos 	result = dns_rbt_addname(ring->keys, name, tkey);
242*e2b1b9c0Schristos 	if (result == ISC_R_SUCCESS && tkey->generated) {
243*e2b1b9c0Schristos 		/*
244*e2b1b9c0Schristos 		 * Add the new key to the LRU list and remove the least
245*e2b1b9c0Schristos 		 * recently used key if there are too many keys on the list.
246*e2b1b9c0Schristos 		 */
247*e2b1b9c0Schristos 		ISC_LIST_APPEND(ring->lru, tkey, link);
248*e2b1b9c0Schristos 		if (ring->generated++ > ring->maxgenerated)
249*e2b1b9c0Schristos 			remove_fromring(ISC_LIST_HEAD(ring->lru));
250*e2b1b9c0Schristos 	}
251*e2b1b9c0Schristos 	RWUNLOCK(&ring->lock, isc_rwlocktype_write);
252*e2b1b9c0Schristos 
253*e2b1b9c0Schristos 	return (result);
254*e2b1b9c0Schristos }
255*e2b1b9c0Schristos 
256*e2b1b9c0Schristos isc_result_t
257*e2b1b9c0Schristos dns_tsigkey_createfromkey(const dns_name_t *name, const dns_name_t *algorithm,
258*e2b1b9c0Schristos 			  dst_key_t *dstkey, isc_boolean_t generated,
259*e2b1b9c0Schristos 			  const dns_name_t *creator, isc_stdtime_t inception,
260*e2b1b9c0Schristos 			  isc_stdtime_t expire, isc_mem_t *mctx,
261*e2b1b9c0Schristos 			  dns_tsig_keyring_t *ring, dns_tsigkey_t **key)
262*e2b1b9c0Schristos {
263*e2b1b9c0Schristos 	dns_tsigkey_t *tkey;
264*e2b1b9c0Schristos 	isc_result_t ret;
265*e2b1b9c0Schristos 	unsigned int refs = 0;
266*e2b1b9c0Schristos 	unsigned int dstalg = 0;
267*e2b1b9c0Schristos 
268*e2b1b9c0Schristos 	REQUIRE(key == NULL || *key == NULL);
269*e2b1b9c0Schristos 	REQUIRE(name != NULL);
270*e2b1b9c0Schristos 	REQUIRE(algorithm != NULL);
271*e2b1b9c0Schristos 	REQUIRE(mctx != NULL);
272*e2b1b9c0Schristos 	REQUIRE(key != NULL || ring != NULL);
273*e2b1b9c0Schristos 
274*e2b1b9c0Schristos 	tkey = (dns_tsigkey_t *) isc_mem_get(mctx, sizeof(dns_tsigkey_t));
275*e2b1b9c0Schristos 	if (tkey == NULL)
276*e2b1b9c0Schristos 		return (ISC_R_NOMEMORY);
277*e2b1b9c0Schristos 
278*e2b1b9c0Schristos 	dns_name_init(&tkey->name, NULL);
279*e2b1b9c0Schristos 	ret = dns_name_dup(name, mctx, &tkey->name);
280*e2b1b9c0Schristos 	if (ret != ISC_R_SUCCESS)
281*e2b1b9c0Schristos 		goto cleanup_key;
282*e2b1b9c0Schristos 	(void)dns_name_downcase(&tkey->name, &tkey->name, NULL);
283*e2b1b9c0Schristos 
284*e2b1b9c0Schristos 	/* Check against known algorithm names */
285*e2b1b9c0Schristos 	dstalg = dns__tsig_algfromname(algorithm);
286*e2b1b9c0Schristos 	if (dstalg != 0) {
287*e2b1b9c0Schristos 		/*
288*e2b1b9c0Schristos 		 * 'algorithm' must be set to a static pointer
289*e2b1b9c0Schristos 		 * so that dns__tsig_algallocated() can compare them.
290*e2b1b9c0Schristos 		 */
291*e2b1b9c0Schristos 		tkey->algorithm = dns__tsig_algnamefromname(algorithm);
292*e2b1b9c0Schristos 		if (dstkey != NULL && dst_key_alg(dstkey) != dstalg) {
293*e2b1b9c0Schristos 			ret = DNS_R_BADALG;
294*e2b1b9c0Schristos 			goto cleanup_name;
295*e2b1b9c0Schristos 		}
296*e2b1b9c0Schristos 	} else {
297*e2b1b9c0Schristos 		dns_name_t *tmpname;
298*e2b1b9c0Schristos 		if (dstkey != NULL) {
299*e2b1b9c0Schristos 			ret = DNS_R_BADALG;
300*e2b1b9c0Schristos 			goto cleanup_name;
301*e2b1b9c0Schristos 		}
302*e2b1b9c0Schristos 		tmpname = isc_mem_get(mctx, sizeof(dns_name_t));
303*e2b1b9c0Schristos 		if (tmpname == NULL) {
304*e2b1b9c0Schristos 			ret = ISC_R_NOMEMORY;
305*e2b1b9c0Schristos 			goto cleanup_name;
306*e2b1b9c0Schristos 		}
307*e2b1b9c0Schristos 		dns_name_init(tmpname, NULL);
308*e2b1b9c0Schristos 		ret = dns_name_dup(algorithm, mctx, tmpname);
309*e2b1b9c0Schristos 		if (ret != ISC_R_SUCCESS) {
310*e2b1b9c0Schristos 			isc_mem_put(mctx, tmpname, sizeof(dns_name_t));
311*e2b1b9c0Schristos 			goto cleanup_name;
312*e2b1b9c0Schristos 		}
313*e2b1b9c0Schristos 		(void)dns_name_downcase(tmpname, tmpname, NULL);
314*e2b1b9c0Schristos 		tkey->algorithm = tmpname;
315*e2b1b9c0Schristos 	}
316*e2b1b9c0Schristos 
317*e2b1b9c0Schristos 	if (creator != NULL) {
318*e2b1b9c0Schristos 		tkey->creator = isc_mem_get(mctx, sizeof(dns_name_t));
319*e2b1b9c0Schristos 		if (tkey->creator == NULL) {
320*e2b1b9c0Schristos 			ret = ISC_R_NOMEMORY;
321*e2b1b9c0Schristos 			goto cleanup_algorithm;
322*e2b1b9c0Schristos 		}
323*e2b1b9c0Schristos 		dns_name_init(tkey->creator, NULL);
324*e2b1b9c0Schristos 		ret = dns_name_dup(creator, mctx, tkey->creator);
325*e2b1b9c0Schristos 		if (ret != ISC_R_SUCCESS) {
326*e2b1b9c0Schristos 			isc_mem_put(mctx, tkey->creator, sizeof(dns_name_t));
327*e2b1b9c0Schristos 			goto cleanup_algorithm;
328*e2b1b9c0Schristos 		}
329*e2b1b9c0Schristos 	} else
330*e2b1b9c0Schristos 		tkey->creator = NULL;
331*e2b1b9c0Schristos 
332*e2b1b9c0Schristos 	tkey->key = NULL;
333*e2b1b9c0Schristos 	if (dstkey != NULL)
334*e2b1b9c0Schristos 		dst_key_attach(dstkey, &tkey->key);
335*e2b1b9c0Schristos 	tkey->ring = ring;
336*e2b1b9c0Schristos 
337*e2b1b9c0Schristos 	if (key != NULL)
338*e2b1b9c0Schristos 		refs = 1;
339*e2b1b9c0Schristos 	if (ring != NULL)
340*e2b1b9c0Schristos 		refs++;
341*e2b1b9c0Schristos 	ret = isc_refcount_init(&tkey->refs, refs);
342*e2b1b9c0Schristos 	if (ret != ISC_R_SUCCESS)
343*e2b1b9c0Schristos 		goto cleanup_creator;
344*e2b1b9c0Schristos 
345*e2b1b9c0Schristos 	tkey->generated = generated;
346*e2b1b9c0Schristos 	tkey->inception = inception;
347*e2b1b9c0Schristos 	tkey->expire = expire;
348*e2b1b9c0Schristos 	tkey->mctx = NULL;
349*e2b1b9c0Schristos 	isc_mem_attach(mctx, &tkey->mctx);
350*e2b1b9c0Schristos 	ISC_LINK_INIT(tkey, link);
351*e2b1b9c0Schristos 
352*e2b1b9c0Schristos 	tkey->magic = TSIG_MAGIC;
353*e2b1b9c0Schristos 
354*e2b1b9c0Schristos 	if (ring != NULL) {
355*e2b1b9c0Schristos 		ret = keyring_add(ring, name, tkey);
356*e2b1b9c0Schristos 		if (ret != ISC_R_SUCCESS)
357*e2b1b9c0Schristos 			goto cleanup_refs;
358*e2b1b9c0Schristos 	}
359*e2b1b9c0Schristos 
360*e2b1b9c0Schristos 	/*
361*e2b1b9c0Schristos 	 * Ignore this if it's a GSS key, since the key size is meaningless.
362*e2b1b9c0Schristos 	 */
363*e2b1b9c0Schristos 	if (dstkey != NULL && dst_key_size(dstkey) < 64 &&
364*e2b1b9c0Schristos 		dstalg != DST_ALG_GSSAPI) {
365*e2b1b9c0Schristos 		char namestr[DNS_NAME_FORMATSIZE];
366*e2b1b9c0Schristos 		dns_name_format(name, namestr, sizeof(namestr));
367*e2b1b9c0Schristos 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
368*e2b1b9c0Schristos 			      DNS_LOGMODULE_TSIG, ISC_LOG_INFO,
369*e2b1b9c0Schristos 			      "the key '%s' is too short to be secure",
370*e2b1b9c0Schristos 			      namestr);
371*e2b1b9c0Schristos 	}
372*e2b1b9c0Schristos 
373*e2b1b9c0Schristos 	if (key != NULL)
374*e2b1b9c0Schristos 		*key = tkey;
375*e2b1b9c0Schristos 
376*e2b1b9c0Schristos 	return (ISC_R_SUCCESS);
377*e2b1b9c0Schristos 
378*e2b1b9c0Schristos  cleanup_refs:
379*e2b1b9c0Schristos 	tkey->magic = 0;
380*e2b1b9c0Schristos 	while (refs-- > 0)
381*e2b1b9c0Schristos 		isc_refcount_decrement(&tkey->refs, NULL);
382*e2b1b9c0Schristos 	isc_refcount_destroy(&tkey->refs);
383*e2b1b9c0Schristos  cleanup_creator:
384*e2b1b9c0Schristos 	if (tkey->key != NULL)
385*e2b1b9c0Schristos 		dst_key_free(&tkey->key);
386*e2b1b9c0Schristos 	if (tkey->creator != NULL) {
387*e2b1b9c0Schristos 		dns_name_free(tkey->creator, mctx);
388*e2b1b9c0Schristos 		isc_mem_put(mctx, tkey->creator, sizeof(dns_name_t));
389*e2b1b9c0Schristos 	}
390*e2b1b9c0Schristos  cleanup_algorithm:
391*e2b1b9c0Schristos 	if (dns__tsig_algallocated(tkey->algorithm)) {
392*e2b1b9c0Schristos 		dns_name_t *tmpname;
393*e2b1b9c0Schristos 		DE_CONST(tkey->algorithm, tmpname);
394*e2b1b9c0Schristos 		if (dns_name_dynamic(tmpname))
395*e2b1b9c0Schristos 			dns_name_free(tmpname, mctx);
396*e2b1b9c0Schristos 		isc_mem_put(mctx, tmpname, sizeof(dns_name_t));
397*e2b1b9c0Schristos 	}
398*e2b1b9c0Schristos  cleanup_name:
399*e2b1b9c0Schristos 	dns_name_free(&tkey->name, mctx);
400*e2b1b9c0Schristos  cleanup_key:
401*e2b1b9c0Schristos 	isc_mem_put(mctx, tkey, sizeof(dns_tsigkey_t));
402*e2b1b9c0Schristos 
403*e2b1b9c0Schristos 	return (ret);
404*e2b1b9c0Schristos }
405*e2b1b9c0Schristos 
406*e2b1b9c0Schristos /*
407*e2b1b9c0Schristos  * Find a few nodes to destroy if possible.
408*e2b1b9c0Schristos  */
409*e2b1b9c0Schristos static void
410*e2b1b9c0Schristos cleanup_ring(dns_tsig_keyring_t *ring)
411*e2b1b9c0Schristos {
412*e2b1b9c0Schristos 	isc_result_t result;
413*e2b1b9c0Schristos 	dns_rbtnodechain_t chain;
414*e2b1b9c0Schristos 	dns_name_t foundname;
415*e2b1b9c0Schristos 	dns_fixedname_t fixedorigin;
416*e2b1b9c0Schristos 	dns_name_t *origin;
417*e2b1b9c0Schristos 	isc_stdtime_t now;
418*e2b1b9c0Schristos 	dns_rbtnode_t *node;
419*e2b1b9c0Schristos 	dns_tsigkey_t *tkey;
420*e2b1b9c0Schristos 
421*e2b1b9c0Schristos 	/*
422*e2b1b9c0Schristos 	 * Start up a new iterator each time.
423*e2b1b9c0Schristos 	 */
424*e2b1b9c0Schristos 	isc_stdtime_get(&now);
425*e2b1b9c0Schristos 	dns_name_init(&foundname, NULL);
426*e2b1b9c0Schristos 	origin = dns_fixedname_initname(&fixedorigin);
427*e2b1b9c0Schristos 
428*e2b1b9c0Schristos  again:
429*e2b1b9c0Schristos 	dns_rbtnodechain_init(&chain, ring->mctx);
430*e2b1b9c0Schristos 	result = dns_rbtnodechain_first(&chain, ring->keys, &foundname,
431*e2b1b9c0Schristos 					origin);
432*e2b1b9c0Schristos 	if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
433*e2b1b9c0Schristos 		dns_rbtnodechain_invalidate(&chain);
434*e2b1b9c0Schristos 		return;
435*e2b1b9c0Schristos 	}
436*e2b1b9c0Schristos 
437*e2b1b9c0Schristos 	for (;;) {
438*e2b1b9c0Schristos 		node = NULL;
439*e2b1b9c0Schristos 		dns_rbtnodechain_current(&chain, &foundname, origin, &node);
440*e2b1b9c0Schristos 		tkey = node->data;
441*e2b1b9c0Schristos 		if (tkey != NULL) {
442*e2b1b9c0Schristos 			if (tkey->generated
443*e2b1b9c0Schristos 			    && isc_refcount_current(&tkey->refs) == 1
444*e2b1b9c0Schristos 			    && tkey->inception != tkey->expire
445*e2b1b9c0Schristos 			    && tkey->expire < now) {
446*e2b1b9c0Schristos 				tsig_log(tkey, 2, "tsig expire: deleting");
447*e2b1b9c0Schristos 				/* delete the key */
448*e2b1b9c0Schristos 				dns_rbtnodechain_invalidate(&chain);
449*e2b1b9c0Schristos 				remove_fromring(tkey);
450*e2b1b9c0Schristos 				goto again;
451*e2b1b9c0Schristos 			}
452*e2b1b9c0Schristos 		}
453*e2b1b9c0Schristos 		result = dns_rbtnodechain_next(&chain, &foundname,
454*e2b1b9c0Schristos 					       origin);
455*e2b1b9c0Schristos 		if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
456*e2b1b9c0Schristos 			dns_rbtnodechain_invalidate(&chain);
457*e2b1b9c0Schristos 			return;
458*e2b1b9c0Schristos 		}
459*e2b1b9c0Schristos 	}
460*e2b1b9c0Schristos }
461*e2b1b9c0Schristos 
462*e2b1b9c0Schristos static void
463*e2b1b9c0Schristos destroyring(dns_tsig_keyring_t *ring) {
464*e2b1b9c0Schristos 	dns_rbt_destroy(&ring->keys);
465*e2b1b9c0Schristos 	isc_rwlock_destroy(&ring->lock);
466*e2b1b9c0Schristos 	isc_mem_putanddetach(&ring->mctx, ring, sizeof(dns_tsig_keyring_t));
467*e2b1b9c0Schristos }
468*e2b1b9c0Schristos 
469*e2b1b9c0Schristos /*
470*e2b1b9c0Schristos  * Look up the DST_ALG_ constant for a given name.
471*e2b1b9c0Schristos  */
472*e2b1b9c0Schristos unsigned int
473*e2b1b9c0Schristos dns__tsig_algfromname(const dns_name_t *algorithm) {
474*e2b1b9c0Schristos 	int i;
475*e2b1b9c0Schristos 	int n = sizeof(known_algs) / sizeof(*known_algs);
476*e2b1b9c0Schristos 	for (i = 0; i < n; ++i) {
477*e2b1b9c0Schristos 		const dns_name_t *name = known_algs[i].name;
478*e2b1b9c0Schristos 		if (algorithm == name || dns_name_equal(algorithm, name)) {
479*e2b1b9c0Schristos 			return (known_algs[i].dstalg);
480*e2b1b9c0Schristos 		}
481*e2b1b9c0Schristos 	}
482*e2b1b9c0Schristos 	return (0);
483*e2b1b9c0Schristos }
484*e2b1b9c0Schristos 
485*e2b1b9c0Schristos /*
486*e2b1b9c0Schristos  * Convert an algorithm name into a pointer to the
487*e2b1b9c0Schristos  * corresponding pre-defined dns_name_t structure.
488*e2b1b9c0Schristos  */
489*e2b1b9c0Schristos const dns_name_t*
490*e2b1b9c0Schristos dns__tsig_algnamefromname(const dns_name_t *algorithm) {
491*e2b1b9c0Schristos 	int i;
492*e2b1b9c0Schristos 	int n = sizeof(known_algs) / sizeof(*known_algs);
493*e2b1b9c0Schristos 	for (i = 0; i < n; ++i) {
494*e2b1b9c0Schristos 		const dns_name_t *name = known_algs[i].name;
495*e2b1b9c0Schristos 		if (algorithm == name || dns_name_equal(algorithm, name)) {
496*e2b1b9c0Schristos 			return (name);
497*e2b1b9c0Schristos 		}
498*e2b1b9c0Schristos 	}
499*e2b1b9c0Schristos 	return (NULL);
500*e2b1b9c0Schristos }
501*e2b1b9c0Schristos 
502*e2b1b9c0Schristos /*
503*e2b1b9c0Schristos  * Test whether the passed algorithm is NOT a pointer to one of the
504*e2b1b9c0Schristos  * pre-defined known algorithms (and therefore one that has been
505*e2b1b9c0Schristos  * dynamically allocated).
506*e2b1b9c0Schristos  *
507*e2b1b9c0Schristos  * This will return an incorrect result if passed a dynamically allocated
508*e2b1b9c0Schristos  * dns_name_t that happens to match one of the pre-defined names.
509*e2b1b9c0Schristos  */
510*e2b1b9c0Schristos isc_boolean_t
511*e2b1b9c0Schristos dns__tsig_algallocated(const dns_name_t *algorithm) {
512*e2b1b9c0Schristos 	int i;
513*e2b1b9c0Schristos 	int n = sizeof(known_algs) / sizeof(*known_algs);
514*e2b1b9c0Schristos 	for (i = 0; i < n; ++i) {
515*e2b1b9c0Schristos 		const dns_name_t *name = known_algs[i].name;
516*e2b1b9c0Schristos 		if (algorithm == name) {
517*e2b1b9c0Schristos 			return (ISC_FALSE);
518*e2b1b9c0Schristos 		}
519*e2b1b9c0Schristos 	}
520*e2b1b9c0Schristos 	return (ISC_TRUE);
521*e2b1b9c0Schristos }
522*e2b1b9c0Schristos 
523*e2b1b9c0Schristos static isc_result_t
524*e2b1b9c0Schristos restore_key(dns_tsig_keyring_t *ring, isc_stdtime_t now, FILE *fp) {
525*e2b1b9c0Schristos 	dst_key_t *dstkey = NULL;
526*e2b1b9c0Schristos 	char namestr[1024];
527*e2b1b9c0Schristos 	char creatorstr[1024];
528*e2b1b9c0Schristos 	char algorithmstr[1024];
529*e2b1b9c0Schristos 	char keystr[4096];
530*e2b1b9c0Schristos 	unsigned int inception, expire;
531*e2b1b9c0Schristos 	int n;
532*e2b1b9c0Schristos 	isc_buffer_t b;
533*e2b1b9c0Schristos 	dns_name_t *name, *creator, *algorithm;
534*e2b1b9c0Schristos 	dns_fixedname_t fname, fcreator, falgorithm;
535*e2b1b9c0Schristos 	isc_result_t result;
536*e2b1b9c0Schristos 	unsigned int dstalg;
537*e2b1b9c0Schristos 
538*e2b1b9c0Schristos 	n = fscanf(fp, "%1023s %1023s %u %u %1023s %4095s\n", namestr,
539*e2b1b9c0Schristos 		   creatorstr, &inception, &expire, algorithmstr, keystr);
540*e2b1b9c0Schristos 	if (n == EOF)
541*e2b1b9c0Schristos 		return (ISC_R_NOMORE);
542*e2b1b9c0Schristos 	if (n != 6)
543*e2b1b9c0Schristos 		return (ISC_R_FAILURE);
544*e2b1b9c0Schristos 
545*e2b1b9c0Schristos 	if (isc_serial_lt(expire, now))
546*e2b1b9c0Schristos 		return (DNS_R_EXPIRED);
547*e2b1b9c0Schristos 
548*e2b1b9c0Schristos 	name = dns_fixedname_initname(&fname);
549*e2b1b9c0Schristos 	isc_buffer_init(&b, namestr, strlen(namestr));
550*e2b1b9c0Schristos 	isc_buffer_add(&b, strlen(namestr));
551*e2b1b9c0Schristos 	result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
552*e2b1b9c0Schristos 	if (result != ISC_R_SUCCESS)
553*e2b1b9c0Schristos 		return (result);
554*e2b1b9c0Schristos 
555*e2b1b9c0Schristos 	creator = dns_fixedname_initname(&fcreator);
556*e2b1b9c0Schristos 	isc_buffer_init(&b, creatorstr, strlen(creatorstr));
557*e2b1b9c0Schristos 	isc_buffer_add(&b, strlen(creatorstr));
558*e2b1b9c0Schristos 	result = dns_name_fromtext(creator, &b, dns_rootname, 0, NULL);
559*e2b1b9c0Schristos 	if (result != ISC_R_SUCCESS)
560*e2b1b9c0Schristos 		return (result);
561*e2b1b9c0Schristos 
562*e2b1b9c0Schristos 	algorithm = dns_fixedname_initname(&falgorithm);
563*e2b1b9c0Schristos 	isc_buffer_init(&b, algorithmstr, strlen(algorithmstr));
564*e2b1b9c0Schristos 	isc_buffer_add(&b, strlen(algorithmstr));
565*e2b1b9c0Schristos 	result = dns_name_fromtext(algorithm, &b, dns_rootname, 0, NULL);
566*e2b1b9c0Schristos 	if (result != ISC_R_SUCCESS)
567*e2b1b9c0Schristos 		return (result);
568*e2b1b9c0Schristos 
569*e2b1b9c0Schristos 	dstalg = dns__tsig_algfromname(algorithm);
570*e2b1b9c0Schristos 	if (dstalg == 0)
571*e2b1b9c0Schristos 		return (DNS_R_BADALG);
572*e2b1b9c0Schristos 
573*e2b1b9c0Schristos 	result = dst_key_restore(name, dstalg, DNS_KEYOWNER_ENTITY,
574*e2b1b9c0Schristos 				 DNS_KEYPROTO_DNSSEC, dns_rdataclass_in,
575*e2b1b9c0Schristos 				 ring->mctx, keystr, &dstkey);
576*e2b1b9c0Schristos 	if (result != ISC_R_SUCCESS)
577*e2b1b9c0Schristos 		return (result);
578*e2b1b9c0Schristos 
579*e2b1b9c0Schristos 	result = dns_tsigkey_createfromkey(name, algorithm, dstkey,
580*e2b1b9c0Schristos 					   ISC_TRUE, creator, inception,
581*e2b1b9c0Schristos 					   expire, ring->mctx, ring, NULL);
582*e2b1b9c0Schristos 	if (dstkey != NULL)
583*e2b1b9c0Schristos 		dst_key_free(&dstkey);
584*e2b1b9c0Schristos 	return (result);
585*e2b1b9c0Schristos }
586*e2b1b9c0Schristos 
587*e2b1b9c0Schristos static void
588*e2b1b9c0Schristos dump_key(dns_tsigkey_t *tkey, FILE *fp) {
589*e2b1b9c0Schristos 	char *buffer = NULL;
590*e2b1b9c0Schristos 	int length = 0;
591*e2b1b9c0Schristos 	char namestr[DNS_NAME_FORMATSIZE];
592*e2b1b9c0Schristos 	char creatorstr[DNS_NAME_FORMATSIZE];
593*e2b1b9c0Schristos 	char algorithmstr[DNS_NAME_FORMATSIZE];
594*e2b1b9c0Schristos 	isc_result_t result;
595*e2b1b9c0Schristos 
596*e2b1b9c0Schristos 	REQUIRE(tkey != NULL);
597*e2b1b9c0Schristos 	REQUIRE(fp != NULL);
598*e2b1b9c0Schristos 
599*e2b1b9c0Schristos 	dns_name_format(&tkey->name, namestr, sizeof(namestr));
600*e2b1b9c0Schristos 	dns_name_format(tkey->creator, creatorstr, sizeof(creatorstr));
601*e2b1b9c0Schristos 	dns_name_format(tkey->algorithm, algorithmstr, sizeof(algorithmstr));
602*e2b1b9c0Schristos 	result = dst_key_dump(tkey->key, tkey->mctx, &buffer, &length);
603*e2b1b9c0Schristos 	if (result == ISC_R_SUCCESS)
604*e2b1b9c0Schristos 		fprintf(fp, "%s %s %u %u %s %.*s\n", namestr, creatorstr,
605*e2b1b9c0Schristos 			tkey->inception, tkey->expire, algorithmstr,
606*e2b1b9c0Schristos 			length, buffer);
607*e2b1b9c0Schristos 	if (buffer != NULL)
608*e2b1b9c0Schristos 		isc_mem_put(tkey->mctx, buffer, length);
609*e2b1b9c0Schristos }
610*e2b1b9c0Schristos 
611*e2b1b9c0Schristos isc_result_t
612*e2b1b9c0Schristos dns_tsigkeyring_dumpanddetach(dns_tsig_keyring_t **ringp, FILE *fp) {
613*e2b1b9c0Schristos 	isc_result_t result;
614*e2b1b9c0Schristos 	dns_rbtnodechain_t chain;
615*e2b1b9c0Schristos 	dns_name_t foundname;
616*e2b1b9c0Schristos 	dns_fixedname_t fixedorigin;
617*e2b1b9c0Schristos 	dns_name_t *origin;
618*e2b1b9c0Schristos 	isc_stdtime_t now;
619*e2b1b9c0Schristos 	dns_rbtnode_t *node;
620*e2b1b9c0Schristos 	dns_tsigkey_t *tkey;
621*e2b1b9c0Schristos 	dns_tsig_keyring_t *ring;
622*e2b1b9c0Schristos 	unsigned int references;
623*e2b1b9c0Schristos 
624*e2b1b9c0Schristos 	REQUIRE(ringp != NULL && *ringp != NULL);
625*e2b1b9c0Schristos 
626*e2b1b9c0Schristos 	ring = *ringp;
627*e2b1b9c0Schristos 	*ringp = NULL;
628*e2b1b9c0Schristos 
629*e2b1b9c0Schristos 	RWLOCK(&ring->lock, isc_rwlocktype_write);
630*e2b1b9c0Schristos 	INSIST(ring->references > 0);
631*e2b1b9c0Schristos 	ring->references--;
632*e2b1b9c0Schristos 	references = ring->references;
633*e2b1b9c0Schristos 	RWUNLOCK(&ring->lock, isc_rwlocktype_write);
634*e2b1b9c0Schristos 
635*e2b1b9c0Schristos 	if (references != 0)
636*e2b1b9c0Schristos 		return (DNS_R_CONTINUE);
637*e2b1b9c0Schristos 
638*e2b1b9c0Schristos 	isc_stdtime_get(&now);
639*e2b1b9c0Schristos 	dns_name_init(&foundname, NULL);
640*e2b1b9c0Schristos 	origin = dns_fixedname_initname(&fixedorigin);
641*e2b1b9c0Schristos 	dns_rbtnodechain_init(&chain, ring->mctx);
642*e2b1b9c0Schristos 	result = dns_rbtnodechain_first(&chain, ring->keys, &foundname,
643*e2b1b9c0Schristos 					origin);
644*e2b1b9c0Schristos 	if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
645*e2b1b9c0Schristos 		dns_rbtnodechain_invalidate(&chain);
646*e2b1b9c0Schristos 		goto destroy;
647*e2b1b9c0Schristos 	}
648*e2b1b9c0Schristos 
649*e2b1b9c0Schristos 	for (;;) {
650*e2b1b9c0Schristos 		node = NULL;
651*e2b1b9c0Schristos 		dns_rbtnodechain_current(&chain, &foundname, origin, &node);
652*e2b1b9c0Schristos 		tkey = node->data;
653*e2b1b9c0Schristos 		if (tkey != NULL && tkey->generated && tkey->expire >= now)
654*e2b1b9c0Schristos 			dump_key(tkey, fp);
655*e2b1b9c0Schristos 		result = dns_rbtnodechain_next(&chain, &foundname,
656*e2b1b9c0Schristos 					       origin);
657*e2b1b9c0Schristos 		if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
658*e2b1b9c0Schristos 			dns_rbtnodechain_invalidate(&chain);
659*e2b1b9c0Schristos 			if (result == ISC_R_NOMORE)
660*e2b1b9c0Schristos 				result = ISC_R_SUCCESS;
661*e2b1b9c0Schristos 			goto destroy;
662*e2b1b9c0Schristos 		}
663*e2b1b9c0Schristos 	}
664*e2b1b9c0Schristos 
665*e2b1b9c0Schristos  destroy:
666*e2b1b9c0Schristos 	destroyring(ring);
667*e2b1b9c0Schristos 	return (result);
668*e2b1b9c0Schristos }
669*e2b1b9c0Schristos 
670*e2b1b9c0Schristos isc_result_t
671*e2b1b9c0Schristos dns_tsigkey_create(const dns_name_t *name, const dns_name_t *algorithm,
672*e2b1b9c0Schristos 		   unsigned char *secret, int length, isc_boolean_t generated,
673*e2b1b9c0Schristos 		   const dns_name_t *creator, isc_stdtime_t inception,
674*e2b1b9c0Schristos 		   isc_stdtime_t expire, isc_mem_t *mctx,
675*e2b1b9c0Schristos 		   dns_tsig_keyring_t *ring, dns_tsigkey_t **key)
676*e2b1b9c0Schristos {
677*e2b1b9c0Schristos 	dst_key_t *dstkey = NULL;
678*e2b1b9c0Schristos 	isc_result_t result;
679*e2b1b9c0Schristos 	unsigned int dstalg = 0;
680*e2b1b9c0Schristos 
681*e2b1b9c0Schristos 	REQUIRE(length >= 0);
682*e2b1b9c0Schristos 	if (length > 0)
683*e2b1b9c0Schristos 		REQUIRE(secret != NULL);
684*e2b1b9c0Schristos 
685*e2b1b9c0Schristos 	dstalg = dns__tsig_algfromname(algorithm);
686*e2b1b9c0Schristos 	if (dns__tsig_algvalid(dstalg)) {
687*e2b1b9c0Schristos 		if (secret != NULL) {
688*e2b1b9c0Schristos 			isc_buffer_t b;
689*e2b1b9c0Schristos 
690*e2b1b9c0Schristos 			isc_buffer_init(&b, secret, length);
691*e2b1b9c0Schristos 			isc_buffer_add(&b, length);
692*e2b1b9c0Schristos 			result = dst_key_frombuffer(name, dstalg,
693*e2b1b9c0Schristos 						    DNS_KEYOWNER_ENTITY,
694*e2b1b9c0Schristos 						    DNS_KEYPROTO_DNSSEC,
695*e2b1b9c0Schristos 						    dns_rdataclass_in,
696*e2b1b9c0Schristos 						    &b, mctx, &dstkey);
697*e2b1b9c0Schristos 			if (result != ISC_R_SUCCESS)
698*e2b1b9c0Schristos 				return (result);
699*e2b1b9c0Schristos 		}
700*e2b1b9c0Schristos 	} else if (length > 0) {
701*e2b1b9c0Schristos 		return (DNS_R_BADALG);
702*e2b1b9c0Schristos 	}
703*e2b1b9c0Schristos 
704*e2b1b9c0Schristos 	result = dns_tsigkey_createfromkey(name, algorithm, dstkey,
705*e2b1b9c0Schristos 					   generated, creator,
706*e2b1b9c0Schristos 					   inception, expire, mctx, ring, key);
707*e2b1b9c0Schristos 	if (dstkey != NULL)
708*e2b1b9c0Schristos 		dst_key_free(&dstkey);
709*e2b1b9c0Schristos 	return (result);
710*e2b1b9c0Schristos }
711*e2b1b9c0Schristos 
712*e2b1b9c0Schristos void
713*e2b1b9c0Schristos dns_tsigkey_attach(dns_tsigkey_t *source, dns_tsigkey_t **targetp) {
714*e2b1b9c0Schristos 	REQUIRE(VALID_TSIG_KEY(source));
715*e2b1b9c0Schristos 	REQUIRE(targetp != NULL && *targetp == NULL);
716*e2b1b9c0Schristos 
717*e2b1b9c0Schristos 	isc_refcount_increment(&source->refs, NULL);
718*e2b1b9c0Schristos 	*targetp = source;
719*e2b1b9c0Schristos }
720*e2b1b9c0Schristos 
721*e2b1b9c0Schristos static void
722*e2b1b9c0Schristos tsigkey_free(dns_tsigkey_t *key) {
723*e2b1b9c0Schristos 	REQUIRE(VALID_TSIG_KEY(key));
724*e2b1b9c0Schristos 
725*e2b1b9c0Schristos 	key->magic = 0;
726*e2b1b9c0Schristos 	dns_name_free(&key->name, key->mctx);
727*e2b1b9c0Schristos 	if (dns__tsig_algallocated(key->algorithm)) {
728*e2b1b9c0Schristos 		dns_name_t *name;
729*e2b1b9c0Schristos 		DE_CONST(key->algorithm, name);
730*e2b1b9c0Schristos 		dns_name_free(name, key->mctx);
731*e2b1b9c0Schristos 		isc_mem_put(key->mctx, name, sizeof(dns_name_t));
732*e2b1b9c0Schristos 	}
733*e2b1b9c0Schristos 	if (key->key != NULL)
734*e2b1b9c0Schristos 		dst_key_free(&key->key);
735*e2b1b9c0Schristos 	if (key->creator != NULL) {
736*e2b1b9c0Schristos 		dns_name_free(key->creator, key->mctx);
737*e2b1b9c0Schristos 		isc_mem_put(key->mctx, key->creator, sizeof(dns_name_t));
738*e2b1b9c0Schristos 	}
739*e2b1b9c0Schristos 	isc_refcount_destroy(&key->refs);
740*e2b1b9c0Schristos 	isc_mem_putanddetach(&key->mctx, key, sizeof(dns_tsigkey_t));
741*e2b1b9c0Schristos }
742*e2b1b9c0Schristos 
743*e2b1b9c0Schristos void
744*e2b1b9c0Schristos dns_tsigkey_detach(dns_tsigkey_t **keyp) {
745*e2b1b9c0Schristos 	dns_tsigkey_t *key;
746*e2b1b9c0Schristos 	unsigned int refs;
747*e2b1b9c0Schristos 
748*e2b1b9c0Schristos 	REQUIRE(keyp != NULL);
749*e2b1b9c0Schristos 	REQUIRE(VALID_TSIG_KEY(*keyp));
750*e2b1b9c0Schristos 
751*e2b1b9c0Schristos 	key = *keyp;
752*e2b1b9c0Schristos 	isc_refcount_decrement(&key->refs, &refs);
753*e2b1b9c0Schristos 
754*e2b1b9c0Schristos 	if (refs == 0)
755*e2b1b9c0Schristos 		tsigkey_free(key);
756*e2b1b9c0Schristos 
757*e2b1b9c0Schristos 	*keyp = NULL;
758*e2b1b9c0Schristos }
759*e2b1b9c0Schristos 
760*e2b1b9c0Schristos void
761*e2b1b9c0Schristos dns_tsigkey_setdeleted(dns_tsigkey_t *key) {
762*e2b1b9c0Schristos 	REQUIRE(VALID_TSIG_KEY(key));
763*e2b1b9c0Schristos 	REQUIRE(key->ring != NULL);
764*e2b1b9c0Schristos 
765*e2b1b9c0Schristos 	RWLOCK(&key->ring->lock, isc_rwlocktype_write);
766*e2b1b9c0Schristos 	remove_fromring(key);
767*e2b1b9c0Schristos 	RWUNLOCK(&key->ring->lock, isc_rwlocktype_write);
768*e2b1b9c0Schristos }
769*e2b1b9c0Schristos 
770*e2b1b9c0Schristos isc_result_t
771*e2b1b9c0Schristos dns_tsig_sign(dns_message_t *msg) {
772*e2b1b9c0Schristos 	dns_tsigkey_t *key;
773*e2b1b9c0Schristos 	dns_rdata_any_tsig_t tsig, querytsig;
774*e2b1b9c0Schristos 	unsigned char data[128];
775*e2b1b9c0Schristos 	isc_buffer_t databuf, sigbuf;
776*e2b1b9c0Schristos 	isc_buffer_t *dynbuf;
777*e2b1b9c0Schristos 	dns_name_t *owner;
778*e2b1b9c0Schristos 	dns_rdata_t *rdata = NULL;
779*e2b1b9c0Schristos 	dns_rdatalist_t *datalist;
780*e2b1b9c0Schristos 	dns_rdataset_t *dataset;
781*e2b1b9c0Schristos 	isc_region_t r;
782*e2b1b9c0Schristos 	isc_stdtime_t now;
783*e2b1b9c0Schristos 	isc_mem_t *mctx;
784*e2b1b9c0Schristos 	dst_context_t *ctx = NULL;
785*e2b1b9c0Schristos 	isc_result_t ret;
786*e2b1b9c0Schristos 	unsigned char badtimedata[BADTIMELEN];
787*e2b1b9c0Schristos 	unsigned int sigsize = 0;
788*e2b1b9c0Schristos 	isc_boolean_t response;
789*e2b1b9c0Schristos 
790*e2b1b9c0Schristos 	REQUIRE(msg != NULL);
791*e2b1b9c0Schristos 	key = dns_message_gettsigkey(msg);
792*e2b1b9c0Schristos 	REQUIRE(VALID_TSIG_KEY(key));
793*e2b1b9c0Schristos 
794*e2b1b9c0Schristos 	/*
795*e2b1b9c0Schristos 	 * If this is a response, there should be a query tsig.
796*e2b1b9c0Schristos 	 */
797*e2b1b9c0Schristos 	response = is_response(msg);
798*e2b1b9c0Schristos 	if (response && msg->querytsig == NULL)
799*e2b1b9c0Schristos 		return (DNS_R_EXPECTEDTSIG);
800*e2b1b9c0Schristos 
801*e2b1b9c0Schristos 	dynbuf = NULL;
802*e2b1b9c0Schristos 
803*e2b1b9c0Schristos 	mctx = msg->mctx;
804*e2b1b9c0Schristos 
805*e2b1b9c0Schristos 	tsig.mctx = mctx;
806*e2b1b9c0Schristos 	tsig.common.rdclass = dns_rdataclass_any;
807*e2b1b9c0Schristos 	tsig.common.rdtype = dns_rdatatype_tsig;
808*e2b1b9c0Schristos 	ISC_LINK_INIT(&tsig.common, link);
809*e2b1b9c0Schristos 	dns_name_init(&tsig.algorithm, NULL);
810*e2b1b9c0Schristos 	dns_name_clone(key->algorithm, &tsig.algorithm);
811*e2b1b9c0Schristos 
812*e2b1b9c0Schristos 	isc_stdtime_get(&now);
813*e2b1b9c0Schristos 	tsig.timesigned = now + msg->timeadjust;
814*e2b1b9c0Schristos 	tsig.fudge = DNS_TSIG_FUDGE;
815*e2b1b9c0Schristos 
816*e2b1b9c0Schristos 	tsig.originalid = msg->id;
817*e2b1b9c0Schristos 
818*e2b1b9c0Schristos 	isc_buffer_init(&databuf, data, sizeof(data));
819*e2b1b9c0Schristos 
820*e2b1b9c0Schristos 	if (response)
821*e2b1b9c0Schristos 		tsig.error = msg->querytsigstatus;
822*e2b1b9c0Schristos 	else
823*e2b1b9c0Schristos 		tsig.error = dns_rcode_noerror;
824*e2b1b9c0Schristos 
825*e2b1b9c0Schristos 	if (tsig.error != dns_tsigerror_badtime) {
826*e2b1b9c0Schristos 		tsig.otherlen = 0;
827*e2b1b9c0Schristos 		tsig.other = NULL;
828*e2b1b9c0Schristos 	} else {
829*e2b1b9c0Schristos 		isc_buffer_t otherbuf;
830*e2b1b9c0Schristos 
831*e2b1b9c0Schristos 		tsig.otherlen = BADTIMELEN;
832*e2b1b9c0Schristos 		tsig.other = badtimedata;
833*e2b1b9c0Schristos 		isc_buffer_init(&otherbuf, tsig.other, tsig.otherlen);
834*e2b1b9c0Schristos 		isc_buffer_putuint48(&otherbuf, tsig.timesigned);
835*e2b1b9c0Schristos 	}
836*e2b1b9c0Schristos 
837*e2b1b9c0Schristos 	if ((key->key != NULL) &&
838*e2b1b9c0Schristos 	    (tsig.error != dns_tsigerror_badsig) &&
839*e2b1b9c0Schristos 	    (tsig.error != dns_tsigerror_badkey))
840*e2b1b9c0Schristos 	{
841*e2b1b9c0Schristos 		unsigned char header[DNS_MESSAGE_HEADERLEN];
842*e2b1b9c0Schristos 		isc_buffer_t headerbuf;
843*e2b1b9c0Schristos 		isc_uint16_t digestbits;
844*e2b1b9c0Schristos 
845*e2b1b9c0Schristos 		/*
846*e2b1b9c0Schristos 		 * If it is a response, we assume that the request MAC
847*e2b1b9c0Schristos 		 * has validated at this point. This is why we include a
848*e2b1b9c0Schristos 		 * MAC length > 0 in the reply.
849*e2b1b9c0Schristos 		 */
850*e2b1b9c0Schristos 		ret = dst_context_create3(key->key, mctx,
851*e2b1b9c0Schristos 					  DNS_LOGCATEGORY_DNSSEC,
852*e2b1b9c0Schristos 					  ISC_TRUE, &ctx);
853*e2b1b9c0Schristos 		if (ret != ISC_R_SUCCESS)
854*e2b1b9c0Schristos 			return (ret);
855*e2b1b9c0Schristos 
856*e2b1b9c0Schristos 		/*
857*e2b1b9c0Schristos 		 * If this is a response, digest the request's MAC.
858*e2b1b9c0Schristos 		 */
859*e2b1b9c0Schristos 		if (response) {
860*e2b1b9c0Schristos 			dns_rdata_t querytsigrdata = DNS_RDATA_INIT;
861*e2b1b9c0Schristos 
862*e2b1b9c0Schristos 			INSIST(msg->verified_sig);
863*e2b1b9c0Schristos 
864*e2b1b9c0Schristos 			ret = dns_rdataset_first(msg->querytsig);
865*e2b1b9c0Schristos 			if (ret != ISC_R_SUCCESS)
866*e2b1b9c0Schristos 				goto cleanup_context;
867*e2b1b9c0Schristos 			dns_rdataset_current(msg->querytsig, &querytsigrdata);
868*e2b1b9c0Schristos 			ret = dns_rdata_tostruct(&querytsigrdata, &querytsig,
869*e2b1b9c0Schristos 						 NULL);
870*e2b1b9c0Schristos 			if (ret != ISC_R_SUCCESS)
871*e2b1b9c0Schristos 				goto cleanup_context;
872*e2b1b9c0Schristos 			isc_buffer_putuint16(&databuf, querytsig.siglen);
873*e2b1b9c0Schristos 			if (isc_buffer_availablelength(&databuf) <
874*e2b1b9c0Schristos 			    querytsig.siglen) {
875*e2b1b9c0Schristos 				ret = ISC_R_NOSPACE;
876*e2b1b9c0Schristos 				goto cleanup_context;
877*e2b1b9c0Schristos 			}
878*e2b1b9c0Schristos 			isc_buffer_putmem(&databuf, querytsig.signature,
879*e2b1b9c0Schristos 					  querytsig.siglen);
880*e2b1b9c0Schristos 			isc_buffer_usedregion(&databuf, &r);
881*e2b1b9c0Schristos 			ret = dst_context_adddata(ctx, &r);
882*e2b1b9c0Schristos 			if (ret != ISC_R_SUCCESS)
883*e2b1b9c0Schristos 				goto cleanup_context;
884*e2b1b9c0Schristos 		}
885*e2b1b9c0Schristos #if defined(__clang__)  && \
886*e2b1b9c0Schristos        ( __clang_major__ < 3 || \
887*e2b1b9c0Schristos 	(__clang_major__ == 3 && __clang_minor__ < 2) || \
888*e2b1b9c0Schristos 	(__clang_major__ == 4 && __clang_minor__ < 2))
889*e2b1b9c0Schristos 	/* false positive: http://llvm.org/bugs/show_bug.cgi?id=14461 */
890*e2b1b9c0Schristos 		else memset(&querytsig, 0, sizeof(querytsig));
891*e2b1b9c0Schristos #endif
892*e2b1b9c0Schristos 
893*e2b1b9c0Schristos 		/*
894*e2b1b9c0Schristos 		 * Digest the header.
895*e2b1b9c0Schristos 		 */
896*e2b1b9c0Schristos 		isc_buffer_init(&headerbuf, header, sizeof(header));
897*e2b1b9c0Schristos 		dns_message_renderheader(msg, &headerbuf);
898*e2b1b9c0Schristos 		isc_buffer_usedregion(&headerbuf, &r);
899*e2b1b9c0Schristos 		ret = dst_context_adddata(ctx, &r);
900*e2b1b9c0Schristos 		if (ret != ISC_R_SUCCESS)
901*e2b1b9c0Schristos 			goto cleanup_context;
902*e2b1b9c0Schristos 
903*e2b1b9c0Schristos 		/*
904*e2b1b9c0Schristos 		 * Digest the remainder of the message.
905*e2b1b9c0Schristos 		 */
906*e2b1b9c0Schristos 		isc_buffer_usedregion(msg->buffer, &r);
907*e2b1b9c0Schristos 		isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
908*e2b1b9c0Schristos 		ret = dst_context_adddata(ctx, &r);
909*e2b1b9c0Schristos 		if (ret != ISC_R_SUCCESS)
910*e2b1b9c0Schristos 			goto cleanup_context;
911*e2b1b9c0Schristos 
912*e2b1b9c0Schristos 		if (msg->tcp_continuation == 0) {
913*e2b1b9c0Schristos 			/*
914*e2b1b9c0Schristos 			 * Digest the name, class, ttl, alg.
915*e2b1b9c0Schristos 			 */
916*e2b1b9c0Schristos 			dns_name_toregion(&key->name, &r);
917*e2b1b9c0Schristos 			ret = dst_context_adddata(ctx, &r);
918*e2b1b9c0Schristos 			if (ret != ISC_R_SUCCESS)
919*e2b1b9c0Schristos 				goto cleanup_context;
920*e2b1b9c0Schristos 
921*e2b1b9c0Schristos 			isc_buffer_clear(&databuf);
922*e2b1b9c0Schristos 			isc_buffer_putuint16(&databuf, dns_rdataclass_any);
923*e2b1b9c0Schristos 			isc_buffer_putuint32(&databuf, 0); /* ttl */
924*e2b1b9c0Schristos 			isc_buffer_usedregion(&databuf, &r);
925*e2b1b9c0Schristos 			ret = dst_context_adddata(ctx, &r);
926*e2b1b9c0Schristos 			if (ret != ISC_R_SUCCESS)
927*e2b1b9c0Schristos 				goto cleanup_context;
928*e2b1b9c0Schristos 
929*e2b1b9c0Schristos 			dns_name_toregion(&tsig.algorithm, &r);
930*e2b1b9c0Schristos 			ret = dst_context_adddata(ctx, &r);
931*e2b1b9c0Schristos 			if (ret != ISC_R_SUCCESS)
932*e2b1b9c0Schristos 				goto cleanup_context;
933*e2b1b9c0Schristos 
934*e2b1b9c0Schristos 		}
935*e2b1b9c0Schristos 		/* Digest the timesigned and fudge */
936*e2b1b9c0Schristos 		isc_buffer_clear(&databuf);
937*e2b1b9c0Schristos 		if (tsig.error == dns_tsigerror_badtime) {
938*e2b1b9c0Schristos 			INSIST(response);
939*e2b1b9c0Schristos 			tsig.timesigned = querytsig.timesigned;
940*e2b1b9c0Schristos 		}
941*e2b1b9c0Schristos 		isc_buffer_putuint48(&databuf, tsig.timesigned);
942*e2b1b9c0Schristos 		isc_buffer_putuint16(&databuf, tsig.fudge);
943*e2b1b9c0Schristos 		isc_buffer_usedregion(&databuf, &r);
944*e2b1b9c0Schristos 		ret = dst_context_adddata(ctx, &r);
945*e2b1b9c0Schristos 		if (ret != ISC_R_SUCCESS)
946*e2b1b9c0Schristos 			goto cleanup_context;
947*e2b1b9c0Schristos 
948*e2b1b9c0Schristos 		if (msg->tcp_continuation == 0) {
949*e2b1b9c0Schristos 			/*
950*e2b1b9c0Schristos 			 * Digest the error and other data length.
951*e2b1b9c0Schristos 			 */
952*e2b1b9c0Schristos 			isc_buffer_clear(&databuf);
953*e2b1b9c0Schristos 			isc_buffer_putuint16(&databuf, tsig.error);
954*e2b1b9c0Schristos 			isc_buffer_putuint16(&databuf, tsig.otherlen);
955*e2b1b9c0Schristos 
956*e2b1b9c0Schristos 			isc_buffer_usedregion(&databuf, &r);
957*e2b1b9c0Schristos 			ret = dst_context_adddata(ctx, &r);
958*e2b1b9c0Schristos 			if (ret != ISC_R_SUCCESS)
959*e2b1b9c0Schristos 				goto cleanup_context;
960*e2b1b9c0Schristos 
961*e2b1b9c0Schristos 			/*
962*e2b1b9c0Schristos 			 * Digest other data.
963*e2b1b9c0Schristos 			 */
964*e2b1b9c0Schristos 			if (tsig.otherlen > 0) {
965*e2b1b9c0Schristos 				r.length = tsig.otherlen;
966*e2b1b9c0Schristos 				r.base = tsig.other;
967*e2b1b9c0Schristos 				ret = dst_context_adddata(ctx, &r);
968*e2b1b9c0Schristos 				if (ret != ISC_R_SUCCESS)
969*e2b1b9c0Schristos 					goto cleanup_context;
970*e2b1b9c0Schristos 			}
971*e2b1b9c0Schristos 		}
972*e2b1b9c0Schristos 
973*e2b1b9c0Schristos 		ret = dst_key_sigsize(key->key, &sigsize);
974*e2b1b9c0Schristos 		if (ret != ISC_R_SUCCESS)
975*e2b1b9c0Schristos 			goto cleanup_context;
976*e2b1b9c0Schristos 		tsig.signature = (unsigned char *) isc_mem_get(mctx, sigsize);
977*e2b1b9c0Schristos 		if (tsig.signature == NULL) {
978*e2b1b9c0Schristos 			ret = ISC_R_NOMEMORY;
979*e2b1b9c0Schristos 			goto cleanup_context;
980*e2b1b9c0Schristos 		}
981*e2b1b9c0Schristos 
982*e2b1b9c0Schristos 		isc_buffer_init(&sigbuf, tsig.signature, sigsize);
983*e2b1b9c0Schristos 		ret = dst_context_sign(ctx, &sigbuf);
984*e2b1b9c0Schristos 		if (ret != ISC_R_SUCCESS)
985*e2b1b9c0Schristos 			goto cleanup_signature;
986*e2b1b9c0Schristos 		dst_context_destroy(&ctx);
987*e2b1b9c0Schristos 		digestbits = dst_key_getbits(key->key);
988*e2b1b9c0Schristos 		if (digestbits != 0) {
989*e2b1b9c0Schristos 			/*
990*e2b1b9c0Schristos 			 * XXXRAY: Is this correct? What is the
991*e2b1b9c0Schristos 			 * expected behavior when digestbits is not an
992*e2b1b9c0Schristos 			 * integral multiple of 8? It looks like bytes
993*e2b1b9c0Schristos 			 * should either be (digestbits/8) or
994*e2b1b9c0Schristos 			 * (digestbits+7)/8.
995*e2b1b9c0Schristos 			 *
996*e2b1b9c0Schristos 			 * In any case, for current algorithms,
997*e2b1b9c0Schristos 			 * digestbits are an integral multiple of 8, so
998*e2b1b9c0Schristos 			 * it has the same effect as (digestbits/8).
999*e2b1b9c0Schristos 			 */
1000*e2b1b9c0Schristos 			unsigned int bytes = (digestbits + 1) / 8;
1001*e2b1b9c0Schristos 			if (response && bytes < querytsig.siglen)
1002*e2b1b9c0Schristos 				bytes = querytsig.siglen;
1003*e2b1b9c0Schristos 			if (bytes > isc_buffer_usedlength(&sigbuf))
1004*e2b1b9c0Schristos 				bytes = isc_buffer_usedlength(&sigbuf);
1005*e2b1b9c0Schristos 			tsig.siglen = bytes;
1006*e2b1b9c0Schristos 		} else
1007*e2b1b9c0Schristos 			tsig.siglen = isc_buffer_usedlength(&sigbuf);
1008*e2b1b9c0Schristos 	} else {
1009*e2b1b9c0Schristos 		tsig.siglen = 0;
1010*e2b1b9c0Schristos 		tsig.signature = NULL;
1011*e2b1b9c0Schristos 	}
1012*e2b1b9c0Schristos 
1013*e2b1b9c0Schristos 	ret = dns_message_gettemprdata(msg, &rdata);
1014*e2b1b9c0Schristos 	if (ret != ISC_R_SUCCESS)
1015*e2b1b9c0Schristos 		goto cleanup_signature;
1016*e2b1b9c0Schristos 	ret = isc_buffer_allocate(msg->mctx, &dynbuf, 512);
1017*e2b1b9c0Schristos 	if (ret != ISC_R_SUCCESS)
1018*e2b1b9c0Schristos 		goto cleanup_rdata;
1019*e2b1b9c0Schristos 	ret = dns_rdata_fromstruct(rdata, dns_rdataclass_any,
1020*e2b1b9c0Schristos 				   dns_rdatatype_tsig, &tsig, dynbuf);
1021*e2b1b9c0Schristos 	if (ret != ISC_R_SUCCESS)
1022*e2b1b9c0Schristos 		goto cleanup_dynbuf;
1023*e2b1b9c0Schristos 
1024*e2b1b9c0Schristos 	dns_message_takebuffer(msg, &dynbuf);
1025*e2b1b9c0Schristos 
1026*e2b1b9c0Schristos 	if (tsig.signature != NULL) {
1027*e2b1b9c0Schristos 		isc_mem_put(mctx, tsig.signature, sigsize);
1028*e2b1b9c0Schristos 		tsig.signature = NULL;
1029*e2b1b9c0Schristos 	}
1030*e2b1b9c0Schristos 
1031*e2b1b9c0Schristos 	owner = NULL;
1032*e2b1b9c0Schristos 	ret = dns_message_gettempname(msg, &owner);
1033*e2b1b9c0Schristos 	if (ret != ISC_R_SUCCESS)
1034*e2b1b9c0Schristos 		goto cleanup_rdata;
1035*e2b1b9c0Schristos 	dns_name_init(owner, NULL);
1036*e2b1b9c0Schristos 	ret = dns_name_dup(&key->name, msg->mctx, owner);
1037*e2b1b9c0Schristos 	if (ret != ISC_R_SUCCESS)
1038*e2b1b9c0Schristos 		goto cleanup_owner;
1039*e2b1b9c0Schristos 
1040*e2b1b9c0Schristos 	datalist = NULL;
1041*e2b1b9c0Schristos 	ret = dns_message_gettemprdatalist(msg, &datalist);
1042*e2b1b9c0Schristos 	if (ret != ISC_R_SUCCESS)
1043*e2b1b9c0Schristos 		goto cleanup_owner;
1044*e2b1b9c0Schristos 	dataset = NULL;
1045*e2b1b9c0Schristos 	ret = dns_message_gettemprdataset(msg, &dataset);
1046*e2b1b9c0Schristos 	if (ret != ISC_R_SUCCESS)
1047*e2b1b9c0Schristos 		goto cleanup_rdatalist;
1048*e2b1b9c0Schristos 	datalist->rdclass = dns_rdataclass_any;
1049*e2b1b9c0Schristos 	datalist->type = dns_rdatatype_tsig;
1050*e2b1b9c0Schristos 	ISC_LIST_APPEND(datalist->rdata, rdata, link);
1051*e2b1b9c0Schristos 	RUNTIME_CHECK(dns_rdatalist_tordataset(datalist, dataset)
1052*e2b1b9c0Schristos 		      == ISC_R_SUCCESS);
1053*e2b1b9c0Schristos 	msg->tsig = dataset;
1054*e2b1b9c0Schristos 	msg->tsigname = owner;
1055*e2b1b9c0Schristos 
1056*e2b1b9c0Schristos 	/* Windows does not like the tsig name being compressed. */
1057*e2b1b9c0Schristos 	msg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
1058*e2b1b9c0Schristos 
1059*e2b1b9c0Schristos 	return (ISC_R_SUCCESS);
1060*e2b1b9c0Schristos 
1061*e2b1b9c0Schristos  cleanup_rdatalist:
1062*e2b1b9c0Schristos 	dns_message_puttemprdatalist(msg, &datalist);
1063*e2b1b9c0Schristos  cleanup_owner:
1064*e2b1b9c0Schristos 	dns_message_puttempname(msg, &owner);
1065*e2b1b9c0Schristos 	goto cleanup_rdata;
1066*e2b1b9c0Schristos  cleanup_dynbuf:
1067*e2b1b9c0Schristos 	isc_buffer_free(&dynbuf);
1068*e2b1b9c0Schristos  cleanup_rdata:
1069*e2b1b9c0Schristos 	dns_message_puttemprdata(msg, &rdata);
1070*e2b1b9c0Schristos  cleanup_signature:
1071*e2b1b9c0Schristos 	if (tsig.signature != NULL)
1072*e2b1b9c0Schristos 		isc_mem_put(mctx, tsig.signature, sigsize);
1073*e2b1b9c0Schristos  cleanup_context:
1074*e2b1b9c0Schristos 	if (ctx != NULL)
1075*e2b1b9c0Schristos 		dst_context_destroy(&ctx);
1076*e2b1b9c0Schristos 	return (ret);
1077*e2b1b9c0Schristos }
1078*e2b1b9c0Schristos 
1079*e2b1b9c0Schristos isc_result_t
1080*e2b1b9c0Schristos dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
1081*e2b1b9c0Schristos 		dns_tsig_keyring_t *ring1, dns_tsig_keyring_t *ring2)
1082*e2b1b9c0Schristos {
1083*e2b1b9c0Schristos 	dns_rdata_any_tsig_t tsig, querytsig;
1084*e2b1b9c0Schristos 	isc_region_t r, source_r, header_r, sig_r;
1085*e2b1b9c0Schristos 	isc_buffer_t databuf;
1086*e2b1b9c0Schristos 	unsigned char data[32];
1087*e2b1b9c0Schristos 	dns_name_t *keyname;
1088*e2b1b9c0Schristos 	dns_rdata_t rdata = DNS_RDATA_INIT;
1089*e2b1b9c0Schristos 	isc_stdtime_t now;
1090*e2b1b9c0Schristos 	isc_result_t ret;
1091*e2b1b9c0Schristos 	dns_tsigkey_t *tsigkey;
1092*e2b1b9c0Schristos 	dst_key_t *key = NULL;
1093*e2b1b9c0Schristos 	unsigned char header[DNS_MESSAGE_HEADERLEN];
1094*e2b1b9c0Schristos 	dst_context_t *ctx = NULL;
1095*e2b1b9c0Schristos 	isc_mem_t *mctx;
1096*e2b1b9c0Schristos 	isc_uint16_t addcount, id;
1097*e2b1b9c0Schristos 	unsigned int siglen;
1098*e2b1b9c0Schristos 	unsigned int alg;
1099*e2b1b9c0Schristos 	isc_boolean_t response;
1100*e2b1b9c0Schristos 
1101*e2b1b9c0Schristos 	REQUIRE(source != NULL);
1102*e2b1b9c0Schristos 	REQUIRE(DNS_MESSAGE_VALID(msg));
1103*e2b1b9c0Schristos 	tsigkey = dns_message_gettsigkey(msg);
1104*e2b1b9c0Schristos 	response = is_response(msg);
1105*e2b1b9c0Schristos 
1106*e2b1b9c0Schristos 	REQUIRE(tsigkey == NULL || VALID_TSIG_KEY(tsigkey));
1107*e2b1b9c0Schristos 
1108*e2b1b9c0Schristos 	msg->verify_attempted = 1;
1109*e2b1b9c0Schristos 	msg->verified_sig = 0;
1110*e2b1b9c0Schristos 	msg->tsigstatus = dns_tsigerror_badsig;
1111*e2b1b9c0Schristos 
1112*e2b1b9c0Schristos 	if (msg->tcp_continuation) {
1113*e2b1b9c0Schristos 		if (tsigkey == NULL || msg->querytsig == NULL)
1114*e2b1b9c0Schristos 			return (DNS_R_UNEXPECTEDTSIG);
1115*e2b1b9c0Schristos 		return (tsig_verify_tcp(source, msg));
1116*e2b1b9c0Schristos 	}
1117*e2b1b9c0Schristos 
1118*e2b1b9c0Schristos 	/*
1119*e2b1b9c0Schristos 	 * There should be a TSIG record...
1120*e2b1b9c0Schristos 	 */
1121*e2b1b9c0Schristos 	if (msg->tsig == NULL)
1122*e2b1b9c0Schristos 		return (DNS_R_EXPECTEDTSIG);
1123*e2b1b9c0Schristos 
1124*e2b1b9c0Schristos 	/*
1125*e2b1b9c0Schristos 	 * If this is a response and there's no key or query TSIG, there
1126*e2b1b9c0Schristos 	 * shouldn't be one on the response.
1127*e2b1b9c0Schristos 	 */
1128*e2b1b9c0Schristos 	if (response && (tsigkey == NULL || msg->querytsig == NULL))
1129*e2b1b9c0Schristos 		return (DNS_R_UNEXPECTEDTSIG);
1130*e2b1b9c0Schristos 
1131*e2b1b9c0Schristos 	mctx = msg->mctx;
1132*e2b1b9c0Schristos 
1133*e2b1b9c0Schristos 	/*
1134*e2b1b9c0Schristos 	 * If we're here, we know the message is well formed and contains a
1135*e2b1b9c0Schristos 	 * TSIG record.
1136*e2b1b9c0Schristos 	 */
1137*e2b1b9c0Schristos 
1138*e2b1b9c0Schristos 	keyname = msg->tsigname;
1139*e2b1b9c0Schristos 	ret = dns_rdataset_first(msg->tsig);
1140*e2b1b9c0Schristos 	if (ret != ISC_R_SUCCESS)
1141*e2b1b9c0Schristos 		return (ret);
1142*e2b1b9c0Schristos 	dns_rdataset_current(msg->tsig, &rdata);
1143*e2b1b9c0Schristos 	ret = dns_rdata_tostruct(&rdata, &tsig, NULL);
1144*e2b1b9c0Schristos 	if (ret != ISC_R_SUCCESS)
1145*e2b1b9c0Schristos 		return (ret);
1146*e2b1b9c0Schristos 	dns_rdata_reset(&rdata);
1147*e2b1b9c0Schristos 	if (response) {
1148*e2b1b9c0Schristos 		ret = dns_rdataset_first(msg->querytsig);
1149*e2b1b9c0Schristos 		if (ret != ISC_R_SUCCESS)
1150*e2b1b9c0Schristos 			return (ret);
1151*e2b1b9c0Schristos 		dns_rdataset_current(msg->querytsig, &rdata);
1152*e2b1b9c0Schristos 		ret = dns_rdata_tostruct(&rdata, &querytsig, NULL);
1153*e2b1b9c0Schristos 		if (ret != ISC_R_SUCCESS)
1154*e2b1b9c0Schristos 			return (ret);
1155*e2b1b9c0Schristos 	}
1156*e2b1b9c0Schristos #if defined(__clang__) && \
1157*e2b1b9c0Schristos        ( __clang_major__ < 3 || \
1158*e2b1b9c0Schristos 	(__clang_major__ == 3 && __clang_minor__ < 2) || \
1159*e2b1b9c0Schristos 	(__clang_major__ == 4 && __clang_minor__ < 2))
1160*e2b1b9c0Schristos 	/* false positive: http://llvm.org/bugs/show_bug.cgi?id=14461 */
1161*e2b1b9c0Schristos 		else memset(&querytsig, 0, sizeof(querytsig));
1162*e2b1b9c0Schristos #endif
1163*e2b1b9c0Schristos 
1164*e2b1b9c0Schristos 	/*
1165*e2b1b9c0Schristos 	 * Do the key name and algorithm match that of the query?
1166*e2b1b9c0Schristos 	 */
1167*e2b1b9c0Schristos 	if (response &&
1168*e2b1b9c0Schristos 	    (!dns_name_equal(keyname, &tsigkey->name) ||
1169*e2b1b9c0Schristos 	     !dns_name_equal(&tsig.algorithm, &querytsig.algorithm))) {
1170*e2b1b9c0Schristos 		msg->tsigstatus = dns_tsigerror_badkey;
1171*e2b1b9c0Schristos 		tsig_log(msg->tsigkey, 2,
1172*e2b1b9c0Schristos 			 "key name and algorithm do not match");
1173*e2b1b9c0Schristos 		return (DNS_R_TSIGVERIFYFAILURE);
1174*e2b1b9c0Schristos 	}
1175*e2b1b9c0Schristos 
1176*e2b1b9c0Schristos 	/*
1177*e2b1b9c0Schristos 	 * Get the current time.
1178*e2b1b9c0Schristos 	 */
1179*e2b1b9c0Schristos 	isc_stdtime_get(&now);
1180*e2b1b9c0Schristos 
1181*e2b1b9c0Schristos 	/*
1182*e2b1b9c0Schristos 	 * Find dns_tsigkey_t based on keyname.
1183*e2b1b9c0Schristos 	 */
1184*e2b1b9c0Schristos 	if (tsigkey == NULL) {
1185*e2b1b9c0Schristos 		ret = ISC_R_NOTFOUND;
1186*e2b1b9c0Schristos 		if (ring1 != NULL)
1187*e2b1b9c0Schristos 			ret = dns_tsigkey_find(&tsigkey, keyname,
1188*e2b1b9c0Schristos 					       &tsig.algorithm, ring1);
1189*e2b1b9c0Schristos 		if (ret == ISC_R_NOTFOUND && ring2 != NULL)
1190*e2b1b9c0Schristos 			ret = dns_tsigkey_find(&tsigkey, keyname,
1191*e2b1b9c0Schristos 					       &tsig.algorithm, ring2);
1192*e2b1b9c0Schristos 		if (ret != ISC_R_SUCCESS) {
1193*e2b1b9c0Schristos 			msg->tsigstatus = dns_tsigerror_badkey;
1194*e2b1b9c0Schristos 			ret = dns_tsigkey_create(keyname, &tsig.algorithm,
1195*e2b1b9c0Schristos 						 NULL, 0, ISC_FALSE, NULL,
1196*e2b1b9c0Schristos 						 now, now,
1197*e2b1b9c0Schristos 						 mctx, NULL, &msg->tsigkey);
1198*e2b1b9c0Schristos 			if (ret != ISC_R_SUCCESS)
1199*e2b1b9c0Schristos 				return (ret);
1200*e2b1b9c0Schristos 			tsig_log(msg->tsigkey, 2, "unknown key");
1201*e2b1b9c0Schristos 			return (DNS_R_TSIGVERIFYFAILURE);
1202*e2b1b9c0Schristos 		}
1203*e2b1b9c0Schristos 		msg->tsigkey = tsigkey;
1204*e2b1b9c0Schristos 	}
1205*e2b1b9c0Schristos 
1206*e2b1b9c0Schristos 	key = tsigkey->key;
1207*e2b1b9c0Schristos 
1208*e2b1b9c0Schristos 	/*
1209*e2b1b9c0Schristos 	 * Check digest length.
1210*e2b1b9c0Schristos 	 */
1211*e2b1b9c0Schristos 	alg = dst_key_alg(key);
1212*e2b1b9c0Schristos 	ret = dst_key_sigsize(key, &siglen);
1213*e2b1b9c0Schristos 	if (ret != ISC_R_SUCCESS)
1214*e2b1b9c0Schristos 		return (ret);
1215*e2b1b9c0Schristos 	if (dns__tsig_algvalid(alg)) {
1216*e2b1b9c0Schristos 		if (tsig.siglen > siglen) {
1217*e2b1b9c0Schristos 			tsig_log(msg->tsigkey, 2, "signature length too big");
1218*e2b1b9c0Schristos 			return (DNS_R_FORMERR);
1219*e2b1b9c0Schristos 		}
1220*e2b1b9c0Schristos 		if (tsig.siglen > 0 &&
1221*e2b1b9c0Schristos 		    (tsig.siglen < 10 || tsig.siglen < ((siglen + 1) / 2)))
1222*e2b1b9c0Schristos 		{
1223*e2b1b9c0Schristos 			tsig_log(msg->tsigkey, 2,
1224*e2b1b9c0Schristos 				 "signature length below minimum");
1225*e2b1b9c0Schristos 			return (DNS_R_FORMERR);
1226*e2b1b9c0Schristos 		}
1227*e2b1b9c0Schristos 	}
1228*e2b1b9c0Schristos 
1229*e2b1b9c0Schristos 	if (tsig.siglen > 0) {
1230*e2b1b9c0Schristos 		isc_uint16_t addcount_n;
1231*e2b1b9c0Schristos 
1232*e2b1b9c0Schristos 		sig_r.base = tsig.signature;
1233*e2b1b9c0Schristos 		sig_r.length = tsig.siglen;
1234*e2b1b9c0Schristos 
1235*e2b1b9c0Schristos 		ret = dst_context_create3(key, mctx,
1236*e2b1b9c0Schristos 					  DNS_LOGCATEGORY_DNSSEC,
1237*e2b1b9c0Schristos 					  ISC_FALSE, &ctx);
1238*e2b1b9c0Schristos 		if (ret != ISC_R_SUCCESS)
1239*e2b1b9c0Schristos 			return (ret);
1240*e2b1b9c0Schristos 
1241*e2b1b9c0Schristos 		if (response) {
1242*e2b1b9c0Schristos 			isc_buffer_init(&databuf, data, sizeof(data));
1243*e2b1b9c0Schristos 			isc_buffer_putuint16(&databuf, querytsig.siglen);
1244*e2b1b9c0Schristos 			isc_buffer_usedregion(&databuf, &r);
1245*e2b1b9c0Schristos 			ret = dst_context_adddata(ctx, &r);
1246*e2b1b9c0Schristos 			if (ret != ISC_R_SUCCESS)
1247*e2b1b9c0Schristos 				goto cleanup_context;
1248*e2b1b9c0Schristos 			if (querytsig.siglen > 0) {
1249*e2b1b9c0Schristos 				r.length = querytsig.siglen;
1250*e2b1b9c0Schristos 				r.base = querytsig.signature;
1251*e2b1b9c0Schristos 				ret = dst_context_adddata(ctx, &r);
1252*e2b1b9c0Schristos 				if (ret != ISC_R_SUCCESS)
1253*e2b1b9c0Schristos 					goto cleanup_context;
1254*e2b1b9c0Schristos 			}
1255*e2b1b9c0Schristos 		}
1256*e2b1b9c0Schristos 
1257*e2b1b9c0Schristos 		/*
1258*e2b1b9c0Schristos 		 * Extract the header.
1259*e2b1b9c0Schristos 		 */
1260*e2b1b9c0Schristos 		isc_buffer_usedregion(source, &r);
1261*e2b1b9c0Schristos 		memmove(header, r.base, DNS_MESSAGE_HEADERLEN);
1262*e2b1b9c0Schristos 		isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
1263*e2b1b9c0Schristos 
1264*e2b1b9c0Schristos 		/*
1265*e2b1b9c0Schristos 		 * Decrement the additional field counter.
1266*e2b1b9c0Schristos 		 */
1267*e2b1b9c0Schristos 		memmove(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
1268*e2b1b9c0Schristos 		addcount_n = ntohs(addcount);
1269*e2b1b9c0Schristos 		addcount = htons((isc_uint16_t)(addcount_n - 1));
1270*e2b1b9c0Schristos 		memmove(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);
1271*e2b1b9c0Schristos 
1272*e2b1b9c0Schristos 		/*
1273*e2b1b9c0Schristos 		 * Put in the original id.
1274*e2b1b9c0Schristos 		 */
1275*e2b1b9c0Schristos 		id = htons(tsig.originalid);
1276*e2b1b9c0Schristos 		memmove(&header[0], &id, 2);
1277*e2b1b9c0Schristos 
1278*e2b1b9c0Schristos 		/*
1279*e2b1b9c0Schristos 		 * Digest the modified header.
1280*e2b1b9c0Schristos 		 */
1281*e2b1b9c0Schristos 		header_r.base = (unsigned char *) header;
1282*e2b1b9c0Schristos 		header_r.length = DNS_MESSAGE_HEADERLEN;
1283*e2b1b9c0Schristos 		ret = dst_context_adddata(ctx, &header_r);
1284*e2b1b9c0Schristos 		if (ret != ISC_R_SUCCESS)
1285*e2b1b9c0Schristos 			goto cleanup_context;
1286*e2b1b9c0Schristos 
1287*e2b1b9c0Schristos 		/*
1288*e2b1b9c0Schristos 		 * Digest all non-TSIG records.
1289*e2b1b9c0Schristos 		 */
1290*e2b1b9c0Schristos 		isc_buffer_usedregion(source, &source_r);
1291*e2b1b9c0Schristos 		r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
1292*e2b1b9c0Schristos 		r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN;
1293*e2b1b9c0Schristos 		ret = dst_context_adddata(ctx, &r);
1294*e2b1b9c0Schristos 		if (ret != ISC_R_SUCCESS)
1295*e2b1b9c0Schristos 			goto cleanup_context;
1296*e2b1b9c0Schristos 
1297*e2b1b9c0Schristos 		/*
1298*e2b1b9c0Schristos 		 * Digest the key name.
1299*e2b1b9c0Schristos 		 */
1300*e2b1b9c0Schristos 		dns_name_toregion(&tsigkey->name, &r);
1301*e2b1b9c0Schristos 		ret = dst_context_adddata(ctx, &r);
1302*e2b1b9c0Schristos 		if (ret != ISC_R_SUCCESS)
1303*e2b1b9c0Schristos 			goto cleanup_context;
1304*e2b1b9c0Schristos 
1305*e2b1b9c0Schristos 		isc_buffer_init(&databuf, data, sizeof(data));
1306*e2b1b9c0Schristos 		isc_buffer_putuint16(&databuf, tsig.common.rdclass);
1307*e2b1b9c0Schristos 		isc_buffer_putuint32(&databuf, msg->tsig->ttl);
1308*e2b1b9c0Schristos 		isc_buffer_usedregion(&databuf, &r);
1309*e2b1b9c0Schristos 		ret = dst_context_adddata(ctx, &r);
1310*e2b1b9c0Schristos 		if (ret != ISC_R_SUCCESS)
1311*e2b1b9c0Schristos 			goto cleanup_context;
1312*e2b1b9c0Schristos 
1313*e2b1b9c0Schristos 		/*
1314*e2b1b9c0Schristos 		 * Digest the key algorithm.
1315*e2b1b9c0Schristos 		 */
1316*e2b1b9c0Schristos 		dns_name_toregion(tsigkey->algorithm, &r);
1317*e2b1b9c0Schristos 		ret = dst_context_adddata(ctx, &r);
1318*e2b1b9c0Schristos 		if (ret != ISC_R_SUCCESS)
1319*e2b1b9c0Schristos 			goto cleanup_context;
1320*e2b1b9c0Schristos 
1321*e2b1b9c0Schristos 		isc_buffer_clear(&databuf);
1322*e2b1b9c0Schristos 		isc_buffer_putuint48(&databuf, tsig.timesigned);
1323*e2b1b9c0Schristos 		isc_buffer_putuint16(&databuf, tsig.fudge);
1324*e2b1b9c0Schristos 		isc_buffer_putuint16(&databuf, tsig.error);
1325*e2b1b9c0Schristos 		isc_buffer_putuint16(&databuf, tsig.otherlen);
1326*e2b1b9c0Schristos 		isc_buffer_usedregion(&databuf, &r);
1327*e2b1b9c0Schristos 		ret = dst_context_adddata(ctx, &r);
1328*e2b1b9c0Schristos 		if (ret != ISC_R_SUCCESS)
1329*e2b1b9c0Schristos 			goto cleanup_context;
1330*e2b1b9c0Schristos 
1331*e2b1b9c0Schristos 		if (tsig.otherlen > 0) {
1332*e2b1b9c0Schristos 			r.base = tsig.other;
1333*e2b1b9c0Schristos 			r.length = tsig.otherlen;
1334*e2b1b9c0Schristos 			ret = dst_context_adddata(ctx, &r);
1335*e2b1b9c0Schristos 			if (ret != ISC_R_SUCCESS)
1336*e2b1b9c0Schristos 				goto cleanup_context;
1337*e2b1b9c0Schristos 		}
1338*e2b1b9c0Schristos 
1339*e2b1b9c0Schristos 		ret = dst_context_verify(ctx, &sig_r);
1340*e2b1b9c0Schristos 		if (ret == DST_R_VERIFYFAILURE) {
1341*e2b1b9c0Schristos 			ret = DNS_R_TSIGVERIFYFAILURE;
1342*e2b1b9c0Schristos 			tsig_log(msg->tsigkey, 2,
1343*e2b1b9c0Schristos 				 "signature failed to verify(1)");
1344*e2b1b9c0Schristos 			goto cleanup_context;
1345*e2b1b9c0Schristos 		} else if (ret != ISC_R_SUCCESS) {
1346*e2b1b9c0Schristos 			goto cleanup_context;
1347*e2b1b9c0Schristos 		}
1348*e2b1b9c0Schristos 		msg->verified_sig = 1;
1349*e2b1b9c0Schristos 	} else if (tsig.error != dns_tsigerror_badsig &&
1350*e2b1b9c0Schristos 		   tsig.error != dns_tsigerror_badkey) {
1351*e2b1b9c0Schristos 		tsig_log(msg->tsigkey, 2, "signature was empty");
1352*e2b1b9c0Schristos 		return (DNS_R_TSIGVERIFYFAILURE);
1353*e2b1b9c0Schristos 	}
1354*e2b1b9c0Schristos 
1355*e2b1b9c0Schristos 	/*
1356*e2b1b9c0Schristos 	 * Here at this point, the MAC has been verified. Even if any of
1357*e2b1b9c0Schristos 	 * the following code returns a TSIG error, the reply will be
1358*e2b1b9c0Schristos 	 * signed and WILL always include the request MAC in the digest
1359*e2b1b9c0Schristos 	 * computation.
1360*e2b1b9c0Schristos 	 */
1361*e2b1b9c0Schristos 
1362*e2b1b9c0Schristos 	/*
1363*e2b1b9c0Schristos 	 * Is the time ok?
1364*e2b1b9c0Schristos 	 */
1365*e2b1b9c0Schristos 	if (now + msg->timeadjust > tsig.timesigned + tsig.fudge) {
1366*e2b1b9c0Schristos 		msg->tsigstatus = dns_tsigerror_badtime;
1367*e2b1b9c0Schristos 		tsig_log(msg->tsigkey, 2, "signature has expired");
1368*e2b1b9c0Schristos 		ret = DNS_R_CLOCKSKEW;
1369*e2b1b9c0Schristos 		goto cleanup_context;
1370*e2b1b9c0Schristos 	} else if (now + msg->timeadjust < tsig.timesigned - tsig.fudge) {
1371*e2b1b9c0Schristos 		msg->tsigstatus = dns_tsigerror_badtime;
1372*e2b1b9c0Schristos 		tsig_log(msg->tsigkey, 2, "signature is in the future");
1373*e2b1b9c0Schristos 		ret = DNS_R_CLOCKSKEW;
1374*e2b1b9c0Schristos 		goto cleanup_context;
1375*e2b1b9c0Schristos 	}
1376*e2b1b9c0Schristos 
1377*e2b1b9c0Schristos 	if (dns__tsig_algvalid(alg)) {
1378*e2b1b9c0Schristos 		isc_uint16_t digestbits = dst_key_getbits(key);
1379*e2b1b9c0Schristos 
1380*e2b1b9c0Schristos 		/*
1381*e2b1b9c0Schristos 		 * XXXRAY: Is this correct? What is the expected
1382*e2b1b9c0Schristos 		 * behavior when digestbits is not an integral multiple
1383*e2b1b9c0Schristos 		 * of 8? It looks like bytes should either be
1384*e2b1b9c0Schristos 		 * (digestbits/8) or (digestbits+7)/8.
1385*e2b1b9c0Schristos 		 *
1386*e2b1b9c0Schristos 		 * In any case, for current algorithms, digestbits are
1387*e2b1b9c0Schristos 		 * an integral multiple of 8, so it has the same effect
1388*e2b1b9c0Schristos 		 * as (digestbits/8).
1389*e2b1b9c0Schristos 		 */
1390*e2b1b9c0Schristos 		if (tsig.siglen > 0 && digestbits != 0 &&
1391*e2b1b9c0Schristos 		    tsig.siglen < ((digestbits + 1) / 8))
1392*e2b1b9c0Schristos 		{
1393*e2b1b9c0Schristos 			msg->tsigstatus = dns_tsigerror_badtrunc;
1394*e2b1b9c0Schristos 			tsig_log(msg->tsigkey, 2,
1395*e2b1b9c0Schristos 				 "truncated signature length too small");
1396*e2b1b9c0Schristos 			ret = DNS_R_TSIGVERIFYFAILURE;
1397*e2b1b9c0Schristos 			goto cleanup_context;
1398*e2b1b9c0Schristos 		}
1399*e2b1b9c0Schristos 		if (tsig.siglen > 0 && digestbits == 0 &&
1400*e2b1b9c0Schristos 		    tsig.siglen < siglen)
1401*e2b1b9c0Schristos 		{
1402*e2b1b9c0Schristos 			msg->tsigstatus = dns_tsigerror_badtrunc;
1403*e2b1b9c0Schristos 			tsig_log(msg->tsigkey, 2, "signature length too small");
1404*e2b1b9c0Schristos 			ret = DNS_R_TSIGVERIFYFAILURE;
1405*e2b1b9c0Schristos 			goto cleanup_context;
1406*e2b1b9c0Schristos 		}
1407*e2b1b9c0Schristos 	}
1408*e2b1b9c0Schristos 
1409*e2b1b9c0Schristos 	if (tsig.error != dns_rcode_noerror) {
1410*e2b1b9c0Schristos 		msg->tsigstatus = tsig.error;
1411*e2b1b9c0Schristos 		if (tsig.error == dns_tsigerror_badtime)
1412*e2b1b9c0Schristos 			ret = DNS_R_CLOCKSKEW;
1413*e2b1b9c0Schristos 		else
1414*e2b1b9c0Schristos 			ret = DNS_R_TSIGERRORSET;
1415*e2b1b9c0Schristos 		goto cleanup_context;
1416*e2b1b9c0Schristos 	}
1417*e2b1b9c0Schristos 
1418*e2b1b9c0Schristos 	msg->tsigstatus = dns_rcode_noerror;
1419*e2b1b9c0Schristos 	ret = ISC_R_SUCCESS;
1420*e2b1b9c0Schristos 
1421*e2b1b9c0Schristos  cleanup_context:
1422*e2b1b9c0Schristos 	if (ctx != NULL)
1423*e2b1b9c0Schristos 		dst_context_destroy(&ctx);
1424*e2b1b9c0Schristos 
1425*e2b1b9c0Schristos 	return (ret);
1426*e2b1b9c0Schristos }
1427*e2b1b9c0Schristos 
1428*e2b1b9c0Schristos static isc_result_t
1429*e2b1b9c0Schristos tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) {
1430*e2b1b9c0Schristos 	dns_rdata_any_tsig_t tsig, querytsig;
1431*e2b1b9c0Schristos 	isc_region_t r, source_r, header_r, sig_r;
1432*e2b1b9c0Schristos 	isc_buffer_t databuf;
1433*e2b1b9c0Schristos 	unsigned char data[32];
1434*e2b1b9c0Schristos 	dns_name_t *keyname;
1435*e2b1b9c0Schristos 	dns_rdata_t rdata = DNS_RDATA_INIT;
1436*e2b1b9c0Schristos 	isc_stdtime_t now;
1437*e2b1b9c0Schristos 	isc_result_t ret;
1438*e2b1b9c0Schristos 	dns_tsigkey_t *tsigkey;
1439*e2b1b9c0Schristos 	dst_key_t *key = NULL;
1440*e2b1b9c0Schristos 	unsigned char header[DNS_MESSAGE_HEADERLEN];
1441*e2b1b9c0Schristos 	isc_uint16_t addcount, id;
1442*e2b1b9c0Schristos 	isc_boolean_t has_tsig = ISC_FALSE;
1443*e2b1b9c0Schristos 	isc_mem_t *mctx;
1444*e2b1b9c0Schristos 	unsigned int siglen;
1445*e2b1b9c0Schristos 	unsigned int alg;
1446*e2b1b9c0Schristos 
1447*e2b1b9c0Schristos 	REQUIRE(source != NULL);
1448*e2b1b9c0Schristos 	REQUIRE(msg != NULL);
1449*e2b1b9c0Schristos 	REQUIRE(dns_message_gettsigkey(msg) != NULL);
1450*e2b1b9c0Schristos 	REQUIRE(msg->tcp_continuation == 1);
1451*e2b1b9c0Schristos 	REQUIRE(msg->querytsig != NULL);
1452*e2b1b9c0Schristos 
1453*e2b1b9c0Schristos 	msg->verified_sig = 0;
1454*e2b1b9c0Schristos 	msg->tsigstatus = dns_tsigerror_badsig;
1455*e2b1b9c0Schristos 
1456*e2b1b9c0Schristos 	if (!is_response(msg))
1457*e2b1b9c0Schristos 		return (DNS_R_EXPECTEDRESPONSE);
1458*e2b1b9c0Schristos 
1459*e2b1b9c0Schristos 	mctx = msg->mctx;
1460*e2b1b9c0Schristos 
1461*e2b1b9c0Schristos 	tsigkey = dns_message_gettsigkey(msg);
1462*e2b1b9c0Schristos 	key = tsigkey->key;
1463*e2b1b9c0Schristos 
1464*e2b1b9c0Schristos 	/*
1465*e2b1b9c0Schristos 	 * Extract and parse the previous TSIG
1466*e2b1b9c0Schristos 	 */
1467*e2b1b9c0Schristos 	ret = dns_rdataset_first(msg->querytsig);
1468*e2b1b9c0Schristos 	if (ret != ISC_R_SUCCESS)
1469*e2b1b9c0Schristos 		return (ret);
1470*e2b1b9c0Schristos 	dns_rdataset_current(msg->querytsig, &rdata);
1471*e2b1b9c0Schristos 	ret = dns_rdata_tostruct(&rdata, &querytsig, NULL);
1472*e2b1b9c0Schristos 	if (ret != ISC_R_SUCCESS)
1473*e2b1b9c0Schristos 		return (ret);
1474*e2b1b9c0Schristos 	dns_rdata_reset(&rdata);
1475*e2b1b9c0Schristos 
1476*e2b1b9c0Schristos 	/*
1477*e2b1b9c0Schristos 	 * If there is a TSIG in this message, do some checks.
1478*e2b1b9c0Schristos 	 */
1479*e2b1b9c0Schristos 	if (msg->tsig != NULL) {
1480*e2b1b9c0Schristos 		has_tsig = ISC_TRUE;
1481*e2b1b9c0Schristos 
1482*e2b1b9c0Schristos 		keyname = msg->tsigname;
1483*e2b1b9c0Schristos 		ret = dns_rdataset_first(msg->tsig);
1484*e2b1b9c0Schristos 		if (ret != ISC_R_SUCCESS)
1485*e2b1b9c0Schristos 			goto cleanup_querystruct;
1486*e2b1b9c0Schristos 		dns_rdataset_current(msg->tsig, &rdata);
1487*e2b1b9c0Schristos 		ret = dns_rdata_tostruct(&rdata, &tsig, NULL);
1488*e2b1b9c0Schristos 		if (ret != ISC_R_SUCCESS)
1489*e2b1b9c0Schristos 			goto cleanup_querystruct;
1490*e2b1b9c0Schristos 
1491*e2b1b9c0Schristos 		/*
1492*e2b1b9c0Schristos 		 * Do the key name and algorithm match that of the query?
1493*e2b1b9c0Schristos 		 */
1494*e2b1b9c0Schristos 		if (!dns_name_equal(keyname, &tsigkey->name) ||
1495*e2b1b9c0Schristos 		    !dns_name_equal(&tsig.algorithm, &querytsig.algorithm))
1496*e2b1b9c0Schristos 		{
1497*e2b1b9c0Schristos 			msg->tsigstatus = dns_tsigerror_badkey;
1498*e2b1b9c0Schristos 			ret = DNS_R_TSIGVERIFYFAILURE;
1499*e2b1b9c0Schristos 			tsig_log(msg->tsigkey, 2,
1500*e2b1b9c0Schristos 				 "key name and algorithm do not match");
1501*e2b1b9c0Schristos 			goto cleanup_querystruct;
1502*e2b1b9c0Schristos 		}
1503*e2b1b9c0Schristos 
1504*e2b1b9c0Schristos 		/*
1505*e2b1b9c0Schristos 		 * Check digest length.
1506*e2b1b9c0Schristos 		 */
1507*e2b1b9c0Schristos 		alg = dst_key_alg(key);
1508*e2b1b9c0Schristos 		ret = dst_key_sigsize(key, &siglen);
1509*e2b1b9c0Schristos 		if (ret != ISC_R_SUCCESS)
1510*e2b1b9c0Schristos 			goto cleanup_querystruct;
1511*e2b1b9c0Schristos 		if (dns__tsig_algvalid(alg)) {
1512*e2b1b9c0Schristos 			if (tsig.siglen > siglen) {
1513*e2b1b9c0Schristos 				tsig_log(tsigkey, 2,
1514*e2b1b9c0Schristos 					 "signature length too big");
1515*e2b1b9c0Schristos 				ret = DNS_R_FORMERR;
1516*e2b1b9c0Schristos 				goto cleanup_querystruct;
1517*e2b1b9c0Schristos 			}
1518*e2b1b9c0Schristos 			if (tsig.siglen > 0 &&
1519*e2b1b9c0Schristos 			    (tsig.siglen < 10 ||
1520*e2b1b9c0Schristos 			     tsig.siglen < ((siglen + 1) / 2)))
1521*e2b1b9c0Schristos 			{
1522*e2b1b9c0Schristos 				tsig_log(tsigkey, 2,
1523*e2b1b9c0Schristos 					 "signature length below minimum");
1524*e2b1b9c0Schristos 				ret = DNS_R_FORMERR;
1525*e2b1b9c0Schristos 				goto cleanup_querystruct;
1526*e2b1b9c0Schristos 			}
1527*e2b1b9c0Schristos 		}
1528*e2b1b9c0Schristos 	}
1529*e2b1b9c0Schristos 
1530*e2b1b9c0Schristos 	if (msg->tsigctx == NULL) {
1531*e2b1b9c0Schristos 		ret = dst_context_create3(key, mctx,
1532*e2b1b9c0Schristos 					  DNS_LOGCATEGORY_DNSSEC,
1533*e2b1b9c0Schristos 					  ISC_FALSE, &msg->tsigctx);
1534*e2b1b9c0Schristos 		if (ret != ISC_R_SUCCESS)
1535*e2b1b9c0Schristos 			goto cleanup_querystruct;
1536*e2b1b9c0Schristos 
1537*e2b1b9c0Schristos 		/*
1538*e2b1b9c0Schristos 		 * Digest the length of the query signature
1539*e2b1b9c0Schristos 		 */
1540*e2b1b9c0Schristos 		isc_buffer_init(&databuf, data, sizeof(data));
1541*e2b1b9c0Schristos 		isc_buffer_putuint16(&databuf, querytsig.siglen);
1542*e2b1b9c0Schristos 		isc_buffer_usedregion(&databuf, &r);
1543*e2b1b9c0Schristos 		ret = dst_context_adddata(msg->tsigctx, &r);
1544*e2b1b9c0Schristos 		if (ret != ISC_R_SUCCESS)
1545*e2b1b9c0Schristos 			goto cleanup_context;
1546*e2b1b9c0Schristos 
1547*e2b1b9c0Schristos 		/*
1548*e2b1b9c0Schristos 		 * Digest the data of the query signature
1549*e2b1b9c0Schristos 		 */
1550*e2b1b9c0Schristos 		if (querytsig.siglen > 0) {
1551*e2b1b9c0Schristos 			r.length = querytsig.siglen;
1552*e2b1b9c0Schristos 			r.base = querytsig.signature;
1553*e2b1b9c0Schristos 			ret = dst_context_adddata(msg->tsigctx, &r);
1554*e2b1b9c0Schristos 			if (ret != ISC_R_SUCCESS)
1555*e2b1b9c0Schristos 				goto cleanup_context;
1556*e2b1b9c0Schristos 		}
1557*e2b1b9c0Schristos 	}
1558*e2b1b9c0Schristos 
1559*e2b1b9c0Schristos 	/*
1560*e2b1b9c0Schristos 	 * Extract the header.
1561*e2b1b9c0Schristos 	 */
1562*e2b1b9c0Schristos 	isc_buffer_usedregion(source, &r);
1563*e2b1b9c0Schristos 	memmove(header, r.base, DNS_MESSAGE_HEADERLEN);
1564*e2b1b9c0Schristos 	isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
1565*e2b1b9c0Schristos 
1566*e2b1b9c0Schristos 	/*
1567*e2b1b9c0Schristos 	 * Decrement the additional field counter if necessary.
1568*e2b1b9c0Schristos 	 */
1569*e2b1b9c0Schristos 	if (has_tsig) {
1570*e2b1b9c0Schristos 		isc_uint16_t addcount_n;
1571*e2b1b9c0Schristos 
1572*e2b1b9c0Schristos 		memmove(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
1573*e2b1b9c0Schristos 		addcount_n = ntohs(addcount);
1574*e2b1b9c0Schristos 		addcount = htons((isc_uint16_t)(addcount_n - 1));
1575*e2b1b9c0Schristos 		memmove(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);
1576*e2b1b9c0Schristos 
1577*e2b1b9c0Schristos 		/*
1578*e2b1b9c0Schristos 		 * Put in the original id.
1579*e2b1b9c0Schristos 		 *
1580*e2b1b9c0Schristos 		 * XXX Can TCP transfers be forwarded?  How would that
1581*e2b1b9c0Schristos 		 * work?
1582*e2b1b9c0Schristos 		 */
1583*e2b1b9c0Schristos 		id = htons(tsig.originalid);
1584*e2b1b9c0Schristos 		memmove(&header[0], &id, 2);
1585*e2b1b9c0Schristos 	}
1586*e2b1b9c0Schristos 
1587*e2b1b9c0Schristos 	/*
1588*e2b1b9c0Schristos 	 * Digest the modified header.
1589*e2b1b9c0Schristos 	 */
1590*e2b1b9c0Schristos 	header_r.base = (unsigned char *) header;
1591*e2b1b9c0Schristos 	header_r.length = DNS_MESSAGE_HEADERLEN;
1592*e2b1b9c0Schristos 	ret = dst_context_adddata(msg->tsigctx, &header_r);
1593*e2b1b9c0Schristos 	if (ret != ISC_R_SUCCESS)
1594*e2b1b9c0Schristos 		goto cleanup_context;
1595*e2b1b9c0Schristos 
1596*e2b1b9c0Schristos 	/*
1597*e2b1b9c0Schristos 	 * Digest all non-TSIG records.
1598*e2b1b9c0Schristos 	 */
1599*e2b1b9c0Schristos 	isc_buffer_usedregion(source, &source_r);
1600*e2b1b9c0Schristos 	r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
1601*e2b1b9c0Schristos 	if (has_tsig)
1602*e2b1b9c0Schristos 		r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN;
1603*e2b1b9c0Schristos 	else
1604*e2b1b9c0Schristos 		r.length = source_r.length - DNS_MESSAGE_HEADERLEN;
1605*e2b1b9c0Schristos 	ret = dst_context_adddata(msg->tsigctx, &r);
1606*e2b1b9c0Schristos 	if (ret != ISC_R_SUCCESS)
1607*e2b1b9c0Schristos 		goto cleanup_context;
1608*e2b1b9c0Schristos 
1609*e2b1b9c0Schristos 	/*
1610*e2b1b9c0Schristos 	 * Digest the time signed and fudge.
1611*e2b1b9c0Schristos 	 */
1612*e2b1b9c0Schristos 	if (has_tsig) {
1613*e2b1b9c0Schristos 		isc_buffer_init(&databuf, data, sizeof(data));
1614*e2b1b9c0Schristos 		isc_buffer_putuint48(&databuf, tsig.timesigned);
1615*e2b1b9c0Schristos 		isc_buffer_putuint16(&databuf, tsig.fudge);
1616*e2b1b9c0Schristos 		isc_buffer_usedregion(&databuf, &r);
1617*e2b1b9c0Schristos 		ret = dst_context_adddata(msg->tsigctx, &r);
1618*e2b1b9c0Schristos 		if (ret != ISC_R_SUCCESS)
1619*e2b1b9c0Schristos 			goto cleanup_context;
1620*e2b1b9c0Schristos 
1621*e2b1b9c0Schristos 		sig_r.base = tsig.signature;
1622*e2b1b9c0Schristos 		sig_r.length = tsig.siglen;
1623*e2b1b9c0Schristos 		if (tsig.siglen == 0) {
1624*e2b1b9c0Schristos 			if (tsig.error != dns_rcode_noerror) {
1625*e2b1b9c0Schristos 				msg->tsigstatus = tsig.error;
1626*e2b1b9c0Schristos 				if (tsig.error == dns_tsigerror_badtime) {
1627*e2b1b9c0Schristos 					ret = DNS_R_CLOCKSKEW;
1628*e2b1b9c0Schristos 				} else {
1629*e2b1b9c0Schristos 					ret = DNS_R_TSIGERRORSET;
1630*e2b1b9c0Schristos 				}
1631*e2b1b9c0Schristos 			} else {
1632*e2b1b9c0Schristos 				tsig_log(msg->tsigkey, 2,
1633*e2b1b9c0Schristos 					 "signature is empty");
1634*e2b1b9c0Schristos 				ret = DNS_R_TSIGVERIFYFAILURE;
1635*e2b1b9c0Schristos 			}
1636*e2b1b9c0Schristos 			goto cleanup_context;
1637*e2b1b9c0Schristos 		}
1638*e2b1b9c0Schristos 
1639*e2b1b9c0Schristos 		ret = dst_context_verify(msg->tsigctx, &sig_r);
1640*e2b1b9c0Schristos 		if (ret == DST_R_VERIFYFAILURE) {
1641*e2b1b9c0Schristos 			tsig_log(msg->tsigkey, 2,
1642*e2b1b9c0Schristos 				 "signature failed to verify(2)");
1643*e2b1b9c0Schristos 			ret = DNS_R_TSIGVERIFYFAILURE;
1644*e2b1b9c0Schristos 			goto cleanup_context;
1645*e2b1b9c0Schristos 		} else if (ret != ISC_R_SUCCESS) {
1646*e2b1b9c0Schristos 			goto cleanup_context;
1647*e2b1b9c0Schristos 		}
1648*e2b1b9c0Schristos 		msg->verified_sig = 1;
1649*e2b1b9c0Schristos 
1650*e2b1b9c0Schristos 		/*
1651*e2b1b9c0Schristos 		 * Here at this point, the MAC has been verified. Even
1652*e2b1b9c0Schristos 		 * if any of the following code returns a TSIG error,
1653*e2b1b9c0Schristos 		 * the reply will be signed and WILL always include the
1654*e2b1b9c0Schristos 		 * request MAC in the digest computation.
1655*e2b1b9c0Schristos 		 */
1656*e2b1b9c0Schristos 
1657*e2b1b9c0Schristos 		/*
1658*e2b1b9c0Schristos 		 * Is the time ok?
1659*e2b1b9c0Schristos 		 */
1660*e2b1b9c0Schristos 		isc_stdtime_get(&now);
1661*e2b1b9c0Schristos 
1662*e2b1b9c0Schristos 		if (now + msg->timeadjust > tsig.timesigned + tsig.fudge) {
1663*e2b1b9c0Schristos 			msg->tsigstatus = dns_tsigerror_badtime;
1664*e2b1b9c0Schristos 			tsig_log(msg->tsigkey, 2, "signature has expired");
1665*e2b1b9c0Schristos 			ret = DNS_R_CLOCKSKEW;
1666*e2b1b9c0Schristos 			goto cleanup_context;
1667*e2b1b9c0Schristos 		} else if (now + msg->timeadjust <
1668*e2b1b9c0Schristos 			   tsig.timesigned - tsig.fudge)
1669*e2b1b9c0Schristos 		{
1670*e2b1b9c0Schristos 			msg->tsigstatus = dns_tsigerror_badtime;
1671*e2b1b9c0Schristos 			tsig_log(msg->tsigkey, 2,
1672*e2b1b9c0Schristos 				 "signature is in the future");
1673*e2b1b9c0Schristos 			ret = DNS_R_CLOCKSKEW;
1674*e2b1b9c0Schristos 			goto cleanup_context;
1675*e2b1b9c0Schristos 		}
1676*e2b1b9c0Schristos 
1677*e2b1b9c0Schristos 		alg = dst_key_alg(key);
1678*e2b1b9c0Schristos 		ret = dst_key_sigsize(key, &siglen);
1679*e2b1b9c0Schristos 		if (ret != ISC_R_SUCCESS)
1680*e2b1b9c0Schristos 			goto cleanup_context;
1681*e2b1b9c0Schristos 		if (dns__tsig_algvalid(alg)) {
1682*e2b1b9c0Schristos 			isc_uint16_t digestbits = dst_key_getbits(key);
1683*e2b1b9c0Schristos 
1684*e2b1b9c0Schristos 			/*
1685*e2b1b9c0Schristos 			 * XXXRAY: Is this correct? What is the
1686*e2b1b9c0Schristos 			 * expected behavior when digestbits is not an
1687*e2b1b9c0Schristos 			 * integral multiple of 8? It looks like bytes
1688*e2b1b9c0Schristos 			 * should either be (digestbits/8) or
1689*e2b1b9c0Schristos 			 * (digestbits+7)/8.
1690*e2b1b9c0Schristos 			 *
1691*e2b1b9c0Schristos 			 * In any case, for current algorithms,
1692*e2b1b9c0Schristos 			 * digestbits are an integral multiple of 8, so
1693*e2b1b9c0Schristos 			 * it has the same effect as (digestbits/8).
1694*e2b1b9c0Schristos 			 */
1695*e2b1b9c0Schristos 			if (tsig.siglen > 0 && digestbits != 0 &&
1696*e2b1b9c0Schristos 			    tsig.siglen < ((digestbits + 1) / 8))
1697*e2b1b9c0Schristos 			{
1698*e2b1b9c0Schristos 				msg->tsigstatus = dns_tsigerror_badtrunc;
1699*e2b1b9c0Schristos 				tsig_log(msg->tsigkey, 2,
1700*e2b1b9c0Schristos 					 "truncated signature length "
1701*e2b1b9c0Schristos 					 "too small");
1702*e2b1b9c0Schristos 				ret = DNS_R_TSIGVERIFYFAILURE;
1703*e2b1b9c0Schristos 				goto cleanup_context;
1704*e2b1b9c0Schristos 			}
1705*e2b1b9c0Schristos 			if (tsig.siglen > 0 && digestbits == 0 &&
1706*e2b1b9c0Schristos 			    tsig.siglen < siglen)
1707*e2b1b9c0Schristos 			{
1708*e2b1b9c0Schristos 				msg->tsigstatus = dns_tsigerror_badtrunc;
1709*e2b1b9c0Schristos 				tsig_log(msg->tsigkey, 2,
1710*e2b1b9c0Schristos 					 "signature length too small");
1711*e2b1b9c0Schristos 				ret = DNS_R_TSIGVERIFYFAILURE;
1712*e2b1b9c0Schristos 				goto cleanup_context;
1713*e2b1b9c0Schristos 			}
1714*e2b1b9c0Schristos 		}
1715*e2b1b9c0Schristos 
1716*e2b1b9c0Schristos 		if (tsig.error != dns_rcode_noerror) {
1717*e2b1b9c0Schristos 			msg->tsigstatus = tsig.error;
1718*e2b1b9c0Schristos 			if (tsig.error == dns_tsigerror_badtime)
1719*e2b1b9c0Schristos 				ret = DNS_R_CLOCKSKEW;
1720*e2b1b9c0Schristos 			else
1721*e2b1b9c0Schristos 				ret = DNS_R_TSIGERRORSET;
1722*e2b1b9c0Schristos 			goto cleanup_context;
1723*e2b1b9c0Schristos 		}
1724*e2b1b9c0Schristos 	}
1725*e2b1b9c0Schristos 
1726*e2b1b9c0Schristos 	msg->tsigstatus = dns_rcode_noerror;
1727*e2b1b9c0Schristos 	ret = ISC_R_SUCCESS;
1728*e2b1b9c0Schristos 
1729*e2b1b9c0Schristos  cleanup_context:
1730*e2b1b9c0Schristos 	/*
1731*e2b1b9c0Schristos 	 * Except in error conditions, don't destroy the DST context
1732*e2b1b9c0Schristos 	 * for unsigned messages; it is a running sum till the next
1733*e2b1b9c0Schristos 	 * TSIG signed message.
1734*e2b1b9c0Schristos 	 */
1735*e2b1b9c0Schristos 	if ((ret != ISC_R_SUCCESS || has_tsig) && msg->tsigctx != NULL) {
1736*e2b1b9c0Schristos 		dst_context_destroy(&msg->tsigctx);
1737*e2b1b9c0Schristos 	}
1738*e2b1b9c0Schristos 
1739*e2b1b9c0Schristos  cleanup_querystruct:
1740*e2b1b9c0Schristos 	dns_rdata_freestruct(&querytsig);
1741*e2b1b9c0Schristos 
1742*e2b1b9c0Schristos 	return (ret);
1743*e2b1b9c0Schristos }
1744*e2b1b9c0Schristos 
1745*e2b1b9c0Schristos isc_result_t
1746*e2b1b9c0Schristos dns_tsigkey_find(dns_tsigkey_t **tsigkey, const dns_name_t *name,
1747*e2b1b9c0Schristos 		 const dns_name_t *algorithm, dns_tsig_keyring_t *ring)
1748*e2b1b9c0Schristos {
1749*e2b1b9c0Schristos 	dns_tsigkey_t *key;
1750*e2b1b9c0Schristos 	isc_stdtime_t now;
1751*e2b1b9c0Schristos 	isc_result_t result;
1752*e2b1b9c0Schristos 
1753*e2b1b9c0Schristos 	REQUIRE(tsigkey != NULL);
1754*e2b1b9c0Schristos 	REQUIRE(*tsigkey == NULL);
1755*e2b1b9c0Schristos 	REQUIRE(name != NULL);
1756*e2b1b9c0Schristos 	REQUIRE(ring != NULL);
1757*e2b1b9c0Schristos 
1758*e2b1b9c0Schristos 	RWLOCK(&ring->lock, isc_rwlocktype_write);
1759*e2b1b9c0Schristos 	cleanup_ring(ring);
1760*e2b1b9c0Schristos 	RWUNLOCK(&ring->lock, isc_rwlocktype_write);
1761*e2b1b9c0Schristos 
1762*e2b1b9c0Schristos 	isc_stdtime_get(&now);
1763*e2b1b9c0Schristos 	RWLOCK(&ring->lock, isc_rwlocktype_read);
1764*e2b1b9c0Schristos 	key = NULL;
1765*e2b1b9c0Schristos 	result = dns_rbt_findname(ring->keys, name, 0, NULL, (void *)&key);
1766*e2b1b9c0Schristos 	if (result == DNS_R_PARTIALMATCH || result == ISC_R_NOTFOUND) {
1767*e2b1b9c0Schristos 		RWUNLOCK(&ring->lock, isc_rwlocktype_read);
1768*e2b1b9c0Schristos 		return (ISC_R_NOTFOUND);
1769*e2b1b9c0Schristos 	}
1770*e2b1b9c0Schristos 	if (algorithm != NULL && !dns_name_equal(key->algorithm, algorithm)) {
1771*e2b1b9c0Schristos 		RWUNLOCK(&ring->lock, isc_rwlocktype_read);
1772*e2b1b9c0Schristos 		return (ISC_R_NOTFOUND);
1773*e2b1b9c0Schristos 	}
1774*e2b1b9c0Schristos 	if (key->inception != key->expire && isc_serial_lt(key->expire, now)) {
1775*e2b1b9c0Schristos 		/*
1776*e2b1b9c0Schristos 		 * The key has expired.
1777*e2b1b9c0Schristos 		 */
1778*e2b1b9c0Schristos 		RWUNLOCK(&ring->lock, isc_rwlocktype_read);
1779*e2b1b9c0Schristos 		RWLOCK(&ring->lock, isc_rwlocktype_write);
1780*e2b1b9c0Schristos 		remove_fromring(key);
1781*e2b1b9c0Schristos 		RWUNLOCK(&ring->lock, isc_rwlocktype_write);
1782*e2b1b9c0Schristos 		return (ISC_R_NOTFOUND);
1783*e2b1b9c0Schristos 	}
1784*e2b1b9c0Schristos #if 0
1785*e2b1b9c0Schristos 	/*
1786*e2b1b9c0Schristos 	 * MPAXXX We really should look at the inception time.
1787*e2b1b9c0Schristos 	 */
1788*e2b1b9c0Schristos 	if (key->inception != key->expire &&
1789*e2b1b9c0Schristos 	    isc_serial_lt(key->inception, now)) {
1790*e2b1b9c0Schristos 		RWUNLOCK(&ring->lock, isc_rwlocktype_read);
1791*e2b1b9c0Schristos 		adjust_lru(key);
1792*e2b1b9c0Schristos 		return (ISC_R_NOTFOUND);
1793*e2b1b9c0Schristos 	}
1794*e2b1b9c0Schristos #endif
1795*e2b1b9c0Schristos 	isc_refcount_increment(&key->refs, NULL);
1796*e2b1b9c0Schristos 	RWUNLOCK(&ring->lock, isc_rwlocktype_read);
1797*e2b1b9c0Schristos 	adjust_lru(key);
1798*e2b1b9c0Schristos 	*tsigkey = key;
1799*e2b1b9c0Schristos 	return (ISC_R_SUCCESS);
1800*e2b1b9c0Schristos }
1801*e2b1b9c0Schristos 
1802*e2b1b9c0Schristos static void
1803*e2b1b9c0Schristos free_tsignode(void *node, void *_unused) {
1804*e2b1b9c0Schristos 	dns_tsigkey_t *key;
1805*e2b1b9c0Schristos 
1806*e2b1b9c0Schristos 	REQUIRE(node != NULL);
1807*e2b1b9c0Schristos 
1808*e2b1b9c0Schristos 	UNUSED(_unused);
1809*e2b1b9c0Schristos 
1810*e2b1b9c0Schristos 	key = node;
1811*e2b1b9c0Schristos 	if (key->generated) {
1812*e2b1b9c0Schristos 		if (ISC_LINK_LINKED(key, link))
1813*e2b1b9c0Schristos 			ISC_LIST_UNLINK(key->ring->lru, key, link);
1814*e2b1b9c0Schristos 	}
1815*e2b1b9c0Schristos 	dns_tsigkey_detach(&key);
1816*e2b1b9c0Schristos }
1817*e2b1b9c0Schristos 
1818*e2b1b9c0Schristos isc_result_t
1819*e2b1b9c0Schristos dns_tsigkeyring_create(isc_mem_t *mctx, dns_tsig_keyring_t **ringp) {
1820*e2b1b9c0Schristos 	isc_result_t result;
1821*e2b1b9c0Schristos 	dns_tsig_keyring_t *ring;
1822*e2b1b9c0Schristos 
1823*e2b1b9c0Schristos 	REQUIRE(mctx != NULL);
1824*e2b1b9c0Schristos 	REQUIRE(ringp != NULL);
1825*e2b1b9c0Schristos 	REQUIRE(*ringp == NULL);
1826*e2b1b9c0Schristos 
1827*e2b1b9c0Schristos 	ring = isc_mem_get(mctx, sizeof(dns_tsig_keyring_t));
1828*e2b1b9c0Schristos 	if (ring == NULL)
1829*e2b1b9c0Schristos 		return (ISC_R_NOMEMORY);
1830*e2b1b9c0Schristos 
1831*e2b1b9c0Schristos 	result = isc_rwlock_init(&ring->lock, 0, 0);
1832*e2b1b9c0Schristos 	if (result != ISC_R_SUCCESS) {
1833*e2b1b9c0Schristos 		isc_mem_put(mctx, ring, sizeof(dns_tsig_keyring_t));
1834*e2b1b9c0Schristos 		return (result);
1835*e2b1b9c0Schristos 	}
1836*e2b1b9c0Schristos 
1837*e2b1b9c0Schristos 	ring->keys = NULL;
1838*e2b1b9c0Schristos 	result = dns_rbt_create(mctx, free_tsignode, NULL, &ring->keys);
1839*e2b1b9c0Schristos 	if (result != ISC_R_SUCCESS) {
1840*e2b1b9c0Schristos 		isc_rwlock_destroy(&ring->lock);
1841*e2b1b9c0Schristos 		isc_mem_put(mctx, ring, sizeof(dns_tsig_keyring_t));
1842*e2b1b9c0Schristos 		return (result);
1843*e2b1b9c0Schristos 	}
1844*e2b1b9c0Schristos 
1845*e2b1b9c0Schristos 	ring->writecount = 0;
1846*e2b1b9c0Schristos 	ring->mctx = NULL;
1847*e2b1b9c0Schristos 	ring->generated = 0;
1848*e2b1b9c0Schristos 	ring->maxgenerated = DNS_TSIG_MAXGENERATEDKEYS;
1849*e2b1b9c0Schristos 	ISC_LIST_INIT(ring->lru);
1850*e2b1b9c0Schristos 	isc_mem_attach(mctx, &ring->mctx);
1851*e2b1b9c0Schristos 	ring->references = 1;
1852*e2b1b9c0Schristos 
1853*e2b1b9c0Schristos 	*ringp = ring;
1854*e2b1b9c0Schristos 	return (ISC_R_SUCCESS);
1855*e2b1b9c0Schristos }
1856*e2b1b9c0Schristos 
1857*e2b1b9c0Schristos isc_result_t
1858*e2b1b9c0Schristos dns_tsigkeyring_add(dns_tsig_keyring_t *ring, const dns_name_t *name,
1859*e2b1b9c0Schristos 		    dns_tsigkey_t *tkey)
1860*e2b1b9c0Schristos {
1861*e2b1b9c0Schristos 	isc_result_t result;
1862*e2b1b9c0Schristos 
1863*e2b1b9c0Schristos 	result = keyring_add(ring, name, tkey);
1864*e2b1b9c0Schristos 	if (result == ISC_R_SUCCESS)
1865*e2b1b9c0Schristos 		isc_refcount_increment(&tkey->refs, NULL);
1866*e2b1b9c0Schristos 
1867*e2b1b9c0Schristos 	return (result);
1868*e2b1b9c0Schristos }
1869*e2b1b9c0Schristos 
1870*e2b1b9c0Schristos void
1871*e2b1b9c0Schristos dns_tsigkeyring_attach(dns_tsig_keyring_t *source, dns_tsig_keyring_t **target)
1872*e2b1b9c0Schristos {
1873*e2b1b9c0Schristos 	REQUIRE(source != NULL);
1874*e2b1b9c0Schristos 	REQUIRE(target != NULL && *target == NULL);
1875*e2b1b9c0Schristos 
1876*e2b1b9c0Schristos 	RWLOCK(&source->lock, isc_rwlocktype_write);
1877*e2b1b9c0Schristos 	INSIST(source->references > 0);
1878*e2b1b9c0Schristos 	source->references++;
1879*e2b1b9c0Schristos 	INSIST(source->references > 0);
1880*e2b1b9c0Schristos 	*target = source;
1881*e2b1b9c0Schristos 	RWUNLOCK(&source->lock, isc_rwlocktype_write);
1882*e2b1b9c0Schristos }
1883*e2b1b9c0Schristos 
1884*e2b1b9c0Schristos void
1885*e2b1b9c0Schristos dns_tsigkeyring_detach(dns_tsig_keyring_t **ringp) {
1886*e2b1b9c0Schristos 	dns_tsig_keyring_t *ring;
1887*e2b1b9c0Schristos 	unsigned int references;
1888*e2b1b9c0Schristos 
1889*e2b1b9c0Schristos 	REQUIRE(ringp != NULL);
1890*e2b1b9c0Schristos 	REQUIRE(*ringp != NULL);
1891*e2b1b9c0Schristos 
1892*e2b1b9c0Schristos 	ring = *ringp;
1893*e2b1b9c0Schristos 	*ringp = NULL;
1894*e2b1b9c0Schristos 
1895*e2b1b9c0Schristos 	RWLOCK(&ring->lock, isc_rwlocktype_write);
1896*e2b1b9c0Schristos 	INSIST(ring->references > 0);
1897*e2b1b9c0Schristos 	ring->references--;
1898*e2b1b9c0Schristos 	references = ring->references;
1899*e2b1b9c0Schristos 	RWUNLOCK(&ring->lock, isc_rwlocktype_write);
1900*e2b1b9c0Schristos 
1901*e2b1b9c0Schristos 	if (references == 0)
1902*e2b1b9c0Schristos 		destroyring(ring);
1903*e2b1b9c0Schristos }
1904*e2b1b9c0Schristos 
1905*e2b1b9c0Schristos void
1906*e2b1b9c0Schristos dns_keyring_restore(dns_tsig_keyring_t *ring, FILE *fp) {
1907*e2b1b9c0Schristos 	isc_stdtime_t now;
1908*e2b1b9c0Schristos 	isc_result_t result;
1909*e2b1b9c0Schristos 
1910*e2b1b9c0Schristos 	isc_stdtime_get(&now);
1911*e2b1b9c0Schristos 	do {
1912*e2b1b9c0Schristos 		result = restore_key(ring, now, fp);
1913*e2b1b9c0Schristos 		if (result == ISC_R_NOMORE)
1914*e2b1b9c0Schristos 			return;
1915*e2b1b9c0Schristos 		if (result == DNS_R_BADALG || result == DNS_R_EXPIRED)
1916*e2b1b9c0Schristos 			result = ISC_R_SUCCESS;
1917*e2b1b9c0Schristos 	} while (result == ISC_R_SUCCESS);
1918*e2b1b9c0Schristos }
1919