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