Coverage Report

Created: 2026-03-07 06:55

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, 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, 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, nsec3param->salt,
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[8244];
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.len != len || memcmp(cbm, nsec3.typebits, len) != 0) {
470
0
    dns_name_format(name, namebuf, sizeof(namebuf));
471
0
    zoneverify_log_error(vctx,
472
0
             "Bad NSEC3 record for %s, bit map "
473
0
             "mismatch",
474
0
             namebuf);
475
0
    *vresult = ISC_R_FAILURE;
476
0
    return ISC_R_SUCCESS;
477
0
  }
478
479
  /*
480
   * Record chain.
481
   */
482
0
  record_nsec3(vctx, rawhash, &nsec3, vctx->expected_chains);
483
484
  /*
485
   * Make sure there is only one NSEC3 record with this set of
486
   * parameters.
487
   */
488
0
  for (result = dns_rdataset_next(rdataset); result == ISC_R_SUCCESS;
489
0
       result = dns_rdataset_next(rdataset))
490
0
  {
491
0
    dns_rdata_t rdata = DNS_RDATA_INIT;
492
0
    dns_rdataset_current(rdataset, &rdata);
493
0
    result = dns_rdata_tostruct(&rdata, &nsec3, NULL);
494
0
    RUNTIME_CHECK(result == ISC_R_SUCCESS);
495
0
    if (nsec3.hash == nsec3param->hash &&
496
0
        nsec3.iterations == nsec3param->iterations &&
497
0
        nsec3.salt_length == nsec3param->salt_length &&
498
0
        memcmp(nsec3.salt, nsec3param->salt, nsec3.salt_length) ==
499
0
          0)
500
0
    {
501
0
      dns_name_format(name, namebuf, sizeof(namebuf));
502
0
      zoneverify_log_error(vctx,
503
0
               "Multiple NSEC3 records with the "
504
0
               "same parameter set for %s",
505
0
               namebuf);
506
0
      *vresult = DNS_R_DUPLICATE;
507
0
      return ISC_R_SUCCESS;
508
0
    }
509
0
  }
510
0
  if (result != ISC_R_NOMORE) {
511
0
    return result;
512
0
  }
513
514
0
  *vresult = ISC_R_SUCCESS;
515
516
0
  return ISC_R_SUCCESS;
