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