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