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