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