2 * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003 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: dnssec.c,v 1.69.2.7 2004/03/09 06:11:01 marka Exp $
27 #include <isc/buffer.h>
29 #include <isc/serial.h>
30 #include <isc/string.h>
34 #include <dns/dnssec.h>
35 #include <dns/fixedname.h>
36 #include <dns/keyvalues.h>
37 #include <dns/message.h>
38 #include <dns/rdata.h>
39 #include <dns/rdatalist.h>
40 #include <dns/rdataset.h>
41 #include <dns/rdatastruct.h>
42 #include <dns/result.h>
43 #include <dns/tsig.h> /* for DNS_TSIG_FUDGE */
45 #include <dst/result.h>
47 #define is_response(msg) (msg->flags & DNS_MESSAGEFLAG_QR)
49 #define RETERR(x) do { \
51 if (result != ISC_R_SUCCESS) \
60 digest_callback(void *arg
, isc_region_t
*data
);
63 rdata_compare_wrapper(const void *rdata1
, const void *rdata2
);
66 rdataset_to_sortedarray(dns_rdataset_t
*set
, isc_mem_t
*mctx
,
67 dns_rdata_t
**rdata
, int *nrdata
);
70 digest_callback(void *arg
, isc_region_t
*data
) {
71 dst_context_t
*ctx
= arg
;
73 return (dst_context_adddata(ctx
, data
));
80 rdata_compare_wrapper(const void *rdata1
, const void *rdata2
) {
81 return (dns_rdata_compare((const dns_rdata_t
*)rdata1
,
82 (const dns_rdata_t
*)rdata2
));
86 * Sort the rdataset into an array.
89 rdataset_to_sortedarray(dns_rdataset_t
*set
, isc_mem_t
*mctx
,
90 dns_rdata_t
**rdata
, int *nrdata
)
96 n
= dns_rdataset_count(set
);
98 data
= isc_mem_get(mctx
, n
* sizeof(dns_rdata_t
));
100 return (ISC_R_NOMEMORY
);
102 ret
= dns_rdataset_first(set
);
103 if (ret
!= ISC_R_SUCCESS
) {
104 isc_mem_put(mctx
, data
, n
* sizeof(dns_rdata_t
));
109 * Put them in the array.
112 dns_rdata_init(&data
[i
]);
113 dns_rdataset_current(set
, &data
[i
++]);
114 } while (dns_rdataset_next(set
) == ISC_R_SUCCESS
);
119 qsort(data
, n
, sizeof(dns_rdata_t
), rdata_compare_wrapper
);
122 return (ISC_R_SUCCESS
);
126 dns_dnssec_keyfromrdata(dns_name_t
*name
, dns_rdata_t
*rdata
, isc_mem_t
*mctx
,
132 INSIST(name
!= NULL
);
133 INSIST(rdata
!= NULL
);
134 INSIST(mctx
!= NULL
);
136 INSIST(*key
== NULL
);
138 dns_rdata_toregion(rdata
, &r
);
139 isc_buffer_init(&b
, r
.base
, r
.length
);
140 isc_buffer_add(&b
, r
.length
);
141 return (dst_key_fromdns(name
, rdata
->rdclass
, &b
, mctx
, key
));
145 digest_sig(dst_context_t
*ctx
, dns_rdata_t
*sigrdata
, dns_rdata_sig_t
*sig
) {
148 dns_fixedname_t fname
;
150 dns_rdata_toregion(sigrdata
, &r
);
151 INSIST(r
.length
>= 19);
154 ret
= dst_context_adddata(ctx
, &r
);
155 if (ret
!= ISC_R_SUCCESS
)
157 dns_fixedname_init(&fname
);
158 dns_name_downcase(&sig
->signer
, dns_fixedname_name(&fname
), NULL
);
159 dns_name_toregion(dns_fixedname_name(&fname
), &r
);
160 return (dst_context_adddata(ctx
, &r
));
164 dns_dnssec_sign(dns_name_t
*name
, dns_rdataset_t
*set
, dst_key_t
*key
,
165 isc_stdtime_t
*inception
, isc_stdtime_t
*expire
,
166 isc_mem_t
*mctx
, isc_buffer_t
*buffer
, dns_rdata_t
*sigrdata
)
169 dns_rdata_t tmpsigrdata
;
172 isc_buffer_t sigbuf
, envbuf
;
174 dst_context_t
*ctx
= NULL
;
176 isc_buffer_t
*databuf
= NULL
;
179 unsigned int sigsize
;
180 dns_fixedname_t fnewname
;
182 REQUIRE(name
!= NULL
);
183 REQUIRE(dns_name_depth(name
) <= 255);
184 REQUIRE(set
!= NULL
);
185 REQUIRE(key
!= NULL
);
186 REQUIRE(inception
!= NULL
);
187 REQUIRE(expire
!= NULL
);
188 REQUIRE(mctx
!= NULL
);
189 REQUIRE(sigrdata
!= NULL
);
191 if (*inception
>= *expire
)
192 return (DNS_R_INVALIDTIME
);
195 * Is the key allowed to sign data?
197 flags
= dst_key_flags(key
);
198 if (flags
& DNS_KEYTYPE_NOAUTH
)
199 return (DNS_R_KEYUNAUTHORIZED
);
200 if ((flags
& DNS_KEYFLAG_OWNERMASK
) != DNS_KEYOWNER_ZONE
)
201 return (DNS_R_KEYUNAUTHORIZED
);
204 sig
.common
.rdclass
= set
->rdclass
;
205 sig
.common
.rdtype
= dns_rdatatype_sig
;
206 ISC_LINK_INIT(&sig
.common
, link
);
208 dns_name_init(&sig
.signer
, NULL
);
209 dns_name_clone(dst_key_name(key
), &sig
.signer
);
211 sig
.covered
= set
->type
;
212 sig
.algorithm
= dst_key_alg(key
);
213 sig
.labels
= dns_name_depth(name
) - 1;
214 if (dns_name_iswildcard(name
))
216 sig
.originalttl
= set
->ttl
;
217 sig
.timesigned
= *inception
;
218 sig
.timeexpire
= *expire
;
219 sig
.keyid
= dst_key_id(key
);
220 ret
= dst_key_sigsize(key
, &sigsize
);
221 if (ret
!= ISC_R_SUCCESS
)
223 sig
.siglen
= sigsize
;
225 * The actual contents of sig.signature are not important yet, since
226 * they're not used in digest_sig().
228 sig
.signature
= isc_mem_get(mctx
, sig
.siglen
);
229 if (sig
.signature
== NULL
)
230 return (ISC_R_NOMEMORY
);
232 ret
= isc_buffer_allocate(mctx
, &databuf
, sigsize
+ 256 + 18);
233 if (ret
!= ISC_R_SUCCESS
)
234 goto cleanup_signature
;
236 dns_rdata_init(&tmpsigrdata
);
237 ret
= dns_rdata_fromstruct(&tmpsigrdata
, sig
.common
.rdclass
,
238 sig
.common
.rdtype
, &sig
, databuf
);
239 if (ret
!= ISC_R_SUCCESS
)
240 goto cleanup_databuf
;
242 ret
= dst_context_create(key
, mctx
, &ctx
);
243 if (ret
!= ISC_R_SUCCESS
)
244 goto cleanup_databuf
;
247 * Digest the SIG rdata.
249 ret
= digest_sig(ctx
, &tmpsigrdata
, &sig
);
250 if (ret
!= ISC_R_SUCCESS
)
251 goto cleanup_context
;
253 dns_fixedname_init(&fnewname
);
254 dns_name_downcase(name
, dns_fixedname_name(&fnewname
), NULL
);
255 dns_name_toregion(dns_fixedname_name(&fnewname
), &r
);
258 * Create an envelope for each rdata: <name|type|class|ttl>.
260 isc_buffer_init(&envbuf
, data
, sizeof(data
));
261 memcpy(data
, r
.base
, r
.length
);
262 isc_buffer_add(&envbuf
, r
.length
);
263 isc_buffer_putuint16(&envbuf
, set
->type
);
264 isc_buffer_putuint16(&envbuf
, set
->rdclass
);
265 isc_buffer_putuint32(&envbuf
, set
->ttl
);
267 ret
= rdataset_to_sortedarray(set
, mctx
, &rdatas
, &nrdatas
);
268 if (ret
!= ISC_R_SUCCESS
)
269 goto cleanup_context
;
270 isc_buffer_usedregion(&envbuf
, &r
);
272 for (i
= 0; i
< nrdatas
; i
++) {
280 if (i
> 0 && dns_rdata_compare(&rdatas
[i
], &rdatas
[i
-1]) == 0)
284 * Digest the envelope.
286 ret
= dst_context_adddata(ctx
, &r
);
287 if (ret
!= ISC_R_SUCCESS
)
291 * Digest the length of the rdata.
293 isc_buffer_init(&lenbuf
, &len
, sizeof(len
));
294 INSIST(rdatas
[i
].length
< 65536);
295 isc_buffer_putuint16(&lenbuf
, (isc_uint16_t
)rdatas
[i
].length
);
296 isc_buffer_usedregion(&lenbuf
, &lenr
);
297 ret
= dst_context_adddata(ctx
, &lenr
);
298 if (ret
!= ISC_R_SUCCESS
)
304 ret
= dns_rdata_digest(&rdatas
[i
], digest_callback
, ctx
);
305 if (ret
!= ISC_R_SUCCESS
)
309 isc_buffer_init(&sigbuf
, sig
.signature
, sig
.siglen
);
310 ret
= dst_context_sign(ctx
, &sigbuf
);
311 if (ret
!= ISC_R_SUCCESS
)
313 isc_buffer_usedregion(&sigbuf
, &r
);
314 if (r
.length
!= sig
.siglen
) {
318 memcpy(sig
.signature
, r
.base
, sig
.siglen
);
320 ret
= dns_rdata_fromstruct(sigrdata
, sig
.common
.rdclass
,
321 sig
.common
.rdtype
, &sig
, buffer
);
324 isc_mem_put(mctx
, rdatas
, nrdatas
* sizeof(dns_rdata_t
));
326 dst_context_destroy(&ctx
);
329 isc_buffer_free(&databuf
);
331 isc_mem_put(mctx
, sig
.signature
, sig
.siglen
);
337 dns_dnssec_verify(dns_name_t
*name
, dns_rdataset_t
*set
, dst_key_t
*key
,
338 isc_boolean_t ignoretime
, isc_mem_t
*mctx
,
339 dns_rdata_t
*sigrdata
)
342 dns_fixedname_t fnewname
;
349 unsigned char data
[300];
350 dst_context_t
*ctx
= NULL
;
354 REQUIRE(name
!= NULL
);
355 REQUIRE(set
!= NULL
);
356 REQUIRE(key
!= NULL
);
357 REQUIRE(mctx
!= NULL
);
358 REQUIRE(sigrdata
!= NULL
&& sigrdata
->type
== dns_rdatatype_sig
);
360 ret
= dns_rdata_tostruct(sigrdata
, &sig
, NULL
);
361 if (ret
!= ISC_R_SUCCESS
)
364 if (isc_serial_lt(sig
.timeexpire
, sig
.timesigned
))
365 return (DNS_R_SIGINVALID
);
368 isc_stdtime_get(&now
);
371 * Is SIG temporally valid?
373 if (isc_serial_lt((isc_uint32_t
)now
, sig
.timesigned
))
374 return (DNS_R_SIGFUTURE
);
375 else if (isc_serial_lt(sig
.timeexpire
, (isc_uint32_t
)now
))
376 return (DNS_R_SIGEXPIRED
);
380 * Is the key allowed to sign data?
382 flags
= dst_key_flags(key
);
383 if (flags
& DNS_KEYTYPE_NOAUTH
)
384 return (DNS_R_KEYUNAUTHORIZED
);
385 if ((flags
& DNS_KEYFLAG_OWNERMASK
) != DNS_KEYOWNER_ZONE
)
386 return (DNS_R_KEYUNAUTHORIZED
);
388 ret
= dst_context_create(key
, mctx
, &ctx
);
389 if (ret
!= ISC_R_SUCCESS
)
393 * Digest the SIG rdata (not including the signature).
395 ret
= digest_sig(ctx
, sigrdata
, &sig
);
396 if (ret
!= ISC_R_SUCCESS
)
397 goto cleanup_context
;
400 * If the name is an expanded wildcard, use the wildcard name.
402 dns_fixedname_init(&fnewname
);
403 labels
= dns_name_depth(name
) - 1;
404 if (labels
- sig
.labels
> 0) {
405 dns_name_splitatdepth(name
, sig
.labels
+ 1, NULL
,
406 dns_fixedname_name(&fnewname
));
407 dns_name_downcase(dns_fixedname_name(&fnewname
),
408 dns_fixedname_name(&fnewname
),
412 dns_name_downcase(name
, dns_fixedname_name(&fnewname
), NULL
);
414 dns_name_toregion(dns_fixedname_name(&fnewname
), &r
);
417 * Create an envelope for each rdata: <name|type|class|ttl>.
419 isc_buffer_init(&envbuf
, data
, sizeof(data
));
420 if (labels
- sig
.labels
> 0) {
421 isc_buffer_putuint8(&envbuf
, 1);
422 isc_buffer_putuint8(&envbuf
, '*');
423 memcpy(data
+ 2, r
.base
, r
.length
);
426 memcpy(data
, r
.base
, r
.length
);
427 isc_buffer_add(&envbuf
, r
.length
);
428 isc_buffer_putuint16(&envbuf
, set
->type
);
429 isc_buffer_putuint16(&envbuf
, set
->rdclass
);
430 isc_buffer_putuint32(&envbuf
, sig
.originalttl
);
432 ret
= rdataset_to_sortedarray(set
, mctx
, &rdatas
, &nrdatas
);
433 if (ret
!= ISC_R_SUCCESS
)
434 goto cleanup_context
;
436 isc_buffer_usedregion(&envbuf
, &r
);
438 for (i
= 0; i
< nrdatas
; i
++) {
446 if (i
> 0 && dns_rdata_compare(&rdatas
[i
], &rdatas
[i
-1]) == 0)
450 * Digest the envelope.
452 ret
= dst_context_adddata(ctx
, &r
);
453 if (ret
!= ISC_R_SUCCESS
)
457 * Digest the rdata length.
459 isc_buffer_init(&lenbuf
, &len
, sizeof(len
));
460 INSIST(rdatas
[i
].length
< 65536);
461 isc_buffer_putuint16(&lenbuf
, (isc_uint16_t
)rdatas
[i
].length
);
462 isc_buffer_usedregion(&lenbuf
, &lenr
);
467 ret
= dst_context_adddata(ctx
, &lenr
);
468 if (ret
!= ISC_R_SUCCESS
)
470 ret
= dns_rdata_digest(&rdatas
[i
], digest_callback
, ctx
);
471 if (ret
!= ISC_R_SUCCESS
)
475 r
.base
= sig
.signature
;
476 r
.length
= sig
.siglen
;
477 ret
= dst_context_verify(ctx
, &r
);
478 if (ret
== DST_R_VERIFYFAILURE
)
479 ret
= DNS_R_SIGINVALID
;
482 isc_mem_put(mctx
, rdatas
, nrdatas
* sizeof(dns_rdata_t
));
484 dst_context_destroy(&ctx
);
486 dns_rdata_freestruct(&sig
);
491 #define is_zone_key(key) ((dst_key_flags(key) & DNS_KEYFLAG_OWNERMASK) \
492 == DNS_KEYOWNER_ZONE)
495 dns_dnssec_findzonekeys(dns_db_t
*db
, dns_dbversion_t
*ver
,
496 dns_dbnode_t
*node
, dns_name_t
*name
, isc_mem_t
*mctx
,
497 unsigned int maxkeys
, dst_key_t
**keys
,
500 dns_rdataset_t rdataset
;
501 dns_rdata_t rdata
= DNS_RDATA_INIT
;
503 dst_key_t
*pubkey
= NULL
;
504 unsigned int count
= 0;
507 dns_rdataset_init(&rdataset
);
508 RETERR(dns_db_findrdataset(db
, node
, ver
, dns_rdatatype_key
, 0, 0,
510 RETERR(dns_rdataset_first(&rdataset
));
511 while (result
== ISC_R_SUCCESS
&& count
< maxkeys
) {
513 dns_rdataset_current(&rdataset
, &rdata
);
514 RETERR(dns_dnssec_keyfromrdata(name
, &rdata
, mctx
, &pubkey
));
515 if (!is_zone_key(pubkey
))
518 result
= dst_key_fromfile(dst_key_name(pubkey
),
521 DST_TYPE_PUBLIC
|DST_TYPE_PRIVATE
,
524 if (result
== ISC_R_FILENOTFOUND
)
526 if (result
!= ISC_R_SUCCESS
)
528 if ((dst_key_flags(keys
[count
]) & DNS_KEYTYPE_NOAUTH
) != 0) {
529 dst_key_free(&keys
[count
]);
534 dst_key_free(&pubkey
);
535 dns_rdata_reset(&rdata
);
536 result
= dns_rdataset_next(&rdataset
);
538 if (result
!= ISC_R_NOMORE
)
541 result
= ISC_R_NOTFOUND
;
543 result
= ISC_R_SUCCESS
;
546 if (dns_rdataset_isassociated(&rdataset
))
547 dns_rdataset_disassociate(&rdataset
);
549 dst_key_free(&pubkey
);
555 dns_dnssec_signmessage(dns_message_t
*msg
, dst_key_t
*key
) {
557 unsigned char data
[512];
558 unsigned char header
[DNS_MESSAGE_HEADERLEN
];
559 isc_buffer_t headerbuf
, databuf
, sigbuf
;
560 unsigned int sigsize
;
561 isc_buffer_t
*dynbuf
= NULL
;
563 dns_rdatalist_t
*datalist
;
564 dns_rdataset_t
*dataset
;
567 dst_context_t
*ctx
= NULL
;
570 isc_boolean_t signeedsfree
= ISC_TRUE
;
572 REQUIRE(msg
!= NULL
);
573 REQUIRE(key
!= NULL
);
575 if (is_response(msg
))
576 REQUIRE(msg
->query
.base
!= NULL
);
580 memset(&sig
, 0, sizeof(dns_rdata_sig_t
));
583 sig
.common
.rdclass
= dns_rdataclass_any
;
584 sig
.common
.rdtype
= dns_rdatatype_sig
;
585 ISC_LINK_INIT(&sig
.common
, link
);
588 sig
.algorithm
= dst_key_alg(key
);
589 sig
.labels
= 0; /* the root name */
592 isc_stdtime_get(&now
);
593 sig
.timesigned
= now
- DNS_TSIG_FUDGE
;
594 sig
.timeexpire
= now
+ DNS_TSIG_FUDGE
;
596 sig
.keyid
= dst_key_id(key
);
598 dns_name_init(&sig
.signer
, NULL
);
599 dns_name_clone(dst_key_name(key
), &sig
.signer
);
602 sig
.signature
= NULL
;
604 isc_buffer_init(&databuf
, data
, sizeof(data
));
606 RETERR(dst_context_create(key
, mctx
, &ctx
));
609 * Digest the fields of the SIG - we can cheat and use
610 * dns_rdata_fromstruct. Since siglen is 0, the digested data
611 * is identical to dns format.
613 RETERR(dns_rdata_fromstruct(NULL
, dns_rdataclass_any
,
614 dns_rdatatype_sig
, &sig
, &databuf
));
615 isc_buffer_usedregion(&databuf
, &r
);
616 RETERR(dst_context_adddata(ctx
, &r
));
619 * If this is a response, digest the query.
621 if (is_response(msg
))
622 RETERR(dst_context_adddata(ctx
, &msg
->query
));
627 isc_buffer_init(&headerbuf
, header
, sizeof(header
));
628 dns_message_renderheader(msg
, &headerbuf
);
629 isc_buffer_usedregion(&headerbuf
, &r
);
630 RETERR(dst_context_adddata(ctx
, &r
));
633 * Digest the remainder of the message.
635 isc_buffer_usedregion(msg
->buffer
, &r
);
636 isc_region_consume(&r
, DNS_MESSAGE_HEADERLEN
);
637 RETERR(dst_context_adddata(ctx
, &r
));
639 RETERR(dst_key_sigsize(key
, &sigsize
));
640 sig
.siglen
= sigsize
;
641 sig
.signature
= (unsigned char *) isc_mem_get(mctx
, sig
.siglen
);
642 if (sig
.signature
== NULL
) {
643 result
= ISC_R_NOMEMORY
;
647 isc_buffer_init(&sigbuf
, sig
.signature
, sig
.siglen
);
648 RETERR(dst_context_sign(ctx
, &sigbuf
));
649 dst_context_destroy(&ctx
);
652 RETERR(dns_message_gettemprdata(msg
, &rdata
));
653 RETERR(isc_buffer_allocate(msg
->mctx
, &dynbuf
, 1024));
654 RETERR(dns_rdata_fromstruct(rdata
, dns_rdataclass_any
,
655 dns_rdatatype_sig
, &sig
, dynbuf
));
657 isc_mem_put(mctx
, sig
.signature
, sig
.siglen
);
658 signeedsfree
= ISC_FALSE
;
660 dns_message_takebuffer(msg
, &dynbuf
);
663 RETERR(dns_message_gettemprdatalist(msg
, &datalist
));
664 datalist
->rdclass
= dns_rdataclass_any
;
665 datalist
->type
= dns_rdatatype_sig
;
666 datalist
->covers
= 0;
668 ISC_LIST_INIT(datalist
->rdata
);
669 ISC_LIST_APPEND(datalist
->rdata
, rdata
, link
);
671 RETERR(dns_message_gettemprdataset(msg
, &dataset
));
672 dns_rdataset_init(dataset
);
673 dns_rdatalist_tordataset(datalist
, dataset
);
676 return (ISC_R_SUCCESS
);
680 isc_buffer_free(&dynbuf
);
682 isc_mem_put(mctx
, sig
.signature
, sig
.siglen
);
684 dst_context_destroy(&ctx
);
690 dns_dnssec_verifymessage(isc_buffer_t
*source
, dns_message_t
*msg
,
694 unsigned char header
[DNS_MESSAGE_HEADERLEN
];
695 dns_rdata_t rdata
= DNS_RDATA_INIT
;
696 isc_region_t r
, source_r
, sig_r
, header_r
;
698 dst_context_t
*ctx
= NULL
;
701 isc_uint16_t addcount
;
702 isc_boolean_t signeedsfree
= ISC_FALSE
;
704 REQUIRE(source
!= NULL
);
705 REQUIRE(msg
!= NULL
);
706 REQUIRE(key
!= NULL
);
710 msg
->verify_attempted
= 1;
712 if (is_response(msg
)) {
713 if (msg
->query
.base
== NULL
)
714 return (DNS_R_UNEXPECTEDTSIG
);
717 isc_buffer_usedregion(source
, &source_r
);
719 RETERR(dns_rdataset_first(msg
->sig0
));
720 dns_rdataset_current(msg
->sig0
, &rdata
);
722 RETERR(dns_rdata_tostruct(&rdata
, &sig
, NULL
));
723 signeedsfree
= ISC_TRUE
;
725 if (sig
.labels
!= 0) {
726 result
= DNS_R_SIGINVALID
;
730 if (isc_serial_lt(sig
.timeexpire
, sig
.timesigned
)) {
731 result
= DNS_R_SIGINVALID
;
732 msg
->sig0status
= dns_tsigerror_badtime
;
736 isc_stdtime_get(&now
);
737 if (isc_serial_lt((isc_uint32_t
)now
, sig
.timesigned
)) {
738 result
= DNS_R_SIGFUTURE
;
739 msg
->sig0status
= dns_tsigerror_badtime
;
742 else if (isc_serial_lt(sig
.timeexpire
, (isc_uint32_t
)now
)) {
743 result
= DNS_R_SIGEXPIRED
;
744 msg
->sig0status
= dns_tsigerror_badtime
;
748 if (!dns_name_equal(dst_key_name(key
), &sig
.signer
)) {
749 result
= DNS_R_SIGINVALID
;
750 msg
->sig0status
= dns_tsigerror_badkey
;
754 RETERR(dst_context_create(key
, mctx
, &ctx
));
757 * Digest the SIG(0) record, except for the signature.
759 dns_rdata_toregion(&rdata
, &r
);
760 r
.length
-= sig
.siglen
;
761 RETERR(dst_context_adddata(ctx
, &r
));
764 * If this is a response, digest the query.
766 if (is_response(msg
))
767 RETERR(dst_context_adddata(ctx
, &msg
->query
));
770 * Extract the header.
772 memcpy(header
, source_r
.base
, DNS_MESSAGE_HEADERLEN
);
775 * Decrement the additional field counter.
777 memcpy(&addcount
, &header
[DNS_MESSAGE_HEADERLEN
- 2], 2);
778 addcount
= htons((isc_uint16_t
)(ntohs(addcount
) - 1));
779 memcpy(&header
[DNS_MESSAGE_HEADERLEN
- 2], &addcount
, 2);
782 * Digest the modified header.
784 header_r
.base
= (unsigned char *) header
;
785 header_r
.length
= DNS_MESSAGE_HEADERLEN
;
786 RETERR(dst_context_adddata(ctx
, &header_r
));
789 * Digest all non-SIG(0) records.
791 r
.base
= source_r
.base
+ DNS_MESSAGE_HEADERLEN
;
792 r
.length
= msg
->sigstart
- DNS_MESSAGE_HEADERLEN
;
793 RETERR(dst_context_adddata(ctx
, &r
));
795 sig_r
.base
= sig
.signature
;
796 sig_r
.length
= sig
.siglen
;
797 result
= dst_context_verify(ctx
, &sig_r
);
798 if (result
!= ISC_R_SUCCESS
) {
799 msg
->sig0status
= dns_tsigerror_badsig
;
803 msg
->verified_sig
= 1;
805 dst_context_destroy(&ctx
);
806 dns_rdata_freestruct(&sig
);
808 return (ISC_R_SUCCESS
);
812 dns_rdata_freestruct(&sig
);
814 dst_context_destroy(&ctx
);