Coverage Report

Created: 2025-12-12 06:30

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