Coverage Report

Created: 2026-06-09 06:10

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