517
0
}
518
519
static bool
520
0
innsec3params(const dns_rdata_nsec3_t *nsec3, dns_rdataset_t *nsec3paramset) {
521
0
  dns_rdata_nsec3param_t nsec3param;
522
0
  isc_result_t result;
523
524
0
  DNS_RDATASET_FOREACH(nsec3paramset) {
525
0
    dns_rdata_t rdata = DNS_RDATA_INIT;
526
527
0
    dns_rdataset_current(nsec3paramset, &rdata);
528
0
    result = dns_rdata_tostruct(&rdata, &nsec3param, NULL);
529
0
    RUNTIME_CHECK(result == ISC_R_SUCCESS);
530
0
    if (nsec3param.flags == 0 && nsec3param.hash == nsec3->hash &&
531
0
        nsec3param.iterations == nsec3->iterations &&
532
0
        nsec3param.salt_length == nsec3->salt_length &&
533
0
        memcmp(nsec3param.salt, nsec3->salt, nsec3->salt_length) ==
534
0
          0)
535
0
    {
536
0
      return true;
537
0
    }
538
0
  }
539
0
  return false;
540
0
}
541
542
static isc_result_t
543
record_found(const vctx_t *vctx, const dns_name_t *name, dns_dbnode_t *node,
544
0
       dns_rdataset_t *nsec3paramset) {
545
0
  unsigned char owner[NSEC3_MAX_HASH_LENGTH];
546
0
  dns_rdata_nsec3_t nsec3;
547
0
  dns_rdataset_t rdataset;
548
0
  dns_label_t hashlabel;
549
0
  isc_buffer_t b;
550
0
  isc_result_t result;
551
552
0
  if (nsec3paramset == NULL || !dns_rdataset_isassociated(nsec3paramset))
553
0
  {
554
0
    return ISC_R_SUCCESS;
555
0
  }
556
557
0
  dns_rdataset_init(&rdataset);
558
0
  result = dns_db_findrdataset(vctx->db, node, vctx->ver,
559
0
             dns_rdatatype_nsec3, 0, 0, &rdataset,
560
0
             NULL);
561
0
  if (result != ISC_R_SUCCESS) {
562
0
    return ISC_R_SUCCESS;
563
0
  }
564
565
0
  dns_name_getlabel(name, 0, &hashlabel);
566
0
  isc_region_consume(&hashlabel, 1);
567
0
  isc_buffer_init(&b, owner, sizeof(owner));
568
0
  result = isc_base32hex_decoderegion(&hashlabel, &b);
569
0
  if (result != ISC_R_SUCCESS) {
570
0
    result = ISC_R_SUCCESS;
571
0
    goto cleanup;
572
0
  }
573
574
0
  DNS_RDATASET_FOREACH(&rdataset) {
575
0
    dns_rdata_t rdata = DNS_RDATA_INIT;
576
0
    dns_rdataset_current(&rdataset, &rdata);
577
0
    result = dns_rdata_tostruct(&rdata, &nsec3, NULL);
578
0
    RUNTIME_CHECK(result == ISC_R_SUCCESS);
579
0
    if (nsec3.next_length != isc_buffer_usedlength(&b)) {
580
0
      continue;
581
0
    }
582
583
    /*
584
     * We only care about NSEC3 records that match a NSEC3PARAM
585
     * record.
586
     */
587
0
    if (!innsec3params(&nsec3, nsec3paramset)) {
588
0
      continue;
589
0
    }
590
591
    /*
592
     * Record chain.
593
     */
594
0
    record_nsec3(vctx, owner, &nsec3, vctx->found_chains);
595
0
  }
596
0
  result = ISC_R_SUCCESS;
597
598
0
cleanup:
599
0
  dns_rdataset_disassociate(&rdataset);
600
0
  return result;
601
0
}
602
603
static isc_result_t
604
isoptout(const vctx_t *vctx, const dns_rdata_nsec3param_t *nsec3param,
605
0
   bool *optout) {
606
0
  dns_rdataset_t rdataset;
607
0
  dns_rdata_t rdata = DNS_RDATA_INIT;
608
0
  dns_rdata_nsec3_t nsec3;
609
0
  dns_fixedname_t fixed;
610
0
  dns_name_t *hashname;
611
0
  isc_result_t result;
612
0
  dns_dbnode_t *node = NULL;
613
0
  unsigned char rawhash[NSEC3_MAX_HASH_LENGTH];
614
0
  size_t rhsize = sizeof(rawhash);
615
616
0
  dns_fixedname_init(&fixed);
617
0
  result = dns_nsec3_hashname(&fixed, rawhash, &rhsize, vctx->origin,
618
0
            vctx->origin, nsec3param->hash,
619
0
            nsec3param->iterations, nsec3param->salt,
620
0
            nsec3param->salt_length);
621
0
  if (result != ISC_R_SUCCESS) {
622
0
    zoneverify_log_error(vctx, "dns_nsec3_hashname(): %s",
623
0
             isc_result_totext(result));
624
0
    return result;
625
0
  }
626
627
0
  dns_rdataset_init(&rdataset);
628
0
  hashname = dns_fixedname_name(&fixed);
629
0
  result = dns_db_findnsec3node(vctx->db, hashname, false, &node);
630
0
  if (result == ISC_R_SUCCESS) {
631
0
    result = dns_db_findrdataset(vctx->db, node, vctx->ver,
632
0
               dns_rdatatype_nsec3, 0, 0,
633
0
               &rdataset, NULL);
634
0
  }
635
0
  if (result != ISC_R_SUCCESS) {
636
0
    *optout = false;
637
0
    result = ISC_R_SUCCESS;
638
0
    goto done;
639
0
  }
640
641
0
  result = dns_rdataset_first(&rdataset);
642
0
  if (result != ISC_R_SUCCESS) {
643
0
    zoneverify_log_error(vctx, "dns_rdataset_first(): %s",
644
0
             isc_result_totext(result));
645
0
    goto done;
646
0
  }
647
648
0
  dns_rdataset_current(&rdataset, &rdata);
649
650
0
  result = dns_rdata_tostruct(&rdata, &nsec3, NULL);
651
0
  RUNTIME_CHECK(result == ISC_R_SUCCESS);
652
0
  *optout = ((nsec3.flags & DNS_NSEC3FLAG_OPTOUT) != 0);
653
654
0
done:
655
0
  dns_rdataset_cleanup(&rdataset);
656
0
  if (node != NULL) {
657
0
    dns_db_detachnode(&node);
658
0
  }
659
660
0
  return result;
661
0
}
662
663
static isc_result_t
664
verifynsec3(const vctx_t *vctx, const dns_name_t *name,
665
      const dns_rdata_t *rdata, bool delegation, bool empty,
666
      const unsigned char types[8192], unsigned int maxtype,
667
0
      isc_result_t *vresult) {
668
0
  char namebuf[DNS_NAME_FORMATSIZE];
669
0
  char hashbuf[DNS_NAME_FORMATSIZE];
670
0
  dns_rdataset_t rdataset;
671
0
  dns_rdata_nsec3param_t nsec3param;
672
0
  dns_fixedname_t fixed;
673
0
  dns_name_t *hashname;
674
0
  isc_result_t result, tvresult = ISC_R_UNSET;
675
0
  dns_dbnode_t *node = NULL;
676
0
  unsigned char rawhash[NSEC3_MAX_HASH_LENGTH];
677
0
  size_t rhsize = sizeof(rawhash);
678
0
  bool optout = false;
679
680
0
  result = dns_rdata_tostruct(rdata, &nsec3param, NULL);
681
0
  RUNTIME_CHECK(result == ISC_R_SUCCESS);
682
683
0
  if (nsec3param.flags != 0) {
684
0
    return ISC_R_SUCCESS;
685
0
  }
686
687
0
  if (!dns_nsec3_supportedhash(nsec3param.hash)) {
688
0
    return ISC_R_SUCCESS;
689
0
  }
690
691
0
  if (nsec3param.iterations > DNS_NSEC3_MAXITERATIONS) {
692
0
    result = DNS_R_NSEC3ITERRANGE;
693
0
    zoneverify_log_error(vctx, "verifynsec3: %s",
694
0
             isc_result_totext(result));
695
0
    return result;
696
0
  }
697
698
0
  RETERR(isoptout(vctx, &nsec3param, &optout));
699
700
0
  dns_fixedname_init(&fixed);
701
0
  result = dns_nsec3_hashname(
702
0
    &fixed, rawhash, &rhsize, name, vctx->origin, nsec3param.hash,
703
0
    nsec3param.iterations, nsec3param.salt, nsec3param.salt_length);
704
0
  if (result != ISC_R_SUCCESS) {
705
0
    zoneverify_log_error(vctx, "dns_nsec3_hashname(): %s",
706
0
             isc_result_totext(result));
707
0
    return result;
708
0
  }
709
710
  /*
711
   * We don't use dns_db_find() here as it works with the chosen
712
   * nsec3 chain and we may also be called with uncommitted data
713
   * from dnssec-signzone so the secure status of the zone may not
714
   * be up to date.
715
   */
716
0
  dns_rdataset_init(&rdataset);
717
0
  hashname = dns_fixedname_name(&fixed);
718
0
  result = dns_db_findnsec3node(vctx->db, hashname, false, &node);
719
0
  if (result == ISC_R_SUCCESS) {
720
0
    result = dns_db_findrdataset(vctx->db, node, vctx->ver,
721
0
               dns_rdatatype_nsec3, 0, 0,
722
0
               &rdataset, NULL);
723
0
  }
724
0
  if (result != ISC_R_SUCCESS &&
725
0
      (!delegation || (empty && !optout) ||
726
0
       (!empty && dns_nsec_isset(types, dns_rdatatype_ds))))
727
0
  {
728
0
    dns_name_format(name, namebuf, sizeof(namebuf));
729
0
    dns_name_format(hashname, hashbuf, sizeof(hashbuf));
730
0
    zoneverify_log_error(vctx, "Missing NSEC3 record for %s (%s)",
731
0
             namebuf, hashbuf);
732
0
  } else if (result == ISC_R_NOTFOUND && delegation && (!empty || optout))
733
0
  {
734
0
    result = ISC_R_SUCCESS;
735
0
  } else if (result == ISC_R_SUCCESS) {
736
0
    result = match_nsec3(vctx, name, &nsec3param, &rdataset, types,
737
0
             maxtype, rawhash, rhsize, &tvresult);
738
0
    if (result != ISC_R_SUCCESS) {
739
0
      goto done;
740
0
    }
741
0
    result = tvresult;
742
0
  }
743
744
0
  *vresult = result;
745
0
  result = ISC_R_SUCCESS;
746
747
0
done:
748
0
  dns_rdataset_cleanup(&rdataset);
749
0
  if (node != NULL) {
750
0
    dns_db_detachnode(&node);
751
0
  }
752
753
0
  return result;
754
0
}
755
756
static isc_result_t
757
verifynsec3s(const vctx_t *vctx, const dns_name_t *name,
758
       dns_rdataset_t *nsec3paramset, bool delegation, bool empty,
759
       const unsigned char types[8192], unsigned int maxtype,
760
0
       isc_result_t *vresult) {
761
0
  DNS_RDATASET_FOREACH(nsec3paramset) {
762
0
    dns_rdata_t rdata = DNS_RDATA_INIT;
763
764
0
    dns_rdataset_current(nsec3paramset, &rdata);
765
0
    RETERR(verifynsec3(vctx, name, &rdata, delegation, empty, types,
766
0
           maxtype, vresult));
767
0
    if (*vresult != ISC_R_SUCCESS) {
768
0
      break;
769
0
    }
770
0
  }
771
772
0
  return ISC_R_SUCCESS;
773
0
}
774
775
static isc_result_t
776
verifyset(vctx_t *vctx, dns_rdataset_t *rdataset, const dns_name_t *name,
777
0
    dns_dbnode_t *node, dst_key_t **dstkeys, size_t nkeys) {
778
0
  unsigned char set_algorithms[DST_MAX_ALGS] = { 0 };
779
0
  char namebuf[DNS_NAME_FORMATSIZE];
780
0
  char algbuf[DNS_SECALG_FORMATSIZE];
781
0
  char typebuf[DNS_RDATATYPE_FORMATSIZE];
782
0
  dns_rdataset_t sigrdataset = DNS_RDATASET_INIT;
783
0
  dns_rdatasetiter_t *rdsiter = NULL;
784
0
  bool match = false;
785
0
  isc_result_t result;
786
787
0
  result = dns_db_allrdatasets(vctx->db, node, vctx->ver, 0, 0, &rdsiter);
788
0
  if (result != ISC_R_SUCCESS) {
789
0
    zoneverify_log_error(vctx, "dns_db_allrdatasets(): %s",
790
0
             isc_result_totext(result));
791
0
    return result;
792
0
  }
793
0
  DNS_RDATASETITER_FOREACH(rdsiter) {
794
0
    dns_rdatasetiter_current(rdsiter, &sigrdataset);
795
0
    if (sigrdataset.type == dns_rdatatype_rrsig &&
796
0
        sigrdataset.covers == rdataset->type)
797
0
    {
798
0
      match = true;
799
0
      break;
800
0
    }
801
0
    dns_rdataset_disassociate(&sigrdataset);
802
0
  }
803
804
0
  if (!match) {
805
0
    dns_name_format(name, namebuf, sizeof(namebuf));
806
0
    dns_rdatatype_format(rdataset->type, typebuf, sizeof(typebuf));
807
0
    zoneverify_log_error(vctx, "No signatures for %s/%s", namebuf,
808
0
             typebuf);
809
0
    for (size_t i = 0; i < ARRAY_SIZE(set_algorithms); i++) {
810
0
      if (vctx->act_algorithms[i] != 0) {
811
0
        vctx->bad_algorithms[i] = 1;
812
0
      }
813
0
    }
814
0
    result = ISC_R_SUCCESS;
815
0
    goto done;
816
0
  }
817
818
0
  DNS_RDATASET_FOREACH(&sigrdataset) {
819
0
    dns_rdata_t rdata = DNS_RDATA_INIT;
820
0
    dns_rdata_rrsig_t sig;
821
0
    dst_algorithm_t algorithm;
822
823
0
    dns_rdataset_current(&sigrdataset, &rdata);
824
0
    result = dns_rdata_tostruct(&rdata, &sig, NULL);
825
0
    RUNTIME_CHECK(result == ISC_R_SUCCESS);
826
0
    if (rdataset->ttl != sig.originalttl) {
827
0
      dns_name_format(name, namebuf, sizeof(namebuf));
828
0
      dns_rdatatype_format(rdataset->type, typebuf,
829
0
               sizeof(typebuf));
830
0
      zoneverify_log_error(vctx,
831
0
               "TTL mismatch for "
832
0
               "%s %s keytag %u",
833
0
               namebuf, typebuf, sig.keyid);
834
0
      continue;
835
0
    }
836
0
    algorithm = dst_algorithm_fromdata(sig.algorithm, sig.signature,
837
0
               sig.siglen);
838
0
    if ((set_algorithms[algorithm] != 0) ||
839
0
        (vctx->act_algorithms[algorithm] == 0))
840
0
    {
841
0
      continue;
842
0
    }
843
0
    if (goodsig(vctx, &rdata, name, dstkeys, nkeys, rdataset)) {
844
0
      dns_rdataset_settrust(rdataset, dns_trust_secure);
845
0
      dns_rdataset_settrust(&sigrdataset, dns_trust_secure);
846
0
      set_algorithms[algorithm] = 1;
847
0
    }
848
0
  }
849
0
  result = ISC_R_SUCCESS;
850
851
0
  if (memcmp(set_algorithms, vctx->act_algorithms,
852
0
       sizeof(set_algorithms)) != 0)
853
0
  {
854
0
    dns_name_format(name, namebuf, sizeof(namebuf));
855
0
    dns_rdatatype_format(rdataset->type, typebuf, sizeof(typebuf));
856
0
    for (size_t i = 0; i < ARRAY_SIZE(set_algorithms); i++) {
857
0
      if ((vctx->act_algorithms[i] != 0) &&
858
0
          (set_algorithms[i] == 0))
859
0
      {
860
0
        dst_algorithm_format(i, algbuf, sizeof(algbuf));
861
0
        zoneverify_log_error(vctx,
862
0
                 "No correct %s signature "
863
0
                 "for %s %s",
864
0
                 algbuf, namebuf, typebuf);
865
0
        vctx->bad_algorithms[i] = 1;
866
0
      }
867
0
    }
868
0
  }
869
870
0
done:
871
0
  dns_rdataset_cleanup(&sigrdataset);
872
0
  dns_rdatasetiter_destroy(&rdsiter);
873
874
0
  return result;
875
0
}
876
877
static isc_result_t
878
verifynode(vctx_t *vctx, const dns_name_t *name, dns_dbnode_t *node,
879
     bool delegation, dst_key_t **dstkeys, size_t nkeys,
880
     dns_rdataset_t *nsecset, dns_rdataset_t *nsec3paramset,
881
0
     const dns_name_t *nextname, isc_result_t *vresult) {
882
0
  unsigned char types[8192] = { 0 };
883
0
  unsigned int maxtype = 0;
884
0
  dns_rdatasetiter_t *rdsiter = NULL;
885
0
  isc_result_t result, tvresult = ISC_R_UNSET;
886
887
0
  REQUIRE(vresult != NULL || (nsecset == NULL && nsec3paramset == NULL));
888
889
0
  result = dns_db_allrdatasets(vctx->db, node, vctx->ver, 0, 0, &rdsiter);
890
0
  if (result != ISC_R_SUCCESS) {
891
0
    zoneverify_log_error(vctx, "dns_db_allrdatasets(): %s",
892
0
             isc_result_totext(result));
893
0
    return result;
894
0
  }
895
896
0
  DNS_RDATASETITER_FOREACH(rdsiter) {
897
0
    dns_rdataset_t rdataset = DNS_RDATASET_INIT;
898
0
    dns_rdatasetiter_current(rdsiter, &rdataset);
899
900
    /*
901
     * If we are not at a delegation then everything should be
902
     * signed.  If we are at a delegation then only the DS set
903
     * is signed.  The NS set is not signed at a delegation but
904
     * its existence is recorded in the bit map.  Anything else
905
     * other than NSEC and DS is not signed at a delegation.
906
     */
907
0
    if (rdataset.type != dns_rdatatype_rrsig &&
908
0
        (!delegation || rdataset.type == dns_rdatatype_ds ||
909
0
         rdataset.type == dns_rdatatype_nsec))
910
0
    {
911
0
      result = verifyset(vctx, &rdataset, name, node, dstkeys,
912
0
             nkeys);
913
0
      if (result != ISC_R_SUCCESS) {
914
0
        dns_rdataset_disassociate(&rdataset);
915
0
        dns_rdatasetiter_destroy(&rdsiter);
916
0
        return result;
917
0
      }
918
0
      dns_nsec_setbit(types, rdataset.type, 1);
919
0
      if (rdataset.type > maxtype) {
920
0
        maxtype = rdataset.type;
921
0
      }
922
0
    } else if (rdataset.type != dns_rdatatype_rrsig) {
923
0
      if (rdataset.type == dns_rdatatype_ns) {
924
0
        dns_nsec_setbit(types, rdataset.type, 1);
925
0
        if (rdataset.type > maxtype) {
926
0
          maxtype = rdataset.type;
927
0
        }
928
0
      }
929
0
      result = check_no_rrsig(vctx, &rdataset, name, node);
930
0
      if (result != ISC_R_SUCCESS) {
931
0
        dns_rdataset_disassociate(&rdataset);
932
0
        dns_rdatasetiter_destroy(&rdsiter);
933
0
        return result;
934
0
      }
935
0
    } else {
936
0
      dns_nsec_setbit(types, rdataset.type, 1);
937
0
      if (rdataset.type > maxtype) {
938
0
        maxtype = rdataset.type;
939
0
      }
940
0
    }
941
0
    dns_rdataset_disassociate(&rdataset);
942
0
  }
943
0
  dns_rdatasetiter_destroy(&rdsiter);
944
945
0
  if (vresult == NULL) {
946
0
    return ISC_R_SUCCESS;
947
0
  }
948
949
0
  *vresult = ISC_R_SUCCESS;
950
951
0
  if (nsecset != NULL && dns_rdataset_isassociated(nsecset)) {
952
0
    RETERR(verifynsec(vctx, name, node, nextname, &tvresult));
953
0
    *vresult = tvresult;
954
0
  }
955
956
0
  if (nsec3paramset != NULL && dns_rdataset_isassociated(nsec3paramset)) {
957
0
    RETERR(verifynsec3s(vctx, name, nsec3paramset, delegation,
958
0
            false, types, maxtype, &tvresult));
959
0
    if (*vresult == ISC_R_SUCCESS) {
960
0
      *vresult = tvresult;
961
0
    }
962
0
  }
963
964
0
  return ISC_R_SUCCESS;
965
0
}
966
967
static isc_result_t
968
0
is_empty(const vctx_t *vctx, dns_dbnode_t *node) {
969
0
  dns_rdatasetiter_t *rdsiter = NULL;
970
0
  isc_result_t result;
971
972
0
  result = dns_db_allrdatasets(vctx->db, node, vctx->ver, 0, 0, &rdsiter);
973
0
  if (result != ISC_R_SUCCESS) {
974
0
    zoneverify_log_error(vctx, "dns_db_allrdatasets(): %s",
975
0
             isc_result_totext(result));
976
0
    return result;
977
0
  }
978
0
  result = dns_rdatasetiter_first(rdsiter);
979
0
  dns_rdatasetiter_destroy(&rdsiter);
980
981
0
  return result;
982
0
}
983
984
static isc_result_t
985
0
check_no_nsec(const vctx_t *vctx, const dns_name_t *name, dns_dbnode_t *node) {
986
0
  bool nsec_exists = false;
987
0
  dns_rdataset_t rdataset;
988
0
  isc_result_t result;
989
990
0
  dns_rdataset_init(&rdataset);
991
0
  result = dns_db_findrdataset(vctx->db, node, vctx->ver,
992
0
             dns_rdatatype_nsec, 0, 0, &rdataset, NULL);
993
0
  if (result != ISC_R_NOTFOUND) {
994
0
    char namebuf[DNS_NAME_FORMATSIZE];
995
0
    dns_name_format(name, namebuf, sizeof(namebuf));
996
0
    zoneverify_log_error(vctx, "unexpected NSEC RRset at %s",
997
0
             namebuf);
998
0
    nsec_exists = true;
999
0
  }
1000
1001
0
  dns_rdataset_cleanup(&rdataset);
1002
1003
0
  return nsec_exists ? ISC_R_FAILURE : ISC_R_SUCCESS;
1004
0
}
1005
1006
static void
1007
0
free_element(isc_mem_t *mctx, struct nsec3_chain_fixed *e) {
1008
0
  size_t len;
1009
1010
0
  len = sizeof(*e) + e->salt_length + 2 * e->next_length;
1011
0
  isc_mem_put(mctx, e, len);
1012
0
}
1013
1014
static void
1015
0
free_element_heap(void *element, void *uap) {
1016
0
  struct nsec3_chain_fixed *e = (struct nsec3_chain_fixed *)element;
1017
0
  isc_mem_t *mctx = (isc_mem_t *)uap;
1018
1019
0
  free_element(mctx, e);
1020
0
}
1021
1022
static bool
1023
_checknext(const vctx_t *vctx, const struct nsec3_chain_fixed *first,
1024
0
     const struct nsec3_chain_fixed *e) {
1025
0
  char buf[512];
1026
0
  const unsigned char *d1 = (const unsigned char *)(first + 1);
1027
0
  const unsigned char *d2 = (const unsigned char *)(e + 1);
1028
0
  isc_buffer_t b;
1029
0
  isc_region_t sr;
1030
1031
0
  d1 += first->salt_length + first->next_length;
1032
0
  d2 += e->salt_length;
1033
1034
0
  if (memcmp(d1, d2, first->next_length) == 0) {
1035
0
    return true;
1036
0
  }
1037
1038
0
  sr.base = UNCONST(d1 - first->next_length);
1039
0
  sr.length = first->next_length;
1040
0
  isc_buffer_init(&b, buf, sizeof(buf));
1041
0
  isc_base32hex_totext(&sr, 1, "", &b);
1042
0
  zoneverify_log_error(vctx, "Break in NSEC3 chain at: %.*s",
1043
0
           (int)isc_buffer_usedlength(&b), buf);
1044
1045
0
  sr.base = UNCONST(d1);
1046
0
  sr.length = first->next_length;
1047
0
  isc_buffer_init(&b, buf, sizeof(buf));
1048
0
  isc_base32hex_totext(&sr, 1, "", &b);
1049
0
  zoneverify_log_error(vctx, "Expected: %.*s",
1050
0
           (int)isc_buffer_usedlength(&b), buf);
1051
1052
0
  sr.base = UNCONST(d2);
1053
0
  sr.length = first->next_length;
1054
0
  isc_buffer_init(&b, buf, sizeof(buf));
1055
0
  isc_base32hex_totext(&sr, 1, "", &b);
1056
0
  zoneverify_log_error(vctx, "Found: %.*s",
1057
0
           (int)isc_buffer_usedlength(&b), buf);
1058
1059
0
  return false;
1060
0
}
1061
1062
static bool
1063
checknext(isc_mem_t *mctx, const vctx_t *vctx,
1064
    const struct nsec3_chain_fixed *first, struct nsec3_chain_fixed *prev,
1065
0
    const struct nsec3_chain_fixed *cur) {
1066
0
  bool result = _checknext(vctx, prev, cur);
1067
1068
0
  if (prev != first) {
1069
0
    free_element(mctx, prev);
1070
0
  }
1071
1072
0
  return result;
1073
0
}
1074
1075
static bool
1076
checklast(isc_mem_t *mctx, const vctx_t *vctx, struct nsec3_chain_fixed *first,
1077
0
    struct nsec3_chain_fixed *prev) {
1078
0
  bool result = _checknext(vctx, prev, first);
1079
0
  if (prev != first) {
1080
0
    free_element(mctx, prev);
1081
0
  }
1082
0
  free_element(mctx, first);
1083
1084
0
  return result;
1085
0
}
1086
1087
static isc_result_t
1088
0
verify_nsec3_chains(const vctx_t *vctx, isc_mem_t *mctx) {
1089
0
  isc_result_t result = ISC_R_SUCCESS;
1090
0
  struct nsec3_chain_fixed *e, *f = NULL;
1091
0
  struct nsec3_chain_fixed *first = NULL, *prev = NULL;
1092
1093
0
  while ((e = isc_heap_element(vctx->expected_chains, 1)) != NULL) {
1094
0
    isc_heap_delete(vctx->expected_chains, 1);
1095
0
    if (f == NULL) {
1096
0
      f = isc_heap_element(vctx->found_chains, 1);
1097
0
    }
1098
0
    if (f != NULL) {
1099
0
      isc_heap_delete(vctx->found_chains, 1);
1100
1101
      /*
1102
       * Check that they match.
1103
       */
1104
0
      if (chain_equal(e, f, chain_length(e))) {
1105
0
        free_element(mctx, f);
1106
0
        f = NULL;
1107
0
      } else {
1108
0
        if (result == ISC_R_SUCCESS) {
1109
0
          zoneverify_log_error(vctx, "Expected "
1110
0
                   "and found "
1111
0
                   "NSEC3 "
1112
0
                   "chains not "
1113
0
                   "equal");
1114
0
        }
1115
0
        result = ISC_R_FAILURE;
1116
        /*
1117
         * Attempt to resync found_chain.
1118
         */
1119
0
        while (f != NULL && !chain_compare(e, f)) {
1120
0
          free_element(mctx, f);
1121
0
          f = isc_heap_element(vctx->found_chains,
1122
0
                   1);
1123
0
          if (f != NULL) {
1124
0
            isc_heap_delete(
1125
0
              vctx->found_chains, 1);
1126
0
          }
1127
0
          if (f != NULL &&
1128
0
              chain_equal(e, f, chain_length(e)))
1129
0
          {
1130
0
            free_element(mctx, f);
1131
0
            f = NULL;
1132
0
            break;
1133
0
          }
1134
0
        }
1135
0
      }
1136
0
    } else if (result == ISC_R_SUCCESS) {
1137
0
      zoneverify_log_error(vctx, "Expected and found NSEC3 "
1138
0
               "chains "
1139
0
               "not equal");
1140
0
      result = ISC_R_FAILURE;
1141
0
    }
1142
1143
0
    if (first == NULL) {
1144
0
      prev = first = e;
1145
0
    } else if (!chain_equal(first, e, first->salt_length)) {
1146
0
      if (!checklast(mctx, vctx, first, prev)) {
1147
0
        result = ISC_R_FAILURE;
1148
0
      }
1149
1150
0
      prev = first = e;
1151
0
    } else {
1152
0
      if (!checknext(mctx, vctx, first, prev, e)) {
1153
0
        result = ISC_R_FAILURE;
1154
0
      }
1155
1156
0
      prev = e;
1157
0
    }
1158
0
  }
1159
0
  if (prev != NULL) {
1160
0
    if (!checklast(mctx, vctx, first, prev)) {
1161
0
      result = ISC_R_FAILURE;
1162
0
    }
1163
0
  }
1164
0
  do {
1165
0
    if (f != NULL) {
1166
0
      if (result == ISC_R_SUCCESS) {
1167
0
        zoneverify_log_error(vctx, "Expected and found "
1168
0
                 "NSEC3 chains not "
1169
0
                 "equal");
1170
0
        result = ISC_R_FAILURE;
1171
0
      }
1172
0
      free_element(mctx, f);
1173
0
    }
1174
0
    f = isc_heap_element(vctx->found_chains, 1);
1175
0
    if (f != NULL) {
1176
0
      isc_heap_delete(vctx->found_chains, 1);
1177
0
    }
1178
0
  } while (f != NULL);
1179
1180
0
  return result;
1181
0
}
1182
1183
static isc_result_t
1184
verifyemptynodes(const vctx_t *vctx, const dns_name_t *name,
1185
     const dns_name_t *prevname, bool isdelegation,
1186
0
     dns_rdataset_t *nsec3paramset, isc_result_t *vresult) {
1187
0
  dns_namereln_t reln;
1188
0
  int order;
1189
0
  unsigned int labels, nlabels, i;
1190
0
  dns_name_t suffix;
1191
0
  isc_result_t tvresult = ISC_R_UNSET;
1192
1193
0
  *vresult = ISC_R_SUCCESS;
1194
1195
0
  reln = dns_name_fullcompare(prevname, name, &order, &labels);
1196
0
  if (order >= 0) {
1197
0
    return ISC_R_SUCCESS;
1198
0
  }
1199
1200
0
  nlabels = dns_name_countlabels(name);
1201
1202
0
  if (reln == dns_namereln_commonancestor ||
1203
0
      reln == dns_namereln_contains)
1204
0
  {
1205
0
    dns_name_init(&suffix);
1206
0
    for (i = labels + 1; i < nlabels; i++) {
1207
0
      dns_name_getlabelsequence(name, nlabels - i, i,
1208
0
              &suffix);
1209
0
      if (nsec3paramset != NULL &&
1210
0
          dns_rdataset_isassociated(nsec3paramset))
1211
0
      {
1212
0
        RETERR(verifynsec3s(vctx, &suffix,
1213
0
                nsec3paramset, isdelegation,
1214
0
                true, NULL, 0, &tvresult));
1215
0
        if (*vresult == ISC_R_SUCCESS) {
1216
0
          *vresult = tvresult;
1217
0
        }
1218
0
      }
1219
0
    }
1220
0
  }
1221
1222
0
  return ISC_R_SUCCESS;
1223
0
}
1224
1225
static void
1226
vctx_init(vctx_t *vctx, isc_mem_t *mctx, dns_zone_t *zone, dns_db_t *db,
1227
0
    dns_dbversion_t *ver, dns_name_t *origin, dns_keytable_t *secroots) {
1228
0
  memset(vctx, 0, sizeof(*vctx));
1229
1230
0
  vctx->mctx = mctx;
1231
0
  vctx->zone = zone;
1232
0
  vctx->db = db;
1233
0
  vctx->ver = ver;
1234
0
  vctx->origin = origin;
1235
0
  vctx->secroots = secroots;
1236
0
  vctx->goodksk = false;
1237
0
  vctx->goodzsk = false;
1238
1239
0
  dns_rdataset_init(&vctx->keyset);
1240
0
  dns_rdataset_init(&vctx->keysigs);
1241
0
  dns_rdataset_init(&vctx->soaset);
1242
0
  dns_rdataset_init(&vctx->soasigs);
1243
0
  dns_rdataset_init(&vctx->nsecset);
1244
0
  dns_rdataset_init(&vctx->nsecsigs);
1245
0
  dns_rdataset_init(&vctx->nsec3paramset);
1246
0
  dns_rdataset_init(&vctx->nsec3paramsigs);
1247
1248
0
  vctx->expected_chains = NULL;
1249
0
  isc_heap_create(mctx, chain_compare, NULL, 1024,
1250
0
      &vctx->expected_chains);
1251
1252
0
  vctx->found_chains = NULL;
1253
0
  isc_heap_create(mctx, chain_compare, NULL, 1024, &vctx->found_chains);
1254
0
}
1255
1256
static void
1257
0
vctx_destroy(vctx_t *vctx) {
1258
0
  dns_rdataset_cleanup(&vctx->keyset);
1259
0
  dns_rdataset_cleanup(&vctx->keysigs);
1260
0
  dns_rdataset_cleanup(&vctx->soaset);
1261
0
  dns_rdataset_cleanup(&vctx->soasigs);
1262
0
  dns_rdataset_cleanup(&vctx->nsecset);
1263
0
  dns_rdataset_cleanup(&vctx->nsecsigs);
1264
0
  dns_rdataset_cleanup(&vctx->nsec3paramset);
1265
0
  dns_rdataset_cleanup(&vctx->nsec3paramsigs);
1266
0
  isc_heap_foreach(vctx->expected_chains, free_element_heap, vctx->mctx);
1267
0
  isc_heap_destroy(&vctx->expected_chains);
1268
0
  isc_heap_foreach(vctx->found_chains, free_element_heap, vctx->mctx);
1269
0
  isc_heap_destroy(&vctx->found_chains);
1270
0
}
1271
1272
static isc_result_t
1273
0
check_apex_rrsets(vctx_t *vctx) {
1274
0
  dns_dbnode_t *node = NULL;
1275
0
  isc_result_t result;
1276
1277
0
  result = dns_db_findnode(vctx->db, vctx->origin, false, &node);
1278
0
  if (result != ISC_R_SUCCESS) {
1279
0
    zoneverify_log_error(vctx,
1280
0
             "failed to find the zone's origin: %s",
1281
0
             isc_result_totext(result));
1282
0
    return result;
1283
0
  }
1284
1285
0
  result = dns_db_findrdataset(vctx->db, node, vctx->ver,
1286
0
             dns_rdatatype_dnskey, 0, 0, &vctx->keyset,
1287
0
             &vctx->keysigs);
1288
0
  if (result != ISC_R_SUCCESS) {
1289
0
    zoneverify_log_error(vctx, "Zone contains no DNSSEC keys");
1290
0
    goto done;
1291
0
  }
1292
1293
0
  result = dns_db_findrdataset(vctx->db, node, vctx->ver,
1294
0
             dns_rdatatype_soa, 0, 0, &vctx->soaset,
1295
0
             &vctx->soasigs);
1296
0
  if (result != ISC_R_SUCCESS) {
1297
0
    zoneverify_log_error(vctx, "Zone contains no SOA record");
1298
0
    goto done;
1299
0
  }
1300
1301
0
  result = dns_db_findrdataset(vctx->db, node, vctx->ver,
1302
0
             dns_rdatatype_nsec, 0, 0, &vctx->nsecset,
1303
0
             &vctx->nsecsigs);
1304
0
  if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
1305
0
    zoneverify_log_error(vctx, "NSEC lookup failed");
1306
0
    goto done;
1307
0
  }
