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