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