1308
1309
0
  result = dns_db_findrdataset(
1310
0
    vctx->db, node, vctx->ver, dns_rdatatype_nsec3param, 0, 0,
1311
0
    &vctx->nsec3paramset, &vctx->nsec3paramsigs);
1312
0
  if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
1313
0
    zoneverify_log_error(vctx, "NSEC3PARAM lookup failed");
1314
0
    goto done;
1315
0
  }
1316
1317
0
  if (!dns_rdataset_isassociated(&vctx->keysigs)) {
1318
0
    zoneverify_log_error(vctx, "DNSKEY is not signed "
1319
0
             "(keys offline or inactive?)");
1320
0
    result = ISC_R_FAILURE;
1321
0
    goto done;
1322
0
  }
1323
1324
0
  if (!dns_rdataset_isassociated(&vctx->soasigs)) {
1325
0
    zoneverify_log_error(vctx, "SOA is not signed "
1326
0
             "(keys offline or inactive?)");
1327
0
    result = ISC_R_FAILURE;
1328
0
    goto done;
1329
0
  }
1330
1331
0
  if (dns_rdataset_isassociated(&vctx->nsecset) &&
1332
0
      !dns_rdataset_isassociated(&vctx->nsecsigs))
1333
0
  {
1334
0
    zoneverify_log_error(vctx, "NSEC is not signed "
1335
0
             "(keys offline or inactive?)");
1336
0
    result = ISC_R_FAILURE;
1337
0
    goto done;
1338
0
  }
