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