]> CyberLeo.Net >> Repos - FreeBSD/releng/9.0.git/blob - contrib/bind9/lib/dns/tsig.c
Copy stable/9 to releng/9.0 as part of the FreeBSD 9.0-RELEASE release
[FreeBSD/releng/9.0.git] / contrib / bind9 / lib / dns / tsig.c
1 /*
2  * Copyright (C) 2004-2011  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: tsig.c,v 1.147.10.1 2011-03-21 19:53:34 each Exp $
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
893         REQUIRE(msg != NULL);
894         REQUIRE(VALID_TSIG_KEY(dns_message_gettsigkey(msg)));
895
896         /*
897          * If this is a response, there should be a query tsig.
898          */
899         if (is_response(msg) && msg->querytsig == NULL)
900                 return (DNS_R_EXPECTEDTSIG);
901
902         dynbuf = NULL;
903
904         mctx = msg->mctx;
905         key = dns_message_gettsigkey(msg);
906
907         tsig.mctx = mctx;
908         tsig.common.rdclass = dns_rdataclass_any;
909         tsig.common.rdtype = dns_rdatatype_tsig;
910         ISC_LINK_INIT(&tsig.common, link);
911         dns_name_init(&tsig.algorithm, NULL);
912         dns_name_clone(key->algorithm, &tsig.algorithm);
913
914         isc_stdtime_get(&now);
915         tsig.timesigned = now + msg->timeadjust;
916         tsig.fudge = DNS_TSIG_FUDGE;
917
918         tsig.originalid = msg->id;
919
920         isc_buffer_init(&databuf, data, sizeof(data));
921
922         if (is_response(msg))
923                 tsig.error = msg->querytsigstatus;
924         else
925                 tsig.error = dns_rcode_noerror;
926
927         if (tsig.error != dns_tsigerror_badtime) {
928                 tsig.otherlen = 0;
929                 tsig.other = NULL;
930         } else {
931                 isc_buffer_t otherbuf;
932
933                 tsig.otherlen = BADTIMELEN;
934                 tsig.other = badtimedata;
935                 isc_buffer_init(&otherbuf, tsig.other, tsig.otherlen);
936                 isc_buffer_putuint48(&otherbuf, tsig.timesigned);
937         }
938
939         if (key->key != NULL && tsig.error != dns_tsigerror_badsig) {
940                 unsigned char header[DNS_MESSAGE_HEADERLEN];
941                 isc_buffer_t headerbuf;
942                 isc_uint16_t digestbits;
943
944                 ret = dst_context_create(key->key, mctx, &ctx);
945                 if (ret != ISC_R_SUCCESS)
946                         return (ret);
947
948                 /*
949                  * If this is a response, digest the query signature.
950                  */
951                 if (is_response(msg)) {
952                         dns_rdata_t querytsigrdata = DNS_RDATA_INIT;
953
954                         ret = dns_rdataset_first(msg->querytsig);
955                         if (ret != ISC_R_SUCCESS)
956                                 goto cleanup_context;
957                         dns_rdataset_current(msg->querytsig, &querytsigrdata);
958                         ret = dns_rdata_tostruct(&querytsigrdata, &querytsig,
959                                                  NULL);
960                         if (ret != ISC_R_SUCCESS)
961                                 goto cleanup_context;
962                         isc_buffer_putuint16(&databuf, querytsig.siglen);
963                         if (isc_buffer_availablelength(&databuf) <
964                             querytsig.siglen) {
965                                 ret = ISC_R_NOSPACE;
966                                 goto cleanup_context;
967                         }
968                         isc_buffer_putmem(&databuf, querytsig.signature,
969                                           querytsig.siglen);
970                         isc_buffer_usedregion(&databuf, &r);
971                         ret = dst_context_adddata(ctx, &r);
972                         if (ret != ISC_R_SUCCESS)
973                                 goto cleanup_context;
974                 }
975
976                 /*
977                  * Digest the header.
978                  */
979                 isc_buffer_init(&headerbuf, header, sizeof(header));
980                 dns_message_renderheader(msg, &headerbuf);
981                 isc_buffer_usedregion(&headerbuf, &r);
982                 ret = dst_context_adddata(ctx, &r);
983                 if (ret != ISC_R_SUCCESS)
984                         goto cleanup_context;
985
986                 /*
987                  * Digest the remainder of the message.
988                  */
989                 isc_buffer_usedregion(msg->buffer, &r);
990                 isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
991                 ret = dst_context_adddata(ctx, &r);
992                 if (ret != ISC_R_SUCCESS)
993                         goto cleanup_context;
994
995                 if (msg->tcp_continuation == 0) {
996                         /*
997                          * Digest the name, class, ttl, alg.
998                          */
999                         dns_name_toregion(&key->name, &r);
1000                         ret = dst_context_adddata(ctx, &r);
1001                         if (ret != ISC_R_SUCCESS)
1002                                 goto cleanup_context;
1003
1004                         isc_buffer_clear(&databuf);
1005                         isc_buffer_putuint16(&databuf, dns_rdataclass_any);
1006                         isc_buffer_putuint32(&databuf, 0); /* ttl */
1007                         isc_buffer_usedregion(&databuf, &r);
1008                         ret = dst_context_adddata(ctx, &r);
1009                         if (ret != ISC_R_SUCCESS)
1010                                 goto cleanup_context;
1011
1012                         dns_name_toregion(&tsig.algorithm, &r);
1013                         ret = dst_context_adddata(ctx, &r);
1014                         if (ret != ISC_R_SUCCESS)
1015                                 goto cleanup_context;
1016
1017                 }
1018                 /* Digest the timesigned and fudge */
1019                 isc_buffer_clear(&databuf);
1020                 if (tsig.error == dns_tsigerror_badtime)
1021                         tsig.timesigned = querytsig.timesigned;
1022                 isc_buffer_putuint48(&databuf, tsig.timesigned);
1023                 isc_buffer_putuint16(&databuf, tsig.fudge);
1024                 isc_buffer_usedregion(&databuf, &r);
1025                 ret = dst_context_adddata(ctx, &r);
1026                 if (ret != ISC_R_SUCCESS)
1027                         goto cleanup_context;
1028
1029                 if (msg->tcp_continuation == 0) {
1030                         /*
1031                          * Digest the error and other data length.
1032                          */
1033                         isc_buffer_clear(&databuf);
1034                         isc_buffer_putuint16(&databuf, tsig.error);
1035                         isc_buffer_putuint16(&databuf, tsig.otherlen);
1036
1037                         isc_buffer_usedregion(&databuf, &r);
1038                         ret = dst_context_adddata(ctx, &r);
1039                         if (ret != ISC_R_SUCCESS)
1040                                 goto cleanup_context;
1041
1042                         /*
1043                          * Digest the error and other data.
1044                          */
1045                         if (tsig.otherlen > 0) {
1046                                 r.length = tsig.otherlen;
1047                                 r.base = tsig.other;
1048                                 ret = dst_context_adddata(ctx, &r);
1049                                 if (ret != ISC_R_SUCCESS)
1050                                         goto cleanup_context;
1051                         }
1052                 }
1053
1054                 ret = dst_key_sigsize(key->key, &sigsize);
1055                 if (ret != ISC_R_SUCCESS)
1056                         goto cleanup_context;
1057                 tsig.signature = (unsigned char *) isc_mem_get(mctx, sigsize);
1058                 if (tsig.signature == NULL) {
1059                         ret = ISC_R_NOMEMORY;
1060                         goto cleanup_context;
1061                 }
1062
1063                 isc_buffer_init(&sigbuf, tsig.signature, sigsize);
1064                 ret = dst_context_sign(ctx, &sigbuf);
1065                 if (ret != ISC_R_SUCCESS)
1066                         goto cleanup_signature;
1067                 dst_context_destroy(&ctx);
1068                 digestbits = dst_key_getbits(key->key);
1069                 if (digestbits != 0) {
1070                         unsigned int bytes = (digestbits + 1) / 8;
1071                         if (is_response(msg) && bytes < querytsig.siglen)
1072                                 bytes = querytsig.siglen;
1073                         if (bytes > isc_buffer_usedlength(&sigbuf))
1074                                 bytes = isc_buffer_usedlength(&sigbuf);
1075                         tsig.siglen = bytes;
1076                 } else
1077                         tsig.siglen = isc_buffer_usedlength(&sigbuf);
1078         } else {
1079                 tsig.siglen = 0;
1080                 tsig.signature = NULL;
1081         }
1082
1083         ret = dns_message_gettemprdata(msg, &rdata);
1084         if (ret != ISC_R_SUCCESS)
1085                 goto cleanup_signature;
1086         ret = isc_buffer_allocate(msg->mctx, &dynbuf, 512);
1087         if (ret != ISC_R_SUCCESS)
1088                 goto cleanup_rdata;
1089         ret = dns_rdata_fromstruct(rdata, dns_rdataclass_any,
1090                                    dns_rdatatype_tsig, &tsig, dynbuf);
1091         if (ret != ISC_R_SUCCESS)
1092                 goto cleanup_dynbuf;
1093
1094         dns_message_takebuffer(msg, &dynbuf);
1095
1096         if (tsig.signature != NULL) {
1097                 isc_mem_put(mctx, tsig.signature, sigsize);
1098                 tsig.signature = NULL;
1099         }
1100
1101         owner = NULL;
1102         ret = dns_message_gettempname(msg, &owner);
1103         if (ret != ISC_R_SUCCESS)
1104                 goto cleanup_rdata;
1105         dns_name_init(owner, NULL);
1106         ret = dns_name_dup(&key->name, msg->mctx, owner);
1107         if (ret != ISC_R_SUCCESS)
1108                 goto cleanup_owner;
1109
1110         datalist = NULL;
1111         ret = dns_message_gettemprdatalist(msg, &datalist);
1112         if (ret != ISC_R_SUCCESS)
1113                 goto cleanup_owner;
1114         dataset = NULL;
1115         ret = dns_message_gettemprdataset(msg, &dataset);
1116         if (ret != ISC_R_SUCCESS)
1117                 goto cleanup_rdatalist;
1118         datalist->rdclass = dns_rdataclass_any;
1119         datalist->type = dns_rdatatype_tsig;
1120         datalist->covers = 0;
1121         datalist->ttl = 0;
1122         ISC_LIST_INIT(datalist->rdata);
1123         ISC_LIST_APPEND(datalist->rdata, rdata, link);
1124         dns_rdataset_init(dataset);
1125         RUNTIME_CHECK(dns_rdatalist_tordataset(datalist, dataset)
1126                       == ISC_R_SUCCESS);
1127         msg->tsig = dataset;
1128         msg->tsigname = owner;
1129
1130         /* Windows does not like the tsig name being compressed. */
1131         msg->tsigname->attributes |= DNS_NAMEATTR_NOCOMPRESS;
1132
1133         return (ISC_R_SUCCESS);
1134
1135  cleanup_rdatalist:
1136         dns_message_puttemprdatalist(msg, &datalist);
1137  cleanup_owner:
1138         dns_message_puttempname(msg, &owner);
1139         goto cleanup_rdata;
1140  cleanup_dynbuf:
1141         isc_buffer_free(&dynbuf);
1142  cleanup_rdata:
1143         dns_message_puttemprdata(msg, &rdata);
1144  cleanup_signature:
1145         if (tsig.signature != NULL)
1146                 isc_mem_put(mctx, tsig.signature, sigsize);
1147  cleanup_context:
1148         if (ctx != NULL)
1149                 dst_context_destroy(&ctx);
1150         return (ret);
1151 }
1152
1153 isc_result_t
1154 dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
1155                 dns_tsig_keyring_t *ring1, dns_tsig_keyring_t *ring2)
1156 {
1157         dns_rdata_any_tsig_t tsig, querytsig;
1158         isc_region_t r, source_r, header_r, sig_r;
1159         isc_buffer_t databuf;
1160         unsigned char data[32];
1161         dns_name_t *keyname;
1162         dns_rdata_t rdata = DNS_RDATA_INIT;
1163         isc_stdtime_t now;
1164         isc_result_t ret;
1165         dns_tsigkey_t *tsigkey;
1166         dst_key_t *key = NULL;
1167         unsigned char header[DNS_MESSAGE_HEADERLEN];
1168         dst_context_t *ctx = NULL;
1169         isc_mem_t *mctx;
1170         isc_uint16_t addcount, id;
1171         unsigned int siglen;
1172         unsigned int alg;
1173
1174         REQUIRE(source != NULL);
1175         REQUIRE(DNS_MESSAGE_VALID(msg));
1176         tsigkey = dns_message_gettsigkey(msg);
1177
1178         REQUIRE(tsigkey == NULL || VALID_TSIG_KEY(tsigkey));
1179
1180         msg->verify_attempted = 1;
1181
1182         if (msg->tcp_continuation) {
1183                 if (tsigkey == NULL || msg->querytsig == NULL)
1184                         return (DNS_R_UNEXPECTEDTSIG);
1185                 return (tsig_verify_tcp(source, msg));
1186         }
1187
1188         /*
1189          * There should be a TSIG record...
1190          */
1191         if (msg->tsig == NULL)
1192                 return (DNS_R_EXPECTEDTSIG);
1193
1194         /*
1195          * If this is a response and there's no key or query TSIG, there
1196          * shouldn't be one on the response.
1197          */
1198         if (is_response(msg) &&
1199             (tsigkey == NULL || msg->querytsig == NULL))
1200                 return (DNS_R_UNEXPECTEDTSIG);
1201
1202         mctx = msg->mctx;
1203
1204         /*
1205          * If we're here, we know the message is well formed and contains a
1206          * TSIG record.
1207          */
1208
1209         keyname = msg->tsigname;
1210         ret = dns_rdataset_first(msg->tsig);
1211         if (ret != ISC_R_SUCCESS)
1212                 return (ret);
1213         dns_rdataset_current(msg->tsig, &rdata);
1214         ret = dns_rdata_tostruct(&rdata, &tsig, NULL);
1215         if (ret != ISC_R_SUCCESS)
1216                 return (ret);
1217         dns_rdata_reset(&rdata);
1218         if (is_response(msg)) {
1219                 ret = dns_rdataset_first(msg->querytsig);
1220                 if (ret != ISC_R_SUCCESS)
1221                         return (ret);
1222                 dns_rdataset_current(msg->querytsig, &rdata);
1223                 ret = dns_rdata_tostruct(&rdata, &querytsig, NULL);
1224                 if (ret != ISC_R_SUCCESS)
1225                         return (ret);
1226         }
1227
1228         /*
1229          * Do the key name and algorithm match that of the query?
1230          */
1231         if (is_response(msg) &&
1232             (!dns_name_equal(keyname, &tsigkey->name) ||
1233              !dns_name_equal(&tsig.algorithm, &querytsig.algorithm))) {
1234                 msg->tsigstatus = dns_tsigerror_badkey;
1235                 tsig_log(msg->tsigkey, 2,
1236                          "key name and algorithm do not match");
1237                 return (DNS_R_TSIGVERIFYFAILURE);
1238         }
1239
1240         /*
1241          * Get the current time.
1242          */
1243         isc_stdtime_get(&now);
1244
1245         /*
1246          * Find dns_tsigkey_t based on keyname.
1247          */
1248         if (tsigkey == NULL) {
1249                 ret = ISC_R_NOTFOUND;
1250                 if (ring1 != NULL)
1251                         ret = dns_tsigkey_find(&tsigkey, keyname,
1252                                                &tsig.algorithm, ring1);
1253                 if (ret == ISC_R_NOTFOUND && ring2 != NULL)
1254                         ret = dns_tsigkey_find(&tsigkey, keyname,
1255                                                &tsig.algorithm, ring2);
1256                 if (ret != ISC_R_SUCCESS) {
1257                         msg->tsigstatus = dns_tsigerror_badkey;
1258                         ret = dns_tsigkey_create(keyname, &tsig.algorithm,
1259                                                  NULL, 0, ISC_FALSE, NULL,
1260                                                  now, now,
1261                                                  mctx, NULL, &msg->tsigkey);
1262                         if (ret != ISC_R_SUCCESS)
1263                                 return (ret);
1264                         tsig_log(msg->tsigkey, 2, "unknown key");
1265                         return (DNS_R_TSIGVERIFYFAILURE);
1266                 }
1267                 msg->tsigkey = tsigkey;
1268         }
1269
1270         key = tsigkey->key;
1271
1272         /*
1273          * Is the time ok?
1274          */
1275         if (now + msg->timeadjust > tsig.timesigned + tsig.fudge) {
1276                 msg->tsigstatus = dns_tsigerror_badtime;
1277                 tsig_log(msg->tsigkey, 2, "signature has expired");
1278                 return (DNS_R_CLOCKSKEW);
1279         } else if (now + msg->timeadjust < tsig.timesigned - tsig.fudge) {
1280                 msg->tsigstatus = dns_tsigerror_badtime;
1281                 tsig_log(msg->tsigkey, 2, "signature is in the future");
1282                 return (DNS_R_CLOCKSKEW);
1283         }
1284
1285         /*
1286          * Check digest length.
1287          */
1288         alg = dst_key_alg(key);
1289         ret = dst_key_sigsize(key, &siglen);
1290         if (ret != ISC_R_SUCCESS)
1291                 return (ret);
1292         if (alg == DST_ALG_HMACMD5 || alg == DST_ALG_HMACSHA1 ||
1293             alg == DST_ALG_HMACSHA224 || alg == DST_ALG_HMACSHA256 ||
1294             alg == DST_ALG_HMACSHA384 || alg == DST_ALG_HMACSHA512) {
1295                 isc_uint16_t digestbits = dst_key_getbits(key);
1296                 if (tsig.siglen > siglen) {
1297                         tsig_log(msg->tsigkey, 2, "signature length to big");
1298                         return (DNS_R_FORMERR);
1299                 }
1300                 if (tsig.siglen > 0 &&
1301                     (tsig.siglen < 10 || tsig.siglen < ((siglen + 1) / 2))) {
1302                         tsig_log(msg->tsigkey, 2,
1303                                  "signature length below minimum");
1304                         return (DNS_R_FORMERR);
1305                 }
1306                 if (tsig.siglen > 0 && digestbits != 0 &&
1307                     tsig.siglen < ((digestbits + 1) / 8)) {
1308                         msg->tsigstatus = dns_tsigerror_badtrunc;
1309                         tsig_log(msg->tsigkey, 2,
1310                                  "truncated signature length too small");
1311                         return (DNS_R_TSIGVERIFYFAILURE);
1312                 }
1313                 if (tsig.siglen > 0 && digestbits == 0 &&
1314                     tsig.siglen < siglen) {
1315                         msg->tsigstatus = dns_tsigerror_badtrunc;
1316                         tsig_log(msg->tsigkey, 2, "signature length too small");
1317                         return (DNS_R_TSIGVERIFYFAILURE);
1318                 }
1319         }
1320
1321         if (tsig.siglen > 0) {
1322                 sig_r.base = tsig.signature;
1323                 sig_r.length = tsig.siglen;
1324
1325                 ret = dst_context_create(key, mctx, &ctx);
1326                 if (ret != ISC_R_SUCCESS)
1327                         return (ret);
1328
1329                 if (is_response(msg)) {
1330                         isc_buffer_init(&databuf, data, sizeof(data));
1331                         isc_buffer_putuint16(&databuf, querytsig.siglen);
1332                         isc_buffer_usedregion(&databuf, &r);
1333                         ret = dst_context_adddata(ctx, &r);
1334                         if (ret != ISC_R_SUCCESS)
1335                                 goto cleanup_context;
1336                         if (querytsig.siglen > 0) {
1337                                 r.length = querytsig.siglen;
1338                                 r.base = querytsig.signature;
1339                                 ret = dst_context_adddata(ctx, &r);
1340                                 if (ret != ISC_R_SUCCESS)
1341                                         goto cleanup_context;
1342                         }
1343                 }
1344
1345                 /*
1346                  * Extract the header.
1347                  */
1348                 isc_buffer_usedregion(source, &r);
1349                 memcpy(header, r.base, DNS_MESSAGE_HEADERLEN);
1350                 isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
1351
1352                 /*
1353                  * Decrement the additional field counter.
1354                  */
1355                 memcpy(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
1356                 addcount = htons((isc_uint16_t)(ntohs(addcount) - 1));
1357                 memcpy(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);
1358
1359                 /*
1360                  * Put in the original id.
1361                  */
1362                 id = htons(tsig.originalid);
1363                 memcpy(&header[0], &id, 2);
1364
1365                 /*
1366                  * Digest the modified header.
1367                  */
1368                 header_r.base = (unsigned char *) header;
1369                 header_r.length = DNS_MESSAGE_HEADERLEN;
1370                 ret = dst_context_adddata(ctx, &header_r);
1371                 if (ret != ISC_R_SUCCESS)
1372                         goto cleanup_context;
1373
1374                 /*
1375                  * Digest all non-TSIG records.
1376                  */
1377                 isc_buffer_usedregion(source, &source_r);
1378                 r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
1379                 r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN;
1380                 ret = dst_context_adddata(ctx, &r);
1381                 if (ret != ISC_R_SUCCESS)
1382                         goto cleanup_context;
1383
1384                 /*
1385                  * Digest the key name.
1386                  */
1387                 dns_name_toregion(&tsigkey->name, &r);
1388                 ret = dst_context_adddata(ctx, &r);
1389                 if (ret != ISC_R_SUCCESS)
1390                         goto cleanup_context;
1391
1392                 isc_buffer_init(&databuf, data, sizeof(data));
1393                 isc_buffer_putuint16(&databuf, tsig.common.rdclass);
1394                 isc_buffer_putuint32(&databuf, msg->tsig->ttl);
1395                 isc_buffer_usedregion(&databuf, &r);
1396                 ret = dst_context_adddata(ctx, &r);
1397                 if (ret != ISC_R_SUCCESS)
1398                         goto cleanup_context;
1399
1400                 /*
1401                  * Digest the key algorithm.
1402                  */
1403                 dns_name_toregion(tsigkey->algorithm, &r);
1404                 ret = dst_context_adddata(ctx, &r);
1405                 if (ret != ISC_R_SUCCESS)
1406                         goto cleanup_context;
1407
1408                 isc_buffer_clear(&databuf);
1409                 isc_buffer_putuint48(&databuf, tsig.timesigned);
1410                 isc_buffer_putuint16(&databuf, tsig.fudge);
1411                 isc_buffer_putuint16(&databuf, tsig.error);
1412                 isc_buffer_putuint16(&databuf, tsig.otherlen);
1413                 isc_buffer_usedregion(&databuf, &r);
1414                 ret = dst_context_adddata(ctx, &r);
1415                 if (ret != ISC_R_SUCCESS)
1416                         goto cleanup_context;
1417
1418                 if (tsig.otherlen > 0) {
1419                         r.base = tsig.other;
1420                         r.length = tsig.otherlen;
1421                         ret = dst_context_adddata(ctx, &r);
1422                         if (ret != ISC_R_SUCCESS)
1423                                 goto cleanup_context;
1424                 }
1425
1426                 ret = dst_context_verify(ctx, &sig_r);
1427                 if (ret == DST_R_VERIFYFAILURE) {
1428                         msg->tsigstatus = dns_tsigerror_badsig;
1429                         ret = DNS_R_TSIGVERIFYFAILURE;
1430                         tsig_log(msg->tsigkey, 2,
1431                                  "signature failed to verify(1)");
1432                         goto cleanup_context;
1433                 } else if (ret != ISC_R_SUCCESS)
1434                         goto cleanup_context;
1435
1436                 dst_context_destroy(&ctx);
1437         } else if (tsig.error != dns_tsigerror_badsig &&
1438                    tsig.error != dns_tsigerror_badkey) {
1439                 msg->tsigstatus = dns_tsigerror_badsig;
1440                 tsig_log(msg->tsigkey, 2, "signature was empty");
1441                 return (DNS_R_TSIGVERIFYFAILURE);
1442         }
1443
1444         msg->tsigstatus = dns_rcode_noerror;
1445
1446         if (tsig.error != dns_rcode_noerror) {
1447                 if (tsig.error == dns_tsigerror_badtime)
1448                         return (DNS_R_CLOCKSKEW);
1449                 else
1450                         return (DNS_R_TSIGERRORSET);
1451         }
1452
1453         msg->verified_sig = 1;
1454
1455         return (ISC_R_SUCCESS);
1456
1457 cleanup_context:
1458         if (ctx != NULL)
1459                 dst_context_destroy(&ctx);
1460
1461         return (ret);
1462 }
1463
1464 static isc_result_t
1465 tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) {
1466         dns_rdata_any_tsig_t tsig, querytsig;
1467         isc_region_t r, source_r, header_r, sig_r;
1468         isc_buffer_t databuf;
1469         unsigned char data[32];
1470         dns_name_t *keyname;
1471         dns_rdata_t rdata = DNS_RDATA_INIT;
1472         isc_stdtime_t now;
1473         isc_result_t ret;
1474         dns_tsigkey_t *tsigkey;
1475         dst_key_t *key = NULL;
1476         unsigned char header[DNS_MESSAGE_HEADERLEN];
1477         isc_uint16_t addcount, id;
1478         isc_boolean_t has_tsig = ISC_FALSE;
1479         isc_mem_t *mctx;
1480
1481         REQUIRE(source != NULL);
1482         REQUIRE(msg != NULL);
1483         REQUIRE(dns_message_gettsigkey(msg) != NULL);
1484         REQUIRE(msg->tcp_continuation == 1);
1485         REQUIRE(msg->querytsig != NULL);
1486
1487         if (!is_response(msg))
1488                 return (DNS_R_EXPECTEDRESPONSE);
1489
1490         mctx = msg->mctx;
1491
1492         tsigkey = dns_message_gettsigkey(msg);
1493
1494         /*
1495          * Extract and parse the previous TSIG
1496          */
1497         ret = dns_rdataset_first(msg->querytsig);
1498         if (ret != ISC_R_SUCCESS)
1499                 return (ret);
1500         dns_rdataset_current(msg->querytsig, &rdata);
1501         ret = dns_rdata_tostruct(&rdata, &querytsig, NULL);
1502         if (ret != ISC_R_SUCCESS)
1503                 return (ret);
1504         dns_rdata_reset(&rdata);
1505
1506         /*
1507          * If there is a TSIG in this message, do some checks.
1508          */
1509         if (msg->tsig != NULL) {
1510                 has_tsig = ISC_TRUE;
1511
1512                 keyname = msg->tsigname;
1513                 ret = dns_rdataset_first(msg->tsig);
1514                 if (ret != ISC_R_SUCCESS)
1515                         goto cleanup_querystruct;
1516                 dns_rdataset_current(msg->tsig, &rdata);
1517                 ret = dns_rdata_tostruct(&rdata, &tsig, NULL);
1518                 if (ret != ISC_R_SUCCESS)
1519                         goto cleanup_querystruct;
1520
1521                 /*
1522                  * Do the key name and algorithm match that of the query?
1523                  */
1524                 if (!dns_name_equal(keyname, &tsigkey->name) ||
1525                     !dns_name_equal(&tsig.algorithm, &querytsig.algorithm)) {
1526                         msg->tsigstatus = dns_tsigerror_badkey;
1527                         ret = DNS_R_TSIGVERIFYFAILURE;
1528                         tsig_log(msg->tsigkey, 2,
1529                                  "key name and algorithm do not match");
1530                         goto cleanup_querystruct;
1531                 }
1532
1533                 /*
1534                  * Is the time ok?
1535                  */
1536                 isc_stdtime_get(&now);
1537
1538                 if (now + msg->timeadjust > tsig.timesigned + tsig.fudge) {
1539                         msg->tsigstatus = dns_tsigerror_badtime;
1540                         tsig_log(msg->tsigkey, 2, "signature has expired");
1541                         ret = DNS_R_CLOCKSKEW;
1542                         goto cleanup_querystruct;
1543                 } else if (now + msg->timeadjust <
1544                            tsig.timesigned - tsig.fudge) {
1545                         msg->tsigstatus = dns_tsigerror_badtime;
1546                         tsig_log(msg->tsigkey, 2,
1547                                  "signature is in the future");
1548                         ret = DNS_R_CLOCKSKEW;
1549                         goto cleanup_querystruct;
1550                 }
1551         }
1552
1553         key = tsigkey->key;
1554
1555         if (msg->tsigctx == NULL) {
1556                 ret = dst_context_create(key, mctx, &msg->tsigctx);
1557                 if (ret != ISC_R_SUCCESS)
1558                         goto cleanup_querystruct;
1559
1560                 /*
1561                  * Digest the length of the query signature
1562                  */
1563                 isc_buffer_init(&databuf, data, sizeof(data));
1564                 isc_buffer_putuint16(&databuf, querytsig.siglen);
1565                 isc_buffer_usedregion(&databuf, &r);
1566                 ret = dst_context_adddata(msg->tsigctx, &r);
1567                 if (ret != ISC_R_SUCCESS)
1568                         goto cleanup_context;
1569
1570                 /*
1571                  * Digest the data of the query signature
1572                  */
1573                 if (querytsig.siglen > 0) {
1574                         r.length = querytsig.siglen;
1575                         r.base = querytsig.signature;
1576                         ret = dst_context_adddata(msg->tsigctx, &r);
1577                         if (ret != ISC_R_SUCCESS)
1578                                 goto cleanup_context;
1579                 }
1580         }
1581
1582         /*
1583          * Extract the header.
1584          */
1585         isc_buffer_usedregion(source, &r);
1586         memcpy(header, r.base, DNS_MESSAGE_HEADERLEN);
1587         isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
1588
1589         /*
1590          * Decrement the additional field counter if necessary.
1591          */
1592         if (has_tsig) {
1593                 memcpy(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
1594                 addcount = htons((isc_uint16_t)(ntohs(addcount) - 1));
1595                 memcpy(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);
1596         }
1597
1598         /*
1599          * Put in the original id.
1600          */
1601         /* XXX Can TCP transfers be forwarded?  How would that work? */
1602         if (has_tsig) {
1603                 id = htons(tsig.originalid);
1604                 memcpy(&header[0], &id, 2);
1605         }
1606
1607         /*
1608          * Digest the modified header.
1609          */
1610         header_r.base = (unsigned char *) header;
1611         header_r.length = DNS_MESSAGE_HEADERLEN;
1612         ret = dst_context_adddata(msg->tsigctx, &header_r);
1613         if (ret != ISC_R_SUCCESS)
1614                 goto cleanup_context;
1615
1616         /*
1617          * Digest all non-TSIG records.
1618          */
1619         isc_buffer_usedregion(source, &source_r);
1620         r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
1621         if (has_tsig)
1622                 r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN;
1623         else
1624                 r.length = source_r.length - DNS_MESSAGE_HEADERLEN;
1625         ret = dst_context_adddata(msg->tsigctx, &r);
1626         if (ret != ISC_R_SUCCESS)
1627                 goto cleanup_context;
1628
1629         /*
1630          * Digest the time signed and fudge.
1631          */
1632         if (has_tsig) {
1633                 isc_buffer_init(&databuf, data, sizeof(data));
1634                 isc_buffer_putuint48(&databuf, tsig.timesigned);
1635                 isc_buffer_putuint16(&databuf, tsig.fudge);
1636                 isc_buffer_usedregion(&databuf, &r);
1637                 ret = dst_context_adddata(msg->tsigctx, &r);
1638                 if (ret != ISC_R_SUCCESS)
1639                         goto cleanup_context;
1640
1641                 sig_r.base = tsig.signature;
1642                 sig_r.length = tsig.siglen;
1643                 if (tsig.siglen == 0) {
1644                         if (tsig.error != dns_rcode_noerror) {
1645                                 if (tsig.error == dns_tsigerror_badtime)
1646                                         ret = DNS_R_CLOCKSKEW;
1647                                 else
1648                                         ret = DNS_R_TSIGERRORSET;
1649                         } else {
1650                                 tsig_log(msg->tsigkey, 2,
1651                                          "signature is empty");
1652                                 ret = DNS_R_TSIGVERIFYFAILURE;
1653                         }
1654                         goto cleanup_context;
1655                 }
1656
1657                 ret = dst_context_verify(msg->tsigctx, &sig_r);
1658                 if (ret == DST_R_VERIFYFAILURE) {
1659                         msg->tsigstatus = dns_tsigerror_badsig;
1660                         tsig_log(msg->tsigkey, 2,
1661                                  "signature failed to verify(2)");
1662                         ret = DNS_R_TSIGVERIFYFAILURE;
1663                         goto cleanup_context;
1664                 }
1665                 else if (ret != ISC_R_SUCCESS)
1666                         goto cleanup_context;
1667
1668                 dst_context_destroy(&msg->tsigctx);
1669         }
1670
1671         msg->tsigstatus = dns_rcode_noerror;
1672         return (ISC_R_SUCCESS);
1673
1674  cleanup_context:
1675         dst_context_destroy(&msg->tsigctx);
1676
1677  cleanup_querystruct:
1678         dns_rdata_freestruct(&querytsig);
1679
1680         return (ret);
1681
1682 }
1683
1684 isc_result_t
1685 dns_tsigkey_find(dns_tsigkey_t **tsigkey, dns_name_t *name,
1686                  dns_name_t *algorithm, dns_tsig_keyring_t *ring)
1687 {
1688         dns_tsigkey_t *key;
1689         isc_stdtime_t now;
1690         isc_result_t result;
1691
1692         REQUIRE(tsigkey != NULL);
1693         REQUIRE(*tsigkey == NULL);
1694         REQUIRE(name != NULL);
1695         REQUIRE(ring != NULL);
1696
1697         RWLOCK(&ring->lock, isc_rwlocktype_write);
1698         cleanup_ring(ring);
1699         RWUNLOCK(&ring->lock, isc_rwlocktype_write);
1700
1701         isc_stdtime_get(&now);
1702         RWLOCK(&ring->lock, isc_rwlocktype_read);
1703         key = NULL;
1704         result = dns_rbt_findname(ring->keys, name, 0, NULL, (void *)&key);
1705         if (result == DNS_R_PARTIALMATCH || result == ISC_R_NOTFOUND) {
1706                 RWUNLOCK(&ring->lock, isc_rwlocktype_read);
1707                 return (ISC_R_NOTFOUND);
1708         }
1709         if (algorithm != NULL && !dns_name_equal(key->algorithm, algorithm)) {
1710                 RWUNLOCK(&ring->lock, isc_rwlocktype_read);
1711                 return (ISC_R_NOTFOUND);
1712         }
1713         if (key->inception != key->expire && isc_serial_lt(key->expire, now)) {
1714                 /*
1715                  * The key has expired.
1716                  */
1717                 RWUNLOCK(&ring->lock, isc_rwlocktype_read);
1718                 RWLOCK(&ring->lock, isc_rwlocktype_write);
1719                 remove_fromring(key);
1720                 RWUNLOCK(&ring->lock, isc_rwlocktype_write);
1721                 return (ISC_R_NOTFOUND);
1722         }
1723 #if 0
1724         /*
1725          * MPAXXX We really should look at the inception time.
1726          */
1727         if (key->inception != key->expire &&
1728             isc_serial_lt(key->inception, now)) {
1729                 RWUNLOCK(&ring->lock, isc_rwlocktype_read);
1730                 adjust_lru(key);
1731                 return (ISC_R_NOTFOUND);
1732         }
1733 #endif
1734         isc_refcount_increment(&key->refs, NULL);
1735         RWUNLOCK(&ring->lock, isc_rwlocktype_read);
1736         adjust_lru(key);
1737         *tsigkey = key;
1738         return (ISC_R_SUCCESS);
1739 }
1740
1741 static void
1742 free_tsignode(void *node, void *_unused) {
1743         dns_tsigkey_t *key;
1744
1745         UNUSED(_unused);
1746
1747         REQUIRE(node != NULL);
1748
1749         key = node;
1750         dns_tsigkey_detach(&key);
1751 }
1752
1753 isc_result_t
1754 dns_tsigkeyring_create(isc_mem_t *mctx, dns_tsig_keyring_t **ringp) {
1755         isc_result_t result;
1756         dns_tsig_keyring_t *ring;
1757
1758         REQUIRE(mctx != NULL);
1759         REQUIRE(ringp != NULL);
1760         REQUIRE(*ringp == NULL);
1761
1762         ring = isc_mem_get(mctx, sizeof(dns_tsig_keyring_t));
1763         if (ring == NULL)
1764                 return (ISC_R_NOMEMORY);
1765
1766         result = isc_rwlock_init(&ring->lock, 0, 0);
1767         if (result != ISC_R_SUCCESS) {
1768                 isc_mem_put(mctx, ring, sizeof(dns_tsig_keyring_t));
1769                 return (result);
1770         }
1771
1772         ring->keys = NULL;
1773         result = dns_rbt_create(mctx, free_tsignode, NULL, &ring->keys);
1774         if (result != ISC_R_SUCCESS) {
1775                 isc_rwlock_destroy(&ring->lock);
1776                 isc_mem_put(mctx, ring, sizeof(dns_tsig_keyring_t));
1777                 return (result);
1778         }
1779
1780         ring->writecount = 0;
1781         ring->mctx = NULL;
1782         ring->generated = 0;
1783         ring->maxgenerated = DNS_TSIG_MAXGENERATEDKEYS;
1784         ISC_LIST_INIT(ring->lru);
1785         isc_mem_attach(mctx, &ring->mctx);
1786         ring->references = 1;
1787
1788         *ringp = ring;
1789         return (ISC_R_SUCCESS);
1790 }
1791
1792 isc_result_t
1793 dns_tsigkeyring_add(dns_tsig_keyring_t *ring, dns_name_t *name,
1794                     dns_tsigkey_t *tkey)
1795 {
1796         isc_result_t result;
1797
1798         result = keyring_add(ring, name, tkey);
1799         if (result == ISC_R_SUCCESS)
1800                 isc_refcount_increment(&tkey->refs, NULL);
1801
1802         return (result);
1803 }
1804
1805 void
1806 dns_tsigkeyring_attach(dns_tsig_keyring_t *source, dns_tsig_keyring_t **target)
1807 {
1808         REQUIRE(source != NULL);
1809         REQUIRE(target != NULL && *target == NULL);
1810
1811         RWLOCK(&source->lock, isc_rwlocktype_write);
1812         INSIST(source->references > 0);
1813         source->references++;
1814         INSIST(source->references > 0);
1815         *target = source;
1816         RWUNLOCK(&source->lock, isc_rwlocktype_write);
1817 }
1818
1819 void
1820 dns_tsigkeyring_detach(dns_tsig_keyring_t **ringp) {
1821         dns_tsig_keyring_t *ring;
1822         unsigned int references;
1823
1824         REQUIRE(ringp != NULL);
1825         REQUIRE(*ringp != NULL);
1826
1827         ring = *ringp;
1828         *ringp = NULL;
1829
1830         RWLOCK(&ring->lock, isc_rwlocktype_write);
1831         INSIST(ring->references > 0);
1832         ring->references--;
1833         references = ring->references;
1834         RWUNLOCK(&ring->lock, isc_rwlocktype_write);
1835
1836         if (references == 0)
1837                 destroyring(ring);
1838 }
1839
1840 void
1841 dns_keyring_restore(dns_tsig_keyring_t *ring, FILE *fp) {
1842         isc_stdtime_t now;
1843         isc_result_t result;
1844
1845         isc_stdtime_get(&now);
1846         do {
1847                 result = restore_key(ring, now, fp);
1848                 if (result == ISC_R_NOMORE)
1849                         return;
1850                 if (result == DNS_R_BADALG || result == DNS_R_EXPIRED)
1851                         result = ISC_R_SUCCESS;
1852         } while (result == ISC_R_SUCCESS);
1853 }