1339
1340
0
  if (dns_rdataset_isassociated(&vctx->nsec3paramset) &&
1341
0
      !dns_rdataset_isassociated(&vctx->nsec3paramsigs))
1342
0
  {
1343
0
    zoneverify_log_error(vctx, "NSEC3PARAM is not signed "
1344
0
             "(keys offline or inactive?)");
1345
0
    result = ISC_R_FAILURE;
1346
0
    goto done;
1347
0
  }
1348
1349
0
  if (!dns_rdataset_isassociated(&vctx->nsecset) &&
1350
0
      !dns_rdataset_isassociated(&vctx->nsec3paramset))
1351
0
  {
1352
0
    zoneverify_log_error(vctx, "No valid NSEC/NSEC3 chain for "
1353
0
             "testing");
1354
0
    result = ISC_R_FAILURE;
1355
0
    goto done;
1356
0
  }
1357
1358
0
  result = ISC_R_SUCCESS;
1359
1360
0
done:
1361
0
  dns_db_detachnode(&node);
1362
1363
0
  return result;
1364
0
}
1365
1366
/*%
1367
 * Update 'vctx' tables tracking active and standby key algorithms used in the
1368
 * verified zone based on the signatures made using 'dnskey' (prepared from
1369
 * 'rdata') found at zone apex.  Set 'vctx->goodksk' or 'vctx->goodzsk' to true
1370
 * if 'dnskey' correctly signs the DNSKEY RRset at zone apex and either
1371
 * 'vctx->secroots' is NULL or 'dnskey' is present in 'vctx->secroots'.
1372
 *
1373
 * The variables to update are chosen based on 'is_ksk', which is true when
1374
 * 'dnskey' is a KSK and false otherwise.
1375
 */
