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