xref: /netbsd-src/external/mpl/bind/dist/lib/dns/zoneverify.c (revision 2f62cc9c12bc202c40224f32c879f81443fee079)
1 /*	$NetBSD: zoneverify.c,v 1.11 2024/02/21 22:52:08 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 <inttypes.h>
19 #include <stdarg.h>
20 #include <stdbool.h>
21 #include <stdio.h>
22 #include <string.h>
23 
24 #include <isc/base32.h>
25 #include <isc/buffer.h>
26 #include <isc/heap.h>
27 #include <isc/iterated_hash.h>
28 #include <isc/log.h>
29 #include <isc/mem.h>
30 #include <isc/region.h>
31 #include <isc/result.h>
32 #include <isc/types.h>
33 #include <isc/util.h>
34 
35 #include <dns/db.h>
36 #include <dns/dbiterator.h>
37 #include <dns/dnssec.h>
38 #include <dns/fixedname.h>
39 #include <dns/keytable.h>
40 #include <dns/keyvalues.h>
41 #include <dns/log.h>
42 #include <dns/name.h>
43 #include <dns/nsec.h>
44 #include <dns/nsec3.h>
45 #include <dns/rdata.h>
46 #include <dns/rdataset.h>
47 #include <dns/rdatasetiter.h>
48 #include <dns/rdatastruct.h>
49 #include <dns/rdatatype.h>
50 #include <dns/secalg.h>
51 #include <dns/types.h>
52 #include <dns/zone.h>
53 #include <dns/zoneverify.h>
54 
55 #include <dst/dst.h>
56 
57 typedef struct vctx {
58 	isc_mem_t *mctx;
59 	dns_zone_t *zone;
60 	dns_db_t *db;
61 	dns_dbversion_t *ver;
62 	dns_name_t *origin;
63 	dns_keytable_t *secroots;
64 	bool goodksk;
65 	bool goodzsk;
66 	dns_rdataset_t keyset;
67 	dns_rdataset_t keysigs;
68 	dns_rdataset_t soaset;
69 	dns_rdataset_t soasigs;
70 	dns_rdataset_t nsecset;
71 	dns_rdataset_t nsecsigs;
72 	dns_rdataset_t nsec3paramset;
73 	dns_rdataset_t nsec3paramsigs;
74 	unsigned char revoked_ksk[256];
75 	unsigned char revoked_zsk[256];
76 	unsigned char standby_ksk[256];
77 	unsigned char standby_zsk[256];
78 	unsigned char ksk_algorithms[256];
79 	unsigned char zsk_algorithms[256];
80 	unsigned char bad_algorithms[256];
81 	unsigned char act_algorithms[256];
82 	isc_heap_t *expected_chains;
83 	isc_heap_t *found_chains;
84 } vctx_t;
85 
86 struct nsec3_chain_fixed {
87 	uint8_t hash;
88 	uint8_t salt_length;
89 	uint8_t next_length;
90 	uint16_t iterations;
91 	/*
92 	 * The following non-fixed-length data is stored in memory after the
93 	 * fields declared above for each NSEC3 chain element:
94 	 *
95 	 * unsigned char	salt[salt_length];
96 	 * unsigned char	owner[next_length];
97 	 * unsigned char	next[next_length];
98 	 */
99 };
100 
101 /*
102  * Helper function used to calculate length of variable-length
103  * data section in object pointed to by 'chain'.
104  */
105 static size_t
106 chain_length(struct nsec3_chain_fixed *chain) {
107 	return (chain->salt_length + 2 * chain->next_length);
108 }
109 
110 /*%
111  * Log a zone verification error described by 'fmt' and the variable arguments
112  * following it.  Either use dns_zone_logv() or print to stderr, depending on
113  * whether the function was invoked from within named or by a standalone tool,
114  * respectively.
115  */
116 static void
117 zoneverify_log_error(const vctx_t *vctx, const char *fmt, ...) {
118 	va_list ap;
119 
120 	va_start(ap, fmt);
121 	if (vctx->zone != NULL) {
122 		dns_zone_logv(vctx->zone, DNS_LOGCATEGORY_GENERAL,
123 			      ISC_LOG_ERROR, NULL, fmt, ap);
124 	} else {
125 		vfprintf(stderr, fmt, ap);
126 		fprintf(stderr, "\n");
127 	}
128 	va_end(ap);
129 }
130 
131 static bool
132 is_delegation(const vctx_t *vctx, const dns_name_t *name, dns_dbnode_t *node,
133 	      uint32_t *ttlp) {
134 	dns_rdataset_t nsset;
135 	isc_result_t result;
136 
137 	if (dns_name_equal(name, vctx->origin)) {
138 		return (false);
139 	}
140 
141 	dns_rdataset_init(&nsset);
142 	result = dns_db_findrdataset(vctx->db, node, vctx->ver,
143 				     dns_rdatatype_ns, 0, 0, &nsset, NULL);
144 	if (dns_rdataset_isassociated(&nsset)) {
145 		if (ttlp != NULL) {
146 			*ttlp = nsset.ttl;
147 		}
148 		dns_rdataset_disassociate(&nsset);
149 	}
150 
151 	return ((result == ISC_R_SUCCESS));
152 }
153 
154 /*%
155  * Return true if version 'ver' of database 'db' contains a DNAME RRset at
156  * 'node'; return false otherwise.
157  */
158 static bool
159 has_dname(const vctx_t *vctx, dns_dbnode_t *node) {
160 	dns_rdataset_t dnameset;
161 	isc_result_t result;
162 
163 	dns_rdataset_init(&dnameset);
164 	result = dns_db_findrdataset(vctx->db, node, vctx->ver,
165 				     dns_rdatatype_dname, 0, 0, &dnameset,
166 				     NULL);
167 	if (dns_rdataset_isassociated(&dnameset)) {
168 		dns_rdataset_disassociate(&dnameset);
169 	}
170 
171 	return ((result == ISC_R_SUCCESS));
172 }
173 
174 static bool
175 goodsig(const vctx_t *vctx, dns_rdata_t *sigrdata, const dns_name_t *name,
176 	dst_key_t **dstkeys, size_t nkeys, dns_rdataset_t *rdataset) {
177 	dns_rdata_rrsig_t sig;
178 	isc_result_t result;
179 
180 	result = dns_rdata_tostruct(sigrdata, &sig, NULL);
181 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
182 
183 	for (size_t key = 0; key < nkeys; key++) {
184 		if (sig.algorithm != dst_key_alg(dstkeys[key]) ||
185 		    sig.keyid != dst_key_id(dstkeys[key]) ||
186 		    !dns_name_equal(&sig.signer, vctx->origin))
187 		{
188 			continue;
189 		}
190 		result = dns_dnssec_verify(name, rdataset, dstkeys[key], false,
191 					   0, vctx->mctx, sigrdata, NULL);
192 		if (result == ISC_R_SUCCESS || result == DNS_R_FROMWILDCARD) {
193 			return (true);
194 		}
195 	}
196 	return (false);
197 }
198 
199 static bool
200 nsec_bitmap_equal(dns_rdata_nsec_t *nsec, dns_rdata_t *rdata) {
201 	isc_result_t result;
202 	dns_rdata_nsec_t tmpnsec;
203 
204 	result = dns_rdata_tostruct(rdata, &tmpnsec, NULL);
205 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
206 
207 	if (nsec->len != tmpnsec.len ||
208 	    memcmp(nsec->typebits, tmpnsec.typebits, nsec->len) != 0)
209 	{
210 		return (false);
211 	}
212 	return (true);
213 }
214 
215 static isc_result_t
216 verifynsec(const vctx_t *vctx, const dns_name_t *name, dns_dbnode_t *node,
217 	   const dns_name_t *nextname, isc_result_t *vresult) {
218 	unsigned char buffer[DNS_NSEC_BUFFERSIZE];
219 	char namebuf[DNS_NAME_FORMATSIZE];
220 	char nextbuf[DNS_NAME_FORMATSIZE];
221 	char found[DNS_NAME_FORMATSIZE];
222 	dns_rdataset_t rdataset;
223 	dns_rdata_t rdata = DNS_RDATA_INIT;
224 	dns_rdata_t tmprdata = DNS_RDATA_INIT;
225 	dns_rdata_nsec_t nsec;
226 	isc_result_t result;
227 
228 	dns_rdataset_init(&rdataset);
229 	result = dns_db_findrdataset(vctx->db, node, vctx->ver,
230 				     dns_rdatatype_nsec, 0, 0, &rdataset, NULL);
231 	if (result != ISC_R_SUCCESS) {
232 		dns_name_format(name, namebuf, sizeof(namebuf));
233 		zoneverify_log_error(vctx, "Missing NSEC record for %s",
234 				     namebuf);
235 		*vresult = ISC_R_FAILURE;
236 		result = ISC_R_SUCCESS;
237 		goto done;
238 	}
239 
240 	result = dns_rdataset_first(&rdataset);
241 	if (result != ISC_R_SUCCESS) {
242 		zoneverify_log_error(vctx, "dns_rdataset_first(): %s",
243 				     isc_result_totext(result));
244 		goto done;
245 	}
246 
247 	dns_rdataset_current(&rdataset, &rdata);
248 	result = dns_rdata_tostruct(&rdata, &nsec, NULL);
249 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
250 
251 	/* Check next name is consistent */
252 	if (!dns_name_equal(&nsec.next, nextname)) {
253 		dns_name_format(name, namebuf, sizeof(namebuf));
254 		dns_name_format(nextname, nextbuf, sizeof(nextbuf));
255 		dns_name_format(&nsec.next, found, sizeof(found));
256 		zoneverify_log_error(vctx,
257 				     "Bad NSEC record for %s, next name "
258 				     "mismatch (expected:%s, found:%s)",
259 				     namebuf, nextbuf, found);
260 		*vresult = ISC_R_FAILURE;
261 		goto done;
262 	}
263 
264 	/* Check bit map is consistent */
265 	result = dns_nsec_buildrdata(vctx->db, vctx->ver, node, nextname,
266 				     buffer, &tmprdata);
267 	if (result != ISC_R_SUCCESS) {
268 		zoneverify_log_error(vctx, "dns_nsec_buildrdata(): %s",
269 				     isc_result_totext(result));
270 		goto done;
271 	}
272 	if (!nsec_bitmap_equal(&nsec, &tmprdata)) {
273 		dns_name_format(name, namebuf, sizeof(namebuf));
274 		zoneverify_log_error(vctx,
275 				     "Bad NSEC record for %s, bit map "
276 				     "mismatch",
277 				     namebuf);
278 		*vresult = ISC_R_FAILURE;
279 		goto done;
280 	}
281 
282 	result = dns_rdataset_next(&rdataset);
283 	if (result != ISC_R_NOMORE) {
284 		dns_name_format(name, namebuf, sizeof(namebuf));
285 		zoneverify_log_error(vctx, "Multiple NSEC records for %s",
286 				     namebuf);
287 		*vresult = ISC_R_FAILURE;
288 		goto done;
289 	}
290 
291 	*vresult = ISC_R_SUCCESS;
292 	result = ISC_R_SUCCESS;
293 
294 done:
295 	if (dns_rdataset_isassociated(&rdataset)) {
296 		dns_rdataset_disassociate(&rdataset);
297 	}
298 
299 	return (result);
300 }
301 
302 static isc_result_t
303 check_no_rrsig(const vctx_t *vctx, const dns_rdataset_t *rdataset,
304 	       const dns_name_t *name, dns_dbnode_t *node) {
305 	char namebuf[DNS_NAME_FORMATSIZE];
306 	char typebuf[DNS_RDATATYPE_FORMATSIZE];
307 	dns_rdataset_t sigrdataset;
308 	dns_rdatasetiter_t *rdsiter = NULL;
309 	isc_result_t result;
310 
311 	dns_rdataset_init(&sigrdataset);
312 	result = dns_db_allrdatasets(vctx->db, node, vctx->ver, 0, 0, &rdsiter);
313 	if (result != ISC_R_SUCCESS) {
314 		zoneverify_log_error(vctx, "dns_db_allrdatasets(): %s",
315 				     isc_result_totext(result));
316 		return (result);
317 	}
318 	for (result = dns_rdatasetiter_first(rdsiter); result == ISC_R_SUCCESS;
319 	     result = dns_rdatasetiter_next(rdsiter))
320 	{
321 		dns_rdatasetiter_current(rdsiter, &sigrdataset);
322 		if (sigrdataset.type == dns_rdatatype_rrsig &&
323 		    sigrdataset.covers == rdataset->type)
324 		{
325 			dns_name_format(name, namebuf, sizeof(namebuf));
326 			dns_rdatatype_format(rdataset->type, typebuf,
327 					     sizeof(typebuf));
328 			zoneverify_log_error(
329 				vctx,
330 				"Warning: Found unexpected signatures "
331 				"for %s/%s",
332 				namebuf, typebuf);
333 			break;
334 		}
335 		dns_rdataset_disassociate(&sigrdataset);
336 	}
337 	if (dns_rdataset_isassociated(&sigrdataset)) {
338 		dns_rdataset_disassociate(&sigrdataset);
339 	}
340 	dns_rdatasetiter_destroy(&rdsiter);
341 
342 	return (ISC_R_SUCCESS);
343 }
344 
345 static bool
346 chain_compare(void *arg1, void *arg2) {
347 	struct nsec3_chain_fixed *e1 = arg1, *e2 = arg2;
348 	/*
349 	 * Do each element in turn to get a stable sort.
350 	 */
351 	if (e1->hash < e2->hash) {
352 		return (true);
353 	}
354 	if (e1->hash > e2->hash) {
355 		return (false);
356 	}
357 	if (e1->iterations < e2->iterations) {
358 		return (true);
359 	}
360 	if (e1->iterations > e2->iterations) {
361 		return (false);
362 	}
363 	if (e1->salt_length < e2->salt_length) {
364 		return (true);
365 	}
366 	if (e1->salt_length > e2->salt_length) {
367 		return (false);
368 	}
369 	if (e1->next_length < e2->next_length) {
370 		return (true);
371 	}
372 	if (e1->next_length > e2->next_length) {
373 		return (false);
374 	}
375 	if (memcmp(e1 + 1, e2 + 1, chain_length(e1)) < 0) {
376 		return (true);
377 	}
378 	return (false);
379 }
380 
381 static bool
382 chain_equal(const struct nsec3_chain_fixed *e1,
383 	    const struct nsec3_chain_fixed *e2, size_t data_length) {
384 	if (e1->hash != e2->hash) {
385 		return (false);
386 	}
387 	if (e1->iterations != e2->iterations) {
388 		return (false);
389 	}
390 	if (e1->salt_length != e2->salt_length) {
391 		return (false);
392 	}
393 	if (e1->next_length != e2->next_length) {
394 		return (false);
395 	}
396 
397 	return (memcmp(e1 + 1, e2 + 1, data_length) == 0);
398 }
399 
400 static void
401 record_nsec3(const vctx_t *vctx, const unsigned char *rawhash,
402 	     const dns_rdata_nsec3_t *nsec3, isc_heap_t *chains) {
403 	struct nsec3_chain_fixed *element = NULL;
404 	unsigned char *cp = NULL;
405 	size_t len;
406 
407 	len = sizeof(*element) + nsec3->next_length * 2 + nsec3->salt_length;
408 
409 	element = isc_mem_get(vctx->mctx, len);
410 	memset(element, 0, len);
411 	element->hash = nsec3->hash;
412 	element->salt_length = nsec3->salt_length;
413 	element->next_length = nsec3->next_length;
414 	element->iterations = nsec3->iterations;
415 	cp = (unsigned char *)(element + 1);
416 	memmove(cp, nsec3->salt, nsec3->salt_length);
417 	cp += nsec3->salt_length;
418 	memmove(cp, rawhash, nsec3->next_length);
419 	cp += nsec3->next_length;
420 	memmove(cp, nsec3->next, nsec3->next_length);
421 	isc_heap_insert(chains, element);
422 }
423 
424 /*
425  * Check whether any NSEC3 within 'rdataset' matches the parameters in
426  * 'nsec3param'.
427  */
428 static isc_result_t
429 find_nsec3_match(const dns_rdata_nsec3param_t *nsec3param,
430 		 dns_rdataset_t *rdataset, size_t rhsize,
431 		 dns_rdata_nsec3_t *nsec3_match) {
432 	isc_result_t result;
433 
434 	/*
435 	 * Find matching NSEC3 record.
436 	 */
437 	for (result = dns_rdataset_first(rdataset); result == ISC_R_SUCCESS;
438 	     result = dns_rdataset_next(rdataset))
439 	{
440 		dns_rdata_t rdata = DNS_RDATA_INIT;
441 		dns_rdataset_current(rdataset, &rdata);
442 		result = dns_rdata_tostruct(&rdata, nsec3_match, NULL);
443 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
444 		if (nsec3_match->hash == nsec3param->hash &&
445 		    nsec3_match->next_length == rhsize &&
446 		    nsec3_match->iterations == nsec3param->iterations &&
447 		    nsec3_match->salt_length == nsec3param->salt_length &&
448 		    memcmp(nsec3_match->salt, nsec3param->salt,
449 			   nsec3param->salt_length) == 0)
450 		{
451 			return (ISC_R_SUCCESS);
452 		}
453 	}
454 
455 	return (result);
456 }
457 
458 static isc_result_t
459 match_nsec3(const vctx_t *vctx, const dns_name_t *name,
460 	    const dns_rdata_nsec3param_t *nsec3param, dns_rdataset_t *rdataset,
461 	    const unsigned char types[8192], unsigned int maxtype,
462 	    const unsigned char *rawhash, size_t rhsize,
463 	    isc_result_t *vresult) {
464 	unsigned char cbm[8244];
465 	char namebuf[DNS_NAME_FORMATSIZE];
466 	dns_rdata_nsec3_t nsec3;
467 	isc_result_t result;
468 	unsigned int len;
469 
470 	result = find_nsec3_match(nsec3param, rdataset, rhsize, &nsec3);
471 	if (result != ISC_R_SUCCESS) {
472 		dns_name_format(name, namebuf, sizeof(namebuf));
473 		zoneverify_log_error(vctx, "Missing NSEC3 record for %s",
474 				     namebuf);
475 		*vresult = result;
476 		return (ISC_R_SUCCESS);
477 	}
478 
479 	/*
480 	 * Check the type list.
481 	 */
482 	len = dns_nsec_compressbitmap(cbm, types, maxtype);
483 	if (nsec3.len != len || memcmp(cbm, nsec3.typebits, len) != 0) {
484 		dns_name_format(name, namebuf, sizeof(namebuf));
485 		zoneverify_log_error(vctx,
486 				     "Bad NSEC3 record for %s, bit map "
487 				     "mismatch",
488 				     namebuf);
489 		*vresult = ISC_R_FAILURE;
490 		return (ISC_R_SUCCESS);
491 	}
492 
493 	/*
494 	 * Record chain.
495 	 */
496 	record_nsec3(vctx, rawhash, &nsec3, vctx->expected_chains);
497 
498 	/*
499 	 * Make sure there is only one NSEC3 record with this set of
500 	 * parameters.
501 	 */
502 	for (result = dns_rdataset_next(rdataset); result == ISC_R_SUCCESS;
503 	     result = dns_rdataset_next(rdataset))
504 	{
505 		dns_rdata_t rdata = DNS_RDATA_INIT;
506 		dns_rdataset_current(rdataset, &rdata);
507 		result = dns_rdata_tostruct(&rdata, &nsec3, NULL);
508 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
509 		if (nsec3.hash == nsec3param->hash &&
510 		    nsec3.iterations == nsec3param->iterations &&
511 		    nsec3.salt_length == nsec3param->salt_length &&
512 		    memcmp(nsec3.salt, nsec3param->salt, nsec3.salt_length) ==
513 			    0)
514 		{
515 			dns_name_format(name, namebuf, sizeof(namebuf));
516 			zoneverify_log_error(vctx,
517 					     "Multiple NSEC3 records with the "
518 					     "same parameter set for %s",
519 					     namebuf);
520 			*vresult = DNS_R_DUPLICATE;
521 			return (ISC_R_SUCCESS);
522 		}
523 	}
524 	if (result != ISC_R_NOMORE) {
525 		return (result);
526 	}
527 
528 	*vresult = ISC_R_SUCCESS;
529 
530 	return (ISC_R_SUCCESS);
531 }
532 
533 static bool
534 innsec3params(const dns_rdata_nsec3_t *nsec3, dns_rdataset_t *nsec3paramset) {
535 	dns_rdata_nsec3param_t nsec3param;
536 	isc_result_t result;
537 
538 	for (result = dns_rdataset_first(nsec3paramset);
539 	     result == ISC_R_SUCCESS; result = dns_rdataset_next(nsec3paramset))
540 	{
541 		dns_rdata_t rdata = DNS_RDATA_INIT;
542 
543 		dns_rdataset_current(nsec3paramset, &rdata);
544 		result = dns_rdata_tostruct(&rdata, &nsec3param, NULL);
545 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
546 		if (nsec3param.flags == 0 && nsec3param.hash == nsec3->hash &&
547 		    nsec3param.iterations == nsec3->iterations &&
548 		    nsec3param.salt_length == nsec3->salt_length &&
549 		    memcmp(nsec3param.salt, nsec3->salt, nsec3->salt_length) ==
550 			    0)
551 		{
552 			return (true);
553 		}
554 	}
555 	return (false);
556 }
557 
558 static isc_result_t
559 record_found(const vctx_t *vctx, const dns_name_t *name, dns_dbnode_t *node,
560 	     dns_rdataset_t *nsec3paramset) {
561 	unsigned char owner[NSEC3_MAX_HASH_LENGTH];
562 	dns_rdata_nsec3_t nsec3;
563 	dns_rdataset_t rdataset;
564 	dns_label_t hashlabel;
565 	isc_buffer_t b;
566 	isc_result_t result;
567 
568 	if (nsec3paramset == NULL || !dns_rdataset_isassociated(nsec3paramset))
569 	{
570 		return (ISC_R_SUCCESS);
571 	}
572 
573 	dns_rdataset_init(&rdataset);
574 	result = dns_db_findrdataset(vctx->db, node, vctx->ver,
575 				     dns_rdatatype_nsec3, 0, 0, &rdataset,
576 				     NULL);
577 	if (result != ISC_R_SUCCESS) {
578 		return (ISC_R_SUCCESS);
579 	}
580 
581 	dns_name_getlabel(name, 0, &hashlabel);
582 	isc_region_consume(&hashlabel, 1);
583 	isc_buffer_init(&b, owner, sizeof(owner));
584 	result = isc_base32hex_decoderegion(&hashlabel, &b);
585 	if (result != ISC_R_SUCCESS) {
586 		result = ISC_R_SUCCESS;
587 		goto cleanup;
588 	}
589 
590 	for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS;
591 	     result = dns_rdataset_next(&rdataset))
592 	{
593 		dns_rdata_t rdata = DNS_RDATA_INIT;
594 		dns_rdataset_current(&rdataset, &rdata);
595 		result = dns_rdata_tostruct(&rdata, &nsec3, NULL);
596 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
597 		if (nsec3.next_length != isc_buffer_usedlength(&b)) {
598 			continue;
599 		}
600 
601 		/*
602 		 * We only care about NSEC3 records that match a NSEC3PARAM
603 		 * record.
604 		 */
605 		if (!innsec3params(&nsec3, nsec3paramset)) {
606 			continue;
607 		}
608 
609 		/*
610 		 * Record chain.
611 		 */
612 		record_nsec3(vctx, owner, &nsec3, vctx->found_chains);
613 	}
614 	result = ISC_R_SUCCESS;
615 
616 cleanup:
617 	dns_rdataset_disassociate(&rdataset);
618 	return (result);
619 }
620 
621 static isc_result_t
622 isoptout(const vctx_t *vctx, const dns_rdata_nsec3param_t *nsec3param,
623 	 bool *optout) {
624 	dns_rdataset_t rdataset;
625 	dns_rdata_t rdata = DNS_RDATA_INIT;
626 	dns_rdata_nsec3_t nsec3;
627 	dns_fixedname_t fixed;
628 	dns_name_t *hashname;
629 	isc_result_t result;
630 	dns_dbnode_t *node = NULL;
631 	unsigned char rawhash[NSEC3_MAX_HASH_LENGTH];
632 	size_t rhsize = sizeof(rawhash);
633 
634 	dns_fixedname_init(&fixed);
635 	result = dns_nsec3_hashname(&fixed, rawhash, &rhsize, vctx->origin,
636 				    vctx->origin, nsec3param->hash,
637 				    nsec3param->iterations, nsec3param->salt,
638 				    nsec3param->salt_length);
639 	if (result != ISC_R_SUCCESS) {
640 		zoneverify_log_error(vctx, "dns_nsec3_hashname(): %s",
641 				     isc_result_totext(result));
642 		return (result);
643 	}
644 
645 	dns_rdataset_init(&rdataset);
646 	hashname = dns_fixedname_name(&fixed);
647 	result = dns_db_findnsec3node(vctx->db, hashname, false, &node);
648 	if (result == ISC_R_SUCCESS) {
649 		result = dns_db_findrdataset(vctx->db, node, vctx->ver,
650 					     dns_rdatatype_nsec3, 0, 0,
651 					     &rdataset, NULL);
652 	}
653 	if (result != ISC_R_SUCCESS) {
654 		*optout = false;
655 		result = ISC_R_SUCCESS;
656 		goto done;
657 	}
658 
659 	result = dns_rdataset_first(&rdataset);
660 	if (result != ISC_R_SUCCESS) {
661 		zoneverify_log_error(vctx, "dns_rdataset_first(): %s",
662 				     isc_result_totext(result));
663 		goto done;
664 	}
665 
666 	dns_rdataset_current(&rdataset, &rdata);
667 
668 	result = dns_rdata_tostruct(&rdata, &nsec3, NULL);
669 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
670 	*optout = ((nsec3.flags & DNS_NSEC3FLAG_OPTOUT) != 0);
671 
672 done:
673 	if (dns_rdataset_isassociated(&rdataset)) {
674 		dns_rdataset_disassociate(&rdataset);
675 	}
676 	if (node != NULL) {
677 		dns_db_detachnode(vctx->db, &node);
678 	}
679 
680 	return (result);
681 }
682 
683 static isc_result_t
684 verifynsec3(const vctx_t *vctx, const dns_name_t *name,
685 	    const dns_rdata_t *rdata, bool delegation, bool empty,
686 	    const unsigned char types[8192], unsigned int maxtype,
687 	    isc_result_t *vresult) {
688 	char namebuf[DNS_NAME_FORMATSIZE];
689 	char hashbuf[DNS_NAME_FORMATSIZE];
690 	dns_rdataset_t rdataset;
691 	dns_rdata_nsec3param_t nsec3param;
692 	dns_fixedname_t fixed;
693 	dns_name_t *hashname;
694 	isc_result_t result, tvresult = ISC_R_UNSET;
695 	dns_dbnode_t *node = NULL;
696 	unsigned char rawhash[NSEC3_MAX_HASH_LENGTH];
697 	size_t rhsize = sizeof(rawhash);
698 	bool optout = false;
699 
700 	result = dns_rdata_tostruct(rdata, &nsec3param, NULL);
701 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
702 
703 	if (nsec3param.flags != 0) {
704 		return (ISC_R_SUCCESS);
705 	}
706 
707 	if (!dns_nsec3_supportedhash(nsec3param.hash)) {
708 		return (ISC_R_SUCCESS);
709 	}
710 
711 	if (nsec3param.iterations > DNS_NSEC3_MAXITERATIONS) {
712 		result = DNS_R_NSEC3ITERRANGE;
713 		zoneverify_log_error(vctx, "verifynsec3: %s",
714 				     isc_result_totext(result));
715 		return (result);
716 	}
717 
718 	result = isoptout(vctx, &nsec3param, &optout);
719 	if (result != ISC_R_SUCCESS) {
720 		return (result);
721 	}
722 
723 	dns_fixedname_init(&fixed);
724 	result = dns_nsec3_hashname(
725 		&fixed, rawhash, &rhsize, name, vctx->origin, nsec3param.hash,
726 		nsec3param.iterations, nsec3param.salt, nsec3param.salt_length);
727 	if (result != ISC_R_SUCCESS) {
728 		zoneverify_log_error(vctx, "dns_nsec3_hashname(): %s",
729 				     isc_result_totext(result));
730 		return (result);
731 	}
732 
733 	/*
734 	 * We don't use dns_db_find() here as it works with the chosen
735 	 * nsec3 chain and we may also be called with uncommitted data
736 	 * from dnssec-signzone so the secure status of the zone may not
737 	 * be up to date.
738 	 */
739 	dns_rdataset_init(&rdataset);
740 	hashname = dns_fixedname_name(&fixed);
741 	result = dns_db_findnsec3node(vctx->db, hashname, false, &node);
742 	if (result == ISC_R_SUCCESS) {
743 		result = dns_db_findrdataset(vctx->db, node, vctx->ver,
744 					     dns_rdatatype_nsec3, 0, 0,
745 					     &rdataset, NULL);
746 	}
747 	if (result != ISC_R_SUCCESS &&
748 	    (!delegation || (empty && !optout) ||
749 	     (!empty && dns_nsec_isset(types, dns_rdatatype_ds))))
750 	{
751 		dns_name_format(name, namebuf, sizeof(namebuf));
752 		dns_name_format(hashname, hashbuf, sizeof(hashbuf));
753 		zoneverify_log_error(vctx, "Missing NSEC3 record for %s (%s)",
754 				     namebuf, hashbuf);
755 	} else if (result == ISC_R_NOTFOUND && delegation && (!empty || optout))
756 	{
757 		result = ISC_R_SUCCESS;
758 	} else if (result == ISC_R_SUCCESS) {
759 		result = match_nsec3(vctx, name, &nsec3param, &rdataset, types,
760 				     maxtype, rawhash, rhsize, &tvresult);
761 		if (result != ISC_R_SUCCESS) {
762 			goto done;
763 		}
764 		result = tvresult;
765 	}
766 
767 	*vresult = result;
768 	result = ISC_R_SUCCESS;
769 
770 done:
771 	if (dns_rdataset_isassociated(&rdataset)) {
772 		dns_rdataset_disassociate(&rdataset);
773 	}
774 	if (node != NULL) {
775 		dns_db_detachnode(vctx->db, &node);
776 	}
777 
778 	return (result);
779 }
780 
781 static isc_result_t
782 verifynsec3s(const vctx_t *vctx, const dns_name_t *name,
783 	     dns_rdataset_t *nsec3paramset, bool delegation, bool empty,
784 	     const unsigned char types[8192], unsigned int maxtype,
785 	     isc_result_t *vresult) {
786 	isc_result_t result;
787 
788 	for (result = dns_rdataset_first(nsec3paramset);
789 	     result == ISC_R_SUCCESS; result = dns_rdataset_next(nsec3paramset))
790 	{
791 		dns_rdata_t rdata = DNS_RDATA_INIT;
792 
793 		dns_rdataset_current(nsec3paramset, &rdata);
794 		result = verifynsec3(vctx, name, &rdata, delegation, empty,
795 				     types, maxtype, vresult);
796 		if (result != ISC_R_SUCCESS) {
797 			return (result);
798 		}
799 		if (*vresult != ISC_R_SUCCESS) {
800 			break;
801 		}
802 	}
803 	if (result == ISC_R_NOMORE) {
804 		result = ISC_R_SUCCESS;
805 	}
806 	return (result);
807 }
808 
809 static isc_result_t
810 verifyset(vctx_t *vctx, dns_rdataset_t *rdataset, const dns_name_t *name,
811 	  dns_dbnode_t *node, dst_key_t **dstkeys, size_t nkeys) {
812 	unsigned char set_algorithms[256] = { 0 };
813 	char namebuf[DNS_NAME_FORMATSIZE];
814 	char algbuf[DNS_SECALG_FORMATSIZE];
815 	char typebuf[DNS_RDATATYPE_FORMATSIZE];
816 	dns_rdataset_t sigrdataset;
817 	dns_rdatasetiter_t *rdsiter = NULL;
818 	isc_result_t result;
819 
820 	dns_rdataset_init(&sigrdataset);
821 	result = dns_db_allrdatasets(vctx->db, node, vctx->ver, 0, 0, &rdsiter);
822 	if (result != ISC_R_SUCCESS) {
823 		zoneverify_log_error(vctx, "dns_db_allrdatasets(): %s",
824 				     isc_result_totext(result));
825 		return (result);
826 	}
827 	for (result = dns_rdatasetiter_first(rdsiter); result == ISC_R_SUCCESS;
828 	     result = dns_rdatasetiter_next(rdsiter))
829 	{
830 		dns_rdatasetiter_current(rdsiter, &sigrdataset);
831 		if (sigrdataset.type == dns_rdatatype_rrsig &&
832 		    sigrdataset.covers == rdataset->type)
833 		{
834 			break;
835 		}
836 		dns_rdataset_disassociate(&sigrdataset);
837 	}
838 	if (result != ISC_R_SUCCESS) {
839 		dns_name_format(name, namebuf, sizeof(namebuf));
840 		dns_rdatatype_format(rdataset->type, typebuf, sizeof(typebuf));
841 		zoneverify_log_error(vctx, "No signatures for %s/%s", namebuf,
842 				     typebuf);
843 		for (size_t i = 0; i < ARRAY_SIZE(set_algorithms); i++) {
844 			if (vctx->act_algorithms[i] != 0) {
845 				vctx->bad_algorithms[i] = 1;
846 			}
847 		}
848 		result = ISC_R_SUCCESS;
849 		goto done;
850 	}
851 
852 	for (result = dns_rdataset_first(&sigrdataset); result == ISC_R_SUCCESS;
853 	     result = dns_rdataset_next(&sigrdataset))
854 	{
855 		dns_rdata_t rdata = DNS_RDATA_INIT;
856 		dns_rdata_rrsig_t sig;
857 
858 		dns_rdataset_current(&sigrdataset, &rdata);
859 		result = dns_rdata_tostruct(&rdata, &sig, NULL);
860 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
861 		if (rdataset->ttl != sig.originalttl) {
862 			dns_name_format(name, namebuf, sizeof(namebuf));
863 			dns_rdatatype_format(rdataset->type, typebuf,
864 					     sizeof(typebuf));
865 			zoneverify_log_error(vctx,
866 					     "TTL mismatch for "
867 					     "%s %s keytag %u",
868 					     namebuf, typebuf, sig.keyid);
869 			continue;
870 		}
871 		if ((set_algorithms[sig.algorithm] != 0) ||
872 		    (vctx->act_algorithms[sig.algorithm] == 0))
873 		{
874 			continue;
875 		}
876 		if (goodsig(vctx, &rdata, name, dstkeys, nkeys, rdataset)) {
877 			dns_rdataset_settrust(rdataset, dns_trust_secure);
878 			dns_rdataset_settrust(&sigrdataset, dns_trust_secure);
879 			set_algorithms[sig.algorithm] = 1;
880 		}
881 	}
882 	result = ISC_R_SUCCESS;
883 
884 	if (memcmp(set_algorithms, vctx->act_algorithms,
885 		   sizeof(set_algorithms)) != 0)
886 	{
887 		dns_name_format(name, namebuf, sizeof(namebuf));
888 		dns_rdatatype_format(rdataset->type, typebuf, sizeof(typebuf));
889 		for (size_t i = 0; i < ARRAY_SIZE(set_algorithms); i++) {
890 			if ((vctx->act_algorithms[i] != 0) &&
891 			    (set_algorithms[i] == 0))
892 			{
893 				dns_secalg_format(i, algbuf, sizeof(algbuf));
894 				zoneverify_log_error(vctx,
895 						     "No correct %s signature "
896 						     "for %s %s",
897 						     algbuf, namebuf, typebuf);
898 				vctx->bad_algorithms[i] = 1;
899 			}
900 		}
901 	}
902 
903 done:
904 	if (dns_rdataset_isassociated(&sigrdataset)) {
905 		dns_rdataset_disassociate(&sigrdataset);
906 	}
907 	dns_rdatasetiter_destroy(&rdsiter);
908 
909 	return (result);
910 }
911 
912 static isc_result_t
913 verifynode(vctx_t *vctx, const dns_name_t *name, dns_dbnode_t *node,
914 	   bool delegation, dst_key_t **dstkeys, size_t nkeys,
915 	   dns_rdataset_t *nsecset, dns_rdataset_t *nsec3paramset,
916 	   const dns_name_t *nextname, isc_result_t *vresult) {
917 	unsigned char types[8192] = { 0 };
918 	unsigned int maxtype = 0;
919 	dns_rdataset_t rdataset;
920 	dns_rdatasetiter_t *rdsiter = NULL;
921 	isc_result_t result, tvresult = ISC_R_UNSET;
922 
923 	REQUIRE(vresult != NULL || (nsecset == NULL && nsec3paramset == NULL));
924 
925 	result = dns_db_allrdatasets(vctx->db, node, vctx->ver, 0, 0, &rdsiter);
926 	if (result != ISC_R_SUCCESS) {
927 		zoneverify_log_error(vctx, "dns_db_allrdatasets(): %s",
928 				     isc_result_totext(result));
929 		return (result);
930 	}
931 
932 	result = dns_rdatasetiter_first(rdsiter);
933 	dns_rdataset_init(&rdataset);
934 	while (result == ISC_R_SUCCESS) {
935 		dns_rdatasetiter_current(rdsiter, &rdataset);
936 		/*
937 		 * If we are not at a delegation then everything should be
938 		 * signed.  If we are at a delegation then only the DS set
939 		 * is signed.  The NS set is not signed at a delegation but
940 		 * its existence is recorded in the bit map.  Anything else
941 		 * other than NSEC and DS is not signed at a delegation.
942 		 */
943 		if (rdataset.type != dns_rdatatype_rrsig &&
944 		    rdataset.type != dns_rdatatype_dnskey &&
945 		    (!delegation || rdataset.type == dns_rdatatype_ds ||
946 		     rdataset.type == dns_rdatatype_nsec))
947 		{
948 			result = verifyset(vctx, &rdataset, name, node, dstkeys,
949 					   nkeys);
950 			if (result != ISC_R_SUCCESS) {
951 				dns_rdataset_disassociate(&rdataset);
952 				dns_rdatasetiter_destroy(&rdsiter);
953 				return (result);
954 			}
955 			dns_nsec_setbit(types, rdataset.type, 1);
956 			if (rdataset.type > maxtype) {
957 				maxtype = rdataset.type;
958 			}
959 		} else if (rdataset.type != dns_rdatatype_rrsig &&
960 			   rdataset.type != dns_rdatatype_dnskey)
961 		{
962 			if (rdataset.type == dns_rdatatype_ns) {
963 				dns_nsec_setbit(types, rdataset.type, 1);
964 			}
965 			result = check_no_rrsig(vctx, &rdataset, name, node);
966 			if (result != ISC_R_SUCCESS) {
967 				dns_rdataset_disassociate(&rdataset);
968 				dns_rdatasetiter_destroy(&rdsiter);
969 				return (result);
970 			}
971 		} else {
972 			dns_nsec_setbit(types, rdataset.type, 1);
973 		}
974 		dns_rdataset_disassociate(&rdataset);
975 		result = dns_rdatasetiter_next(rdsiter);
976 	}
977 	dns_rdatasetiter_destroy(&rdsiter);
978 	if (result != ISC_R_NOMORE) {
979 		zoneverify_log_error(vctx, "rdataset iteration failed: %s",
980 				     isc_result_totext(result));
981 		return (result);
982 	}
983 
984 	if (vresult == NULL) {
985 		return (ISC_R_SUCCESS);
986 	}
987 
988 	*vresult = ISC_R_SUCCESS;
989 
990 	if (nsecset != NULL && dns_rdataset_isassociated(nsecset)) {
991 		result = verifynsec(vctx, name, node, nextname, &tvresult);
992 		if (result != ISC_R_SUCCESS) {
993 			return (result);
994 		}
995 		*vresult = tvresult;
996 	}
997 
998 	if (nsec3paramset != NULL && dns_rdataset_isassociated(nsec3paramset)) {
999 		result = verifynsec3s(vctx, name, nsec3paramset, delegation,
1000 				      false, types, maxtype, &tvresult);
1001 		if (result != ISC_R_SUCCESS) {
1002 			return (result);
1003 		}
1004 		if (*vresult == ISC_R_SUCCESS) {
1005 			*vresult = tvresult;
1006 		}
1007 	}
1008 
1009 	return (ISC_R_SUCCESS);
1010 }
1011 
1012 static isc_result_t
1013 is_empty(const vctx_t *vctx, dns_dbnode_t *node, bool *empty) {
1014 	dns_rdatasetiter_t *rdsiter = NULL;
1015 	isc_result_t result;
1016 
1017 	result = dns_db_allrdatasets(vctx->db, node, vctx->ver, 0, 0, &rdsiter);
1018 	if (result != ISC_R_SUCCESS) {
1019 		zoneverify_log_error(vctx, "dns_db_allrdatasets(): %s",
1020 				     isc_result_totext(result));
1021 		return (result);
1022 	}
1023 	result = dns_rdatasetiter_first(rdsiter);
1024 	dns_rdatasetiter_destroy(&rdsiter);
1025 
1026 	*empty = (result == ISC_R_NOMORE);
1027 
1028 	return (ISC_R_SUCCESS);
1029 }
1030 
1031 static isc_result_t
1032 check_no_nsec(const vctx_t *vctx, const dns_name_t *name, dns_dbnode_t *node) {
1033 	bool nsec_exists = false;
1034 	dns_rdataset_t rdataset;
1035 	isc_result_t result;
1036 
1037 	dns_rdataset_init(&rdataset);
1038 	result = dns_db_findrdataset(vctx->db, node, vctx->ver,
1039 				     dns_rdatatype_nsec, 0, 0, &rdataset, NULL);
1040 	if (result != ISC_R_NOTFOUND) {
1041 		char namebuf[DNS_NAME_FORMATSIZE];
1042 		dns_name_format(name, namebuf, sizeof(namebuf));
1043 		zoneverify_log_error(vctx, "unexpected NSEC RRset at %s",
1044 				     namebuf);
1045 		nsec_exists = true;
1046 	}
1047 
1048 	if (dns_rdataset_isassociated(&rdataset)) {
1049 		dns_rdataset_disassociate(&rdataset);
1050 	}
1051 
1052 	return (nsec_exists ? ISC_R_FAILURE : ISC_R_SUCCESS);
1053 }
1054 
1055 static void
1056 free_element(isc_mem_t *mctx, struct nsec3_chain_fixed *e) {
1057 	size_t len;
1058 
1059 	len = sizeof(*e) + e->salt_length + 2 * e->next_length;
1060 	isc_mem_put(mctx, e, len);
1061 }
1062 
1063 static void
1064 free_element_heap(void *element, void *uap) {
1065 	struct nsec3_chain_fixed *e = (struct nsec3_chain_fixed *)element;
1066 	isc_mem_t *mctx = (isc_mem_t *)uap;
1067 
1068 	free_element(mctx, e);
1069 }
1070 
1071 static bool
1072 _checknext(const vctx_t *vctx, const struct nsec3_chain_fixed *first,
1073 	   const struct nsec3_chain_fixed *e) {
1074 	char buf[512];
1075 	const unsigned char *d1 = (const unsigned char *)(first + 1);
1076 	const unsigned char *d2 = (const unsigned char *)(e + 1);
1077 	isc_buffer_t b;
1078 	isc_region_t sr;
1079 
1080 	d1 += first->salt_length + first->next_length;
1081 	d2 += e->salt_length;
1082 
1083 	if (memcmp(d1, d2, first->next_length) == 0) {
1084 		return (true);
1085 	}
1086 
1087 	DE_CONST(d1 - first->next_length, sr.base);
1088 	sr.length = first->next_length;
1089 	isc_buffer_init(&b, buf, sizeof(buf));
1090 	isc_base32hex_totext(&sr, 1, "", &b);
1091 	zoneverify_log_error(vctx, "Break in NSEC3 chain at: %.*s",
1092 			     (int)isc_buffer_usedlength(&b), buf);
1093 
1094 	DE_CONST(d1, sr.base);
1095 	sr.length = first->next_length;
1096 	isc_buffer_init(&b, buf, sizeof(buf));
1097 	isc_base32hex_totext(&sr, 1, "", &b);
1098 	zoneverify_log_error(vctx, "Expected: %.*s",
1099 			     (int)isc_buffer_usedlength(&b), buf);
1100 
1101 	DE_CONST(d2, sr.base);
1102 	sr.length = first->next_length;
1103 	isc_buffer_init(&b, buf, sizeof(buf));
1104 	isc_base32hex_totext(&sr, 1, "", &b);
1105 	zoneverify_log_error(vctx, "Found: %.*s",
1106 			     (int)isc_buffer_usedlength(&b), buf);
1107 
1108 	return (false);
1109 }
1110 
1111 static bool
1112 checknext(isc_mem_t *mctx, const vctx_t *vctx,
1113 	  const struct nsec3_chain_fixed *first, struct nsec3_chain_fixed *prev,
1114 	  const struct nsec3_chain_fixed *cur) {
1115 	bool result = _checknext(vctx, prev, cur);
1116 
1117 	if (prev != first) {
1118 		free_element(mctx, prev);
1119 	}
1120 
1121 	return (result);
1122 }
1123 
1124 static bool
1125 checklast(isc_mem_t *mctx, const vctx_t *vctx, struct nsec3_chain_fixed *first,
1126 	  struct nsec3_chain_fixed *prev) {
1127 	bool result = _checknext(vctx, prev, first);
1128 	if (prev != first) {
1129 		free_element(mctx, prev);
1130 	}
1131 	free_element(mctx, first);
1132 
1133 	return (result);
1134 }
1135 
1136 static isc_result_t
1137 verify_nsec3_chains(const vctx_t *vctx, isc_mem_t *mctx) {
1138 	isc_result_t result = ISC_R_SUCCESS;
1139 	struct nsec3_chain_fixed *e, *f = NULL;
1140 	struct nsec3_chain_fixed *first = NULL, *prev = NULL;
1141 
1142 	while ((e = isc_heap_element(vctx->expected_chains, 1)) != NULL) {
1143 		isc_heap_delete(vctx->expected_chains, 1);
1144 		if (f == NULL) {
1145 			f = isc_heap_element(vctx->found_chains, 1);
1146 		}
1147 		if (f != NULL) {
1148 			isc_heap_delete(vctx->found_chains, 1);
1149 
1150 			/*
1151 			 * Check that they match.
1152 			 */
1153 			if (chain_equal(e, f, chain_length(e))) {
1154 				free_element(mctx, f);
1155 				f = NULL;
1156 			} else {
1157 				if (result == ISC_R_SUCCESS) {
1158 					zoneverify_log_error(vctx, "Expected "
1159 								   "and found "
1160 								   "NSEC3 "
1161 								   "chains not "
1162 								   "equal");
1163 				}
1164 				result = ISC_R_FAILURE;
1165 				/*
1166 				 * Attempt to resync found_chain.
1167 				 */
1168 				while (f != NULL && !chain_compare(e, f)) {
1169 					free_element(mctx, f);
1170 					f = isc_heap_element(vctx->found_chains,
1171 							     1);
1172 					if (f != NULL) {
1173 						isc_heap_delete(
1174 							vctx->found_chains, 1);
1175 					}
1176 					if (f != NULL &&
1177 					    chain_equal(e, f, chain_length(e)))
1178 					{
1179 						free_element(mctx, f);
1180 						f = NULL;
1181 						break;
1182 					}
1183 				}
1184 			}
1185 		} else if (result == ISC_R_SUCCESS) {
1186 			zoneverify_log_error(vctx, "Expected and found NSEC3 "
1187 						   "chains "
1188 						   "not equal");
1189 			result = ISC_R_FAILURE;
1190 		}
1191 
1192 		if (first == NULL) {
1193 			prev = first = e;
1194 		} else if (!chain_equal(first, e, first->salt_length)) {
1195 			if (!checklast(mctx, vctx, first, prev)) {
1196 				result = ISC_R_FAILURE;
1197 			}
1198 
1199 			prev = first = e;
1200 		} else {
1201 			if (!checknext(mctx, vctx, first, prev, e)) {
1202 				result = ISC_R_FAILURE;
1203 			}
1204 
1205 			prev = e;
1206 		}
1207 	}
1208 	if (prev != NULL) {
1209 		if (!checklast(mctx, vctx, first, prev)) {
1210 			result = ISC_R_FAILURE;
1211 		}
1212 	}
1213 	do {
1214 		if (f != NULL) {
1215 			if (result == ISC_R_SUCCESS) {
1216 				zoneverify_log_error(vctx, "Expected and found "
1217 							   "NSEC3 chains not "
1218 							   "equal");
1219 				result = ISC_R_FAILURE;
1220 			}
1221 			free_element(mctx, f);
1222 		}
1223 		f = isc_heap_element(vctx->found_chains, 1);
1224 		if (f != NULL) {
1225 			isc_heap_delete(vctx->found_chains, 1);
1226 		}
1227 	} while (f != NULL);
1228 
1229 	return (result);
1230 }
1231 
1232 static isc_result_t
1233 verifyemptynodes(const vctx_t *vctx, const dns_name_t *name,
1234 		 const dns_name_t *prevname, bool isdelegation,
1235 		 dns_rdataset_t *nsec3paramset, isc_result_t *vresult) {
1236 	dns_namereln_t reln;
1237 	int order;
1238 	unsigned int labels, nlabels, i;
1239 	dns_name_t suffix;
1240 	isc_result_t result, tvresult = ISC_R_UNSET;
1241 
1242 	*vresult = ISC_R_SUCCESS;
1243 
1244 	reln = dns_name_fullcompare(prevname, name, &order, &labels);
1245 	if (order >= 0) {
1246 		return (ISC_R_SUCCESS);
1247 	}
1248 
1249 	nlabels = dns_name_countlabels(name);
1250 
1251 	if (reln == dns_namereln_commonancestor ||
1252 	    reln == dns_namereln_contains)
1253 	{
1254 		dns_name_init(&suffix, NULL);
1255 		for (i = labels + 1; i < nlabels; i++) {
1256 			dns_name_getlabelsequence(name, nlabels - i, i,
1257 						  &suffix);
1258 			if (nsec3paramset != NULL &&
1259 			    dns_rdataset_isassociated(nsec3paramset))
1260 			{
1261 				result = verifynsec3s(
1262 					vctx, &suffix, nsec3paramset,
1263 					isdelegation, true, NULL, 0, &tvresult);
1264 				if (result != ISC_R_SUCCESS) {
1265 					return (result);
1266 				}
1267 				if (*vresult == ISC_R_SUCCESS) {
1268 					*vresult = tvresult;
1269 				}
1270 			}
1271 		}
1272 	}
1273 
1274 	return (ISC_R_SUCCESS);
1275 }
1276 
1277 static void
1278 vctx_init(vctx_t *vctx, isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db,
1279 	  dns_dbversion_t *ver, dns_name_t *origin, dns_keytable_t *secroots) {
1280 	memset(vctx, 0, sizeof(*vctx));
1281 
1282 	vctx->mctx = mctx;
1283 	vctx->zone = zone;
1284 	vctx->db = db;
1285 	vctx->ver = ver;
1286 	vctx->origin = origin;
1287 	vctx->secroots = secroots;
1288 	vctx->goodksk = false;
1289 	vctx->goodzsk = false;
1290 
1291 	dns_rdataset_init(&vctx->keyset);
1292 	dns_rdataset_init(&vctx->keysigs);
1293 	dns_rdataset_init(&vctx->soaset);
1294 	dns_rdataset_init(&vctx->soasigs);
1295 	dns_rdataset_init(&vctx->nsecset);
1296 	dns_rdataset_init(&vctx->nsecsigs);
1297 	dns_rdataset_init(&vctx->nsec3paramset);
1298 	dns_rdataset_init(&vctx->nsec3paramsigs);
1299 
1300 	vctx->expected_chains = NULL;
1301 	isc_heap_create(mctx, chain_compare, NULL, 1024,
1302 			&vctx->expected_chains);
1303 
1304 	vctx->found_chains = NULL;
1305 	isc_heap_create(mctx, chain_compare, NULL, 1024, &vctx->found_chains);
1306 }
1307 
1308 static void
1309 vctx_destroy(vctx_t *vctx) {
1310 	if (dns_rdataset_isassociated(&vctx->keyset)) {
1311 		dns_rdataset_disassociate(&vctx->keyset);
1312 	}
1313 	if (dns_rdataset_isassociated(&vctx->keysigs)) {
1314 		dns_rdataset_disassociate(&vctx->keysigs);
1315 	}
1316 	if (dns_rdataset_isassociated(&vctx->soaset)) {
1317 		dns_rdataset_disassociate(&vctx->soaset);
1318 	}
1319 	if (dns_rdataset_isassociated(&vctx->soasigs)) {
1320 		dns_rdataset_disassociate(&vctx->soasigs);
1321 	}
1322 	if (dns_rdataset_isassociated(&vctx->nsecset)) {
1323 		dns_rdataset_disassociate(&vctx->nsecset);
1324 	}
1325 	if (dns_rdataset_isassociated(&vctx->nsecsigs)) {
1326 		dns_rdataset_disassociate(&vctx->nsecsigs);
1327 	}
1328 	if (dns_rdataset_isassociated(&vctx->nsec3paramset)) {
1329 		dns_rdataset_disassociate(&vctx->nsec3paramset);
1330 	}
1331 	if (dns_rdataset_isassociated(&vctx->nsec3paramsigs)) {
1332 		dns_rdataset_disassociate(&vctx->nsec3paramsigs);
1333 	}
1334 	isc_heap_foreach(vctx->expected_chains, free_element_heap, vctx->mctx);
1335 	isc_heap_destroy(&vctx->expected_chains);
1336 	isc_heap_foreach(vctx->found_chains, free_element_heap, vctx->mctx);
1337 	isc_heap_destroy(&vctx->found_chains);
1338 }
1339 
1340 static isc_result_t
1341 check_apex_rrsets(vctx_t *vctx) {
1342 	dns_dbnode_t *node = NULL;
1343 	isc_result_t result;
1344 
1345 	result = dns_db_findnode(vctx->db, vctx->origin, false, &node);
1346 	if (result != ISC_R_SUCCESS) {
1347 		zoneverify_log_error(vctx,
1348 				     "failed to find the zone's origin: %s",
1349 				     isc_result_totext(result));
1350 		return (result);
1351 	}
1352 
1353 	result = dns_db_findrdataset(vctx->db, node, vctx->ver,
1354 				     dns_rdatatype_dnskey, 0, 0, &vctx->keyset,
1355 				     &vctx->keysigs);
1356 	if (result != ISC_R_SUCCESS) {
1357 		zoneverify_log_error(vctx, "Zone contains no DNSSEC keys");
1358 		goto done;
1359 	}
1360 
1361 	result = dns_db_findrdataset(vctx->db, node, vctx->ver,
1362 				     dns_rdatatype_soa, 0, 0, &vctx->soaset,
1363 				     &vctx->soasigs);
1364 	if (result != ISC_R_SUCCESS) {
1365 		zoneverify_log_error(vctx, "Zone contains no SOA record");
1366 		goto done;
1367 	}
1368 
1369 	result = dns_db_findrdataset(vctx->db, node, vctx->ver,
1370 				     dns_rdatatype_nsec, 0, 0, &vctx->nsecset,
1371 				     &vctx->nsecsigs);
1372 	if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
1373 		zoneverify_log_error(vctx, "NSEC lookup failed");
1374 		goto done;
1375 	}
1376 
1377 	result = dns_db_findrdataset(
1378 		vctx->db, node, vctx->ver, dns_rdatatype_nsec3param, 0, 0,
1379 		&vctx->nsec3paramset, &vctx->nsec3paramsigs);
1380 	if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
1381 		zoneverify_log_error(vctx, "NSEC3PARAM lookup failed");
1382 		goto done;
1383 	}
1384 
1385 	if (!dns_rdataset_isassociated(&vctx->keysigs)) {
1386 		zoneverify_log_error(vctx, "DNSKEY is not signed "
1387 					   "(keys offline or inactive?)");
1388 		result = ISC_R_FAILURE;
1389 		goto done;
1390 	}
1391 
1392 	if (!dns_rdataset_isassociated(&vctx->soasigs)) {
1393 		zoneverify_log_error(vctx, "SOA is not signed "
1394 					   "(keys offline or inactive?)");
1395 		result = ISC_R_FAILURE;
1396 		goto done;
1397 	}
1398 
1399 	if (dns_rdataset_isassociated(&vctx->nsecset) &&
1400 	    !dns_rdataset_isassociated(&vctx->nsecsigs))
1401 	{
1402 		zoneverify_log_error(vctx, "NSEC is not signed "
1403 					   "(keys offline or inactive?)");
1404 		result = ISC_R_FAILURE;
1405 		goto done;
1406 	}
1407 
1408 	if (dns_rdataset_isassociated(&vctx->nsec3paramset) &&
1409 	    !dns_rdataset_isassociated(&vctx->nsec3paramsigs))
1410 	{
1411 		zoneverify_log_error(vctx, "NSEC3PARAM is not signed "
1412 					   "(keys offline or inactive?)");
1413 		result = ISC_R_FAILURE;
1414 		goto done;
1415 	}
1416 
1417 	if (!dns_rdataset_isassociated(&vctx->nsecset) &&
1418 	    !dns_rdataset_isassociated(&vctx->nsec3paramset))
1419 	{
1420 		zoneverify_log_error(vctx, "No valid NSEC/NSEC3 chain for "
1421 					   "testing");
1422 		result = ISC_R_FAILURE;
1423 		goto done;
1424 	}
1425 
1426 	result = ISC_R_SUCCESS;
1427 
1428 done:
1429 	dns_db_detachnode(vctx->db, &node);
1430 
1431 	return (result);
1432 }
1433 
1434 /*%
1435  * Update 'vctx' tables tracking active and standby key algorithms used in the
1436  * verified zone based on the signatures made using 'dnskey' (prepared from
1437  * 'rdata') found at zone apex.  Set 'vctx->goodksk' or 'vctx->goodzsk' to true
1438  * if 'dnskey' correctly signs the DNSKEY RRset at zone apex and either
1439  * 'vctx->secroots' is NULL or 'dnskey' is present in 'vctx->secroots'.
1440  *
1441  * The variables to update are chosen based on 'is_ksk', which is true when
1442  * 'dnskey' is a KSK and false otherwise.
1443  */
1444 static void
1445 check_dnskey_sigs(vctx_t *vctx, const dns_rdata_dnskey_t *dnskey,
1446 		  dns_rdata_t *keyrdata, bool is_ksk) {
1447 	unsigned char *active_keys = NULL, *standby_keys = NULL;
1448 	dns_keynode_t *keynode = NULL;
1449 	bool *goodkey = NULL;
1450 	dst_key_t *key = NULL;
1451 	isc_result_t result;
1452 	dns_rdataset_t dsset;
1453 
1454 	active_keys = (is_ksk ? vctx->ksk_algorithms : vctx->zsk_algorithms);
1455 	standby_keys = (is_ksk ? vctx->standby_ksk : vctx->standby_zsk);
1456 	goodkey = (is_ksk ? &vctx->goodksk : &vctx->goodzsk);
1457 
1458 	/*
1459 	 * First, does this key sign the DNSKEY rrset?
1460 	 */
1461 	if (!dns_dnssec_selfsigns(keyrdata, vctx->origin, &vctx->keyset,
1462 				  &vctx->keysigs, false, vctx->mctx))
1463 	{
1464 		if (!is_ksk &&
1465 		    dns_dnssec_signs(keyrdata, vctx->origin, &vctx->soaset,
1466 				     &vctx->soasigs, false, vctx->mctx))
1467 		{
1468 			if (active_keys[dnskey->algorithm] != DNS_KEYALG_MAX) {
1469 				active_keys[dnskey->algorithm]++;
1470 			}
1471 		} else {
1472 			if (standby_keys[dnskey->algorithm] != DNS_KEYALG_MAX) {
1473 				standby_keys[dnskey->algorithm]++;
1474 			}
1475 		}
1476 		return;
1477 	}
1478 
1479 	if (active_keys[dnskey->algorithm] != DNS_KEYALG_MAX) {
1480 		active_keys[dnskey->algorithm]++;
1481 	}
1482 
1483 	/*
1484 	 * If a trust anchor table was not supplied, a correctly self-signed
1485 	 * DNSKEY RRset is good enough.
1486 	 */
1487 	if (vctx->secroots == NULL) {
1488 		*goodkey = true;
1489 		return;
1490 	}
1491 
1492 	/*
1493 	 * Convert the supplied key rdata to dst_key_t. (If this
1494 	 * fails we can't go further.)
1495 	 */
1496 	result = dns_dnssec_keyfromrdata(vctx->origin, keyrdata, vctx->mctx,
1497 					 &key);
1498 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
1499 
1500 	/*
1501 	 * Look up the supplied key in the trust anchor table.
1502 	 * If we don't find an exact match, or if the keynode data
1503 	 * is NULL, then we have neither a DNSKEY nor a DS format
1504 	 * trust anchor, and can give up.
1505 	 */
1506 	result = dns_keytable_find(vctx->secroots, vctx->origin, &keynode);
1507 	if (result != ISC_R_SUCCESS) {
1508 		/* No such trust anchor */
1509 		goto cleanup;
1510 	}
1511 
1512 	/*
1513 	 * If the keynode has any DS format trust anchors, that means
1514 	 * it doesn't have any DNSKEY ones. So, we can check for a DS
1515 	 * match and then stop.
1516 	 */
1517 	dns_rdataset_init(&dsset);
1518 	if (dns_keynode_dsset(keynode, &dsset)) {
1519 		for (result = dns_rdataset_first(&dsset);
1520 		     result == ISC_R_SUCCESS;
1521 		     result = dns_rdataset_next(&dsset))
1522 		{
1523 			dns_rdata_t dsrdata = DNS_RDATA_INIT;
1524 			dns_rdata_t newdsrdata = DNS_RDATA_INIT;
1525 			unsigned char buf[DNS_DS_BUFFERSIZE];
1526 			dns_rdata_ds_t ds;
1527 
1528 			dns_rdata_reset(&dsrdata);
1529 			dns_rdataset_current(&dsset, &dsrdata);
1530 			result = dns_rdata_tostruct(&dsrdata, &ds, NULL);
1531 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
1532 
1533 			if (ds.key_tag != dst_key_id(key) ||
1534 			    ds.algorithm != dst_key_alg(key))
1535 			{
1536 				continue;
1537 			}
1538 
1539 			result = dns_ds_buildrdata(vctx->origin, keyrdata,
1540 						   ds.digest_type, buf,
1541 						   &newdsrdata);
1542 			if (result != ISC_R_SUCCESS) {
1543 				continue;
1544 			}
1545 
1546 			if (dns_rdata_compare(&dsrdata, &newdsrdata) == 0) {
1547 				dns_rdataset_settrust(&vctx->keyset,
1548 						      dns_trust_secure);
1549 				dns_rdataset_settrust(&vctx->keysigs,
1550 						      dns_trust_secure);
1551 				*goodkey = true;
1552 				break;
1553 			}
1554 		}
1555 		dns_rdataset_disassociate(&dsset);
1556 
1557 		goto cleanup;
1558 	}
1559 
1560 cleanup:
1561 	if (keynode != NULL) {
1562 		dns_keytable_detachkeynode(vctx->secroots, &keynode);
1563 	}
1564 	if (key != NULL) {
1565 		dst_key_free(&key);
1566 	}
1567 }
1568 
1569 /*%
1570  * Check that the DNSKEY RR has at least one self signing KSK and one ZSK per
1571  * algorithm in it (or, if -x was used, one self-signing KSK).
1572  */
1573 static isc_result_t
1574 check_dnskey(vctx_t *vctx) {
1575 	dns_rdata_t rdata = DNS_RDATA_INIT;
1576 	dns_rdata_dnskey_t dnskey;
1577 	isc_result_t result;
1578 	bool is_ksk;
1579 
1580 	for (result = dns_rdataset_first(&vctx->keyset);
1581 	     result == ISC_R_SUCCESS; result = dns_rdataset_next(&vctx->keyset))
1582 	{
1583 		dns_rdataset_current(&vctx->keyset, &rdata);
1584 		result = dns_rdata_tostruct(&rdata, &dnskey, NULL);
1585 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
1586 		is_ksk = ((dnskey.flags & DNS_KEYFLAG_KSK) != 0);
1587 
1588 		if ((dnskey.flags & DNS_KEYOWNER_ZONE) != 0 &&
1589 		    (dnskey.flags & DNS_KEYFLAG_REVOKE) != 0)
1590 		{
1591 			if ((dnskey.flags & DNS_KEYFLAG_KSK) != 0 &&
1592 			    !dns_dnssec_selfsigns(&rdata, vctx->origin,
1593 						  &vctx->keyset, &vctx->keysigs,
1594 						  false, vctx->mctx))
1595 			{
1596 				char namebuf[DNS_NAME_FORMATSIZE];
1597 				char buffer[1024];
1598 				isc_buffer_t buf;
1599 
1600 				dns_name_format(vctx->origin, namebuf,
1601 						sizeof(namebuf));
1602 				isc_buffer_init(&buf, buffer, sizeof(buffer));
1603 				result = dns_rdata_totext(&rdata, NULL, &buf);
1604 				if (result != ISC_R_SUCCESS) {
1605 					zoneverify_log_error(
1606 						vctx, "dns_rdata_totext: %s",
1607 						isc_result_totext(result));
1608 					return (ISC_R_FAILURE);
1609 				}
1610 				zoneverify_log_error(
1611 					vctx,
1612 					"revoked KSK is not self signed:\n"
1613 					"%s DNSKEY %.*s",
1614 					namebuf,
1615 					(int)isc_buffer_usedlength(&buf),
1616 					buffer);
1617 				return (ISC_R_FAILURE);
1618 			}
1619 			if ((dnskey.flags & DNS_KEYFLAG_KSK) != 0 &&
1620 			    vctx->revoked_ksk[dnskey.algorithm] !=
1621 				    DNS_KEYALG_MAX)
1622 			{
1623 				vctx->revoked_ksk[dnskey.algorithm]++;
1624 			} else if ((dnskey.flags & DNS_KEYFLAG_KSK) == 0 &&
1625 				   vctx->revoked_zsk[dnskey.algorithm] !=
1626 					   DNS_KEYALG_MAX)
1627 			{
1628 				vctx->revoked_zsk[dnskey.algorithm]++;
1629 			}
1630 		} else {
1631 			check_dnskey_sigs(vctx, &dnskey, &rdata, is_ksk);
1632 		}
1633 		dns_rdata_freestruct(&dnskey);
1634 		dns_rdata_reset(&rdata);
1635 	}
1636 
1637 	return (ISC_R_SUCCESS);
1638 }
1639 
1640 static void
1641 determine_active_algorithms(vctx_t *vctx, bool ignore_kskflag,
1642 			    bool keyset_kskonly,
1643 			    void (*report)(const char *, ...)) {
1644 	char algbuf[DNS_SECALG_FORMATSIZE];
1645 
1646 	report("Verifying the zone using the following algorithms:");
1647 
1648 	for (size_t i = 0; i < ARRAY_SIZE(vctx->act_algorithms); i++) {
1649 		if (ignore_kskflag) {
1650 			vctx->act_algorithms[i] = (vctx->ksk_algorithms[i] !=
1651 							   0 ||
1652 						   vctx->zsk_algorithms[i] != 0)
1653 							  ? 1
1654 							  : 0;
1655 		} else {
1656 			vctx->act_algorithms[i] = vctx->ksk_algorithms[i] != 0
1657 							  ? 1
1658 							  : 0;
1659 		}
1660 		if (vctx->act_algorithms[i] != 0) {
1661 			dns_secalg_format(i, algbuf, sizeof(algbuf));
1662 			report("- %s", algbuf);
1663 		}
1664 	}
1665 
1666 	if (ignore_kskflag || keyset_kskonly) {
1667 		return;
1668 	}
1669 
1670 	for (size_t i = 0; i < ARRAY_SIZE(vctx->ksk_algorithms); i++) {
1671 		/*
1672 		 * The counts should both be zero or both be non-zero.  Mark
1673 		 * the algorithm as bad if this is not met.
1674 		 */
1675 		if ((vctx->ksk_algorithms[i] != 0) ==
1676 		    (vctx->zsk_algorithms[i] != 0))
1677 		{
1678 			continue;
1679 		}
1680 		dns_secalg_format(i, algbuf, sizeof(algbuf));
1681 		zoneverify_log_error(vctx, "Missing %s for algorithm %s",
1682 				     (vctx->ksk_algorithms[i] != 0) ? "ZSK"
1683 								    : "self-"
1684 								      "signed "
1685 								      "KSK",
1686 				     algbuf);
1687 		vctx->bad_algorithms[i] = 1;
1688 	}
1689 }
1690 
1691 /*%
1692  * Check that all the records not yet verified were signed by keys that are
1693  * present in the DNSKEY RRset.
1694  */
1695 static isc_result_t
1696 verify_nodes(vctx_t *vctx, isc_result_t *vresult) {
1697 	dns_fixedname_t fname, fnextname, fprevname, fzonecut;
1698 	dns_name_t *name, *nextname, *prevname, *zonecut;
1699 	dns_dbnode_t *node = NULL, *nextnode;
1700 	dns_dbiterator_t *dbiter = NULL;
1701 	dst_key_t **dstkeys;
1702 	size_t count, nkeys = 0;
1703 	bool done = false;
1704 	isc_result_t tvresult = ISC_R_UNSET;
1705 	isc_result_t result;
1706 
1707 	name = dns_fixedname_initname(&fname);
1708 	nextname = dns_fixedname_initname(&fnextname);
1709 	dns_fixedname_init(&fprevname);
1710 	prevname = NULL;
1711 	dns_fixedname_init(&fzonecut);
1712 	zonecut = NULL;
1713 
1714 	count = dns_rdataset_count(&vctx->keyset);
1715 	dstkeys = isc_mem_get(vctx->mctx, sizeof(*dstkeys) * count);
1716 
1717 	for (result = dns_rdataset_first(&vctx->keyset);
1718 	     result == ISC_R_SUCCESS; result = dns_rdataset_next(&vctx->keyset))
1719 	{
1720 		dns_rdata_t rdata = DNS_RDATA_INIT;
1721 		dns_rdataset_current(&vctx->keyset, &rdata);
1722 		dstkeys[nkeys] = NULL;
1723 		result = dns_dnssec_keyfromrdata(vctx->origin, &rdata,
1724 						 vctx->mctx, &dstkeys[nkeys]);
1725 		if (result == ISC_R_SUCCESS) {
1726 			nkeys++;
1727 		}
1728 	}
1729 
1730 	result = dns_db_createiterator(vctx->db, DNS_DB_NONSEC3, &dbiter);
1731 	if (result != ISC_R_SUCCESS) {
1732 		zoneverify_log_error(vctx, "dns_db_createiterator(): %s",
1733 				     isc_result_totext(result));
1734 		goto done;
1735 	}
1736 
1737 	result = dns_dbiterator_first(dbiter);
1738 	if (result != ISC_R_SUCCESS) {
1739 		zoneverify_log_error(vctx, "dns_dbiterator_first(): %s",
1740 				     isc_result_totext(result));
1741 		goto done;
1742 	}
1743 
1744 	while (!done) {
1745 		bool isdelegation = false;
1746 
1747 		result = dns_dbiterator_current(dbiter, &node, name);
1748 		if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
1749 			zoneverify_log_error(vctx,
1750 					     "dns_dbiterator_current(): %s",
1751 					     isc_result_totext(result));
1752 			goto done;
1753 		}
1754 		if (!dns_name_issubdomain(name, vctx->origin)) {
1755 			result = check_no_nsec(vctx, name, node);
1756 			if (result != ISC_R_SUCCESS) {
1757 				dns_db_detachnode(vctx->db, &node);
1758 				goto done;
1759 			}
1760 			dns_db_detachnode(vctx->db, &node);
1761 			result = dns_dbiterator_next(dbiter);
1762 			if (result == ISC_R_NOMORE) {
1763 				done = true;
1764 			} else if (result != ISC_R_SUCCESS) {
1765 				zoneverify_log_error(vctx,
1766 						     "dns_dbiterator_next(): "
1767 						     "%s",
1768 						     isc_result_totext(result));
1769 				goto done;
1770 			}
1771 			continue;
1772 		}
1773 		if (is_delegation(vctx, name, node, NULL)) {
1774 			zonecut = dns_fixedname_name(&fzonecut);
1775 			dns_name_copy(name, zonecut);
1776 			isdelegation = true;
1777 		} else if (has_dname(vctx, node)) {
1778 			zonecut = dns_fixedname_name(&fzonecut);
1779 			dns_name_copy(name, zonecut);
1780 		}
1781 		nextnode = NULL;
1782 		result = dns_dbiterator_next(dbiter);
1783 		while (result == ISC_R_SUCCESS) {
1784 			bool empty;
1785 			result = dns_dbiterator_current(dbiter, &nextnode,
1786 							nextname);
1787 			if (result != ISC_R_SUCCESS &&
1788 			    result != DNS_R_NEWORIGIN)
1789 			{
1790 				zoneverify_log_error(vctx,
1791 						     "dns_dbiterator_current():"
1792 						     " %s",
1793 						     isc_result_totext(result));
1794 				dns_db_detachnode(vctx->db, &node);
1795 				goto done;
1796 			}
1797 			if (!dns_name_issubdomain(nextname, vctx->origin) ||
1798 			    (zonecut != NULL &&
1799 			     dns_name_issubdomain(nextname, zonecut)))
1800 			{
1801 				result = check_no_nsec(vctx, nextname,
1802 						       nextnode);
1803 				if (result != ISC_R_SUCCESS) {
1804 					dns_db_detachnode(vctx->db, &node);
1805 					dns_db_detachnode(vctx->db, &nextnode);
1806 					goto done;
1807 				}
1808 				dns_db_detachnode(vctx->db, &nextnode);
1809 				result = dns_dbiterator_next(dbiter);
1810 				continue;
1811 			}
1812 			result = is_empty(vctx, nextnode, &empty);
1813 			dns_db_detachnode(vctx->db, &nextnode);
1814 			if (result != ISC_R_SUCCESS) {
1815 				dns_db_detachnode(vctx->db, &node);
1816 				goto done;
1817 			}
1818 			if (empty) {
1819 				result = dns_dbiterator_next(dbiter);
1820 				continue;
1821 			}
1822 			break;
1823 		}
1824 		if (result == ISC_R_NOMORE) {
1825 			done = true;
1826 			nextname = vctx->origin;
1827 		} else if (result != ISC_R_SUCCESS) {
1828 			zoneverify_log_error(vctx,
1829 					     "iterating through the database "
1830 					     "failed: %s",
1831 					     isc_result_totext(result));
1832 			dns_db_detachnode(vctx->db, &node);
1833 			goto done;
1834 		}
1835 		result = verifynode(vctx, name, node, isdelegation, dstkeys,
1836 				    nkeys, &vctx->nsecset, &vctx->nsec3paramset,
1837 				    nextname, &tvresult);
1838 		if (result != ISC_R_SUCCESS) {
1839 			dns_db_detachnode(vctx->db, &node);
1840 			goto done;
1841 		}
1842 		if (*vresult == ISC_R_UNSET) {
1843 			*vresult = ISC_R_SUCCESS;
1844 		}
1845 		if (*vresult == ISC_R_SUCCESS) {
1846 			*vresult = tvresult;
1847 		}
1848 		if (prevname != NULL) {
1849 			result = verifyemptynodes(
1850 				vctx, name, prevname, isdelegation,
1851 				&vctx->nsec3paramset, &tvresult);
1852 			if (result != ISC_R_SUCCESS) {
1853 				dns_db_detachnode(vctx->db, &node);
1854 				goto done;
1855 			}
1856 		} else {
1857 			prevname = dns_fixedname_name(&fprevname);
1858 		}
1859 		dns_name_copy(name, prevname);
1860 		if (*vresult == ISC_R_SUCCESS) {
1861 			*vresult = tvresult;
1862 		}
1863 		dns_db_detachnode(vctx->db, &node);
1864 	}
1865 
1866 	dns_dbiterator_destroy(&dbiter);
1867 
1868 	result = dns_db_createiterator(vctx->db, DNS_DB_NSEC3ONLY, &dbiter);
1869 	if (result != ISC_R_SUCCESS) {
1870 		zoneverify_log_error(vctx, "dns_db_createiterator(): %s",
1871 				     isc_result_totext(result));
1872 		return (result);
1873 	}
1874 
1875 	for (result = dns_dbiterator_first(dbiter); result == ISC_R_SUCCESS;
1876 	     result = dns_dbiterator_next(dbiter))
1877 	{
1878 		result = dns_dbiterator_current(dbiter, &node, name);
1879 		if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
1880 			zoneverify_log_error(vctx,
1881 					     "dns_dbiterator_current(): %s",
1882 					     isc_result_totext(result));
1883 			goto done;
1884 		}
1885 		result = verifynode(vctx, name, node, false, dstkeys, nkeys,
1886 				    NULL, NULL, NULL, NULL);
1887 		if (result != ISC_R_SUCCESS) {
1888 			zoneverify_log_error(vctx, "verifynode: %s",
1889 					     isc_result_totext(result));
1890 			dns_db_detachnode(vctx->db, &node);
1891 			goto done;
1892 		}
1893 		result = record_found(vctx, name, node, &vctx->nsec3paramset);
1894 		dns_db_detachnode(vctx->db, &node);
1895 		if (result != ISC_R_SUCCESS) {
1896 			goto done;
1897 		}
1898 	}
1899 
1900 	result = ISC_R_SUCCESS;
1901 
1902 done:
1903 	while (nkeys-- > 0U) {
1904 		dst_key_free(&dstkeys[nkeys]);
1905 	}
1906 	isc_mem_put(vctx->mctx, dstkeys, sizeof(*dstkeys) * count);
1907 	if (dbiter != NULL) {
1908 		dns_dbiterator_destroy(&dbiter);
1909 	}
1910 
1911 	return (result);
1912 }
1913 
1914 static isc_result_t
1915 check_bad_algorithms(const vctx_t *vctx, void (*report)(const char *, ...)) {
1916 	char algbuf[DNS_SECALG_FORMATSIZE];
1917 	bool first = true;
1918 
1919 	for (size_t i = 0; i < ARRAY_SIZE(vctx->bad_algorithms); i++) {
1920 		if (vctx->bad_algorithms[i] == 0) {
1921 			continue;
1922 		}
1923 		if (first) {
1924 			report("The zone is not fully signed "
1925 			       "for the following algorithms:");
1926 		}
1927 		dns_secalg_format(i, algbuf, sizeof(algbuf));
1928 		report(" %s", algbuf);
1929 		first = false;
1930 	}
1931 
1932 	if (!first) {
1933 		report(".");
1934 	}
1935 
1936 	return (first ? ISC_R_SUCCESS : ISC_R_FAILURE);
1937 }
1938 
1939 static void
1940 print_summary(const vctx_t *vctx, bool keyset_kskonly,
1941 	      void (*report)(const char *, ...)) {
1942 	char algbuf[DNS_SECALG_FORMATSIZE];
1943 
1944 	report("Zone fully signed:");
1945 	for (size_t i = 0; i < ARRAY_SIZE(vctx->ksk_algorithms); i++) {
1946 		if ((vctx->ksk_algorithms[i] == 0) &&
1947 		    (vctx->standby_ksk[i] == 0) &&
1948 		    (vctx->revoked_ksk[i] == 0) &&
1949 		    (vctx->zsk_algorithms[i] == 0) &&
1950 		    (vctx->standby_zsk[i] == 0) && (vctx->revoked_zsk[i] == 0))
1951 		{
1952 			continue;
1953 		}
1954 		dns_secalg_format(i, algbuf, sizeof(algbuf));
1955 		report("Algorithm: %s: KSKs: "
1956 		       "%u active, %u stand-by, %u revoked",
1957 		       algbuf, vctx->ksk_algorithms[i], vctx->standby_ksk[i],
1958 		       vctx->revoked_ksk[i]);
1959 		report("%*sZSKs: "
1960 		       "%u active, %u %s, %u revoked",
1961 		       (int)strlen(algbuf) + 13, "", vctx->zsk_algorithms[i],
1962 		       vctx->standby_zsk[i],
1963 		       keyset_kskonly ? "present" : "stand-by",
1964 		       vctx->revoked_zsk[i]);
1965 	}
1966 }
1967 
1968 isc_result_t
1969 dns_zoneverify_dnssec(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
1970 		      dns_name_t *origin, dns_keytable_t *secroots,
1971 		      isc_mem_t *mctx, bool ignore_kskflag, bool keyset_kskonly,
1972 		      void (*report)(const char *, ...)) {
1973 	const char *keydesc = (secroots == NULL ? "self-signed" : "trusted");
1974 	isc_result_t result, vresult = ISC_R_UNSET;
1975 	vctx_t vctx;
1976 
1977 	vctx_init(&vctx, mctx, zone, db, ver, origin, secroots);
1978 
1979 	result = check_apex_rrsets(&vctx);
1980 	if (result != ISC_R_SUCCESS) {
1981 		goto done;
1982 	}
1983 
1984 	result = check_dnskey(&vctx);
1985 	if (result != ISC_R_SUCCESS) {
1986 		goto done;
1987 	}
1988 
1989 	if (ignore_kskflag) {
1990 		if (!vctx.goodksk && !vctx.goodzsk) {
1991 			zoneverify_log_error(&vctx, "No %s DNSKEY found",
1992 					     keydesc);
1993 			result = ISC_R_FAILURE;
1994 			goto done;
1995 		}
1996 	} else if (!vctx.goodksk) {
1997 		zoneverify_log_error(&vctx, "No %s KSK DNSKEY found", keydesc);
1998 		result = ISC_R_FAILURE;
1999 		goto done;
2000 	}
2001 
2002 	determine_active_algorithms(&vctx, ignore_kskflag, keyset_kskonly,
2003 				    report);
2004 
2005 	result = verify_nodes(&vctx, &vresult);
2006 	if (result != ISC_R_SUCCESS) {
2007 		goto done;
2008 	}
2009 
2010 	result = verify_nsec3_chains(&vctx, mctx);
2011 	if (vresult == ISC_R_UNSET) {
2012 		vresult = ISC_R_SUCCESS;
2013 	}
2014 	if (result != ISC_R_SUCCESS && vresult == ISC_R_SUCCESS) {
2015 		vresult = result;
2016 	}
2017 
2018 	result = check_bad_algorithms(&vctx, report);
2019 	if (result != ISC_R_SUCCESS) {
2020 		report("DNSSEC completeness test failed.");
2021 		goto done;
2022 	}
2023 
2024 	result = vresult;
2025 	if (result != ISC_R_SUCCESS) {
2026 		report("DNSSEC completeness test failed (%s).",
2027 		       isc_result_totext(result));
2028 		goto done;
2029 	}
2030 
2031 	if (vctx.goodksk || ignore_kskflag) {
2032 		print_summary(&vctx, keyset_kskonly, report);
2033 	}
2034 
2035 done:
2036 	vctx_destroy(&vctx);
2037 
2038 	return (result);
2039 }
2040