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