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