Home | History | Annotate | Line # | Download | only in dns
      1 /*	$NetBSD: dnssec.c,v 1.20 2026/06/19 20:10:00 christos Exp $	*/
      2 
      3 /*
      4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5  *
      6  * SPDX-License-Identifier: MPL-2.0
      7  *
      8  * This Source Code Form is subject to the terms of the Mozilla Public
      9  * License, v. 2.0. If a copy of the MPL was not distributed with this
     10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
     11  *
     12  * See the COPYRIGHT file distributed with this work for additional
     13  * information regarding copyright ownership.
     14  */
     15 
     16 /*! \file */
     17 
     18 #include <ctype.h>
     19 #include <inttypes.h>
     20 #include <stdbool.h>
     21 #include <stdlib.h>
     22 
     23 #include <isc/buffer.h>
     24 #include <isc/dir.h>
     25 #include <isc/mem.h>
     26 #include <isc/result.h>
     27 #include <isc/serial.h>
     28 #include <isc/string.h>
     29 #include <isc/util.h>
     30 
     31 #include <dns/db.h>
     32 #include <dns/diff.h>
     33 #include <dns/dnssec.h>
     34 #include <dns/fixedname.h>
     35 #include <dns/kasp.h>
     36 #include <dns/keyvalues.h>
     37 #include <dns/log.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/stats.h>
     44 #include <dns/tsig.h> /* for DNS_TSIG_FUDGE */
     45 
     46 isc_stats_t *dns_dnssec_stats;
     47 
     48 #define is_response(msg) ((msg->flags & DNS_MESSAGEFLAG_QR) != 0)
     49 
     50 #define TYPE_SIGN   0
     51 #define TYPE_VERIFY 1
     52 
     53 static isc_result_t
     54 digest_callback(void *arg, isc_region_t *data);
     55 
     56 static int
     57 rdata_compare_wrapper(const void *rdata1, const void *rdata2);
     58 
     59 static isc_result_t
     60 rdataset_to_sortedarray(dns_rdataset_t *set, isc_mem_t *mctx,
     61 			dns_rdata_t **rdata, int *nrdata);
     62 
     63 static isc_result_t
     64 digest_callback(void *arg, isc_region_t *data) {
     65 	dst_context_t *ctx = arg;
     66 
     67 	return dst_context_adddata(ctx, data);
     68 }
     69 
     70 static void
     71 inc_stat(isc_statscounter_t counter) {
     72 	if (dns_dnssec_stats != NULL) {
     73 		isc_stats_increment(dns_dnssec_stats, counter);
     74 	}
     75 }
     76 
     77 /*
     78  * Make qsort happy.
     79  */
     80 static int
     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);
     84 }
     85 
     86 /*
     87  * Sort the rdataset into an array.
     88  */
     89 static isc_result_t
     90 rdataset_to_sortedarray(dns_rdataset_t *set, isc_mem_t *mctx,
     91 			dns_rdata_t **rdata, int *nrdata) {
     92 	isc_result_t ret;
     93 	int i = 0, n;
     94 	dns_rdata_t *data;
     95 	dns_rdataset_t rdataset;
     96 
     97 	n = dns_rdataset_count(set);
     98 
     99 	data = isc_mem_cget(mctx, n, sizeof(dns_rdata_t));
    100 
    101 	dns_rdataset_init(&rdataset);
    102 	dns_rdataset_clone(set, &rdataset);
    103 	ret = dns_rdataset_first(&rdataset);
    104 	if (ret != ISC_R_SUCCESS) {
    105 		dns_rdataset_disassociate(&rdataset);
    106 		isc_mem_cput(mctx, data, n, sizeof(dns_rdata_t));
    107 		return ret;
    108 	}
    109 
    110 	/*
    111 	 * Put them in the array.
    112 	 */
    113 	do {
    114 		dns_rdata_init(&data[i]);
    115 		dns_rdataset_current(&rdataset, &data[i++]);
    116 	} while (dns_rdataset_next(&rdataset) == ISC_R_SUCCESS);
    117 
    118 	/*
    119 	 * Sort the array.
    120 	 */
    121 	qsort(data, n, sizeof(dns_rdata_t), rdata_compare_wrapper);
    122 	*rdata = data;
    123 	*nrdata = n;
    124 	dns_rdataset_disassociate(&rdataset);
    125 	return ISC_R_SUCCESS;
    126 }
    127 
    128 isc_result_t
    129 dns_dnssec_keyfromrdata(const dns_name_t *name, const dns_rdata_t *rdata,
    130 			isc_mem_t *mctx, dst_key_t **key) {
    131 	isc_buffer_t b;
    132 	isc_region_t r;
    133 
    134 	INSIST(name != NULL);
    135 	INSIST(rdata != NULL);
    136 	INSIST(mctx != NULL);
    137 	INSIST(key != NULL);
    138 	INSIST(*key == NULL);
    139 	REQUIRE(rdata->type == dns_rdatatype_key ||
    140 		rdata->type == dns_rdatatype_dnskey);
    141 
    142 	dns_rdata_toregion(rdata, &r);
    143 	isc_buffer_init(&b, r.base, r.length);
    144 	isc_buffer_add(&b, r.length);
    145 	return dst_key_fromdns(name, rdata->rdclass, &b, mctx, key);
    146 }
    147 
    148 static isc_result_t
    149 digest_sig(dst_context_t *ctx, bool downcase, dns_rdata_t *sigrdata,
    150 	   dns_rdata_rrsig_t *rrsig) {
    151 	isc_region_t r;
    152 	isc_result_t ret;
    153 	dns_fixedname_t fname;
    154 
    155 	dns_rdata_toregion(sigrdata, &r);
    156 	INSIST(r.length >= 19);
    157 
    158 	r.length = 18;
    159 	ret = dst_context_adddata(ctx, &r);
    160 	if (ret != ISC_R_SUCCESS) {
    161 		return ret;
    162 	}
    163 	if (downcase) {
    164 		dns_fixedname_init(&fname);
    165 
    166 		RUNTIME_CHECK(dns_name_downcase(&rrsig->signer,
    167 						dns_fixedname_name(&fname),
    168 						NULL) == ISC_R_SUCCESS);
    169 		dns_name_toregion(dns_fixedname_name(&fname), &r);
    170 	} else {
    171 		dns_name_toregion(&rrsig->signer, &r);
    172 	}
    173 
    174 	return dst_context_adddata(ctx, &r);
    175 }
    176 
    177 isc_result_t
    178 dns_dnssec_sign(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
    179 		isc_stdtime_t *inception, isc_stdtime_t *expire,
    180 		isc_mem_t *mctx, isc_buffer_t *buffer, dns_rdata_t *sigrdata) {
    181 	dns_rdata_rrsig_t sig;
    182 	dns_rdata_t tmpsigrdata;
    183 	dns_rdata_t *rdatas;
    184 	int nrdatas, i;
    185 	isc_buffer_t sigbuf, envbuf;
    186 	isc_region_t r;
    187 	dst_context_t *ctx = NULL;
    188 	isc_result_t ret;
    189 	isc_buffer_t *databuf = NULL;
    190 	char data[256 + 8];
    191 	unsigned int sigsize;
    192 	dns_fixedname_t fnewname;
    193 	dns_fixedname_t fsigner;
    194 
    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);
    203 
    204 	if (*inception >= *expire) {
    205 		return DNS_R_INVALIDTIME;
    206 	}
    207 
    208 	sig.mctx = mctx;
    209 	sig.common.rdclass = set->rdclass;
    210 	sig.common.rdtype = dns_rdatatype_rrsig;
    211 	ISC_LINK_INIT(&sig.common, link);
    212 
    213 	/*
    214 	 * Downcase signer.
    215 	 */
    216 	dns_name_init(&sig.signer, NULL);
    217 	dns_fixedname_init(&fsigner);
    218 	RUNTIME_CHECK(dns_name_downcase(dst_key_name(key),
    219 					dns_fixedname_name(&fsigner),
    220 					NULL) == ISC_R_SUCCESS);
    221 	dns_name_clone(dns_fixedname_name(&fsigner), &sig.signer);
    222 
    223 	sig.covered = set->type;
    224 	sig.algorithm = dst_key_alg(key);
    225 	sig.labels = dns_name_countlabels(name) - 1;
    226 	if (dns_name_iswildcard(name)) {
    227 		sig.labels--;
    228 	}
    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) {
    235 		return ret;
    236 	}
    237 	sig.siglen = sigsize;
    238 	/*
    239 	 * The actual contents of sig.signature are not important yet, since
    240 	 * they're not used in digest_sig().
    241 	 */
    242 	sig.signature = isc_mem_get(mctx, sig.siglen);
    243 
    244 	isc_buffer_allocate(mctx, &databuf, sigsize + 256 + 18);
    245 
    246 	dns_rdata_init(&tmpsigrdata);
    247 	ret = dns_rdata_fromstruct(&tmpsigrdata, sig.common.rdclass,
    248 				   sig.common.rdtype, &sig, databuf);
    249 	if (ret != ISC_R_SUCCESS) {
    250 		goto cleanup_databuf;
    251 	}
    252 
    253 	ret = dst_context_create(key, mctx, DNS_LOGCATEGORY_DNSSEC, true, 0,
    254 				 &ctx);
    255 	if (ret != ISC_R_SUCCESS) {
    256 		goto cleanup_databuf;
    257 	}
    258 
    259 	/*
    260 	 * Digest the SIG rdata.
    261 	 */
    262 	ret = digest_sig(ctx, false, &tmpsigrdata, &sig);
    263 	if (ret != ISC_R_SUCCESS) {
    264 		goto cleanup_context;
    265 	}
    266 
    267 	dns_fixedname_init(&fnewname);
    268 	RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname),
    269 					NULL) == ISC_R_SUCCESS);
    270 	dns_name_toregion(dns_fixedname_name(&fnewname), &r);
    271 
    272 	/*
    273 	 * Create an envelope for each rdata: <name|type|class|ttl>.
    274 	 */
    275 	isc_buffer_init(&envbuf, data, sizeof(data));
    276 	memmove(data, r.base, r.length);
    277 	isc_buffer_add(&envbuf, r.length);
    278 	isc_buffer_putuint16(&envbuf, set->type);
    279 	isc_buffer_putuint16(&envbuf, set->rdclass);
    280 	isc_buffer_putuint32(&envbuf, set->ttl);
    281 
    282 	ret = rdataset_to_sortedarray(set, mctx, &rdatas, &nrdatas);
    283 	if (ret != ISC_R_SUCCESS) {
    284 		goto cleanup_context;
    285 	}
    286 	isc_buffer_usedregion(&envbuf, &r);
    287 
    288 	for (i = 0; i < nrdatas; i++) {
    289 		uint16_t len;
    290 		isc_buffer_t lenbuf;
    291 		isc_region_t lenr;
    292 
    293 		/*
    294 		 * Skip duplicates.
    295 		 */
    296 		if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i - 1]) == 0)
    297 		{
    298 			continue;
    299 		}
    300 
    301 		/*
    302 		 * Digest the envelope.
    303 		 */
    304 		ret = dst_context_adddata(ctx, &r);
    305 		if (ret != ISC_R_SUCCESS) {
    306 			goto cleanup_array;
    307 		}
    308 
    309 		/*
    310 		 * Digest the length of the rdata.
    311 		 */
    312 		isc_buffer_init(&lenbuf, &len, sizeof(len));
    313 		isc_buffer_putuint16(&lenbuf, (uint16_t)rdatas[i].length);
    314 		isc_buffer_usedregion(&lenbuf, &lenr);
    315 		ret = dst_context_adddata(ctx, &lenr);
    316 		if (ret != ISC_R_SUCCESS) {
    317 			goto cleanup_array;
    318 		}
    319 
    320 		/*
    321 		 * Digest the rdata.
    322 		 */
    323 		ret = dns_rdata_digest(&rdatas[i], digest_callback, ctx);
    324 		if (ret != ISC_R_SUCCESS) {
    325 			goto cleanup_array;
    326 		}
    327 	}
    328 
    329 	isc_buffer_init(&sigbuf, sig.signature, sig.siglen);
    330 	ret = dst_context_sign(ctx, &sigbuf);
    331 	if (ret != ISC_R_SUCCESS) {
    332 		goto cleanup_array;
    333 	}
    334 	isc_buffer_usedregion(&sigbuf, &r);
    335 	if (r.length != sig.siglen) {
    336 		ret = ISC_R_NOSPACE;
    337 		goto cleanup_array;
    338 	}
    339 
    340 	ret = dns_rdata_fromstruct(sigrdata, sig.common.rdclass,
    341 				   sig.common.rdtype, &sig, buffer);
    342 
    343 cleanup_array:
    344 	isc_mem_cput(mctx, rdatas, nrdatas, sizeof(dns_rdata_t));
    345 cleanup_context:
    346 	dst_context_destroy(&ctx);
    347 cleanup_databuf:
    348 	isc_buffer_free(&databuf);
    349 	isc_mem_put(mctx, sig.signature, sig.siglen);
    350 
    351 	return ret;
    352 }
    353 
    354 isc_result_t
    355 dns_dnssec_verify(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
    356 		  bool ignoretime, unsigned int maxbits, isc_mem_t *mctx,
    357 		  dns_rdata_t *sigrdata, dns_name_t *wild) {
    358 	dns_rdata_rrsig_t sig;
    359 	dns_fixedname_t fnewname;
    360 	isc_region_t r;
    361 	isc_buffer_t envbuf;
    362 	dns_rdata_t *rdatas;
    363 	int nrdatas, i;
    364 	isc_stdtime_t now;
    365 	isc_result_t ret;
    366 	unsigned char data[300];
    367 	dst_context_t *ctx = NULL;
    368 	int labels = 0;
    369 	bool downcase = false;
    370 
    371 	REQUIRE(name != NULL);
    372 	REQUIRE(set != NULL);
    373 	REQUIRE(key != NULL);
    374 	REQUIRE(mctx != NULL);
    375 	REQUIRE(sigrdata != NULL && sigrdata->type == dns_rdatatype_rrsig);
    376 
    377 	ret = dns_rdata_tostruct(sigrdata, &sig, NULL);
    378 	if (ret != ISC_R_SUCCESS) {
    379 		return ret;
    380 	}
    381 
    382 	if (set->type != sig.covered) {
    383 		return DNS_R_SIGINVALID;
    384 	}
    385 
    386 	if (isc_serial_lt(sig.timeexpire, sig.timesigned)) {
    387 		inc_stat(dns_dnssecstats_fail);
    388 		return DNS_R_SIGINVALID;
    389 	}
    390 
    391 	if (!ignoretime) {
    392 		now = isc_stdtime_now();
    393 
    394 		/*
    395 		 * Is SIG temporally valid?
    396 		 */
    397 		if (isc_serial_lt((uint32_t)now, sig.timesigned)) {
    398 			inc_stat(dns_dnssecstats_fail);
    399 			return DNS_R_SIGFUTURE;
    400 		} else if (isc_serial_lt(sig.timeexpire, (uint32_t)now)) {
    401 			inc_stat(dns_dnssecstats_fail);
    402 			return DNS_R_SIGEXPIRED;
    403 		}
    404 	}
    405 
    406 	/*
    407 	 * NS, SOA and DNSKEY records are signed by their owner.
    408 	 * DS records are signed by the parent.
    409 	 */
    410 	switch (set->type) {
    411 	case dns_rdatatype_ns:
    412 	case dns_rdatatype_soa:
    413 	case dns_rdatatype_dnskey:
    414 		if (!dns_name_equal(name, &sig.signer)) {
    415 			inc_stat(dns_dnssecstats_fail);
    416 			return DNS_R_SIGINVALID;
    417 		}
    418 		break;
    419 	case dns_rdatatype_ds:
    420 		if (dns_name_equal(name, &sig.signer)) {
    421 			inc_stat(dns_dnssecstats_fail);
    422 			return DNS_R_SIGINVALID;
    423 		}
    424 		FALLTHROUGH;
    425 	default:
    426 		if (!dns_name_issubdomain(name, &sig.signer)) {
    427 			inc_stat(dns_dnssecstats_fail);
    428 			return DNS_R_SIGINVALID;
    429 		}
    430 		break;
    431 	}
    432 
    433 again:
    434 	ret = dst_context_create(key, mctx, DNS_LOGCATEGORY_DNSSEC, false,
    435 				 maxbits, &ctx);
    436 	if (ret != ISC_R_SUCCESS) {
    437 		goto cleanup_struct;
    438 	}
    439 
    440 	/*
    441 	 * Digest the SIG rdata (not including the signature).
    442 	 */
    443 	ret = digest_sig(ctx, downcase, sigrdata, &sig);
    444 	if (ret != ISC_R_SUCCESS) {
    445 		goto cleanup_context;
    446 	}
    447 
    448 	/*
    449 	 * If the name is an expanded wildcard, use the wildcard name.
    450 	 */
    451 	dns_fixedname_init(&fnewname);
    452 	labels = dns_name_countlabels(name) - 1;
    453 	RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname),
    454 					NULL) == ISC_R_SUCCESS);
    455 	if (labels - sig.labels > 0) {
    456 		dns_name_split(dns_fixedname_name(&fnewname), sig.labels + 1,
    457 			       NULL, dns_fixedname_name(&fnewname));
    458 	}
    459 
    460 	dns_name_toregion(dns_fixedname_name(&fnewname), &r);
    461 
    462 	/*
    463 	 * Create an envelope for each rdata: <name|type|class|ttl>.
    464 	 */
    465 	isc_buffer_init(&envbuf, data, sizeof(data));
    466 	if (labels - sig.labels > 0) {
    467 		isc_buffer_putuint8(&envbuf, 1);
    468 		isc_buffer_putuint8(&envbuf, '*');
    469 		memmove(data + 2, r.base, r.length);
    470 	} else {
    471 		memmove(data, r.base, r.length);
    472 	}
    473 	isc_buffer_add(&envbuf, r.length);
    474 	isc_buffer_putuint16(&envbuf, set->type);
    475 	isc_buffer_putuint16(&envbuf, set->rdclass);
    476 	isc_buffer_putuint32(&envbuf, sig.originalttl);
    477 
    478 	ret = rdataset_to_sortedarray(set, mctx, &rdatas, &nrdatas);
    479 	if (ret != ISC_R_SUCCESS) {
    480 		goto cleanup_context;
    481 	}
    482 
    483 	isc_buffer_usedregion(&envbuf, &r);
    484 
    485 	for (i = 0; i < nrdatas; i++) {
    486 		uint16_t len;
    487 		isc_buffer_t lenbuf;
    488 		isc_region_t lenr;
    489 
    490 		/*
    491 		 * Skip duplicates.
    492 		 */
    493 		if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i - 1]) == 0)
    494 		{
    495 			continue;
    496 		}
    497 
    498 		/*
    499 		 * Digest the envelope.
    500 		 */
    501 		ret = dst_context_adddata(ctx, &r);
    502 		if (ret != ISC_R_SUCCESS) {
    503 			goto cleanup_array;
    504 		}
    505 
    506 		/*
    507 		 * Digest the rdata length.
    508 		 */
    509 		isc_buffer_init(&lenbuf, &len, sizeof(len));
    510 		isc_buffer_putuint16(&lenbuf, (uint16_t)rdatas[i].length);
    511 		isc_buffer_usedregion(&lenbuf, &lenr);
    512 
    513 		/*
    514 		 * Digest the rdata.
    515 		 */
    516 		ret = dst_context_adddata(ctx, &lenr);
    517 		if (ret != ISC_R_SUCCESS) {
    518 			goto cleanup_array;
    519 		}
    520 		ret = dns_rdata_digest(&rdatas[i], digest_callback, ctx);
    521 		if (ret != ISC_R_SUCCESS) {
    522 			goto cleanup_array;
    523 		}
    524 	}
    525 
    526 	r.base = sig.signature;
    527 	r.length = sig.siglen;
    528 	ret = dst_context_verify2(ctx, maxbits, &r);
    529 	if (ret == ISC_R_SUCCESS && downcase) {
    530 		char namebuf[DNS_NAME_FORMATSIZE];
    531 		dns_name_format(&sig.signer, namebuf, sizeof(namebuf));
    532 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
    533 			      DNS_LOGMODULE_DNSSEC, ISC_LOG_DEBUG(1),
    534 			      "successfully validated after lower casing "
    535 			      "signer '%s'",
    536 			      namebuf);
    537 		inc_stat(dns_dnssecstats_downcase);
    538 	} else if (ret == ISC_R_SUCCESS) {
    539 		inc_stat(dns_dnssecstats_asis);
    540 	}
    541 
    542 cleanup_array:
    543 	isc_mem_cput(mctx, rdatas, nrdatas, sizeof(dns_rdata_t));
    544 cleanup_context:
    545 	dst_context_destroy(&ctx);
    546 	if (ret == DST_R_VERIFYFAILURE && !downcase) {
    547 		downcase = true;
    548 		goto again;
    549 	}
    550 cleanup_struct:
    551 	dns_rdata_freestruct(&sig);
    552 
    553 	if (ret == DST_R_VERIFYFAILURE) {
    554 		ret = DNS_R_SIGINVALID;
    555 	}
    556 
    557 	if (ret != ISC_R_SUCCESS) {
    558 		inc_stat(dns_dnssecstats_fail);
    559 	}
    560 
    561 	if (ret == ISC_R_SUCCESS && labels - sig.labels > 0) {
    562 		if (wild != NULL) {
    563 			RUNTIME_CHECK(dns_name_concatenate(
    564 					      dns_wildcardname,
    565 					      dns_fixedname_name(&fnewname),
    566 					      wild, NULL) == ISC_R_SUCCESS);
    567 		}
    568 		inc_stat(dns_dnssecstats_wildcard);
    569 		ret = DNS_R_FROMWILDCARD;
    570 	}
    571 	return ret;
    572 }
    573 
    574 bool
    575 dns_dnssec_keyactive(dst_key_t *key, isc_stdtime_t now) {
    576 	isc_result_t result;
    577 	isc_stdtime_t publish, active, revoke, remove;
    578 	bool hint_publish, hint_zsign, hint_ksign, hint_revoke, hint_remove;
    579 	int major, minor;
    580 	bool ksk = false, zsk = false;
    581 	isc_result_t ret;
    582 
    583 	/* Is this an old-style key? */
    584 	result = dst_key_getprivateformat(key, &major, &minor);
    585 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
    586 
    587 	/* Is this a KSK? */
    588 	ret = dst_key_getbool(key, DST_BOOL_KSK, &ksk);
    589 	if (ret != ISC_R_SUCCESS) {
    590 		ksk = ((dst_key_flags(key) & DNS_KEYFLAG_KSK) != 0);
    591 	}
    592 	ret = dst_key_getbool(key, DST_BOOL_ZSK, &zsk);
    593 	if (ret != ISC_R_SUCCESS) {
    594 		zsk = ((dst_key_flags(key) & DNS_KEYFLAG_KSK) == 0);
    595 	}
    596 
    597 	/*
    598 	 * Smart signing started with key format 1.3; prior to that, all
    599 	 * keys are assumed active.
    600 	 */
    601 	if (major == 1 && minor <= 2) {
    602 		return true;
    603 	}
    604 
    605 	hint_publish = dst_key_is_published(key, now, &publish);
    606 	hint_zsign = dst_key_is_signing(key, DST_BOOL_ZSK, now, &active);
    607 	hint_ksign = dst_key_is_signing(key, DST_BOOL_KSK, now, &active);
    608 	hint_revoke = dst_key_is_revoked(key, now, &revoke);
    609 	hint_remove = dst_key_is_removed(key, now, &remove);
    610 
    611 	if (hint_remove) {
    612 		return false;
    613 	}
    614 	if (hint_publish && hint_revoke) {
    615 		return true;
    616 	}
    617 	if (hint_zsign && zsk) {
    618 		return true;
    619 	}
    620 	if (hint_ksign && ksk) {
    621 		return true;
    622 	}
    623 	return false;
    624 }
    625 
    626 /*%<
    627  * Indicate whether a key is scheduled to have CDS/CDNSKEY records
    628  * published now.
    629  *
    630  * Returns true if.
    631  *  - kasp says the DS record should be published (e.g. the DS state is in
    632  *    RUMOURED or OMNIPRESENT state).
    633  * Or:
    634  *  - SyncPublish is set and in the past, AND
    635  *  - SyncDelete is unset or in the future
    636  */
    637 static bool
    638 syncpublish(dst_key_t *key, isc_stdtime_t now) {
    639 	isc_result_t result;
    640 	isc_stdtime_t when;
    641 	dst_key_state_t state;
    642 	int major, minor;
    643 	bool publish;
    644 
    645 	/*
    646 	 * Is this an old-style key?
    647 	 */
    648 	result = dst_key_getprivateformat(key, &major, &minor);
    649 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
    650 
    651 	/*
    652 	 * Smart signing started with key format 1.3
    653 	 */
    654 	if (major == 1 && minor <= 2) {
    655 		return false;
    656 	}
    657 
    658 	/* Check kasp state first. */
    659 	result = dst_key_getstate(key, DST_KEY_DS, &state);
    660 	if (result == ISC_R_SUCCESS) {
    661 		return state == DST_KEY_STATE_RUMOURED ||
    662 		       state == DST_KEY_STATE_OMNIPRESENT;
    663 	}
    664 
    665 	/* If no kasp state, check timings. */
    666 	publish = false;
    667 	result = dst_key_gettime(key, DST_TIME_SYNCPUBLISH, &when);
    668 	if (result == ISC_R_SUCCESS && when <= now) {
    669 		publish = true;
    670 	}
    671 	result = dst_key_gettime(key, DST_TIME_SYNCDELETE, &when);
    672 	if (result == ISC_R_SUCCESS && when < now) {
    673 		publish = false;
    674 	}
    675 	return publish;
    676 }
    677 
    678 /*%<
    679  * Indicate whether a key is scheduled to have CDS/CDNSKEY records
    680  * deleted now.
    681  *
    682  * Returns true if:
    683  *  - kasp says the DS record should be unpublished (e.g. the DS state is in
    684  *    UNRETENTIVE or HIDDEN state).
    685  * Or:
    686  * - SyncDelete is set and in the past.
    687  */
    688 static bool
    689 syncdelete(dst_key_t *key, isc_stdtime_t now) {
    690 	isc_result_t result;
    691 	isc_stdtime_t when;
    692 	dst_key_state_t state;
    693 	int major, minor;
    694 
    695 	/*
    696 	 * Is this an old-style key?
    697 	 */
    698 	result = dst_key_getprivateformat(key, &major, &minor);
    699 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
    700 
    701 	/*
    702 	 * Smart signing started with key format 1.3.
    703 	 */
    704 	if (major == 1 && minor <= 2) {
    705 		return false;
    706 	}
    707 
    708 	/* Check kasp state first. */
    709 	result = dst_key_getstate(key, DST_KEY_DS, &state);
    710 	if (result == ISC_R_SUCCESS) {
    711 		return state == DST_KEY_STATE_UNRETENTIVE ||
    712 		       state == DST_KEY_STATE_HIDDEN;
    713 	}
    714 
    715 	/* If no kasp state, check timings. */
    716 	result = dst_key_gettime(key, DST_TIME_SYNCDELETE, &when);
    717 	if (result != ISC_R_SUCCESS) {
    718 		return false;
    719 	}
    720 	if (when <= now) {
    721 		return true;
    722 	}
    723 	return false;
    724 }
    725 
    726 #define is_zone_key(key) \
    727 	((dst_key_flags(key) & DNS_KEYFLAG_OWNERMASK) == DNS_KEYOWNER_ZONE)
    728 
    729 isc_result_t
    730 dns_dnssec_signmessage(dns_message_t *msg, dst_key_t *key) {
    731 	dns_rdata_sig_t sig; /* SIG(0) */
    732 	unsigned char data[512];
    733 	unsigned char header[DNS_MESSAGE_HEADERLEN];
    734 	isc_buffer_t headerbuf, databuf, sigbuf;
    735 	unsigned int sigsize;
    736 	isc_buffer_t *dynbuf = NULL;
    737 	dns_rdata_t *rdata;
    738 	dns_rdatalist_t *datalist;
    739 	dns_rdataset_t *dataset;
    740 	isc_region_t r;
    741 	isc_stdtime_t now;
    742 	dst_context_t *ctx = NULL;
    743 	isc_mem_t *mctx;
    744 	isc_result_t result;
    745 
    746 	REQUIRE(msg != NULL);
    747 	REQUIRE(key != NULL);
    748 
    749 	if (is_response(msg)) {
    750 		REQUIRE(msg->query.base != NULL);
    751 	}
    752 
    753 	mctx = msg->mctx;
    754 
    755 	memset(&sig, 0, sizeof(sig));
    756 
    757 	sig.mctx = mctx;
    758 	sig.common.rdclass = dns_rdataclass_any;
    759 	sig.common.rdtype = dns_rdatatype_sig; /* SIG(0) */
    760 	ISC_LINK_INIT(&sig.common, link);
    761 
    762 	sig.covered = 0;
    763 	sig.algorithm = dst_key_alg(key);
    764 	sig.labels = 0; /* the root name */
    765 	sig.originalttl = 0;
    766 
    767 	if (msg->fuzzing) {
    768 		now = msg->fuzztime;
    769 	} else {
    770 		now = isc_stdtime_now();
    771 	}
    772 	sig.timesigned = now - DNS_TSIG_FUDGE;
    773 	sig.timeexpire = now + DNS_TSIG_FUDGE;
    774 
    775 	sig.keyid = dst_key_id(key);
    776 
    777 	dns_name_init(&sig.signer, NULL);
    778 	dns_name_clone(dst_key_name(key), &sig.signer);
    779 
    780 	sig.siglen = 0;
    781 	sig.signature = NULL;
    782 
    783 	isc_buffer_init(&databuf, data, sizeof(data));
    784 
    785 	CHECK(dst_context_create(key, mctx, DNS_LOGCATEGORY_DNSSEC, true, 0,
    786 				 &ctx));
    787 
    788 	/*
    789 	 * Digest the fields of the SIG - we can cheat and use
    790 	 * dns_rdata_fromstruct.  Since siglen is 0, the digested data
    791 	 * is identical to dns format.
    792 	 */
    793 	CHECK(dns_rdata_fromstruct(NULL, dns_rdataclass_any,
    794 				   dns_rdatatype_sig /* SIG(0) */, &sig,
    795 				   &databuf));
    796 	isc_buffer_usedregion(&databuf, &r);
    797 	CHECK(dst_context_adddata(ctx, &r));
    798 
    799 	/*
    800 	 * If this is a response, digest the query.
    801 	 */
    802 	if (is_response(msg)) {
    803 		CHECK(dst_context_adddata(ctx, &msg->query));
    804 	}
    805 
    806 	/*
    807 	 * Digest the header.
    808 	 */
    809 	isc_buffer_init(&headerbuf, header, sizeof(header));
    810 	dns_message_renderheader(msg, &headerbuf);
    811 	isc_buffer_usedregion(&headerbuf, &r);
    812 	CHECK(dst_context_adddata(ctx, &r));
    813 
    814 	/*
    815 	 * Digest the remainder of the message.
    816 	 */
    817 	isc_buffer_usedregion(msg->buffer, &r);
    818 	isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
    819 	CHECK(dst_context_adddata(ctx, &r));
    820 
    821 	CHECK(dst_key_sigsize(key, &sigsize));
    822 	sig.siglen = sigsize;
    823 	sig.signature = isc_mem_get(mctx, sig.siglen);
    824 
    825 	isc_buffer_init(&sigbuf, sig.signature, sig.siglen);
    826 	CHECK(dst_context_sign(ctx, &sigbuf));
    827 	dst_context_destroy(&ctx);
    828 
    829 	rdata = NULL;
    830 	dns_message_gettemprdata(msg, &rdata);
    831 	isc_buffer_allocate(msg->mctx, &dynbuf, 1024);
    832 	CHECK(dns_rdata_fromstruct(rdata, dns_rdataclass_any,
    833 				   dns_rdatatype_sig /* SIG(0) */, &sig,
    834 				   dynbuf));
    835 
    836 	isc_mem_put(mctx, sig.signature, sig.siglen);
    837 
    838 	dns_message_takebuffer(msg, &dynbuf);
    839 
    840 	datalist = NULL;
    841 	dns_message_gettemprdatalist(msg, &datalist);
    842 	datalist->rdclass = dns_rdataclass_any;
    843 	datalist->type = dns_rdatatype_sig; /* SIG(0) */
    844 	ISC_LIST_APPEND(datalist->rdata, rdata, link);
    845 	dataset = NULL;
    846 	dns_message_gettemprdataset(msg, &dataset);
    847 	dns_rdatalist_tordataset(datalist, dataset);
    848 	msg->sig0 = dataset;
    849 
    850 	return ISC_R_SUCCESS;
    851 
    852 cleanup:
    853 	if (dynbuf != NULL) {
    854 		isc_buffer_free(&dynbuf);
    855 	}
    856 	if (sig.signature != NULL) {
    857 		isc_mem_put(mctx, sig.signature, sig.siglen);
    858 	}
    859 	if (ctx != NULL) {
    860 		dst_context_destroy(&ctx);
    861 	}
    862 
    863 	return result;
    864 }
    865 
    866 isc_result_t
    867 dns_dnssec_verifymessage(isc_buffer_t *source, dns_message_t *msg,
    868 			 dst_key_t *key) {
    869 	dns_rdata_sig_t sig; /* SIG(0) */
    870 	unsigned char header[DNS_MESSAGE_HEADERLEN];
    871 	dns_rdata_t rdata = DNS_RDATA_INIT;
    872 	isc_region_t r, source_r, sig_r, header_r;
    873 	isc_stdtime_t now;
    874 	dst_context_t *ctx = NULL;
    875 	isc_mem_t *mctx;
    876 	isc_result_t result;
    877 	uint16_t addcount, addcount_n;
    878 	bool signeedsfree = false;
    879 
    880 	REQUIRE(source != NULL);
    881 	REQUIRE(msg != NULL);
    882 	REQUIRE(key != NULL);
    883 
    884 	mctx = msg->mctx;
    885 
    886 	msg->verify_attempted = 1;
    887 	msg->verified_sig = 0;
    888 	msg->sig0status = dns_tsigerror_badsig;
    889 
    890 	if (is_response(msg)) {
    891 		if (msg->query.base == NULL) {
    892 			return DNS_R_UNEXPECTEDTSIG;
    893 		}
    894 	}
    895 
    896 	isc_buffer_usedregion(source, &source_r);
    897 
    898 	CHECK(dns_rdataset_first(msg->sig0));
    899 	dns_rdataset_current(msg->sig0, &rdata);
    900 
    901 	CHECK(dns_rdata_tostruct(&rdata, &sig, NULL));
    902 	signeedsfree = true;
    903 
    904 	if (sig.labels != 0) {
    905 		CHECK(DNS_R_SIGINVALID);
    906 	}
    907 
    908 	if (isc_serial_lt(sig.timeexpire, sig.timesigned)) {
    909 		msg->sig0status = dns_tsigerror_badtime;
    910 		CHECK(DNS_R_SIGINVALID);
    911 	}
    912 
    913 	if (msg->fuzzing) {
    914 		now = msg->fuzztime;
    915 	} else {
    916 		now = isc_stdtime_now();
    917 	}
    918 
    919 	if (isc_serial_lt((uint32_t)now, sig.timesigned)) {
    920 		msg->sig0status = dns_tsigerror_badtime;
    921 		CHECK(DNS_R_SIGFUTURE);
    922 	} else if (isc_serial_lt(sig.timeexpire, (uint32_t)now)) {
    923 		msg->sig0status = dns_tsigerror_badtime;
    924 		CHECK(DNS_R_SIGEXPIRED);
    925 	}
    926 
    927 	if (!dns_name_equal(dst_key_name(key), &sig.signer)) {
    928 		msg->sig0status = dns_tsigerror_badkey;
    929 		CHECK(DNS_R_SIGINVALID);
    930 	}
    931 
    932 	CHECK(dst_context_create(key, mctx, DNS_LOGCATEGORY_DNSSEC, false, 0,
    933 				 &ctx));
    934 
    935 	/*
    936 	 * Digest the SIG(0) record, except for the signature.
    937 	 */
    938 	dns_rdata_toregion(&rdata, &r);
    939 	r.length -= sig.siglen;
    940 	CHECK(dst_context_adddata(ctx, &r));
    941 
    942 	/*
    943 	 * If this is a response, digest the query.
    944 	 */
    945 	if (is_response(msg)) {
    946 		CHECK(dst_context_adddata(ctx, &msg->query));
    947 	}
    948 
    949 	/*
    950 	 * Extract the header.
    951 	 */
    952 	memmove(header, source_r.base, DNS_MESSAGE_HEADERLEN);
    953 
    954 	/*
    955 	 * Decrement the additional field counter.
    956 	 */
    957 	memmove(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
    958 	addcount_n = ntohs(addcount);
    959 	addcount = htons((uint16_t)(addcount_n - 1));
    960 	memmove(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);
    961 
    962 	/*
    963 	 * Digest the modified header.
    964 	 */
    965 	header_r.base = (unsigned char *)header;
    966 	header_r.length = DNS_MESSAGE_HEADERLEN;
    967 	CHECK(dst_context_adddata(ctx, &header_r));
    968 
    969 	/*
    970 	 * Digest all non-SIG(0) records.
    971 	 */
    972 	r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
    973 	r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN;
    974 	CHECK(dst_context_adddata(ctx, &r));
    975 
    976 	sig_r.base = sig.signature;
    977 	sig_r.length = sig.siglen;
    978 	result = dst_context_verify(ctx, &sig_r);
    979 	if (result != ISC_R_SUCCESS) {
    980 		msg->sig0status = dns_tsigerror_badsig;
    981 		goto cleanup;
    982 	}
    983 
    984 	msg->verified_sig = 1;
    985 	msg->sig0status = dns_rcode_noerror;
    986 
    987 	dst_context_destroy(&ctx);
    988 	dns_rdata_freestruct(&sig);
    989 
    990 	return ISC_R_SUCCESS;
    991 
    992 cleanup:
    993 	if (signeedsfree) {
    994 		dns_rdata_freestruct(&sig);
    995 	}
    996 	if (ctx != NULL) {
    997 		dst_context_destroy(&ctx);
    998 	}
    999 
   1000 	return result;
   1001 }
   1002 
   1003 /*%
   1004  * Does this key ('rdata') self sign the rrset ('rdataset')?
   1005  */
   1006 bool
   1007 dns_dnssec_selfsigns(dns_rdata_t *rdata, const dns_name_t *name,
   1008 		     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
   1009 		     bool ignoretime, isc_mem_t *mctx) {
   1010 	INSIST(rdataset->type == dns_rdatatype_key ||
   1011 	       rdataset->type == dns_rdatatype_dnskey);
   1012 	if (rdataset->type == dns_rdatatype_key) {
   1013 		INSIST(sigrdataset->type == dns_rdatatype_sig);
   1014 		INSIST(sigrdataset->covers == dns_rdatatype_key);
   1015 	} else {
   1016 		INSIST(sigrdataset->type == dns_rdatatype_rrsig);
   1017 		INSIST(sigrdataset->covers == dns_rdatatype_dnskey);
   1018 	}
   1019 
   1020 	return dns_dnssec_signs(rdata, name, rdataset, sigrdataset, ignoretime,
   1021 				mctx);
   1022 }
   1023 
   1024 bool
   1025 dns_dnssec_signs(dns_rdata_t *rdata, const dns_name_t *name,
   1026 		 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
   1027 		 bool ignoretime, isc_mem_t *mctx) {
   1028 	dst_key_t *dstkey = NULL;
   1029 	dns_keytag_t keytag;
   1030 	dns_rdata_dnskey_t key;
   1031 	dns_rdata_rrsig_t sig;
   1032 	dns_rdata_t sigrdata = DNS_RDATA_INIT;
   1033 	isc_result_t result;
   1034 
   1035 	INSIST(sigrdataset->type == dns_rdatatype_rrsig);
   1036 	if (sigrdataset->covers != rdataset->type) {
   1037 		return false;
   1038 	}
   1039 
   1040 	result = dns_dnssec_keyfromrdata(name, rdata, mctx, &dstkey);
   1041 	if (result != ISC_R_SUCCESS) {
   1042 		return false;
   1043 	}
   1044 	result = dns_rdata_tostruct(rdata, &key, NULL);
   1045 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   1046 
   1047 	keytag = dst_key_id(dstkey);
   1048 	for (result = dns_rdataset_first(sigrdataset); result == ISC_R_SUCCESS;
   1049 	     result = dns_rdataset_next(sigrdataset))
   1050 	{
   1051 		dns_rdata_reset(&sigrdata);
   1052 		dns_rdataset_current(sigrdataset, &sigrdata);
   1053 		result = dns_rdata_tostruct(&sigrdata, &sig, NULL);
   1054 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   1055 
   1056 		if (sig.algorithm == key.algorithm && sig.keyid == keytag) {
   1057 			result = dns_dnssec_verify(name, rdataset, dstkey,
   1058 						   ignoretime, 0, mctx,
   1059 						   &sigrdata, NULL);
   1060 			if (result == ISC_R_SUCCESS) {
   1061 				dst_key_free(&dstkey);
   1062 				return true;
   1063 			}
   1064 		}
   1065 	}
   1066 	dst_key_free(&dstkey);
   1067 	return false;
   1068 }
   1069 
   1070 void
   1071 dns_dnsseckey_create(isc_mem_t *mctx, dst_key_t **dstkey,
   1072 		     dns_dnsseckey_t **dkp) {
   1073 	isc_result_t result;
   1074 	dns_dnsseckey_t *dk;
   1075 	int major, minor;
   1076 
   1077 	REQUIRE(dkp != NULL && *dkp == NULL);
   1078 	dk = isc_mem_get(mctx, sizeof(dns_dnsseckey_t));
   1079 
   1080 	dk->key = *dstkey;
   1081 	*dstkey = NULL;
   1082 	dk->force_publish = false;
   1083 	dk->force_sign = false;
   1084 	dk->hint_publish = false;
   1085 	dk->hint_sign = false;
   1086 	dk->hint_revoke = false;
   1087 	dk->hint_remove = false;
   1088 	dk->first_sign = false;
   1089 	dk->is_active = false;
   1090 	dk->pubkey = false;
   1091 	dk->purge = false;
   1092 	dk->prepublish = 0;
   1093 	dk->source = dns_keysource_unknown;
   1094 	dk->index = 0;
   1095 
   1096 	/* KSK or ZSK? */
   1097 	result = dst_key_getbool(dk->key, DST_BOOL_KSK, &dk->ksk);
   1098 	if (result != ISC_R_SUCCESS) {
   1099 		dk->ksk = ((dst_key_flags(dk->key) & DNS_KEYFLAG_KSK) != 0);
   1100 	}
   1101 	result = dst_key_getbool(dk->key, DST_BOOL_ZSK, &dk->zsk);
   1102 	if (result != ISC_R_SUCCESS) {
   1103 		dk->zsk = ((dst_key_flags(dk->key) & DNS_KEYFLAG_KSK) == 0);
   1104 	}
   1105 
   1106 	/* Is this an old-style key? */
   1107 	result = dst_key_getprivateformat(dk->key, &major, &minor);
   1108 	INSIST(result == ISC_R_SUCCESS);
   1109 
   1110 	/* Smart signing started with key format 1.3 */
   1111 	dk->legacy = (major == 1 && minor <= 2);
   1112 
   1113 	ISC_LINK_INIT(dk, link);
   1114 	*dkp = dk;
   1115 }
   1116 
   1117 void
   1118 dns_dnsseckey_destroy(isc_mem_t *mctx, dns_dnsseckey_t **dkp) {
   1119 	dns_dnsseckey_t *dk;
   1120 
   1121 	REQUIRE(dkp != NULL && *dkp != NULL);
   1122 	dk = *dkp;
   1123 	*dkp = NULL;
   1124 	if (dk->key != NULL) {
   1125 		dst_key_free(&dk->key);
   1126 	}
   1127 	isc_mem_put(mctx, dk, sizeof(dns_dnsseckey_t));
   1128 }
   1129 
   1130 void
   1131 dns_dnssec_get_hints(dns_dnsseckey_t *key, isc_stdtime_t now) {
   1132 	isc_stdtime_t publish = 0, active = 0, revoke = 0, remove = 0;
   1133 
   1134 	REQUIRE(key != NULL && key->key != NULL);
   1135 
   1136 	key->hint_publish = dst_key_is_published(key->key, now, &publish);
   1137 	key->hint_sign = dst_key_is_signing(key->key, DST_BOOL_ZSK, now,
   1138 					    &active);
   1139 	key->hint_revoke = dst_key_is_revoked(key->key, now, &revoke);
   1140 	key->hint_remove = dst_key_is_removed(key->key, now, &remove);
   1141 
   1142 	/*
   1143 	 * Activation date is set (maybe in the future), but publication date
   1144 	 * isn't. Most likely the user wants to publish now and activate later.
   1145 	 * Most likely because this is true for most rollovers, except for:
   1146 	 * 1. The unpopular ZSK Double-RRSIG method.
   1147 	 * 2. When introducing a new algorithm.
   1148 	 * These two cases are rare enough that we will set hint_publish
   1149 	 * anyway when hint_sign is set, because BIND 9 natively does not
   1150 	 * support the ZSK Double-RRSIG method, and when introducing a new
   1151 	 * algorithm, we strive to publish its signatures and DNSKEY records
   1152 	 * at the same time.
   1153 	 */
   1154 	if (key->hint_sign && publish == 0) {
   1155 		key->hint_publish = true;
   1156 	}
   1157 
   1158 	/*
   1159 	 * If activation date is in the future, make note of how far off.
   1160 	 */
   1161 	if (key->hint_publish && active > now) {
   1162 		key->prepublish = active - now;
   1163 	}
   1164 
   1165 	/*
   1166 	 * Metadata says revoke.  If the key is published, we *have to* sign
   1167 	 * with it per RFC5011 -- even if it was not active before.
   1168 	 *
   1169 	 * If it hasn't already been done, we should also revoke it now.
   1170 	 */
   1171 	if (key->hint_publish && key->hint_revoke) {
   1172 		uint32_t flags;
   1173 		key->hint_sign = true;
   1174 		flags = dst_key_flags(key->key);
   1175 		if ((flags & DNS_KEYFLAG_REVOKE) == 0) {
   1176 			flags |= DNS_KEYFLAG_REVOKE;
   1177 			dst_key_setflags(key->key, flags);
   1178 		}
   1179 	}
   1180 
   1181 	/*
   1182 	 * Metadata says delete, so don't publish this key or sign with it
   1183 	 * (note that signatures of a removed key may still be reused).
   1184 	 */
   1185 	if (key->hint_remove) {
   1186 		key->hint_publish = false;
   1187 		key->hint_sign = false;
   1188 	}
   1189 }
   1190 
   1191 static isc_result_t
   1192 findmatchingkeys(const char *directory, bool rrtypekey, char *namebuf,
   1193 		 unsigned int len, isc_mem_t *mctx, isc_stdtime_t now,
   1194 		 dns_dnsseckeylist_t *list) {
   1195 	isc_result_t result;
   1196 	isc_dir_t dir;
   1197 	bool dir_open = false, match = false;
   1198 	unsigned int i;
   1199 	dns_dnsseckey_t *key = NULL;
   1200 	dst_key_t *dstkey = NULL;
   1201 
   1202 	isc_dir_init(&dir);
   1203 	if (directory == NULL) {
   1204 		directory = ".";
   1205 	}
   1206 
   1207 	CHECK(isc_dir_open(&dir, directory));
   1208 	dir_open = true;
   1209 
   1210 	while (isc_dir_read(&dir) == ISC_R_SUCCESS) {
   1211 		if (dir.entry.name[0] != 'K' || dir.entry.length < len + 1 ||
   1212 		    dir.entry.name[len + 1] != '+' ||
   1213 		    strncasecmp(dir.entry.name + 1, namebuf, len) != 0)
   1214 		{
   1215 			continue;
   1216 		}
   1217 
   1218 		for (i = len + 1 + 1; i < dir.entry.length; i++) {
   1219 			if (!isdigit((unsigned char)dir.entry.name[i])) {
   1220 				break;
   1221 			}
   1222 		}
   1223 
   1224 		/*
   1225 		 * Did we not read exactly 3 digits?
   1226 		 * Did we overflow?
   1227 		 * Did we correctly terminate?
   1228 		 */
   1229 		if (i != len + 1 + 1 + 3 || i >= dir.entry.length ||
   1230 		    dir.entry.name[i] != '+')
   1231 		{
   1232 			continue;
   1233 		}
   1234 
   1235 		for (i++; i < dir.entry.length; i++) {
   1236 			if (!isdigit((unsigned char)dir.entry.name[i])) {
   1237 				break;
   1238 			}
   1239 		}
   1240 
   1241 		/*
   1242 		 * Did we not read exactly 5 more digits?
   1243 		 * Did we overflow?
   1244 		 * Did we correctly terminate?
   1245 		 */
   1246 		if (i != len + 1 + 1 + 3 + 1 + 5 || i >= dir.entry.length ||
   1247 		    strcmp(dir.entry.name + i, ".private") != 0)
   1248 		{
   1249 			continue;
   1250 		}
   1251 
   1252 		int type = DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | DST_TYPE_STATE;
   1253 		if (rrtypekey) {
   1254 			type |= DST_TYPE_KEY;
   1255 		}
   1256 		dstkey = NULL;
   1257 		result = dst_key_fromnamedfile(dir.entry.name, directory, type,
   1258 					       mctx, &dstkey);
   1259 		if (result == DST_R_BADKEYTYPE) {
   1260 			continue;
   1261 		}
   1262 		if (result != ISC_R_SUCCESS) {
   1263 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
   1264 				      DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
   1265 				      "dns_dnssec_findmatchingkeys: "
   1266 				      "error reading key file %s: %s",
   1267 				      dir.entry.name,
   1268 				      isc_result_totext(result));
   1269 			continue;
   1270 		}
   1271 
   1272 		dns_dnsseckey_create(mctx, &dstkey, &key);
   1273 		key->source = dns_keysource_repository;
   1274 		dns_dnssec_get_hints(key, now);
   1275 
   1276 		if (key->legacy) {
   1277 			dns_dnsseckey_destroy(mctx, &key);
   1278 		} else {
   1279 			ISC_LIST_APPEND(*list, key, link);
   1280 			match = true;
   1281 			key = NULL;
   1282 		}
   1283 	}
   1284 	result = match ? ISC_R_SUCCESS : ISC_R_NOTFOUND;
   1285 
   1286 cleanup:
   1287 	if (dir_open) {
   1288 		isc_dir_close(&dir);
   1289 	}
   1290 	if (dstkey != NULL) {
   1291 		dst_key_free(&dstkey);
   1292 	}
   1293 	return result;
   1294 }
   1295 
   1296 /*%
   1297  * Get a list of KEY or DNSKEY keys from the key repository. If rrtypekey
   1298  * is true KEY keys will be returned otherwise DNSSEC keys.
   1299  */
   1300 isc_result_t
   1301 dns_dnssec_findmatchingkeys(const dns_name_t *origin, dns_kasp_t *kasp,
   1302 			    const char *keydir, dns_keystorelist_t *keystores,
   1303 			    isc_stdtime_t now, bool rrtypekey, isc_mem_t *mctx,
   1304 			    dns_dnsseckeylist_t *keylist) {
   1305 	isc_result_t result = ISC_R_SUCCESS;
   1306 	dns_dnsseckeylist_t list;
   1307 	dns_dnsseckey_t *key = NULL;
   1308 	char namebuf[DNS_NAME_FORMATSIZE];
   1309 	isc_buffer_t b;
   1310 	unsigned int len;
   1311 
   1312 	REQUIRE(keylist != NULL);
   1313 	ISC_LIST_INIT(list);
   1314 
   1315 	isc_buffer_init(&b, namebuf, sizeof(namebuf) - 1);
   1316 	CHECK(dns_name_tofilenametext(origin, false, &b));
   1317 	len = isc_buffer_usedlength(&b);
   1318 	namebuf[len] = '\0';
   1319 
   1320 	if (kasp == NULL || (strcmp(dns_kasp_getname(kasp), "none") == 0) ||
   1321 	    (strcmp(dns_kasp_getname(kasp), "insecure") == 0))
   1322 	{
   1323 		CHECK(findmatchingkeys(keydir, rrtypekey, namebuf, len, mctx,
   1324 				       now, &list));
   1325 	} else if (keystores != NULL) {
   1326 		for (dns_keystore_t *keystore = ISC_LIST_HEAD(*keystores);
   1327 		     keystore != NULL; keystore = ISC_LIST_NEXT(keystore, link))
   1328 		{
   1329 			for (dns_kasp_key_t *kkey =
   1330 				     ISC_LIST_HEAD(dns_kasp_keys(kasp));
   1331 			     kkey != NULL; kkey = ISC_LIST_NEXT(kkey, link))
   1332 			{
   1333 				if (dns_kasp_key_keystore(kkey) == keystore) {
   1334 					const char *directory =
   1335 						dns_keystore_directory(keystore,
   1336 								       keydir);
   1337 					CHECK(findmatchingkeys(
   1338 						directory, rrtypekey, namebuf,
   1339 						len, mctx, now, &list));
   1340 					break;
   1341 				}
   1342 			}
   1343 		}
   1344 	}
   1345 
   1346 	if (!ISC_LIST_EMPTY(list)) {
   1347 		result = ISC_R_SUCCESS;
   1348 		ISC_LIST_APPENDLIST(*keylist, list, link);
   1349 	} else {
   1350 		result = ISC_R_NOTFOUND;
   1351 	}
   1352 
   1353 cleanup:
   1354 	while ((key = ISC_LIST_HEAD(list)) != NULL) {
   1355 		ISC_LIST_UNLINK(list, key, link);
   1356 		INSIST(key->key != NULL);
   1357 		dst_key_free(&key->key);
   1358 		dns_dnsseckey_destroy(mctx, &key);
   1359 	}
   1360 	return result;
   1361 }
   1362 
   1363 /*%
   1364  * Add 'newkey' to 'keylist' if it's not already there.
   1365  *
   1366  * If 'savekeys' is true, then we need to preserve all
   1367  * the keys in the keyset, regardless of whether they have
   1368  * metadata indicating they should be deactivated or removed.
   1369  */
   1370 static void
   1371 addkey(dns_dnsseckeylist_t *keylist, dst_key_t **newkey, bool savekeys,
   1372        bool pubkey_only, isc_mem_t *mctx) {
   1373 	dns_dnsseckey_t *key = NULL;
   1374 
   1375 	/* Skip duplicates */
   1376 	for (key = ISC_LIST_HEAD(*keylist); key != NULL;
   1377 	     key = ISC_LIST_NEXT(key, link))
   1378 	{
   1379 		if (dst_key_id(key->key) == dst_key_id(*newkey) &&
   1380 		    dst_key_alg(key->key) == dst_key_alg(*newkey) &&
   1381 		    dns_name_equal(dst_key_name(key->key),
   1382 				   dst_key_name(*newkey)))
   1383 		{
   1384 			break;
   1385 		}
   1386 	}
   1387 
   1388 	if (key != NULL) {
   1389 		/*
   1390 		 * Found a match. If we already had a private key, then
   1391 		 * the new key can't be an improvement. If the existing
   1392 		 * key was public-only but the new key is too, then it's
   1393 		 * still not an improvement. Mark the old key as having
   1394 		 * been found in the zone and stop.
   1395 		 */
   1396 		if (dst_key_isprivate(key->key) || !dst_key_isprivate(*newkey))
   1397 		{
   1398 			key->source = dns_keysource_zoneapex;
   1399 			return;
   1400 		}
   1401 
   1402 		/*
   1403 		 * However, if the old key was public-only, and the new key
   1404 		 * is private, then we're throwing away the old key.
   1405 		 */
   1406 		dst_key_free(&key->key);
   1407 		ISC_LIST_UNLINK(*keylist, key, link);
   1408 		dns_dnsseckey_destroy(mctx, &key);
   1409 	}
   1410 
   1411 	/* Store the new key. */
   1412 	dns_dnsseckey_create(mctx, newkey, &key);
   1413 	key->source = dns_keysource_zoneapex;
   1414 	key->pubkey = pubkey_only;
   1415 	if (key->legacy || savekeys) {
   1416 		key->force_publish = true;
   1417 		key->force_sign = dst_key_isprivate(key->key);
   1418 	}
   1419 	ISC_LIST_APPEND(*keylist, key, link);
   1420 	*newkey = NULL;
   1421 }
   1422 
   1423 /*%
   1424  * Mark all keys which signed the DNSKEY/SOA RRsets as "active",
   1425  * for future reference.
   1426  */
   1427 static isc_result_t
   1428 mark_active_keys(dns_dnsseckeylist_t *keylist, dns_rdataset_t *rrsigs) {
   1429 	isc_result_t result = ISC_R_SUCCESS;
   1430 	dns_rdata_t rdata = DNS_RDATA_INIT;
   1431 	dns_rdataset_t sigs;
   1432 	dns_dnsseckey_t *key;
   1433 
   1434 	REQUIRE(rrsigs != NULL && dns_rdataset_isassociated(rrsigs));
   1435 
   1436 	dns_rdataset_init(&sigs);
   1437 	dns_rdataset_clone(rrsigs, &sigs);
   1438 	for (key = ISC_LIST_HEAD(*keylist); key != NULL;
   1439 	     key = ISC_LIST_NEXT(key, link))
   1440 	{
   1441 		uint16_t keyid, sigid;
   1442 		dns_secalg_t keyalg, sigalg;
   1443 		keyid = dst_key_id(key->key);
   1444 		keyalg = dst_key_alg(key->key);
   1445 
   1446 		for (result = dns_rdataset_first(&sigs);
   1447 		     result == ISC_R_SUCCESS; result = dns_rdataset_next(&sigs))
   1448 		{
   1449 			dns_rdata_rrsig_t sig;
   1450 
   1451 			dns_rdata_reset(&rdata);
   1452 			dns_rdataset_current(&sigs, &rdata);
   1453 			result = dns_rdata_tostruct(&rdata, &sig, NULL);
   1454 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
   1455 			sigalg = sig.algorithm;
   1456 			sigid = sig.keyid;
   1457 			if (keyid == sigid && keyalg == sigalg) {
   1458 				key->is_active = true;
   1459 				break;
   1460 			}
   1461 		}
   1462 	}
   1463 
   1464 	if (result == ISC_R_NOMORE) {
   1465 		result = ISC_R_SUCCESS;
   1466 	}
   1467 
   1468 	if (dns_rdataset_isassociated(&sigs)) {
   1469 		dns_rdataset_disassociate(&sigs);
   1470 	}
   1471 	return result;
   1472 }
   1473 
   1474 static isc_result_t
   1475 keyfromfile(dns_kasp_t *kasp, const char *keydir, dst_key_t *key, int type,
   1476 	    isc_mem_t *mctx, dst_key_t **savekey) {
   1477 	const char *directory = keydir;
   1478 	isc_result_t result = ISC_R_NOTFOUND;
   1479 
   1480 	if (kasp == NULL || (strcmp(dns_kasp_getname(kasp), "none") == 0) ||
   1481 	    (strcmp(dns_kasp_getname(kasp), "insecure") == 0))
   1482 	{
   1483 		result = dst_key_fromfile(dst_key_name(key), dst_key_id(key),
   1484 					  dst_key_alg(key), type, directory,
   1485 					  mctx, savekey);
   1486 	} else {
   1487 		for (dns_kasp_key_t *kkey = ISC_LIST_HEAD(dns_kasp_keys(kasp));
   1488 		     kkey != NULL; kkey = ISC_LIST_NEXT(kkey, link))
   1489 		{
   1490 			dns_keystore_t *ks = dns_kasp_key_keystore(kkey);
   1491 			directory = dns_keystore_directory(ks, keydir);
   1492 			result = dst_key_fromfile(dst_key_name(key),
   1493 						  dst_key_id(key),
   1494 						  dst_key_alg(key), type,
   1495 						  directory, mctx, savekey);
   1496 			if (result == ISC_R_SUCCESS) {
   1497 				break;
   1498 			}
   1499 		}
   1500 	}
   1501 
   1502 	return result;
   1503 }
   1504 
   1505 /*%
   1506  * Add the contents of a DNSKEY rdataset 'keyset' to 'keylist'.
   1507  */
   1508 isc_result_t
   1509 dns_dnssec_keylistfromrdataset(const dns_name_t *origin, dns_kasp_t *kasp,
   1510 			       const char *directory, isc_mem_t *mctx,
   1511 			       dns_rdataset_t *keyset, dns_rdataset_t *keysigs,
   1512 			       dns_rdataset_t *soasigs, bool savekeys,
   1513 			       bool publickey, dns_dnsseckeylist_t *keylist) {
   1514 	dns_rdataset_t keys;
   1515 	dns_rdata_t rdata = DNS_RDATA_INIT;
   1516 	dst_key_t *dnskey = NULL, *pubkey = NULL, *privkey = NULL;
   1517 	isc_result_t result;
   1518 
   1519 	REQUIRE(keyset != NULL && dns_rdataset_isassociated(keyset));
   1520 
   1521 	dns_rdataset_init(&keys);
   1522 
   1523 	dns_rdataset_clone(keyset, &keys);
   1524 	for (result = dns_rdataset_first(&keys); result == ISC_R_SUCCESS;
   1525 	     result = dns_rdataset_next(&keys))
   1526 	{
   1527 		dns_rdata_reset(&rdata);
   1528 		dns_rdataset_current(&keys, &rdata);
   1529 
   1530 		REQUIRE(rdata.type == dns_rdatatype_key ||
   1531 			rdata.type == dns_rdatatype_dnskey);
   1532 		REQUIRE(rdata.length > 3);
   1533 
   1534 		/* Skip unsupported algorithms */
   1535 		if (!dst_algorithm_supported(rdata.data[3])) {
   1536 			goto skip;
   1537 		}
   1538 
   1539 		CHECK(dns_dnssec_keyfromrdata(origin, &rdata, mctx, &dnskey));
   1540 		dst_key_setttl(dnskey, keys.ttl);
   1541 
   1542 		if (!is_zone_key(dnskey)) {
   1543 			goto skip;
   1544 		}
   1545 
   1546 		/* Corrupted .key file? */
   1547 		if (!dns_name_equal(origin, dst_key_name(dnskey))) {
   1548 			goto skip;
   1549 		}
   1550 
   1551 		if (publickey) {
   1552 			addkey(keylist, &dnskey, savekeys, true, mctx);
   1553 			goto skip;
   1554 		}
   1555 
   1556 		/* Try to read the public key. */
   1557 		result = keyfromfile(kasp, directory, dnskey,
   1558 				     DST_TYPE_PUBLIC | DST_TYPE_STATE, mctx,
   1559 				     &pubkey);
   1560 		if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) {
   1561 			result = ISC_R_SUCCESS;
   1562 		}
   1563 		CHECK(result);
   1564 
   1565 		if (kasp != NULL && dns_kasp_offlineksk(kasp) &&
   1566 		    (dst_key_flags(dnskey) & DNS_KEYFLAG_KSK) != 0)
   1567 		{
   1568 			result = ISC_R_NOPERM;
   1569 			goto addkey;
   1570 		}
   1571 
   1572 		/* Now read the private key. */
   1573 		result = keyfromfile(kasp, directory, dnskey,
   1574 				     DST_TYPE_PUBLIC | DST_TYPE_PRIVATE |
   1575 					     DST_TYPE_STATE,
   1576 				     mctx, &privkey);
   1577 
   1578 		/*
   1579 		 * If the key was revoked and the private file
   1580 		 * doesn't exist, maybe it was revoked internally
   1581 		 * by named.  Try loading the unrevoked version.
   1582 		 */
   1583 		if (result == ISC_R_FILENOTFOUND) {
   1584 			uint32_t flags;
   1585 			flags = dst_key_flags(dnskey);
   1586 			if ((flags & DNS_KEYFLAG_REVOKE) != 0) {
   1587 				dst_key_setflags(dnskey,
   1588 						 flags & ~DNS_KEYFLAG_REVOKE);
   1589 				result = keyfromfile(kasp, directory, dnskey,
   1590 						     DST_TYPE_PUBLIC |
   1591 							     DST_TYPE_PRIVATE |
   1592 							     DST_TYPE_STATE,
   1593 						     mctx, &privkey);
   1594 				if (result == ISC_R_SUCCESS &&
   1595 				    dst_key_pubcompare(dnskey, privkey, false))
   1596 				{
   1597 					dst_key_setflags(privkey, flags);
   1598 				}
   1599 				dst_key_setflags(dnskey, flags);
   1600 			}
   1601 		}
   1602 
   1603 		if (result != ISC_R_SUCCESS) {
   1604 			char filename[DNS_NAME_FORMATSIZE +
   1605 				      DNS_SECALG_FORMATSIZE +
   1606 				      sizeof("key file for //65535")];
   1607 			isc_result_t result2;
   1608 			isc_buffer_t buf;
   1609 
   1610 			isc_buffer_init(&buf, filename, NAME_MAX);
   1611 			result2 = dst_key_getfilename(
   1612 				dst_key_name(dnskey), dst_key_id(dnskey),
   1613 				dst_key_alg(dnskey),
   1614 				DST_TYPE_PUBLIC | DST_TYPE_PRIVATE |
   1615 					DST_TYPE_STATE,
   1616 				NULL, mctx, &buf);
   1617 			if (result2 != ISC_R_SUCCESS) {
   1618 				char namebuf[DNS_NAME_FORMATSIZE];
   1619 				char algbuf[DNS_SECALG_FORMATSIZE];
   1620 
   1621 				dns_name_format(dst_key_name(dnskey), namebuf,
   1622 						sizeof(namebuf));
   1623 				dns_secalg_format(dst_key_alg(dnskey), algbuf,
   1624 						  sizeof(algbuf));
   1625 				snprintf(filename, sizeof(filename) - 1,
   1626 					 "key file for %s/%s/%d", namebuf,
   1627 					 algbuf, dst_key_id(dnskey));
   1628 			}
   1629 
   1630 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
   1631 				      DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
   1632 				      "dns_dnssec_keylistfromrdataset: error "
   1633 				      "reading %s: %s",
   1634 				      filename, isc_result_totext(result));
   1635 		}
   1636 
   1637 	addkey:
   1638 		if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) {
   1639 			if (pubkey != NULL) {
   1640 				addkey(keylist, &pubkey, savekeys, true, mctx);
   1641 			} else {
   1642 				addkey(keylist, &dnskey, savekeys, false, mctx);
   1643 			}
   1644 			goto skip;
   1645 		}
   1646 		CHECK(result);
   1647 
   1648 		/*
   1649 		 * Whatever the key's default TTL may have
   1650 		 * been, the rdataset TTL takes priority.
   1651 		 */
   1652 		dst_key_setttl(privkey, dst_key_getttl(dnskey));
   1653 
   1654 		addkey(keylist, &privkey, savekeys, false, mctx);
   1655 	skip:
   1656 		if (dnskey != NULL) {
   1657 			dst_key_free(&dnskey);
   1658 		}
   1659 		if (pubkey != NULL) {
   1660 			dst_key_free(&pubkey);
   1661 		}
   1662 		if (privkey != NULL) {
   1663 			dst_key_free(&privkey);
   1664 		}
   1665 	}
   1666 
   1667 	if (result != ISC_R_NOMORE) {
   1668 		RETERR(result);
   1669 	}
   1670 
   1671 	if (keysigs != NULL && dns_rdataset_isassociated(keysigs)) {
   1672 		CHECK(mark_active_keys(keylist, keysigs));
   1673 	}
   1674 
   1675 	if (soasigs != NULL && dns_rdataset_isassociated(soasigs)) {
   1676 		CHECK(mark_active_keys(keylist, soasigs));
   1677 	}
   1678 
   1679 	result = ISC_R_SUCCESS;
   1680 
   1681 cleanup:
   1682 	if (dns_rdataset_isassociated(&keys)) {
   1683 		dns_rdataset_disassociate(&keys);
   1684 	}
   1685 	if (dnskey != NULL) {
   1686 		dst_key_free(&dnskey);
   1687 	}
   1688 	if (pubkey != NULL) {
   1689 		dst_key_free(&pubkey);
   1690 	}
   1691 	if (privkey != NULL) {
   1692 		dst_key_free(&privkey);
   1693 	}
   1694 	return result;
   1695 }
   1696 
   1697 isc_result_t
   1698 dns_dnssec_make_dnskey(dst_key_t *key, unsigned char *buf, int bufsize,
   1699 		       dns_rdata_t *target) {
   1700 	isc_result_t result;
   1701 	isc_buffer_t b;
   1702 	isc_region_t r;
   1703 
   1704 	isc_buffer_init(&b, buf, bufsize);
   1705 	result = dst_key_todns(key, &b);
   1706 	if (result != ISC_R_SUCCESS) {
   1707 		return result;
   1708 	}
   1709 
   1710 	dns_rdata_reset(target);
   1711 	isc_buffer_usedregion(&b, &r);
   1712 	dns_rdata_fromregion(target, dst_key_class(key), dns_rdatatype_dnskey,
   1713 			     &r);
   1714 	return ISC_R_SUCCESS;
   1715 }
   1716 
   1717 static isc_result_t
   1718 addrdata(dns_rdata_t *rdata, dns_diff_t *diff, const dns_name_t *origin,
   1719 	 dns_ttl_t ttl, isc_mem_t *mctx) {
   1720 	dns_difftuple_t *tuple = NULL;
   1721 
   1722 	RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_ADD, origin, ttl, rdata,
   1723 				    &tuple));
   1724 	dns_diff_appendminimal(diff, &tuple);
   1725 
   1726 	return ISC_R_SUCCESS;
   1727 }
   1728 
   1729 static isc_result_t
   1730 delrdata(dns_rdata_t *rdata, dns_diff_t *diff, const dns_name_t *origin,
   1731 	 dns_ttl_t ttl, isc_mem_t *mctx) {
   1732 	dns_difftuple_t *tuple = NULL;
   1733 
   1734 	RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_DEL, origin, ttl, rdata,
   1735 				    &tuple));
   1736 	dns_diff_appendminimal(diff, &tuple);
   1737 
   1738 	return ISC_R_SUCCESS;
   1739 }
   1740 
   1741 static isc_result_t
   1742 publish_key(dns_diff_t *diff, dns_dnsseckey_t *key, const dns_name_t *origin,
   1743 	    dns_ttl_t ttl, isc_mem_t *mctx,
   1744 	    void (*report)(const char *, ...) ISC_FORMAT_PRINTF(1, 2)) {
   1745 	isc_result_t result;
   1746 	unsigned char buf[DST_KEY_MAXSIZE];
   1747 	char keystr[DST_KEY_FORMATSIZE];
   1748 	dns_rdata_t dnskey = DNS_RDATA_INIT;
   1749 
   1750 	dns_rdata_reset(&dnskey);
   1751 	CHECK(dns_dnssec_make_dnskey(key->key, buf, sizeof(buf), &dnskey));
   1752 	dst_key_format(key->key, keystr, sizeof(keystr));
   1753 
   1754 	report("Fetching %s (%s) from key %s.", keystr,
   1755 	       key->ksk ? (key->zsk ? "CSK" : "KSK") : "ZSK",
   1756 	       key->source == dns_keysource_user ? "file" : "repository");
   1757 
   1758 	if (key->prepublish && ttl > key->prepublish) {
   1759 		isc_stdtime_t now;
   1760 
   1761 		report("Key %s: Delaying activation to match the DNSKEY TTL "
   1762 		       "(%u).",
   1763 		       keystr, ttl);
   1764 
   1765 		now = isc_stdtime_now();
   1766 		dst_key_settime(key->key, DST_TIME_ACTIVATE, now + ttl);
   1767 	}
   1768 
   1769 	/* publish key */
   1770 	result = addrdata(&dnskey, diff, origin, ttl, mctx);
   1771 
   1772 cleanup:
   1773 	return result;
   1774 }
   1775 
   1776 static isc_result_t
   1777 remove_key(dns_diff_t *diff, dns_dnsseckey_t *key, const dns_name_t *origin,
   1778 	   dns_ttl_t ttl, isc_mem_t *mctx, const char *reason,
   1779 	   void (*report)(const char *, ...) ISC_FORMAT_PRINTF(1, 2)) {
   1780 	isc_result_t result;
   1781 	unsigned char buf[DST_KEY_MAXSIZE];
   1782 	dns_rdata_t dnskey = DNS_RDATA_INIT;
   1783 	char alg[80];
   1784 	char namebuf[DNS_NAME_FORMATSIZE];
   1785 
   1786 	dns_secalg_format(dst_key_alg(key->key), alg, sizeof(alg));
   1787 	dns_name_format(dst_key_name(key->key), namebuf, sizeof(namebuf));
   1788 	report("Removing %s key %s/%d/%s from DNSKEY RRset.", reason, namebuf,
   1789 	       dst_key_id(key->key), alg);
   1790 
   1791 	CHECK(dns_dnssec_make_dnskey(key->key, buf, sizeof(buf), &dnskey));
   1792 	result = delrdata(&dnskey, diff, origin, ttl, mctx);
   1793 
   1794 cleanup:
   1795 	return result;
   1796 }
   1797 
   1798 static bool
   1799 exists(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
   1800 	isc_result_t result;
   1801 	dns_rdataset_t trdataset;
   1802 
   1803 	dns_rdataset_init(&trdataset);
   1804 	dns_rdataset_clone(rdataset, &trdataset);
   1805 	for (result = dns_rdataset_first(&trdataset); result == ISC_R_SUCCESS;
   1806 	     result = dns_rdataset_next(&trdataset))
   1807 	{
   1808 		dns_rdata_t current = DNS_RDATA_INIT;
   1809 
   1810 		dns_rdataset_current(&trdataset, &current);
   1811 		if (dns_rdata_compare(rdata, &current) == 0) {
   1812 			dns_rdataset_disassociate(&trdataset);
   1813 			return true;
   1814 		}
   1815 	}
   1816 	dns_rdataset_disassociate(&trdataset);
   1817 	return false;
   1818 }
   1819 
   1820 static isc_result_t
   1821 add_cds(dns_dnsseckey_t *key, dns_rdata_t *keyrdata, const char *keystr,
   1822 	dns_rdataset_t *cds, unsigned int digesttype, dns_ttl_t ttl,
   1823 	dns_diff_t *diff, isc_mem_t *mctx) {
   1824 	isc_result_t r = ISC_R_SUCCESS;
   1825 	unsigned char dsbuf[DNS_DS_BUFFERSIZE];
   1826 	dns_rdata_t cdsrdata = DNS_RDATA_INIT;
   1827 	dns_name_t *origin = dst_key_name(key->key);
   1828 
   1829 	r = dns_ds_buildrdata(origin, keyrdata, digesttype, dsbuf, &cdsrdata);
   1830 	if (r != ISC_R_SUCCESS) {
   1831 		char algbuf[DNS_DSDIGEST_FORMATSIZE];
   1832 		dns_dsdigest_format(digesttype, algbuf,
   1833 				    DNS_DSDIGEST_FORMATSIZE);
   1834 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
   1835 			      DNS_LOGMODULE_DNSSEC, ISC_LOG_ERROR,
   1836 			      "build rdata CDS (%s) for key %s failed", algbuf,
   1837 			      keystr);
   1838 		return r;
   1839 	}
   1840 
   1841 	cdsrdata.type = dns_rdatatype_cds;
   1842 	if (!dns_rdataset_isassociated(cds) || !exists(cds, &cdsrdata)) {
   1843 		char algbuf[DNS_DSDIGEST_FORMATSIZE];
   1844 		dns_dsdigest_format(digesttype, algbuf,
   1845 				    DNS_DSDIGEST_FORMATSIZE);
   1846 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
   1847 			      DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
   1848 			      "CDS (%s) for key %s is now published", algbuf,
   1849 			      keystr);
   1850 		r = addrdata(&cdsrdata, diff, origin, ttl, mctx);
   1851 	}
   1852 	return r;
   1853 }
   1854 
   1855 static isc_result_t
   1856 delete_cds(dns_dnsseckey_t *key, dns_rdata_t *keyrdata, const char *keystr,
   1857 	   dns_rdataset_t *cds, unsigned int digesttype, dns_diff_t *diff,
   1858 	   isc_mem_t *mctx) {
   1859 	isc_result_t r = ISC_R_SUCCESS;
   1860 	unsigned char dsbuf[DNS_DS_BUFFERSIZE];
   1861 	dns_rdata_t cdsrdata = DNS_RDATA_INIT;
   1862 	dns_name_t *origin = dst_key_name(key->key);
   1863 
   1864 	r = dns_ds_buildrdata(origin, keyrdata, digesttype, dsbuf, &cdsrdata);
   1865 	if (r != ISC_R_SUCCESS) {
   1866 		return r;
   1867 	}
   1868 
   1869 	cdsrdata.type = dns_rdatatype_cds;
   1870 	if (exists(cds, &cdsrdata)) {
   1871 		char algbuf[DNS_DSDIGEST_FORMATSIZE];
   1872 		dns_dsdigest_format(digesttype, algbuf,
   1873 				    DNS_DSDIGEST_FORMATSIZE);
   1874 		isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
   1875 			      DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
   1876 			      "CDS (%s) for key %s is now deleted", algbuf,
   1877 			      keystr);
   1878 		r = delrdata(&cdsrdata, diff, origin, cds->ttl, mctx);
   1879 	}
   1880 	return r;
   1881 }
   1882 
   1883 isc_result_t
   1884 dns_dnssec_syncupdate(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *rmkeys,
   1885 		      dns_rdataset_t *cds, dns_rdataset_t *cdnskey,
   1886 		      isc_stdtime_t now, dns_kasp_digestlist_t *digests,
   1887 		      bool gencdnskey, dns_ttl_t ttl, dns_diff_t *diff,
   1888 		      isc_mem_t *mctx) {
   1889 	unsigned char keybuf[DST_KEY_MAXSIZE];
   1890 	isc_result_t result;
   1891 	dns_dnsseckey_t *key;
   1892 	dns_ttl_t cdsttl = ttl;
   1893 	dns_ttl_t cdnskeyttl = ttl;
   1894 
   1895 	REQUIRE(digests != NULL);
   1896 	REQUIRE(keys != NULL);
   1897 	REQUIRE(rmkeys != NULL);
   1898 
   1899 	if (dns_rdataset_isassociated(cds)) {
   1900 		cdsttl = cds->ttl;
   1901 	}
   1902 
   1903 	if (dns_rdataset_isassociated(cdnskey)) {
   1904 		cdnskeyttl = cdnskey->ttl;
   1905 	}
   1906 
   1907 	for (key = ISC_LIST_HEAD(*keys); key != NULL;
   1908 	     key = ISC_LIST_NEXT(key, link))
   1909 	{
   1910 		dns_rdata_t cdnskeyrdata = DNS_RDATA_INIT;
   1911 		dns_name_t *origin = dst_key_name(key->key);
   1912 
   1913 		CHECK(dns_dnssec_make_dnskey(key->key, keybuf, sizeof(keybuf),
   1914 					     &cdnskeyrdata));
   1915 		cdnskeyrdata.type = dns_rdatatype_cdnskey;
   1916 
   1917 		if (syncpublish(key->key, now)) {
   1918 			char keystr[DST_KEY_FORMATSIZE];
   1919 			dst_key_format(key->key, keystr, sizeof(keystr));
   1920 
   1921 			for (dns_kasp_digest_t *alg = ISC_LIST_HEAD(*digests);
   1922 			     alg != NULL; alg = ISC_LIST_NEXT(alg, link))
   1923 			{
   1924 				CHECK(add_cds(key, &cdnskeyrdata,
   1925 					      (const char *)keystr, cds,
   1926 					      alg->digest, cdsttl, diff, mctx));
   1927 			}
   1928 
   1929 			if (gencdnskey &&
   1930 			    (!dns_rdataset_isassociated(cdnskey) ||
   1931 			     !exists(cdnskey, &cdnskeyrdata)))
   1932 			{
   1933 				isc_log_write(
   1934 					dns_lctx, DNS_LOGCATEGORY_GENERAL,
   1935 					DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
   1936 					"CDNSKEY for key %s is now published",
   1937 					keystr);
   1938 				RETERR(addrdata(&cdnskeyrdata, diff, origin,
   1939 						cdnskeyttl, mctx));
   1940 			}
   1941 		}
   1942 
   1943 		if (syncdelete(key->key, now)) {
   1944 			char keystr[DST_KEY_FORMATSIZE];
   1945 			dst_key_format(key->key, keystr, sizeof(keystr));
   1946 
   1947 			if (dns_rdataset_isassociated(cds)) {
   1948 				/* Delete all possible CDS records */
   1949 				delete_cds(key, &cdnskeyrdata,
   1950 					   (const char *)keystr, cds,
   1951 					   DNS_DSDIGEST_SHA1, diff, mctx);
   1952 				delete_cds(key, &cdnskeyrdata,
   1953 					   (const char *)keystr, cds,
   1954 					   DNS_DSDIGEST_SHA256, diff, mctx);
   1955 				delete_cds(key, &cdnskeyrdata,
   1956 					   (const char *)keystr, cds,
   1957 					   DNS_DSDIGEST_SHA384, diff, mctx);
   1958 			}
   1959 
   1960 			if (dns_rdataset_isassociated(cdnskey)) {
   1961 				if (exists(cdnskey, &cdnskeyrdata)) {
   1962 					isc_log_write(dns_lctx,
   1963 						      DNS_LOGCATEGORY_GENERAL,
   1964 						      DNS_LOGMODULE_DNSSEC,
   1965 						      ISC_LOG_INFO,
   1966 						      "CDNSKEY for key %s is "
   1967 						      "now deleted",
   1968 						      keystr);
   1969 					RETERR(delrdata(&cdnskeyrdata, diff,
   1970 							origin, cdnskey->ttl,
   1971 							mctx));
   1972 				}
   1973 			}
   1974 		}
   1975 	}
   1976 
   1977 	if (!dns_rdataset_isassociated(cds) &&
   1978 	    !dns_rdataset_isassociated(cdnskey))
   1979 	{
   1980 		return ISC_R_SUCCESS;
   1981 	}
   1982 
   1983 	/*
   1984 	 * Unconditionally remove CDS/DNSKEY records for removed keys.
   1985 	 */
   1986 	for (key = ISC_LIST_HEAD(*rmkeys); key != NULL;
   1987 	     key = ISC_LIST_NEXT(key, link))
   1988 	{
   1989 		dns_rdata_t cdnskeyrdata = DNS_RDATA_INIT;
   1990 		dns_name_t *origin = dst_key_name(key->key);
   1991 
   1992 		char keystr[DST_KEY_FORMATSIZE];
   1993 		dst_key_format(key->key, keystr, sizeof(keystr));
   1994 
   1995 		CHECK(dns_dnssec_make_dnskey(key->key, keybuf, sizeof(keybuf),
   1996 					     &cdnskeyrdata));
   1997 
   1998 		if (dns_rdataset_isassociated(cds)) {
   1999 			delete_cds(key, &cdnskeyrdata, (const char *)keystr,
   2000 				   cds, DNS_DSDIGEST_SHA1, diff, mctx);
   2001 			delete_cds(key, &cdnskeyrdata, (const char *)keystr,
   2002 				   cds, DNS_DSDIGEST_SHA256, diff, mctx);
   2003 			delete_cds(key, &cdnskeyrdata, (const char *)keystr,
   2004 				   cds, DNS_DSDIGEST_SHA384, diff, mctx);
   2005 		}
   2006 
   2007 		if (dns_rdataset_isassociated(cdnskey)) {
   2008 			if (exists(cdnskey, &cdnskeyrdata)) {
   2009 				isc_log_write(
   2010 					dns_lctx, DNS_LOGCATEGORY_GENERAL,
   2011 					DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
   2012 					"CDNSKEY for key %s is now deleted",
   2013 					keystr);
   2014 				RETERR(delrdata(&cdnskeyrdata, diff, origin,
   2015 						cdnskey->ttl, mctx));
   2016 			}
   2017 		}
   2018 	}
   2019 
   2020 	result = ISC_R_SUCCESS;
   2021 
   2022 cleanup:
   2023 	return result;
   2024 }
   2025 
   2026 isc_result_t
   2027 dns_dnssec_syncdelete(dns_rdataset_t *cds, dns_rdataset_t *cdnskey,
   2028 		      dns_name_t *origin, dns_rdataclass_t zclass,
   2029 		      dns_ttl_t ttl, dns_diff_t *diff, isc_mem_t *mctx,
   2030 		      bool expect_cds_delete, bool expect_cdnskey_delete) {
   2031 	unsigned char dsbuf[5] = { 0, 0, 0, 0, 0 };  /* CDS DELETE rdata */
   2032 	unsigned char keybuf[5] = { 0, 0, 3, 0, 0 }; /* CDNSKEY DELETE rdata */
   2033 	char namebuf[DNS_NAME_FORMATSIZE];
   2034 	dns_rdata_t cds_delete = DNS_RDATA_INIT;
   2035 	dns_rdata_t cdnskey_delete = DNS_RDATA_INIT;
   2036 	isc_region_t r;
   2037 
   2038 	r.base = keybuf;
   2039 	r.length = sizeof(keybuf);
   2040 	dns_rdata_fromregion(&cdnskey_delete, zclass, dns_rdatatype_cdnskey,
   2041 			     &r);
   2042 
   2043 	r.base = dsbuf;
   2044 	r.length = sizeof(dsbuf);
   2045 	dns_rdata_fromregion(&cds_delete, zclass, dns_rdatatype_cds, &r);
   2046 
   2047 	dns_name_format(origin, namebuf, sizeof(namebuf));
   2048 
   2049 	if (expect_cds_delete) {
   2050 		if (!dns_rdataset_isassociated(cds) ||
   2051 		    !exists(cds, &cds_delete))
   2052 		{
   2053 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
   2054 				      DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
   2055 				      "CDS (DELETE) for zone %s is now "
   2056 				      "published",
   2057 				      namebuf);
   2058 			RETERR(addrdata(&cds_delete, diff, origin, ttl, mctx));
   2059 		}
   2060 	} else {
   2061 		if (dns_rdataset_isassociated(cds) && exists(cds, &cds_delete))
   2062 		{
   2063 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
   2064 				      DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
   2065 				      "CDS (DELETE) for zone %s is now "
   2066 				      "deleted",
   2067 				      namebuf);
   2068 			RETERR(delrdata(&cds_delete, diff, origin, cds->ttl,
   2069 					mctx));
   2070 		}
   2071 	}
   2072 
   2073 	if (expect_cdnskey_delete) {
   2074 		if (!dns_rdataset_isassociated(cdnskey) ||
   2075 		    !exists(cdnskey, &cdnskey_delete))
   2076 		{
   2077 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
   2078 				      DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
   2079 				      "CDNSKEY (DELETE) for zone %s is now "
   2080 				      "published",
   2081 				      namebuf);
   2082 			RETERR(addrdata(&cdnskey_delete, diff, origin, ttl,
   2083 					mctx));
   2084 		}
   2085 	} else {
   2086 		if (dns_rdataset_isassociated(cdnskey) &&
   2087 		    exists(cdnskey, &cdnskey_delete))
   2088 		{
   2089 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
   2090 				      DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
   2091 				      "CDNSKEY (DELETE) for zone %s is now "
   2092 				      "deleted",
   2093 				      namebuf);
   2094 			RETERR(delrdata(&cdnskey_delete, diff, origin,
   2095 					cdnskey->ttl, mctx));
   2096 		}
   2097 	}
   2098 
   2099 	return ISC_R_SUCCESS;
   2100 }
   2101 
   2102 /*
   2103  * Update 'keys' with information from 'newkeys'.
   2104  *
   2105  * If 'removed' is not NULL, any keys that are being removed from
   2106  * the zone will be added to the list for post-removal processing.
   2107  */
   2108 isc_result_t
   2109 dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys,
   2110 		      dns_dnsseckeylist_t *removed, const dns_name_t *origin,
   2111 		      dns_ttl_t hint_ttl, dns_diff_t *diff, isc_mem_t *mctx,
   2112 		      void (*report)(const char *, ...)
   2113 			      ISC_FORMAT_PRINTF(1, 2)) {
   2114 	isc_result_t result;
   2115 	dns_dnsseckey_t *key, *key1, *key2, *next;
   2116 	bool found_ttl = false;
   2117 	dns_ttl_t ttl = hint_ttl;
   2118 
   2119 	/*
   2120 	 * First, look through the existing key list to find keys
   2121 	 * supplied from the command line which are not in the zone.
   2122 	 * Update the zone to include them.
   2123 	 *
   2124 	 * Also, if there are keys published in the zone already,
   2125 	 * use their TTL for all subsequent published keys.
   2126 	 */
   2127 	for (key = ISC_LIST_HEAD(*keys); key != NULL;
   2128 	     key = ISC_LIST_NEXT(key, link))
   2129 	{
   2130 		if (key->source == dns_keysource_user &&
   2131 		    (key->hint_publish || key->force_publish))
   2132 		{
   2133 			CHECK(publish_key(diff, key, origin, ttl, mctx,
   2134 					  report));
   2135 		}
   2136 		if (key->source == dns_keysource_zoneapex) {
   2137 			ttl = dst_key_getttl(key->key);
   2138 			found_ttl = true;
   2139 		}
   2140 	}
   2141 
   2142 	/*
   2143 	 * If there were no existing keys, use the smallest nonzero
   2144 	 * TTL of the keys found in the repository.
   2145 	 */
   2146 	if (!found_ttl && !ISC_LIST_EMPTY(*newkeys)) {
   2147 		dns_ttl_t shortest = 0;
   2148 
   2149 		for (key = ISC_LIST_HEAD(*newkeys); key != NULL;
   2150 		     key = ISC_LIST_NEXT(key, link))
   2151 		{
   2152 			dns_ttl_t thisttl = dst_key_getttl(key->key);
   2153 			if (thisttl != 0 &&
   2154 			    (shortest == 0 || thisttl < shortest))
   2155 			{
   2156 				shortest = thisttl;
   2157 			}
   2158 		}
   2159 
   2160 		if (shortest != 0) {
   2161 			ttl = shortest;
   2162 		}
   2163 	}
   2164 
   2165 	/*
   2166 	 * Second, scan the list of newly found keys looking for matches
   2167 	 * with known keys, and update accordingly.
   2168 	 */
   2169 	for (key1 = ISC_LIST_HEAD(*newkeys); key1 != NULL; key1 = next) {
   2170 		bool key_revoked = false;
   2171 		char keystr1[DST_KEY_FORMATSIZE];
   2172 		char keystr2[DST_KEY_FORMATSIZE];
   2173 
   2174 		next = ISC_LIST_NEXT(key1, link);
   2175 
   2176 		for (key2 = ISC_LIST_HEAD(*keys); key2 != NULL;
   2177 		     key2 = ISC_LIST_NEXT(key2, link))
   2178 		{
   2179 			int f1 = dst_key_flags(key1->key);
   2180 			int f2 = dst_key_flags(key2->key);
   2181 			int nr1 = f1 & ~DNS_KEYFLAG_REVOKE;
   2182 			int nr2 = f2 & ~DNS_KEYFLAG_REVOKE;
   2183 			if (nr1 == nr2 &&
   2184 			    dst_key_alg(key1->key) == dst_key_alg(key2->key) &&
   2185 			    dst_key_pubcompare(key1->key, key2->key, true))
   2186 			{
   2187 				int r1, r2;
   2188 				r1 = dst_key_flags(key1->key) &
   2189 				     DNS_KEYFLAG_REVOKE;
   2190 				r2 = dst_key_flags(key2->key) &
   2191 				     DNS_KEYFLAG_REVOKE;
   2192 				key_revoked = (r1 != r2);
   2193 				break;
   2194 			}
   2195 		}
   2196 
   2197 		/* Printable version of key1 (the newly acquired key) */
   2198 		dst_key_format(key1->key, keystr1, sizeof(keystr1));
   2199 
   2200 		/* No match found in keys; add the new key. */
   2201 		if (key2 == NULL) {
   2202 			ISC_LIST_UNLINK(*newkeys, key1, link);
   2203 			ISC_LIST_APPEND(*keys, key1, link);
   2204 
   2205 			if (key1->source != dns_keysource_zoneapex &&
   2206 			    (key1->hint_publish || key1->force_publish))
   2207 			{
   2208 				CHECK(publish_key(diff, key1, origin, ttl, mctx,
   2209 						  report));
   2210 				isc_log_write(
   2211 					dns_lctx, DNS_LOGCATEGORY_DNSSEC,
   2212 					DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
   2213 					"DNSKEY %s (%s) is now published",
   2214 					keystr1,
   2215 					key1->ksk ? (key1->zsk ? "CSK" : "KSK")
   2216 						  : "ZSK");
   2217 				if (key1->hint_sign || key1->force_sign) {
   2218 					key1->first_sign = true;
   2219 					isc_log_write(
   2220 						dns_lctx,
   2221 						DNS_LOGCATEGORY_DNSSEC,
   2222 						DNS_LOGMODULE_DNSSEC,
   2223 						ISC_LOG_INFO,
   2224 						"DNSKEY %s (%s) is now "
   2225 						"active",
   2226 						keystr1,
   2227 						key1->ksk ? (key1->zsk ? "CSK"
   2228 								       : "KSK")
   2229 							  : "ZSK");
   2230 				}
   2231 			}
   2232 
   2233 			continue;
   2234 		}
   2235 
   2236 		/* Printable version of key2 (the old key, if any) */
   2237 		dst_key_format(key2->key, keystr2, sizeof(keystr2));
   2238 
   2239 		/* Copy key metadata. */
   2240 		dst_key_copy_metadata(key2->key, key1->key);
   2241 
   2242 		/* Match found: remove or update it as needed */
   2243 		if (key1->hint_remove) {
   2244 			CHECK(remove_key(diff, key2, origin, ttl, mctx,
   2245 					 "expired", report));
   2246 			ISC_LIST_UNLINK(*keys, key2, link);
   2247 
   2248 			if (removed != NULL) {
   2249 				ISC_LIST_APPEND(*removed, key2, link);
   2250 				isc_log_write(
   2251 					dns_lctx, DNS_LOGCATEGORY_DNSSEC,
   2252 					DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
   2253 					"DNSKEY %s (%s) is now deleted",
   2254 					keystr2,
   2255 					key2->ksk ? (key2->zsk ? "CSK" : "KSK")
   2256 						  : "ZSK");
   2257 			} else {
   2258 				dns_dnsseckey_destroy(mctx, &key2);
   2259 			}
   2260 		} else if (key_revoked &&
   2261 			   (dst_key_flags(key1->key) & DNS_KEYFLAG_REVOKE) != 0)
   2262 		{
   2263 			/*
   2264 			 * A previously valid key has been revoked.
   2265 			 * We need to remove the old version and pull
   2266 			 * in the new one.
   2267 			 */
   2268 			CHECK(remove_key(diff, key2, origin, ttl, mctx,
   2269 					 "revoked", report));
   2270 			ISC_LIST_UNLINK(*keys, key2, link);
   2271 			if (removed != NULL) {
   2272 				ISC_LIST_APPEND(*removed, key2, link);
   2273 				isc_log_write(
   2274 					dns_lctx, DNS_LOGCATEGORY_DNSSEC,
   2275 					DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
   2276 					"DNSKEY %s (%s) is now revoked; "
   2277 					"new ID is %05d",
   2278 					keystr2,
   2279 					key2->ksk ? (key2->zsk ? "CSK" : "KSK")
   2280 						  : "ZSK",
   2281 					dst_key_id(key1->key));
   2282 			} else {
   2283 				dns_dnsseckey_destroy(mctx, &key2);
   2284 			}
   2285 
   2286 			CHECK(publish_key(diff, key1, origin, ttl, mctx,
   2287 					  report));
   2288 			ISC_LIST_UNLINK(*newkeys, key1, link);
   2289 			ISC_LIST_APPEND(*keys, key1, link);
   2290 
   2291 			/*
   2292 			 * XXX: The revoke flag is only defined for trust
   2293 			 * anchors.  Setting the flag on a non-KSK is legal,
   2294 			 * but not defined in any RFC.  It seems reasonable
   2295 			 * to treat it the same as a KSK: keep it in the
   2296 			 * zone, sign the DNSKEY set with it, but not
   2297 			 * sign other records with it.
   2298 			 */
   2299 			key1->ksk = true;
   2300 			continue;
   2301 		} else {
   2302 			if (!key2->is_active &&
   2303 			    (key1->hint_sign || key1->force_sign))
   2304 			{
   2305 				key2->first_sign = true;
   2306 				isc_log_write(
   2307 					dns_lctx, DNS_LOGCATEGORY_DNSSEC,
   2308 					DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
   2309 					"DNSKEY %s (%s) is now active", keystr1,
   2310 					key1->ksk ? (key1->zsk ? "CSK" : "KSK")
   2311 						  : "ZSK");
   2312 			} else if (key2->is_active && !key1->hint_sign &&
   2313 				   !key1->force_sign)
   2314 			{
   2315 				isc_log_write(
   2316 					dns_lctx, DNS_LOGCATEGORY_DNSSEC,
   2317 					DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
   2318 					"DNSKEY %s (%s) is now inactive",
   2319 					keystr1,
   2320 					key1->ksk ? (key1->zsk ? "CSK" : "KSK")
   2321 						  : "ZSK");
   2322 			}
   2323 
   2324 			key2->hint_sign = key1->hint_sign;
   2325 			key2->hint_publish = key1->hint_publish;
   2326 		}
   2327 	}
   2328 
   2329 	/* Free any leftover keys in newkeys */
   2330 	while (!ISC_LIST_EMPTY(*newkeys)) {
   2331 		key1 = ISC_LIST_HEAD(*newkeys);
   2332 		ISC_LIST_UNLINK(*newkeys, key1, link);
   2333 		dns_dnsseckey_destroy(mctx, &key1);
   2334 	}
   2335 
   2336 	result = ISC_R_SUCCESS;
   2337 
   2338 cleanup:
   2339 	return result;
   2340 }
   2341 
   2342 isc_result_t
   2343 dns_dnssec_matchdskey(dns_name_t *name, dns_rdata_t *dsrdata,
   2344 		      dns_rdataset_t *keyset, dns_rdata_t *keyrdata) {
   2345 	isc_result_t result;
   2346 	unsigned char buf[DNS_DS_BUFFERSIZE];
   2347 	dns_keytag_t keytag;
   2348 	dns_rdata_dnskey_t key;
   2349 	dns_rdata_ds_t ds;
   2350 	isc_region_t r;
   2351 
   2352 	result = dns_rdata_tostruct(dsrdata, &ds, NULL);
   2353 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   2354 
   2355 	for (result = dns_rdataset_first(keyset); result == ISC_R_SUCCESS;
   2356 	     result = dns_rdataset_next(keyset))
   2357 	{
   2358 		dns_rdata_t newdsrdata = DNS_RDATA_INIT;
   2359 
   2360 		dns_rdata_reset(keyrdata);
   2361 		dns_rdataset_current(keyset, keyrdata);
   2362 
   2363 		result = dns_rdata_tostruct(keyrdata, &key, NULL);
   2364 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   2365 
   2366 		dns_rdata_toregion(keyrdata, &r);
   2367 		keytag = dst_region_computeid(&r);
   2368 
   2369 		if (ds.key_tag != keytag || ds.algorithm != key.algorithm) {
   2370 			continue;
   2371 		}
   2372 
   2373 		result = dns_ds_buildrdata(name, keyrdata, ds.digest_type, buf,
   2374 					   &newdsrdata);
   2375 		if (result != ISC_R_SUCCESS) {
   2376 			continue;
   2377 		}
   2378 
   2379 		if (dns_rdata_compare(dsrdata, &newdsrdata) == 0) {
   2380 			break;
   2381 		}
   2382 	}
   2383 	if (result == ISC_R_NOMORE) {
   2384 		result = ISC_R_NOTFOUND;
   2385 	}
   2386 
   2387 	return result;
   2388 }
   2389