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