2 * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or 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.91.58.2 2008/11/14 23:46:41 tbox Exp $
28 #include <isc/buffer.h>
30 #include <isc/serial.h>
31 #include <isc/string.h>
35 #include <dns/dnssec.h>
36 #include <dns/fixedname.h>
37 #include <dns/keyvalues.h>
38 #include <dns/message.h>
39 #include <dns/rdata.h>
40 #include <dns/rdatalist.h>
41 #include <dns/rdataset.h>
42 #include <dns/rdatastruct.h>
43 #include <dns/result.h>
44 #include <dns/tsig.h> /* for DNS_TSIG_FUDGE */
46 #include <dst/result.h>
48 #define is_response(msg) (msg->flags & DNS_MESSAGEFLAG_QR)
50 #define RETERR(x) do { \
52 if (result != ISC_R_SUCCESS) \
61 digest_callback(void *arg
, isc_region_t
*data
);
64 rdata_compare_wrapper(const void *rdata1
, const void *rdata2
);
67 rdataset_to_sortedarray(dns_rdataset_t
*set
, isc_mem_t
*mctx
,
68 dns_rdata_t
**rdata
, int *nrdata
);
71 digest_callback(void *arg
, isc_region_t
*data
) {
72 dst_context_t
*ctx
= arg
;
74 return (dst_context_adddata(ctx
, data
));
81 rdata_compare_wrapper(const void *rdata1
, const void *rdata2
) {
82 return (dns_rdata_compare((const dns_rdata_t
*)rdata1
,
83 (const dns_rdata_t
*)rdata2
));
87 * Sort the rdataset into an array.
90 rdataset_to_sortedarray(dns_rdataset_t
*set
, isc_mem_t
*mctx
,
91 dns_rdata_t
**rdata
, int *nrdata
)
97 n
= dns_rdataset_count(set
);
99 data
= isc_mem_get(mctx
, n
* sizeof(dns_rdata_t
));
101 return (ISC_R_NOMEMORY
);
103 ret
= dns_rdataset_first(set
);
104 if (ret
!= ISC_R_SUCCESS
) {
105 isc_mem_put(mctx
, data
, n
* sizeof(dns_rdata_t
));
110 * Put them in the array.
113 dns_rdata_init(&data
[i
]);
114 dns_rdataset_current(set
, &data
[i
++]);
115 } while (dns_rdataset_next(set
) == ISC_R_SUCCESS
);
120 qsort(data
, n
, sizeof(dns_rdata_t
), rdata_compare_wrapper
);
123 return (ISC_R_SUCCESS
);
127 dns_dnssec_keyfromrdata(dns_name_t
*name
, dns_rdata_t
*rdata
, isc_mem_t
*mctx
,
133 INSIST(name
!= NULL
);
134 INSIST(rdata
!= NULL
);
135 INSIST(mctx
!= NULL
);
137 INSIST(*key
== NULL
);
138 REQUIRE(rdata
->type
== dns_rdatatype_key
||
139 rdata
->type
== dns_rdatatype_dnskey
);
141 dns_rdata_toregion(rdata
, &r
);
142 isc_buffer_init(&b
, r
.base
, r
.length
);
143 isc_buffer_add(&b
, r
.length
);
144 return (dst_key_fromdns(name
, rdata
->rdclass
, &b
, mctx
, key
));
148 digest_sig(dst_context_t
*ctx
, dns_rdata_t
*sigrdata
, dns_rdata_rrsig_t
*sig
) {
151 dns_fixedname_t fname
;
153 dns_rdata_toregion(sigrdata
, &r
);
154 INSIST(r
.length
>= 19);
157 ret
= dst_context_adddata(ctx
, &r
);
158 if (ret
!= ISC_R_SUCCESS
)
160 dns_fixedname_init(&fname
);
161 RUNTIME_CHECK(dns_name_downcase(&sig
->signer
,
162 dns_fixedname_name(&fname
), NULL
)
164 dns_name_toregion(dns_fixedname_name(&fname
), &r
);
165 return (dst_context_adddata(ctx
, &r
));
169 dns_dnssec_sign(dns_name_t
*name
, dns_rdataset_t
*set
, dst_key_t
*key
,
170 isc_stdtime_t
*inception
, isc_stdtime_t
*expire
,
171 isc_mem_t
*mctx
, isc_buffer_t
*buffer
, dns_rdata_t
*sigrdata
)
173 dns_rdata_rrsig_t sig
;
174 dns_rdata_t tmpsigrdata
;
177 isc_buffer_t sigbuf
, envbuf
;
179 dst_context_t
*ctx
= NULL
;
181 isc_buffer_t
*databuf
= NULL
;
184 unsigned int sigsize
;
185 dns_fixedname_t fnewname
;
187 REQUIRE(name
!= NULL
);
188 REQUIRE(dns_name_countlabels(name
) <= 255);
189 REQUIRE(set
!= NULL
);
190 REQUIRE(key
!= NULL
);
191 REQUIRE(inception
!= NULL
);
192 REQUIRE(expire
!= NULL
);
193 REQUIRE(mctx
!= NULL
);
194 REQUIRE(sigrdata
!= NULL
);
196 if (*inception
>= *expire
)
197 return (DNS_R_INVALIDTIME
);
200 * Is the key allowed to sign data?
202 flags
= dst_key_flags(key
);
203 if (flags
& DNS_KEYTYPE_NOAUTH
)
204 return (DNS_R_KEYUNAUTHORIZED
);
205 if ((flags
& DNS_KEYFLAG_OWNERMASK
) != DNS_KEYOWNER_ZONE
)
206 return (DNS_R_KEYUNAUTHORIZED
);
209 sig
.common
.rdclass
= set
->rdclass
;
210 sig
.common
.rdtype
= dns_rdatatype_rrsig
;
211 ISC_LINK_INIT(&sig
.common
, link
);
213 dns_name_init(&sig
.signer
, NULL
);
214 dns_name_clone(dst_key_name(key
), &sig
.signer
);
216 sig
.covered
= set
->type
;
217 sig
.algorithm
= dst_key_alg(key
);
218 sig
.labels
= dns_name_countlabels(name
) - 1;
219 if (dns_name_iswildcard(name
))
221 sig
.originalttl
= set
->ttl
;
222 sig
.timesigned
= *inception
;
223 sig
.timeexpire
= *expire
;
224 sig
.keyid
= dst_key_id(key
);
225 ret
= dst_key_sigsize(key
, &sigsize
);
226 if (ret
!= ISC_R_SUCCESS
)
228 sig
.siglen
= sigsize
;
230 * The actual contents of sig.signature are not important yet, since
231 * they're not used in digest_sig().
233 sig
.signature
= isc_mem_get(mctx
, sig
.siglen
);
234 if (sig
.signature
== NULL
)
235 return (ISC_R_NOMEMORY
);
237 ret
= isc_buffer_allocate(mctx
, &databuf
, sigsize
+ 256 + 18);
238 if (ret
!= ISC_R_SUCCESS
)
239 goto cleanup_signature
;
241 dns_rdata_init(&tmpsigrdata
);
242 ret
= dns_rdata_fromstruct(&tmpsigrdata
, sig
.common
.rdclass
,
243 sig
.common
.rdtype
, &sig
, databuf
);
244 if (ret
!= ISC_R_SUCCESS
)
245 goto cleanup_databuf
;
247 ret
= dst_context_create(key
, mctx
, &ctx
);
248 if (ret
!= ISC_R_SUCCESS
)
249 goto cleanup_databuf
;
252 * Digest the SIG rdata.
254 ret
= digest_sig(ctx
, &tmpsigrdata
, &sig
);
255 if (ret
!= ISC_R_SUCCESS
)
256 goto cleanup_context
;
258 dns_fixedname_init(&fnewname
);
259 RUNTIME_CHECK(dns_name_downcase(name
, dns_fixedname_name(&fnewname
),
260 NULL
) == ISC_R_SUCCESS
);
261 dns_name_toregion(dns_fixedname_name(&fnewname
), &r
);
264 * Create an envelope for each rdata: <name|type|class|ttl>.
266 isc_buffer_init(&envbuf
, data
, sizeof(data
));
267 memcpy(data
, r
.base
, r
.length
);
268 isc_buffer_add(&envbuf
, r
.length
);
269 isc_buffer_putuint16(&envbuf
, set
->type
);
270 isc_buffer_putuint16(&envbuf
, set
->rdclass
);
271 isc_buffer_putuint32(&envbuf
, set
->ttl
);
273 ret
= rdataset_to_sortedarray(set
, mctx
, &rdatas
, &nrdatas
);
274 if (ret
!= ISC_R_SUCCESS
)
275 goto cleanup_context
;
276 isc_buffer_usedregion(&envbuf
, &r
);
278 for (i
= 0; i
< nrdatas
; i
++) {
286 if (i
> 0 && dns_rdata_compare(&rdatas
[i
], &rdatas
[i
-1]) == 0)
290 * Digest the envelope.
292 ret
= dst_context_adddata(ctx
, &r
);
293 if (ret
!= ISC_R_SUCCESS
)
297 * Digest the length of the rdata.
299 isc_buffer_init(&lenbuf
, &len
, sizeof(len
));
300 INSIST(rdatas
[i
].length
< 65536);
301 isc_buffer_putuint16(&lenbuf
, (isc_uint16_t
)rdatas
[i
].length
);
302 isc_buffer_usedregion(&lenbuf
, &lenr
);
303 ret
= dst_context_adddata(ctx
, &lenr
);
304 if (ret
!= ISC_R_SUCCESS
)
310 ret
= dns_rdata_digest(&rdatas
[i
], digest_callback
, ctx
);
311 if (ret
!= ISC_R_SUCCESS
)
315 isc_buffer_init(&sigbuf
, sig
.signature
, sig
.siglen
);
316 ret
= dst_context_sign(ctx
, &sigbuf
);
317 if (ret
!= ISC_R_SUCCESS
)
319 isc_buffer_usedregion(&sigbuf
, &r
);
320 if (r
.length
!= sig
.siglen
) {
324 memcpy(sig
.signature
, r
.base
, sig
.siglen
);
326 ret
= dns_rdata_fromstruct(sigrdata
, sig
.common
.rdclass
,
327 sig
.common
.rdtype
, &sig
, buffer
);
330 isc_mem_put(mctx
, rdatas
, nrdatas
* sizeof(dns_rdata_t
));
332 dst_context_destroy(&ctx
);
334 isc_buffer_free(&databuf
);
336 isc_mem_put(mctx
, sig
.signature
, sig
.siglen
);
342 dns_dnssec_verify2(dns_name_t
*name
, dns_rdataset_t
*set
, dst_key_t
*key
,
343 isc_boolean_t ignoretime
, isc_mem_t
*mctx
,
344 dns_rdata_t
*sigrdata
, dns_name_t
*wild
)
346 dns_rdata_rrsig_t sig
;
347 dns_fixedname_t fnewname
;
354 unsigned char data
[300];
355 dst_context_t
*ctx
= NULL
;
359 REQUIRE(name
!= NULL
);
360 REQUIRE(set
!= NULL
);
361 REQUIRE(key
!= NULL
);
362 REQUIRE(mctx
!= NULL
);
363 REQUIRE(sigrdata
!= NULL
&& sigrdata
->type
== dns_rdatatype_rrsig
);
365 ret
= dns_rdata_tostruct(sigrdata
, &sig
, NULL
);
366 if (ret
!= ISC_R_SUCCESS
)
369 if (set
->type
!= sig
.covered
)
370 return (DNS_R_SIGINVALID
);
372 if (isc_serial_lt(sig
.timeexpire
, sig
.timesigned
))
373 return (DNS_R_SIGINVALID
);
376 isc_stdtime_get(&now
);
379 * Is SIG temporally valid?
381 if (isc_serial_lt((isc_uint32_t
)now
, sig
.timesigned
))
382 return (DNS_R_SIGFUTURE
);
383 else if (isc_serial_lt(sig
.timeexpire
, (isc_uint32_t
)now
))
384 return (DNS_R_SIGEXPIRED
);
388 * NS, SOA and DNSSKEY records are signed by their owner.
389 * DS records are signed by the parent.
392 case dns_rdatatype_ns
:
393 case dns_rdatatype_soa
:
394 case dns_rdatatype_dnskey
:
395 if (!dns_name_equal(name
, &sig
.signer
))
396 return (DNS_R_SIGINVALID
);
398 case dns_rdatatype_ds
:
399 if (dns_name_equal(name
, &sig
.signer
))
400 return (DNS_R_SIGINVALID
);
403 if (!dns_name_issubdomain(name
, &sig
.signer
))
404 return (DNS_R_SIGINVALID
);
409 * Is the key allowed to sign data?
411 flags
= dst_key_flags(key
);
412 if (flags
& DNS_KEYTYPE_NOAUTH
)
413 return (DNS_R_KEYUNAUTHORIZED
);
414 if ((flags
& DNS_KEYFLAG_OWNERMASK
) != DNS_KEYOWNER_ZONE
)
415 return (DNS_R_KEYUNAUTHORIZED
);
417 ret
= dst_context_create(key
, mctx
, &ctx
);
418 if (ret
!= ISC_R_SUCCESS
)
422 * Digest the SIG rdata (not including the signature).
424 ret
= digest_sig(ctx
, sigrdata
, &sig
);
425 if (ret
!= ISC_R_SUCCESS
)
426 goto cleanup_context
;
429 * If the name is an expanded wildcard, use the wildcard name.
431 dns_fixedname_init(&fnewname
);
432 labels
= dns_name_countlabels(name
) - 1;
433 RUNTIME_CHECK(dns_name_downcase(name
, dns_fixedname_name(&fnewname
),
434 NULL
) == ISC_R_SUCCESS
);
435 if (labels
- sig
.labels
> 0)
436 dns_name_split(dns_fixedname_name(&fnewname
), sig
.labels
+ 1,
437 NULL
, dns_fixedname_name(&fnewname
));
439 dns_name_toregion(dns_fixedname_name(&fnewname
), &r
);
442 * Create an envelope for each rdata: <name|type|class|ttl>.
444 isc_buffer_init(&envbuf
, data
, sizeof(data
));
445 if (labels
- sig
.labels
> 0) {
446 isc_buffer_putuint8(&envbuf
, 1);
447 isc_buffer_putuint8(&envbuf
, '*');
448 memcpy(data
+ 2, r
.base
, r
.length
);
451 memcpy(data
, r
.base
, r
.length
);
452 isc_buffer_add(&envbuf
, r
.length
);
453 isc_buffer_putuint16(&envbuf
, set
->type
);
454 isc_buffer_putuint16(&envbuf
, set
->rdclass
);
455 isc_buffer_putuint32(&envbuf
, sig
.originalttl
);
457 ret
= rdataset_to_sortedarray(set
, mctx
, &rdatas
, &nrdatas
);
458 if (ret
!= ISC_R_SUCCESS
)
459 goto cleanup_context
;
461 isc_buffer_usedregion(&envbuf
, &r
);
463 for (i
= 0; i
< nrdatas
; i
++) {
471 if (i
> 0 && dns_rdata_compare(&rdatas
[i
], &rdatas
[i
-1]) == 0)
475 * Digest the envelope.
477 ret
= dst_context_adddata(ctx
, &r
);
478 if (ret
!= ISC_R_SUCCESS
)
482 * Digest the rdata length.
484 isc_buffer_init(&lenbuf
, &len
, sizeof(len
));
485 INSIST(rdatas
[i
].length
< 65536);
486 isc_buffer_putuint16(&lenbuf
, (isc_uint16_t
)rdatas
[i
].length
);
487 isc_buffer_usedregion(&lenbuf
, &lenr
);
492 ret
= dst_context_adddata(ctx
, &lenr
);
493 if (ret
!= ISC_R_SUCCESS
)
495 ret
= dns_rdata_digest(&rdatas
[i
], digest_callback
, ctx
);
496 if (ret
!= ISC_R_SUCCESS
)
500 r
.base
= sig
.signature
;
501 r
.length
= sig
.siglen
;
502 ret
= dst_context_verify(ctx
, &r
);
503 if (ret
== DST_R_VERIFYFAILURE
)
504 ret
= DNS_R_SIGINVALID
;
507 isc_mem_put(mctx
, rdatas
, nrdatas
* sizeof(dns_rdata_t
));
509 dst_context_destroy(&ctx
);
511 dns_rdata_freestruct(&sig
);
513 if (ret
== ISC_R_SUCCESS
&& labels
- sig
.labels
> 0) {
515 RUNTIME_CHECK(dns_name_concatenate(dns_wildcardname
,
516 dns_fixedname_name(&fnewname
),
517 wild
, NULL
) == ISC_R_SUCCESS
);
518 ret
= DNS_R_FROMWILDCARD
;
524 dns_dnssec_verify(dns_name_t
*name
, dns_rdataset_t
*set
, dst_key_t
*key
,
525 isc_boolean_t ignoretime
, isc_mem_t
*mctx
,
526 dns_rdata_t
*sigrdata
)
530 result
= dns_dnssec_verify2(name
, set
, key
, ignoretime
, mctx
,
532 if (result
== DNS_R_FROMWILDCARD
)
533 result
= ISC_R_SUCCESS
;
537 #define is_zone_key(key) ((dst_key_flags(key) & DNS_KEYFLAG_OWNERMASK) \
538 == DNS_KEYOWNER_ZONE)
541 dns_dnssec_findzonekeys2(dns_db_t
*db
, dns_dbversion_t
*ver
,
542 dns_dbnode_t
*node
, dns_name_t
*name
,
543 const char *directory
, isc_mem_t
*mctx
,
544 unsigned int maxkeys
, dst_key_t
**keys
,
547 dns_rdataset_t rdataset
;
548 dns_rdata_t rdata
= DNS_RDATA_INIT
;
550 dst_key_t
*pubkey
= NULL
;
551 unsigned int count
= 0;
553 REQUIRE(nkeys
!= NULL
);
554 REQUIRE(keys
!= NULL
);
557 dns_rdataset_init(&rdataset
);
558 RETERR(dns_db_findrdataset(db
, node
, ver
, dns_rdatatype_dnskey
, 0, 0,
560 RETERR(dns_rdataset_first(&rdataset
));
561 while (result
== ISC_R_SUCCESS
&& count
< maxkeys
) {
563 dns_rdataset_current(&rdataset
, &rdata
);
564 RETERR(dns_dnssec_keyfromrdata(name
, &rdata
, mctx
, &pubkey
));
565 if (!is_zone_key(pubkey
) ||
566 (dst_key_flags(pubkey
) & DNS_KEYTYPE_NOAUTH
) != 0)
568 /* Corrupted .key file? */
569 if (!dns_name_equal(name
, dst_key_name(pubkey
)))
572 result
= dst_key_fromfile(dst_key_name(pubkey
),
575 DST_TYPE_PUBLIC
|DST_TYPE_PRIVATE
,
578 if (result
== ISC_R_FILENOTFOUND
) {
579 keys
[count
] = pubkey
;
584 if (result
!= ISC_R_SUCCESS
)
586 if ((dst_key_flags(keys
[count
]) & DNS_KEYTYPE_NOAUTH
) != 0) {
587 /* We should never get here. */
588 dst_key_free(&keys
[count
]);
594 dst_key_free(&pubkey
);
595 dns_rdata_reset(&rdata
);
596 result
= dns_rdataset_next(&rdataset
);
598 if (result
!= ISC_R_NOMORE
)
601 result
= ISC_R_NOTFOUND
;
603 result
= ISC_R_SUCCESS
;
606 if (dns_rdataset_isassociated(&rdataset
))
607 dns_rdataset_disassociate(&rdataset
);
609 dst_key_free(&pubkey
);
610 if (result
!= ISC_R_SUCCESS
)
612 dst_key_free(&keys
[--count
]);
618 dns_dnssec_findzonekeys(dns_db_t
*db
, dns_dbversion_t
*ver
,
619 dns_dbnode_t
*node
, dns_name_t
*name
, isc_mem_t
*mctx
,
620 unsigned int maxkeys
, dst_key_t
**keys
,
623 return (dns_dnssec_findzonekeys2(db
, ver
, node
, name
, NULL
, mctx
,
624 maxkeys
, keys
, nkeys
));
628 dns_dnssec_signmessage(dns_message_t
*msg
, dst_key_t
*key
) {
629 dns_rdata_sig_t sig
; /* SIG(0) */
630 unsigned char data
[512];
631 unsigned char header
[DNS_MESSAGE_HEADERLEN
];
632 isc_buffer_t headerbuf
, databuf
, sigbuf
;
633 unsigned int sigsize
;
634 isc_buffer_t
*dynbuf
= NULL
;
636 dns_rdatalist_t
*datalist
;
637 dns_rdataset_t
*dataset
;
640 dst_context_t
*ctx
= NULL
;
643 isc_boolean_t signeedsfree
= ISC_TRUE
;
645 REQUIRE(msg
!= NULL
);
646 REQUIRE(key
!= NULL
);
648 if (is_response(msg
))
649 REQUIRE(msg
->query
.base
!= NULL
);
653 memset(&sig
, 0, sizeof(sig
));
656 sig
.common
.rdclass
= dns_rdataclass_any
;
657 sig
.common
.rdtype
= dns_rdatatype_sig
; /* SIG(0) */
658 ISC_LINK_INIT(&sig
.common
, link
);
661 sig
.algorithm
= dst_key_alg(key
);
662 sig
.labels
= 0; /* the root name */
665 isc_stdtime_get(&now
);
666 sig
.timesigned
= now
- DNS_TSIG_FUDGE
;
667 sig
.timeexpire
= now
+ DNS_TSIG_FUDGE
;
669 sig
.keyid
= dst_key_id(key
);
671 dns_name_init(&sig
.signer
, NULL
);
672 dns_name_clone(dst_key_name(key
), &sig
.signer
);
675 sig
.signature
= NULL
;
677 isc_buffer_init(&databuf
, data
, sizeof(data
));
679 RETERR(dst_context_create(key
, mctx
, &ctx
));
682 * Digest the fields of the SIG - we can cheat and use
683 * dns_rdata_fromstruct. Since siglen is 0, the digested data
684 * is identical to dns format.
686 RETERR(dns_rdata_fromstruct(NULL
, dns_rdataclass_any
,
687 dns_rdatatype_sig
/* SIG(0) */,
689 isc_buffer_usedregion(&databuf
, &r
);
690 RETERR(dst_context_adddata(ctx
, &r
));
693 * If this is a response, digest the query.
695 if (is_response(msg
))
696 RETERR(dst_context_adddata(ctx
, &msg
->query
));
701 isc_buffer_init(&headerbuf
, header
, sizeof(header
));
702 dns_message_renderheader(msg
, &headerbuf
);
703 isc_buffer_usedregion(&headerbuf
, &r
);
704 RETERR(dst_context_adddata(ctx
, &r
));
707 * Digest the remainder of the message.
709 isc_buffer_usedregion(msg
->buffer
, &r
);
710 isc_region_consume(&r
, DNS_MESSAGE_HEADERLEN
);
711 RETERR(dst_context_adddata(ctx
, &r
));
713 RETERR(dst_key_sigsize(key
, &sigsize
));
714 sig
.siglen
= sigsize
;
715 sig
.signature
= (unsigned char *) isc_mem_get(mctx
, sig
.siglen
);
716 if (sig
.signature
== NULL
) {
717 result
= ISC_R_NOMEMORY
;
721 isc_buffer_init(&sigbuf
, sig
.signature
, sig
.siglen
);
722 RETERR(dst_context_sign(ctx
, &sigbuf
));
723 dst_context_destroy(&ctx
);
726 RETERR(dns_message_gettemprdata(msg
, &rdata
));
727 RETERR(isc_buffer_allocate(msg
->mctx
, &dynbuf
, 1024));
728 RETERR(dns_rdata_fromstruct(rdata
, dns_rdataclass_any
,
729 dns_rdatatype_sig
/* SIG(0) */,
732 isc_mem_put(mctx
, sig
.signature
, sig
.siglen
);
733 signeedsfree
= ISC_FALSE
;
735 dns_message_takebuffer(msg
, &dynbuf
);
738 RETERR(dns_message_gettemprdatalist(msg
, &datalist
));
739 datalist
->rdclass
= dns_rdataclass_any
;
740 datalist
->type
= dns_rdatatype_sig
; /* SIG(0) */
741 datalist
->covers
= 0;
743 ISC_LIST_INIT(datalist
->rdata
);
744 ISC_LIST_APPEND(datalist
->rdata
, rdata
, link
);
746 RETERR(dns_message_gettemprdataset(msg
, &dataset
));
747 dns_rdataset_init(dataset
);
748 RUNTIME_CHECK(dns_rdatalist_tordataset(datalist
, dataset
) == ISC_R_SUCCESS
);
751 return (ISC_R_SUCCESS
);
755 isc_buffer_free(&dynbuf
);
757 isc_mem_put(mctx
, sig
.signature
, sig
.siglen
);
759 dst_context_destroy(&ctx
);
765 dns_dnssec_verifymessage(isc_buffer_t
*source
, dns_message_t
*msg
,
768 dns_rdata_sig_t sig
; /* SIG(0) */
769 unsigned char header
[DNS_MESSAGE_HEADERLEN
];
770 dns_rdata_t rdata
= DNS_RDATA_INIT
;
771 isc_region_t r
, source_r
, sig_r
, header_r
;
773 dst_context_t
*ctx
= NULL
;
776 isc_uint16_t addcount
;
777 isc_boolean_t signeedsfree
= ISC_FALSE
;
779 REQUIRE(source
!= NULL
);
780 REQUIRE(msg
!= NULL
);
781 REQUIRE(key
!= NULL
);
785 msg
->verify_attempted
= 1;
787 if (is_response(msg
)) {
788 if (msg
->query
.base
== NULL
)
789 return (DNS_R_UNEXPECTEDTSIG
);
792 isc_buffer_usedregion(source
, &source_r
);
794 RETERR(dns_rdataset_first(msg
->sig0
));
795 dns_rdataset_current(msg
->sig0
, &rdata
);
797 RETERR(dns_rdata_tostruct(&rdata
, &sig
, NULL
));
798 signeedsfree
= ISC_TRUE
;
800 if (sig
.labels
!= 0) {
801 result
= DNS_R_SIGINVALID
;
805 if (isc_serial_lt(sig
.timeexpire
, sig
.timesigned
)) {
806 result
= DNS_R_SIGINVALID
;
807 msg
->sig0status
= dns_tsigerror_badtime
;
811 isc_stdtime_get(&now
);
812 if (isc_serial_lt((isc_uint32_t
)now
, sig
.timesigned
)) {
813 result
= DNS_R_SIGFUTURE
;
814 msg
->sig0status
= dns_tsigerror_badtime
;
817 else if (isc_serial_lt(sig
.timeexpire
, (isc_uint32_t
)now
)) {
818 result
= DNS_R_SIGEXPIRED
;
819 msg
->sig0status
= dns_tsigerror_badtime
;
823 if (!dns_name_equal(dst_key_name(key
), &sig
.signer
)) {
824 result
= DNS_R_SIGINVALID
;
825 msg
->sig0status
= dns_tsigerror_badkey
;
829 RETERR(dst_context_create(key
, mctx
, &ctx
));
832 * Digest the SIG(0) record, except for the signature.
834 dns_rdata_toregion(&rdata
, &r
);
835 r
.length
-= sig
.siglen
;
836 RETERR(dst_context_adddata(ctx
, &r
));
839 * If this is a response, digest the query.
841 if (is_response(msg
))
842 RETERR(dst_context_adddata(ctx
, &msg
->query
));
845 * Extract the header.
847 memcpy(header
, source_r
.base
, DNS_MESSAGE_HEADERLEN
);
850 * Decrement the additional field counter.
852 memcpy(&addcount
, &header
[DNS_MESSAGE_HEADERLEN
- 2], 2);
853 addcount
= htons((isc_uint16_t
)(ntohs(addcount
) - 1));
854 memcpy(&header
[DNS_MESSAGE_HEADERLEN
- 2], &addcount
, 2);
857 * Digest the modified header.
859 header_r
.base
= (unsigned char *) header
;
860 header_r
.length
= DNS_MESSAGE_HEADERLEN
;
861 RETERR(dst_context_adddata(ctx
, &header_r
));
864 * Digest all non-SIG(0) records.
866 r
.base
= source_r
.base
+ DNS_MESSAGE_HEADERLEN
;
867 r
.length
= msg
->sigstart
- DNS_MESSAGE_HEADERLEN
;
868 RETERR(dst_context_adddata(ctx
, &r
));
870 sig_r
.base
= sig
.signature
;
871 sig_r
.length
= sig
.siglen
;
872 result
= dst_context_verify(ctx
, &sig_r
);
873 if (result
!= ISC_R_SUCCESS
) {
874 msg
->sig0status
= dns_tsigerror_badsig
;
878 msg
->verified_sig
= 1;
880 dst_context_destroy(&ctx
);
881 dns_rdata_freestruct(&sig
);
883 return (ISC_R_SUCCESS
);
887 dns_rdata_freestruct(&sig
);
889 dst_context_destroy(&ctx
);