Coverage Report

Created: 2025-11-09 06:44

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