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