1376
static void
1377
check_dnskey_sigs(vctx_t *vctx, const dns_rdata_dnskey_t *dnskey,
1378
0
      dns_rdata_t *keyrdata, bool is_ksk) {
1379
0
  unsigned char *active_keys = NULL, *standby_keys = NULL;
1380
0
  dns_keynode_t *keynode = NULL;
1381
0
  bool *goodkey = NULL;
1382
0
  dst_key_t *key = NULL;
1383
0
  isc_result_t result;
1384
0
  dns_rdataset_t dsset;
1385
0
  dst_algorithm_t algorithm;
1386
1387
0
  active_keys = (is_ksk ? vctx->ksk_algorithms : vctx->zsk_algorithms);
1388
0
  standby_keys = (is_ksk ? vctx->standby_ksk : vctx->standby_zsk);
1389
0
  goodkey = (is_ksk ? &vctx->goodksk : &vctx->goodzsk);
1390
0
  algorithm = dst_algorithm_fromdata(dnskey->algorithm, dnskey->data,
1391
0
             dnskey->datalen);
1392
1393
  /*
1394
   * First, does this key sign the DNSKEY rrset?
1395
   */
1396
0
  if (!dns_dnssec_selfsigns(keyrdata, vctx->origin, &vctx->keyset,
1397
0
          &vctx->keysigs, false, vctx->mctx))
1398
0
  {
1399
0
    if (!is_ksk &&
1400
0
        dns_dnssec_signs(keyrdata, vctx->origin, &vctx->soaset,
1401
0
             &vctx->soasigs, false, vctx->mctx))
1402
0
    {
1403
0
      if (active_keys[algorithm] != DNS_KEYALG_MAX) {
1404
0
        active_keys[algorithm]++;
1405
0
      }
1406
0
    } else {
1407
0
      if (standby_keys[algorithm] != DNS_KEYALG_MAX) {
1408
0
        standby_keys[algorithm]++;
1409
0
      }
1410
0
    }
1411
0
    return;
1412
0
  }
1413
1414
0
  if (active_keys[algorithm] != DNS_KEYALG_MAX) {
1415
0
    active_keys[algorithm]++;
1416
0
  }
1417
1418
  /*
1419
   * If a trust anchor table was not supplied, a correctly self-signed
1420
   * DNSKEY RRset is good enough.
1421
   */
1422
0
  if (vctx->secroots == NULL) {
1423
0
    *goodkey = true;
1424
0
    return;
1425
0
  }
1426
1427
  /*
1428
   * Convert the supplied key rdata to dst_key_t. (If this
1429
   * fails we can't go further.)
1430
   */
1431
0
  result = dns_dnssec_keyfromrdata(vctx->origin, keyrdata, vctx->mctx,
1432
0
           &key);
1433
0
  RUNTIME_CHECK(result == ISC_R_SUCCESS);
1434
1435
  /*
1436
   * Look up the supplied key in the trust anchor table.
1437
   * If we don't find an exact match, or if the keynode data
1438
   * is NULL, then we have neither a DNSKEY nor a DS format
1439
   * trust anchor, and can give up.
1440
   */
1441
0
  CHECK(dns_keytable_find(vctx->secroots, vctx->origin, &keynode));
1442
1443
  /*
1444
   * If the keynode has any DS format trust anchors, that means
1445
   * it doesn't have any DNSKEY ones. So, we can check for a DS
1446
   * match and then stop.
1447
   */
1448
0
  dns_rdataset_init(&dsset);
1449
0
  if (dns_keynode_dsset(keynode, &dsset)) {
1450
0
    DNS_RDATASET_FOREACH(&dsset) {
1451
0
      dns_rdata_t dsrdata = DNS_RDATA_INIT;
1452
0
      dns_rdata_t newdsrdata = DNS_RDATA_INIT;
1453
0
      unsigned char buf[DNS_DS_BUFFERSIZE];
1454
0
      dns_rdata_ds_t ds;
1455
1456
0
      dns_rdata_reset(&dsrdata);
1457
0
      dns_rdataset_current(&dsset, &dsrdata);
1458
0
      result = dns_rdata_tostruct(&dsrdata, &ds, NULL);
1459
0
      RUNTIME_CHECK(result == ISC_R_SUCCESS);
1460
1461
0
      if (ds.key_tag != dst_key_id(key) ||
1462
0
          ds.algorithm !=
1463
0
            dst_algorithm_tosecalg(dst_key_alg(key)))
1464
0
      {
1465
0
        continue;
1466
0
      }
1467
1468
0
      result = dns_ds_buildrdata(vctx->origin, keyrdata,
1469
0
               ds.digest_type, buf,
1470
0
               sizeof(buf), &newdsrdata);
1471
0
      if (result != ISC_R_SUCCESS) {
1472
0
        continue;
1473
0
      }
1474
1475
0
      if (dns_rdata_compare(&dsrdata, &newdsrdata) == 0) {
1476
0
        dns_rdataset_settrust(&vctx->keyset,
1477
0
                  dns_trust_secure);
1478
0
        dns_rdataset_settrust(&vctx->keysigs,
1479
0
                  dns_trust_secure);
1480
0
        *goodkey = true;
1481
0
        break;
1482
0
      }
1483
0
    }
1484
0
    dns_rdataset_disassociate(&dsset);
1485
1486
0
    goto cleanup;
1487
0
  }
1488
1489
0
cleanup:
1490
0
  if (keynode != NULL) {
1491
0
    dns_keynode_detach(&keynode);
1492
0
  }
1493
0
  if (key != NULL) {
1494
0
    dst_key_free(&key);
1495
0
  }
1496
0
}
1497
1498
/*%
1499
 * Check that the DNSKEY RR has at least one self signing KSK and one ZSK per
1500
 * algorithm in it (or, if -x was used, one self-signing KSK).
1501
 */
