zoneverify.c revision 1.1.1.11 1 /* $NetBSD: zoneverify.c,v 1.1.1.11 2024/09/22 00:06:17 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