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