1502
static isc_result_t
1503
0
check_dnskey(vctx_t *vctx) {
1504
0
  dns_rdata_dnskey_t dnskey;
1505
0
  isc_result_t result;
1506
0
  bool is_ksk;
1507
1508
0
  DNS_RDATASET_FOREACH(&vctx->keyset) {
1509
0
    dns_rdata_t rdata = DNS_RDATA_INIT;
1510
0
    dns_rdataset_current(&vctx->keyset, &rdata);
1511
0
    result = dns_rdata_tostruct(&rdata, &dnskey, NULL);
1512
0
    RUNTIME_CHECK(result == ISC_R_SUCCESS);
1513
0
    is_ksk = ((dnskey.flags & DNS_KEYFLAG_KSK) != 0);
1514
1515
0
    if ((dnskey.flags & DNS_KEYOWNER_ZONE) != 0 &&
1516
0
        (dnskey.flags & DNS_KEYFLAG_REVOKE) != 0)
1517
0
    {
1518
0
      dst_algorithm_t algorithm;
1519
0
      if ((dnskey.flags & DNS_KEYFLAG_KSK) != 0 &&
1520
0
          !dns_dnssec_selfsigns(&rdata, vctx->origin,
1521
0
              &vctx->keyset, &vctx->keysigs,
1522
0
              false, vctx->mctx))
1523
0
      {
1524
0
        char namebuf[DNS_NAME_FORMATSIZE];
1525
0
        char buffer[1024];
1526
0
        isc_buffer_t buf;
1527
1528
0
        dns_name_format(vctx->origin, namebuf,
1529
0
            sizeof(namebuf));
1530
0
        isc_buffer_init(&buf, buffer, sizeof(buffer));
1531
0
        result = dns_rdata_totext(&rdata, NULL, &buf);
1532
0
        if (result != ISC_R_SUCCESS) {
1533
0
          zoneverify_log_error(
1534
0
            vctx, "dns_rdata_totext: %s",
1535
0
            isc_result_totext(result));
1536
0
          return ISC_R_FAILURE;
1537
0
        }
1538
0
        zoneverify_log_error(
1539
0
          vctx,
1540
0
          "revoked KSK is not self signed:\n"
1541
0
          "%s DNSKEY %.*s",
1542
0
          namebuf,
1543
0
          (int)isc_buffer_usedlength(&buf),
1544
0
          buffer);
1545
0
        return ISC_R_FAILURE;
1546
0
      }
1547
0
      algorithm = dst_algorithm_fromdata(
1548
0
        dnskey.algorithm, dnskey.data, dnskey.datalen);
1549
0
      if ((dnskey.flags & DNS_KEYFLAG_KSK) != 0 &&
1550
0
          vctx->revoked_ksk[algorithm] != DNS_KEYALG_MAX)
1551
0
      {
1552
0
        vctx->revoked_ksk[algorithm]++;
1553
0
      } else if ((dnskey.flags & DNS_KEYFLAG_KSK) == 0 &&
1554
0
           vctx->revoked_zsk[algorithm] !=
1555
0
             DNS_KEYALG_MAX)
1556
0
      {
1557
0
        vctx->revoked_zsk[algorithm]++;
1558
0
      }
1559
0
    } else {
1560
0
      check_dnskey_sigs(vctx, &dnskey, &rdata, is_ksk);
1561
0
    }
1562
0
    dns_rdata_freestruct(&dnskey);
1563
0
  }
1564
1565
0
  return ISC_R_SUCCESS;
1566
0
}
1567
1568
static void
1569
determine_active_algorithms(vctx_t *vctx, bool ignore_kskflag,
1570
          bool keyset_kskonly,
1571
0
          void (*report)(const char *, ...)) {
1572
0
  char algbuf[DNS_SECALG_FORMATSIZE];
1573
1574
0
  report("Verifying the zone using the following algorithms:");
1575
1576
0
  for (size_t i = 0; i < ARRAY_SIZE(vctx->act_algorithms); i++) {
1577
0
    if (ignore_kskflag) {
1578
0
      vctx->act_algorithms[i] = (vctx->ksk_algorithms[i] !=
1579
0
                 0 ||
1580
0
               vctx->zsk_algorithms[i] != 0)
1581
0
                ? 1
1582
0
                : 0;
1583
0
    } else {
1584
0
      vctx->act_algorithms[i] = vctx->ksk_algorithms[i] != 0
1585
0
                ? 1
1586
0
                : 0;
1587
0
    }
1588
0
    if (vctx->act_algorithms[i] != 0) {
1589
0
      dst_algorithm_format(i, algbuf, sizeof(algbuf));
1590
0
      report("- %s", algbuf);
1591
0
    }
1592
0
  }
1593
1594
0
  if (ignore_kskflag || keyset_kskonly) {
1595
0
    return;
1596
0
  }
1597
1598
0
  for (size_t i = 0; i < ARRAY_SIZE(vctx->ksk_algorithms); i++) {
1599
    /*
1600
     * The counts should both be zero or both be non-zero.  Mark
1601
     * the algorithm as bad if this is not met.
1602
     */
1603
0
    if ((vctx->ksk_algorithms[i] != 0) ==
1604
0
        (vctx->zsk_algorithms[i] != 0))
1605
0
    {
1606
0
      continue;
1607
0
    }
1608
0
    dst_algorithm_format(i, algbuf, sizeof(algbuf));
1609
0
    zoneverify_log_error(vctx, "Missing %s for algorithm %s",
1610
0
             (vctx->ksk_algorithms[i] != 0) ? "ZSK"
1611
0
                    : "self-"
1612
0
                      "signed "
1613
0
                      "KSK",
1614
0
             algbuf);
1615
0
    vctx->bad_algorithms[i] = 1;
1616
0
  }
1617
0
}
1618
1619
/*%
1620
 * Check that all the records not yet verified were signed by keys that are
1621
 * present in the DNSKEY RRset.
1622
 */
