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