Coverage Report

Created: 2026-08-13 07:06

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