1623
static isc_result_t
1624
0
verify_nodes(vctx_t *vctx, isc_result_t *vresult) {
1625
0
  dns_fixedname_t fname, fnextname, fprevname, fzonecut;
1626
0
  dns_name_t *name, *nextname, *prevname, *zonecut;
1627
0
  dns_dbnode_t *node = NULL, *nextnode;
1628
0
  dns_dbiterator_t *dbiter = NULL;
1629
0
  dst_key_t **dstkeys;
1630
0
  size_t count, nkeys = 0;
1631
0
  bool done = false;
1632
0
  isc_result_t tvresult = ISC_R_UNSET;
1633
0
  isc_result_t result;
1634
1635
0
  name = dns_fixedname_initname(&fname);
1636
0
  nextname = dns_fixedname_initname(&fnextname);
1637
0
  dns_fixedname_init(&fprevname);
1638
0
  prevname = NULL;
1639
0
  dns_fixedname_init(&fzonecut);
1640
0
  zonecut = NULL;
1641
1642
0
  count = dns_rdataset_count(&vctx->keyset);
1643
0
  dstkeys = isc_mem_cget(vctx->mctx, count, sizeof(*dstkeys));
1644
1645
0
  DNS_RDATASET_FOREACH(&vctx->keyset) {
1646
0
    dns_rdata_t rdata = DNS_RDATA_INIT;
1647
0
    dns_rdataset_current(&vctx->keyset, &rdata);
1648
0
    dstkeys[nkeys] = NULL;
1649
0
    result = dns_dnssec_keyfromrdata(vctx->origin, &rdata,
1650
0
             vctx->mctx, &dstkeys[nkeys]);
1651
0
    if (result == ISC_R_SUCCESS) {
1652
0
      nkeys++;
1653
0
    }
1654
0
  }
1655
1656
0
  result = dns_db_createiterator(vctx->db, DNS_DB_NONSEC3, &dbiter);
1657
0
  if (result != ISC_R_SUCCESS) {
1658
0
    zoneverify_log_error(vctx, "dns_db_createiterator(): %s",
1659
0
             isc_result_totext(result));
1660
0
    goto done;
1661
0
  }
1662
1663
0
  result = dns_dbiterator_first(dbiter);
1664
0
  if (result != ISC_R_SUCCESS) {
1665
0
    zoneverify_log_error(vctx, "dns_dbiterator_first(): %s",
1666
0
             isc_result_totext(result));
1667
0
    goto done;
1668
0
  }
1669
1670
0
  while (!done) {
1671
0
    bool isdelegation = false;
1672
1673
0
    result = dns_dbiterator_current(dbiter, &node, name);
1674
0
    if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
1675
0
      zoneverify_log_error(vctx,
1676
0
               "dns_dbiterator_current(): %s",
1677
0
               isc_result_totext(result));
1678
0
      goto done;
1679
0
    }
1680
0
    if (!dns_name_issubdomain(name, vctx->origin)) {
1681
0
      result = check_no_nsec(vctx, name, node);
1682
0
      if (result != ISC_R_SUCCESS) {
1683
0
        dns_db_detachnode(&node);
1684
0
        goto done;
1685
0
      }
1686
0
      dns_db_detachnode(&node);
1687
0
      result = dns_dbiterator_next(dbiter);
1688
0
      if (result == ISC_R_NOMORE) {
1689
0
        done = true;
1690
0
      } else if (result != ISC_R_SUCCESS) {
1691
0
        zoneverify_log_error(vctx,
1692
0
                 "dns_dbiterator_next(): "
1693
0
                 "%s",
1694
0
                 isc_result_totext(result));
1695
0
        goto done;
1696
0
      }
1697
0
      continue;
1698
0
    }
1699
0
    if (is_delegation(vctx, name, node, NULL)) {
1700
0
      zonecut = dns_fixedname_name(&fzonecut);
1701
0
      dns_name_copy(name, zonecut);
1702
0
      isdelegation = true;
1703
0
    } else if (has_dname(vctx, node)) {
1704
0
      zonecut = dns_fixedname_name(&fzonecut);
1705
0
      dns_name_copy(name, zonecut);
1706
0
    }
1707
0
    nextnode = NULL;
1708
0
    result = dns_dbiterator_next(dbiter);
1709
0
    while (result == ISC_R_SUCCESS) {
1710
0
      result = dns_dbiterator_current(dbiter, &nextnode,
1711
0
              nextname);
1712
0
      if (result != ISC_R_SUCCESS &&
1713
0
          result != DNS_R_NEWORIGIN)
1714
0
      {
1715
0
        zoneverify_log_error(vctx,
1716
0
                 "dns_dbiterator_current():"
1717
0
                 " %s",
1718
0
                 isc_result_totext(result));
1719
0
        dns_db_detachnode(&node);
1720
0
        goto done;
1721
0
      }
1722
0
      if (!dns_name_issubdomain(nextname, vctx->origin) ||
1723
0
          (zonecut != NULL &&
1724
0
           dns_name_issubdomain(nextname, zonecut)))
1725
0
      {
1726
0
        result = check_no_nsec(vctx, nextname,
1727
0
                   nextnode);
1728
0
        if (result != ISC_R_SUCCESS) {
1729
0
          dns_db_detachnode(&node);
1730
0
          dns_db_detachnode(&nextnode);
1731
0
          goto done;
1732
0
        }
1733
0
        dns_db_detachnode(&nextnode);
1734
0
        result = dns_dbiterator_next(dbiter);
1735
0
        continue;
1736
0
      }
1737
0
      result = is_empty(vctx, nextnode);
1738
0
      dns_db_detachnode(&nextnode);
1739
0
      switch (result) {
1740
0
      case ISC_R_SUCCESS:
1741
0
        break;
1742
0
      case ISC_R_NOMORE:
1743
0
        result = dns_dbiterator_next(dbiter);
1744
0
        continue;
1745
0
      default:
1746
0
        dns_db_detachnode(&node);
1747
0
      }
1748
0
      break;
1749
0
    }
1750
0
    if (result == ISC_R_NOMORE) {
1751
0
      done = true;
1752
0
      nextname = vctx->origin;
1753
0
    } else if (result != ISC_R_SUCCESS) {
1754
0
      zoneverify_log_error(vctx,
1755
0
               "iterating through the database "
1756
0
               "failed: %s",
1757
0
               isc_result_totext(result));
1758
0
      dns_db_detachnode(&node);
1759
0
      goto done;
1760
0
    }
1761
0
    result = verifynode(vctx, name, node, isdelegation, dstkeys,
1762
0
            nkeys, &vctx->nsecset, &vctx->nsec3paramset,
1763
0
            nextname, &tvresult);
1764
0
    if (result != ISC_R_SUCCESS) {
1765
0
      dns_db_detachnode(&node);
1766
0
      goto done;
1767
0
    }
1768
0
    if (*vresult == ISC_R_UNSET) {
1769
0
      *vresult = ISC_R_SUCCESS;
1770
0
    }
1771
0
    if (*vresult == ISC_R_SUCCESS) {
1772
0
      *vresult = tvresult;
1773
0
    }
1774
0
    if (prevname != NULL) {
1775
0
      result = verifyemptynodes(
1776
0
        vctx, name, prevname, isdelegation,
1777
0
        &vctx->nsec3paramset, &tvresult);
1778
0
      if (result != ISC_R_SUCCESS) {
1779
0
        dns_db_detachnode(&node);
1780
0
        goto done;
1781
0
      }
1782
0
    } else {
1783
0
      prevname = dns_fixedname_name(&fprevname);
1784
0
    }
1785
0
    dns_name_copy(name, prevname);
1786
0
    if (*vresult == ISC_R_SUCCESS) {
1787
0
      *vresult = tvresult;
1788
0
    }
1789
0
    dns_db_detachnode(&node);
1790
0
  }
