2 * Copyright (C) 2004-2012 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.
28 #include <isc/buffer.h>
31 #include <isc/serial.h>
32 #include <isc/string.h>
37 #include <dns/dnssec.h>
38 #include <dns/fixedname.h>
39 #include <dns/keyvalues.h>
41 #include <dns/message.h>
42 #include <dns/rdata.h>
43 #include <dns/rdatalist.h>
44 #include <dns/rdataset.h>
45 #include <dns/rdatastruct.h>
46 #include <dns/result.h>
47 #include <dns/tsig.h> /* for DNS_TSIG_FUDGE */
49 #include <dst/result.h>
51 #define is_response(msg) (msg->flags & DNS_MESSAGEFLAG_QR)
53 #define RETERR(x) do { \
55 if (result != ISC_R_SUCCESS) \
64 digest_callback(void *arg, isc_region_t *data);
67 rdata_compare_wrapper(const void *rdata1, const void *rdata2);
70 rdataset_to_sortedarray(dns_rdataset_t *set, isc_mem_t *mctx,
71 dns_rdata_t **rdata, int *nrdata);
74 digest_callback(void *arg, isc_region_t *data) {
75 dst_context_t *ctx = arg;
77 return (dst_context_adddata(ctx, data));
84 rdata_compare_wrapper(const void *rdata1, const void *rdata2) {
85 return (dns_rdata_compare((const dns_rdata_t *)rdata1,
86 (const dns_rdata_t *)rdata2));
90 * Sort the rdataset into an array.
93 rdataset_to_sortedarray(dns_rdataset_t *set, isc_mem_t *mctx,
94 dns_rdata_t **rdata, int *nrdata)
99 dns_rdataset_t rdataset;
101 n = dns_rdataset_count(set);
103 data = isc_mem_get(mctx, n * sizeof(dns_rdata_t));
105 return (ISC_R_NOMEMORY);
107 dns_rdataset_init(&rdataset);
108 dns_rdataset_clone(set, &rdataset);
109 ret = dns_rdataset_first(&rdataset);
110 if (ret != ISC_R_SUCCESS) {
111 dns_rdataset_disassociate(&rdataset);
112 isc_mem_put(mctx, data, n * sizeof(dns_rdata_t));
117 * Put them in the array.
120 dns_rdata_init(&data[i]);
121 dns_rdataset_current(&rdataset, &data[i++]);
122 } while (dns_rdataset_next(&rdataset) == ISC_R_SUCCESS);
127 qsort(data, n, sizeof(dns_rdata_t), rdata_compare_wrapper);
130 dns_rdataset_disassociate(&rdataset);
131 return (ISC_R_SUCCESS);
135 dns_dnssec_keyfromrdata(dns_name_t *name, dns_rdata_t *rdata, isc_mem_t *mctx,
141 INSIST(name != NULL);
142 INSIST(rdata != NULL);
143 INSIST(mctx != NULL);
145 INSIST(*key == NULL);
146 REQUIRE(rdata->type == dns_rdatatype_key ||
147 rdata->type == dns_rdatatype_dnskey);
149 dns_rdata_toregion(rdata, &r);
150 isc_buffer_init(&b, r.base, r.length);
151 isc_buffer_add(&b, r.length);
152 return (dst_key_fromdns(name, rdata->rdclass, &b, mctx, key));
156 digest_sig(dst_context_t *ctx, dns_rdata_t *sigrdata, dns_rdata_rrsig_t *sig) {
159 dns_fixedname_t fname;
161 dns_rdata_toregion(sigrdata, &r);
162 INSIST(r.length >= 19);
165 ret = dst_context_adddata(ctx, &r);
166 if (ret != ISC_R_SUCCESS)
168 dns_fixedname_init(&fname);
169 RUNTIME_CHECK(dns_name_downcase(&sig->signer,
170 dns_fixedname_name(&fname), NULL)
172 dns_name_toregion(dns_fixedname_name(&fname), &r);
173 return (dst_context_adddata(ctx, &r));
177 dns_dnssec_sign(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
178 isc_stdtime_t *inception, isc_stdtime_t *expire,
179 isc_mem_t *mctx, isc_buffer_t *buffer, dns_rdata_t *sigrdata)
181 dns_rdata_rrsig_t sig;
182 dns_rdata_t tmpsigrdata;
185 isc_buffer_t sigbuf, envbuf;
187 dst_context_t *ctx = NULL;
189 isc_buffer_t *databuf = NULL;
192 unsigned int sigsize;
193 dns_fixedname_t fnewname;
195 REQUIRE(name != NULL);
196 REQUIRE(dns_name_countlabels(name) <= 255);
197 REQUIRE(set != NULL);
198 REQUIRE(key != NULL);
199 REQUIRE(inception != NULL);
200 REQUIRE(expire != NULL);
201 REQUIRE(mctx != NULL);
202 REQUIRE(sigrdata != NULL);
204 if (*inception >= *expire)
205 return (DNS_R_INVALIDTIME);
208 * Is the key allowed to sign data?
210 flags = dst_key_flags(key);
211 if (flags & DNS_KEYTYPE_NOAUTH)
212 return (DNS_R_KEYUNAUTHORIZED);
213 if ((flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE)
214 return (DNS_R_KEYUNAUTHORIZED);
217 sig.common.rdclass = set->rdclass;
218 sig.common.rdtype = dns_rdatatype_rrsig;
219 ISC_LINK_INIT(&sig.common, link);
221 dns_name_init(&sig.signer, NULL);
222 dns_name_clone(dst_key_name(key), &sig.signer);
224 sig.covered = set->type;
225 sig.algorithm = dst_key_alg(key);
226 sig.labels = dns_name_countlabels(name) - 1;
227 if (dns_name_iswildcard(name))
229 sig.originalttl = set->ttl;
230 sig.timesigned = *inception;
231 sig.timeexpire = *expire;
232 sig.keyid = dst_key_id(key);
233 ret = dst_key_sigsize(key, &sigsize);
234 if (ret != ISC_R_SUCCESS)
236 sig.siglen = sigsize;
238 * The actual contents of sig.signature are not important yet, since
239 * they're not used in digest_sig().
241 sig.signature = isc_mem_get(mctx, sig.siglen);
242 if (sig.signature == NULL)
243 return (ISC_R_NOMEMORY);
245 ret = isc_buffer_allocate(mctx, &databuf, sigsize + 256 + 18);
246 if (ret != ISC_R_SUCCESS)
247 goto cleanup_signature;
249 dns_rdata_init(&tmpsigrdata);
250 ret = dns_rdata_fromstruct(&tmpsigrdata, sig.common.rdclass,
251 sig.common.rdtype, &sig, databuf);
252 if (ret != ISC_R_SUCCESS)
253 goto cleanup_databuf;
255 ret = dst_context_create(key, mctx, &ctx);
256 if (ret != ISC_R_SUCCESS)
257 goto cleanup_databuf;
260 * Digest the SIG rdata.
262 ret = digest_sig(ctx, &tmpsigrdata, &sig);
263 if (ret != ISC_R_SUCCESS)
264 goto cleanup_context;
266 dns_fixedname_init(&fnewname);
267 RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname),
268 NULL) == ISC_R_SUCCESS);
269 dns_name_toregion(dns_fixedname_name(&fnewname), &r);
272 * Create an envelope for each rdata: <name|type|class|ttl>.
274 isc_buffer_init(&envbuf, data, sizeof(data));
275 memcpy(data, r.base, r.length);
276 isc_buffer_add(&envbuf, r.length);
277 isc_buffer_putuint16(&envbuf, set->type);
278 isc_buffer_putuint16(&envbuf, set->rdclass);
279 isc_buffer_putuint32(&envbuf, set->ttl);
281 ret = rdataset_to_sortedarray(set, mctx, &rdatas, &nrdatas);
282 if (ret != ISC_R_SUCCESS)
283 goto cleanup_context;
284 isc_buffer_usedregion(&envbuf, &r);
286 for (i = 0; i < nrdatas; i++) {
294 if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i-1]) == 0)
298 * Digest the envelope.
300 ret = dst_context_adddata(ctx, &r);
301 if (ret != ISC_R_SUCCESS)
305 * Digest the length of the rdata.
307 isc_buffer_init(&lenbuf, &len, sizeof(len));
308 INSIST(rdatas[i].length < 65536);
309 isc_buffer_putuint16(&lenbuf, (isc_uint16_t)rdatas[i].length);
310 isc_buffer_usedregion(&lenbuf, &lenr);
311 ret = dst_context_adddata(ctx, &lenr);
312 if (ret != ISC_R_SUCCESS)
318 ret = dns_rdata_digest(&rdatas[i], digest_callback, ctx);
319 if (ret != ISC_R_SUCCESS)
323 isc_buffer_init(&sigbuf, sig.signature, sig.siglen);
324 ret = dst_context_sign(ctx, &sigbuf);
325 if (ret != ISC_R_SUCCESS)
327 isc_buffer_usedregion(&sigbuf, &r);
328 if (r.length != sig.siglen) {
332 memcpy(sig.signature, r.base, sig.siglen);
334 ret = dns_rdata_fromstruct(sigrdata, sig.common.rdclass,
335 sig.common.rdtype, &sig, buffer);
338 isc_mem_put(mctx, rdatas, nrdatas * sizeof(dns_rdata_t));
340 dst_context_destroy(&ctx);
342 isc_buffer_free(&databuf);
344 isc_mem_put(mctx, sig.signature, sig.siglen);
350 dns_dnssec_verify2(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
351 isc_boolean_t ignoretime, isc_mem_t *mctx,
352 dns_rdata_t *sigrdata, dns_name_t *wild)
354 dns_rdata_rrsig_t sig;
355 dns_fixedname_t fnewname;
362 unsigned char data[300];
363 dst_context_t *ctx = NULL;
367 REQUIRE(name != NULL);
368 REQUIRE(set != NULL);
369 REQUIRE(key != NULL);
370 REQUIRE(mctx != NULL);
371 REQUIRE(sigrdata != NULL && sigrdata->type == dns_rdatatype_rrsig);
373 ret = dns_rdata_tostruct(sigrdata, &sig, NULL);
374 if (ret != ISC_R_SUCCESS)
377 if (set->type != sig.covered)
378 return (DNS_R_SIGINVALID);
380 if (isc_serial_lt(sig.timeexpire, sig.timesigned))
381 return (DNS_R_SIGINVALID);
384 isc_stdtime_get(&now);
387 * Is SIG temporally valid?
389 if (isc_serial_lt((isc_uint32_t)now, sig.timesigned))
390 return (DNS_R_SIGFUTURE);
391 else if (isc_serial_lt(sig.timeexpire, (isc_uint32_t)now))
392 return (DNS_R_SIGEXPIRED);
396 * NS, SOA and DNSSKEY records are signed by their owner.
397 * DS records are signed by the parent.
400 case dns_rdatatype_ns:
401 case dns_rdatatype_soa:
402 case dns_rdatatype_dnskey:
403 if (!dns_name_equal(name, &sig.signer))
404 return (DNS_R_SIGINVALID);
406 case dns_rdatatype_ds:
407 if (dns_name_equal(name, &sig.signer))
408 return (DNS_R_SIGINVALID);
411 if (!dns_name_issubdomain(name, &sig.signer))
412 return (DNS_R_SIGINVALID);
417 * Is the key allowed to sign data?
419 flags = dst_key_flags(key);
420 if (flags & DNS_KEYTYPE_NOAUTH)
421 return (DNS_R_KEYUNAUTHORIZED);
422 if ((flags & DNS_KEYFLAG_OWNERMASK) != DNS_KEYOWNER_ZONE)
423 return (DNS_R_KEYUNAUTHORIZED);
425 ret = dst_context_create(key, mctx, &ctx);
426 if (ret != ISC_R_SUCCESS)
430 * Digest the SIG rdata (not including the signature).
432 ret = digest_sig(ctx, sigrdata, &sig);
433 if (ret != ISC_R_SUCCESS)
434 goto cleanup_context;
437 * If the name is an expanded wildcard, use the wildcard name.
439 dns_fixedname_init(&fnewname);
440 labels = dns_name_countlabels(name) - 1;
441 RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname),
442 NULL) == ISC_R_SUCCESS);
443 if (labels - sig.labels > 0)
444 dns_name_split(dns_fixedname_name(&fnewname), sig.labels + 1,
445 NULL, dns_fixedname_name(&fnewname));
447 dns_name_toregion(dns_fixedname_name(&fnewname), &r);
450 * Create an envelope for each rdata: <name|type|class|ttl>.
452 isc_buffer_init(&envbuf, data, sizeof(data));
453 if (labels - sig.labels > 0) {
454 isc_buffer_putuint8(&envbuf, 1);
455 isc_buffer_putuint8(&envbuf, '*');
456 memcpy(data + 2, r.base, r.length);
459 memcpy(data, r.base, r.length);
460 isc_buffer_add(&envbuf, r.length);
461 isc_buffer_putuint16(&envbuf, set->type);
462 isc_buffer_putuint16(&envbuf, set->rdclass);
463 isc_buffer_putuint32(&envbuf, sig.originalttl);
465 ret = rdataset_to_sortedarray(set, mctx, &rdatas, &nrdatas);
466 if (ret != ISC_R_SUCCESS)
467 goto cleanup_context;
469 isc_buffer_usedregion(&envbuf, &r);
471 for (i = 0; i < nrdatas; i++) {
479 if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i-1]) == 0)
483 * Digest the envelope.
485 ret = dst_context_adddata(ctx, &r);
486 if (ret != ISC_R_SUCCESS)
490 * Digest the rdata length.
492 isc_buffer_init(&lenbuf, &len, sizeof(len));
493 INSIST(rdatas[i].length < 65536);
494 isc_buffer_putuint16(&lenbuf, (isc_uint16_t)rdatas[i].length);
495 isc_buffer_usedregion(&lenbuf, &lenr);
500 ret = dst_context_adddata(ctx, &lenr);
501 if (ret != ISC_R_SUCCESS)
503 ret = dns_rdata_digest(&rdatas[i], digest_callback, ctx);
504 if (ret != ISC_R_SUCCESS)
508 r.base = sig.signature;
509 r.length = sig.siglen;
510 ret = dst_context_verify(ctx, &r);
511 if (ret == DST_R_VERIFYFAILURE)
512 ret = DNS_R_SIGINVALID;
515 isc_mem_put(mctx, rdatas, nrdatas * sizeof(dns_rdata_t));
517 dst_context_destroy(&ctx);
519 dns_rdata_freestruct(&sig);
521 if (ret == ISC_R_SUCCESS && labels - sig.labels > 0) {
523 RUNTIME_CHECK(dns_name_concatenate(dns_wildcardname,
524 dns_fixedname_name(&fnewname),
525 wild, NULL) == ISC_R_SUCCESS);
526 ret = DNS_R_FROMWILDCARD;
532 dns_dnssec_verify(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
533 isc_boolean_t ignoretime, isc_mem_t *mctx,
534 dns_rdata_t *sigrdata)
538 result = dns_dnssec_verify2(name, set, key, ignoretime, mctx,
540 if (result == DNS_R_FROMWILDCARD)
541 result = ISC_R_SUCCESS;
546 key_active(dst_key_t *key, isc_stdtime_t now) {
548 isc_stdtime_t publish, active, revoke, inactive, delete;
549 isc_boolean_t pubset = ISC_FALSE, actset = ISC_FALSE;
550 isc_boolean_t revset = ISC_FALSE, inactset = ISC_FALSE;
551 isc_boolean_t delset = ISC_FALSE;
554 /* Is this an old-style key? */
555 result = dst_key_getprivateformat(key, &major, &minor);
556 RUNTIME_CHECK(result == ISC_R_SUCCESS);
559 * Smart signing started with key format 1.3; prior to that, all
560 * keys are assumed active
562 if (major == 1 && minor <= 2)
565 result = dst_key_gettime(key, DST_TIME_PUBLISH, &publish);
566 if (result == ISC_R_SUCCESS)
569 result = dst_key_gettime(key, DST_TIME_ACTIVATE, &active);
570 if (result == ISC_R_SUCCESS)
573 result = dst_key_gettime(key, DST_TIME_REVOKE, &revoke);
574 if (result == ISC_R_SUCCESS)
577 result = dst_key_gettime(key, DST_TIME_INACTIVE, &inactive);
578 if (result == ISC_R_SUCCESS)
581 result = dst_key_gettime(key, DST_TIME_DELETE, &delete);
582 if (result == ISC_R_SUCCESS)
585 if ((inactset && inactive <= now) || (delset && delete <= now))
588 if (revset && revoke <= now && pubset && publish <= now)
591 if (actset && active <= now)
597 #define is_zone_key(key) ((dst_key_flags(key) & DNS_KEYFLAG_OWNERMASK) \
598 == DNS_KEYOWNER_ZONE)
601 dns_dnssec_findzonekeys2(dns_db_t *db, dns_dbversion_t *ver,
602 dns_dbnode_t *node, dns_name_t *name,
603 const char *directory, isc_mem_t *mctx,
604 unsigned int maxkeys, dst_key_t **keys,
607 dns_rdataset_t rdataset;
608 dns_rdata_t rdata = DNS_RDATA_INIT;
610 dst_key_t *pubkey = NULL;
611 unsigned int count = 0;
614 REQUIRE(nkeys != NULL);
615 REQUIRE(keys != NULL);
617 isc_stdtime_get(&now);
620 dns_rdataset_init(&rdataset);
621 RETERR(dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, 0, 0,
623 RETERR(dns_rdataset_first(&rdataset));
624 while (result == ISC_R_SUCCESS && count < maxkeys) {
626 dns_rdataset_current(&rdataset, &rdata);
627 RETERR(dns_dnssec_keyfromrdata(name, &rdata, mctx, &pubkey));
628 if (!is_zone_key(pubkey) ||
629 (dst_key_flags(pubkey) & DNS_KEYTYPE_NOAUTH) != 0)
631 /* Corrupted .key file? */
632 if (!dns_name_equal(name, dst_key_name(pubkey)))
635 result = dst_key_fromfile(dst_key_name(pubkey),
638 DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
643 * If the key was revoked and the private file
644 * doesn't exist, maybe it was revoked internally
645 * by named. Try loading the unrevoked version.
647 if (result == ISC_R_FILENOTFOUND) {
649 flags = dst_key_flags(pubkey);
650 if ((flags & DNS_KEYFLAG_REVOKE) != 0) {
651 dst_key_setflags(pubkey,
652 flags & ~DNS_KEYFLAG_REVOKE);
653 result = dst_key_fromfile(dst_key_name(pubkey),
660 if (result == ISC_R_SUCCESS &&
661 dst_key_pubcompare(pubkey, keys[count],
663 dst_key_setflags(keys[count], flags);
665 dst_key_setflags(pubkey, flags);
669 if (result != ISC_R_SUCCESS) {
670 char keybuf[DNS_NAME_FORMATSIZE];
671 char algbuf[DNS_SECALG_FORMATSIZE];
672 dns_name_format(dst_key_name(pubkey), keybuf,
674 dns_secalg_format(dst_key_alg(pubkey), algbuf,
676 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
677 DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
678 "dns_dnssec_findzonekeys2: error "
679 "reading private key file %s/%s/%d: %s",
680 keybuf, algbuf, dst_key_id(pubkey),
681 isc_result_totext(result));
684 if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) {
685 keys[count] = pubkey;
691 if (result != ISC_R_SUCCESS)
695 * If a key is marked inactive, skip it
697 if (!key_active(keys[count], now)) {
698 dst_key_free(&keys[count]);
699 keys[count] = pubkey;
705 if ((dst_key_flags(keys[count]) & DNS_KEYTYPE_NOAUTH) != 0) {
706 /* We should never get here. */
707 dst_key_free(&keys[count]);
713 dst_key_free(&pubkey);
714 dns_rdata_reset(&rdata);
715 result = dns_rdataset_next(&rdataset);
717 if (result != ISC_R_NOMORE)
720 result = ISC_R_NOTFOUND;
722 result = ISC_R_SUCCESS;
725 if (dns_rdataset_isassociated(&rdataset))
726 dns_rdataset_disassociate(&rdataset);
728 dst_key_free(&pubkey);
729 if (result != ISC_R_SUCCESS)
731 dst_key_free(&keys[--count]);
737 dns_dnssec_findzonekeys(dns_db_t *db, dns_dbversion_t *ver,
738 dns_dbnode_t *node, dns_name_t *name, isc_mem_t *mctx,
739 unsigned int maxkeys, dst_key_t **keys,
742 return (dns_dnssec_findzonekeys2(db, ver, node, name, NULL, mctx,
743 maxkeys, keys, nkeys));
747 dns_dnssec_signmessage(dns_message_t *msg, dst_key_t *key) {
748 dns_rdata_sig_t sig; /* SIG(0) */
749 unsigned char data[512];
750 unsigned char header[DNS_MESSAGE_HEADERLEN];
751 isc_buffer_t headerbuf, databuf, sigbuf;
752 unsigned int sigsize;
753 isc_buffer_t *dynbuf = NULL;
755 dns_rdatalist_t *datalist;
756 dns_rdataset_t *dataset;
759 dst_context_t *ctx = NULL;
762 isc_boolean_t signeedsfree = ISC_TRUE;
764 REQUIRE(msg != NULL);
765 REQUIRE(key != NULL);
767 if (is_response(msg))
768 REQUIRE(msg->query.base != NULL);
772 memset(&sig, 0, sizeof(sig));
775 sig.common.rdclass = dns_rdataclass_any;
776 sig.common.rdtype = dns_rdatatype_sig; /* SIG(0) */
777 ISC_LINK_INIT(&sig.common, link);
780 sig.algorithm = dst_key_alg(key);
781 sig.labels = 0; /* the root name */
784 isc_stdtime_get(&now);
785 sig.timesigned = now - DNS_TSIG_FUDGE;
786 sig.timeexpire = now + DNS_TSIG_FUDGE;
788 sig.keyid = dst_key_id(key);
790 dns_name_init(&sig.signer, NULL);
791 dns_name_clone(dst_key_name(key), &sig.signer);
794 sig.signature = NULL;
796 isc_buffer_init(&databuf, data, sizeof(data));
798 RETERR(dst_context_create(key, mctx, &ctx));
801 * Digest the fields of the SIG - we can cheat and use
802 * dns_rdata_fromstruct. Since siglen is 0, the digested data
803 * is identical to dns format.
805 RETERR(dns_rdata_fromstruct(NULL, dns_rdataclass_any,
806 dns_rdatatype_sig /* SIG(0) */,
808 isc_buffer_usedregion(&databuf, &r);
809 RETERR(dst_context_adddata(ctx, &r));
812 * If this is a response, digest the query.
814 if (is_response(msg))
815 RETERR(dst_context_adddata(ctx, &msg->query));
820 isc_buffer_init(&headerbuf, header, sizeof(header));
821 dns_message_renderheader(msg, &headerbuf);
822 isc_buffer_usedregion(&headerbuf, &r);
823 RETERR(dst_context_adddata(ctx, &r));
826 * Digest the remainder of the message.
828 isc_buffer_usedregion(msg->buffer, &r);
829 isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
830 RETERR(dst_context_adddata(ctx, &r));
832 RETERR(dst_key_sigsize(key, &sigsize));
833 sig.siglen = sigsize;
834 sig.signature = (unsigned char *) isc_mem_get(mctx, sig.siglen);
835 if (sig.signature == NULL) {
836 result = ISC_R_NOMEMORY;
840 isc_buffer_init(&sigbuf, sig.signature, sig.siglen);
841 RETERR(dst_context_sign(ctx, &sigbuf));
842 dst_context_destroy(&ctx);
845 RETERR(dns_message_gettemprdata(msg, &rdata));
846 RETERR(isc_buffer_allocate(msg->mctx, &dynbuf, 1024));
847 RETERR(dns_rdata_fromstruct(rdata, dns_rdataclass_any,
848 dns_rdatatype_sig /* SIG(0) */,
851 isc_mem_put(mctx, sig.signature, sig.siglen);
852 signeedsfree = ISC_FALSE;
854 dns_message_takebuffer(msg, &dynbuf);
857 RETERR(dns_message_gettemprdatalist(msg, &datalist));
858 datalist->rdclass = dns_rdataclass_any;
859 datalist->type = dns_rdatatype_sig; /* SIG(0) */
860 datalist->covers = 0;
862 ISC_LIST_INIT(datalist->rdata);
863 ISC_LIST_APPEND(datalist->rdata, rdata, link);
865 RETERR(dns_message_gettemprdataset(msg, &dataset));
866 dns_rdataset_init(dataset);
867 RUNTIME_CHECK(dns_rdatalist_tordataset(datalist, dataset) == ISC_R_SUCCESS);
870 return (ISC_R_SUCCESS);
874 isc_buffer_free(&dynbuf);
876 isc_mem_put(mctx, sig.signature, sig.siglen);
878 dst_context_destroy(&ctx);
884 dns_dnssec_verifymessage(isc_buffer_t *source, dns_message_t *msg,
887 dns_rdata_sig_t sig; /* SIG(0) */
888 unsigned char header[DNS_MESSAGE_HEADERLEN];
889 dns_rdata_t rdata = DNS_RDATA_INIT;
890 isc_region_t r, source_r, sig_r, header_r;
892 dst_context_t *ctx = NULL;
895 isc_uint16_t addcount;
896 isc_boolean_t signeedsfree = ISC_FALSE;
898 REQUIRE(source != NULL);
899 REQUIRE(msg != NULL);
900 REQUIRE(key != NULL);
904 msg->verify_attempted = 1;
906 if (is_response(msg)) {
907 if (msg->query.base == NULL)
908 return (DNS_R_UNEXPECTEDTSIG);
911 isc_buffer_usedregion(source, &source_r);
913 RETERR(dns_rdataset_first(msg->sig0));
914 dns_rdataset_current(msg->sig0, &rdata);
916 RETERR(dns_rdata_tostruct(&rdata, &sig, NULL));
917 signeedsfree = ISC_TRUE;
919 if (sig.labels != 0) {
920 result = DNS_R_SIGINVALID;
924 if (isc_serial_lt(sig.timeexpire, sig.timesigned)) {
925 result = DNS_R_SIGINVALID;
926 msg->sig0status = dns_tsigerror_badtime;
930 isc_stdtime_get(&now);
931 if (isc_serial_lt((isc_uint32_t)now, sig.timesigned)) {
932 result = DNS_R_SIGFUTURE;
933 msg->sig0status = dns_tsigerror_badtime;
936 else if (isc_serial_lt(sig.timeexpire, (isc_uint32_t)now)) {
937 result = DNS_R_SIGEXPIRED;
938 msg->sig0status = dns_tsigerror_badtime;
942 if (!dns_name_equal(dst_key_name(key), &sig.signer)) {
943 result = DNS_R_SIGINVALID;
944 msg->sig0status = dns_tsigerror_badkey;
948 RETERR(dst_context_create(key, mctx, &ctx));
951 * Digest the SIG(0) record, except for the signature.
953 dns_rdata_toregion(&rdata, &r);
954 r.length -= sig.siglen;
955 RETERR(dst_context_adddata(ctx, &r));
958 * If this is a response, digest the query.
960 if (is_response(msg))
961 RETERR(dst_context_adddata(ctx, &msg->query));
964 * Extract the header.
966 memcpy(header, source_r.base, DNS_MESSAGE_HEADERLEN);
969 * Decrement the additional field counter.
971 memcpy(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
972 addcount = htons((isc_uint16_t)(ntohs(addcount) - 1));
973 memcpy(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);
976 * Digest the modified header.
978 header_r.base = (unsigned char *) header;
979 header_r.length = DNS_MESSAGE_HEADERLEN;
980 RETERR(dst_context_adddata(ctx, &header_r));
983 * Digest all non-SIG(0) records.
985 r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
986 r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN;
987 RETERR(dst_context_adddata(ctx, &r));
989 sig_r.base = sig.signature;
990 sig_r.length = sig.siglen;
991 result = dst_context_verify(ctx, &sig_r);
992 if (result != ISC_R_SUCCESS) {
993 msg->sig0status = dns_tsigerror_badsig;
997 msg->verified_sig = 1;
999 dst_context_destroy(&ctx);
1000 dns_rdata_freestruct(&sig);
1002 return (ISC_R_SUCCESS);
1006 dns_rdata_freestruct(&sig);
1008 dst_context_destroy(&ctx);
1014 * Does this key ('rdata') self sign the rrset ('rdataset')?
1017 dns_dnssec_selfsigns(dns_rdata_t *rdata, dns_name_t *name,
1018 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
1019 isc_boolean_t ignoretime, isc_mem_t *mctx)
1021 INSIST(rdataset->type == dns_rdatatype_key ||
1022 rdataset->type == dns_rdatatype_dnskey);
1023 if (rdataset->type == dns_rdatatype_key) {
1024 INSIST(sigrdataset->type == dns_rdatatype_sig);
1025 INSIST(sigrdataset->covers == dns_rdatatype_key);
1027 INSIST(sigrdataset->type == dns_rdatatype_rrsig);
1028 INSIST(sigrdataset->covers == dns_rdatatype_dnskey);
1031 return (dns_dnssec_signs(rdata, name, rdataset, sigrdataset,
1037 dns_dnssec_signs(dns_rdata_t *rdata, dns_name_t *name,
1038 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
1039 isc_boolean_t ignoretime, isc_mem_t *mctx)
1041 dst_key_t *dstkey = NULL;
1042 dns_keytag_t keytag;
1043 dns_rdata_dnskey_t key;
1044 dns_rdata_rrsig_t sig;
1045 dns_rdata_t sigrdata = DNS_RDATA_INIT;
1046 isc_result_t result;
1048 INSIST(sigrdataset->type == dns_rdatatype_rrsig);
1049 if (sigrdataset->covers != rdataset->type)
1052 result = dns_dnssec_keyfromrdata(name, rdata, mctx, &dstkey);
1053 if (result != ISC_R_SUCCESS)
1055 result = dns_rdata_tostruct(rdata, &key, NULL);
1056 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1058 keytag = dst_key_id(dstkey);
1059 for (result = dns_rdataset_first(sigrdataset);
1060 result == ISC_R_SUCCESS;
1061 result = dns_rdataset_next(sigrdataset))
1063 dns_rdata_reset(&sigrdata);
1064 dns_rdataset_current(sigrdataset, &sigrdata);
1065 result = dns_rdata_tostruct(&sigrdata, &sig, NULL);
1066 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1068 if (sig.algorithm == key.algorithm &&
1069 sig.keyid == keytag) {
1070 result = dns_dnssec_verify2(name, rdataset, dstkey,
1073 if (result == ISC_R_SUCCESS) {
1074 dst_key_free(&dstkey);
1079 dst_key_free(&dstkey);
1084 dns_dnsseckey_create(isc_mem_t *mctx, dst_key_t **dstkey,
1085 dns_dnsseckey_t **dkp)
1087 isc_result_t result;
1088 dns_dnsseckey_t *dk;
1091 REQUIRE(dkp != NULL && *dkp == NULL);
1092 dk = isc_mem_get(mctx, sizeof(dns_dnsseckey_t));
1094 return (ISC_R_NOMEMORY);
1098 dk->force_publish = ISC_FALSE;
1099 dk->force_sign = ISC_FALSE;
1100 dk->hint_publish = ISC_FALSE;
1101 dk->hint_sign = ISC_FALSE;
1102 dk->hint_remove = ISC_FALSE;
1103 dk->first_sign = ISC_FALSE;
1104 dk->is_active = ISC_FALSE;
1106 dk->source = dns_keysource_unknown;
1110 dk->ksk = ISC_TF((dst_key_flags(dk->key) & DNS_KEYFLAG_KSK) != 0);
1112 /* Is this an old-style key? */
1113 result = dst_key_getprivateformat(dk->key, &major, &minor);
1114 INSIST(result == ISC_R_SUCCESS);
1116 /* Smart signing started with key format 1.3 */
1117 dk->legacy = ISC_TF(major == 1 && minor <= 2);
1119 ISC_LINK_INIT(dk, link);
1121 return (ISC_R_SUCCESS);
1125 dns_dnsseckey_destroy(isc_mem_t *mctx, dns_dnsseckey_t **dkp) {
1126 dns_dnsseckey_t *dk;
1128 REQUIRE(dkp != NULL && *dkp != NULL);
1130 if (dk->key != NULL)
1131 dst_key_free(&dk->key);
1132 isc_mem_put(mctx, dk, sizeof(dns_dnsseckey_t));
1137 get_hints(dns_dnsseckey_t *key, isc_stdtime_t now) {
1138 isc_result_t result;
1139 isc_stdtime_t publish, active, revoke, inactive, delete;
1140 isc_boolean_t pubset = ISC_FALSE, actset = ISC_FALSE;
1141 isc_boolean_t revset = ISC_FALSE, inactset = ISC_FALSE;
1142 isc_boolean_t delset = ISC_FALSE;
1144 REQUIRE(key != NULL && key->key != NULL);
1146 result = dst_key_gettime(key->key, DST_TIME_PUBLISH, &publish);
1147 if (result == ISC_R_SUCCESS)
1150 result = dst_key_gettime(key->key, DST_TIME_ACTIVATE, &active);
1151 if (result == ISC_R_SUCCESS)
1154 result = dst_key_gettime(key->key, DST_TIME_REVOKE, &revoke);
1155 if (result == ISC_R_SUCCESS)
1158 result = dst_key_gettime(key->key, DST_TIME_INACTIVE, &inactive);
1159 if (result == ISC_R_SUCCESS)
1160 inactset = ISC_TRUE;
1162 result = dst_key_gettime(key->key, DST_TIME_DELETE, &delete);
1163 if (result == ISC_R_SUCCESS)
1166 /* Metadata says publish (but possibly not activate) */
1167 if (pubset && publish <= now)
1168 key->hint_publish = ISC_TRUE;
1170 /* Metadata says activate (so we must also publish) */
1171 if (actset && active <= now) {
1172 key->hint_sign = ISC_TRUE;
1173 key->hint_publish = ISC_TRUE;
1177 * Activation date is set (maybe in the future), but
1178 * publication date isn't. Most likely the user wants to
1179 * publish now and activate later.
1181 if (actset && !pubset)
1182 key->hint_publish = ISC_TRUE;
1185 * If activation date is in the future, make note of how far off
1187 if (key->hint_publish && actset && active > now) {
1188 key->prepublish = active - now;
1192 * Key has been marked inactive: we can continue publishing,
1195 if (key->hint_publish && inactset && inactive <= now) {
1196 key->hint_sign = ISC_FALSE;
1200 * Metadata says revoke. If the key is published,
1201 * we *have to* sign with it per RFC5011--even if it was
1202 * not active before.
1204 * If it hasn't already been done, we should also revoke it now.
1206 if (key->hint_publish && (revset && revoke <= now)) {
1208 key->hint_sign = ISC_TRUE;
1209 flags = dst_key_flags(key->key);
1210 if ((flags & DNS_KEYFLAG_REVOKE) == 0) {
1211 flags |= DNS_KEYFLAG_REVOKE;
1212 dst_key_setflags(key->key, flags);
1217 * Metadata says delete, so don't publish this key or sign with it.
1219 if (delset && delete <= now) {
1220 key->hint_publish = ISC_FALSE;
1221 key->hint_sign = ISC_FALSE;
1222 key->hint_remove = ISC_TRUE;
1227 * Get a list of DNSSEC keys from the key repository
1230 dns_dnssec_findmatchingkeys(dns_name_t *origin, const char *directory,
1231 isc_mem_t *mctx, dns_dnsseckeylist_t *keylist)
1233 isc_result_t result = ISC_R_SUCCESS;
1234 isc_boolean_t dir_open = ISC_FALSE;
1235 dns_dnsseckeylist_t list;
1237 dns_dnsseckey_t *key = NULL;
1238 dst_key_t *dstkey = NULL;
1239 char namebuf[DNS_NAME_FORMATSIZE], *p;
1244 REQUIRE(keylist != NULL);
1245 ISC_LIST_INIT(list);
1248 isc_buffer_init(&b, namebuf, sizeof(namebuf) - 1);
1249 RETERR(dns_name_tofilenametext(origin, ISC_FALSE, &b));
1250 len = isc_buffer_usedlength(&b);
1251 namebuf[len] = '\0';
1253 if (directory == NULL)
1255 RETERR(isc_dir_open(&dir, directory));
1256 dir_open = ISC_TRUE;
1258 isc_stdtime_get(&now);
1260 while (isc_dir_read(&dir) == ISC_R_SUCCESS) {
1261 if (dir.entry.name[0] == 'K' &&
1262 dir.entry.length > len + 1 &&
1263 dir.entry.name[len + 1] == '+' &&
1264 strncasecmp(dir.entry.name + 1, namebuf, len) == 0) {
1265 p = strrchr(dir.entry.name, '.');
1266 if (p != NULL && strcmp(p, ".private") != 0)
1270 result = dst_key_fromnamedfile(dir.entry.name,
1276 if (result != ISC_R_SUCCESS) {
1277 isc_log_write(dns_lctx,
1278 DNS_LOGCATEGORY_GENERAL,
1279 DNS_LOGMODULE_DNSSEC,
1281 "dns_dnssec_findmatchingkeys: "
1282 "error reading key file %s: %s",
1284 isc_result_totext(result));
1288 RETERR(dns_dnsseckey_create(mctx, &dstkey, &key));
1289 key->source = dns_keysource_repository;
1290 get_hints(key, now);
1293 dns_dnsseckey_destroy(mctx, &key);
1295 ISC_LIST_APPEND(list, key, link);
1301 if (!ISC_LIST_EMPTY(list))
1302 ISC_LIST_APPENDLIST(*keylist, list, link);
1304 result = ISC_R_NOTFOUND;
1308 isc_dir_close(&dir);
1309 INSIST(key == NULL);
1310 while ((key = ISC_LIST_HEAD(list)) != NULL) {
1311 ISC_LIST_UNLINK(list, key, link);
1312 INSIST(key->key != NULL);
1313 dst_key_free(&key->key);
1314 dns_dnsseckey_destroy(mctx, &key);
1317 dst_key_free(&dstkey);
1322 * Add 'newkey' to 'keylist' if it's not already there.
1324 * If 'savekeys' is ISC_TRUE, then we need to preserve all
1325 * the keys in the keyset, regardless of whether they have
1326 * metadata indicating they should be deactivated or removed.
1329 addkey(dns_dnsseckeylist_t *keylist, dst_key_t **newkey,
1330 isc_boolean_t savekeys, isc_mem_t *mctx)
1332 dns_dnsseckey_t *key;
1334 /* Skip duplicates */
1335 for (key = ISC_LIST_HEAD(*keylist);
1337 key = ISC_LIST_NEXT(key, link)) {
1338 if (dst_key_id(key->key) == dst_key_id(*newkey) &&
1339 dst_key_alg(key->key) == dst_key_alg(*newkey) &&
1340 dns_name_equal(dst_key_name(key->key),
1341 dst_key_name(*newkey)))
1347 * Found a match. If the old key was only public and the
1348 * new key is private, replace the old one; otherwise
1349 * leave it. But either way, mark the key as having
1350 * been found in the zone.
1352 if (dst_key_isprivate(key->key)) {
1353 dst_key_free(newkey);
1354 } else if (dst_key_isprivate(*newkey)) {
1355 dst_key_free(&key->key);
1359 key->source = dns_keysource_zoneapex;
1363 dns_dnsseckey_create(mctx, newkey, &key);
1364 if (key->legacy || savekeys) {
1365 key->force_publish = ISC_TRUE;
1366 key->force_sign = dst_key_isprivate(key->key);
1368 key->source = dns_keysource_zoneapex;
1369 ISC_LIST_APPEND(*keylist, key, link);
1375 * Mark all keys which signed the DNSKEY/SOA RRsets as "active",
1376 * for future reference.
1379 mark_active_keys(dns_dnsseckeylist_t *keylist, dns_rdataset_t *rrsigs) {
1380 isc_result_t result = ISC_R_SUCCESS;
1381 dns_rdata_t rdata = DNS_RDATA_INIT;
1382 dns_rdataset_t sigs;
1383 dns_dnsseckey_t *key;
1385 REQUIRE(rrsigs != NULL && dns_rdataset_isassociated(rrsigs));
1387 dns_rdataset_init(&sigs);
1388 dns_rdataset_clone(rrsigs, &sigs);
1389 for (key = ISC_LIST_HEAD(*keylist);
1391 key = ISC_LIST_NEXT(key, link)) {
1392 isc_uint16_t keyid, sigid;
1393 dns_secalg_t keyalg, sigalg;
1394 keyid = dst_key_id(key->key);
1395 keyalg = dst_key_alg(key->key);
1397 for (result = dns_rdataset_first(&sigs);
1398 result == ISC_R_SUCCESS;
1399 result = dns_rdataset_next(&sigs)) {
1400 dns_rdata_rrsig_t sig;
1402 dns_rdata_reset(&rdata);
1403 dns_rdataset_current(&sigs, &rdata);
1404 result = dns_rdata_tostruct(&rdata, &sig, NULL);
1405 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1406 sigalg = sig.algorithm;
1408 if (keyid == sigid && keyalg == sigalg) {
1409 key->is_active = ISC_TRUE;
1415 if (result == ISC_R_NOMORE)
1416 result = ISC_R_SUCCESS;
1418 if (dns_rdataset_isassociated(&sigs))
1419 dns_rdataset_disassociate(&sigs);
1424 * Add the contents of a DNSKEY rdataset 'keyset' to 'keylist'.
1427 dns_dnssec_keylistfromrdataset(dns_name_t *origin,
1428 const char *directory, isc_mem_t *mctx,
1429 dns_rdataset_t *keyset, dns_rdataset_t *keysigs,
1430 dns_rdataset_t *soasigs, isc_boolean_t savekeys,
1431 isc_boolean_t public,
1432 dns_dnsseckeylist_t *keylist)
1434 dns_rdataset_t keys;
1435 dns_rdata_t rdata = DNS_RDATA_INIT;
1436 dst_key_t *pubkey = NULL, *privkey = NULL;
1437 isc_result_t result;
1439 REQUIRE(keyset != NULL && dns_rdataset_isassociated(keyset));
1441 dns_rdataset_init(&keys);
1443 dns_rdataset_clone(keyset, &keys);
1444 for (result = dns_rdataset_first(&keys);
1445 result == ISC_R_SUCCESS;
1446 result = dns_rdataset_next(&keys)) {
1447 dns_rdata_reset(&rdata);
1448 dns_rdataset_current(&keys, &rdata);
1449 RETERR(dns_dnssec_keyfromrdata(origin, &rdata, mctx, &pubkey));
1451 if (!is_zone_key(pubkey) ||
1452 (dst_key_flags(pubkey) & DNS_KEYTYPE_NOAUTH) != 0)
1455 /* Corrupted .key file? */
1456 if (!dns_name_equal(origin, dst_key_name(pubkey)))
1460 addkey(keylist, &pubkey, savekeys, mctx);
1464 result = dst_key_fromfile(dst_key_name(pubkey),
1466 dst_key_alg(pubkey),
1467 DST_TYPE_PUBLIC|DST_TYPE_PRIVATE,
1468 directory, mctx, &privkey);
1471 * If the key was revoked and the private file
1472 * doesn't exist, maybe it was revoked internally
1473 * by named. Try loading the unrevoked version.
1475 if (result == ISC_R_FILENOTFOUND) {
1477 flags = dst_key_flags(pubkey);
1478 if ((flags & DNS_KEYFLAG_REVOKE) != 0) {
1479 dst_key_setflags(pubkey,
1480 flags & ~DNS_KEYFLAG_REVOKE);
1481 result = dst_key_fromfile(dst_key_name(pubkey),
1483 dst_key_alg(pubkey),
1488 if (result == ISC_R_SUCCESS &&
1489 dst_key_pubcompare(pubkey, privkey,
1491 dst_key_setflags(privkey, flags);
1493 dst_key_setflags(pubkey, flags);
1497 if (result != ISC_R_SUCCESS) {
1498 char keybuf[DNS_NAME_FORMATSIZE];
1499 char algbuf[DNS_SECALG_FORMATSIZE];
1500 dns_name_format(dst_key_name(pubkey), keybuf,
1502 dns_secalg_format(dst_key_alg(pubkey), algbuf,
1504 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1505 DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
1506 "dns_dnssec_keylistfromrdataset: error "
1507 "reading private key file %s/%s/%d: %s",
1508 keybuf, algbuf, dst_key_id(pubkey),
1509 isc_result_totext(result));
1512 if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) {
1513 addkey(keylist, &pubkey, savekeys, mctx);
1518 /* This should never happen. */
1519 if ((dst_key_flags(privkey) & DNS_KEYTYPE_NOAUTH) != 0)
1522 addkey(keylist, &privkey, savekeys, mctx);
1525 dst_key_free(&pubkey);
1526 if (privkey != NULL)
1527 dst_key_free(&privkey);
1530 if (result != ISC_R_NOMORE)
1533 if (keysigs != NULL && dns_rdataset_isassociated(keysigs))
1534 RETERR(mark_active_keys(keylist, keysigs));
1536 if (soasigs != NULL && dns_rdataset_isassociated(soasigs))
1537 RETERR(mark_active_keys(keylist, soasigs));
1539 result = ISC_R_SUCCESS;
1542 if (dns_rdataset_isassociated(&keys))
1543 dns_rdataset_disassociate(&keys);
1545 dst_key_free(&pubkey);
1546 if (privkey != NULL)
1547 dst_key_free(&privkey);
1552 make_dnskey(dst_key_t *key, unsigned char *buf, int bufsize,
1553 dns_rdata_t *target)
1555 isc_result_t result;
1559 isc_buffer_init(&b, buf, bufsize);
1560 result = dst_key_todns(key, &b);
1561 if (result != ISC_R_SUCCESS)
1564 dns_rdata_reset(target);
1565 isc_buffer_usedregion(&b, &r);
1566 dns_rdata_fromregion(target, dst_key_class(key),
1567 dns_rdatatype_dnskey, &r);
1568 return (ISC_R_SUCCESS);
1572 publish_key(dns_diff_t *diff, dns_dnsseckey_t *key, dns_name_t *origin,
1573 dns_ttl_t ttl, isc_mem_t *mctx, isc_boolean_t allzsk,
1574 void (*report)(const char *, ...))
1576 isc_result_t result;
1577 dns_difftuple_t *tuple = NULL;
1578 unsigned char buf[DST_KEY_MAXSIZE];
1579 dns_rdata_t dnskey = DNS_RDATA_INIT;
1582 dns_rdata_reset(&dnskey);
1583 RETERR(make_dnskey(key->key, buf, sizeof(buf), &dnskey));
1585 dns_secalg_format(dst_key_alg(key->key), alg, sizeof(alg));
1586 report("Fetching %s %d/%s from key %s.",
1587 key->ksk ? (allzsk ? "KSK/ZSK" : "KSK") : "ZSK",
1588 dst_key_id(key->key), alg,
1589 key->source == dns_keysource_user ? "file" : "repository");
1591 if (key->prepublish && ttl > key->prepublish) {
1592 char keystr[DST_KEY_FORMATSIZE];
1595 dst_key_format(key->key, keystr, sizeof(keystr));
1596 report("Key %s: Delaying activation to match the DNSKEY TTL.\n",
1599 isc_stdtime_get(&now);
1600 dst_key_settime(key->key, DST_TIME_ACTIVATE, now + ttl);
1604 RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_ADD, origin, ttl,
1606 dns_diff_appendminimal(diff, &tuple);
1607 result = ISC_R_SUCCESS;
1614 remove_key(dns_diff_t *diff, dns_dnsseckey_t *key, dns_name_t *origin,
1615 dns_ttl_t ttl, isc_mem_t *mctx, const char *reason,
1616 void (*report)(const char *, ...))
1618 isc_result_t result;
1619 dns_difftuple_t *tuple = NULL;
1620 unsigned char buf[DST_KEY_MAXSIZE];
1621 dns_rdata_t dnskey = DNS_RDATA_INIT;
1624 dns_secalg_format(dst_key_alg(key->key), alg, sizeof(alg));
1625 report("Removing %s key %d/%s from DNSKEY RRset.",
1626 reason, dst_key_id(key->key), alg);
1628 RETERR(make_dnskey(key->key, buf, sizeof(buf), &dnskey));
1629 RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_DEL, origin, ttl, &dnskey,
1631 dns_diff_appendminimal(diff, &tuple);
1632 result = ISC_R_SUCCESS;
1639 * Update 'keys' with information from 'newkeys'.
1641 * If 'removed' is not NULL, any keys that are being removed from
1642 * the zone will be added to the list for post-removal processing.
1645 dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys,
1646 dns_dnsseckeylist_t *removed, dns_name_t *origin,
1647 dns_ttl_t ttl, dns_diff_t *diff, isc_boolean_t allzsk,
1648 isc_mem_t *mctx, void (*report)(const char *, ...))
1650 isc_result_t result;
1651 dns_dnsseckey_t *key, *key1, *key2, *next;
1654 * First, look through the existing key list to find keys
1655 * supplied from the command line which are not in the zone.
1656 * Update the zone to include them.
1658 for (key = ISC_LIST_HEAD(*keys);
1660 key = ISC_LIST_NEXT(key, link)) {
1661 if (key->source == dns_keysource_user &&
1662 (key->hint_publish || key->force_publish)) {
1663 RETERR(publish_key(diff, key, origin, ttl,
1664 mctx, allzsk, report));
1669 * Second, scan the list of newly found keys looking for matches
1670 * with known keys, and update accordingly.
1672 for (key1 = ISC_LIST_HEAD(*newkeys); key1 != NULL; key1 = next) {
1673 isc_boolean_t key_revoked = ISC_FALSE;
1675 next = ISC_LIST_NEXT(key1, link);
1677 for (key2 = ISC_LIST_HEAD(*keys);
1679 key2 = ISC_LIST_NEXT(key2, link)) {
1680 if (dst_key_pubcompare(key1->key, key2->key,
1683 r1 = dst_key_flags(key1->key) &
1685 r2 = dst_key_flags(key2->key) &
1687 key_revoked = ISC_TF(r1 != r2);
1692 /* No match found in keys; add the new key. */
1694 ISC_LIST_UNLINK(*newkeys, key1, link);
1695 ISC_LIST_APPEND(*keys, key1, link);
1697 if (key1->source != dns_keysource_zoneapex &&
1698 (key1->hint_publish || key1->force_publish)) {
1699 RETERR(publish_key(diff, key1, origin, ttl,
1700 mctx, allzsk, report));
1701 if (key1->hint_sign || key1->force_sign)
1702 key1->first_sign = ISC_TRUE;
1708 /* Match found: remove or update it as needed */
1709 if (key1->hint_remove) {
1710 RETERR(remove_key(diff, key2, origin, ttl, mctx,
1711 "expired", report));
1712 ISC_LIST_UNLINK(*keys, key2, link);
1713 if (removed != NULL)
1714 ISC_LIST_APPEND(*removed, key2, link);
1716 dns_dnsseckey_destroy(mctx, &key2);
1717 } else if (key_revoked &&
1718 (dst_key_flags(key1->key) & DNS_KEYFLAG_REVOKE) != 0) {
1721 * A previously valid key has been revoked.
1722 * We need to remove the old version and pull
1725 RETERR(remove_key(diff, key2, origin, ttl, mctx,
1726 "revoked", report));
1727 ISC_LIST_UNLINK(*keys, key2, link);
1728 if (removed != NULL)
1729 ISC_LIST_APPEND(*removed, key2, link);
1731 dns_dnsseckey_destroy(mctx, &key2);
1733 RETERR(publish_key(diff, key1, origin, ttl,
1734 mctx, allzsk, report));
1735 ISC_LIST_UNLINK(*newkeys, key1, link);
1736 ISC_LIST_APPEND(*keys, key1, link);
1739 * XXX: The revoke flag is only defined for trust
1740 * anchors. Setting the flag on a non-KSK is legal,
1741 * but not defined in any RFC. It seems reasonable
1742 * to treat it the same as a KSK: keep it in the
1743 * zone, sign the DNSKEY set with it, but not
1744 * sign other records with it.
1746 key1->ksk = ISC_TRUE;
1749 if (!key2->is_active &&
1750 (key1->hint_sign || key1->force_sign))
1751 key2->first_sign = ISC_TRUE;
1752 key2->hint_sign = key1->hint_sign;
1753 key2->hint_publish = key1->hint_publish;
1757 /* Free any leftover keys in newkeys */
1758 while (!ISC_LIST_EMPTY(*newkeys)) {
1759 key1 = ISC_LIST_HEAD(*newkeys);
1760 ISC_LIST_UNLINK(*newkeys, key1, link);
1761 dns_dnsseckey_destroy(mctx, &key1);
1764 result = ISC_R_SUCCESS;