2 * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2002 Internet Software Consortium.
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.
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.
19 * $Id: tsig.c,v 1.117.18.11 2007/09/26 23:46:34 tbox Exp $
25 #include <isc/buffer.h>
27 #include <isc/print.h>
28 #include <isc/refcount.h>
29 #include <isc/string.h> /* Required for HP/UX (and others?) */
32 #include <dns/keyvalues.h>
34 #include <dns/message.h>
36 #include <dns/rdata.h>
37 #include <dns/rdatalist.h>
38 #include <dns/rdataset.h>
39 #include <dns/rdatastruct.h>
40 #include <dns/result.h>
43 #include <dst/result.h>
45 #define TSIG_MAGIC ISC_MAGIC('T', 'S', 'I', 'G')
46 #define VALID_TSIG_KEY(x) ISC_MAGIC_VALID(x, TSIG_MAGIC)
48 #define is_response(msg) (msg->flags & DNS_MESSAGEFLAG_QR)
49 #define algname_is_allocated(algname) \
50 ((algname) != dns_tsig_hmacmd5_name && \
51 (algname) != dns_tsig_hmacsha1_name && \
52 (algname) != dns_tsig_hmacsha224_name && \
53 (algname) != dns_tsig_hmacsha256_name && \
54 (algname) != dns_tsig_hmacsha384_name && \
55 (algname) != dns_tsig_hmacsha512_name && \
56 (algname) != dns_tsig_gssapi_name && \
57 (algname) != dns_tsig_gssapims_name)
61 static unsigned char hmacmd5_ndata[] = "\010hmac-md5\007sig-alg\003reg\003int";
62 static unsigned char hmacmd5_offsets[] = { 0, 9, 17, 21, 25 };
64 static dns_name_t hmacmd5 = {
67 DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
68 hmacmd5_offsets, NULL,
69 {(void *)-1, (void *)-1},
73 dns_name_t *dns_tsig_hmacmd5_name = &hmacmd5;
75 static unsigned char gsstsig_ndata[] = "\010gss-tsig";
76 static unsigned char gsstsig_offsets[] = { 0, 9 };
78 static dns_name_t gsstsig = {
81 DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
82 gsstsig_offsets, NULL,
83 {(void *)-1, (void *)-1},
87 LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_gssapi_name = &gsstsig;
89 /* It's nice of Microsoft to conform to their own standard. */
90 static unsigned char gsstsigms_ndata[] = "\003gss\011microsoft\003com";
91 static unsigned char gsstsigms_offsets[] = { 0, 4, 14, 18 };
93 static dns_name_t gsstsigms = {
95 gsstsigms_ndata, 19, 4,
96 DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
97 gsstsigms_offsets, NULL,
98 {(void *)-1, (void *)-1},
102 LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_gssapims_name = &gsstsigms;
104 static unsigned char hmacsha1_ndata[] = "\011hmac-sha1";
105 static unsigned char hmacsha1_offsets[] = { 0, 10 };
107 static dns_name_t hmacsha1 = {
109 hmacsha1_ndata, 11, 2,
110 DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
111 hmacsha1_offsets, NULL,
112 {(void *)-1, (void *)-1},
116 LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_hmacsha1_name = &hmacsha1;
118 static unsigned char hmacsha224_ndata[] = "\013hmac-sha224";
119 static unsigned char hmacsha224_offsets[] = { 0, 12 };
121 static dns_name_t hmacsha224 = {
123 hmacsha224_ndata, 13, 2,
124 DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
125 hmacsha224_offsets, NULL,
126 {(void *)-1, (void *)-1},
130 LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_hmacsha224_name = &hmacsha224;
132 static unsigned char hmacsha256_ndata[] = "\013hmac-sha256";
133 static unsigned char hmacsha256_offsets[] = { 0, 12 };
135 static dns_name_t hmacsha256 = {
137 hmacsha256_ndata, 13, 2,
138 DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
139 hmacsha256_offsets, NULL,
140 {(void *)-1, (void *)-1},
144 LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_hmacsha256_name = &hmacsha256;
146 static unsigned char hmacsha384_ndata[] = "\013hmac-sha384";
147 static unsigned char hmacsha384_offsets[] = { 0, 12 };
149 static dns_name_t hmacsha384 = {
151 hmacsha384_ndata, 13, 2,
152 DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
153 hmacsha384_offsets, NULL,
154 {(void *)-1, (void *)-1},
158 LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_hmacsha384_name = &hmacsha384;
160 static unsigned char hmacsha512_ndata[] = "\013hmac-sha512";
161 static unsigned char hmacsha512_offsets[] = { 0, 12 };
163 static dns_name_t hmacsha512 = {
165 hmacsha512_ndata, 13, 2,
166 DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
167 hmacsha512_offsets, NULL,
168 {(void *)-1, (void *)-1},
172 LIBDNS_EXTERNAL_DATA dns_name_t *dns_tsig_hmacsha512_name = &hmacsha512;
175 tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg);
178 tsig_log(dns_tsigkey_t *key, int level, const char *fmt, ...)
179 ISC_FORMAT_PRINTF(3, 4);
182 tsig_log(dns_tsigkey_t *key, int level, const char *fmt, ...) {
185 char namestr[DNS_NAME_FORMATSIZE];
187 if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE)
190 dns_name_format(&key->name, namestr, sizeof(namestr));
192 strcpy(namestr, "<null>");
194 vsnprintf(message, sizeof(message), fmt, ap);
196 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_TSIG,
197 level, "tsig key '%s': %s", namestr, message);
201 dns_tsigkey_createfromkey(dns_name_t *name, dns_name_t *algorithm,
202 dst_key_t *dstkey, isc_boolean_t generated,
203 dns_name_t *creator, isc_stdtime_t inception,
204 isc_stdtime_t expire, isc_mem_t *mctx,
205 dns_tsig_keyring_t *ring, dns_tsigkey_t **key)
209 unsigned int refs = 0;
211 REQUIRE(key == NULL || *key == NULL);
212 REQUIRE(name != NULL);
213 REQUIRE(algorithm != NULL);
214 REQUIRE(mctx != NULL);
215 REQUIRE(key != NULL || ring != NULL);
217 tkey = (dns_tsigkey_t *) isc_mem_get(mctx, sizeof(dns_tsigkey_t));
219 return (ISC_R_NOMEMORY);
221 dns_name_init(&tkey->name, NULL);
222 ret = dns_name_dup(name, mctx, &tkey->name);
223 if (ret != ISC_R_SUCCESS)
225 (void)dns_name_downcase(&tkey->name, &tkey->name, NULL);
227 if (dns_name_equal(algorithm, DNS_TSIG_HMACMD5_NAME)) {
228 tkey->algorithm = DNS_TSIG_HMACMD5_NAME;
229 if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACMD5) {
233 } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA1_NAME)) {
234 tkey->algorithm = DNS_TSIG_HMACSHA1_NAME;
235 if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_HMACSHA1) {
239 } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA224_NAME)) {
240 tkey->algorithm = DNS_TSIG_HMACSHA224_NAME;
241 if (dstkey != NULL &&
242 dst_key_alg(dstkey) != DST_ALG_HMACSHA224) {
246 } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA256_NAME)) {
247 tkey->algorithm = DNS_TSIG_HMACSHA256_NAME;
248 if (dstkey != NULL &&
249 dst_key_alg(dstkey) != DST_ALG_HMACSHA256) {
253 } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA384_NAME)) {
254 tkey->algorithm = DNS_TSIG_HMACSHA384_NAME;
255 if (dstkey != NULL &&
256 dst_key_alg(dstkey) != DST_ALG_HMACSHA384) {
260 } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA512_NAME)) {
261 tkey->algorithm = DNS_TSIG_HMACSHA512_NAME;
262 if (dstkey != NULL &&
263 dst_key_alg(dstkey) != DST_ALG_HMACSHA512) {
267 } else if (dns_name_equal(algorithm, DNS_TSIG_GSSAPI_NAME)) {
268 tkey->algorithm = DNS_TSIG_GSSAPI_NAME;
269 if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_GSSAPI) {
273 } else if (dns_name_equal(algorithm, DNS_TSIG_GSSAPIMS_NAME)) {
274 tkey->algorithm = DNS_TSIG_GSSAPIMS_NAME;
275 if (dstkey != NULL && dst_key_alg(dstkey) != DST_ALG_GSSAPI) {
280 if (dstkey != NULL) {
284 tkey->algorithm = isc_mem_get(mctx, sizeof(dns_name_t));
285 if (tkey->algorithm == NULL) {
286 ret = ISC_R_NOMEMORY;
289 dns_name_init(tkey->algorithm, NULL);
290 ret = dns_name_dup(algorithm, mctx, tkey->algorithm);
291 if (ret != ISC_R_SUCCESS)
292 goto cleanup_algorithm;
293 (void)dns_name_downcase(tkey->algorithm, tkey->algorithm,
297 if (creator != NULL) {
298 tkey->creator = isc_mem_get(mctx, sizeof(dns_name_t));
299 if (tkey->creator == NULL) {
300 ret = ISC_R_NOMEMORY;
301 goto cleanup_algorithm;
303 dns_name_init(tkey->creator, NULL);
304 ret = dns_name_dup(creator, mctx, tkey->creator);
305 if (ret != ISC_R_SUCCESS) {
306 isc_mem_put(mctx, tkey->creator, sizeof(dns_name_t));
307 goto cleanup_algorithm;
310 tkey->creator = NULL;
319 ret = isc_refcount_init(&tkey->refs, refs);
320 if (ret != ISC_R_SUCCESS)
321 goto cleanup_creator;
323 tkey->generated = generated;
324 tkey->inception = inception;
325 tkey->expire = expire;
328 tkey->magic = TSIG_MAGIC;
331 RWLOCK(&ring->lock, isc_rwlocktype_write);
332 ret = dns_rbt_addname(ring->keys, name, tkey);
333 if (ret != ISC_R_SUCCESS) {
334 RWUNLOCK(&ring->lock, isc_rwlocktype_write);
337 RWUNLOCK(&ring->lock, isc_rwlocktype_write);
340 if (dstkey != NULL && dst_key_size(dstkey) < 64) {
341 char namestr[DNS_NAME_FORMATSIZE];
342 dns_name_format(name, namestr, sizeof(namestr));
343 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
344 DNS_LOGMODULE_TSIG, ISC_LOG_INFO,
345 "the key '%s' is too short to be secure",
351 return (ISC_R_SUCCESS);
356 isc_refcount_decrement(&tkey->refs, NULL);
357 isc_refcount_destroy(&tkey->refs);
359 if (tkey->creator != NULL) {
360 dns_name_free(tkey->creator, mctx);
361 isc_mem_put(mctx, tkey->creator, sizeof(dns_name_t));
364 if (algname_is_allocated(tkey->algorithm)) {
365 if (dns_name_dynamic(tkey->algorithm))
366 dns_name_free(tkey->algorithm, mctx);
367 isc_mem_put(mctx, tkey->algorithm, sizeof(dns_name_t));
370 dns_name_free(&tkey->name, mctx);
372 isc_mem_put(mctx, tkey, sizeof(dns_tsigkey_t));
378 dns_tsigkey_create(dns_name_t *name, dns_name_t *algorithm,
379 unsigned char *secret, int length, isc_boolean_t generated,
380 dns_name_t *creator, isc_stdtime_t inception,
381 isc_stdtime_t expire, isc_mem_t *mctx,
382 dns_tsig_keyring_t *ring, dns_tsigkey_t **key)
384 dst_key_t *dstkey = NULL;
387 REQUIRE(length >= 0);
389 REQUIRE(secret != NULL);
391 if (dns_name_equal(algorithm, DNS_TSIG_HMACMD5_NAME)) {
392 if (secret != NULL) {
395 isc_buffer_init(&b, secret, length);
396 isc_buffer_add(&b, length);
397 result = dst_key_frombuffer(name, DST_ALG_HMACMD5,
402 if (result != ISC_R_SUCCESS)
405 } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA1_NAME)) {
406 if (secret != NULL) {
409 isc_buffer_init(&b, secret, length);
410 isc_buffer_add(&b, length);
411 result = dst_key_frombuffer(name, DST_ALG_HMACSHA1,
416 if (result != ISC_R_SUCCESS)
419 } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA224_NAME)) {
420 if (secret != NULL) {
423 isc_buffer_init(&b, secret, length);
424 isc_buffer_add(&b, length);
425 result = dst_key_frombuffer(name, DST_ALG_HMACSHA224,
430 if (result != ISC_R_SUCCESS)
433 } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA256_NAME)) {
434 if (secret != NULL) {
437 isc_buffer_init(&b, secret, length);
438 isc_buffer_add(&b, length);
439 result = dst_key_frombuffer(name, DST_ALG_HMACSHA256,
444 if (result != ISC_R_SUCCESS)
447 } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA384_NAME)) {
448 if (secret != NULL) {
451 isc_buffer_init(&b, secret, length);
452 isc_buffer_add(&b, length);
453 result = dst_key_frombuffer(name, DST_ALG_HMACSHA384,
458 if (result != ISC_R_SUCCESS)
461 } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA512_NAME)) {
462 if (secret != NULL) {
465 isc_buffer_init(&b, secret, length);
466 isc_buffer_add(&b, length);
467 result = dst_key_frombuffer(name, DST_ALG_HMACSHA512,
472 if (result != ISC_R_SUCCESS)
475 } else if (length > 0)
476 return (DNS_R_BADALG);
478 result = dns_tsigkey_createfromkey(name, algorithm, dstkey,
480 inception, expire, mctx, ring, key);
481 if (result != ISC_R_SUCCESS && dstkey != NULL)
482 dst_key_free(&dstkey);
487 dns_tsigkey_attach(dns_tsigkey_t *source, dns_tsigkey_t **targetp) {
488 REQUIRE(VALID_TSIG_KEY(source));
489 REQUIRE(targetp != NULL && *targetp == NULL);
491 isc_refcount_increment(&source->refs, NULL);
496 tsigkey_free(dns_tsigkey_t *key) {
497 REQUIRE(VALID_TSIG_KEY(key));
500 dns_name_free(&key->name, key->mctx);
501 if (algname_is_allocated(key->algorithm)) {
502 dns_name_free(key->algorithm, key->mctx);
503 isc_mem_put(key->mctx, key->algorithm, sizeof(dns_name_t));
505 if (key->key != NULL)
506 dst_key_free(&key->key);
507 if (key->creator != NULL) {
508 dns_name_free(key->creator, key->mctx);
509 isc_mem_put(key->mctx, key->creator, sizeof(dns_name_t));
511 isc_refcount_destroy(&key->refs);
512 isc_mem_put(key->mctx, key, sizeof(dns_tsigkey_t));
516 dns_tsigkey_detach(dns_tsigkey_t **keyp) {
520 REQUIRE(keyp != NULL);
521 REQUIRE(VALID_TSIG_KEY(*keyp));
524 isc_refcount_decrement(&key->refs, &refs);
533 dns_tsigkey_setdeleted(dns_tsigkey_t *key) {
534 REQUIRE(VALID_TSIG_KEY(key));
535 REQUIRE(key->ring != NULL);
537 RWLOCK(&key->ring->lock, isc_rwlocktype_write);
538 (void)dns_rbt_deletename(key->ring->keys, &key->name, ISC_FALSE);
539 RWUNLOCK(&key->ring->lock, isc_rwlocktype_write);
543 buffer_putuint48(isc_buffer_t *b, isc_uint64_t val) {
547 valhi = (isc_uint16_t)(val >> 32);
548 vallo = (isc_uint32_t)(val & 0xFFFFFFFF);
549 isc_buffer_putuint16(b, valhi);
550 isc_buffer_putuint32(b, vallo);
554 dns_tsig_sign(dns_message_t *msg) {
556 dns_rdata_any_tsig_t tsig, querytsig;
557 unsigned char data[128];
558 isc_buffer_t databuf, sigbuf;
559 isc_buffer_t *dynbuf;
561 dns_rdata_t *rdata = NULL;
562 dns_rdatalist_t *datalist;
563 dns_rdataset_t *dataset;
567 dst_context_t *ctx = NULL;
569 unsigned char badtimedata[BADTIMELEN];
570 unsigned int sigsize = 0;
572 REQUIRE(msg != NULL);
573 REQUIRE(VALID_TSIG_KEY(dns_message_gettsigkey(msg)));
576 * If this is a response, there should be a query tsig.
578 if (is_response(msg) && msg->querytsig == NULL)
579 return (DNS_R_EXPECTEDTSIG);
584 key = dns_message_gettsigkey(msg);
587 tsig.common.rdclass = dns_rdataclass_any;
588 tsig.common.rdtype = dns_rdatatype_tsig;
589 ISC_LINK_INIT(&tsig.common, link);
590 dns_name_init(&tsig.algorithm, NULL);
591 dns_name_clone(key->algorithm, &tsig.algorithm);
593 isc_stdtime_get(&now);
594 tsig.timesigned = now + msg->timeadjust;
595 tsig.fudge = DNS_TSIG_FUDGE;
597 tsig.originalid = msg->id;
599 isc_buffer_init(&databuf, data, sizeof(data));
601 if (is_response(msg))
602 tsig.error = msg->querytsigstatus;
604 tsig.error = dns_rcode_noerror;
606 if (tsig.error != dns_tsigerror_badtime) {
610 isc_buffer_t otherbuf;
612 tsig.otherlen = BADTIMELEN;
613 tsig.other = badtimedata;
614 isc_buffer_init(&otherbuf, tsig.other, tsig.otherlen);
615 buffer_putuint48(&otherbuf, tsig.timesigned);
618 if (key->key != NULL && tsig.error != dns_tsigerror_badsig) {
619 unsigned char header[DNS_MESSAGE_HEADERLEN];
620 isc_buffer_t headerbuf;
621 isc_uint16_t digestbits;
623 ret = dst_context_create(key->key, mctx, &ctx);
624 if (ret != ISC_R_SUCCESS)
628 * If this is a response, digest the query signature.
630 if (is_response(msg)) {
631 dns_rdata_t querytsigrdata = DNS_RDATA_INIT;
633 ret = dns_rdataset_first(msg->querytsig);
634 if (ret != ISC_R_SUCCESS)
635 goto cleanup_context;
636 dns_rdataset_current(msg->querytsig, &querytsigrdata);
637 ret = dns_rdata_tostruct(&querytsigrdata, &querytsig,
639 if (ret != ISC_R_SUCCESS)
640 goto cleanup_context;
641 isc_buffer_putuint16(&databuf, querytsig.siglen);
642 if (isc_buffer_availablelength(&databuf) <
646 goto cleanup_context;
648 isc_buffer_putmem(&databuf, querytsig.signature,
650 isc_buffer_usedregion(&databuf, &r);
651 ret = dst_context_adddata(ctx, &r);
652 if (ret != ISC_R_SUCCESS)
653 goto cleanup_context;
659 isc_buffer_init(&headerbuf, header, sizeof(header));
660 dns_message_renderheader(msg, &headerbuf);
661 isc_buffer_usedregion(&headerbuf, &r);
662 ret = dst_context_adddata(ctx, &r);
663 if (ret != ISC_R_SUCCESS)
664 goto cleanup_context;
667 * Digest the remainder of the message.
669 isc_buffer_usedregion(msg->buffer, &r);
670 isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
671 ret = dst_context_adddata(ctx, &r);
672 if (ret != ISC_R_SUCCESS)
673 goto cleanup_context;
675 if (msg->tcp_continuation == 0) {
677 * Digest the name, class, ttl, alg.
679 dns_name_toregion(&key->name, &r);
680 ret = dst_context_adddata(ctx, &r);
681 if (ret != ISC_R_SUCCESS)
682 goto cleanup_context;
684 isc_buffer_clear(&databuf);
685 isc_buffer_putuint16(&databuf, dns_rdataclass_any);
686 isc_buffer_putuint32(&databuf, 0); /* ttl */
687 isc_buffer_usedregion(&databuf, &r);
688 ret = dst_context_adddata(ctx, &r);
689 if (ret != ISC_R_SUCCESS)
690 goto cleanup_context;
692 dns_name_toregion(&tsig.algorithm, &r);
693 ret = dst_context_adddata(ctx, &r);
694 if (ret != ISC_R_SUCCESS)
695 goto cleanup_context;
698 /* Digest the timesigned and fudge */
699 isc_buffer_clear(&databuf);
700 if (tsig.error == dns_tsigerror_badtime)
701 tsig.timesigned = querytsig.timesigned;
702 buffer_putuint48(&databuf, tsig.timesigned);
703 isc_buffer_putuint16(&databuf, tsig.fudge);
704 isc_buffer_usedregion(&databuf, &r);
705 ret = dst_context_adddata(ctx, &r);
706 if (ret != ISC_R_SUCCESS)
707 goto cleanup_context;
709 if (msg->tcp_continuation == 0) {
711 * Digest the error and other data length.
713 isc_buffer_clear(&databuf);
714 isc_buffer_putuint16(&databuf, tsig.error);
715 isc_buffer_putuint16(&databuf, tsig.otherlen);
717 isc_buffer_usedregion(&databuf, &r);
718 ret = dst_context_adddata(ctx, &r);
719 if (ret != ISC_R_SUCCESS)
720 goto cleanup_context;
723 * Digest the error and other data.
725 if (tsig.otherlen > 0) {
726 r.length = tsig.otherlen;
728 ret = dst_context_adddata(ctx, &r);
729 if (ret != ISC_R_SUCCESS)
730 goto cleanup_context;
734 ret = dst_key_sigsize(key->key, &sigsize);
735 if (ret != ISC_R_SUCCESS)
736 goto cleanup_context;
737 tsig.signature = (unsigned char *) isc_mem_get(mctx, sigsize);
738 if (tsig.signature == NULL) {
739 ret = ISC_R_NOMEMORY;
740 goto cleanup_context;
743 isc_buffer_init(&sigbuf, tsig.signature, sigsize);
744 ret = dst_context_sign(ctx, &sigbuf);
745 if (ret != ISC_R_SUCCESS)
746 goto cleanup_signature;
747 dst_context_destroy(&ctx);
748 digestbits = dst_key_getbits(key->key);
749 if (digestbits != 0) {
750 unsigned int bytes = (digestbits + 1) / 8;
751 if (is_response(msg) && bytes < querytsig.siglen)
752 bytes = querytsig.siglen;
753 if (bytes > isc_buffer_usedlength(&sigbuf))
754 bytes = isc_buffer_usedlength(&sigbuf);
757 tsig.siglen = isc_buffer_usedlength(&sigbuf);
760 tsig.signature = NULL;
763 ret = dns_message_gettemprdata(msg, &rdata);
764 if (ret != ISC_R_SUCCESS)
765 goto cleanup_signature;
766 ret = isc_buffer_allocate(msg->mctx, &dynbuf, 512);
767 if (ret != ISC_R_SUCCESS)
769 ret = dns_rdata_fromstruct(rdata, dns_rdataclass_any,
770 dns_rdatatype_tsig, &tsig, dynbuf);
771 if (ret != ISC_R_SUCCESS)
774 dns_message_takebuffer(msg, &dynbuf);
776 if (tsig.signature != NULL) {
777 isc_mem_put(mctx, tsig.signature, sigsize);
778 tsig.signature = NULL;
782 ret = dns_message_gettempname(msg, &owner);
783 if (ret != ISC_R_SUCCESS)
785 dns_name_init(owner, NULL);
786 ret = dns_name_dup(&key->name, msg->mctx, owner);
787 if (ret != ISC_R_SUCCESS)
791 ret = dns_message_gettemprdatalist(msg, &datalist);
792 if (ret != ISC_R_SUCCESS)
795 ret = dns_message_gettemprdataset(msg, &dataset);
796 if (ret != ISC_R_SUCCESS)
797 goto cleanup_rdatalist;
798 datalist->rdclass = dns_rdataclass_any;
799 datalist->type = dns_rdatatype_tsig;
800 datalist->covers = 0;
802 ISC_LIST_INIT(datalist->rdata);
803 ISC_LIST_APPEND(datalist->rdata, rdata, link);
804 dns_rdataset_init(dataset);
805 RUNTIME_CHECK(dns_rdatalist_tordataset(datalist, dataset)
808 msg->tsigname = owner;
810 return (ISC_R_SUCCESS);
813 dns_message_puttemprdatalist(msg, &datalist);
815 dns_message_puttempname(msg, &owner);
818 isc_buffer_free(&dynbuf);
820 dns_message_puttemprdata(msg, &rdata);
822 if (tsig.signature != NULL)
823 isc_mem_put(mctx, tsig.signature, sigsize);
826 dst_context_destroy(&ctx);
831 dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
832 dns_tsig_keyring_t *ring1, dns_tsig_keyring_t *ring2)
834 dns_rdata_any_tsig_t tsig, querytsig;
835 isc_region_t r, source_r, header_r, sig_r;
836 isc_buffer_t databuf;
837 unsigned char data[32];
839 dns_rdata_t rdata = DNS_RDATA_INIT;
842 dns_tsigkey_t *tsigkey;
843 dst_key_t *key = NULL;
844 unsigned char header[DNS_MESSAGE_HEADERLEN];
845 dst_context_t *ctx = NULL;
847 isc_uint16_t addcount, id;
851 REQUIRE(source != NULL);
852 REQUIRE(DNS_MESSAGE_VALID(msg));
853 tsigkey = dns_message_gettsigkey(msg);
854 REQUIRE(tsigkey == NULL || VALID_TSIG_KEY(tsigkey));
856 msg->verify_attempted = 1;
858 if (msg->tcp_continuation) {
859 if (tsigkey == NULL || msg->querytsig == NULL)
860 return (DNS_R_UNEXPECTEDTSIG);
861 return (tsig_verify_tcp(source, msg));
865 * There should be a TSIG record...
867 if (msg->tsig == NULL)
868 return (DNS_R_EXPECTEDTSIG);
871 * If this is a response and there's no key or query TSIG, there
872 * shouldn't be one on the response.
874 if (is_response(msg) &&
875 (tsigkey == NULL || msg->querytsig == NULL))
876 return (DNS_R_UNEXPECTEDTSIG);
881 * If we're here, we know the message is well formed and contains a
885 keyname = msg->tsigname;
886 ret = dns_rdataset_first(msg->tsig);
887 if (ret != ISC_R_SUCCESS)
889 dns_rdataset_current(msg->tsig, &rdata);
890 ret = dns_rdata_tostruct(&rdata, &tsig, NULL);
891 if (ret != ISC_R_SUCCESS)
893 dns_rdata_reset(&rdata);
894 if (is_response(msg)) {
895 ret = dns_rdataset_first(msg->querytsig);
896 if (ret != ISC_R_SUCCESS)
898 dns_rdataset_current(msg->querytsig, &rdata);
899 ret = dns_rdata_tostruct(&rdata, &querytsig, NULL);
900 if (ret != ISC_R_SUCCESS)
905 * Do the key name and algorithm match that of the query?
907 if (is_response(msg) &&
908 (!dns_name_equal(keyname, &tsigkey->name) ||
909 !dns_name_equal(&tsig.algorithm, &querytsig.algorithm)))
911 msg->tsigstatus = dns_tsigerror_badkey;
912 tsig_log(msg->tsigkey, 2,
913 "key name and algorithm do not match");
914 return (DNS_R_TSIGVERIFYFAILURE);
918 * Get the current time.
920 isc_stdtime_get(&now);
923 * Find dns_tsigkey_t based on keyname.
925 if (tsigkey == NULL) {
926 ret = ISC_R_NOTFOUND;
928 ret = dns_tsigkey_find(&tsigkey, keyname,
929 &tsig.algorithm, ring1);
930 if (ret == ISC_R_NOTFOUND && ring2 != NULL)
931 ret = dns_tsigkey_find(&tsigkey, keyname,
932 &tsig.algorithm, ring2);
933 if (ret != ISC_R_SUCCESS) {
934 msg->tsigstatus = dns_tsigerror_badkey;
935 ret = dns_tsigkey_create(keyname, &tsig.algorithm,
936 NULL, 0, ISC_FALSE, NULL,
938 mctx, NULL, &msg->tsigkey);
939 if (ret != ISC_R_SUCCESS)
941 tsig_log(msg->tsigkey, 2, "unknown key");
942 return (DNS_R_TSIGVERIFYFAILURE);
944 msg->tsigkey = tsigkey;
952 if (now + msg->timeadjust > tsig.timesigned + tsig.fudge) {
953 msg->tsigstatus = dns_tsigerror_badtime;
954 tsig_log(msg->tsigkey, 2, "signature has expired");
955 return (DNS_R_CLOCKSKEW);
956 } else if (now + msg->timeadjust < tsig.timesigned - tsig.fudge) {
957 msg->tsigstatus = dns_tsigerror_badtime;
958 tsig_log(msg->tsigkey, 2, "signature is in the future");
959 return (DNS_R_CLOCKSKEW);
963 * Check digest length.
965 alg = dst_key_alg(key);
966 ret = dst_key_sigsize(key, &siglen);
967 if (ret != ISC_R_SUCCESS)
969 if (alg == DST_ALG_HMACMD5 || alg == DST_ALG_HMACSHA1 ||
970 alg == DST_ALG_HMACSHA224 || alg == DST_ALG_HMACSHA256 ||
971 alg == DST_ALG_HMACSHA384 || alg == DST_ALG_HMACSHA512) {
972 isc_uint16_t digestbits = dst_key_getbits(key);
973 if (tsig.siglen > siglen) {
974 tsig_log(msg->tsigkey, 2, "signature length to big");
975 return (DNS_R_FORMERR);
977 if (tsig.siglen > 0 &&
978 (tsig.siglen < 10 || tsig.siglen < ((siglen + 1) / 2))) {
979 tsig_log(msg->tsigkey, 2,
980 "signature length below minimum");
981 return (DNS_R_FORMERR);
983 if (tsig.siglen > 0 && digestbits != 0 &&
984 tsig.siglen < ((digestbits + 1) / 8)) {
985 msg->tsigstatus = dns_tsigerror_badtrunc;
986 tsig_log(msg->tsigkey, 2,
987 "truncated signature length too small");
988 return (DNS_R_TSIGVERIFYFAILURE);
990 if (tsig.siglen > 0 && digestbits == 0 &&
991 tsig.siglen < siglen) {
992 msg->tsigstatus = dns_tsigerror_badtrunc;
993 tsig_log(msg->tsigkey, 2, "signature length too small");
994 return (DNS_R_TSIGVERIFYFAILURE);
998 if (tsig.siglen > 0) {
999 sig_r.base = tsig.signature;
1000 sig_r.length = tsig.siglen;
1002 ret = dst_context_create(key, mctx, &ctx);
1003 if (ret != ISC_R_SUCCESS)
1006 if (is_response(msg)) {
1007 isc_buffer_init(&databuf, data, sizeof(data));
1008 isc_buffer_putuint16(&databuf, querytsig.siglen);
1009 isc_buffer_usedregion(&databuf, &r);
1010 ret = dst_context_adddata(ctx, &r);
1011 if (ret != ISC_R_SUCCESS)
1012 goto cleanup_context;
1013 if (querytsig.siglen > 0) {
1014 r.length = querytsig.siglen;
1015 r.base = querytsig.signature;
1016 ret = dst_context_adddata(ctx, &r);
1017 if (ret != ISC_R_SUCCESS)
1018 goto cleanup_context;
1023 * Extract the header.
1025 isc_buffer_usedregion(source, &r);
1026 memcpy(header, r.base, DNS_MESSAGE_HEADERLEN);
1027 isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
1030 * Decrement the additional field counter.
1032 memcpy(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
1033 addcount = htons((isc_uint16_t)(ntohs(addcount) - 1));
1034 memcpy(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);
1037 * Put in the original id.
1039 id = htons(tsig.originalid);
1040 memcpy(&header[0], &id, 2);
1043 * Digest the modified header.
1045 header_r.base = (unsigned char *) header;
1046 header_r.length = DNS_MESSAGE_HEADERLEN;
1047 ret = dst_context_adddata(ctx, &header_r);
1048 if (ret != ISC_R_SUCCESS)
1049 goto cleanup_context;
1052 * Digest all non-TSIG records.
1054 isc_buffer_usedregion(source, &source_r);
1055 r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
1056 r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN;
1057 ret = dst_context_adddata(ctx, &r);
1058 if (ret != ISC_R_SUCCESS)
1059 goto cleanup_context;
1062 * Digest the key name.
1064 dns_name_toregion(&tsigkey->name, &r);
1065 ret = dst_context_adddata(ctx, &r);
1066 if (ret != ISC_R_SUCCESS)
1067 goto cleanup_context;
1069 isc_buffer_init(&databuf, data, sizeof(data));
1070 isc_buffer_putuint16(&databuf, tsig.common.rdclass);
1071 isc_buffer_putuint32(&databuf, msg->tsig->ttl);
1072 isc_buffer_usedregion(&databuf, &r);
1073 ret = dst_context_adddata(ctx, &r);
1074 if (ret != ISC_R_SUCCESS)
1075 goto cleanup_context;
1078 * Digest the key algorithm.
1080 dns_name_toregion(tsigkey->algorithm, &r);
1081 ret = dst_context_adddata(ctx, &r);
1082 if (ret != ISC_R_SUCCESS)
1083 goto cleanup_context;
1085 isc_buffer_clear(&databuf);
1086 buffer_putuint48(&databuf, tsig.timesigned);
1087 isc_buffer_putuint16(&databuf, tsig.fudge);
1088 isc_buffer_putuint16(&databuf, tsig.error);
1089 isc_buffer_putuint16(&databuf, tsig.otherlen);
1090 isc_buffer_usedregion(&databuf, &r);
1091 ret = dst_context_adddata(ctx, &r);
1092 if (ret != ISC_R_SUCCESS)
1093 goto cleanup_context;
1095 if (tsig.otherlen > 0) {
1096 r.base = tsig.other;
1097 r.length = tsig.otherlen;
1098 ret = dst_context_adddata(ctx, &r);
1099 if (ret != ISC_R_SUCCESS)
1100 goto cleanup_context;
1103 ret = dst_context_verify(ctx, &sig_r);
1104 if (ret == DST_R_VERIFYFAILURE) {
1105 msg->tsigstatus = dns_tsigerror_badsig;
1106 ret = DNS_R_TSIGVERIFYFAILURE;
1107 tsig_log(msg->tsigkey, 2,
1108 "signature failed to verify");
1109 goto cleanup_context;
1110 } else if (ret != ISC_R_SUCCESS)
1111 goto cleanup_context;
1113 dst_context_destroy(&ctx);
1114 } else if (tsig.error != dns_tsigerror_badsig &&
1115 tsig.error != dns_tsigerror_badkey)
1117 msg->tsigstatus = dns_tsigerror_badsig;
1118 tsig_log(msg->tsigkey, 2, "signature was empty");
1119 return (DNS_R_TSIGVERIFYFAILURE);
1122 msg->tsigstatus = dns_rcode_noerror;
1124 if (tsig.error != dns_rcode_noerror) {
1125 if (tsig.error == dns_tsigerror_badtime)
1126 return (DNS_R_CLOCKSKEW);
1128 return (DNS_R_TSIGERRORSET);
1131 msg->verified_sig = 1;
1133 return (ISC_R_SUCCESS);
1137 dst_context_destroy(&ctx);
1143 tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) {
1144 dns_rdata_any_tsig_t tsig, querytsig;
1145 isc_region_t r, source_r, header_r, sig_r;
1146 isc_buffer_t databuf;
1147 unsigned char data[32];
1148 dns_name_t *keyname;
1149 dns_rdata_t rdata = DNS_RDATA_INIT;
1152 dns_tsigkey_t *tsigkey;
1153 dst_key_t *key = NULL;
1154 unsigned char header[DNS_MESSAGE_HEADERLEN];
1155 isc_uint16_t addcount, id;
1156 isc_boolean_t has_tsig = ISC_FALSE;
1159 REQUIRE(source != NULL);
1160 REQUIRE(msg != NULL);
1161 REQUIRE(dns_message_gettsigkey(msg) != NULL);
1162 REQUIRE(msg->tcp_continuation == 1);
1163 REQUIRE(msg->querytsig != NULL);
1165 if (!is_response(msg))
1166 return (DNS_R_EXPECTEDRESPONSE);
1170 tsigkey = dns_message_gettsigkey(msg);
1173 * Extract and parse the previous TSIG
1175 ret = dns_rdataset_first(msg->querytsig);
1176 if (ret != ISC_R_SUCCESS)
1178 dns_rdataset_current(msg->querytsig, &rdata);
1179 ret = dns_rdata_tostruct(&rdata, &querytsig, NULL);
1180 if (ret != ISC_R_SUCCESS)
1182 dns_rdata_reset(&rdata);
1185 * If there is a TSIG in this message, do some checks.
1187 if (msg->tsig != NULL) {
1188 has_tsig = ISC_TRUE;
1190 keyname = msg->tsigname;
1191 ret = dns_rdataset_first(msg->tsig);
1192 if (ret != ISC_R_SUCCESS)
1193 goto cleanup_querystruct;
1194 dns_rdataset_current(msg->tsig, &rdata);
1195 ret = dns_rdata_tostruct(&rdata, &tsig, NULL);
1196 if (ret != ISC_R_SUCCESS)
1197 goto cleanup_querystruct;
1200 * Do the key name and algorithm match that of the query?
1202 if (!dns_name_equal(keyname, &tsigkey->name) ||
1203 !dns_name_equal(&tsig.algorithm, &querytsig.algorithm))
1205 msg->tsigstatus = dns_tsigerror_badkey;
1206 ret = DNS_R_TSIGVERIFYFAILURE;
1207 tsig_log(msg->tsigkey, 2,
1208 "key name and algorithm do not match");
1209 goto cleanup_querystruct;
1215 isc_stdtime_get(&now);
1217 if (now + msg->timeadjust > tsig.timesigned + tsig.fudge) {
1218 msg->tsigstatus = dns_tsigerror_badtime;
1219 tsig_log(msg->tsigkey, 2, "signature has expired");
1220 ret = DNS_R_CLOCKSKEW;
1221 goto cleanup_querystruct;
1222 } else if (now + msg->timeadjust <
1223 tsig.timesigned - tsig.fudge)
1225 msg->tsigstatus = dns_tsigerror_badtime;
1226 tsig_log(msg->tsigkey, 2,
1227 "signature is in the future");
1228 ret = DNS_R_CLOCKSKEW;
1229 goto cleanup_querystruct;
1235 if (msg->tsigctx == NULL) {
1236 ret = dst_context_create(key, mctx, &msg->tsigctx);
1237 if (ret != ISC_R_SUCCESS)
1238 goto cleanup_querystruct;
1241 * Digest the length of the query signature
1243 isc_buffer_init(&databuf, data, sizeof(data));
1244 isc_buffer_putuint16(&databuf, querytsig.siglen);
1245 isc_buffer_usedregion(&databuf, &r);
1246 ret = dst_context_adddata(msg->tsigctx, &r);
1247 if (ret != ISC_R_SUCCESS)
1248 goto cleanup_context;
1251 * Digest the data of the query signature
1253 if (querytsig.siglen > 0) {
1254 r.length = querytsig.siglen;
1255 r.base = querytsig.signature;
1256 ret = dst_context_adddata(msg->tsigctx, &r);
1257 if (ret != ISC_R_SUCCESS)
1258 goto cleanup_context;
1263 * Extract the header.
1265 isc_buffer_usedregion(source, &r);
1266 memcpy(header, r.base, DNS_MESSAGE_HEADERLEN);
1267 isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
1270 * Decrement the additional field counter if necessary.
1273 memcpy(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
1274 addcount = htons((isc_uint16_t)(ntohs(addcount) - 1));
1275 memcpy(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);
1279 * Put in the original id.
1281 /* XXX Can TCP transfers be forwarded? How would that work? */
1283 id = htons(tsig.originalid);
1284 memcpy(&header[0], &id, 2);
1288 * Digest the modified header.
1290 header_r.base = (unsigned char *) header;
1291 header_r.length = DNS_MESSAGE_HEADERLEN;
1292 ret = dst_context_adddata(msg->tsigctx, &header_r);
1293 if (ret != ISC_R_SUCCESS)
1294 goto cleanup_context;
1297 * Digest all non-TSIG records.
1299 isc_buffer_usedregion(source, &source_r);
1300 r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
1302 r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN;
1304 r.length = source_r.length - DNS_MESSAGE_HEADERLEN;
1305 ret = dst_context_adddata(msg->tsigctx, &r);
1306 if (ret != ISC_R_SUCCESS)
1307 goto cleanup_context;
1310 * Digest the time signed and fudge.
1313 isc_buffer_init(&databuf, data, sizeof(data));
1314 buffer_putuint48(&databuf, tsig.timesigned);
1315 isc_buffer_putuint16(&databuf, tsig.fudge);
1316 isc_buffer_usedregion(&databuf, &r);
1317 ret = dst_context_adddata(msg->tsigctx, &r);
1318 if (ret != ISC_R_SUCCESS)
1319 goto cleanup_context;
1321 sig_r.base = tsig.signature;
1322 sig_r.length = tsig.siglen;
1323 if (tsig.siglen == 0) {
1324 if (tsig.error != dns_rcode_noerror) {
1325 if (tsig.error == dns_tsigerror_badtime)
1326 ret = DNS_R_CLOCKSKEW;
1328 ret = DNS_R_TSIGERRORSET;
1330 tsig_log(msg->tsigkey, 2,
1331 "signature is empty");
1332 ret = DNS_R_TSIGVERIFYFAILURE;
1334 goto cleanup_context;
1337 ret = dst_context_verify(msg->tsigctx, &sig_r);
1338 if (ret == DST_R_VERIFYFAILURE) {
1339 msg->tsigstatus = dns_tsigerror_badsig;
1340 tsig_log(msg->tsigkey, 2,
1341 "signature failed to verify");
1342 ret = DNS_R_TSIGVERIFYFAILURE;
1343 goto cleanup_context;
1345 else if (ret != ISC_R_SUCCESS)
1346 goto cleanup_context;
1348 dst_context_destroy(&msg->tsigctx);
1351 msg->tsigstatus = dns_rcode_noerror;
1352 return (ISC_R_SUCCESS);
1355 dst_context_destroy(&msg->tsigctx);
1357 cleanup_querystruct:
1358 dns_rdata_freestruct(&querytsig);
1365 dns_tsigkey_find(dns_tsigkey_t **tsigkey, dns_name_t *name,
1366 dns_name_t *algorithm, dns_tsig_keyring_t *ring)
1370 isc_result_t result;
1372 REQUIRE(tsigkey != NULL);
1373 REQUIRE(*tsigkey == NULL);
1374 REQUIRE(name != NULL);
1375 REQUIRE(ring != NULL);
1377 isc_stdtime_get(&now);
1378 RWLOCK(&ring->lock, isc_rwlocktype_read);
1380 result = dns_rbt_findname(ring->keys, name, 0, NULL, (void *)&key);
1381 if (result == DNS_R_PARTIALMATCH || result == ISC_R_NOTFOUND) {
1382 RWUNLOCK(&ring->lock, isc_rwlocktype_read);
1383 return (ISC_R_NOTFOUND);
1385 if (algorithm != NULL && !dns_name_equal(key->algorithm, algorithm)) {
1386 RWUNLOCK(&ring->lock, isc_rwlocktype_read);
1387 return (ISC_R_NOTFOUND);
1389 if (key->inception != key->expire && key->expire < now) {
1391 * The key has expired.
1393 RWUNLOCK(&ring->lock, isc_rwlocktype_read);
1394 RWLOCK(&ring->lock, isc_rwlocktype_write);
1395 (void) dns_rbt_deletename(ring->keys, name, ISC_FALSE);
1396 RWUNLOCK(&ring->lock, isc_rwlocktype_write);
1397 return (ISC_R_NOTFOUND);
1400 isc_refcount_increment(&key->refs, NULL);
1401 RWUNLOCK(&ring->lock, isc_rwlocktype_read);
1403 return (ISC_R_SUCCESS);
1407 free_tsignode(void *node, void *_unused) {
1412 REQUIRE(node != NULL);
1415 dns_tsigkey_detach(&key);
1419 dns_tsigkeyring_create(isc_mem_t *mctx, dns_tsig_keyring_t **ringp) {
1420 isc_result_t result;
1421 dns_tsig_keyring_t *ring;
1423 REQUIRE(mctx != NULL);
1424 REQUIRE(ringp != NULL);
1425 REQUIRE(*ringp == NULL);
1427 ring = isc_mem_get(mctx, sizeof(dns_tsig_keyring_t));
1429 return (ISC_R_NOMEMORY);
1431 result = isc_rwlock_init(&ring->lock, 0, 0);
1432 if (result != ISC_R_SUCCESS) {
1433 isc_mem_put(mctx, ring, sizeof(dns_tsig_keyring_t));
1438 result = dns_rbt_create(mctx, free_tsignode, NULL, &ring->keys);
1439 if (result != ISC_R_SUCCESS) {
1440 isc_rwlock_destroy(&ring->lock);
1441 isc_mem_put(mctx, ring, sizeof(dns_tsig_keyring_t));
1448 return (ISC_R_SUCCESS);
1452 dns_tsigkeyring_destroy(dns_tsig_keyring_t **ringp) {
1453 dns_tsig_keyring_t *ring;
1455 REQUIRE(ringp != NULL);
1456 REQUIRE(*ringp != NULL);
1461 dns_rbt_destroy(&ring->keys);
1462 isc_rwlock_destroy(&ring->lock);
1463 isc_mem_put(ring->mctx, ring, sizeof(dns_tsig_keyring_t));