1791
1792
0
  dns_dbiterator_destroy(&dbiter);
1793
1794
0
  result = dns_db_createiterator(vctx->db, DNS_DB_NSEC3ONLY, &dbiter);
1795
0
  if (result != ISC_R_SUCCESS) {
1796
0
    zoneverify_log_error(vctx, "dns_db_createiterator(): %s",
1797
0
             isc_result_totext(result));
1798
0
    return result;
1799
0
  }
1800
1801
0
  DNS_DBITERATOR_FOREACH(dbiter) {
1802
0
    result = dns_dbiterator_current(dbiter, &node, name);
1803
0
    if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
1804
0
      zoneverify_log_error(vctx,
1805
0
               "dns_dbiterator_current(): %s",
1806
0
               isc_result_totext(result));
1807
0
      goto done;
1808
0
    }
1809
0
    result = verifynode(vctx, name, node, false, dstkeys, nkeys,
1810
0
            NULL, NULL, NULL, NULL);
1811
0
    if (result != ISC_R_SUCCESS) {
1812
0
      zoneverify_log_error(vctx, "verifynode: %s",
1813
0
               isc_result_totext(result));
1814
0
      dns_db_detachnode(&node);
1815
0
      goto done;
1816
0
    }
1817
0
    result = record_found(vctx, name, node, &vctx->nsec3paramset);
1818
0
    dns_db_detachnode(&node);
1819
0
    if (result != ISC_R_SUCCESS) {
1820
0
      goto done;
1821
0
    }
1822
0
  }
1823
1824
0
  result = ISC_R_SUCCESS;
1825
1826
0
done:
1827
0
  while (nkeys-- > 0U) {
1828
0
    dst_key_free(&dstkeys[nkeys]);
1829
0
  }
1830
0
  isc_mem_cput(vctx->mctx, dstkeys, count, sizeof(*dstkeys));
1831
0
  if (dbiter != NULL) {
1832
0
    dns_dbiterator_destroy(&dbiter);
1833
0
  }
1834
1835
0
  return result;
1836
0
}
1837
1838
static isc_result_t
1839
0
check_bad_algorithms(const vctx_t *vctx, void (*report)(const char *, ...)) {
1840
0
  char algbuf[DNS_SECALG_FORMATSIZE];
1841
0
  bool first = true;
1842
1843
0
  for (size_t i = 0; i < ARRAY_SIZE(vctx->bad_algorithms); i++) {
1844
0
    if (vctx->bad_algorithms[i] == 0) {
1845
0
      continue;
1846
0
    }
1847
0
    if (first) {
1848
0
      report("The zone is not fully signed "
1849
0
             "for the following algorithms:");
1850
0
    }
1851
0
    dst_algorithm_format(i, algbuf, sizeof(algbuf));
1852
0
    report(" %s", algbuf);
1853
0
    first = false;
1854
0
  }
1855
1856
0
  if (!first) {
1857
0
    report(".");
1858
0
  }
1859
1860
0
  return first ? ISC_R_SUCCESS : ISC_R_FAILURE;
1861
0
}
1862
1863
static void
1864
print_summary(const vctx_t *vctx, bool keyset_kskonly,
1865
0
        void (*report)(const char *, ...)) {
1866
0
  char algbuf[DNS_SECALG_FORMATSIZE];
1867
1868
0
  report("Zone fully signed:");
1869
0
  for (size_t i = 0; i < ARRAY_SIZE(vctx->ksk_algorithms); i++) {
1870
0
    if ((vctx->ksk_algorithms[i] == 0) &&
1871
0
        (vctx->standby_ksk[i] == 0) &&
1872
0
        (vctx->revoked_ksk[i] == 0) &&
1873
0
        (vctx->zsk_algorithms[i] == 0) &&
1874
0
        (vctx->standby_zsk[i] == 0) && (vctx->revoked_zsk[i] == 0))
1875
0
    {
1876
0
      continue;
1877
0
    }
1878
0
    dst_algorithm_format(i, algbuf, sizeof(algbuf));
1879
0
    report("Algorithm: %s: KSKs: "
1880
0
           "%u active, %u stand-by, %u revoked",
1881
0
           algbuf, vctx->ksk_algorithms[i], vctx->standby_ksk[i],
1882
0
           vctx->revoked_ksk[i]);
1883
0
    report("%*sZSKs: "
1884
0
           "%u active, %u %s, %u revoked",
1885
0
           (int)strlen(algbuf) + 13, "", vctx->zsk_algorithms[i],
1886
0
           vctx->standby_zsk[i],
1887
0
           keyset_kskonly ? "present" : "stand-by",
1888
0
           vctx->revoked_zsk[i]);
1889
0
  }
1890
0
}
1891
1892
isc_result_t
1893
dns_zoneverify_dnssec(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
1894
          dns_name_t *origin, dns_keytable_t *secroots,
1895
          isc_mem_t *mctx, bool ignore_kskflag, bool keyset_kskonly,
1896
0
          void (*report)(const char *, ...)) {
1897
0
  const char *keydesc = (secroots == NULL ? "self-signed" : "trusted");
1898
0
  isc_result_t result, vresult = ISC_R_UNSET;
1899
0
  vctx_t vctx;
1900
1901
0
  vctx_init(&vctx, mctx, zone, db, ver, origin, secroots);
1902
1903
0
  result = check_apex_rrsets(&vctx);
1904
0
  if (result != ISC_R_SUCCESS) {
1905
0
    goto done;
1906
0
  }
1907
1908
0
  result = check_dnskey(&vctx);
1909
0
  if (result != ISC_R_SUCCESS) {
1910
0
    goto done;
1911
0
  }
1912
1913
0
  if (ignore_kskflag) {
1914
0
    if (!vctx.goodksk && !vctx.goodzsk) {
1915
0
      zoneverify_log_error(&vctx, "No %s DNSKEY found",
1916
0
               keydesc);
1917
0
      result = ISC_R_FAILURE;
1918
0
      goto done;
1919
0
    }
1920
0
  } else if (!vctx.goodksk) {
1921
0
    zoneverify_log_error(&vctx, "No %s KSK DNSKEY found", keydesc);
1922
0
    result = ISC_R_FAILURE;
1923
0
    goto done;
1924
0
  }
1925
1926
0
  determine_active_algorithms(&vctx, ignore_kskflag, keyset_kskonly,
1927
0
            report);
1928
1929
0
  result = verify_nodes(&vctx, &vresult);
1930
0
  if (result != ISC_R_SUCCESS) {
1931
0
    goto done;
1932
0
  }
1933
1934
0
  result = verify_nsec3_chains(&vctx, mctx);
1935
0
  if (vresult == ISC_R_UNSET) {
1936
0
    vresult = ISC_R_SUCCESS;
1937
0
  }
1938
0
  if (result != ISC_R_SUCCESS && vresult == ISC_R_SUCCESS) {
1939
0
    vresult = result;
1940
0
  }
1941
1942
0
  result = check_bad_algorithms(&vctx, report);
1943
0
  if (result != ISC_R_SUCCESS) {
1944
0
    report("DNSSEC completeness test failed.");
1945
0
    goto done;
1946
0
  }
1947
1948
0
  result = vresult;
1949
0
  if (result != ISC_R_SUCCESS) {
1950
0
    report("DNSSEC completeness test failed (%s).",
1951
0
           isc_result_totext(result));
1952
0
    goto done;
1953
0
  }
1954
1955
0
  if (vctx.goodksk || ignore_kskflag) {
1956
0
    print_summary(&vctx, keyset_kskonly, report);
1957
0
  }
1958
1959
0
done:
1960
0
  vctx_destroy(&vctx);
1961
1962
0
  return result;
1963
0
}