xref: /netbsd/external/mpl/bind/dist/lib/dns/dnssec.c (revision 4ac1c27e)
1 /*	$NetBSD: dnssec.c,v 1.13 2023/01/25 21:43:30 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
digest_callback(void * arg,isc_region_t * data)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
inc_stat(isc_statscounter_t counter)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
rdata_compare_wrapper(const void * rdata1,const void * rdata2)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
rdataset_to_sortedarray(dns_rdataset_t * set,isc_mem_t * mctx,dns_rdata_t ** rdata,int * nrdata)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
dns_dnssec_keyfromrdata(const dns_name_t * name,const dns_rdata_t * rdata,isc_mem_t * mctx,dst_key_t ** key)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
digest_sig(dst_context_t * ctx,bool downcase,dns_rdata_t * sigrdata,dns_rdata_rrsig_t * rrsig)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
dns_dnssec_sign(const dns_name_t * name,dns_rdataset_t * set,dst_key_t * key,isc_stdtime_t * inception,isc_stdtime_t * expire,isc_mem_t * mctx,isc_buffer_t * buffer,dns_rdata_t * sigrdata)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
dns_dnssec_verify(const dns_name_t * name,dns_rdataset_t * set,dst_key_t * key,bool ignoretime,unsigned int maxbits,isc_mem_t * mctx,dns_rdata_t * sigrdata,dns_name_t * wild)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
dns_dnssec_keyactive(dst_key_t * key,isc_stdtime_t now)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
syncpublish(dst_key_t * key,isc_stdtime_t now)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
syncdelete(dst_key_t * key,isc_stdtime_t now)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
dns_dnssec_findzonekeys(dns_db_t * db,dns_dbversion_t * ver,dns_dbnode_t * node,const dns_name_t * name,const char * directory,isc_stdtime_t now,isc_mem_t * mctx,unsigned int maxkeys,dst_key_t ** keys,unsigned int * nkeys)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 		{
799 			goto next;
800 		}
801 		/* Corrupted .key file? */
802 		if (!dns_name_equal(name, dst_key_name(pubkey))) {
803 			goto next;
804 		}
805 		keys[count] = NULL;
806 		result = dst_key_fromfile(
807 			dst_key_name(pubkey), dst_key_id(pubkey),
808 			dst_key_alg(pubkey),
809 			DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | DST_TYPE_STATE,
810 			directory, mctx, &keys[count]);
811 
812 		/*
813 		 * If the key was revoked and the private file
814 		 * doesn't exist, maybe it was revoked internally
815 		 * by named.  Try loading the unrevoked version.
816 		 */
817 		if (result == ISC_R_FILENOTFOUND) {
818 			uint32_t flags;
819 			flags = dst_key_flags(pubkey);
820 			if ((flags & DNS_KEYFLAG_REVOKE) != 0) {
821 				dst_key_setflags(pubkey,
822 						 flags & ~DNS_KEYFLAG_REVOKE);
823 				result = dst_key_fromfile(
824 					dst_key_name(pubkey),
825 					dst_key_id(pubkey), dst_key_alg(pubkey),
826 					DST_TYPE_PUBLIC | DST_TYPE_PRIVATE |
827 						DST_TYPE_STATE,
828 					directory, mctx, &keys[count]);
829 				if (result == ISC_R_SUCCESS &&
830 				    dst_key_pubcompare(pubkey, keys[count],
831 						       false))
832 				{
833 					dst_key_setflags(keys[count], flags);
834 				}
835 				dst_key_setflags(pubkey, flags);
836 			}
837 		}
838 
839 		if (result != ISC_R_SUCCESS) {
840 			char filename[DNS_NAME_FORMATSIZE +
841 				      DNS_SECALG_FORMATSIZE +
842 				      sizeof("key file for //65535")];
843 			isc_result_t result2;
844 			isc_buffer_t buf;
845 
846 			isc_buffer_init(&buf, filename, NAME_MAX);
847 			result2 = dst_key_getfilename(
848 				dst_key_name(pubkey), dst_key_id(pubkey),
849 				dst_key_alg(pubkey),
850 				(DST_TYPE_PUBLIC | DST_TYPE_PRIVATE |
851 				 DST_TYPE_STATE),
852 				directory, mctx, &buf);
853 			if (result2 != ISC_R_SUCCESS) {
854 				char namebuf[DNS_NAME_FORMATSIZE];
855 				char algbuf[DNS_SECALG_FORMATSIZE];
856 
857 				dns_name_format(dst_key_name(pubkey), namebuf,
858 						sizeof(namebuf));
859 				dns_secalg_format(dst_key_alg(pubkey), algbuf,
860 						  sizeof(algbuf));
861 				snprintf(filename, sizeof(filename) - 1,
862 					 "key file for %s/%s/%d", namebuf,
863 					 algbuf, dst_key_id(pubkey));
864 			}
865 
866 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
867 				      DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
868 				      "dns_dnssec_findzonekeys2: error "
869 				      "reading %s: %s",
870 				      filename, isc_result_totext(result));
871 		}
872 
873 		if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) {
874 			keys[count] = pubkey;
875 			pubkey = NULL;
876 			count++;
877 			goto next;
878 		}
879 
880 		if (result != ISC_R_SUCCESS) {
881 			goto failure;
882 		}
883 
884 		/*
885 		 * If a key is marked inactive, skip it
886 		 */
887 		if (!dns_dnssec_keyactive(keys[count], now)) {
888 			dst_key_setinactive(pubkey, true);
889 			dst_key_free(&keys[count]);
890 			keys[count] = pubkey;
891 			pubkey = NULL;
892 			count++;
893 			goto next;
894 		}
895 
896 		/*
897 		 * Whatever the key's default TTL may have
898 		 * been, the rdataset TTL takes priority.
899 		 */
900 		dst_key_setttl(keys[count], rdataset.ttl);
901 
902 		if ((dst_key_flags(keys[count]) & DNS_KEYTYPE_NOAUTH) != 0) {
903 			/* We should never get here. */
904 			dst_key_free(&keys[count]);
905 			goto next;
906 		}
907 		count++;
908 	next:
909 		if (pubkey != NULL) {
910 			dst_key_free(&pubkey);
911 		}
912 		dns_rdata_reset(&rdata);
913 		result = dns_rdataset_next(&rdataset);
914 	}
915 	if (result != ISC_R_NOMORE) {
916 		goto failure;
917 	}
918 	if (count == 0) {
919 		result = ISC_R_NOTFOUND;
920 	} else {
921 		result = ISC_R_SUCCESS;
922 	}
923 
924 failure:
925 	if (dns_rdataset_isassociated(&rdataset)) {
926 		dns_rdataset_disassociate(&rdataset);
927 	}
928 	if (pubkey != NULL) {
929 		dst_key_free(&pubkey);
930 	}
931 	if (result != ISC_R_SUCCESS) {
932 		while (count > 0) {
933 			dst_key_free(&keys[--count]);
934 		}
935 	}
936 	*nkeys = count;
937 	return (result);
938 }
939 
940 isc_result_t
dns_dnssec_signmessage(dns_message_t * msg,dst_key_t * key)941 dns_dnssec_signmessage(dns_message_t *msg, dst_key_t *key) {
942 	dns_rdata_sig_t sig; /* SIG(0) */
943 	unsigned char data[512];
944 	unsigned char header[DNS_MESSAGE_HEADERLEN];
945 	isc_buffer_t headerbuf, databuf, sigbuf;
946 	unsigned int sigsize;
947 	isc_buffer_t *dynbuf = NULL;
948 	dns_rdata_t *rdata;
949 	dns_rdatalist_t *datalist;
950 	dns_rdataset_t *dataset;
951 	isc_region_t r;
952 	isc_stdtime_t now;
953 	dst_context_t *ctx = NULL;
954 	isc_mem_t *mctx;
955 	isc_result_t result;
956 
957 	REQUIRE(msg != NULL);
958 	REQUIRE(key != NULL);
959 
960 	if (is_response(msg)) {
961 		REQUIRE(msg->query.base != NULL);
962 	}
963 
964 	mctx = msg->mctx;
965 
966 	memset(&sig, 0, sizeof(sig));
967 
968 	sig.mctx = mctx;
969 	sig.common.rdclass = dns_rdataclass_any;
970 	sig.common.rdtype = dns_rdatatype_sig; /* SIG(0) */
971 	ISC_LINK_INIT(&sig.common, link);
972 
973 	sig.covered = 0;
974 	sig.algorithm = dst_key_alg(key);
975 	sig.labels = 0; /* the root name */
976 	sig.originalttl = 0;
977 
978 	isc_stdtime_get(&now);
979 	sig.timesigned = now - DNS_TSIG_FUDGE;
980 	sig.timeexpire = now + DNS_TSIG_FUDGE;
981 
982 	sig.keyid = dst_key_id(key);
983 
984 	dns_name_init(&sig.signer, NULL);
985 	dns_name_clone(dst_key_name(key), &sig.signer);
986 
987 	sig.siglen = 0;
988 	sig.signature = NULL;
989 
990 	isc_buffer_init(&databuf, data, sizeof(data));
991 
992 	RETERR(dst_context_create(key, mctx, DNS_LOGCATEGORY_DNSSEC, true, 0,
993 				  &ctx));
994 
995 	/*
996 	 * Digest the fields of the SIG - we can cheat and use
997 	 * dns_rdata_fromstruct.  Since siglen is 0, the digested data
998 	 * is identical to dns format.
999 	 */
1000 	RETERR(dns_rdata_fromstruct(NULL, dns_rdataclass_any,
1001 				    dns_rdatatype_sig /* SIG(0) */, &sig,
1002 				    &databuf));
1003 	isc_buffer_usedregion(&databuf, &r);
1004 	RETERR(dst_context_adddata(ctx, &r));
1005 
1006 	/*
1007 	 * If this is a response, digest the query.
1008 	 */
1009 	if (is_response(msg)) {
1010 		RETERR(dst_context_adddata(ctx, &msg->query));
1011 	}
1012 
1013 	/*
1014 	 * Digest the header.
1015 	 */
1016 	isc_buffer_init(&headerbuf, header, sizeof(header));
1017 	dns_message_renderheader(msg, &headerbuf);
1018 	isc_buffer_usedregion(&headerbuf, &r);
1019 	RETERR(dst_context_adddata(ctx, &r));
1020 
1021 	/*
1022 	 * Digest the remainder of the message.
1023 	 */
1024 	isc_buffer_usedregion(msg->buffer, &r);
1025 	isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
1026 	RETERR(dst_context_adddata(ctx, &r));
1027 
1028 	RETERR(dst_key_sigsize(key, &sigsize));
1029 	sig.siglen = sigsize;
1030 	sig.signature = isc_mem_get(mctx, sig.siglen);
1031 
1032 	isc_buffer_init(&sigbuf, sig.signature, sig.siglen);
1033 	RETERR(dst_context_sign(ctx, &sigbuf));
1034 	dst_context_destroy(&ctx);
1035 
1036 	rdata = NULL;
1037 	RETERR(dns_message_gettemprdata(msg, &rdata));
1038 	isc_buffer_allocate(msg->mctx, &dynbuf, 1024);
1039 	RETERR(dns_rdata_fromstruct(rdata, dns_rdataclass_any,
1040 				    dns_rdatatype_sig /* SIG(0) */, &sig,
1041 				    dynbuf));
1042 
1043 	isc_mem_put(mctx, sig.signature, sig.siglen);
1044 
1045 	dns_message_takebuffer(msg, &dynbuf);
1046 
1047 	datalist = NULL;
1048 	RETERR(dns_message_gettemprdatalist(msg, &datalist));
1049 	datalist->rdclass = dns_rdataclass_any;
1050 	datalist->type = dns_rdatatype_sig; /* SIG(0) */
1051 	ISC_LIST_APPEND(datalist->rdata, rdata, link);
1052 	dataset = NULL;
1053 	RETERR(dns_message_gettemprdataset(msg, &dataset));
1054 	RUNTIME_CHECK(dns_rdatalist_tordataset(datalist, dataset) ==
1055 		      ISC_R_SUCCESS);
1056 	msg->sig0 = dataset;
1057 
1058 	return (ISC_R_SUCCESS);
1059 
1060 failure:
1061 	if (dynbuf != NULL) {
1062 		isc_buffer_free(&dynbuf);
1063 	}
1064 	if (sig.signature != NULL) {
1065 		isc_mem_put(mctx, sig.signature, sig.siglen);
1066 	}
1067 	if (ctx != NULL) {
1068 		dst_context_destroy(&ctx);
1069 	}
1070 
1071 	return (result);
1072 }
1073 
1074 isc_result_t
dns_dnssec_verifymessage(isc_buffer_t * source,dns_message_t * msg,dst_key_t * key)1075 dns_dnssec_verifymessage(isc_buffer_t *source, dns_message_t *msg,
1076 			 dst_key_t *key) {
1077 	dns_rdata_sig_t sig; /* SIG(0) */
1078 	unsigned char header[DNS_MESSAGE_HEADERLEN];
1079 	dns_rdata_t rdata = DNS_RDATA_INIT;
1080 	isc_region_t r, source_r, sig_r, header_r;
1081 	isc_stdtime_t now;
1082 	dst_context_t *ctx = NULL;
1083 	isc_mem_t *mctx;
1084 	isc_result_t result;
1085 	uint16_t addcount, addcount_n;
1086 	bool signeedsfree = false;
1087 
1088 	REQUIRE(source != NULL);
1089 	REQUIRE(msg != NULL);
1090 	REQUIRE(key != NULL);
1091 
1092 	mctx = msg->mctx;
1093 
1094 	msg->verify_attempted = 1;
1095 	msg->verified_sig = 0;
1096 	msg->sig0status = dns_tsigerror_badsig;
1097 
1098 	if (is_response(msg)) {
1099 		if (msg->query.base == NULL) {
1100 			return (DNS_R_UNEXPECTEDTSIG);
1101 		}
1102 	}
1103 
1104 	isc_buffer_usedregion(source, &source_r);
1105 
1106 	RETERR(dns_rdataset_first(msg->sig0));
1107 	dns_rdataset_current(msg->sig0, &rdata);
1108 
1109 	RETERR(dns_rdata_tostruct(&rdata, &sig, NULL));
1110 	signeedsfree = true;
1111 
1112 	if (sig.labels != 0) {
1113 		result = DNS_R_SIGINVALID;
1114 		goto failure;
1115 	}
1116 
1117 	if (isc_serial_lt(sig.timeexpire, sig.timesigned)) {
1118 		result = DNS_R_SIGINVALID;
1119 		msg->sig0status = dns_tsigerror_badtime;
1120 		goto failure;
1121 	}
1122 
1123 	isc_stdtime_get(&now);
1124 	if (isc_serial_lt((uint32_t)now, sig.timesigned)) {
1125 		result = DNS_R_SIGFUTURE;
1126 		msg->sig0status = dns_tsigerror_badtime;
1127 		goto failure;
1128 	} else if (isc_serial_lt(sig.timeexpire, (uint32_t)now)) {
1129 		result = DNS_R_SIGEXPIRED;
1130 		msg->sig0status = dns_tsigerror_badtime;
1131 		goto failure;
1132 	}
1133 
1134 	if (!dns_name_equal(dst_key_name(key), &sig.signer)) {
1135 		result = DNS_R_SIGINVALID;
1136 		msg->sig0status = dns_tsigerror_badkey;
1137 		goto failure;
1138 	}
1139 
1140 	RETERR(dst_context_create(key, mctx, DNS_LOGCATEGORY_DNSSEC, false, 0,
1141 				  &ctx));
1142 
1143 	/*
1144 	 * Digest the SIG(0) record, except for the signature.
1145 	 */
1146 	dns_rdata_toregion(&rdata, &r);
1147 	r.length -= sig.siglen;
1148 	RETERR(dst_context_adddata(ctx, &r));
1149 
1150 	/*
1151 	 * If this is a response, digest the query.
1152 	 */
1153 	if (is_response(msg)) {
1154 		RETERR(dst_context_adddata(ctx, &msg->query));
1155 	}
1156 
1157 	/*
1158 	 * Extract the header.
1159 	 */
1160 	memmove(header, source_r.base, DNS_MESSAGE_HEADERLEN);
1161 
1162 	/*
1163 	 * Decrement the additional field counter.
1164 	 */
1165 	memmove(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
1166 	addcount_n = ntohs(addcount);
1167 	addcount = htons((uint16_t)(addcount_n - 1));
1168 	memmove(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);
1169 
1170 	/*
1171 	 * Digest the modified header.
1172 	 */
1173 	header_r.base = (unsigned char *)header;
1174 	header_r.length = DNS_MESSAGE_HEADERLEN;
1175 	RETERR(dst_context_adddata(ctx, &header_r));
1176 
1177 	/*
1178 	 * Digest all non-SIG(0) records.
1179 	 */
1180 	r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
1181 	r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN;
1182 	RETERR(dst_context_adddata(ctx, &r));
1183 
1184 	sig_r.base = sig.signature;
1185 	sig_r.length = sig.siglen;
1186 	result = dst_context_verify(ctx, &sig_r);
1187 	if (result != ISC_R_SUCCESS) {
1188 		msg->sig0status = dns_tsigerror_badsig;
1189 		goto failure;
1190 	}
1191 
1192 	msg->verified_sig = 1;
1193 	msg->sig0status = dns_rcode_noerror;
1194 
1195 	dst_context_destroy(&ctx);
1196 	dns_rdata_freestruct(&sig);
1197 
1198 	return (ISC_R_SUCCESS);
1199 
1200 failure:
1201 	if (signeedsfree) {
1202 		dns_rdata_freestruct(&sig);
1203 	}
1204 	if (ctx != NULL) {
1205 		dst_context_destroy(&ctx);
1206 	}
1207 
1208 	return (result);
1209 }
1210 
1211 /*%
1212  * Does this key ('rdata') self sign the rrset ('rdataset')?
1213  */
1214 bool
dns_dnssec_selfsigns(dns_rdata_t * rdata,const dns_name_t * name,dns_rdataset_t * rdataset,dns_rdataset_t * sigrdataset,bool ignoretime,isc_mem_t * mctx)1215 dns_dnssec_selfsigns(dns_rdata_t *rdata, const dns_name_t *name,
1216 		     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
1217 		     bool ignoretime, isc_mem_t *mctx) {
1218 	INSIST(rdataset->type == dns_rdatatype_key ||
1219 	       rdataset->type == dns_rdatatype_dnskey);
1220 	if (rdataset->type == dns_rdatatype_key) {
1221 		INSIST(sigrdataset->type == dns_rdatatype_sig);
1222 		INSIST(sigrdataset->covers == dns_rdatatype_key);
1223 	} else {
1224 		INSIST(sigrdataset->type == dns_rdatatype_rrsig);
1225 		INSIST(sigrdataset->covers == dns_rdatatype_dnskey);
1226 	}
1227 
1228 	return (dns_dnssec_signs(rdata, name, rdataset, sigrdataset, ignoretime,
1229 				 mctx));
1230 }
1231 
1232 bool
dns_dnssec_signs(dns_rdata_t * rdata,const dns_name_t * name,dns_rdataset_t * rdataset,dns_rdataset_t * sigrdataset,bool ignoretime,isc_mem_t * mctx)1233 dns_dnssec_signs(dns_rdata_t *rdata, const dns_name_t *name,
1234 		 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
1235 		 bool ignoretime, isc_mem_t *mctx) {
1236 	dst_key_t *dstkey = NULL;
1237 	dns_keytag_t keytag;
1238 	dns_rdata_dnskey_t key;
1239 	dns_rdata_rrsig_t sig;
1240 	dns_rdata_t sigrdata = DNS_RDATA_INIT;
1241 	isc_result_t result;
1242 
1243 	INSIST(sigrdataset->type == dns_rdatatype_rrsig);
1244 	if (sigrdataset->covers != rdataset->type) {
1245 		return (false);
1246 	}
1247 
1248 	result = dns_dnssec_keyfromrdata(name, rdata, mctx, &dstkey);
1249 	if (result != ISC_R_SUCCESS) {
1250 		return (false);
1251 	}
1252 	result = dns_rdata_tostruct(rdata, &key, NULL);
1253 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
1254 
1255 	keytag = dst_key_id(dstkey);
1256 	for (result = dns_rdataset_first(sigrdataset); result == ISC_R_SUCCESS;
1257 	     result = dns_rdataset_next(sigrdataset))
1258 	{
1259 		dns_rdata_reset(&sigrdata);
1260 		dns_rdataset_current(sigrdataset, &sigrdata);
1261 		result = dns_rdata_tostruct(&sigrdata, &sig, NULL);
1262 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
1263 
1264 		if (sig.algorithm == key.algorithm && sig.keyid == keytag) {
1265 			result = dns_dnssec_verify(name, rdataset, dstkey,
1266 						   ignoretime, 0, mctx,
1267 						   &sigrdata, NULL);
1268 			if (result == ISC_R_SUCCESS) {
1269 				dst_key_free(&dstkey);
1270 				return (true);
1271 			}
1272 		}
1273 	}
1274 	dst_key_free(&dstkey);
1275 	return (false);
1276 }
1277 
1278 isc_result_t
dns_dnsseckey_create(isc_mem_t * mctx,dst_key_t ** dstkey,dns_dnsseckey_t ** dkp)1279 dns_dnsseckey_create(isc_mem_t *mctx, dst_key_t **dstkey,
1280 		     dns_dnsseckey_t **dkp) {
1281 	isc_result_t result;
1282 	dns_dnsseckey_t *dk;
1283 	int major, minor;
1284 
1285 	REQUIRE(dkp != NULL && *dkp == NULL);
1286 	dk = isc_mem_get(mctx, sizeof(dns_dnsseckey_t));
1287 
1288 	dk->key = *dstkey;
1289 	*dstkey = NULL;
1290 	dk->force_publish = false;
1291 	dk->force_sign = false;
1292 	dk->hint_publish = false;
1293 	dk->hint_sign = false;
1294 	dk->hint_revoke = false;
1295 	dk->hint_remove = false;
1296 	dk->first_sign = false;
1297 	dk->is_active = false;
1298 	dk->purge = false;
1299 	dk->prepublish = 0;
1300 	dk->source = dns_keysource_unknown;
1301 	dk->index = 0;
1302 
1303 	/* KSK or ZSK? */
1304 	result = dst_key_getbool(dk->key, DST_BOOL_KSK, &dk->ksk);
1305 	if (result != ISC_R_SUCCESS) {
1306 		dk->ksk = ((dst_key_flags(dk->key) & DNS_KEYFLAG_KSK) != 0);
1307 	}
1308 	result = dst_key_getbool(dk->key, DST_BOOL_ZSK, &dk->zsk);
1309 	if (result != ISC_R_SUCCESS) {
1310 		dk->zsk = ((dst_key_flags(dk->key) & DNS_KEYFLAG_KSK) == 0);
1311 	}
1312 
1313 	/* Is this an old-style key? */
1314 	result = dst_key_getprivateformat(dk->key, &major, &minor);
1315 	INSIST(result == ISC_R_SUCCESS);
1316 
1317 	/* Smart signing started with key format 1.3 */
1318 	dk->legacy = (major == 1 && minor <= 2);
1319 
1320 	ISC_LINK_INIT(dk, link);
1321 	*dkp = dk;
1322 	return (ISC_R_SUCCESS);
1323 }
1324 
1325 void
dns_dnsseckey_destroy(isc_mem_t * mctx,dns_dnsseckey_t ** dkp)1326 dns_dnsseckey_destroy(isc_mem_t *mctx, dns_dnsseckey_t **dkp) {
1327 	dns_dnsseckey_t *dk;
1328 
1329 	REQUIRE(dkp != NULL && *dkp != NULL);
1330 	dk = *dkp;
1331 	*dkp = NULL;
1332 	if (dk->key != NULL) {
1333 		dst_key_free(&dk->key);
1334 	}
1335 	isc_mem_put(mctx, dk, sizeof(dns_dnsseckey_t));
1336 }
1337 
1338 void
dns_dnssec_get_hints(dns_dnsseckey_t * key,isc_stdtime_t now)1339 dns_dnssec_get_hints(dns_dnsseckey_t *key, isc_stdtime_t now) {
1340 	isc_stdtime_t publish = 0, active = 0, revoke = 0, remove = 0;
1341 
1342 	REQUIRE(key != NULL && key->key != NULL);
1343 
1344 	key->hint_publish = dst_key_is_published(key->key, now, &publish);
1345 	key->hint_sign = dst_key_is_signing(key->key, DST_BOOL_ZSK, now,
1346 					    &active);
1347 	key->hint_revoke = dst_key_is_revoked(key->key, now, &revoke);
1348 	key->hint_remove = dst_key_is_removed(key->key, now, &remove);
1349 
1350 	/*
1351 	 * Activation date is set (maybe in the future), but publication date
1352 	 * isn't. Most likely the user wants to publish now and activate later.
1353 	 * Most likely because this is true for most rollovers, except for:
1354 	 * 1. The unpopular ZSK Double-RRSIG method.
1355 	 * 2. When introducing a new algorithm.
1356 	 * These two cases are rare enough that we will set hint_publish
1357 	 * anyway when hint_sign is set, because BIND 9 natively does not
1358 	 * support the ZSK Double-RRSIG method, and when introducing a new
1359 	 * algorithm, we strive to publish its signatures and DNSKEY records
1360 	 * at the same time.
1361 	 */
1362 	if (key->hint_sign && publish == 0) {
1363 		key->hint_publish = true;
1364 	}
1365 
1366 	/*
1367 	 * If activation date is in the future, make note of how far off.
1368 	 */
1369 	if (key->hint_publish && active > now) {
1370 		key->prepublish = active - now;
1371 	}
1372 
1373 	/*
1374 	 * Metadata says revoke.  If the key is published, we *have to* sign
1375 	 * with it per RFC5011 -- even if it was not active before.
1376 	 *
1377 	 * If it hasn't already been done, we should also revoke it now.
1378 	 */
1379 	if (key->hint_publish && key->hint_revoke) {
1380 		uint32_t flags;
1381 		key->hint_sign = true;
1382 		flags = dst_key_flags(key->key);
1383 		if ((flags & DNS_KEYFLAG_REVOKE) == 0) {
1384 			flags |= DNS_KEYFLAG_REVOKE;
1385 			dst_key_setflags(key->key, flags);
1386 		}
1387 	}
1388 
1389 	/*
1390 	 * Metadata says delete, so don't publish this key or sign with it
1391 	 * (note that signatures of a removed key may still be reused).
1392 	 */
1393 	if (key->hint_remove) {
1394 		key->hint_publish = false;
1395 		key->hint_sign = false;
1396 	}
1397 }
1398 
1399 /*%
1400  * Get a list of DNSSEC keys from the key repository.
1401  */
1402 isc_result_t
dns_dnssec_findmatchingkeys(const dns_name_t * origin,const char * directory,isc_stdtime_t now,isc_mem_t * mctx,dns_dnsseckeylist_t * keylist)1403 dns_dnssec_findmatchingkeys(const dns_name_t *origin, const char *directory,
1404 			    isc_stdtime_t now, isc_mem_t *mctx,
1405 			    dns_dnsseckeylist_t *keylist) {
1406 	isc_result_t result = ISC_R_SUCCESS;
1407 	bool dir_open = false;
1408 	dns_dnsseckeylist_t list;
1409 	isc_dir_t dir;
1410 	dns_dnsseckey_t *key = NULL;
1411 	dst_key_t *dstkey = NULL;
1412 	char namebuf[DNS_NAME_FORMATSIZE];
1413 	isc_buffer_t b;
1414 	unsigned int len, i, alg;
1415 
1416 	REQUIRE(keylist != NULL);
1417 	ISC_LIST_INIT(list);
1418 	isc_dir_init(&dir);
1419 
1420 	isc_buffer_init(&b, namebuf, sizeof(namebuf) - 1);
1421 	RETERR(dns_name_tofilenametext(origin, false, &b));
1422 	len = isc_buffer_usedlength(&b);
1423 	namebuf[len] = '\0';
1424 
1425 	if (directory == NULL) {
1426 		directory = ".";
1427 	}
1428 	RETERR(isc_dir_open(&dir, directory));
1429 	dir_open = true;
1430 
1431 	while (isc_dir_read(&dir) == ISC_R_SUCCESS) {
1432 		if (dir.entry.name[0] != 'K' || dir.entry.length < len + 1 ||
1433 		    dir.entry.name[len + 1] != '+' ||
1434 		    strncasecmp(dir.entry.name + 1, namebuf, len) != 0)
1435 		{
1436 			continue;
1437 		}
1438 
1439 		alg = 0;
1440 		for (i = len + 1 + 1; i < dir.entry.length; i++) {
1441 			if (!isdigit((unsigned char)dir.entry.name[i])) {
1442 				break;
1443 			}
1444 			alg *= 10;
1445 			alg += dir.entry.name[i] - '0';
1446 		}
1447 
1448 		/*
1449 		 * Did we not read exactly 3 digits?
1450 		 * Did we overflow?
1451 		 * Did we correctly terminate?
1452 		 */
1453 		if (i != len + 1 + 1 + 3 || i >= dir.entry.length ||
1454 		    dir.entry.name[i] != '+')
1455 		{
1456 			continue;
1457 		}
1458 
1459 		for (i++; i < dir.entry.length; i++) {
1460 			if (!isdigit((unsigned char)dir.entry.name[i])) {
1461 				break;
1462 			}
1463 		}
1464 
1465 		/*
1466 		 * Did we not read exactly 5 more digits?
1467 		 * Did we overflow?
1468 		 * Did we correctly terminate?
1469 		 */
1470 		if (i != len + 1 + 1 + 3 + 1 + 5 || i >= dir.entry.length ||
1471 		    strcmp(dir.entry.name + i, ".private") != 0)
1472 		{
1473 			continue;
1474 		}
1475 
1476 		dstkey = NULL;
1477 		result = dst_key_fromnamedfile(
1478 			dir.entry.name, directory,
1479 			DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | DST_TYPE_STATE,
1480 			mctx, &dstkey);
1481 
1482 		switch (alg) {
1483 		case DST_ALG_HMACMD5:
1484 		case DST_ALG_HMACSHA1:
1485 		case DST_ALG_HMACSHA224:
1486 		case DST_ALG_HMACSHA256:
1487 		case DST_ALG_HMACSHA384:
1488 		case DST_ALG_HMACSHA512:
1489 			if (result == DST_R_BADKEYTYPE) {
1490 				continue;
1491 			}
1492 		}
1493 
1494 		if (result != ISC_R_SUCCESS) {
1495 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1496 				      DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
1497 				      "dns_dnssec_findmatchingkeys: "
1498 				      "error reading key file %s: %s",
1499 				      dir.entry.name,
1500 				      isc_result_totext(result));
1501 			continue;
1502 		}
1503 
1504 		RETERR(dns_dnsseckey_create(mctx, &dstkey, &key));
1505 		key->source = dns_keysource_repository;
1506 		dns_dnssec_get_hints(key, now);
1507 
1508 		if (key->legacy) {
1509 			dns_dnsseckey_destroy(mctx, &key);
1510 		} else {
1511 			ISC_LIST_APPEND(list, key, link);
1512 			key = NULL;
1513 		}
1514 	}
1515 
1516 	if (!ISC_LIST_EMPTY(list)) {
1517 		result = ISC_R_SUCCESS;
1518 		ISC_LIST_APPENDLIST(*keylist, list, link);
1519 	} else {
1520 		result = ISC_R_NOTFOUND;
1521 	}
1522 
1523 failure:
1524 	if (dir_open) {
1525 		isc_dir_close(&dir);
1526 	}
1527 	INSIST(key == NULL);
1528 	while ((key = ISC_LIST_HEAD(list)) != NULL) {
1529 		ISC_LIST_UNLINK(list, key, link);
1530 		INSIST(key->key != NULL);
1531 		dst_key_free(&key->key);
1532 		dns_dnsseckey_destroy(mctx, &key);
1533 	}
1534 	if (dstkey != NULL) {
1535 		dst_key_free(&dstkey);
1536 	}
1537 	return (result);
1538 }
1539 
1540 /*%
1541  * Add 'newkey' to 'keylist' if it's not already there.
1542  *
1543  * If 'savekeys' is true, then we need to preserve all
1544  * the keys in the keyset, regardless of whether they have
1545  * metadata indicating they should be deactivated or removed.
1546  */
1547 static isc_result_t
addkey(dns_dnsseckeylist_t * keylist,dst_key_t ** newkey,bool savekeys,isc_mem_t * mctx)1548 addkey(dns_dnsseckeylist_t *keylist, dst_key_t **newkey, bool savekeys,
1549        isc_mem_t *mctx) {
1550 	dns_dnsseckey_t *key;
1551 	isc_result_t result;
1552 
1553 	/* Skip duplicates */
1554 	for (key = ISC_LIST_HEAD(*keylist); key != NULL;
1555 	     key = ISC_LIST_NEXT(key, link))
1556 	{
1557 		if (dst_key_id(key->key) == dst_key_id(*newkey) &&
1558 		    dst_key_alg(key->key) == dst_key_alg(*newkey) &&
1559 		    dns_name_equal(dst_key_name(key->key),
1560 				   dst_key_name(*newkey)))
1561 		{
1562 			break;
1563 		}
1564 	}
1565 
1566 	if (key != NULL) {
1567 		/*
1568 		 * Found a match.  If the old key was only public and the
1569 		 * new key is private, replace the old one; otherwise
1570 		 * leave it.  But either way, mark the key as having
1571 		 * been found in the zone.
1572 		 */
1573 		if (dst_key_isprivate(key->key)) {
1574 			dst_key_free(newkey);
1575 		} else if (dst_key_isprivate(*newkey)) {
1576 			dst_key_free(&key->key);
1577 			key->key = *newkey;
1578 		}
1579 
1580 		key->source = dns_keysource_zoneapex;
1581 		return (ISC_R_SUCCESS);
1582 	}
1583 
1584 	result = dns_dnsseckey_create(mctx, newkey, &key);
1585 	if (result != ISC_R_SUCCESS) {
1586 		return (result);
1587 	}
1588 	if (key->legacy || savekeys) {
1589 		key->force_publish = true;
1590 		key->force_sign = dst_key_isprivate(key->key);
1591 	}
1592 	key->source = dns_keysource_zoneapex;
1593 	ISC_LIST_APPEND(*keylist, key, link);
1594 	*newkey = NULL;
1595 	return (ISC_R_SUCCESS);
1596 }
1597 
1598 /*%
1599  * Mark all keys which signed the DNSKEY/SOA RRsets as "active",
1600  * for future reference.
1601  */
1602 static isc_result_t
mark_active_keys(dns_dnsseckeylist_t * keylist,dns_rdataset_t * rrsigs)1603 mark_active_keys(dns_dnsseckeylist_t *keylist, dns_rdataset_t *rrsigs) {
1604 	isc_result_t result = ISC_R_SUCCESS;
1605 	dns_rdata_t rdata = DNS_RDATA_INIT;
1606 	dns_rdataset_t sigs;
1607 	dns_dnsseckey_t *key;
1608 
1609 	REQUIRE(rrsigs != NULL && dns_rdataset_isassociated(rrsigs));
1610 
1611 	dns_rdataset_init(&sigs);
1612 	dns_rdataset_clone(rrsigs, &sigs);
1613 	for (key = ISC_LIST_HEAD(*keylist); key != NULL;
1614 	     key = ISC_LIST_NEXT(key, link))
1615 	{
1616 		uint16_t keyid, sigid;
1617 		dns_secalg_t keyalg, sigalg;
1618 		keyid = dst_key_id(key->key);
1619 		keyalg = dst_key_alg(key->key);
1620 
1621 		for (result = dns_rdataset_first(&sigs);
1622 		     result == ISC_R_SUCCESS; result = dns_rdataset_next(&sigs))
1623 		{
1624 			dns_rdata_rrsig_t sig;
1625 
1626 			dns_rdata_reset(&rdata);
1627 			dns_rdataset_current(&sigs, &rdata);
1628 			result = dns_rdata_tostruct(&rdata, &sig, NULL);
1629 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
1630 			sigalg = sig.algorithm;
1631 			sigid = sig.keyid;
1632 			if (keyid == sigid && keyalg == sigalg) {
1633 				key->is_active = true;
1634 				break;
1635 			}
1636 		}
1637 	}
1638 
1639 	if (result == ISC_R_NOMORE) {
1640 		result = ISC_R_SUCCESS;
1641 	}
1642 
1643 	if (dns_rdataset_isassociated(&sigs)) {
1644 		dns_rdataset_disassociate(&sigs);
1645 	}
1646 	return (result);
1647 }
1648 
1649 /*%
1650  * Add the contents of a DNSKEY rdataset 'keyset' to 'keylist'.
1651  */
1652 isc_result_t
dns_dnssec_keylistfromrdataset(const dns_name_t * origin,const char * directory,isc_mem_t * mctx,dns_rdataset_t * keyset,dns_rdataset_t * keysigs,dns_rdataset_t * soasigs,bool savekeys,bool publickey,dns_dnsseckeylist_t * keylist)1653 dns_dnssec_keylistfromrdataset(const dns_name_t *origin, const char *directory,
1654 			       isc_mem_t *mctx, dns_rdataset_t *keyset,
1655 			       dns_rdataset_t *keysigs, dns_rdataset_t *soasigs,
1656 			       bool savekeys, bool publickey,
1657 			       dns_dnsseckeylist_t *keylist) {
1658 	dns_rdataset_t keys;
1659 	dns_rdata_t rdata = DNS_RDATA_INIT;
1660 	dst_key_t *dnskey = NULL, *pubkey = NULL, *privkey = NULL;
1661 	isc_result_t result;
1662 
1663 	REQUIRE(keyset != NULL && dns_rdataset_isassociated(keyset));
1664 
1665 	dns_rdataset_init(&keys);
1666 
1667 	dns_rdataset_clone(keyset, &keys);
1668 	for (result = dns_rdataset_first(&keys); result == ISC_R_SUCCESS;
1669 	     result = dns_rdataset_next(&keys))
1670 	{
1671 		dns_rdata_reset(&rdata);
1672 		dns_rdataset_current(&keys, &rdata);
1673 
1674 		REQUIRE(rdata.type == dns_rdatatype_key ||
1675 			rdata.type == dns_rdatatype_dnskey);
1676 		REQUIRE(rdata.length > 3);
1677 
1678 		/* Skip unsupported algorithms */
1679 		if (!dst_algorithm_supported(rdata.data[3])) {
1680 			goto skip;
1681 		}
1682 
1683 		RETERR(dns_dnssec_keyfromrdata(origin, &rdata, mctx, &dnskey));
1684 		dst_key_setttl(dnskey, keys.ttl);
1685 
1686 		if (!is_zone_key(dnskey) ||
1687 		    (dst_key_flags(dnskey) & DNS_KEYTYPE_NOAUTH) != 0)
1688 		{
1689 			goto skip;
1690 		}
1691 
1692 		/* Corrupted .key file? */
1693 		if (!dns_name_equal(origin, dst_key_name(dnskey))) {
1694 			goto skip;
1695 		}
1696 
1697 		if (publickey) {
1698 			RETERR(addkey(keylist, &dnskey, savekeys, mctx));
1699 			goto skip;
1700 		}
1701 
1702 		/* Try to read the public key. */
1703 		result = dst_key_fromfile(
1704 			dst_key_name(dnskey), dst_key_id(dnskey),
1705 			dst_key_alg(dnskey), (DST_TYPE_PUBLIC | DST_TYPE_STATE),
1706 			directory, mctx, &pubkey);
1707 		if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) {
1708 			result = ISC_R_SUCCESS;
1709 		}
1710 		RETERR(result);
1711 
1712 		/* Now read the private key. */
1713 		result = dst_key_fromfile(
1714 			dst_key_name(dnskey), dst_key_id(dnskey),
1715 			dst_key_alg(dnskey),
1716 			(DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | DST_TYPE_STATE),
1717 			directory, mctx, &privkey);
1718 
1719 		/*
1720 		 * If the key was revoked and the private file
1721 		 * doesn't exist, maybe it was revoked internally
1722 		 * by named.  Try loading the unrevoked version.
1723 		 */
1724 		if (result == ISC_R_FILENOTFOUND) {
1725 			uint32_t flags;
1726 			flags = dst_key_flags(dnskey);
1727 			if ((flags & DNS_KEYFLAG_REVOKE) != 0) {
1728 				dst_key_setflags(dnskey,
1729 						 flags & ~DNS_KEYFLAG_REVOKE);
1730 				result = dst_key_fromfile(
1731 					dst_key_name(dnskey),
1732 					dst_key_id(dnskey), dst_key_alg(dnskey),
1733 					(DST_TYPE_PUBLIC | DST_TYPE_PRIVATE |
1734 					 DST_TYPE_STATE),
1735 					directory, mctx, &privkey);
1736 				if (result == ISC_R_SUCCESS &&
1737 				    dst_key_pubcompare(dnskey, privkey, false))
1738 				{
1739 					dst_key_setflags(privkey, flags);
1740 				}
1741 				dst_key_setflags(dnskey, flags);
1742 			}
1743 		}
1744 
1745 		if (result != ISC_R_SUCCESS) {
1746 			char filename[DNS_NAME_FORMATSIZE +
1747 				      DNS_SECALG_FORMATSIZE +
1748 				      sizeof("key file for //65535")];
1749 			isc_result_t result2;
1750 			isc_buffer_t buf;
1751 
1752 			isc_buffer_init(&buf, filename, NAME_MAX);
1753 			result2 = dst_key_getfilename(
1754 				dst_key_name(dnskey), dst_key_id(dnskey),
1755 				dst_key_alg(dnskey),
1756 				(DST_TYPE_PUBLIC | DST_TYPE_PRIVATE |
1757 				 DST_TYPE_STATE),
1758 				directory, mctx, &buf);
1759 			if (result2 != ISC_R_SUCCESS) {
1760 				char namebuf[DNS_NAME_FORMATSIZE];
1761 				char algbuf[DNS_SECALG_FORMATSIZE];
1762 
1763 				dns_name_format(dst_key_name(dnskey), namebuf,
1764 						sizeof(namebuf));
1765 				dns_secalg_format(dst_key_alg(dnskey), algbuf,
1766 						  sizeof(algbuf));
1767 				snprintf(filename, sizeof(filename) - 1,
1768 					 "key file for %s/%s/%d", namebuf,
1769 					 algbuf, dst_key_id(dnskey));
1770 			}
1771 
1772 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
1773 				      DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
1774 				      "dns_dnssec_keylistfromrdataset: error "
1775 				      "reading %s: %s",
1776 				      filename, isc_result_totext(result));
1777 		}
1778 
1779 		if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) {
1780 			if (pubkey != NULL) {
1781 				RETERR(addkey(keylist, &pubkey, savekeys,
1782 					      mctx));
1783 			} else {
1784 				RETERR(addkey(keylist, &dnskey, savekeys,
1785 					      mctx));
1786 			}
1787 			goto skip;
1788 		}
1789 		RETERR(result);
1790 
1791 		/* This should never happen. */
1792 		if ((dst_key_flags(privkey) & DNS_KEYTYPE_NOAUTH) != 0) {
1793 			goto skip;
1794 		}
1795 
1796 		/*
1797 		 * Whatever the key's default TTL may have
1798 		 * been, the rdataset TTL takes priority.
1799 		 */
1800 		dst_key_setttl(privkey, dst_key_getttl(dnskey));
1801 
1802 		RETERR(addkey(keylist, &privkey, savekeys, mctx));
1803 	skip:
1804 		if (dnskey != NULL) {
1805 			dst_key_free(&dnskey);
1806 		}
1807 		if (pubkey != NULL) {
1808 			dst_key_free(&pubkey);
1809 		}
1810 		if (privkey != NULL) {
1811 			dst_key_free(&privkey);
1812 		}
1813 	}
1814 
1815 	if (result != ISC_R_NOMORE) {
1816 		RETERR(result);
1817 	}
1818 
1819 	if (keysigs != NULL && dns_rdataset_isassociated(keysigs)) {
1820 		RETERR(mark_active_keys(keylist, keysigs));
1821 	}
1822 
1823 	if (soasigs != NULL && dns_rdataset_isassociated(soasigs)) {
1824 		RETERR(mark_active_keys(keylist, soasigs));
1825 	}
1826 
1827 	result = ISC_R_SUCCESS;
1828 
1829 failure:
1830 	if (dns_rdataset_isassociated(&keys)) {
1831 		dns_rdataset_disassociate(&keys);
1832 	}
1833 	if (dnskey != NULL) {
1834 		dst_key_free(&dnskey);
1835 	}
1836 	if (pubkey != NULL) {
1837 		dst_key_free(&pubkey);
1838 	}
1839 	if (privkey != NULL) {
1840 		dst_key_free(&privkey);
1841 	}
1842 	return (result);
1843 }
1844 
1845 static isc_result_t
make_dnskey(dst_key_t * key,unsigned char * buf,int bufsize,dns_rdata_t * target)1846 make_dnskey(dst_key_t *key, unsigned char *buf, int bufsize,
1847 	    dns_rdata_t *target) {
1848 	isc_result_t result;
1849 	isc_buffer_t b;
1850 	isc_region_t r;
1851 
1852 	isc_buffer_init(&b, buf, bufsize);
1853 	result = dst_key_todns(key, &b);
1854 	if (result != ISC_R_SUCCESS) {
1855 		return (result);
1856 	}
1857 
1858 	dns_rdata_reset(target);
1859 	isc_buffer_usedregion(&b, &r);
1860 	dns_rdata_fromregion(target, dst_key_class(key), dns_rdatatype_dnskey,
1861 			     &r);
1862 	return (ISC_R_SUCCESS);
1863 }
1864 
1865 static isc_result_t
addrdata(dns_rdata_t * rdata,dns_diff_t * diff,const dns_name_t * origin,dns_ttl_t ttl,isc_mem_t * mctx)1866 addrdata(dns_rdata_t *rdata, dns_diff_t *diff, const dns_name_t *origin,
1867 	 dns_ttl_t ttl, isc_mem_t *mctx) {
1868 	isc_result_t result;
1869 	dns_difftuple_t *tuple = NULL;
1870 
1871 	RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_ADD, origin, ttl, rdata,
1872 				    &tuple));
1873 	dns_diff_appendminimal(diff, &tuple);
1874 
1875 failure:
1876 	return (result);
1877 }
1878 
1879 static isc_result_t
delrdata(dns_rdata_t * rdata,dns_diff_t * diff,const dns_name_t * origin,dns_ttl_t ttl,isc_mem_t * mctx)1880 delrdata(dns_rdata_t *rdata, dns_diff_t *diff, const dns_name_t *origin,
1881 	 dns_ttl_t ttl, isc_mem_t *mctx) {
1882 	isc_result_t result;
1883 	dns_difftuple_t *tuple = NULL;
1884 
1885 	RETERR(dns_difftuple_create(mctx, DNS_DIFFOP_DEL, origin, ttl, rdata,
1886 				    &tuple));
1887 	dns_diff_appendminimal(diff, &tuple);
1888 
1889 failure:
1890 	return (result);
1891 }
1892 
1893 static isc_result_t
publish_key(dns_diff_t * diff,dns_dnsseckey_t * key,const dns_name_t * origin,dns_ttl_t ttl,isc_mem_t * mctx,void (* report)(const char *,...))1894 publish_key(dns_diff_t *diff, dns_dnsseckey_t *key, const dns_name_t *origin,
1895 	    dns_ttl_t ttl, isc_mem_t *mctx, void (*report)(const char *, ...)) {
1896 	isc_result_t result;
1897 	unsigned char buf[DST_KEY_MAXSIZE];
1898 	char keystr[DST_KEY_FORMATSIZE];
1899 	dns_rdata_t dnskey = DNS_RDATA_INIT;
1900 
1901 	dns_rdata_reset(&dnskey);
1902 	RETERR(make_dnskey(key->key, buf, sizeof(buf), &dnskey));
1903 	dst_key_format(key->key, keystr, sizeof(keystr));
1904 
1905 	report("Fetching %s (%s) from key %s.", keystr,
1906 	       key->ksk ? (key->zsk ? "CSK" : "KSK") : "ZSK",
1907 	       key->source == dns_keysource_user ? "file" : "repository");
1908 
1909 	if (key->prepublish && ttl > key->prepublish) {
1910 		isc_stdtime_t now;
1911 
1912 		report("Key %s: Delaying activation to match the DNSKEY TTL.",
1913 		       keystr, ttl);
1914 
1915 		isc_stdtime_get(&now);
1916 		dst_key_settime(key->key, DST_TIME_ACTIVATE, now + ttl);
1917 	}
1918 
1919 	/* publish key */
1920 	result = addrdata(&dnskey, diff, origin, ttl, mctx);
1921 
1922 failure:
1923 	return (result);
1924 }
1925 
1926 static isc_result_t
remove_key(dns_diff_t * diff,dns_dnsseckey_t * key,const dns_name_t * origin,dns_ttl_t ttl,isc_mem_t * mctx,const char * reason,void (* report)(const char *,...))1927 remove_key(dns_diff_t *diff, dns_dnsseckey_t *key, const dns_name_t *origin,
1928 	   dns_ttl_t ttl, isc_mem_t *mctx, const char *reason,
1929 	   void (*report)(const char *, ...)) {
1930 	isc_result_t result;
1931 	unsigned char buf[DST_KEY_MAXSIZE];
1932 	dns_rdata_t dnskey = DNS_RDATA_INIT;
1933 	char alg[80];
1934 
1935 	dns_secalg_format(dst_key_alg(key->key), alg, sizeof(alg));
1936 	report("Removing %s key %d/%s from DNSKEY RRset.", reason,
1937 	       dst_key_id(key->key), alg);
1938 
1939 	RETERR(make_dnskey(key->key, buf, sizeof(buf), &dnskey));
1940 	result = delrdata(&dnskey, diff, origin, ttl, mctx);
1941 
1942 failure:
1943 	return (result);
1944 }
1945 
1946 static bool
exists(dns_rdataset_t * rdataset,dns_rdata_t * rdata)1947 exists(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
1948 	isc_result_t result;
1949 	dns_rdataset_t trdataset;
1950 
1951 	dns_rdataset_init(&trdataset);
1952 	dns_rdataset_clone(rdataset, &trdataset);
1953 	for (result = dns_rdataset_first(&trdataset); result == ISC_R_SUCCESS;
1954 	     result = dns_rdataset_next(&trdataset))
1955 	{
1956 		dns_rdata_t current = DNS_RDATA_INIT;
1957 
1958 		dns_rdataset_current(&trdataset, &current);
1959 		if (dns_rdata_compare(rdata, &current) == 0) {
1960 			dns_rdataset_disassociate(&trdataset);
1961 			return (true);
1962 		}
1963 	}
1964 	dns_rdataset_disassociate(&trdataset);
1965 	return (false);
1966 }
1967 
1968 isc_result_t
dns_dnssec_syncupdate(dns_dnsseckeylist_t * keys,dns_dnsseckeylist_t * rmkeys,dns_rdataset_t * cds,dns_rdataset_t * cdnskey,isc_stdtime_t now,dns_ttl_t ttl,dns_diff_t * diff,isc_mem_t * mctx)1969 dns_dnssec_syncupdate(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *rmkeys,
1970 		      dns_rdataset_t *cds, dns_rdataset_t *cdnskey,
1971 		      isc_stdtime_t now, dns_ttl_t ttl, dns_diff_t *diff,
1972 		      isc_mem_t *mctx) {
1973 	unsigned char dsbuf1[DNS_DS_BUFFERSIZE];
1974 	unsigned char dsbuf2[DNS_DS_BUFFERSIZE];
1975 	unsigned char keybuf[DST_KEY_MAXSIZE];
1976 	isc_result_t result;
1977 	dns_dnsseckey_t *key;
1978 
1979 	for (key = ISC_LIST_HEAD(*keys); key != NULL;
1980 	     key = ISC_LIST_NEXT(key, link))
1981 	{
1982 		dns_rdata_t cds_sha1 = DNS_RDATA_INIT;
1983 		dns_rdata_t cds_sha256 = DNS_RDATA_INIT;
1984 		dns_rdata_t cdnskeyrdata = DNS_RDATA_INIT;
1985 		dns_name_t *origin = dst_key_name(key->key);
1986 
1987 		RETERR(make_dnskey(key->key, keybuf, sizeof(keybuf),
1988 				   &cdnskeyrdata));
1989 
1990 		/*
1991 		 * We construct the SHA-1 version of the record so we can
1992 		 * delete any old records generated by previous versions of
1993 		 * BIND. We only add SHA-256 records.
1994 		 *
1995 		 * XXXMPA we need to be able to specify the DS algorithms
1996 		 * to be used here and below with rmkeys.
1997 		 */
1998 		RETERR(dns_ds_buildrdata(origin, &cdnskeyrdata,
1999 					 DNS_DSDIGEST_SHA1, dsbuf1, &cds_sha1));
2000 		RETERR(dns_ds_buildrdata(origin, &cdnskeyrdata,
2001 					 DNS_DSDIGEST_SHA256, dsbuf2,
2002 					 &cds_sha256));
2003 
2004 		/*
2005 		 * Now that the we have created the DS records convert
2006 		 * the rdata to CDNSKEY and CDS for comparison.
2007 		 */
2008 		cdnskeyrdata.type = dns_rdatatype_cdnskey;
2009 		cds_sha1.type = dns_rdatatype_cds;
2010 		cds_sha256.type = dns_rdatatype_cds;
2011 
2012 		if (syncpublish(key->key, now)) {
2013 			char keystr[DST_KEY_FORMATSIZE];
2014 			dst_key_format(key->key, keystr, sizeof(keystr));
2015 
2016 			if (!dns_rdataset_isassociated(cdnskey) ||
2017 			    !exists(cdnskey, &cdnskeyrdata))
2018 			{
2019 				isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
2020 					      DNS_LOGMODULE_DNSSEC,
2021 					      ISC_LOG_INFO,
2022 					      "CDS for key %s is now published",
2023 					      keystr);
2024 				RETERR(addrdata(&cdnskeyrdata, diff, origin,
2025 						ttl, mctx));
2026 			}
2027 			/* Only publish SHA-256 (SHA-1 is deprecated) */
2028 			if (!dns_rdataset_isassociated(cds) ||
2029 			    !exists(cds, &cds_sha256))
2030 			{
2031 				isc_log_write(
2032 					dns_lctx, DNS_LOGCATEGORY_GENERAL,
2033 					DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
2034 					"CDNSKEY for key %s is now published",
2035 					keystr);
2036 				RETERR(addrdata(&cds_sha256, diff, origin, ttl,
2037 						mctx));
2038 			}
2039 		}
2040 
2041 		if (syncdelete(key->key, now)) {
2042 			char keystr[DST_KEY_FORMATSIZE];
2043 			dst_key_format(key->key, keystr, sizeof(keystr));
2044 
2045 			if (dns_rdataset_isassociated(cds)) {
2046 				/* Delete both SHA-1 and SHA-256 */
2047 				if (exists(cds, &cds_sha1)) {
2048 					isc_log_write(dns_lctx,
2049 						      DNS_LOGCATEGORY_GENERAL,
2050 						      DNS_LOGMODULE_DNSSEC,
2051 						      ISC_LOG_INFO,
2052 						      "CDS (SHA-1) for key %s "
2053 						      "is now deleted",
2054 						      keystr);
2055 					RETERR(delrdata(&cds_sha1, diff, origin,
2056 							cds->ttl, mctx));
2057 				}
2058 				if (exists(cds, &cds_sha256)) {
2059 					isc_log_write(dns_lctx,
2060 						      DNS_LOGCATEGORY_GENERAL,
2061 						      DNS_LOGMODULE_DNSSEC,
2062 						      ISC_LOG_INFO,
2063 						      "CDS (SHA-256) for key "
2064 						      "%s is now deleted",
2065 						      keystr);
2066 					RETERR(delrdata(&cds_sha256, diff,
2067 							origin, cds->ttl,
2068 							mctx));
2069 				}
2070 			}
2071 
2072 			if (dns_rdataset_isassociated(cdnskey)) {
2073 				if (exists(cdnskey, &cdnskeyrdata)) {
2074 					isc_log_write(dns_lctx,
2075 						      DNS_LOGCATEGORY_GENERAL,
2076 						      DNS_LOGMODULE_DNSSEC,
2077 						      ISC_LOG_INFO,
2078 						      "CDNSKEY for key %s is "
2079 						      "now deleted",
2080 						      keystr);
2081 					RETERR(delrdata(&cdnskeyrdata, diff,
2082 							origin, cdnskey->ttl,
2083 							mctx));
2084 				}
2085 			}
2086 		}
2087 	}
2088 
2089 	if (!dns_rdataset_isassociated(cds) &&
2090 	    !dns_rdataset_isassociated(cdnskey))
2091 	{
2092 		return (ISC_R_SUCCESS);
2093 	}
2094 
2095 	/*
2096 	 * Unconditionally remove CDS/DNSKEY records for removed keys.
2097 	 */
2098 	for (key = ISC_LIST_HEAD(*rmkeys); key != NULL;
2099 	     key = ISC_LIST_NEXT(key, link))
2100 	{
2101 		dns_rdata_t cds_sha1 = DNS_RDATA_INIT;
2102 		dns_rdata_t cds_sha256 = DNS_RDATA_INIT;
2103 		dns_rdata_t cdnskeyrdata = DNS_RDATA_INIT;
2104 		dns_name_t *origin = dst_key_name(key->key);
2105 
2106 		char keystr[DST_KEY_FORMATSIZE];
2107 		dst_key_format(key->key, keystr, sizeof(keystr));
2108 
2109 		RETERR(make_dnskey(key->key, keybuf, sizeof(keybuf),
2110 				   &cdnskeyrdata));
2111 
2112 		if (dns_rdataset_isassociated(cds)) {
2113 			RETERR(dns_ds_buildrdata(origin, &cdnskeyrdata,
2114 						 DNS_DSDIGEST_SHA1, dsbuf1,
2115 						 &cds_sha1));
2116 			RETERR(dns_ds_buildrdata(origin, &cdnskeyrdata,
2117 						 DNS_DSDIGEST_SHA256, dsbuf2,
2118 						 &cds_sha256));
2119 			if (exists(cds, &cds_sha1)) {
2120 				isc_log_write(
2121 					dns_lctx, DNS_LOGCATEGORY_GENERAL,
2122 					DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
2123 					"CDS (SHA-1) for key %s is now deleted",
2124 					keystr);
2125 				RETERR(delrdata(&cds_sha1, diff, origin,
2126 						cds->ttl, mctx));
2127 			}
2128 			if (exists(cds, &cds_sha256)) {
2129 				isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
2130 					      DNS_LOGMODULE_DNSSEC,
2131 					      ISC_LOG_INFO,
2132 					      "CDS (SHA-256) for key %s is now "
2133 					      "deleted",
2134 					      keystr);
2135 				RETERR(delrdata(&cds_sha256, diff, origin,
2136 						cds->ttl, mctx));
2137 			}
2138 		}
2139 
2140 		if (dns_rdataset_isassociated(cdnskey)) {
2141 			if (exists(cdnskey, &cdnskeyrdata)) {
2142 				isc_log_write(
2143 					dns_lctx, DNS_LOGCATEGORY_GENERAL,
2144 					DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
2145 					"CDNSKEY for key %s is now deleted",
2146 					keystr);
2147 				RETERR(delrdata(&cdnskeyrdata, diff, origin,
2148 						cdnskey->ttl, mctx));
2149 			}
2150 		}
2151 	}
2152 
2153 	result = ISC_R_SUCCESS;
2154 
2155 failure:
2156 	return (result);
2157 }
2158 
2159 isc_result_t
dns_dnssec_syncdelete(dns_rdataset_t * cds,dns_rdataset_t * cdnskey,dns_name_t * origin,dns_rdataclass_t zclass,dns_ttl_t ttl,dns_diff_t * diff,isc_mem_t * mctx,bool expect_cds_delete,bool expect_cdnskey_delete)2160 dns_dnssec_syncdelete(dns_rdataset_t *cds, dns_rdataset_t *cdnskey,
2161 		      dns_name_t *origin, dns_rdataclass_t zclass,
2162 		      dns_ttl_t ttl, dns_diff_t *diff, isc_mem_t *mctx,
2163 		      bool expect_cds_delete, bool expect_cdnskey_delete) {
2164 	unsigned char dsbuf[5] = { 0, 0, 0, 0, 0 };  /* CDS DELETE rdata */
2165 	unsigned char keybuf[5] = { 0, 0, 3, 0, 0 }; /* CDNSKEY DELETE rdata */
2166 	char namebuf[DNS_NAME_FORMATSIZE];
2167 	dns_rdata_t cds_delete = DNS_RDATA_INIT;
2168 	dns_rdata_t cdnskey_delete = DNS_RDATA_INIT;
2169 	isc_region_t r;
2170 	isc_result_t result;
2171 
2172 	r.base = keybuf;
2173 	r.length = sizeof(keybuf);
2174 	dns_rdata_fromregion(&cdnskey_delete, zclass, dns_rdatatype_cdnskey,
2175 			     &r);
2176 
2177 	r.base = dsbuf;
2178 	r.length = sizeof(dsbuf);
2179 	dns_rdata_fromregion(&cds_delete, zclass, dns_rdatatype_cds, &r);
2180 
2181 	dns_name_format(origin, namebuf, sizeof(namebuf));
2182 
2183 	if (expect_cds_delete) {
2184 		if (!dns_rdataset_isassociated(cds) ||
2185 		    !exists(cds, &cds_delete))
2186 		{
2187 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
2188 				      DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
2189 				      "CDS (DELETE) for zone %s is now "
2190 				      "published",
2191 				      namebuf);
2192 			RETERR(addrdata(&cds_delete, diff, origin, ttl, mctx));
2193 		}
2194 	} else {
2195 		if (dns_rdataset_isassociated(cds) && exists(cds, &cds_delete))
2196 		{
2197 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
2198 				      DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
2199 				      "CDS (DELETE) for zone %s is now "
2200 				      "deleted",
2201 				      namebuf);
2202 			RETERR(delrdata(&cds_delete, diff, origin, cds->ttl,
2203 					mctx));
2204 		}
2205 	}
2206 
2207 	if (expect_cdnskey_delete) {
2208 		if (!dns_rdataset_isassociated(cdnskey) ||
2209 		    !exists(cdnskey, &cdnskey_delete))
2210 		{
2211 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
2212 				      DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
2213 				      "CDNSKEY (DELETE) for zone %s is now "
2214 				      "published",
2215 				      namebuf);
2216 			RETERR(addrdata(&cdnskey_delete, diff, origin, ttl,
2217 					mctx));
2218 		}
2219 	} else {
2220 		if (dns_rdataset_isassociated(cdnskey) &&
2221 		    exists(cdnskey, &cdnskey_delete))
2222 		{
2223 			isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
2224 				      DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
2225 				      "CDNSKEY (DELETE) for zone %s is now "
2226 				      "deleted",
2227 				      namebuf);
2228 			RETERR(delrdata(&cdnskey_delete, diff, origin,
2229 					cdnskey->ttl, mctx));
2230 		}
2231 	}
2232 
2233 	result = ISC_R_SUCCESS;
2234 
2235 failure:
2236 	return (result);
2237 }
2238 
2239 /*
2240  * Update 'keys' with information from 'newkeys'.
2241  *
2242  * If 'removed' is not NULL, any keys that are being removed from
2243  * the zone will be added to the list for post-removal processing.
2244  */
2245 isc_result_t
dns_dnssec_updatekeys(dns_dnsseckeylist_t * keys,dns_dnsseckeylist_t * newkeys,dns_dnsseckeylist_t * removed,const dns_name_t * origin,dns_ttl_t hint_ttl,dns_diff_t * diff,isc_mem_t * mctx,void (* report)(const char *,...))2246 dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys,
2247 		      dns_dnsseckeylist_t *removed, const dns_name_t *origin,
2248 		      dns_ttl_t hint_ttl, dns_diff_t *diff, isc_mem_t *mctx,
2249 		      void (*report)(const char *, ...)) {
2250 	isc_result_t result;
2251 	dns_dnsseckey_t *key, *key1, *key2, *next;
2252 	bool found_ttl = false;
2253 	dns_ttl_t ttl = hint_ttl;
2254 
2255 	/*
2256 	 * First, look through the existing key list to find keys
2257 	 * supplied from the command line which are not in the zone.
2258 	 * Update the zone to include them.
2259 	 *
2260 	 * Also, if there are keys published in the zone already,
2261 	 * use their TTL for all subsequent published keys.
2262 	 */
2263 	for (key = ISC_LIST_HEAD(*keys); key != NULL;
2264 	     key = ISC_LIST_NEXT(key, link))
2265 	{
2266 		if (key->source == dns_keysource_user &&
2267 		    (key->hint_publish || key->force_publish))
2268 		{
2269 			RETERR(publish_key(diff, key, origin, ttl, mctx,
2270 					   report));
2271 		}
2272 		if (key->source == dns_keysource_zoneapex) {
2273 			ttl = dst_key_getttl(key->key);
2274 			found_ttl = true;
2275 		}
2276 	}
2277 
2278 	/*
2279 	 * If there were no existing keys, use the smallest nonzero
2280 	 * TTL of the keys found in the repository.
2281 	 */
2282 	if (!found_ttl && !ISC_LIST_EMPTY(*newkeys)) {
2283 		dns_ttl_t shortest = 0;
2284 
2285 		for (key = ISC_LIST_HEAD(*newkeys); key != NULL;
2286 		     key = ISC_LIST_NEXT(key, link))
2287 		{
2288 			dns_ttl_t thisttl = dst_key_getttl(key->key);
2289 			if (thisttl != 0 &&
2290 			    (shortest == 0 || thisttl < shortest))
2291 			{
2292 				shortest = thisttl;
2293 			}
2294 		}
2295 
2296 		if (shortest != 0) {
2297 			ttl = shortest;
2298 		}
2299 	}
2300 
2301 	/*
2302 	 * Second, scan the list of newly found keys looking for matches
2303 	 * with known keys, and update accordingly.
2304 	 */
2305 	for (key1 = ISC_LIST_HEAD(*newkeys); key1 != NULL; key1 = next) {
2306 		bool key_revoked = false;
2307 		char keystr1[DST_KEY_FORMATSIZE];
2308 		char keystr2[DST_KEY_FORMATSIZE];
2309 
2310 		next = ISC_LIST_NEXT(key1, link);
2311 
2312 		for (key2 = ISC_LIST_HEAD(*keys); key2 != NULL;
2313 		     key2 = ISC_LIST_NEXT(key2, link))
2314 		{
2315 			int f1 = dst_key_flags(key1->key);
2316 			int f2 = dst_key_flags(key2->key);
2317 			int nr1 = f1 & ~DNS_KEYFLAG_REVOKE;
2318 			int nr2 = f2 & ~DNS_KEYFLAG_REVOKE;
2319 			if (nr1 == nr2 &&
2320 			    dst_key_alg(key1->key) == dst_key_alg(key2->key) &&
2321 			    dst_key_pubcompare(key1->key, key2->key, true))
2322 			{
2323 				int r1, r2;
2324 				r1 = dst_key_flags(key1->key) &
2325 				     DNS_KEYFLAG_REVOKE;
2326 				r2 = dst_key_flags(key2->key) &
2327 				     DNS_KEYFLAG_REVOKE;
2328 				key_revoked = (r1 != r2);
2329 				break;
2330 			}
2331 		}
2332 
2333 		/* Printable version of key1 (the newly acquired key) */
2334 		dst_key_format(key1->key, keystr1, sizeof(keystr1));
2335 
2336 		/* No match found in keys; add the new key. */
2337 		if (key2 == NULL) {
2338 			ISC_LIST_UNLINK(*newkeys, key1, link);
2339 			ISC_LIST_APPEND(*keys, key1, link);
2340 
2341 			if (key1->source != dns_keysource_zoneapex &&
2342 			    (key1->hint_publish || key1->force_publish))
2343 			{
2344 				RETERR(publish_key(diff, key1, origin, ttl,
2345 						   mctx, report));
2346 				isc_log_write(
2347 					dns_lctx, DNS_LOGCATEGORY_DNSSEC,
2348 					DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
2349 					"DNSKEY %s (%s) is now published",
2350 					keystr1,
2351 					key1->ksk ? (key1->zsk ? "CSK" : "KSK")
2352 						  : "ZSK");
2353 				if (key1->hint_sign || key1->force_sign) {
2354 					key1->first_sign = true;
2355 					isc_log_write(
2356 						dns_lctx,
2357 						DNS_LOGCATEGORY_DNSSEC,
2358 						DNS_LOGMODULE_DNSSEC,
2359 						ISC_LOG_INFO,
2360 						"DNSKEY %s (%s) is now "
2361 						"active",
2362 						keystr1,
2363 						key1->ksk ? (key1->zsk ? "CSK"
2364 								       : "KSK")
2365 							  : "ZSK");
2366 				}
2367 			}
2368 
2369 			continue;
2370 		}
2371 
2372 		/* Printable version of key2 (the old key, if any) */
2373 		dst_key_format(key2->key, keystr2, sizeof(keystr2));
2374 
2375 		/* Copy key metadata. */
2376 		dst_key_copy_metadata(key2->key, key1->key);
2377 
2378 		/* Match found: remove or update it as needed */
2379 		if (key1->hint_remove) {
2380 			RETERR(remove_key(diff, key2, origin, ttl, mctx,
2381 					  "expired", report));
2382 			ISC_LIST_UNLINK(*keys, key2, link);
2383 
2384 			if (removed != NULL) {
2385 				ISC_LIST_APPEND(*removed, key2, link);
2386 				isc_log_write(
2387 					dns_lctx, DNS_LOGCATEGORY_DNSSEC,
2388 					DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
2389 					"DNSKEY %s (%s) is now deleted",
2390 					keystr2,
2391 					key2->ksk ? (key2->zsk ? "CSK" : "KSK")
2392 						  : "ZSK");
2393 			} else {
2394 				dns_dnsseckey_destroy(mctx, &key2);
2395 			}
2396 		} else if (key_revoked &&
2397 			   (dst_key_flags(key1->key) & DNS_KEYFLAG_REVOKE) != 0)
2398 		{
2399 			/*
2400 			 * A previously valid key has been revoked.
2401 			 * We need to remove the old version and pull
2402 			 * in the new one.
2403 			 */
2404 			RETERR(remove_key(diff, key2, origin, ttl, mctx,
2405 					  "revoked", report));
2406 			ISC_LIST_UNLINK(*keys, key2, link);
2407 			if (removed != NULL) {
2408 				ISC_LIST_APPEND(*removed, key2, link);
2409 				isc_log_write(
2410 					dns_lctx, DNS_LOGCATEGORY_DNSSEC,
2411 					DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
2412 					"DNSKEY %s (%s) is now revoked; "
2413 					"new ID is %05d",
2414 					keystr2,
2415 					key2->ksk ? (key2->zsk ? "CSK" : "KSK")
2416 						  : "ZSK",
2417 					dst_key_id(key1->key));
2418 			} else {
2419 				dns_dnsseckey_destroy(mctx, &key2);
2420 			}
2421 
2422 			RETERR(publish_key(diff, key1, origin, ttl, mctx,
2423 					   report));
2424 			ISC_LIST_UNLINK(*newkeys, key1, link);
2425 			ISC_LIST_APPEND(*keys, key1, link);
2426 
2427 			/*
2428 			 * XXX: The revoke flag is only defined for trust
2429 			 * anchors.  Setting the flag on a non-KSK is legal,
2430 			 * but not defined in any RFC.  It seems reasonable
2431 			 * to treat it the same as a KSK: keep it in the
2432 			 * zone, sign the DNSKEY set with it, but not
2433 			 * sign other records with it.
2434 			 */
2435 			key1->ksk = true;
2436 			continue;
2437 		} else {
2438 			if (!key2->is_active &&
2439 			    (key1->hint_sign || key1->force_sign))
2440 			{
2441 				key2->first_sign = true;
2442 				isc_log_write(
2443 					dns_lctx, DNS_LOGCATEGORY_DNSSEC,
2444 					DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
2445 					"DNSKEY %s (%s) is now active", keystr1,
2446 					key1->ksk ? (key1->zsk ? "CSK" : "KSK")
2447 						  : "ZSK");
2448 			} else if (key2->is_active && !key1->hint_sign &&
2449 				   !key1->force_sign)
2450 			{
2451 				isc_log_write(
2452 					dns_lctx, DNS_LOGCATEGORY_DNSSEC,
2453 					DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
2454 					"DNSKEY %s (%s) is now inactive",
2455 					keystr1,
2456 					key1->ksk ? (key1->zsk ? "CSK" : "KSK")
2457 						  : "ZSK");
2458 			}
2459 
2460 			key2->hint_sign = key1->hint_sign;
2461 			key2->hint_publish = key1->hint_publish;
2462 		}
2463 	}
2464 
2465 	/* Free any leftover keys in newkeys */
2466 	while (!ISC_LIST_EMPTY(*newkeys)) {
2467 		key1 = ISC_LIST_HEAD(*newkeys);
2468 		ISC_LIST_UNLINK(*newkeys, key1, link);
2469 		dns_dnsseckey_destroy(mctx, &key1);
2470 	}
2471 
2472 	result = ISC_R_SUCCESS;
2473 
2474 failure:
2475 	return (result);
2476 }
2477 
2478 isc_result_t
dns_dnssec_matchdskey(dns_name_t * name,dns_rdata_t * dsrdata,dns_rdataset_t * keyset,dns_rdata_t * keyrdata)2479 dns_dnssec_matchdskey(dns_name_t *name, dns_rdata_t *dsrdata,
2480 		      dns_rdataset_t *keyset, dns_rdata_t *keyrdata) {
2481 	isc_result_t result;
2482 	unsigned char buf[DNS_DS_BUFFERSIZE];
2483 	dns_keytag_t keytag;
2484 	dns_rdata_dnskey_t key;
2485 	dns_rdata_ds_t ds;
2486 	isc_region_t r;
2487 
2488 	result = dns_rdata_tostruct(dsrdata, &ds, NULL);
2489 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
2490 
2491 	for (result = dns_rdataset_first(keyset); result == ISC_R_SUCCESS;
2492 	     result = dns_rdataset_next(keyset))
2493 	{
2494 		dns_rdata_t newdsrdata = DNS_RDATA_INIT;
2495 
2496 		dns_rdata_reset(keyrdata);
2497 		dns_rdataset_current(keyset, keyrdata);
2498 
2499 		result = dns_rdata_tostruct(keyrdata, &key, NULL);
2500 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
2501 
2502 		dns_rdata_toregion(keyrdata, &r);
2503 		keytag = dst_region_computeid(&r);
2504 
2505 		if (ds.key_tag != keytag || ds.algorithm != key.algorithm) {
2506 			continue;
2507 		}
2508 
2509 		result = dns_ds_buildrdata(name, keyrdata, ds.digest_type, buf,
2510 					   &newdsrdata);
2511 		if (result != ISC_R_SUCCESS) {
2512 			continue;
2513 		}
2514 
2515 		if (dns_rdata_compare(dsrdata, &newdsrdata) == 0) {
2516 			break;
2517 		}
2518 	}
2519 	if (result == ISC_R_NOMORE) {
2520 		result = ISC_R_NOTFOUND;
2521 	}
2522 
2523 	return (result);
2524 }
2525