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