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