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