Home | History | Annotate | Line # | Download | only in dns
zoneverify.c revision 1.12
      1 /*	$NetBSD: zoneverify.c,v 1.12 2024/09/22 00:14:07 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 		    (!delegation || rdataset.type == dns_rdatatype_ds ||
    945 		     rdataset.type == dns_rdatatype_nsec))
    946 		{
    947 			result = verifyset(vctx, &rdataset, name, node, dstkeys,
    948 					   nkeys);
    949 			if (result != ISC_R_SUCCESS) {
    950 				dns_rdataset_disassociate(&rdataset);
    951 				dns_rdatasetiter_destroy(&rdsiter);
    952 				return (result);
    953 			}
    954 			dns_nsec_setbit(types, rdataset.type, 1);
    955 			if (rdataset.type > maxtype) {
    956 				maxtype = rdataset.type;
    957 			}
    958 		} else if (rdataset.type != dns_rdatatype_rrsig) {
    959 			if (rdataset.type == dns_rdatatype_ns) {
    960 				dns_nsec_setbit(types, rdataset.type, 1);
    961 				if (rdataset.type > maxtype) {
    962 					maxtype = rdataset.type;
    963 				}
    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 			if (rdataset.type > maxtype) {
    974 				maxtype = rdataset.type;
    975 			}
    976 		}
    977 		dns_rdataset_disassociate(&rdataset);
    978 		result = dns_rdatasetiter_next(rdsiter);
    979 	}
    980 	dns_rdatasetiter_destroy(&rdsiter);
    981 	if (result != ISC_R_NOMORE) {
    982 		zoneverify_log_error(vctx, "rdataset iteration failed: %s",
    983 				     isc_result_totext(result));
    984 		return (result);
    985 	}
    986 
    987 	if (vresult == NULL) {
    988 		return (ISC_R_SUCCESS);
    989 	}
    990 
    991 	*vresult = ISC_R_SUCCESS;
    992 
    993 	if (nsecset != NULL && dns_rdataset_isassociated(nsecset)) {
    994 		result = verifynsec(vctx, name, node, nextname, &tvresult);
    995 		if (result != ISC_R_SUCCESS) {
    996 			return (result);
    997 		}
    998 		*vresult = tvresult;
    999 	}
   1000 
   1001 	if (nsec3paramset != NULL && dns_rdataset_isassociated(nsec3paramset)) {
   1002 		result = verifynsec3s(vctx, name, nsec3paramset, delegation,
   1003 				      false, types, maxtype, &tvresult);
   1004 		if (result != ISC_R_SUCCESS) {
   1005 			return (result);
   1006 		}
   1007 		if (*vresult == ISC_R_SUCCESS) {
   1008 			*vresult = tvresult;
   1009 		}
   1010 	}
   1011 
   1012 	return (ISC_R_SUCCESS);
   1013 }
   1014 
   1015 static isc_result_t
   1016 is_empty(const vctx_t *vctx, dns_dbnode_t *node, bool *empty) {
   1017 	dns_rdatasetiter_t *rdsiter = NULL;
   1018 	isc_result_t result;
   1019 
   1020 	result = dns_db_allrdatasets(vctx->db, node, vctx->ver, 0, 0, &rdsiter);
   1021 	if (result != ISC_R_SUCCESS) {
   1022 		zoneverify_log_error(vctx, "dns_db_allrdatasets(): %s",
   1023 				     isc_result_totext(result));
   1024 		return (result);
   1025 	}
   1026 	result = dns_rdatasetiter_first(rdsiter);
   1027 	dns_rdatasetiter_destroy(&rdsiter);
   1028 
   1029 	*empty = (result == ISC_R_NOMORE);
   1030 
   1031 	return (ISC_R_SUCCESS);
   1032 }
   1033 
   1034 static isc_result_t
   1035 check_no_nsec(const vctx_t *vctx, const dns_name_t *name, dns_dbnode_t *node) {
   1036 	bool nsec_exists = false;
   1037 	dns_rdataset_t rdataset;
   1038 	isc_result_t result;
   1039 
   1040 	dns_rdataset_init(&rdataset);
   1041 	result = dns_db_findrdataset(vctx->db, node, vctx->ver,
   1042 				     dns_rdatatype_nsec, 0, 0, &rdataset, NULL);
   1043 	if (result != ISC_R_NOTFOUND) {
   1044 		char namebuf[DNS_NAME_FORMATSIZE];
   1045 		dns_name_format(name, namebuf, sizeof(namebuf));
   1046 		zoneverify_log_error(vctx, "unexpected NSEC RRset at %s",
   1047 				     namebuf);
   1048 		nsec_exists = true;
   1049 	}
   1050 
   1051 	if (dns_rdataset_isassociated(&rdataset)) {
   1052 		dns_rdataset_disassociate(&rdataset);
   1053 	}
   1054 
   1055 	return (nsec_exists ? ISC_R_FAILURE : ISC_R_SUCCESS);
   1056 }
   1057 
   1058 static void
   1059 free_element(isc_mem_t *mctx, struct nsec3_chain_fixed *e) {
   1060 	size_t len;
   1061 
   1062 	len = sizeof(*e) + e->salt_length + 2 * e->next_length;
   1063 	isc_mem_put(mctx, e, len);
   1064 }
   1065 
   1066 static void
   1067 free_element_heap(void *element, void *uap) {
   1068 	struct nsec3_chain_fixed *e = (struct nsec3_chain_fixed *)element;
   1069 	isc_mem_t *mctx = (isc_mem_t *)uap;
   1070 
   1071 	free_element(mctx, e);
   1072 }
   1073 
   1074 static bool
   1075 _checknext(const vctx_t *vctx, const struct nsec3_chain_fixed *first,
   1076 	   const struct nsec3_chain_fixed *e) {
   1077 	char buf[512];
   1078 	const unsigned char *d1 = (const unsigned char *)(first + 1);
   1079 	const unsigned char *d2 = (const unsigned char *)(e + 1);
   1080 	isc_buffer_t b;
   1081 	isc_region_t sr;
   1082 
   1083 	d1 += first->salt_length + first->next_length;
   1084 	d2 += e->salt_length;
   1085 
   1086 	if (memcmp(d1, d2, first->next_length) == 0) {
   1087 		return (true);
   1088 	}
   1089 
   1090 	DE_CONST(d1 - first->next_length, sr.base);
   1091 	sr.length = first->next_length;
   1092 	isc_buffer_init(&b, buf, sizeof(buf));
   1093 	isc_base32hex_totext(&sr, 1, "", &b);
   1094 	zoneverify_log_error(vctx, "Break in NSEC3 chain at: %.*s",
   1095 			     (int)isc_buffer_usedlength(&b), buf);
   1096 
   1097 	DE_CONST(d1, sr.base);
   1098 	sr.length = first->next_length;
   1099 	isc_buffer_init(&b, buf, sizeof(buf));
   1100 	isc_base32hex_totext(&sr, 1, "", &b);
   1101 	zoneverify_log_error(vctx, "Expected: %.*s",
   1102 			     (int)isc_buffer_usedlength(&b), buf);
   1103 
   1104 	DE_CONST(d2, sr.base);
   1105 	sr.length = first->next_length;
   1106 	isc_buffer_init(&b, buf, sizeof(buf));
   1107 	isc_base32hex_totext(&sr, 1, "", &b);
   1108 	zoneverify_log_error(vctx, "Found: %.*s",
   1109 			     (int)isc_buffer_usedlength(&b), buf);
   1110 
   1111 	return (false);
   1112 }
   1113 
   1114 static bool
   1115 checknext(isc_mem_t *mctx, const vctx_t *vctx,
   1116 	  const struct nsec3_chain_fixed *first, struct nsec3_chain_fixed *prev,
   1117 	  const struct nsec3_chain_fixed *cur) {
   1118 	bool result = _checknext(vctx, prev, cur);
   1119 
   1120 	if (prev != first) {
   1121 		free_element(mctx, prev);
   1122 	}
   1123 
   1124 	return (result);
   1125 }
   1126 
   1127 static bool
   1128 checklast(isc_mem_t *mctx, const vctx_t *vctx, struct nsec3_chain_fixed *first,
   1129 	  struct nsec3_chain_fixed *prev) {
   1130 	bool result = _checknext(vctx, prev, first);
   1131 	if (prev != first) {
   1132 		free_element(mctx, prev);
   1133 	}
   1134 	free_element(mctx, first);
   1135 
   1136 	return (result);
   1137 }
   1138 
   1139 static isc_result_t
   1140 verify_nsec3_chains(const vctx_t *vctx, isc_mem_t *mctx) {
   1141 	isc_result_t result = ISC_R_SUCCESS;
   1142 	struct nsec3_chain_fixed *e, *f = NULL;
   1143 	struct nsec3_chain_fixed *first = NULL, *prev = NULL;
   1144 
   1145 	while ((e = isc_heap_element(vctx->expected_chains, 1)) != NULL) {
   1146 		isc_heap_delete(vctx->expected_chains, 1);
   1147 		if (f == NULL) {
   1148 			f = isc_heap_element(vctx->found_chains, 1);
   1149 		}
   1150 		if (f != NULL) {
   1151 			isc_heap_delete(vctx->found_chains, 1);
   1152 
   1153 			/*
   1154 			 * Check that they match.
   1155 			 */
   1156 			if (chain_equal(e, f, chain_length(e))) {
   1157 				free_element(mctx, f);
   1158 				f = NULL;
   1159 			} else {
   1160 				if (result == ISC_R_SUCCESS) {
   1161 					zoneverify_log_error(vctx, "Expected "
   1162 								   "and found "
   1163 								   "NSEC3 "
   1164 								   "chains not "
   1165 								   "equal");
   1166 				}
   1167 				result = ISC_R_FAILURE;
   1168 				/*
   1169 				 * Attempt to resync found_chain.
   1170 				 */
   1171 				while (f != NULL && !chain_compare(e, f)) {
   1172 					free_element(mctx, f);
   1173 					f = isc_heap_element(vctx->found_chains,
   1174 							     1);
   1175 					if (f != NULL) {
   1176 						isc_heap_delete(
   1177 							vctx->found_chains, 1);
   1178 					}
   1179 					if (f != NULL &&
   1180 					    chain_equal(e, f, chain_length(e)))
   1181 					{
   1182 						free_element(mctx, f);
   1183 						f = NULL;
   1184 						break;
   1185 					}
   1186 				}
   1187 			}
   1188 		} else if (result == ISC_R_SUCCESS) {
   1189 			zoneverify_log_error(vctx, "Expected and found NSEC3 "
   1190 						   "chains "
   1191 						   "not equal");
   1192 			result = ISC_R_FAILURE;
   1193 		}
   1194 
   1195 		if (first == NULL) {
   1196 			prev = first = e;
   1197 		} else if (!chain_equal(first, e, first->salt_length)) {
   1198 			if (!checklast(mctx, vctx, first, prev)) {
   1199 				result = ISC_R_FAILURE;
   1200 			}
   1201 
   1202 			prev = first = e;
   1203 		} else {
   1204 			if (!checknext(mctx, vctx, first, prev, e)) {
   1205 				result = ISC_R_FAILURE;
   1206 			}
   1207 
   1208 			prev = e;
   1209 		}
   1210 	}
   1211 	if (prev != NULL) {
   1212 		if (!checklast(mctx, vctx, first, prev)) {
   1213 			result = ISC_R_FAILURE;
   1214 		}
   1215 	}
   1216 	do {
   1217 		if (f != NULL) {
   1218 			if (result == ISC_R_SUCCESS) {
   1219 				zoneverify_log_error(vctx, "Expected and found "
   1220 							   "NSEC3 chains not "
   1221 							   "equal");
   1222 				result = ISC_R_FAILURE;
   1223 			}
   1224 			free_element(mctx, f);
   1225 		}
   1226 		f = isc_heap_element(vctx->found_chains, 1);
   1227 		if (f != NULL) {
   1228 			isc_heap_delete(vctx->found_chains, 1);
   1229 		}
   1230 	} while (f != NULL);
   1231 
   1232 	return (result);
   1233 }
   1234 
   1235 static isc_result_t
   1236 verifyemptynodes(const vctx_t *vctx, const dns_name_t *name,
   1237 		 const dns_name_t *prevname, bool isdelegation,
   1238 		 dns_rdataset_t *nsec3paramset, isc_result_t *vresult) {
   1239 	dns_namereln_t reln;
   1240 	int order;
   1241 	unsigned int labels, nlabels, i;
   1242 	dns_name_t suffix;
   1243 	isc_result_t result, tvresult = ISC_R_UNSET;
   1244 
   1245 	*vresult = ISC_R_SUCCESS;
   1246 
   1247 	reln = dns_name_fullcompare(prevname, name, &order, &labels);
   1248 	if (order >= 0) {
   1249 		return (ISC_R_SUCCESS);
   1250 	}
   1251 
   1252 	nlabels = dns_name_countlabels(name);
   1253 
   1254 	if (reln == dns_namereln_commonancestor ||
   1255 	    reln == dns_namereln_contains)
   1256 	{
   1257 		dns_name_init(&suffix, NULL);
   1258 		for (i = labels + 1; i < nlabels; i++) {
   1259 			dns_name_getlabelsequence(name, nlabels - i, i,
   1260 						  &suffix);
   1261 			if (nsec3paramset != NULL &&
   1262 			    dns_rdataset_isassociated(nsec3paramset))
   1263 			{
   1264 				result = verifynsec3s(
   1265 					vctx, &suffix, nsec3paramset,
   1266 					isdelegation, true, NULL, 0, &tvresult);
   1267 				if (result != ISC_R_SUCCESS) {
   1268 					return (result);
   1269 				}
   1270 				if (*vresult == ISC_R_SUCCESS) {
   1271 					*vresult = tvresult;
   1272 				}
   1273 			}
   1274 		}
   1275 	}
   1276 
   1277 	return (ISC_R_SUCCESS);
   1278 }
   1279 
   1280 static void
   1281 vctx_init(vctx_t *vctx, isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db,
   1282 	  dns_dbversion_t *ver, dns_name_t *origin, dns_keytable_t *secroots) {
   1283 	memset(vctx, 0, sizeof(*vctx));
   1284 
   1285 	vctx->mctx = mctx;
   1286 	vctx->zone = zone;
   1287 	vctx->db = db;
   1288 	vctx->ver = ver;
   1289 	vctx->origin = origin;
   1290 	vctx->secroots = secroots;
   1291 	vctx->goodksk = false;
   1292 	vctx->goodzsk = false;
   1293 
   1294 	dns_rdataset_init(&vctx->keyset);
   1295 	dns_rdataset_init(&vctx->keysigs);
   1296 	dns_rdataset_init(&vctx->soaset);
   1297 	dns_rdataset_init(&vctx->soasigs);
   1298 	dns_rdataset_init(&vctx->nsecset);
   1299 	dns_rdataset_init(&vctx->nsecsigs);
   1300 	dns_rdataset_init(&vctx->nsec3paramset);
   1301 	dns_rdataset_init(&vctx->nsec3paramsigs);
   1302 
   1303 	vctx->expected_chains = NULL;
   1304 	isc_heap_create(mctx, chain_compare, NULL, 1024,
   1305 			&vctx->expected_chains);
   1306 
   1307 	vctx->found_chains = NULL;
   1308 	isc_heap_create(mctx, chain_compare, NULL, 1024, &vctx->found_chains);
   1309 }
   1310 
   1311 static void
   1312 vctx_destroy(vctx_t *vctx) {
   1313 	if (dns_rdataset_isassociated(&vctx->keyset)) {
   1314 		dns_rdataset_disassociate(&vctx->keyset);
   1315 	}
   1316 	if (dns_rdataset_isassociated(&vctx->keysigs)) {
   1317 		dns_rdataset_disassociate(&vctx->keysigs);
   1318 	}
   1319 	if (dns_rdataset_isassociated(&vctx->soaset)) {
   1320 		dns_rdataset_disassociate(&vctx->soaset);
   1321 	}
   1322 	if (dns_rdataset_isassociated(&vctx->soasigs)) {
   1323 		dns_rdataset_disassociate(&vctx->soasigs);
   1324 	}
   1325 	if (dns_rdataset_isassociated(&vctx->nsecset)) {
   1326 		dns_rdataset_disassociate(&vctx->nsecset);
   1327 	}
   1328 	if (dns_rdataset_isassociated(&vctx->nsecsigs)) {
   1329 		dns_rdataset_disassociate(&vctx->nsecsigs);
   1330 	}
   1331 	if (dns_rdataset_isassociated(&vctx->nsec3paramset)) {
   1332 		dns_rdataset_disassociate(&vctx->nsec3paramset);
   1333 	}
   1334 	if (dns_rdataset_isassociated(&vctx->nsec3paramsigs)) {
   1335 		dns_rdataset_disassociate(&vctx->nsec3paramsigs);
   1336 	}
   1337 	isc_heap_foreach(vctx->expected_chains, free_element_heap, vctx->mctx);
   1338 	isc_heap_destroy(&vctx->expected_chains);
   1339 	isc_heap_foreach(vctx->found_chains, free_element_heap, vctx->mctx);
   1340 	isc_heap_destroy(&vctx->found_chains);
   1341 }
   1342 
   1343 static isc_result_t
   1344 check_apex_rrsets(vctx_t *vctx) {
   1345 	dns_dbnode_t *node = NULL;
   1346 	isc_result_t result;
   1347 
   1348 	result = dns_db_findnode(vctx->db, vctx->origin, false, &node);
   1349 	if (result != ISC_R_SUCCESS) {
   1350 		zoneverify_log_error(vctx,
   1351 				     "failed to find the zone's origin: %s",
   1352 				     isc_result_totext(result));
   1353 		return (result);
   1354 	}
   1355 
   1356 	result = dns_db_findrdataset(vctx->db, node, vctx->ver,
   1357 				     dns_rdatatype_dnskey, 0, 0, &vctx->keyset,
   1358 				     &vctx->keysigs);
   1359 	if (result != ISC_R_SUCCESS) {
   1360 		zoneverify_log_error(vctx, "Zone contains no DNSSEC keys");
   1361 		goto done;
   1362 	}
   1363 
   1364 	result = dns_db_findrdataset(vctx->db, node, vctx->ver,
   1365 				     dns_rdatatype_soa, 0, 0, &vctx->soaset,
   1366 				     &vctx->soasigs);
   1367 	if (result != ISC_R_SUCCESS) {
   1368 		zoneverify_log_error(vctx, "Zone contains no SOA record");
   1369 		goto done;
   1370 	}
   1371 
   1372 	result = dns_db_findrdataset(vctx->db, node, vctx->ver,
   1373 				     dns_rdatatype_nsec, 0, 0, &vctx->nsecset,
   1374 				     &vctx->nsecsigs);
   1375 	if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
   1376 		zoneverify_log_error(vctx, "NSEC lookup failed");
   1377 		goto done;
   1378 	}
   1379 
   1380 	result = dns_db_findrdataset(
   1381 		vctx->db, node, vctx->ver, dns_rdatatype_nsec3param, 0, 0,
   1382 		&vctx->nsec3paramset, &vctx->nsec3paramsigs);
   1383 	if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
   1384 		zoneverify_log_error(vctx, "NSEC3PARAM lookup failed");
   1385 		goto done;
   1386 	}
   1387 
   1388 	if (!dns_rdataset_isassociated(&vctx->keysigs)) {
   1389 		zoneverify_log_error(vctx, "DNSKEY is not signed "
   1390 					   "(keys offline or inactive?)");
   1391 		result = ISC_R_FAILURE;
   1392 		goto done;
   1393 	}
   1394 
   1395 	if (!dns_rdataset_isassociated(&vctx->soasigs)) {
   1396 		zoneverify_log_error(vctx, "SOA is not signed "
   1397 					   "(keys offline or inactive?)");
   1398 		result = ISC_R_FAILURE;
   1399 		goto done;
   1400 	}
   1401 
   1402 	if (dns_rdataset_isassociated(&vctx->nsecset) &&
   1403 	    !dns_rdataset_isassociated(&vctx->nsecsigs))
   1404 	{
   1405 		zoneverify_log_error(vctx, "NSEC is not signed "
   1406 					   "(keys offline or inactive?)");
   1407 		result = ISC_R_FAILURE;
   1408 		goto done;
   1409 	}
   1410 
   1411 	if (dns_rdataset_isassociated(&vctx->nsec3paramset) &&
   1412 	    !dns_rdataset_isassociated(&vctx->nsec3paramsigs))
   1413 	{
   1414 		zoneverify_log_error(vctx, "NSEC3PARAM is not signed "
   1415 					   "(keys offline or inactive?)");
   1416 		result = ISC_R_FAILURE;
   1417 		goto done;
   1418 	}
   1419 
   1420 	if (!dns_rdataset_isassociated(&vctx->nsecset) &&
   1421 	    !dns_rdataset_isassociated(&vctx->nsec3paramset))
   1422 	{
   1423 		zoneverify_log_error(vctx, "No valid NSEC/NSEC3 chain for "
   1424 					   "testing");
   1425 		result = ISC_R_FAILURE;
   1426 		goto done;
   1427 	}
   1428 
   1429 	result = ISC_R_SUCCESS;
   1430 
   1431 done:
   1432 	dns_db_detachnode(vctx->db, &node);
   1433 
   1434 	return (result);
   1435 }
   1436 
   1437 /*%
   1438  * Update 'vctx' tables tracking active and standby key algorithms used in the
   1439  * verified zone based on the signatures made using 'dnskey' (prepared from
   1440  * 'rdata') found at zone apex.  Set 'vctx->goodksk' or 'vctx->goodzsk' to true
   1441  * if 'dnskey' correctly signs the DNSKEY RRset at zone apex and either
   1442  * 'vctx->secroots' is NULL or 'dnskey' is present in 'vctx->secroots'.
   1443  *
   1444  * The variables to update are chosen based on 'is_ksk', which is true when
   1445  * 'dnskey' is a KSK and false otherwise.
   1446  */
   1447 static void
   1448 check_dnskey_sigs(vctx_t *vctx, const dns_rdata_dnskey_t *dnskey,
   1449 		  dns_rdata_t *keyrdata, bool is_ksk) {
   1450 	unsigned char *active_keys = NULL, *standby_keys = NULL;
   1451 	dns_keynode_t *keynode = NULL;
   1452 	bool *goodkey = NULL;
   1453 	dst_key_t *key = NULL;
   1454 	isc_result_t result;
   1455 	dns_rdataset_t dsset;
   1456 
   1457 	active_keys = (is_ksk ? vctx->ksk_algorithms : vctx->zsk_algorithms);
   1458 	standby_keys = (is_ksk ? vctx->standby_ksk : vctx->standby_zsk);
   1459 	goodkey = (is_ksk ? &vctx->goodksk : &vctx->goodzsk);
   1460 
   1461 	/*
   1462 	 * First, does this key sign the DNSKEY rrset?
   1463 	 */
   1464 	if (!dns_dnssec_selfsigns(keyrdata, vctx->origin, &vctx->keyset,
   1465 				  &vctx->keysigs, false, vctx->mctx))
   1466 	{
   1467 		if (!is_ksk &&
   1468 		    dns_dnssec_signs(keyrdata, vctx->origin, &vctx->soaset,
   1469 				     &vctx->soasigs, false, vctx->mctx))
   1470 		{
   1471 			if (active_keys[dnskey->algorithm] != DNS_KEYALG_MAX) {
   1472 				active_keys[dnskey->algorithm]++;
   1473 			}
   1474 		} else {
   1475 			if (standby_keys[dnskey->algorithm] != DNS_KEYALG_MAX) {
   1476 				standby_keys[dnskey->algorithm]++;
   1477 			}
   1478 		}
   1479 		return;
   1480 	}
   1481 
   1482 	if (active_keys[dnskey->algorithm] != DNS_KEYALG_MAX) {
   1483 		active_keys[dnskey->algorithm]++;
   1484 	}
   1485 
   1486 	/*
   1487 	 * If a trust anchor table was not supplied, a correctly self-signed
   1488 	 * DNSKEY RRset is good enough.
   1489 	 */
   1490 	if (vctx->secroots == NULL) {
   1491 		*goodkey = true;
   1492 		return;
   1493 	}
   1494 
   1495 	/*
   1496 	 * Convert the supplied key rdata to dst_key_t. (If this
   1497 	 * fails we can't go further.)
   1498 	 */
   1499 	result = dns_dnssec_keyfromrdata(vctx->origin, keyrdata, vctx->mctx,
   1500 					 &key);
   1501 	RUNTIME_CHECK(result == ISC_R_SUCCESS);
   1502 
   1503 	/*
   1504 	 * Look up the supplied key in the trust anchor table.
   1505 	 * If we don't find an exact match, or if the keynode data
   1506 	 * is NULL, then we have neither a DNSKEY nor a DS format
   1507 	 * trust anchor, and can give up.
   1508 	 */
   1509 	result = dns_keytable_find(vctx->secroots, vctx->origin, &keynode);
   1510 	if (result != ISC_R_SUCCESS) {
   1511 		/* No such trust anchor */
   1512 		goto cleanup;
   1513 	}
   1514 
   1515 	/*
   1516 	 * If the keynode has any DS format trust anchors, that means
   1517 	 * it doesn't have any DNSKEY ones. So, we can check for a DS
   1518 	 * match and then stop.
   1519 	 */
   1520 	dns_rdataset_init(&dsset);
   1521 	if (dns_keynode_dsset(keynode, &dsset)) {
   1522 		for (result = dns_rdataset_first(&dsset);
   1523 		     result == ISC_R_SUCCESS;
   1524 		     result = dns_rdataset_next(&dsset))
   1525 		{
   1526 			dns_rdata_t dsrdata = DNS_RDATA_INIT;
   1527 			dns_rdata_t newdsrdata = DNS_RDATA_INIT;
   1528 			unsigned char buf[DNS_DS_BUFFERSIZE];
   1529 			dns_rdata_ds_t ds;
   1530 
   1531 			dns_rdata_reset(&dsrdata);
   1532 			dns_rdataset_current(&dsset, &dsrdata);
   1533 			result = dns_rdata_tostruct(&dsrdata, &ds, NULL);
   1534 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
   1535 
   1536 			if (ds.key_tag != dst_key_id(key) ||
   1537 			    ds.algorithm != dst_key_alg(key))
   1538 			{
   1539 				continue;
   1540 			}
   1541 
   1542 			result = dns_ds_buildrdata(vctx->origin, keyrdata,
   1543 						   ds.digest_type, buf,
   1544 						   &newdsrdata);
   1545 			if (result != ISC_R_SUCCESS) {
   1546 				continue;
   1547 			}
   1548 
   1549 			if (dns_rdata_compare(&dsrdata, &newdsrdata) == 0) {
   1550 				dns_rdataset_settrust(&vctx->keyset,
   1551 						      dns_trust_secure);
   1552 				dns_rdataset_settrust(&vctx->keysigs,
   1553 						      dns_trust_secure);
   1554 				*goodkey = true;
   1555 				break;
   1556 			}
   1557 		}
   1558 		dns_rdataset_disassociate(&dsset);
   1559 
   1560 		goto cleanup;
   1561 	}
   1562 
   1563 cleanup:
   1564 	if (keynode != NULL) {
   1565 		dns_keytable_detachkeynode(vctx->secroots, &keynode);
   1566 	}
   1567 	if (key != NULL) {
   1568 		dst_key_free(&key);
   1569 	}
   1570 }
   1571 
   1572 /*%
   1573  * Check that the DNSKEY RR has at least one self signing KSK and one ZSK per
   1574  * algorithm in it (or, if -x was used, one self-signing KSK).
   1575  */
   1576 static isc_result_t
   1577 check_dnskey(vctx_t *vctx) {
   1578 	dns_rdata_t rdata = DNS_RDATA_INIT;
   1579 	dns_rdata_dnskey_t dnskey;
   1580 	isc_result_t result;
   1581 	bool is_ksk;
   1582 
   1583 	for (result = dns_rdataset_first(&vctx->keyset);
   1584 	     result == ISC_R_SUCCESS; result = dns_rdataset_next(&vctx->keyset))
   1585 	{
   1586 		dns_rdataset_current(&vctx->keyset, &rdata);
   1587 		result = dns_rdata_tostruct(&rdata, &dnskey, NULL);
   1588 		RUNTIME_CHECK(result == ISC_R_SUCCESS);
   1589 		is_ksk = ((dnskey.flags & DNS_KEYFLAG_KSK) != 0);
   1590 
   1591 		if ((dnskey.flags & DNS_KEYOWNER_ZONE) != 0 &&
   1592 		    (dnskey.flags & DNS_KEYFLAG_REVOKE) != 0)
   1593 		{
   1594 			if ((dnskey.flags & DNS_KEYFLAG_KSK) != 0 &&
   1595 			    !dns_dnssec_selfsigns(&rdata, vctx->origin,
   1596 						  &vctx->keyset, &vctx->keysigs,
   1597 						  false, vctx->mctx))
   1598 			{
   1599 				char namebuf[DNS_NAME_FORMATSIZE];
   1600 				char buffer[1024];
   1601 				isc_buffer_t buf;
   1602 
   1603 				dns_name_format(vctx->origin, namebuf,
   1604 						sizeof(namebuf));
   1605 				isc_buffer_init(&buf, buffer, sizeof(buffer));
   1606 				result = dns_rdata_totext(&rdata, NULL, &buf);
   1607 				if (result != ISC_R_SUCCESS) {
   1608 					zoneverify_log_error(
   1609 						vctx, "dns_rdata_totext: %s",
   1610 						isc_result_totext(result));
   1611 					return (ISC_R_FAILURE);
   1612 				}
   1613 				zoneverify_log_error(
   1614 					vctx,
   1615 					"revoked KSK is not self signed:\n"
   1616 					"%s DNSKEY %.*s",
   1617 					namebuf,
   1618 					(int)isc_buffer_usedlength(&buf),
   1619 					buffer);
   1620 				return (ISC_R_FAILURE);
   1621 			}
   1622 			if ((dnskey.flags & DNS_KEYFLAG_KSK) != 0 &&
   1623 			    vctx->revoked_ksk[dnskey.algorithm] !=
   1624 				    DNS_KEYALG_MAX)
   1625 			{
   1626 				vctx->revoked_ksk[dnskey.algorithm]++;
   1627 			} else if ((dnskey.flags & DNS_KEYFLAG_KSK) == 0 &&
   1628 				   vctx->revoked_zsk[dnskey.algorithm] !=
   1629 					   DNS_KEYALG_MAX)
   1630 			{
   1631 				vctx->revoked_zsk[dnskey.algorithm]++;
   1632 			}
   1633 		} else {
   1634 			check_dnskey_sigs(vctx, &dnskey, &rdata, is_ksk);
   1635 		}
   1636 		dns_rdata_freestruct(&dnskey);
   1637 		dns_rdata_reset(&rdata);
   1638 	}
   1639 
   1640 	return (ISC_R_SUCCESS);
   1641 }
   1642 
   1643 static void
   1644 determine_active_algorithms(vctx_t *vctx, bool ignore_kskflag,
   1645 			    bool keyset_kskonly,
   1646 			    void (*report)(const char *, ...)) {
   1647 	char algbuf[DNS_SECALG_FORMATSIZE];
   1648 
   1649 	report("Verifying the zone using the following algorithms:");
   1650 
   1651 	for (size_t i = 0; i < ARRAY_SIZE(vctx->act_algorithms); i++) {
   1652 		if (ignore_kskflag) {
   1653 			vctx->act_algorithms[i] = (vctx->ksk_algorithms[i] !=
   1654 							   0 ||
   1655 						   vctx->zsk_algorithms[i] != 0)
   1656 							  ? 1
   1657 							  : 0;
   1658 		} else {
   1659 			vctx->act_algorithms[i] = vctx->ksk_algorithms[i] != 0
   1660 							  ? 1
   1661 							  : 0;
   1662 		}
   1663 		if (vctx->act_algorithms[i] != 0) {
   1664 			dns_secalg_format(i, algbuf, sizeof(algbuf));
   1665 			report("- %s", algbuf);
   1666 		}
   1667 	}
   1668 
   1669 	if (ignore_kskflag || keyset_kskonly) {
   1670 		return;
   1671 	}
   1672 
   1673 	for (size_t i = 0; i < ARRAY_SIZE(vctx->ksk_algorithms); i++) {
   1674 		/*
   1675 		 * The counts should both be zero or both be non-zero.  Mark
   1676 		 * the algorithm as bad if this is not met.
   1677 		 */
   1678 		if ((vctx->ksk_algorithms[i] != 0) ==
   1679 		    (vctx->zsk_algorithms[i] != 0))
   1680 		{
   1681 			continue;
   1682 		}
   1683 		dns_secalg_format(i, algbuf, sizeof(algbuf));
   1684 		zoneverify_log_error(vctx, "Missing %s for algorithm %s",
   1685 				     (vctx->ksk_algorithms[i] != 0) ? "ZSK"
   1686 								    : "self-"
   1687 								      "signed "
   1688 								      "KSK",
   1689 				     algbuf);
   1690 		vctx->bad_algorithms[i] = 1;
   1691 	}
   1692 }
   1693 
   1694 /*%
   1695  * Check that all the records not yet verified were signed by keys that are
   1696  * present in the DNSKEY RRset.
   1697  */
   1698 static isc_result_t
   1699 verify_nodes(vctx_t *vctx, isc_result_t *vresult) {
   1700 	dns_fixedname_t fname, fnextname, fprevname, fzonecut;
   1701 	dns_name_t *name, *nextname, *prevname, *zonecut;
   1702 	dns_dbnode_t *node = NULL, *nextnode;
   1703 	dns_dbiterator_t *dbiter = NULL;
   1704 	dst_key_t **dstkeys;
   1705 	size_t count, nkeys = 0;
   1706 	bool done = false;
   1707 	isc_result_t tvresult = ISC_R_UNSET;
   1708 	isc_result_t result;
   1709 
   1710 	name = dns_fixedname_initname(&fname);
   1711 	nextname = dns_fixedname_initname(&fnextname);
   1712 	dns_fixedname_init(&fprevname);
   1713 	prevname = NULL;
   1714 	dns_fixedname_init(&fzonecut);
   1715 	zonecut = NULL;
   1716 
   1717 	count = dns_rdataset_count(&vctx->keyset);
   1718 	dstkeys = isc_mem_get(vctx->mctx, sizeof(*dstkeys) * count);
   1719 
   1720 	for (result = dns_rdataset_first(&vctx->keyset);
   1721 	     result == ISC_R_SUCCESS; result = dns_rdataset_next(&vctx->keyset))
   1722 	{
   1723 		dns_rdata_t rdata = DNS_RDATA_INIT;
   1724 		dns_rdataset_current(&vctx->keyset, &rdata);
   1725 		dstkeys[nkeys] = NULL;
   1726 		result = dns_dnssec_keyfromrdata(vctx->origin, &rdata,
   1727 						 vctx->mctx, &dstkeys[nkeys]);
   1728 		if (result == ISC_R_SUCCESS) {
   1729 			nkeys++;
   1730 		}
   1731 	}
   1732 
   1733 	result = dns_db_createiterator(vctx->db, DNS_DB_NONSEC3, &dbiter);
   1734 	if (result != ISC_R_SUCCESS) {
   1735 		zoneverify_log_error(vctx, "dns_db_createiterator(): %s",
   1736 				     isc_result_totext(result));
   1737 		goto done;
   1738 	}
   1739 
   1740 	result = dns_dbiterator_first(dbiter);
   1741 	if (result != ISC_R_SUCCESS) {
   1742 		zoneverify_log_error(vctx, "dns_dbiterator_first(): %s",
   1743 				     isc_result_totext(result));
   1744 		goto done;
   1745 	}
   1746 
   1747 	while (!done) {
   1748 		bool isdelegation = false;
   1749 
   1750 		result = dns_dbiterator_current(dbiter, &node, name);
   1751 		if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
   1752 			zoneverify_log_error(vctx,
   1753 					     "dns_dbiterator_current(): %s",
   1754 					     isc_result_totext(result));
   1755 			goto done;
   1756 		}
   1757 		if (!dns_name_issubdomain(name, vctx->origin)) {
   1758 			result = check_no_nsec(vctx, name, node);
   1759 			if (result != ISC_R_SUCCESS) {
   1760 				dns_db_detachnode(vctx->db, &node);
   1761 				goto done;
   1762 			}
   1763 			dns_db_detachnode(vctx->db, &node);
   1764 			result = dns_dbiterator_next(dbiter);
   1765 			if (result == ISC_R_NOMORE) {
   1766 				done = true;
   1767 			} else if (result != ISC_R_SUCCESS) {
   1768 				zoneverify_log_error(vctx,
   1769 						     "dns_dbiterator_next(): "
   1770 						     "%s",
   1771 						     isc_result_totext(result));
   1772 				goto done;
   1773 			}
   1774 			continue;
   1775 		}
   1776 		if (is_delegation(vctx, name, node, NULL)) {
   1777 			zonecut = dns_fixedname_name(&fzonecut);
   1778 			dns_name_copy(name, zonecut);
   1779 			isdelegation = true;
   1780 		} else if (has_dname(vctx, node)) {
   1781 			zonecut = dns_fixedname_name(&fzonecut);
   1782 			dns_name_copy(name, zonecut);
   1783 		}
   1784 		nextnode = NULL;
   1785 		result = dns_dbiterator_next(dbiter);
   1786 		while (result == ISC_R_SUCCESS) {
   1787 			bool empty;
   1788 			result = dns_dbiterator_current(dbiter, &nextnode,
   1789 							nextname);
   1790 			if (result != ISC_R_SUCCESS &&
   1791 			    result != DNS_R_NEWORIGIN)
   1792 			{
   1793 				zoneverify_log_error(vctx,
   1794 						     "dns_dbiterator_current():"
   1795 						     " %s",
   1796 						     isc_result_totext(result));
   1797 				dns_db_detachnode(vctx->db, &node);
   1798 				goto done;
   1799 			}
   1800 			if (!dns_name_issubdomain(nextname, vctx->origin) ||
   1801 			    (zonecut != NULL &&
   1802 			     dns_name_issubdomain(nextname, zonecut)))
   1803 			{
   1804 				result = check_no_nsec(vctx, nextname,
   1805 						       nextnode);
   1806 				if (result != ISC_R_SUCCESS) {
   1807 					dns_db_detachnode(vctx->db, &node);
   1808 					dns_db_detachnode(vctx->db, &nextnode);
   1809 					goto done;
   1810 				}
   1811 				dns_db_detachnode(vctx->db, &nextnode);
   1812 				result = dns_dbiterator_next(dbiter);
   1813 				continue;
   1814 			}
   1815 			result = is_empty(vctx, nextnode, &empty);
   1816 			dns_db_detachnode(vctx->db, &nextnode);
   1817 			if (result != ISC_R_SUCCESS) {
   1818 				dns_db_detachnode(vctx->db, &node);
   1819 				goto done;
   1820 			}
   1821 			if (empty) {
   1822 				result = dns_dbiterator_next(dbiter);
   1823 				continue;
   1824 			}
   1825 			break;
   1826 		}
   1827 		if (result == ISC_R_NOMORE) {
   1828 			done = true;
   1829 			nextname = vctx->origin;
   1830 		} else if (result != ISC_R_SUCCESS) {
   1831 			zoneverify_log_error(vctx,
   1832 					     "iterating through the database "
   1833 					     "failed: %s",
   1834 					     isc_result_totext(result));
   1835 			dns_db_detachnode(vctx->db, &node);
   1836 			goto done;
   1837 		}
   1838 		result = verifynode(vctx, name, node, isdelegation, dstkeys,
   1839 				    nkeys, &vctx->nsecset, &vctx->nsec3paramset,
   1840 				    nextname, &tvresult);
   1841 		if (result != ISC_R_SUCCESS) {
   1842 			dns_db_detachnode(vctx->db, &node);
   1843 			goto done;
   1844 		}
   1845 		if (*vresult == ISC_R_UNSET) {
   1846 			*vresult = ISC_R_SUCCESS;
   1847 		}
   1848 		if (*vresult == ISC_R_SUCCESS) {
   1849 			*vresult = tvresult;
   1850 		}
   1851 		if (prevname != NULL) {
   1852 			result = verifyemptynodes(
   1853 				vctx, name, prevname, isdelegation,
   1854 				&vctx->nsec3paramset, &tvresult);
   1855 			if (result != ISC_R_SUCCESS) {
   1856 				dns_db_detachnode(vctx->db, &node);
   1857 				goto done;
   1858 			}
   1859 		} else {
   1860 			prevname = dns_fixedname_name(&fprevname);
   1861 		}
   1862 		dns_name_copy(name, prevname);
   1863 		if (*vresult == ISC_R_SUCCESS) {
   1864 			*vresult = tvresult;
   1865 		}
   1866 		dns_db_detachnode(vctx->db, &node);
   1867 	}
   1868 
   1869 	dns_dbiterator_destroy(&dbiter);
   1870 
   1871 	result = dns_db_createiterator(vctx->db, DNS_DB_NSEC3ONLY, &dbiter);
   1872 	if (result != ISC_R_SUCCESS) {
   1873 		zoneverify_log_error(vctx, "dns_db_createiterator(): %s",
   1874 				     isc_result_totext(result));
   1875 		return (result);
   1876 	}
   1877 
   1878 	for (result = dns_dbiterator_first(dbiter); result == ISC_R_SUCCESS;
   1879 	     result = dns_dbiterator_next(dbiter))
   1880 	{
   1881 		result = dns_dbiterator_current(dbiter, &node, name);
   1882 		if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
   1883 			zoneverify_log_error(vctx,
   1884 					     "dns_dbiterator_current(): %s",
   1885 					     isc_result_totext(result));
   1886 			goto done;
   1887 		}
   1888 		result = verifynode(vctx, name, node, false, dstkeys, nkeys,
   1889 				    NULL, NULL, NULL, NULL);
   1890 		if (result != ISC_R_SUCCESS) {
   1891 			zoneverify_log_error(vctx, "verifynode: %s",
   1892 					     isc_result_totext(result));
   1893 			dns_db_detachnode(vctx->db, &node);
   1894 			goto done;
   1895 		}
   1896 		result = record_found(vctx, name, node, &vctx->nsec3paramset);
   1897 		dns_db_detachnode(vctx->db, &node);
   1898 		if (result != ISC_R_SUCCESS) {
   1899 			goto done;
   1900 		}
   1901 	}
   1902 
   1903 	result = ISC_R_SUCCESS;
   1904 
   1905 done:
   1906 	while (nkeys-- > 0U) {
   1907 		dst_key_free(&dstkeys[nkeys]);
   1908 	}
   1909 	isc_mem_put(vctx->mctx, dstkeys, sizeof(*dstkeys) * count);
   1910 	if (dbiter != NULL) {
   1911 		dns_dbiterator_destroy(&dbiter);
   1912 	}
   1913 
   1914 	return (result);
   1915 }
   1916 
   1917 static isc_result_t
   1918 check_bad_algorithms(const vctx_t *vctx, void (*report)(const char *, ...)) {
   1919 	char algbuf[DNS_SECALG_FORMATSIZE];
   1920 	bool first = true;
   1921 
   1922 	for (size_t i = 0; i < ARRAY_SIZE(vctx->bad_algorithms); i++) {
   1923 		if (vctx->bad_algorithms[i] == 0) {
   1924 			continue;
   1925 		}
   1926 		if (first) {
   1927 			report("The zone is not fully signed "
   1928 			       "for the following algorithms:");
   1929 		}
   1930 		dns_secalg_format(i, algbuf, sizeof(algbuf));
   1931 		report(" %s", algbuf);
   1932 		first = false;
   1933 	}
   1934 
   1935 	if (!first) {
   1936 		report(".");
   1937 	}
   1938 
   1939 	return (first ? ISC_R_SUCCESS : ISC_R_FAILURE);
   1940 }
   1941 
   1942 static void
   1943 print_summary(const vctx_t *vctx, bool keyset_kskonly,
   1944 	      void (*report)(const char *, ...)) {
   1945 	char algbuf[DNS_SECALG_FORMATSIZE];
   1946 
   1947 	report("Zone fully signed:");
   1948 	for (size_t i = 0; i < ARRAY_SIZE(vctx->ksk_algorithms); i++) {
   1949 		if ((vctx->ksk_algorithms[i] == 0) &&
   1950 		    (vctx->standby_ksk[i] == 0) &&
   1951 		    (vctx->revoked_ksk[i] == 0) &&
   1952 		    (vctx->zsk_algorithms[i] == 0) &&
   1953 		    (vctx->standby_zsk[i] == 0) && (vctx->revoked_zsk[i] == 0))
   1954 		{
   1955 			continue;
   1956 		}
   1957 		dns_secalg_format(i, algbuf, sizeof(algbuf));
   1958 		report("Algorithm: %s: KSKs: "
   1959 		       "%u active, %u stand-by, %u revoked",
   1960 		       algbuf, vctx->ksk_algorithms[i], vctx->standby_ksk[i],
   1961 		       vctx->revoked_ksk[i]);
   1962 		report("%*sZSKs: "
   1963 		       "%u active, %u %s, %u revoked",
   1964 		       (int)strlen(algbuf) + 13, "", vctx->zsk_algorithms[i],
   1965 		       vctx->standby_zsk[i],
   1966 		       keyset_kskonly ? "present" : "stand-by",
   1967 		       vctx->revoked_zsk[i]);
   1968 	}
   1969 }
   1970 
   1971 isc_result_t
   1972 dns_zoneverify_dnssec(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
   1973 		      dns_name_t *origin, dns_keytable_t *secroots,
   1974 		      isc_mem_t *mctx, bool ignore_kskflag, bool keyset_kskonly,
   1975 		      void (*report)(const char *, ...)) {
   1976 	const char *keydesc = (secroots == NULL ? "self-signed" : "trusted");
   1977 	isc_result_t result, vresult = ISC_R_UNSET;
   1978 	vctx_t vctx;
   1979 
   1980 	vctx_init(&vctx, mctx, zone, db, ver, origin, secroots);
   1981 
   1982 	result = check_apex_rrsets(&vctx);
   1983 	if (result != ISC_R_SUCCESS) {
   1984 		goto done;
   1985 	}
   1986 
   1987 	result = check_dnskey(&vctx);
   1988 	if (result != ISC_R_SUCCESS) {
   1989 		goto done;
   1990 	}
   1991 
   1992 	if (ignore_kskflag) {
   1993 		if (!vctx.goodksk && !vctx.goodzsk) {
   1994 			zoneverify_log_error(&vctx, "No %s DNSKEY found",
   1995 					     keydesc);
   1996 			result = ISC_R_FAILURE;
   1997 			goto done;
   1998 		}
   1999 	} else if (!vctx.goodksk) {
   2000 		zoneverify_log_error(&vctx, "No %s KSK DNSKEY found", keydesc);
   2001 		result = ISC_R_FAILURE;
   2002 		goto done;
   2003 	}
   2004 
   2005 	determine_active_algorithms(&vctx, ignore_kskflag, keyset_kskonly,
   2006 				    report);
   2007 
   2008 	result = verify_nodes(&vctx, &vresult);
   2009 	if (result != ISC_R_SUCCESS) {
   2010 		goto done;
   2011 	}
   2012 
   2013 	result = verify_nsec3_chains(&vctx, mctx);
   2014 	if (vresult == ISC_R_UNSET) {
   2015 		vresult = ISC_R_SUCCESS;
   2016 	}
   2017 	if (result != ISC_R_SUCCESS && vresult == ISC_R_SUCCESS) {
   2018 		vresult = result;
   2019 	}
   2020 
   2021 	result = check_bad_algorithms(&vctx, report);
   2022 	if (result != ISC_R_SUCCESS) {
   2023 		report("DNSSEC completeness test failed.");
   2024 		goto done;
   2025 	}
   2026 
   2027 	result = vresult;
   2028 	if (result != ISC_R_SUCCESS) {
   2029 		report("DNSSEC completeness test failed (%s).",
   2030 		       isc_result_totext(result));
   2031 		goto done;
   2032 	}
   2033 
   2034 	if (vctx.goodksk || ignore_kskflag) {
   2035 		print_summary(&vctx, keyset_kskonly, report);
   2036 	}
   2037 
   2038 done:
   2039 	vctx_destroy(&vctx);
   2040 
   2041 	return (result);
   2042 }
   2043