2 * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2002 Internet Software Consortium.
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.
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.
19 * $Id: tsig.c,v 1.112.2.3.8.10 2006/05/02 04:21:42 marka Exp $
25 #include <isc/buffer.h>
27 #include <isc/print.h>
28 #include <isc/refcount.h>
29 #include <isc/string.h> /* Required for HP/UX (and others?) */
32 #include <dns/keyvalues.h>
34 #include <dns/message.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>
43 #include <dst/result.h>
45 #define TSIG_MAGIC ISC_MAGIC('T', 'S', 'I', 'G')
46 #define VALID_TSIG_KEY(x) ISC_MAGIC_VALID(x, TSIG_MAGIC)
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)
56 static unsigned char hmacmd5_ndata
[] = "\010hmac-md5\007sig-alg\003reg\003int";
57 static unsigned char hmacmd5_offsets
[] = { 0, 9, 17, 21, 25 };
59 static dns_name_t hmacmd5
= {
62 DNS_NAMEATTR_READONLY
| DNS_NAMEATTR_ABSOLUTE
,
63 hmacmd5_offsets
, NULL
,
64 {(void *)-1, (void *)-1},
68 dns_name_t
*dns_tsig_hmacmd5_name
= &hmacmd5
;
70 static unsigned char gsstsig_ndata
[] = "\010gss-tsig";
71 static unsigned char gsstsig_offsets
[] = { 0, 9 };
73 static dns_name_t gsstsig
= {
76 DNS_NAMEATTR_READONLY
| DNS_NAMEATTR_ABSOLUTE
,
77 gsstsig_offsets
, NULL
,
78 {(void *)-1, (void *)-1},
82 LIBDNS_EXTERNAL_DATA dns_name_t
*dns_tsig_gssapi_name
= &gsstsig
;
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 };
88 static dns_name_t gsstsigms
= {
90 gsstsigms_ndata
, 19, 4,
91 DNS_NAMEATTR_READONLY
| DNS_NAMEATTR_ABSOLUTE
,
92 gsstsigms_offsets
, NULL
,
93 {(void *)-1, (void *)-1},
97 LIBDNS_EXTERNAL_DATA dns_name_t
*dns_tsig_gssapims_name
= &gsstsigms
;
100 tsig_verify_tcp(isc_buffer_t
*source
, dns_message_t
*msg
);
103 tsig_log(dns_tsigkey_t
*key
, int level
, const char *fmt
, ...)
104 ISC_FORMAT_PRINTF(3, 4);
107 tsig_log(dns_tsigkey_t
*key
, int level
, const char *fmt
, ...) {
110 char namestr
[DNS_NAME_FORMATSIZE
];
112 if (isc_log_wouldlog(dns_lctx
, level
) == ISC_FALSE
)
115 dns_name_format(&key
->name
, namestr
, sizeof(namestr
));
117 strcpy(namestr
, "<null>");
119 vsnprintf(message
, sizeof(message
), fmt
, ap
);
121 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DNSSEC
, DNS_LOGMODULE_TSIG
,
122 level
, "tsig key '%s': %s", namestr
, message
);
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
)
134 unsigned int refs
= 0;
136 REQUIRE(key
== NULL
|| *key
== NULL
);
137 REQUIRE(name
!= NULL
);
138 REQUIRE(algorithm
!= NULL
);
139 REQUIRE(mctx
!= NULL
);
141 tkey
= (dns_tsigkey_t
*) isc_mem_get(mctx
, sizeof(dns_tsigkey_t
));
143 return (ISC_R_NOMEMORY
);
145 dns_name_init(&tkey
->name
, NULL
);
146 ret
= dns_name_dup(name
, mctx
, &tkey
->name
);
147 if (ret
!= ISC_R_SUCCESS
)
149 (void)dns_name_downcase(&tkey
->name
, &tkey
->name
, NULL
);
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
) {
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
) {
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
) {
170 if (dstkey
!= NULL
) {
174 tkey
->algorithm
= isc_mem_get(mctx
, sizeof(dns_name_t
));
175 if (tkey
->algorithm
== NULL
) {
176 ret
= ISC_R_NOMEMORY
;
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 (void)dns_name_downcase(tkey
->algorithm
, tkey
->algorithm
,
187 if (creator
!= NULL
) {
188 tkey
->creator
= isc_mem_get(mctx
, sizeof(dns_name_t
));
189 if (tkey
->creator
== NULL
) {
190 ret
= ISC_R_NOMEMORY
;
191 goto cleanup_algorithm
;
193 dns_name_init(tkey
->creator
, NULL
);
194 ret
= dns_name_dup(creator
, mctx
, tkey
->creator
);
195 if (ret
!= ISC_R_SUCCESS
) {
196 isc_mem_put(mctx
, tkey
->creator
, sizeof(dns_name_t
));
197 goto cleanup_algorithm
;
200 tkey
->creator
= NULL
;
206 RWLOCK(&ring
->lock
, isc_rwlocktype_write
);
207 ret
= dns_rbt_addname(ring
->keys
, name
, tkey
);
208 if (ret
!= ISC_R_SUCCESS
) {
209 RWUNLOCK(&ring
->lock
, isc_rwlocktype_write
);
210 goto cleanup_algorithm
;
213 RWUNLOCK(&ring
->lock
, isc_rwlocktype_write
);
218 isc_refcount_init(&tkey
->refs
, refs
);
219 tkey
->generated
= generated
;
220 tkey
->inception
= inception
;
221 tkey
->expire
= expire
;
224 tkey
->magic
= TSIG_MAGIC
;
226 if (dstkey
!= NULL
&& dst_key_size(dstkey
) < 64) {
227 char namestr
[DNS_NAME_FORMATSIZE
];
228 dns_name_format(name
, namestr
, sizeof(namestr
));
229 isc_log_write(dns_lctx
, DNS_LOGCATEGORY_DNSSEC
,
230 DNS_LOGMODULE_TSIG
, ISC_LOG_INFO
,
231 "the key '%s' is too short to be secure",
237 return (ISC_R_SUCCESS
);
240 if (algname_is_allocated(tkey
->algorithm
)) {
241 if (dns_name_dynamic(tkey
->algorithm
))
242 dns_name_free(tkey
->algorithm
, mctx
);
243 isc_mem_put(mctx
, tkey
->algorithm
, sizeof(dns_name_t
));
246 dns_name_free(&tkey
->name
, mctx
);
248 isc_mem_put(mctx
, tkey
, sizeof(dns_tsigkey_t
));
254 dns_tsigkey_create(dns_name_t
*name
, dns_name_t
*algorithm
,
255 unsigned char *secret
, int length
, isc_boolean_t generated
,
256 dns_name_t
*creator
, isc_stdtime_t inception
,
257 isc_stdtime_t expire
, isc_mem_t
*mctx
,
258 dns_tsig_keyring_t
*ring
, dns_tsigkey_t
**key
)
260 dst_key_t
*dstkey
= NULL
;
263 REQUIRE(length
>= 0);
265 REQUIRE(secret
!= NULL
);
267 if (!dns_name_equal(algorithm
, DNS_TSIG_HMACMD5_NAME
) && length
> 0)
268 return (DNS_R_BADALG
);
270 if (secret
!= NULL
) {
273 isc_buffer_init(&b
, secret
, length
);
274 isc_buffer_add(&b
, length
);
275 result
= dst_key_frombuffer(name
, DST_ALG_HMACMD5
,
280 if (result
!= ISC_R_SUCCESS
)
283 result
= dns_tsigkey_createfromkey(name
, algorithm
, dstkey
,
285 inception
, expire
, mctx
, ring
, key
);
286 if (result
!= ISC_R_SUCCESS
&& dstkey
!= NULL
)
287 dst_key_free(&dstkey
);
292 dns_tsigkey_attach(dns_tsigkey_t
*source
, dns_tsigkey_t
**targetp
) {
293 REQUIRE(VALID_TSIG_KEY(source
));
294 REQUIRE(targetp
!= NULL
&& *targetp
== NULL
);
296 isc_refcount_increment(&source
->refs
, NULL
);
301 tsigkey_free(dns_tsigkey_t
*key
) {
302 REQUIRE(VALID_TSIG_KEY(key
));
305 dns_name_free(&key
->name
, key
->mctx
);
306 if (algname_is_allocated(key
->algorithm
)) {
307 dns_name_free(key
->algorithm
, key
->mctx
);
308 isc_mem_put(key
->mctx
, key
->algorithm
, sizeof(dns_name_t
));
310 if (key
->key
!= NULL
)
311 dst_key_free(&key
->key
);
312 if (key
->creator
!= NULL
) {
313 dns_name_free(key
->creator
, key
->mctx
);
314 isc_mem_put(key
->mctx
, key
->creator
, sizeof(dns_name_t
));
316 isc_refcount_destroy(&key
->refs
);
317 isc_mem_put(key
->mctx
, key
, sizeof(dns_tsigkey_t
));
321 dns_tsigkey_detach(dns_tsigkey_t
**keyp
) {
325 REQUIRE(keyp
!= NULL
);
326 REQUIRE(VALID_TSIG_KEY(*keyp
));
329 isc_refcount_decrement(&key
->refs
, &refs
);
338 dns_tsigkey_setdeleted(dns_tsigkey_t
*key
) {
339 REQUIRE(VALID_TSIG_KEY(key
));
340 REQUIRE(key
->ring
!= NULL
);
342 RWLOCK(&key
->ring
->lock
, isc_rwlocktype_write
);
343 (void)dns_rbt_deletename(key
->ring
->keys
, &key
->name
, ISC_FALSE
);
344 RWUNLOCK(&key
->ring
->lock
, isc_rwlocktype_write
);
348 buffer_putuint48(isc_buffer_t
*b
, isc_uint64_t val
) {
352 valhi
= (isc_uint16_t
)(val
>> 32);
353 vallo
= (isc_uint32_t
)(val
& 0xFFFFFFFF);
354 isc_buffer_putuint16(b
, valhi
);
355 isc_buffer_putuint32(b
, vallo
);
359 dns_tsig_sign(dns_message_t
*msg
) {
361 dns_rdata_any_tsig_t tsig
, querytsig
;
362 unsigned char data
[128];
363 isc_buffer_t databuf
, sigbuf
;
364 isc_buffer_t
*dynbuf
;
366 dns_rdata_t
*rdata
= NULL
;
367 dns_rdatalist_t
*datalist
;
368 dns_rdataset_t
*dataset
;
372 dst_context_t
*ctx
= NULL
;
374 unsigned char badtimedata
[BADTIMELEN
];
375 unsigned int sigsize
= 0;
377 REQUIRE(msg
!= NULL
);
378 REQUIRE(VALID_TSIG_KEY(dns_message_gettsigkey(msg
)));
381 * If this is a response, there should be a query tsig.
383 if (is_response(msg
) && msg
->querytsig
== NULL
)
384 return (DNS_R_EXPECTEDTSIG
);
389 key
= dns_message_gettsigkey(msg
);
392 tsig
.common
.rdclass
= dns_rdataclass_any
;
393 tsig
.common
.rdtype
= dns_rdatatype_tsig
;
394 ISC_LINK_INIT(&tsig
.common
, link
);
395 dns_name_init(&tsig
.algorithm
, NULL
);
396 dns_name_clone(key
->algorithm
, &tsig
.algorithm
);
398 isc_stdtime_get(&now
);
399 tsig
.timesigned
= now
+ msg
->timeadjust
;
400 tsig
.fudge
= DNS_TSIG_FUDGE
;
402 tsig
.originalid
= msg
->id
;
404 isc_buffer_init(&databuf
, data
, sizeof(data
));
406 if (is_response(msg
))
407 tsig
.error
= msg
->querytsigstatus
;
409 tsig
.error
= dns_rcode_noerror
;
411 if (tsig
.error
!= dns_tsigerror_badtime
) {
415 isc_buffer_t otherbuf
;
417 tsig
.otherlen
= BADTIMELEN
;
418 tsig
.other
= badtimedata
;
419 isc_buffer_init(&otherbuf
, tsig
.other
, tsig
.otherlen
);
420 buffer_putuint48(&otherbuf
, tsig
.timesigned
);
423 if (key
->key
!= NULL
&& tsig
.error
!= dns_tsigerror_badsig
) {
424 unsigned char header
[DNS_MESSAGE_HEADERLEN
];
425 isc_buffer_t headerbuf
;
427 ret
= dst_context_create(key
->key
, mctx
, &ctx
);
428 if (ret
!= ISC_R_SUCCESS
)
432 * If this is a response, digest the query signature.
434 if (is_response(msg
)) {
435 dns_rdata_t querytsigrdata
= DNS_RDATA_INIT
;
437 ret
= dns_rdataset_first(msg
->querytsig
);
438 if (ret
!= ISC_R_SUCCESS
)
439 goto cleanup_context
;
440 dns_rdataset_current(msg
->querytsig
, &querytsigrdata
);
441 ret
= dns_rdata_tostruct(&querytsigrdata
, &querytsig
,
443 if (ret
!= ISC_R_SUCCESS
)
444 goto cleanup_context
;
445 isc_buffer_putuint16(&databuf
, querytsig
.siglen
);
446 if (isc_buffer_availablelength(&databuf
) <
450 goto cleanup_context
;
452 isc_buffer_putmem(&databuf
, querytsig
.signature
,
454 isc_buffer_usedregion(&databuf
, &r
);
455 ret
= dst_context_adddata(ctx
, &r
);
456 if (ret
!= ISC_R_SUCCESS
)
457 goto cleanup_context
;
463 isc_buffer_init(&headerbuf
, header
, sizeof(header
));
464 dns_message_renderheader(msg
, &headerbuf
);
465 isc_buffer_usedregion(&headerbuf
, &r
);
466 ret
= dst_context_adddata(ctx
, &r
);
467 if (ret
!= ISC_R_SUCCESS
)
468 goto cleanup_context
;
471 * Digest the remainder of the message.
473 isc_buffer_usedregion(msg
->buffer
, &r
);
474 isc_region_consume(&r
, DNS_MESSAGE_HEADERLEN
);
475 ret
= dst_context_adddata(ctx
, &r
);
476 if (ret
!= ISC_R_SUCCESS
)
477 goto cleanup_context
;
479 if (msg
->tcp_continuation
== 0) {
481 * Digest the name, class, ttl, alg.
483 dns_name_toregion(&key
->name
, &r
);
484 ret
= dst_context_adddata(ctx
, &r
);
485 if (ret
!= ISC_R_SUCCESS
)
486 goto cleanup_context
;
488 isc_buffer_clear(&databuf
);
489 isc_buffer_putuint16(&databuf
, dns_rdataclass_any
);
490 isc_buffer_putuint32(&databuf
, 0); /* ttl */
491 isc_buffer_usedregion(&databuf
, &r
);
492 ret
= dst_context_adddata(ctx
, &r
);
493 if (ret
!= ISC_R_SUCCESS
)
494 goto cleanup_context
;
496 dns_name_toregion(&tsig
.algorithm
, &r
);
497 ret
= dst_context_adddata(ctx
, &r
);
498 if (ret
!= ISC_R_SUCCESS
)
499 goto cleanup_context
;
502 /* Digest the timesigned and fudge */
503 isc_buffer_clear(&databuf
);
504 if (tsig
.error
== dns_tsigerror_badtime
)
505 tsig
.timesigned
= querytsig
.timesigned
;
506 buffer_putuint48(&databuf
, tsig
.timesigned
);
507 isc_buffer_putuint16(&databuf
, tsig
.fudge
);
508 isc_buffer_usedregion(&databuf
, &r
);
509 ret
= dst_context_adddata(ctx
, &r
);
510 if (ret
!= ISC_R_SUCCESS
)
511 goto cleanup_context
;
513 if (msg
->tcp_continuation
== 0) {
515 * Digest the error and other data length.
517 isc_buffer_clear(&databuf
);
518 isc_buffer_putuint16(&databuf
, tsig
.error
);
519 isc_buffer_putuint16(&databuf
, tsig
.otherlen
);
521 isc_buffer_usedregion(&databuf
, &r
);
522 ret
= dst_context_adddata(ctx
, &r
);
523 if (ret
!= ISC_R_SUCCESS
)
524 goto cleanup_context
;
527 * Digest the error and other data.
529 if (tsig
.otherlen
> 0) {
530 r
.length
= tsig
.otherlen
;
532 ret
= dst_context_adddata(ctx
, &r
);
533 if (ret
!= ISC_R_SUCCESS
)
534 goto cleanup_context
;
538 ret
= dst_key_sigsize(key
->key
, &sigsize
);
539 if (ret
!= ISC_R_SUCCESS
)
540 goto cleanup_context
;
541 tsig
.signature
= (unsigned char *) isc_mem_get(mctx
, sigsize
);
542 if (tsig
.signature
== NULL
) {
543 ret
= ISC_R_NOMEMORY
;
544 goto cleanup_context
;
547 isc_buffer_init(&sigbuf
, tsig
.signature
, sigsize
);
548 ret
= dst_context_sign(ctx
, &sigbuf
);
549 if (ret
!= ISC_R_SUCCESS
)
550 goto cleanup_signature
;
551 dst_context_destroy(&ctx
);
552 tsig
.siglen
= isc_buffer_usedlength(&sigbuf
);
555 tsig
.signature
= 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
)
564 ret
= dns_rdata_fromstruct(rdata
, dns_rdataclass_any
,
565 dns_rdatatype_tsig
, &tsig
, dynbuf
);
566 if (ret
!= ISC_R_SUCCESS
)
569 dns_message_takebuffer(msg
, &dynbuf
);
571 if (tsig
.signature
!= NULL
) {
572 isc_mem_put(mctx
, tsig
.signature
, sigsize
);
573 tsig
.signature
= NULL
;
577 ret
= dns_message_gettempname(msg
, &owner
);
578 if (ret
!= ISC_R_SUCCESS
)
580 dns_name_init(owner
, NULL
);
581 ret
= dns_name_dup(&key
->name
, msg
->mctx
, owner
);
582 if (ret
!= ISC_R_SUCCESS
)
586 ret
= dns_message_gettemprdatalist(msg
, &datalist
);
587 if (ret
!= ISC_R_SUCCESS
)
590 ret
= dns_message_gettemprdataset(msg
, &dataset
);
591 if (ret
!= ISC_R_SUCCESS
)
592 goto cleanup_rdatalist
;
593 datalist
->rdclass
= dns_rdataclass_any
;
594 datalist
->type
= dns_rdatatype_tsig
;
595 datalist
->covers
= 0;
597 ISC_LIST_INIT(datalist
->rdata
);
598 ISC_LIST_APPEND(datalist
->rdata
, rdata
, link
);
599 dns_rdataset_init(dataset
);
600 RUNTIME_CHECK(dns_rdatalist_tordataset(datalist
, dataset
)
603 msg
->tsigname
= owner
;
605 return (ISC_R_SUCCESS
);
608 dns_message_puttemprdatalist(msg
, &datalist
);
610 dns_message_puttempname(msg
, &owner
);
613 isc_buffer_free(&dynbuf
);
615 dns_message_puttemprdata(msg
, &rdata
);
617 if (tsig
.signature
!= NULL
)
618 isc_mem_put(mctx
, tsig
.signature
, sigsize
);
621 dst_context_destroy(&ctx
);
626 dns_tsig_verify(isc_buffer_t
*source
, dns_message_t
*msg
,
627 dns_tsig_keyring_t
*ring1
, dns_tsig_keyring_t
*ring2
)
629 dns_rdata_any_tsig_t tsig
, querytsig
;
630 isc_region_t r
, source_r
, header_r
, sig_r
;
631 isc_buffer_t databuf
;
632 unsigned char data
[32];
634 dns_rdata_t rdata
= DNS_RDATA_INIT
;
637 dns_tsigkey_t
*tsigkey
;
638 dst_key_t
*key
= NULL
;
639 unsigned char header
[DNS_MESSAGE_HEADERLEN
];
640 dst_context_t
*ctx
= NULL
;
642 isc_uint16_t addcount
, id
;
644 REQUIRE(source
!= NULL
);
645 REQUIRE(DNS_MESSAGE_VALID(msg
));
646 tsigkey
= dns_message_gettsigkey(msg
);
647 REQUIRE(tsigkey
== NULL
|| VALID_TSIG_KEY(tsigkey
));
649 msg
->verify_attempted
= 1;
651 if (msg
->tcp_continuation
) {
652 if (tsigkey
== NULL
|| msg
->querytsig
== NULL
)
653 return (DNS_R_UNEXPECTEDTSIG
);
654 return (tsig_verify_tcp(source
, msg
));
658 * There should be a TSIG record...
660 if (msg
->tsig
== NULL
)
661 return (DNS_R_EXPECTEDTSIG
);
664 * If this is a response and there's no key or query TSIG, there
665 * shouldn't be one on the response.
667 if (is_response(msg
) &&
668 (tsigkey
== NULL
|| msg
->querytsig
== NULL
))
669 return (DNS_R_UNEXPECTEDTSIG
);
674 * If we're here, we know the message is well formed and contains a
678 keyname
= msg
->tsigname
;
679 ret
= dns_rdataset_first(msg
->tsig
);
680 if (ret
!= ISC_R_SUCCESS
)
682 dns_rdataset_current(msg
->tsig
, &rdata
);
683 ret
= dns_rdata_tostruct(&rdata
, &tsig
, NULL
);
684 if (ret
!= ISC_R_SUCCESS
)
686 dns_rdata_reset(&rdata
);
687 if (is_response(msg
)) {
688 ret
= dns_rdataset_first(msg
->querytsig
);
689 if (ret
!= ISC_R_SUCCESS
)
691 dns_rdataset_current(msg
->querytsig
, &rdata
);
692 ret
= dns_rdata_tostruct(&rdata
, &querytsig
, NULL
);
693 if (ret
!= ISC_R_SUCCESS
)
698 * Do the key name and algorithm match that of the query?
700 if (is_response(msg
) &&
701 (!dns_name_equal(keyname
, &tsigkey
->name
) ||
702 !dns_name_equal(&tsig
.algorithm
, &querytsig
.algorithm
)))
704 msg
->tsigstatus
= dns_tsigerror_badkey
;
705 tsig_log(msg
->tsigkey
, 2,
706 "key name and algorithm do not match");
707 return (DNS_R_TSIGVERIFYFAILURE
);
711 * Get the current time.
713 isc_stdtime_get(&now
);
716 * Find dns_tsigkey_t based on keyname.
718 if (tsigkey
== NULL
) {
719 ret
= ISC_R_NOTFOUND
;
721 ret
= dns_tsigkey_find(&tsigkey
, keyname
,
722 &tsig
.algorithm
, ring1
);
723 if (ret
== ISC_R_NOTFOUND
&& ring2
!= NULL
)
724 ret
= dns_tsigkey_find(&tsigkey
, keyname
,
725 &tsig
.algorithm
, ring2
);
726 if (ret
!= ISC_R_SUCCESS
) {
727 msg
->tsigstatus
= dns_tsigerror_badkey
;
728 ret
= dns_tsigkey_create(keyname
, &tsig
.algorithm
,
729 NULL
, 0, ISC_FALSE
, NULL
,
731 mctx
, NULL
, &msg
->tsigkey
);
732 if (ret
!= ISC_R_SUCCESS
)
734 tsig_log(msg
->tsigkey
, 2, "unknown key");
735 return (DNS_R_TSIGVERIFYFAILURE
);
737 msg
->tsigkey
= tsigkey
;
745 if (now
+ msg
->timeadjust
> tsig
.timesigned
+ tsig
.fudge
) {
746 msg
->tsigstatus
= dns_tsigerror_badtime
;
747 tsig_log(msg
->tsigkey
, 2, "signature has expired");
748 return (DNS_R_CLOCKSKEW
);
749 } else if (now
+ msg
->timeadjust
< tsig
.timesigned
- tsig
.fudge
) {
750 msg
->tsigstatus
= dns_tsigerror_badtime
;
751 tsig_log(msg
->tsigkey
, 2, "signature is in the future");
752 return (DNS_R_CLOCKSKEW
);
755 if (tsig
.siglen
> 0) {
756 sig_r
.base
= tsig
.signature
;
757 sig_r
.length
= tsig
.siglen
;
759 ret
= dst_context_create(key
, mctx
, &ctx
);
760 if (ret
!= ISC_R_SUCCESS
)
763 if (is_response(msg
)) {
764 isc_buffer_init(&databuf
, data
, sizeof(data
));
765 isc_buffer_putuint16(&databuf
, querytsig
.siglen
);
766 isc_buffer_usedregion(&databuf
, &r
);
767 ret
= dst_context_adddata(ctx
, &r
);
768 if (ret
!= ISC_R_SUCCESS
)
769 goto cleanup_context
;
770 if (querytsig
.siglen
> 0) {
771 r
.length
= querytsig
.siglen
;
772 r
.base
= querytsig
.signature
;
773 ret
= dst_context_adddata(ctx
, &r
);
774 if (ret
!= ISC_R_SUCCESS
)
775 goto cleanup_context
;
780 * Extract the header.
782 isc_buffer_usedregion(source
, &r
);
783 memcpy(header
, r
.base
, DNS_MESSAGE_HEADERLEN
);
784 isc_region_consume(&r
, DNS_MESSAGE_HEADERLEN
);
787 * Decrement the additional field counter.
789 memcpy(&addcount
, &header
[DNS_MESSAGE_HEADERLEN
- 2], 2);
790 addcount
= htons((isc_uint16_t
)(ntohs(addcount
) - 1));
791 memcpy(&header
[DNS_MESSAGE_HEADERLEN
- 2], &addcount
, 2);
794 * Put in the original id.
796 id
= htons(tsig
.originalid
);
797 memcpy(&header
[0], &id
, 2);
800 * Digest the modified header.
802 header_r
.base
= (unsigned char *) header
;
803 header_r
.length
= DNS_MESSAGE_HEADERLEN
;
804 ret
= dst_context_adddata(ctx
, &header_r
);
805 if (ret
!= ISC_R_SUCCESS
)
806 goto cleanup_context
;
809 * Digest all non-TSIG records.
811 isc_buffer_usedregion(source
, &source_r
);
812 r
.base
= source_r
.base
+ DNS_MESSAGE_HEADERLEN
;
813 r
.length
= msg
->sigstart
- DNS_MESSAGE_HEADERLEN
;
814 ret
= dst_context_adddata(ctx
, &r
);
815 if (ret
!= ISC_R_SUCCESS
)
816 goto cleanup_context
;
819 * Digest the key name.
821 dns_name_toregion(&tsigkey
->name
, &r
);
822 ret
= dst_context_adddata(ctx
, &r
);
823 if (ret
!= ISC_R_SUCCESS
)
824 goto cleanup_context
;
826 isc_buffer_init(&databuf
, data
, sizeof(data
));
827 isc_buffer_putuint16(&databuf
, tsig
.common
.rdclass
);
828 isc_buffer_putuint32(&databuf
, msg
->tsig
->ttl
);
829 isc_buffer_usedregion(&databuf
, &r
);
830 ret
= dst_context_adddata(ctx
, &r
);
831 if (ret
!= ISC_R_SUCCESS
)
832 goto cleanup_context
;
835 * Digest the key algorithm.
837 dns_name_toregion(tsigkey
->algorithm
, &r
);
838 ret
= dst_context_adddata(ctx
, &r
);
839 if (ret
!= ISC_R_SUCCESS
)
840 goto cleanup_context
;
842 isc_buffer_clear(&databuf
);
843 buffer_putuint48(&databuf
, tsig
.timesigned
);
844 isc_buffer_putuint16(&databuf
, tsig
.fudge
);
845 isc_buffer_putuint16(&databuf
, tsig
.error
);
846 isc_buffer_putuint16(&databuf
, tsig
.otherlen
);
847 isc_buffer_usedregion(&databuf
, &r
);
848 ret
= dst_context_adddata(ctx
, &r
);
849 if (ret
!= ISC_R_SUCCESS
)
850 goto cleanup_context
;
852 if (tsig
.otherlen
> 0) {
854 r
.length
= tsig
.otherlen
;
855 ret
= dst_context_adddata(ctx
, &r
);
856 if (ret
!= ISC_R_SUCCESS
)
857 goto cleanup_context
;
860 ret
= dst_context_verify(ctx
, &sig_r
);
861 if (ret
== DST_R_VERIFYFAILURE
) {
862 msg
->tsigstatus
= dns_tsigerror_badsig
;
863 ret
= DNS_R_TSIGVERIFYFAILURE
;
864 tsig_log(msg
->tsigkey
, 2,
865 "signature failed to verify");
866 goto cleanup_context
;
867 } else if (ret
!= ISC_R_SUCCESS
)
868 goto cleanup_context
;
870 dst_context_destroy(&ctx
);
871 } else if (tsig
.error
!= dns_tsigerror_badsig
&&
872 tsig
.error
!= dns_tsigerror_badkey
)
874 msg
->tsigstatus
= dns_tsigerror_badsig
;
875 tsig_log(msg
->tsigkey
, 2, "signature was empty");
876 return (DNS_R_TSIGVERIFYFAILURE
);
879 msg
->tsigstatus
= dns_rcode_noerror
;
881 if (tsig
.error
!= dns_rcode_noerror
) {
882 if (tsig
.error
== dns_tsigerror_badtime
)
883 return (DNS_R_CLOCKSKEW
);
885 return (DNS_R_TSIGERRORSET
);
888 msg
->verified_sig
= 1;
890 return (ISC_R_SUCCESS
);
894 dst_context_destroy(&ctx
);
900 tsig_verify_tcp(isc_buffer_t
*source
, dns_message_t
*msg
) {
901 dns_rdata_any_tsig_t tsig
, querytsig
;
902 isc_region_t r
, source_r
, header_r
, sig_r
;
903 isc_buffer_t databuf
;
904 unsigned char data
[32];
906 dns_rdata_t rdata
= DNS_RDATA_INIT
;
909 dns_tsigkey_t
*tsigkey
;
910 dst_key_t
*key
= NULL
;
911 unsigned char header
[DNS_MESSAGE_HEADERLEN
];
912 isc_uint16_t addcount
, id
;
913 isc_boolean_t has_tsig
= ISC_FALSE
;
916 REQUIRE(source
!= NULL
);
917 REQUIRE(msg
!= NULL
);
918 REQUIRE(dns_message_gettsigkey(msg
) != NULL
);
919 REQUIRE(msg
->tcp_continuation
== 1);
920 REQUIRE(msg
->querytsig
!= NULL
);
922 if (!is_response(msg
))
923 return (DNS_R_EXPECTEDRESPONSE
);
927 tsigkey
= dns_message_gettsigkey(msg
);
930 * Extract and parse the previous TSIG
932 ret
= dns_rdataset_first(msg
->querytsig
);
933 if (ret
!= ISC_R_SUCCESS
)
935 dns_rdataset_current(msg
->querytsig
, &rdata
);
936 ret
= dns_rdata_tostruct(&rdata
, &querytsig
, NULL
);
937 if (ret
!= ISC_R_SUCCESS
)
939 dns_rdata_reset(&rdata
);
942 * If there is a TSIG in this message, do some checks.
944 if (msg
->tsig
!= NULL
) {
947 keyname
= msg
->tsigname
;
948 ret
= dns_rdataset_first(msg
->tsig
);
949 if (ret
!= ISC_R_SUCCESS
)
950 goto cleanup_querystruct
;
951 dns_rdataset_current(msg
->tsig
, &rdata
);
952 ret
= dns_rdata_tostruct(&rdata
, &tsig
, NULL
);
953 if (ret
!= ISC_R_SUCCESS
)
954 goto cleanup_querystruct
;
957 * Do the key name and algorithm match that of the query?
959 if (!dns_name_equal(keyname
, &tsigkey
->name
) ||
960 !dns_name_equal(&tsig
.algorithm
, &querytsig
.algorithm
))
962 msg
->tsigstatus
= dns_tsigerror_badkey
;
963 ret
= DNS_R_TSIGVERIFYFAILURE
;
964 tsig_log(msg
->tsigkey
, 2,
965 "key name and algorithm do not match");
966 goto cleanup_querystruct
;
972 isc_stdtime_get(&now
);
974 if (now
+ msg
->timeadjust
> tsig
.timesigned
+ tsig
.fudge
) {
975 msg
->tsigstatus
= dns_tsigerror_badtime
;
976 tsig_log(msg
->tsigkey
, 2, "signature has expired");
977 ret
= DNS_R_CLOCKSKEW
;
978 goto cleanup_querystruct
;
979 } else if (now
+ msg
->timeadjust
<
980 tsig
.timesigned
- tsig
.fudge
)
982 msg
->tsigstatus
= dns_tsigerror_badtime
;
983 tsig_log(msg
->tsigkey
, 2,
984 "signature is in the future");
985 ret
= DNS_R_CLOCKSKEW
;
986 goto cleanup_querystruct
;
992 if (msg
->tsigctx
== NULL
) {
993 ret
= dst_context_create(key
, mctx
, &msg
->tsigctx
);
994 if (ret
!= ISC_R_SUCCESS
)
995 goto cleanup_querystruct
;
998 * Digest the length of the query signature
1000 isc_buffer_init(&databuf
, data
, sizeof(data
));
1001 isc_buffer_putuint16(&databuf
, querytsig
.siglen
);
1002 isc_buffer_usedregion(&databuf
, &r
);
1003 ret
= dst_context_adddata(msg
->tsigctx
, &r
);
1004 if (ret
!= ISC_R_SUCCESS
)
1005 goto cleanup_context
;
1008 * Digest the data of the query signature
1010 if (querytsig
.siglen
> 0) {
1011 r
.length
= querytsig
.siglen
;
1012 r
.base
= querytsig
.signature
;
1013 ret
= dst_context_adddata(msg
->tsigctx
, &r
);
1014 if (ret
!= ISC_R_SUCCESS
)
1015 goto cleanup_context
;
1020 * Extract the header.
1022 isc_buffer_usedregion(source
, &r
);
1023 memcpy(header
, r
.base
, DNS_MESSAGE_HEADERLEN
);
1024 isc_region_consume(&r
, DNS_MESSAGE_HEADERLEN
);
1027 * Decrement the additional field counter if necessary.
1030 memcpy(&addcount
, &header
[DNS_MESSAGE_HEADERLEN
- 2], 2);
1031 addcount
= htons((isc_uint16_t
)(ntohs(addcount
) - 1));
1032 memcpy(&header
[DNS_MESSAGE_HEADERLEN
- 2], &addcount
, 2);
1036 * Put in the original id.
1038 /* XXX Can TCP transfers be forwarded? How would that work? */
1040 id
= htons(tsig
.originalid
);
1041 memcpy(&header
[0], &id
, 2);
1045 * Digest the modified header.
1047 header_r
.base
= (unsigned char *) header
;
1048 header_r
.length
= DNS_MESSAGE_HEADERLEN
;
1049 ret
= dst_context_adddata(msg
->tsigctx
, &header_r
);
1050 if (ret
!= ISC_R_SUCCESS
)
1051 goto cleanup_context
;
1054 * Digest all non-TSIG records.
1056 isc_buffer_usedregion(source
, &source_r
);
1057 r
.base
= source_r
.base
+ DNS_MESSAGE_HEADERLEN
;
1059 r
.length
= msg
->sigstart
- DNS_MESSAGE_HEADERLEN
;
1061 r
.length
= source_r
.length
- DNS_MESSAGE_HEADERLEN
;
1062 ret
= dst_context_adddata(msg
->tsigctx
, &r
);
1063 if (ret
!= ISC_R_SUCCESS
)
1064 goto cleanup_context
;
1067 * Digest the time signed and fudge.
1070 isc_buffer_init(&databuf
, data
, sizeof(data
));
1071 buffer_putuint48(&databuf
, tsig
.timesigned
);
1072 isc_buffer_putuint16(&databuf
, tsig
.fudge
);
1073 isc_buffer_usedregion(&databuf
, &r
);
1074 ret
= dst_context_adddata(msg
->tsigctx
, &r
);
1075 if (ret
!= ISC_R_SUCCESS
)
1076 goto cleanup_context
;
1078 sig_r
.base
= tsig
.signature
;
1079 sig_r
.length
= tsig
.siglen
;
1080 if (tsig
.siglen
== 0) {
1081 if (tsig
.error
!= dns_rcode_noerror
) {
1082 if (tsig
.error
== dns_tsigerror_badtime
)
1083 ret
= DNS_R_CLOCKSKEW
;
1085 ret
= DNS_R_TSIGERRORSET
;
1087 tsig_log(msg
->tsigkey
, 2,
1088 "signature is empty");
1089 ret
= DNS_R_TSIGVERIFYFAILURE
;
1091 goto cleanup_context
;
1094 ret
= dst_context_verify(msg
->tsigctx
, &sig_r
);
1095 if (ret
== DST_R_VERIFYFAILURE
) {
1096 msg
->tsigstatus
= dns_tsigerror_badsig
;
1097 tsig_log(msg
->tsigkey
, 2,
1098 "signature failed to verify");
1099 ret
= DNS_R_TSIGVERIFYFAILURE
;
1100 goto cleanup_context
;
1102 else if (ret
!= ISC_R_SUCCESS
)
1103 goto cleanup_context
;
1105 dst_context_destroy(&msg
->tsigctx
);
1108 msg
->tsigstatus
= dns_rcode_noerror
;
1109 return (ISC_R_SUCCESS
);
1112 dst_context_destroy(&msg
->tsigctx
);
1114 cleanup_querystruct
:
1115 dns_rdata_freestruct(&querytsig
);
1122 dns_tsigkey_find(dns_tsigkey_t
**tsigkey
, dns_name_t
*name
,
1123 dns_name_t
*algorithm
, dns_tsig_keyring_t
*ring
)
1127 isc_result_t result
;
1129 REQUIRE(tsigkey
!= NULL
);
1130 REQUIRE(*tsigkey
== NULL
);
1131 REQUIRE(name
!= NULL
);
1132 REQUIRE(ring
!= NULL
);
1134 isc_stdtime_get(&now
);
1135 RWLOCK(&ring
->lock
, isc_rwlocktype_read
);
1137 result
= dns_rbt_findname(ring
->keys
, name
, 0, NULL
, (void *)&key
);
1138 if (result
== DNS_R_PARTIALMATCH
|| result
== ISC_R_NOTFOUND
) {
1139 RWUNLOCK(&ring
->lock
, isc_rwlocktype_read
);
1140 return (ISC_R_NOTFOUND
);
1142 if (algorithm
!= NULL
&& !dns_name_equal(key
->algorithm
, algorithm
)) {
1143 RWUNLOCK(&ring
->lock
, isc_rwlocktype_read
);
1144 return (ISC_R_NOTFOUND
);
1146 if (key
->inception
!= key
->expire
&& key
->expire
< now
) {
1148 * The key has expired.
1150 RWUNLOCK(&ring
->lock
, isc_rwlocktype_read
);
1151 RWLOCK(&ring
->lock
, isc_rwlocktype_write
);
1152 (void) dns_rbt_deletename(ring
->keys
, name
, ISC_FALSE
);
1153 RWUNLOCK(&ring
->lock
, isc_rwlocktype_write
);
1154 return (ISC_R_NOTFOUND
);
1157 isc_refcount_increment(&key
->refs
, NULL
);
1158 RWUNLOCK(&ring
->lock
, isc_rwlocktype_read
);
1160 return (ISC_R_SUCCESS
);
1164 free_tsignode(void *node
, void *_unused
) {
1169 REQUIRE(node
!= NULL
);
1172 dns_tsigkey_detach(&key
);
1176 dns_tsigkeyring_create(isc_mem_t
*mctx
, dns_tsig_keyring_t
**ringp
) {
1177 isc_result_t result
;
1178 dns_tsig_keyring_t
*ring
;
1180 REQUIRE(mctx
!= NULL
);
1181 REQUIRE(ringp
!= NULL
);
1182 REQUIRE(*ringp
== NULL
);
1184 ring
= isc_mem_get(mctx
, sizeof(dns_tsig_keyring_t
));
1186 return (ISC_R_NOMEMORY
);
1188 result
= isc_rwlock_init(&ring
->lock
, 0, 0);
1189 if (result
!= ISC_R_SUCCESS
) {
1190 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
1191 "isc_rwlock_init() failed: %s",
1192 isc_result_totext(result
));
1193 return (ISC_R_UNEXPECTED
);
1197 result
= dns_rbt_create(mctx
, free_tsignode
, NULL
, &ring
->keys
);
1198 if (result
!= ISC_R_SUCCESS
) {
1199 isc_rwlock_destroy(&ring
->lock
);
1200 isc_mem_put(mctx
, ring
, sizeof(dns_tsig_keyring_t
));
1207 return (ISC_R_SUCCESS
);
1211 dns_tsigkeyring_destroy(dns_tsig_keyring_t
**ringp
) {
1212 dns_tsig_keyring_t
*ring
;
1214 REQUIRE(ringp
!= NULL
);
1215 REQUIRE(*ringp
!= NULL
);
1220 dns_rbt_destroy(&ring
->keys
);
1221 isc_rwlock_destroy(&ring
->lock
);
1222 isc_mem_put(ring
->mctx
, ring
, sizeof(dns_tsig_keyring_t
));