]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bind9/lib/dns/tsig.c
This commit was generated by cvs2svn to compensate for changes in r172314,
[FreeBSD/FreeBSD.git] / contrib / bind9 / lib / dns / tsig.c
1 /*
2  * Copyright (C) 2004-2006  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2002  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and 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.9 2006/05/02 04:23:12 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
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 = mctx;
327
328         tkey->magic = TSIG_MAGIC;
329
330         if (ring != NULL) {
331                 RWLOCK(&ring->lock, isc_rwlocktype_write);
332                 ret = dns_rbt_addname(ring->keys, name, tkey);
333                 if (ret != ISC_R_SUCCESS) {
334                         RWUNLOCK(&ring->lock, isc_rwlocktype_write);
335                         goto cleanup_refs;
336                 }
337                 RWUNLOCK(&ring->lock, isc_rwlocktype_write);
338         }
339
340         if (dstkey != NULL && dst_key_size(dstkey) < 64) {
341                 char namestr[DNS_NAME_FORMATSIZE];
342                 dns_name_format(name, namestr, sizeof(namestr));
343                 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
344                               DNS_LOGMODULE_TSIG, ISC_LOG_INFO,
345                               "the key '%s' is too short to be secure",
346                               namestr);
347         }
348         if (key != NULL)
349                 *key = tkey;
350
351         return (ISC_R_SUCCESS);
352
353  cleanup_refs:
354         tkey->magic = 0;
355         while (refs-- > 0)
356                 isc_refcount_decrement(&tkey->refs, NULL);
357         isc_refcount_destroy(&tkey->refs);
358  cleanup_creator:
359         if (tkey->creator != NULL) {
360                 dns_name_free(tkey->creator, mctx);
361                 isc_mem_put(mctx, tkey->creator, sizeof(dns_name_t));
362         }
363  cleanup_algorithm:
364         if (algname_is_allocated(tkey->algorithm)) {
365                 if (dns_name_dynamic(tkey->algorithm))
366                         dns_name_free(tkey->algorithm, mctx);
367                 isc_mem_put(mctx, tkey->algorithm, sizeof(dns_name_t));
368         }
369  cleanup_name:
370         dns_name_free(&tkey->name, mctx);
371  cleanup_key:
372         isc_mem_put(mctx, tkey, sizeof(dns_tsigkey_t));
373
374         return (ret);
375 }
376
377 isc_result_t
378 dns_tsigkey_create(dns_name_t *name, dns_name_t *algorithm,
379                    unsigned char *secret, int length, isc_boolean_t generated,
380                    dns_name_t *creator, isc_stdtime_t inception,
381                    isc_stdtime_t expire, isc_mem_t *mctx,
382                    dns_tsig_keyring_t *ring, dns_tsigkey_t **key)
383 {
384         dst_key_t *dstkey = NULL;
385         isc_result_t result;
386
387         REQUIRE(length >= 0);
388         if (length > 0)
389                 REQUIRE(secret != NULL);
390
391         if (dns_name_equal(algorithm, DNS_TSIG_HMACMD5_NAME)) {
392                 if (secret != NULL) {
393                         isc_buffer_t b;
394
395                         isc_buffer_init(&b, secret, length);
396                         isc_buffer_add(&b, length);
397                         result = dst_key_frombuffer(name, DST_ALG_HMACMD5,
398                                                     DNS_KEYOWNER_ENTITY,
399                                                     DNS_KEYPROTO_DNSSEC,
400                                                     dns_rdataclass_in,
401                                                     &b, mctx, &dstkey);
402                                 if (result != ISC_R_SUCCESS)
403                                         return (result);
404                 }
405         } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA1_NAME)) {
406                 if (secret != NULL) {
407                         isc_buffer_t b;
408
409                         isc_buffer_init(&b, secret, length);
410                         isc_buffer_add(&b, length);
411                         result = dst_key_frombuffer(name, DST_ALG_HMACSHA1,
412                                                     DNS_KEYOWNER_ENTITY,
413                                                     DNS_KEYPROTO_DNSSEC,
414                                                     dns_rdataclass_in,
415                                                     &b, mctx, &dstkey);
416                                 if (result != ISC_R_SUCCESS)
417                                         return (result);
418                 }
419         } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA224_NAME)) {
420                 if (secret != NULL) {
421                         isc_buffer_t b;
422
423                         isc_buffer_init(&b, secret, length);
424                         isc_buffer_add(&b, length);
425                         result = dst_key_frombuffer(name, DST_ALG_HMACSHA224,
426                                                     DNS_KEYOWNER_ENTITY,
427                                                     DNS_KEYPROTO_DNSSEC,
428                                                     dns_rdataclass_in,
429                                                     &b, mctx, &dstkey);
430                                 if (result != ISC_R_SUCCESS)
431                                         return (result);
432                 }
433         } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA256_NAME)) {
434                 if (secret != NULL) {
435                         isc_buffer_t b;
436
437                         isc_buffer_init(&b, secret, length);
438                         isc_buffer_add(&b, length);
439                         result = dst_key_frombuffer(name, DST_ALG_HMACSHA256,
440                                                     DNS_KEYOWNER_ENTITY,
441                                                     DNS_KEYPROTO_DNSSEC,
442                                                     dns_rdataclass_in,
443                                                     &b, mctx, &dstkey);
444                                 if (result != ISC_R_SUCCESS)
445                                         return (result);
446                 }
447         } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA384_NAME)) {
448                 if (secret != NULL) {
449                         isc_buffer_t b;
450
451                         isc_buffer_init(&b, secret, length);
452                         isc_buffer_add(&b, length);
453                         result = dst_key_frombuffer(name, DST_ALG_HMACSHA384,
454                                                     DNS_KEYOWNER_ENTITY,
455                                                     DNS_KEYPROTO_DNSSEC,
456                                                     dns_rdataclass_in,
457                                                     &b, mctx, &dstkey);
458                                 if (result != ISC_R_SUCCESS)
459                                         return (result);
460                 }
461         } else if (dns_name_equal(algorithm, DNS_TSIG_HMACSHA512_NAME)) {
462                 if (secret != NULL) {
463                         isc_buffer_t b;
464
465                         isc_buffer_init(&b, secret, length);
466                         isc_buffer_add(&b, length);
467                         result = dst_key_frombuffer(name, DST_ALG_HMACSHA512,
468                                                     DNS_KEYOWNER_ENTITY,
469                                                     DNS_KEYPROTO_DNSSEC,
470                                                     dns_rdataclass_in,
471                                                     &b, mctx, &dstkey);
472                                 if (result != ISC_R_SUCCESS)
473                                         return (result);
474                 }
475         } else if (length > 0)
476                 return (DNS_R_BADALG);
477
478         result = dns_tsigkey_createfromkey(name, algorithm, dstkey,
479                                            generated, creator,
480                                            inception, expire, mctx, ring, key);
481         if (result != ISC_R_SUCCESS && dstkey != NULL)
482                 dst_key_free(&dstkey);
483         return (result);
484 }
485
486 void
487 dns_tsigkey_attach(dns_tsigkey_t *source, dns_tsigkey_t **targetp) {
488         REQUIRE(VALID_TSIG_KEY(source));
489         REQUIRE(targetp != NULL && *targetp == NULL);
490
491         isc_refcount_increment(&source->refs, NULL);
492         *targetp = source;
493 }
494
495 static void
496 tsigkey_free(dns_tsigkey_t *key) {
497         REQUIRE(VALID_TSIG_KEY(key));
498
499         key->magic = 0;
500         dns_name_free(&key->name, key->mctx);
501         if (algname_is_allocated(key->algorithm)) {
502                 dns_name_free(key->algorithm, key->mctx);
503                 isc_mem_put(key->mctx, key->algorithm, sizeof(dns_name_t));
504         }
505         if (key->key != NULL)
506                 dst_key_free(&key->key);
507         if (key->creator != NULL) {
508                 dns_name_free(key->creator, key->mctx);
509                 isc_mem_put(key->mctx, key->creator, sizeof(dns_name_t));
510         }
511         isc_refcount_destroy(&key->refs);
512         isc_mem_put(key->mctx, key, sizeof(dns_tsigkey_t));
513 }
514
515 void
516 dns_tsigkey_detach(dns_tsigkey_t **keyp) {
517         dns_tsigkey_t *key;
518         unsigned int refs;
519
520         REQUIRE(keyp != NULL);
521         REQUIRE(VALID_TSIG_KEY(*keyp));
522
523         key = *keyp;
524         isc_refcount_decrement(&key->refs, &refs);
525
526         if (refs == 0)
527                 tsigkey_free(key);
528
529         *keyp = NULL;
530 }
531
532 void
533 dns_tsigkey_setdeleted(dns_tsigkey_t *key) {
534         REQUIRE(VALID_TSIG_KEY(key));
535         REQUIRE(key->ring != NULL);
536
537         RWLOCK(&key->ring->lock, isc_rwlocktype_write);
538         (void)dns_rbt_deletename(key->ring->keys, &key->name, ISC_FALSE);
539         RWUNLOCK(&key->ring->lock, isc_rwlocktype_write);
540 }
541
542 static void
543 buffer_putuint48(isc_buffer_t *b, isc_uint64_t val) {
544         isc_uint16_t valhi;
545         isc_uint32_t vallo;
546
547         valhi = (isc_uint16_t)(val >> 32);
548         vallo = (isc_uint32_t)(val & 0xFFFFFFFF);
549         isc_buffer_putuint16(b, valhi);
550         isc_buffer_putuint32(b, vallo);
551 }
552
553 isc_result_t
554 dns_tsig_sign(dns_message_t *msg) {
555         dns_tsigkey_t *key;
556         dns_rdata_any_tsig_t tsig, querytsig;
557         unsigned char data[128];
558         isc_buffer_t databuf, sigbuf;
559         isc_buffer_t *dynbuf;
560         dns_name_t *owner;
561         dns_rdata_t *rdata = NULL;
562         dns_rdatalist_t *datalist;
563         dns_rdataset_t *dataset;
564         isc_region_t r;
565         isc_stdtime_t now;
566         isc_mem_t *mctx;
567         dst_context_t *ctx = NULL;
568         isc_result_t ret;
569         unsigned char badtimedata[BADTIMELEN];
570         unsigned int sigsize = 0;
571
572         REQUIRE(msg != NULL);
573         REQUIRE(VALID_TSIG_KEY(dns_message_gettsigkey(msg)));
574
575         /*
576          * If this is a response, there should be a query tsig.
577          */
578         if (is_response(msg) && msg->querytsig == NULL)
579                 return (DNS_R_EXPECTEDTSIG);
580
581         dynbuf = NULL;
582
583         mctx = msg->mctx;
584         key = dns_message_gettsigkey(msg);
585
586         tsig.mctx = mctx;
587         tsig.common.rdclass = dns_rdataclass_any;
588         tsig.common.rdtype = dns_rdatatype_tsig;
589         ISC_LINK_INIT(&tsig.common, link);
590         dns_name_init(&tsig.algorithm, NULL);
591         dns_name_clone(key->algorithm, &tsig.algorithm);
592
593         isc_stdtime_get(&now);
594         tsig.timesigned = now + msg->timeadjust;
595         tsig.fudge = DNS_TSIG_FUDGE;
596
597         tsig.originalid = msg->id;
598
599         isc_buffer_init(&databuf, data, sizeof(data));
600
601         if (is_response(msg))
602                 tsig.error = msg->querytsigstatus;
603         else
604                 tsig.error = dns_rcode_noerror;
605
606         if (tsig.error != dns_tsigerror_badtime) {
607                 tsig.otherlen = 0;
608                 tsig.other = NULL;
609         } else {
610                 isc_buffer_t otherbuf;
611
612                 tsig.otherlen = BADTIMELEN;
613                 tsig.other = badtimedata;
614                 isc_buffer_init(&otherbuf, tsig.other, tsig.otherlen);
615                 buffer_putuint48(&otherbuf, tsig.timesigned);
616         }
617
618         if (key->key != NULL && tsig.error != dns_tsigerror_badsig) {
619                 unsigned char header[DNS_MESSAGE_HEADERLEN];
620                 isc_buffer_t headerbuf;
621                 isc_uint16_t digestbits;
622
623                 ret = dst_context_create(key->key, mctx, &ctx);
624                 if (ret != ISC_R_SUCCESS)
625                         return (ret);
626
627                 /*
628                  * If this is a response, digest the query signature.
629                  */
630                 if (is_response(msg)) {
631                         dns_rdata_t querytsigrdata = DNS_RDATA_INIT;
632
633                         ret = dns_rdataset_first(msg->querytsig);
634                         if (ret != ISC_R_SUCCESS)
635                                 goto cleanup_context;
636                         dns_rdataset_current(msg->querytsig, &querytsigrdata);
637                         ret = dns_rdata_tostruct(&querytsigrdata, &querytsig,
638                                                  NULL);
639                         if (ret != ISC_R_SUCCESS)
640                                 goto cleanup_context;
641                         isc_buffer_putuint16(&databuf, querytsig.siglen);
642                         if (isc_buffer_availablelength(&databuf) <
643                             querytsig.siglen)
644                         {
645                                 ret = ISC_R_NOSPACE;
646                                 goto cleanup_context;
647                         }
648                         isc_buffer_putmem(&databuf, querytsig.signature,
649                                           querytsig.siglen);
650                         isc_buffer_usedregion(&databuf, &r);
651                         ret = dst_context_adddata(ctx, &r);
652                         if (ret != ISC_R_SUCCESS)
653                                 goto cleanup_context;
654                 }
655
656                 /*
657                  * Digest the header.
658                  */
659                 isc_buffer_init(&headerbuf, header, sizeof(header));
660                 dns_message_renderheader(msg, &headerbuf);
661                 isc_buffer_usedregion(&headerbuf, &r);
662                 ret = dst_context_adddata(ctx, &r);
663                 if (ret != ISC_R_SUCCESS)
664                         goto cleanup_context;
665
666                 /*
667                  * Digest the remainder of the message.
668                  */
669                 isc_buffer_usedregion(msg->buffer, &r);
670                 isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
671                 ret = dst_context_adddata(ctx, &r);
672                 if (ret != ISC_R_SUCCESS)
673                         goto cleanup_context;
674
675                 if (msg->tcp_continuation == 0) {
676                         /*
677                          * Digest the name, class, ttl, alg.
678                          */
679                         dns_name_toregion(&key->name, &r);
680                         ret = dst_context_adddata(ctx, &r);
681                         if (ret != ISC_R_SUCCESS)
682                                 goto cleanup_context;
683
684                         isc_buffer_clear(&databuf);
685                         isc_buffer_putuint16(&databuf, dns_rdataclass_any);
686                         isc_buffer_putuint32(&databuf, 0); /* ttl */
687                         isc_buffer_usedregion(&databuf, &r);
688                         ret = dst_context_adddata(ctx, &r);
689                         if (ret != ISC_R_SUCCESS)
690                                 goto cleanup_context;
691
692                         dns_name_toregion(&tsig.algorithm, &r);
693                         ret = dst_context_adddata(ctx, &r);
694                         if (ret != ISC_R_SUCCESS)
695                                 goto cleanup_context;
696
697                 }
698                 /* Digest the timesigned and fudge */
699                 isc_buffer_clear(&databuf);
700                 if (tsig.error == dns_tsigerror_badtime)
701                         tsig.timesigned = querytsig.timesigned;
702                 buffer_putuint48(&databuf, tsig.timesigned);
703                 isc_buffer_putuint16(&databuf, tsig.fudge);
704                 isc_buffer_usedregion(&databuf, &r);
705                 ret = dst_context_adddata(ctx, &r);
706                 if (ret != ISC_R_SUCCESS)
707                         goto cleanup_context;
708
709                 if (msg->tcp_continuation == 0) {
710                         /*
711                          * Digest the error and other data length.
712                          */
713                         isc_buffer_clear(&databuf);
714                         isc_buffer_putuint16(&databuf, tsig.error);
715                         isc_buffer_putuint16(&databuf, tsig.otherlen);
716
717                         isc_buffer_usedregion(&databuf, &r);
718                         ret = dst_context_adddata(ctx, &r);
719                         if (ret != ISC_R_SUCCESS)
720                                 goto cleanup_context;
721
722                         /*
723                          * Digest the error and other data.
724                          */
725                         if (tsig.otherlen > 0) {
726                                 r.length = tsig.otherlen;
727                                 r.base = tsig.other;
728                                 ret = dst_context_adddata(ctx, &r);
729                                 if (ret != ISC_R_SUCCESS)
730                                         goto cleanup_context;
731                         }
732                 }
733
734                 ret = dst_key_sigsize(key->key, &sigsize);
735                 if (ret != ISC_R_SUCCESS)
736                         goto cleanup_context;
737                 tsig.signature = (unsigned char *) isc_mem_get(mctx, sigsize);
738                 if (tsig.signature == NULL) {
739                         ret = ISC_R_NOMEMORY;
740                         goto cleanup_context;
741                 }
742
743                 isc_buffer_init(&sigbuf, tsig.signature, sigsize);
744                 ret = dst_context_sign(ctx, &sigbuf);
745                 if (ret != ISC_R_SUCCESS)
746                         goto cleanup_signature;
747                 dst_context_destroy(&ctx);
748                 digestbits = dst_key_getbits(key->key);
749                 if (digestbits != 0) {
750                         unsigned int bytes = (digestbits + 1) / 8;
751                         if (is_response(msg) && bytes < querytsig.siglen)
752                                 bytes = querytsig.siglen;
753                         if (bytes > isc_buffer_usedlength(&sigbuf))
754                                 bytes = isc_buffer_usedlength(&sigbuf);
755                         tsig.siglen = bytes;
756                 } else
757                         tsig.siglen = isc_buffer_usedlength(&sigbuf);
758         } else {
759                 tsig.siglen = 0;
760                 tsig.signature = NULL;
761         }
762
763         ret = dns_message_gettemprdata(msg, &rdata);
764         if (ret != ISC_R_SUCCESS)
765                 goto cleanup_signature;
766         ret = isc_buffer_allocate(msg->mctx, &dynbuf, 512);
767         if (ret != ISC_R_SUCCESS)
768                 goto cleanup_rdata;
769         ret = dns_rdata_fromstruct(rdata, dns_rdataclass_any,
770                                    dns_rdatatype_tsig, &tsig, dynbuf);
771         if (ret != ISC_R_SUCCESS)
772                 goto cleanup_dynbuf;
773
774         dns_message_takebuffer(msg, &dynbuf);
775
776         if (tsig.signature != NULL) {
777                 isc_mem_put(mctx, tsig.signature, sigsize);
778                 tsig.signature = NULL;
779         }
780
781         owner = NULL;
782         ret = dns_message_gettempname(msg, &owner);
783         if (ret != ISC_R_SUCCESS)
784                 goto cleanup_rdata;
785         dns_name_init(owner, NULL);
786         ret = dns_name_dup(&key->name, msg->mctx, owner);
787         if (ret != ISC_R_SUCCESS)
788                 goto cleanup_owner;
789
790         datalist = NULL;
791         ret = dns_message_gettemprdatalist(msg, &datalist);
792         if (ret != ISC_R_SUCCESS)
793                 goto cleanup_owner;
794         dataset = NULL;
795         ret = dns_message_gettemprdataset(msg, &dataset);
796         if (ret != ISC_R_SUCCESS)
797                 goto cleanup_rdatalist;
798         datalist->rdclass = dns_rdataclass_any;
799         datalist->type = dns_rdatatype_tsig;
800         datalist->covers = 0;
801         datalist->ttl = 0;
802         ISC_LIST_INIT(datalist->rdata);
803         ISC_LIST_APPEND(datalist->rdata, rdata, link);
804         dns_rdataset_init(dataset);
805         RUNTIME_CHECK(dns_rdatalist_tordataset(datalist, dataset)
806                       == ISC_R_SUCCESS);
807         msg->tsig = dataset;
808         msg->tsigname = owner;
809
810         return (ISC_R_SUCCESS);
811
812  cleanup_rdatalist:
813         dns_message_puttemprdatalist(msg, &datalist);
814  cleanup_owner:
815         dns_message_puttempname(msg, &owner);
816         goto cleanup_rdata;
817  cleanup_dynbuf:
818         isc_buffer_free(&dynbuf);
819  cleanup_rdata:
820         dns_message_puttemprdata(msg, &rdata);
821  cleanup_signature:
822         if (tsig.signature != NULL)
823                 isc_mem_put(mctx, tsig.signature, sigsize);
824  cleanup_context:
825         if (ctx != NULL)
826                 dst_context_destroy(&ctx);
827         return (ret);
828 }
829
830 isc_result_t
831 dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
832                 dns_tsig_keyring_t *ring1, dns_tsig_keyring_t *ring2)
833 {
834         dns_rdata_any_tsig_t tsig, querytsig;
835         isc_region_t r, source_r, header_r, sig_r;
836         isc_buffer_t databuf;
837         unsigned char data[32];
838         dns_name_t *keyname;
839         dns_rdata_t rdata = DNS_RDATA_INIT;
840         isc_stdtime_t now;
841         isc_result_t ret;
842         dns_tsigkey_t *tsigkey;
843         dst_key_t *key = NULL;
844         unsigned char header[DNS_MESSAGE_HEADERLEN];
845         dst_context_t *ctx = NULL;
846         isc_mem_t *mctx;
847         isc_uint16_t addcount, id;
848         unsigned int siglen;
849         unsigned int alg;
850
851         REQUIRE(source != NULL);
852         REQUIRE(DNS_MESSAGE_VALID(msg));
853         tsigkey = dns_message_gettsigkey(msg);
854         REQUIRE(tsigkey == NULL || VALID_TSIG_KEY(tsigkey));
855
856         msg->verify_attempted = 1;
857
858         if (msg->tcp_continuation) {
859                 if (tsigkey == NULL || msg->querytsig == NULL)
860                         return (DNS_R_UNEXPECTEDTSIG);
861                 return (tsig_verify_tcp(source, msg));
862         }
863
864         /*
865          * There should be a TSIG record...
866          */
867         if (msg->tsig == NULL)
868                 return (DNS_R_EXPECTEDTSIG);
869
870         /*
871          * If this is a response and there's no key or query TSIG, there
872          * shouldn't be one on the response.
873          */
874         if (is_response(msg) &&
875             (tsigkey == NULL || msg->querytsig == NULL))
876                 return (DNS_R_UNEXPECTEDTSIG);
877
878         mctx = msg->mctx;
879
880         /*
881          * If we're here, we know the message is well formed and contains a
882          * TSIG record.
883          */
884
885         keyname = msg->tsigname;
886         ret = dns_rdataset_first(msg->tsig);
887         if (ret != ISC_R_SUCCESS)
888                 return (ret);
889         dns_rdataset_current(msg->tsig, &rdata);
890         ret = dns_rdata_tostruct(&rdata, &tsig, NULL);
891         if (ret != ISC_R_SUCCESS)
892                 return (ret);
893         dns_rdata_reset(&rdata);
894         if (is_response(msg)) {
895                 ret = dns_rdataset_first(msg->querytsig);
896                 if (ret != ISC_R_SUCCESS)
897                         return (ret);
898                 dns_rdataset_current(msg->querytsig, &rdata);
899                 ret = dns_rdata_tostruct(&rdata, &querytsig, NULL);
900                 if (ret != ISC_R_SUCCESS)
901                         return (ret);
902         }
903
904         /*
905          * Do the key name and algorithm match that of the query?
906          */
907         if (is_response(msg) &&
908             (!dns_name_equal(keyname, &tsigkey->name) ||
909              !dns_name_equal(&tsig.algorithm, &querytsig.algorithm)))
910         {
911                 msg->tsigstatus = dns_tsigerror_badkey;
912                 tsig_log(msg->tsigkey, 2,
913                          "key name and algorithm do not match");
914                 return (DNS_R_TSIGVERIFYFAILURE);
915         }
916
917         /*
918          * Get the current time.
919          */
920         isc_stdtime_get(&now);
921
922         /*
923          * Find dns_tsigkey_t based on keyname.
924          */
925         if (tsigkey == NULL) {
926                 ret = ISC_R_NOTFOUND;
927                 if (ring1 != NULL)
928                         ret = dns_tsigkey_find(&tsigkey, keyname,
929                                                &tsig.algorithm, ring1);
930                 if (ret == ISC_R_NOTFOUND && ring2 != NULL)
931                         ret = dns_tsigkey_find(&tsigkey, keyname,
932                                                &tsig.algorithm, ring2);
933                 if (ret != ISC_R_SUCCESS) {
934                         msg->tsigstatus = dns_tsigerror_badkey;
935                         ret = dns_tsigkey_create(keyname, &tsig.algorithm,
936                                                  NULL, 0, ISC_FALSE, NULL,
937                                                  now, now,
938                                                  mctx, NULL, &msg->tsigkey);
939                         if (ret != ISC_R_SUCCESS)
940                                 return (ret);
941                         tsig_log(msg->tsigkey, 2, "unknown key");
942                         return (DNS_R_TSIGVERIFYFAILURE);
943                 }
944                 msg->tsigkey = tsigkey;
945         }
946
947         key = tsigkey->key;
948
949         /*
950          * Is the time ok?
951          */
952         if (now + msg->timeadjust > tsig.timesigned + tsig.fudge) {
953                 msg->tsigstatus = dns_tsigerror_badtime;
954                 tsig_log(msg->tsigkey, 2, "signature has expired");
955                 return (DNS_R_CLOCKSKEW);
956         } else if (now + msg->timeadjust < tsig.timesigned - tsig.fudge) {
957                 msg->tsigstatus = dns_tsigerror_badtime;
958                 tsig_log(msg->tsigkey, 2, "signature is in the future");
959                 return (DNS_R_CLOCKSKEW);
960         }
961
962         /*
963          * Check digest length.
964          */
965         alg = dst_key_alg(key);
966         ret = dst_key_sigsize(key, &siglen);
967         if (ret != ISC_R_SUCCESS)
968                 return (ret);
969         if (alg == DST_ALG_HMACMD5 || alg == DST_ALG_HMACSHA1 ||
970             alg == DST_ALG_HMACSHA224 || alg == DST_ALG_HMACSHA256 ||
971             alg == DST_ALG_HMACSHA384 || alg == DST_ALG_HMACSHA512) {
972                 isc_uint16_t digestbits = dst_key_getbits(key);
973                 if (tsig.siglen > siglen) {
974                         tsig_log(msg->tsigkey, 2, "signature length to big");
975                         return (DNS_R_FORMERR);
976                 }
977                 if (tsig.siglen > 0 &&
978                     (tsig.siglen < 10 || tsig.siglen < ((siglen + 1) / 2))) {
979                         tsig_log(msg->tsigkey, 2,
980                                  "signature length below minimum");
981                         return (DNS_R_FORMERR);
982                 }
983                 if (tsig.siglen > 0 && digestbits != 0 &&
984                     tsig.siglen < ((digestbits + 1) / 8)) { 
985                         msg->tsigstatus = dns_tsigerror_badtrunc;
986                         tsig_log(msg->tsigkey, 2,
987                                  "truncated signature length too small");
988                         return (DNS_R_TSIGVERIFYFAILURE);
989                 }
990                 if (tsig.siglen > 0 && digestbits == 0 &&
991                     tsig.siglen < siglen) {
992                         msg->tsigstatus = dns_tsigerror_badtrunc;
993                         tsig_log(msg->tsigkey, 2, "signature length too small");
994                         return (DNS_R_TSIGVERIFYFAILURE);
995                 }
996         }
997
998         if (tsig.siglen > 0) {
999                 sig_r.base = tsig.signature;
1000                 sig_r.length = tsig.siglen;
1001
1002                 ret = dst_context_create(key, mctx, &ctx);
1003                 if (ret != ISC_R_SUCCESS)
1004                         return (ret);
1005
1006                 if (is_response(msg)) {
1007                         isc_buffer_init(&databuf, data, sizeof(data));
1008                         isc_buffer_putuint16(&databuf, querytsig.siglen);
1009                         isc_buffer_usedregion(&databuf, &r);
1010                         ret = dst_context_adddata(ctx, &r);
1011                         if (ret != ISC_R_SUCCESS)
1012                                 goto cleanup_context;
1013                         if (querytsig.siglen > 0) {
1014                                 r.length = querytsig.siglen;
1015                                 r.base = querytsig.signature;
1016                                 ret = dst_context_adddata(ctx, &r);
1017                                 if (ret != ISC_R_SUCCESS)
1018                                         goto cleanup_context;
1019                         }
1020                 }
1021
1022                 /*
1023                  * Extract the header.
1024                  */
1025                 isc_buffer_usedregion(source, &r);
1026                 memcpy(header, r.base, DNS_MESSAGE_HEADERLEN);
1027                 isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
1028
1029                 /*
1030                  * Decrement the additional field counter.
1031                  */
1032                 memcpy(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
1033                 addcount = htons((isc_uint16_t)(ntohs(addcount) - 1));
1034                 memcpy(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);
1035
1036                 /*
1037                  * Put in the original id.
1038                  */
1039                 id = htons(tsig.originalid);
1040                 memcpy(&header[0], &id, 2);
1041
1042                 /*
1043                  * Digest the modified header.
1044                  */
1045                 header_r.base = (unsigned char *) header;
1046                 header_r.length = DNS_MESSAGE_HEADERLEN;
1047                 ret = dst_context_adddata(ctx, &header_r);
1048                 if (ret != ISC_R_SUCCESS)
1049                         goto cleanup_context;
1050
1051                 /*
1052                  * Digest all non-TSIG records.
1053                  */
1054                 isc_buffer_usedregion(source, &source_r);
1055                 r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
1056                 r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN;
1057                 ret = dst_context_adddata(ctx, &r);
1058                 if (ret != ISC_R_SUCCESS)
1059                         goto cleanup_context;
1060
1061                 /*
1062                  * Digest the key name.
1063                  */
1064                 dns_name_toregion(&tsigkey->name, &r);
1065                 ret = dst_context_adddata(ctx, &r);
1066                 if (ret != ISC_R_SUCCESS)
1067                         goto cleanup_context;
1068
1069                 isc_buffer_init(&databuf, data, sizeof(data));
1070                 isc_buffer_putuint16(&databuf, tsig.common.rdclass);
1071                 isc_buffer_putuint32(&databuf, msg->tsig->ttl);
1072                 isc_buffer_usedregion(&databuf, &r);
1073                 ret = dst_context_adddata(ctx, &r);
1074                 if (ret != ISC_R_SUCCESS)
1075                         goto cleanup_context;
1076
1077                 /*
1078                  * Digest the key algorithm.
1079                  */
1080                 dns_name_toregion(tsigkey->algorithm, &r);
1081                 ret = dst_context_adddata(ctx, &r);
1082                 if (ret != ISC_R_SUCCESS)
1083                         goto cleanup_context;
1084
1085                 isc_buffer_clear(&databuf);
1086                 buffer_putuint48(&databuf, tsig.timesigned);
1087                 isc_buffer_putuint16(&databuf, tsig.fudge);
1088                 isc_buffer_putuint16(&databuf, tsig.error);
1089                 isc_buffer_putuint16(&databuf, tsig.otherlen);
1090                 isc_buffer_usedregion(&databuf, &r);
1091                 ret = dst_context_adddata(ctx, &r);
1092                 if (ret != ISC_R_SUCCESS)
1093                         goto cleanup_context;
1094
1095                 if (tsig.otherlen > 0) {
1096                         r.base = tsig.other;
1097                         r.length = tsig.otherlen;
1098                         ret = dst_context_adddata(ctx, &r);
1099                         if (ret != ISC_R_SUCCESS)
1100                                 goto cleanup_context;
1101                 }
1102
1103                 ret = dst_context_verify(ctx, &sig_r);
1104                 if (ret == DST_R_VERIFYFAILURE) {
1105                         msg->tsigstatus = dns_tsigerror_badsig;
1106                         ret = DNS_R_TSIGVERIFYFAILURE;
1107                         tsig_log(msg->tsigkey, 2,
1108                                  "signature failed to verify");
1109                         goto cleanup_context;
1110                 } else if (ret != ISC_R_SUCCESS)
1111                         goto cleanup_context;
1112
1113                 dst_context_destroy(&ctx);
1114         } else if (tsig.error != dns_tsigerror_badsig &&
1115                    tsig.error != dns_tsigerror_badkey)
1116         {
1117                 msg->tsigstatus = dns_tsigerror_badsig;
1118                 tsig_log(msg->tsigkey, 2, "signature was empty");
1119                 return (DNS_R_TSIGVERIFYFAILURE);
1120         }
1121
1122         msg->tsigstatus = dns_rcode_noerror;
1123
1124         if (tsig.error != dns_rcode_noerror) {
1125                 if (tsig.error == dns_tsigerror_badtime)
1126                         return (DNS_R_CLOCKSKEW);
1127                 else
1128                         return (DNS_R_TSIGERRORSET);
1129         }
1130
1131         msg->verified_sig = 1;
1132
1133         return (ISC_R_SUCCESS);
1134
1135 cleanup_context:
1136         if (ctx != NULL)
1137                 dst_context_destroy(&ctx);
1138
1139         return (ret);
1140 }
1141
1142 static isc_result_t
1143 tsig_verify_tcp(isc_buffer_t *source, dns_message_t *msg) {
1144         dns_rdata_any_tsig_t tsig, querytsig;
1145         isc_region_t r, source_r, header_r, sig_r;
1146         isc_buffer_t databuf;
1147         unsigned char data[32];
1148         dns_name_t *keyname;
1149         dns_rdata_t rdata = DNS_RDATA_INIT;
1150         isc_stdtime_t now;
1151         isc_result_t ret;
1152         dns_tsigkey_t *tsigkey;
1153         dst_key_t *key = NULL;
1154         unsigned char header[DNS_MESSAGE_HEADERLEN];
1155         isc_uint16_t addcount, id;
1156         isc_boolean_t has_tsig = ISC_FALSE;
1157         isc_mem_t *mctx;
1158
1159         REQUIRE(source != NULL);
1160         REQUIRE(msg != NULL);
1161         REQUIRE(dns_message_gettsigkey(msg) != NULL);
1162         REQUIRE(msg->tcp_continuation == 1);
1163         REQUIRE(msg->querytsig != NULL);
1164
1165         if (!is_response(msg))
1166                 return (DNS_R_EXPECTEDRESPONSE);
1167
1168         mctx = msg->mctx;
1169
1170         tsigkey = dns_message_gettsigkey(msg);
1171
1172         /*
1173          * Extract and parse the previous TSIG
1174          */
1175         ret = dns_rdataset_first(msg->querytsig);
1176         if (ret != ISC_R_SUCCESS)
1177                 return (ret);
1178         dns_rdataset_current(msg->querytsig, &rdata);
1179         ret = dns_rdata_tostruct(&rdata, &querytsig, NULL);
1180         if (ret != ISC_R_SUCCESS)
1181                 return (ret);
1182         dns_rdata_reset(&rdata);
1183
1184         /*
1185          * If there is a TSIG in this message, do some checks.
1186          */
1187         if (msg->tsig != NULL) {
1188                 has_tsig = ISC_TRUE;
1189
1190                 keyname = msg->tsigname;
1191                 ret = dns_rdataset_first(msg->tsig);
1192                 if (ret != ISC_R_SUCCESS)
1193                         goto cleanup_querystruct;
1194                 dns_rdataset_current(msg->tsig, &rdata);
1195                 ret = dns_rdata_tostruct(&rdata, &tsig, NULL);
1196                 if (ret != ISC_R_SUCCESS)
1197                         goto cleanup_querystruct;
1198
1199                 /*
1200                  * Do the key name and algorithm match that of the query?
1201                  */
1202                 if (!dns_name_equal(keyname, &tsigkey->name) ||
1203                     !dns_name_equal(&tsig.algorithm, &querytsig.algorithm))
1204                 {
1205                         msg->tsigstatus = dns_tsigerror_badkey;
1206                         ret = DNS_R_TSIGVERIFYFAILURE;
1207                         tsig_log(msg->tsigkey, 2,
1208                                  "key name and algorithm do not match");
1209                         goto cleanup_querystruct;
1210                 }
1211
1212                 /*
1213                  * Is the time ok?
1214                  */
1215                 isc_stdtime_get(&now);
1216
1217                 if (now + msg->timeadjust > tsig.timesigned + tsig.fudge) {
1218                         msg->tsigstatus = dns_tsigerror_badtime;
1219                         tsig_log(msg->tsigkey, 2, "signature has expired");
1220                         ret = DNS_R_CLOCKSKEW;
1221                         goto cleanup_querystruct;
1222                 } else if (now + msg->timeadjust <
1223                            tsig.timesigned - tsig.fudge)
1224                 {
1225                         msg->tsigstatus = dns_tsigerror_badtime;
1226                         tsig_log(msg->tsigkey, 2,
1227                                  "signature is in the future");
1228                         ret = DNS_R_CLOCKSKEW;
1229                         goto cleanup_querystruct;
1230                 }
1231         }
1232
1233         key = tsigkey->key;
1234
1235         if (msg->tsigctx == NULL) {
1236                 ret = dst_context_create(key, mctx, &msg->tsigctx);
1237                 if (ret != ISC_R_SUCCESS)
1238                         goto cleanup_querystruct;
1239
1240                 /*
1241                  * Digest the length of the query signature
1242                  */
1243                 isc_buffer_init(&databuf, data, sizeof(data));
1244                 isc_buffer_putuint16(&databuf, querytsig.siglen);
1245                 isc_buffer_usedregion(&databuf, &r);
1246                 ret = dst_context_adddata(msg->tsigctx, &r);
1247                 if (ret != ISC_R_SUCCESS)
1248                         goto cleanup_context;
1249
1250                 /*
1251                  * Digest the data of the query signature
1252                  */
1253                 if (querytsig.siglen > 0) {
1254                         r.length = querytsig.siglen;
1255                         r.base = querytsig.signature;
1256                         ret = dst_context_adddata(msg->tsigctx, &r);
1257                         if (ret != ISC_R_SUCCESS)
1258                                 goto cleanup_context;
1259                 }
1260         }
1261
1262         /*
1263          * Extract the header.
1264          */
1265         isc_buffer_usedregion(source, &r);
1266         memcpy(header, r.base, DNS_MESSAGE_HEADERLEN);
1267         isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
1268
1269         /*
1270          * Decrement the additional field counter if necessary.
1271          */
1272         if (has_tsig) {
1273                 memcpy(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
1274                 addcount = htons((isc_uint16_t)(ntohs(addcount) - 1));
1275                 memcpy(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);
1276         }
1277
1278         /*
1279          * Put in the original id.
1280          */
1281         /* XXX Can TCP transfers be forwarded?  How would that work? */
1282         if (has_tsig) {
1283                 id = htons(tsig.originalid);
1284                 memcpy(&header[0], &id, 2);
1285         }
1286
1287         /*
1288          * Digest the modified header.
1289          */
1290         header_r.base = (unsigned char *) header;
1291         header_r.length = DNS_MESSAGE_HEADERLEN;
1292         ret = dst_context_adddata(msg->tsigctx, &header_r);
1293         if (ret != ISC_R_SUCCESS)
1294                 goto cleanup_context;
1295
1296         /*
1297          * Digest all non-TSIG records.
1298          */
1299         isc_buffer_usedregion(source, &source_r);
1300         r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
1301         if (has_tsig)
1302                 r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN;
1303         else
1304                 r.length = source_r.length - DNS_MESSAGE_HEADERLEN;
1305         ret = dst_context_adddata(msg->tsigctx, &r);
1306         if (ret != ISC_R_SUCCESS)
1307                 goto cleanup_context;
1308
1309         /*
1310          * Digest the time signed and fudge.
1311          */
1312         if (has_tsig) {
1313                 isc_buffer_init(&databuf, data, sizeof(data));
1314                 buffer_putuint48(&databuf, tsig.timesigned);
1315                 isc_buffer_putuint16(&databuf, tsig.fudge);
1316                 isc_buffer_usedregion(&databuf, &r);
1317                 ret = dst_context_adddata(msg->tsigctx, &r);
1318                 if (ret != ISC_R_SUCCESS)
1319                         goto cleanup_context;
1320
1321                 sig_r.base = tsig.signature;
1322                 sig_r.length = tsig.siglen;
1323                 if (tsig.siglen == 0) {
1324                         if (tsig.error != dns_rcode_noerror) {
1325                                 if (tsig.error == dns_tsigerror_badtime)
1326                                         ret = DNS_R_CLOCKSKEW;
1327                                 else
1328                                         ret = DNS_R_TSIGERRORSET;
1329                         } else {
1330                                 tsig_log(msg->tsigkey, 2,
1331                                          "signature is empty");
1332                                 ret = DNS_R_TSIGVERIFYFAILURE;
1333                         }
1334                         goto cleanup_context;
1335                 }
1336
1337                 ret = dst_context_verify(msg->tsigctx, &sig_r);
1338                 if (ret == DST_R_VERIFYFAILURE) {
1339                         msg->tsigstatus = dns_tsigerror_badsig;
1340                         tsig_log(msg->tsigkey, 2,
1341                                  "signature failed to verify");
1342                         ret = DNS_R_TSIGVERIFYFAILURE;
1343                         goto cleanup_context;
1344                 }
1345                 else if (ret != ISC_R_SUCCESS)
1346                         goto cleanup_context;
1347
1348                 dst_context_destroy(&msg->tsigctx);
1349         }
1350
1351         msg->tsigstatus = dns_rcode_noerror;
1352         return (ISC_R_SUCCESS);
1353
1354  cleanup_context:
1355         dst_context_destroy(&msg->tsigctx);
1356
1357  cleanup_querystruct:
1358         dns_rdata_freestruct(&querytsig);
1359
1360         return (ret);
1361
1362 }
1363
1364 isc_result_t
1365 dns_tsigkey_find(dns_tsigkey_t **tsigkey, dns_name_t *name,
1366                  dns_name_t *algorithm, dns_tsig_keyring_t *ring)
1367 {
1368         dns_tsigkey_t *key;
1369         isc_stdtime_t now;
1370         isc_result_t result;
1371
1372         REQUIRE(tsigkey != NULL);
1373         REQUIRE(*tsigkey == NULL);
1374         REQUIRE(name != NULL);
1375         REQUIRE(ring != NULL);
1376
1377         isc_stdtime_get(&now);
1378         RWLOCK(&ring->lock, isc_rwlocktype_read);
1379         key = NULL;
1380         result = dns_rbt_findname(ring->keys, name, 0, NULL, (void *)&key);
1381         if (result == DNS_R_PARTIALMATCH || result == ISC_R_NOTFOUND) {
1382                 RWUNLOCK(&ring->lock, isc_rwlocktype_read);
1383                 return (ISC_R_NOTFOUND);
1384         }
1385         if (algorithm != NULL && !dns_name_equal(key->algorithm, algorithm)) {
1386                 RWUNLOCK(&ring->lock, isc_rwlocktype_read);
1387                 return (ISC_R_NOTFOUND);
1388         }
1389         if (key->inception != key->expire && key->expire < now) {
1390                 /*
1391                  * The key has expired.
1392                  */
1393                 RWUNLOCK(&ring->lock, isc_rwlocktype_read);
1394                 RWLOCK(&ring->lock, isc_rwlocktype_write);
1395                 (void) dns_rbt_deletename(ring->keys, name, ISC_FALSE);
1396                 RWUNLOCK(&ring->lock, isc_rwlocktype_write);
1397                 return (ISC_R_NOTFOUND);
1398         }
1399
1400         isc_refcount_increment(&key->refs, NULL);
1401         RWUNLOCK(&ring->lock, isc_rwlocktype_read);
1402         *tsigkey = key;
1403         return (ISC_R_SUCCESS);
1404 }
1405
1406 static void
1407 free_tsignode(void *node, void *_unused) {
1408         dns_tsigkey_t *key;
1409
1410         UNUSED(_unused);
1411
1412         REQUIRE(node != NULL);
1413
1414         key = node;
1415         dns_tsigkey_detach(&key);
1416 }
1417
1418 isc_result_t
1419 dns_tsigkeyring_create(isc_mem_t *mctx, dns_tsig_keyring_t **ringp) {
1420         isc_result_t result;
1421         dns_tsig_keyring_t *ring;
1422
1423         REQUIRE(mctx != NULL);
1424         REQUIRE(ringp != NULL);
1425         REQUIRE(*ringp == NULL);
1426
1427         ring = isc_mem_get(mctx, sizeof(dns_tsig_keyring_t));
1428         if (ring == NULL)
1429                 return (ISC_R_NOMEMORY);
1430
1431         result = isc_rwlock_init(&ring->lock, 0, 0);
1432         if (result != ISC_R_SUCCESS)
1433                 return (result);
1434
1435         ring->keys = NULL;
1436         result = dns_rbt_create(mctx, free_tsignode, NULL, &ring->keys);
1437         if (result != ISC_R_SUCCESS) {
1438                 isc_rwlock_destroy(&ring->lock);
1439                 isc_mem_put(mctx, ring, sizeof(dns_tsig_keyring_t));
1440                 return (result);
1441         }
1442
1443         ring->mctx = mctx;
1444
1445         *ringp = ring;
1446         return (ISC_R_SUCCESS);
1447 }
1448
1449 void
1450 dns_tsigkeyring_destroy(dns_tsig_keyring_t **ringp) {
1451         dns_tsig_keyring_t *ring;
1452
1453         REQUIRE(ringp != NULL);
1454         REQUIRE(*ringp != NULL);
1455
1456         ring = *ringp;
1457         *ringp = NULL;
1458
1459         dns_rbt_destroy(&ring->keys);
1460         isc_rwlock_destroy(&ring->lock);
1461         isc_mem_put(ring->mctx, ring, sizeof(dns_tsig_keyring_t));
1462 }