Coverage Report

Created: 2026-08-31 07:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/dns/dnssec.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 <ctype.h>
17
#include <inttypes.h>
18
#include <stdbool.h>
19
#include <stdlib.h>
20
21
#include <isc/buffer.h>
22
#include <isc/dir.h>
23
#include <isc/log.h>
24
#include <isc/mem.h>
25
#include <isc/result.h>
26
#include <isc/serial.h>
27
#include <isc/string.h>
28
#include <isc/util.h>
29
30
#include <dns/db.h>
31
#include <dns/diff.h>
32
#include <dns/dnssec.h>
33
#include <dns/fixedname.h>
34
#include <dns/kasp.h>
35
#include <dns/keyvalues.h>
36
#include <dns/rdata.h>
37
#include <dns/rdatalist.h>
38
#include <dns/rdatastruct.h>
39
#include <dns/stats.h>
40
#include <dns/tsig.h> /* for DNS_TSIG_FUDGE */
41
42
isc_stats_t *dns_dnssec_stats;
43
44
113
#define is_response(msg) ((msg->flags & DNS_MESSAGEFLAG_QR) != 0)
45
46
#define TYPE_SIGN   0
47
#define TYPE_VERIFY 1
48
49
static isc_result_t
50
digest_callback(void *arg, isc_region_t *data);
51
52
static int
53
rdata_compare_wrapper(const void *rdata1, const void *rdata2);
54
55
static isc_result_t
56
rdataset_to_sortedarray(dns_rdataset_t *set, isc_mem_t *mctx,
57
      dns_rdata_t **rdata, int *nrdata);
58
59
static isc_result_t
60
0
digest_callback(void *arg, isc_region_t *data) {
61
0
  dst_context_t *ctx = arg;
62
63
0
  return dst_context_adddata(ctx, data);
64
0
}
65
66
static void
67
0
inc_stat(isc_statscounter_t counter) {
68
0
  if (dns_dnssec_stats != NULL) {
69
0
    isc_stats_increment(dns_dnssec_stats, counter);
70
0
  }
71
0
}
72
73
/*
74
 * Make qsort happy.
75
 */
76
static int
77
0
rdata_compare_wrapper(const void *rdata1, const void *rdata2) {
78
0
  return dns_rdata_compare((const dns_rdata_t *)rdata1,
79
0
         (const dns_rdata_t *)rdata2);
80
0
}
81
82
/*
83
 * Sort the rdataset into an array.
84
 */
85
static isc_result_t
86
rdataset_to_sortedarray(dns_rdataset_t *set, isc_mem_t *mctx,
87
0
      dns_rdata_t **rdata, int *nrdata) {
88
0
  isc_result_t result;
89
0
  int i = 0, n;
90
0
  dns_rdata_t *data;
91
0
  dns_rdataset_t rdataset;
92
93
0
  n = dns_rdataset_count(set);
94
95
0
  data = isc_mem_cget(mctx, n, sizeof(dns_rdata_t));
96
97
0
  dns_rdataset_init(&rdataset);
98
0
  dns_rdataset_clone(set, &rdataset);
99
0
  result = dns_rdataset_first(&rdataset);
100
0
  if (result != ISC_R_SUCCESS) {
101
0
    dns_rdataset_disassociate(&rdataset);
102
0
    isc_mem_cput(mctx, data, n, sizeof(dns_rdata_t));
103
0
    return result;
104
0
  }
105
106
  /*
107
   * Put them in the array.
108
   */
109
0
  do {
110
0
    dns_rdata_init(&data[i]);
111
0
    dns_rdataset_current(&rdataset, &data[i++]);
112
0
  } while (dns_rdataset_next(&rdataset) == ISC_R_SUCCESS);
113
114
  /*
115
   * Sort the array.
116
   */
117
0
  qsort(data, n, sizeof(dns_rdata_t), rdata_compare_wrapper);
118
0
  *rdata = data;
119
0
  *nrdata = n;
120
0
  dns_rdataset_disassociate(&rdataset);
121
0
  return ISC_R_SUCCESS;
122
0
}
123
124
isc_result_t
125
dns_dnssec_keyfromrdata(const dns_name_t *name, const dns_rdata_t *rdata,
126
97
      isc_mem_t *mctx, dst_key_t **key) {
127
97
  isc_buffer_t b;
128
97
  isc_region_t r;
129
130
97
  INSIST(DNS_NAME_VALID(name));
131
97
  INSIST(rdata != NULL);
132
97
  INSIST(mctx != NULL);
133
97
  INSIST(key != NULL);
134
97
  INSIST(*key == NULL);
135
97
  REQUIRE(rdata->type == dns_rdatatype_key ||
136
97
    rdata->type == dns_rdatatype_dnskey);
137
138
97
  dns_rdata_toregion(rdata, &r);
139
97
  isc_buffer_init(&b, r.base, r.length);
140
97
  isc_buffer_add(&b, r.length);
141
97
  return dst_key_fromdns(name, rdata->rdclass, &b, mctx, key);
142
97
}
143
144
static isc_result_t
145
digest_sig(dst_context_t *ctx, bool downcase, dns_rdata_t *sigrdata,
146
0
     dns_rdata_rrsig_t *rrsig) {
147
0
  isc_region_t r;
148
0
  dns_fixedname_t fname;
149
150
0
  dns_rdata_toregion(sigrdata, &r);
151
0
  INSIST(r.length >= 19);
152
153
0
  r.length = 18;
154
0
  RETERR(dst_context_adddata(ctx, &r));
155
0
  if (downcase) {
156
0
    dns_fixedname_init(&fname);
157
158
0
    RUNTIME_CHECK(dns_name_downcase(&rrsig->signer,
159
0
            dns_fixedname_name(&fname)) ==
160
0
            ISC_R_SUCCESS);
161
0
    dns_name_toregion(dns_fixedname_name(&fname), &r);
162
0
  } else {
163
0
    dns_name_toregion(&rrsig->signer, &r);
164
0
  }
165
166
0
  return dst_context_adddata(ctx, &r);
167
0
}
168
169
isc_result_t
170
dns_dnssec_sign(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
171
    isc_stdtime_t *inception, isc_stdtime_t *expire,
172
0
    isc_mem_t *mctx, isc_buffer_t *buffer, dns_rdata_t *sigrdata) {
173
0
  dns_rdata_rrsig_t sig;
174
0
  dns_rdata_t tmpsigrdata;
175
0
  dns_rdata_t *rdatas;
176
0
  int nrdatas, i;
177
0
  isc_buffer_t sigbuf, envbuf;
178
0
  isc_region_t r;
179
0
  dst_context_t *ctx = NULL;
180
0
  isc_result_t result;
181
0
  isc_buffer_t *databuf = NULL;
182
0
  char data[256 + 8];
183
0
  unsigned int labels;
184
0
  unsigned int sigsize;
185
0
  dns_fixedname_t fnewname;
186
0
  dns_fixedname_t fsigner;
187
188
0
  REQUIRE(DNS_NAME_VALID(name));
189
0
  labels = dns_name_countlabels(name);
190
0
  REQUIRE(labels <= 255 && labels > 0);
191
0
  REQUIRE(set != NULL);
192
0
  REQUIRE(key != NULL);
193
0
  REQUIRE(inception != NULL);
194
0
  REQUIRE(expire != NULL);
195
0
  REQUIRE(mctx != NULL);
196
0
  REQUIRE(sigrdata != NULL);
197
198
0
  if (*inception >= *expire) {
199
0
    return DNS_R_INVALIDTIME;
200
0
  }
201
202
0
  sig.mctx = mctx;
203
0
  sig.common.rdclass = set->rdclass;
204
0
  sig.common.rdtype = dns_rdatatype_rrsig;
205
206
  /*
207
   * Downcase signer.
208
   */
209
0
  dns_name_init(&sig.signer);
210
0
  dns_fixedname_init(&fsigner);
211
0
  RUNTIME_CHECK(dns_name_downcase(dst_key_name(key),
212
0
          dns_fixedname_name(&fsigner)) ==
213
0
          ISC_R_SUCCESS);
214
0
  dns_name_clone(dns_fixedname_name(&fsigner), &sig.signer);
215
216
0
  sig.covered = set->type;
217
0
  sig.algorithm = dst_algorithm_tosecalg(dst_key_alg(key));
218
0
  sig.labels = labels - 1;
219
0
  if (dns_name_iswildcard(name)) {
220
0
    sig.labels--;
221
0
  }
222
0
  sig.originalttl = set->ttl;
223
0
  sig.timesigned = *inception;
224
0
  sig.timeexpire = *expire;
225
0
  sig.keyid = dst_key_id(key);
226
0
  RETERR(dst_key_sigsize(key, &sigsize));
227
0
  sig.siglen = sigsize;
228
  /*
229
   * The actual contents of sig.signature are not important yet, since
230
   * they're not used in digest_sig().
231
   */
232
0
  sig.signature = isc_mem_get(mctx, sig.siglen);
233
234
0
  isc_buffer_allocate(mctx, &databuf, sigsize + 256 + 18);
235
236
0
  dns_rdata_init(&tmpsigrdata);
237
0
  result = dns_rdata_fromstruct(&tmpsigrdata, sig.common.rdclass,
238
0
              sig.common.rdtype, &sig, databuf);
239
0
  if (result != ISC_R_SUCCESS) {
240
0
    goto cleanup_databuf;
241
0
  }
242
243
0
  result = dst_context_create(key, mctx, DNS_LOGCATEGORY_DNSSEC, true,
244
0
            &ctx);
245
0
  if (result != ISC_R_SUCCESS) {
246
0
    goto cleanup_databuf;
247
0
  }
248
249
  /*
250
   * Digest the SIG rdata.
251
   */
252
0
  result = digest_sig(ctx, false, &tmpsigrdata, &sig);
253
0
  if (result != ISC_R_SUCCESS) {
254
0
    goto cleanup_context;
255
0
  }
256
257
0
  dns_fixedname_init(&fnewname);
258
0
  RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname)) ==
259
0
          ISC_R_SUCCESS);
260
0
  dns_name_toregion(dns_fixedname_name(&fnewname), &r);
261
262
  /*
263
   * Create an envelope for each rdata: <name|type|class|ttl>.
264
   */
265
0
  isc_buffer_init(&envbuf, data, sizeof(data));
266
0
  memmove(data, r.base, r.length);
267
0
  isc_buffer_add(&envbuf, r.length);
268
0
  isc_buffer_putuint16(&envbuf, set->type);
269
0
  isc_buffer_putuint16(&envbuf, set->rdclass);
270
0
  isc_buffer_putuint32(&envbuf, set->ttl);
271
272
0
  result = rdataset_to_sortedarray(set, mctx, &rdatas, &nrdatas);
273
0
  if (result != ISC_R_SUCCESS) {
274
0
    goto cleanup_context;
275
0
  }
276
0
  isc_buffer_usedregion(&envbuf, &r);
277
278
0
  for (i = 0; i < nrdatas; i++) {
279
0
    uint16_t len;
280
0
    isc_buffer_t lenbuf;
281
0
    isc_region_t lenr;
282
283
    /*
284
     * Skip duplicates.
285
     */
286
0
    if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i - 1]) == 0)
287
0
    {
288
0
      continue;
289
0
    }
290
291
    /*
292
     * Digest the envelope.
293
     */
294
0
    result = dst_context_adddata(ctx, &r);
295
0
    if (result != ISC_R_SUCCESS) {
296
0
      goto cleanup_array;
297
0
    }
298
299
    /*
300
     * Digest the length of the rdata.
301
     */
302
0
    isc_buffer_init(&lenbuf, &len, sizeof(len));
303
0
    isc_buffer_putuint16(&lenbuf, (uint16_t)rdatas[i].length);
304
0
    isc_buffer_usedregion(&lenbuf, &lenr);
305
0
    result = dst_context_adddata(ctx, &lenr);
306
0
    if (result != ISC_R_SUCCESS) {
307
0
      goto cleanup_array;
308
0
    }
309
310
    /*
311
     * Digest the rdata.
312
     */
313
0
    result = dns_rdata_digest(&rdatas[i], digest_callback, ctx);
314
0
    if (result != ISC_R_SUCCESS) {
315
0
      goto cleanup_array;
316
0
    }
317
0
  }
318
319
0
  isc_buffer_init(&sigbuf, sig.signature, sig.siglen);
320
0
  result = dst_context_sign(ctx, &sigbuf);
321
0
  if (result != ISC_R_SUCCESS) {
322
0
    goto cleanup_array;
323
0
  }
324
0
  isc_buffer_usedregion(&sigbuf, &r);
325
0
  if (r.length != sig.siglen) {
326
0
    result = ISC_R_NOSPACE;
327
0
    goto cleanup_array;
328
0
  }
329
330
0
  result = dns_rdata_fromstruct(sigrdata, sig.common.rdclass,
331
0
              sig.common.rdtype, &sig, buffer);
332
333
0
cleanup_array:
334
0
  isc_mem_cput(mctx, rdatas, nrdatas, sizeof(dns_rdata_t));
335
0
cleanup_context:
336
0
  dst_context_destroy(&ctx);
337
0
cleanup_databuf:
338
0
  isc_buffer_free(&databuf);
339
0
  isc_mem_put(mctx, sig.signature, sig.siglen);
340
341
0
  return result;
342
0
}
343
344
isc_result_t
345
dns_dnssec_verify(const dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
346
      bool ignoretime, isc_mem_t *mctx, dns_rdata_t *sigrdata,
347
0
      dns_name_t *wild, dns_name_t *wildsigner) {
348
0
  dns_rdata_nsec_t nsec;
349
0
  dns_rdata_rrsig_t sig;
350
0
  dns_fixedname_t fnewname;
351
0
  dns_rdata_t rdata = DNS_RDATA_INIT;
352
0
  isc_region_t r;
353
0
  isc_buffer_t envbuf;
354
0
  dns_rdata_t *rdatas;
355
0
  int nrdatas, i;
356
0
  isc_stdtime_t now;
357
0
  isc_result_t result;
358
0
  unsigned char data[300];
359
0
  dst_context_t *ctx = NULL;
360
0
  unsigned int labels;
361
0
  unsigned int siglabels;
362
0
  bool downcase = false;
363
364
0
  REQUIRE(DNS_NAME_VALID(name));
365
0
  labels = dns_name_countlabels(name);
366
0
  REQUIRE(labels > 0);
367
0
  REQUIRE(set != NULL);
368
0
  REQUIRE(key != NULL);
369
0
  REQUIRE(mctx != NULL);
370
0
  REQUIRE(sigrdata != NULL && sigrdata->type == dns_rdatatype_rrsig);
371
372
0
  RETERR(dns_rdata_tostruct(sigrdata, &sig, NULL));
373
374
0
  if (set->type != sig.covered) {
375
0
    return DNS_R_SIGINVALID;
376
0
  }
377
378
  /*
379
   * The RRSIG labels field can't indicate fewer labels than the
380
   * signer.  Also the labels shouldn't be greater than that of
381
   * the owner name.
382
   *
383
   * sig.labels doesn't include the root label, so add 1 to account
384
   * for it.
385
   */
386
0
  siglabels = sig.labels + 1;
387
0
  if (siglabels < dns_name_countlabels(&sig.signer) || siglabels > labels)
388
0
  {
389
0
    inc_stat(dns_dnssecstats_fail);
390
0
    return DNS_R_SIGINVALID;
391
0
  }
392
393
0
  if (isc_serial_lt(sig.timeexpire, sig.timesigned)) {
394
0
    inc_stat(dns_dnssecstats_fail);
395
0
    return DNS_R_SIGINVALID;
396
0
  }
397
398
0
  if (!ignoretime) {
399
0
    now = isc_stdtime_now();
400
401
    /*
402
     * Is SIG temporally valid?
403
     */
404
0
    if (isc_serial_lt((uint32_t)now, sig.timesigned)) {
405
0
      inc_stat(dns_dnssecstats_fail);
406
0
      return DNS_R_SIGFUTURE;
407
0
    } else if (isc_serial_lt(sig.timeexpire, (uint32_t)now)) {
408
0
      inc_stat(dns_dnssecstats_fail);
409
0
      return DNS_R_SIGEXPIRED;
410
0
    }
411
0
  }
412
413
  /*
414
   * NS, SOA and DNSKEY records are signed by their owners.
415
   * NSEC3 records are signed by the apex, exactly one level up
416
   * from their owner names.
417
   * DS records are signed by the parent zone.
418
   */
419
0
  switch (set->type) {
420
0
  case dns_rdatatype_nsec3: {
421
0
    dns_name_t apex = DNS_NAME_INITEMPTY;
422
0
    labels = dns_name_countlabels(name);
423
0
    if (labels <= 1) {
424
0
      inc_stat(dns_dnssecstats_fail);
425
0
      return DNS_R_INVALIDNSEC3;
426
0
    }
427
0
    dns_name_split(name, labels - 1, NULL, &apex);
428
0
    if (!dns_name_equal(&apex, &sig.signer)) {
429
0
      inc_stat(dns_dnssecstats_fail);
430
0
      return DNS_R_SIGINVALID;
431
0
    }
432
0
  } break;
433
0
  case dns_rdatatype_ns:
434
0
  case dns_rdatatype_soa:
435
0
  case dns_rdatatype_dnskey:
436
0
    if (!dns_name_equal(name, &sig.signer)) {
437
0
      inc_stat(dns_dnssecstats_fail);
438
0
      return DNS_R_SIGINVALID;
439
0
    }
440
0
    break;
441
0
  case dns_rdatatype_ds:
442
0
    if (dns_name_equal(name, &sig.signer)) {
443
0
      inc_stat(dns_dnssecstats_fail);
444
0
      return DNS_R_SIGINVALID;
445
0
    }
446
0
    FALLTHROUGH;
447
0
  default:
448
0
    if (!dns_name_issubdomain(name, &sig.signer)) {
449
0
      inc_stat(dns_dnssecstats_fail);
450
0
      return DNS_R_SIGINVALID;
451
0
    }
452
0
    break;
453
0
  }
454
  /*
455
   * Check for out of zone NSEC entries.
456
   */
457
0
  if (set->type == dns_rdatatype_nsec) {
458
0
    RETERR(dns_rdataset_first(set));
459
0
    dns_rdataset_current(set, &rdata);
460
0
    RETERR(dns_rdata_tostruct(&rdata, &nsec, NULL));
461
0
    if (!dns_name_issubdomain(&nsec.next, &sig.signer)) {
462
0
      return DNS_R_NOVALIDNSEC;
463
0
    }
464
0
  }
465
466
0
again:
467
0
  result = dst_context_create(key, mctx, DNS_LOGCATEGORY_DNSSEC, false,
468
0
            &ctx);
469
0
  if (result != ISC_R_SUCCESS) {
470
0
    goto cleanup_struct;
471
0
  }
472
473
  /*
474
   * Digest the SIG rdata (not including the signature).
475
   */
476
0
  result = digest_sig(ctx, downcase, sigrdata, &sig);
477
0
  if (result != ISC_R_SUCCESS) {
478
0
    goto cleanup_context;
479
0
  }
480
481
  /*
482
   * If the name is an expanded wildcard, use the wildcard name.
483
   */
484
0
  dns_fixedname_init(&fnewname);
485
0
  RUNTIME_CHECK(dns_name_downcase(name, dns_fixedname_name(&fnewname)) ==
486
0
          ISC_R_SUCCESS);
487
0
  if (labels > siglabels) {
488
0
    dns_name_split(dns_fixedname_name(&fnewname), siglabels, NULL,
489
0
             dns_fixedname_name(&fnewname));
490
0
  }
491
492
0
  dns_name_toregion(dns_fixedname_name(&fnewname), &r);
493
494
  /*
495
   * Create an envelope for each rdata: <name|type|class|ttl>.
496
   */
497
0
  isc_buffer_init(&envbuf, data, sizeof(data));
498
0
  if (labels > siglabels) {
499
0
    isc_buffer_putuint8(&envbuf, 1);
500
0
    isc_buffer_putuint8(&envbuf, '*');
501
0
    memmove(data + 2, r.base, r.length);
502
0
  } else {
503
0
    memmove(data, r.base, r.length);
504
0
  }
505
0
  isc_buffer_add(&envbuf, r.length);
506
0
  isc_buffer_putuint16(&envbuf, set->type);
507
0
  isc_buffer_putuint16(&envbuf, set->rdclass);
508
0
  isc_buffer_putuint32(&envbuf, sig.originalttl);
509
510
0
  result = rdataset_to_sortedarray(set, mctx, &rdatas, &nrdatas);
511
0
  if (result != ISC_R_SUCCESS) {
512
0
    goto cleanup_context;
513
0
  }
514
515
0
  isc_buffer_usedregion(&envbuf, &r);
516
517
0
  for (i = 0; i < nrdatas; i++) {
518
0
    uint16_t len;
519
0
    isc_buffer_t lenbuf;
520
0
    isc_region_t lenr;
521
522
    /*
523
     * Skip duplicates.
524
     */
525
0
    if (i > 0 && dns_rdata_compare(&rdatas[i], &rdatas[i - 1]) == 0)
526
0
    {
527
0
      continue;
528
0
    }
529
530
    /*
531
     * Digest the envelope.
532
     */
533
0
    result = dst_context_adddata(ctx, &r);
534
0
    if (result != ISC_R_SUCCESS) {
535
0
      goto cleanup_array;
536
0
    }
537
538
    /*
539
     * Digest the rdata length.
540
     */
541
0
    isc_buffer_init(&lenbuf, &len, sizeof(len));
542
0
    isc_buffer_putuint16(&lenbuf, (uint16_t)rdatas[i].length);
543
0
    isc_buffer_usedregion(&lenbuf, &lenr);
544
545
    /*
546
     * Digest the rdata.
547
     */
548
0
    result = dst_context_adddata(ctx, &lenr);
549
0
    if (result != ISC_R_SUCCESS) {
550
0
      goto cleanup_array;
551
0
    }
552
0
    result = dns_rdata_digest(&rdatas[i], digest_callback, ctx);
553
0
    if (result != ISC_R_SUCCESS) {
554
0
      goto cleanup_array;
555
0
    }
556
0
  }
557
558
0
  r.base = sig.signature;
559
0
  r.length = sig.siglen;
560
0
  result = dst_context_verify(ctx, &r);
561
0
  if (result == ISC_R_SUCCESS && downcase) {
562
0
    char namebuf[DNS_NAME_FORMATSIZE];
563
0
    dns_name_format(&sig.signer, namebuf, sizeof(namebuf));
564
0
    isc_log_write(DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_DNSSEC,
565
0
            ISC_LOG_DEBUG(1),
566
0
            "successfully validated after lower casing "
567
0
            "signer '%s'",
568
0
            namebuf);
569
0
    inc_stat(dns_dnssecstats_downcase);
570
0
  } else if (result == ISC_R_SUCCESS) {
571
0
    inc_stat(dns_dnssecstats_asis);
572
0
  }
573
574
0
cleanup_array:
575
0
  isc_mem_cput(mctx, rdatas, nrdatas, sizeof(dns_rdata_t));
576
0
cleanup_context:
577
0
  dst_context_destroy(&ctx);
578
0
  if (result == DST_R_VERIFYFAILURE && !downcase) {
579
0
    downcase = true;
580
0
    goto again;
581
0
  }
582
0
cleanup_struct:
583
0
  dns_rdata_freestruct(&sig);
584
585
0
  if (result == DST_R_VERIFYFAILURE) {
586
0
    result = DNS_R_SIGINVALID;
587
0
  }
588
589
0
  if (result != ISC_R_SUCCESS) {
590
0
    inc_stat(dns_dnssecstats_fail);
591
0
  }
592
593
0
  if (result == ISC_R_SUCCESS && labels > siglabels) {
594
0
    if (wild != NULL) {
595
0
      RUNTIME_CHECK(dns_name_concatenate(
596
0
                dns_wildcardname,
597
0
                dns_fixedname_name(&fnewname),
598
0
                wild) == ISC_R_SUCCESS);
599
0
    }
600
0
    if (wildsigner != NULL) {
601
0
      dns_name_copy(&sig.signer, wildsigner);
602
0
    }
603
0
    inc_stat(dns_dnssecstats_wildcard);
604
0
    result = DNS_R_FROMWILDCARD;
605
0
  }
606
0
  return result;
607
0
}
608
609
bool
610
0
dns_dnssec_keyactive(dst_key_t *key, isc_stdtime_t now) {
611
0
  isc_result_t result;
612
0
  isc_stdtime_t publish, active, revoke, remove;
613
0
  bool hint_publish, hint_zsign, hint_ksign, hint_revoke, hint_remove;
614
0
  int major, minor;
615
0
  bool ksk = false, zsk = false;
616
617
  /* Is this an old-style key? */
618
0
  result = dst_key_getprivateformat(key, &major, &minor);
619
0
  RUNTIME_CHECK(result == ISC_R_SUCCESS);
620
621
  /* Is this a KSK? */
622
0
  result = dst_key_getbool(key, DST_BOOL_KSK, &ksk);
623
0
  if (result != ISC_R_SUCCESS) {
624
0
    ksk = ((dst_key_flags(key) & DNS_KEYFLAG_KSK) != 0);
625
0
  }
626
0
  result = dst_key_getbool(key, DST_BOOL_ZSK, &zsk);
627
0
  if (result != ISC_R_SUCCESS) {
628
0
    zsk = ((dst_key_flags(key) & DNS_KEYFLAG_KSK) == 0);
629
0
  }
630
631
  /*
632
   * Smart signing started with key format 1.3; prior to that, all
633
   * keys are assumed active.
634
   */
635
0
  if (major == 1 && minor <= 2) {
636
0
    return true;
637
0
  }
638
639
0
  hint_publish = dst_key_is_published(key, now, &publish);
640
0
  hint_zsign = dst_key_is_signing(key, DST_BOOL_ZSK, now, &active);
641
0
  hint_ksign = dst_key_is_signing(key, DST_BOOL_KSK, now, &active);
642
0
  hint_revoke = dst_key_is_revoked(key, now, &revoke);
643
0
  hint_remove = dst_key_is_removed(key, now, &remove);
644
645
0
  if (hint_remove) {
646
0
    return false;
647
0
  }
648
0
  if (hint_publish && hint_revoke) {
649
0
    return true;
650
0
  }
651
0
  if (hint_zsign && zsk) {
652
0
    return true;
653
0
  }
654
0
  if (hint_ksign && ksk) {
655
0
    return true;
656
0
  }
657
0
  return false;
658
0
}
659
660
/*%<
661
 * Indicate whether a key is scheduled to have CDS/CDNSKEY records
662
 * published now.
663
 *
664
 * Returns true if.
665
 *  - kasp says the DS record should be published (e.g. the DS state is in
666
 *    RUMOURED or OMNIPRESENT state).
667
 * Or:
668
 *  - SyncPublish is set and in the past, AND
669
 *  - SyncDelete is unset or in the future
670
 */
671
static bool
672
0
syncpublish(dst_key_t *key, isc_stdtime_t now) {
673
0
  isc_result_t result;
674
0
  isc_stdtime_t when;
675
0
  dst_key_state_t state;
676
0
  int major, minor;
677
0
  bool publish;
678
679
  /*
680
   * Is this an old-style key?
681
   */
682
0
  result = dst_key_getprivateformat(key, &major, &minor);
683
0
  RUNTIME_CHECK(result == ISC_R_SUCCESS);
684
685
  /*
686
   * Smart signing started with key format 1.3
687
   */
688
0
  if (major == 1 && minor <= 2) {
689
0
    return false;
690
0
  }
691
692
  /* Check kasp state first. */
693
0
  result = dst_key_getstate(key, DST_KEY_DS, &state);
694
0
  if (result == ISC_R_SUCCESS) {
695
0
    return state == DST_KEY_STATE_RUMOURED ||
696
0
           state == DST_KEY_STATE_OMNIPRESENT;
697
0
  }
698
699
  /* If no kasp state, check timings. */
700
0
  publish = false;
701
0
  result = dst_key_gettime(key, DST_TIME_SYNCPUBLISH, &when);
702
0
  if (result == ISC_R_SUCCESS && when <= now) {
703
0
    publish = true;
704
0
  }
705
0
  result = dst_key_gettime(key, DST_TIME_SYNCDELETE, &when);
706
0
  if (result == ISC_R_SUCCESS && when < now) {
707
0
    publish = false;
708
0
  }
709
0
  return publish;
710
0
}
711
712
/*%<
713
 * Indicate whether a key is scheduled to have CDS/CDNSKEY records
714
 * deleted now.
715
 *
716
 * Returns true if:
717
 *  - kasp says the DS record should be unpublished (e.g. the DS state is in
718
 *    UNRETENTIVE or HIDDEN state).
719
 * Or:
720
 * - SyncDelete is set and in the past.
721
 */
722
static bool
723
0
syncdelete(dst_key_t *key, isc_stdtime_t now) {
724
0
  isc_result_t result;
725
0
  isc_stdtime_t when;
726
0
  dst_key_state_t state;
727
0
  int major, minor;
728
729
  /*
730
   * Is this an old-style key?
731
   */
732
0
  result = dst_key_getprivateformat(key, &major, &minor);
733
0
  RUNTIME_CHECK(result == ISC_R_SUCCESS);
734
735
  /*
736
   * Smart signing started with key format 1.3.
737
   */
738
0
  if (major == 1 && minor <= 2) {
739
0
    return false;
740
0
  }
741
742
  /* Check kasp state first. */
743
0
  result = dst_key_getstate(key, DST_KEY_DS, &state);
744
0
  if (result == ISC_R_SUCCESS) {
745
0
    return state == DST_KEY_STATE_UNRETENTIVE ||
746
0
           state == DST_KEY_STATE_HIDDEN;
747
0
  }
748
749
  /* If no kasp state, check timings. */
750
0
  result = dst_key_gettime(key, DST_TIME_SYNCDELETE, &when);
751
0
  if (result != ISC_R_SUCCESS) {
752
0
    return false;
753
0
  }
754
0
  if (when <= now) {
755
0
    return true;
756
0
  }
757
0
  return false;
758
0
}
759
760
0
#define is_zone_key(key) ((dst_key_flags(key) & DNS_KEYOWNER_ZONE) != 0)
761
762
isc_result_t
763
0
dns_dnssec_signmessage(dns_message_t *msg, dst_key_t *key) {
764
0
  dns_rdata_sig_t sig; /* SIG(0) */
765
0
  unsigned char data[512];
766
0
  unsigned char header[DNS_MESSAGE_HEADERLEN];
767
0
  isc_buffer_t headerbuf, databuf, sigbuf;
768
0
  unsigned int sigsize;
769
0
  isc_buffer_t *dynbuf = NULL;
770
0
  dns_rdata_t *rdata;
771
0
  dns_rdatalist_t *datalist;
772
0
  dns_rdataset_t *dataset;
773
0
  isc_region_t r;
774
0
  isc_stdtime_t now;
775
0
  dst_context_t *ctx = NULL;
776
0
  isc_mem_t *mctx;
777
0
  isc_result_t result;
778
779
0
  REQUIRE(msg != NULL);
780
0
  REQUIRE(key != NULL);
781
782
0
  if (is_response(msg)) {
783
0
    REQUIRE(msg->query.base != NULL);
784
0
  }
785
786
0
  mctx = msg->mctx;
787
788
0
  memset(&sig, 0, sizeof(sig));
789
790
0
  sig.mctx = mctx;
791
0
  sig.common.rdclass = dns_rdataclass_any;
792
0
  sig.common.rdtype = dns_rdatatype_sig; /* SIG(0) */
793
794
0
  sig.covered = 0;
795
0
  sig.algorithm = dst_algorithm_tosecalg(dst_key_alg(key));
796
0
  sig.labels = 0; /* the root name */
797
0
  sig.originalttl = 0;
798
799
0
  if (msg->fuzzing) {
800
0
    now = msg->fuzztime;
801
0
  } else {
802
0
    now = isc_stdtime_now();
803
0
  }
804
0
  sig.timesigned = now - DNS_TSIG_FUDGE;
805
0
  sig.timeexpire = now + DNS_TSIG_FUDGE;
806
807
0
  sig.keyid = dst_key_id(key);
808
809
0
  dns_name_init(&sig.signer);
810
0
  dns_name_clone(dst_key_name(key), &sig.signer);
811
812
0
  sig.siglen = 0;
813
0
  sig.signature = NULL;
814
815
0
  isc_buffer_init(&databuf, data, sizeof(data));
816
817
0
  CHECK(dst_context_create(key, mctx, DNS_LOGCATEGORY_DNSSEC, true,
818
0
         &ctx));
819
820
  /*
821
   * Digest the fields of the SIG - we can cheat and use
822
   * dns_rdata_fromstruct.  Since siglen is 0, the digested data
823
   * is identical to dns format.
824
   */
825
0
  CHECK(dns_rdata_fromstruct(NULL, dns_rdataclass_any,
826
0
           dns_rdatatype_sig /* SIG(0) */, &sig,
827
0
           &databuf));
828
0
  isc_buffer_usedregion(&databuf, &r);
829
0
  CHECK(dst_context_adddata(ctx, &r));
830
831
  /*
832
   * If this is a response, digest the query.
833
   */
834
0
  if (is_response(msg)) {
835
0
    CHECK(dst_context_adddata(ctx, &msg->query));
836
0
  }
837
838
  /*
839
   * Digest the header.
840
   */
841
0
  isc_buffer_init(&headerbuf, header, sizeof(header));
842
0
  dns_message_renderheader(msg, &headerbuf);
843
0
  isc_buffer_usedregion(&headerbuf, &r);
844
0
  CHECK(dst_context_adddata(ctx, &r));
845
846
  /*
847
   * Digest the remainder of the message.
848
   */
849
0
  isc_buffer_usedregion(msg->buffer, &r);
850
0
  isc_region_consume(&r, DNS_MESSAGE_HEADERLEN);
851
0
  CHECK(dst_context_adddata(ctx, &r));
852
853
0
  CHECK(dst_key_sigsize(key, &sigsize));
854
0
  sig.siglen = sigsize;
855
0
  sig.signature = isc_mem_get(mctx, sig.siglen);
856
857
0
  isc_buffer_init(&sigbuf, sig.signature, sig.siglen);
858
0
  CHECK(dst_context_sign(ctx, &sigbuf));
859
0
  dst_context_destroy(&ctx);
860
861
0
  rdata = NULL;
862
0
  dns_message_gettemprdata(msg, &rdata);
863
0
  isc_buffer_allocate(msg->mctx, &dynbuf, 1024);
864
0
  CHECK(dns_rdata_fromstruct(rdata, dns_rdataclass_any,
865
0
           dns_rdatatype_sig /* SIG(0) */, &sig,
866
0
           dynbuf));
867
868
0
  isc_mem_put(mctx, sig.signature, sig.siglen);
869
870
0
  dns_message_takebuffer(msg, &dynbuf);
871
872
0
  datalist = NULL;
873
0
  dns_message_gettemprdatalist(msg, &datalist);
874
0
  datalist->rdclass = dns_rdataclass_any;
875
0
  datalist->type = dns_rdatatype_sig; /* SIG(0) */
876
0
  ISC_LIST_APPEND(datalist->rdata, rdata, link);
877
0
  dataset = NULL;
878
0
  dns_message_gettemprdataset(msg, &dataset);
879
0
  dns_rdatalist_tordataset(datalist, dataset);
880
0
  msg->sig0 = dataset;
881
882
0
  return ISC_R_SUCCESS;
883
884
0
cleanup:
885
0
  if (dynbuf != NULL) {
886
0
    isc_buffer_free(&dynbuf);
887
0
  }
888
0
  if (sig.signature != NULL) {
889
0
    isc_mem_put(mctx, sig.signature, sig.siglen);
890
0
  }
891
0
  if (ctx != NULL) {
892
0
    dst_context_destroy(&ctx);
893
0
  }
894
895
0
  return result;
896
0
}
897
898
isc_result_t
899
dns_dnssec_verifymessage(isc_buffer_t *source, dns_message_t *msg,
900
97
       dst_key_t *key) {
901
97
  dns_rdata_sig_t sig; /* SIG(0) */
902
97
  unsigned char header[DNS_MESSAGE_HEADERLEN];
903
97
  dns_rdata_t rdata = DNS_RDATA_INIT;
904
97
  isc_region_t r, source_r, sig_r, header_r;
905
97
  isc_stdtime_t now;
906
97
  dst_context_t *ctx = NULL;
907
97
  isc_mem_t *mctx;
908
97
  isc_result_t result;
909
97
  uint16_t addcount, addcount_n;
910
97
  bool signeedsfree = false;
911
912
97
  REQUIRE(source != NULL);
913
97
  REQUIRE(msg != NULL);
914
97
  REQUIRE(key != NULL);
915
916
97
  mctx = msg->mctx;
917
918
97
  msg->verify_attempted = 1;
919
97
  msg->verified_sig = 0;
920
97
  msg->sig0status = dns_tsigerror_badsig;
921
922
97
  if (is_response(msg)) {
923
3
    if (msg->query.base == NULL) {
924
3
      return DNS_R_UNEXPECTEDTSIG;
925
3
    }
926
3
  }
927
928
94
  isc_buffer_usedregion(source, &source_r);
929
930
94
  CHECK(dns_rdataset_first(msg->sig0));
931
94
  dns_rdataset_current(msg->sig0, &rdata);
932
933
94
  CHECK(dns_rdata_tostruct(&rdata, &sig, NULL));
934
94
  signeedsfree = true;
935
936
94
  if (sig.labels != 0) {
937
9
    CLEANUP(DNS_R_SIGINVALID);
938
0
  }
939
940
85
  if (isc_serial_lt(sig.timeexpire, sig.timesigned)) {
941
54
    msg->sig0status = dns_tsigerror_badtime;
942
54
    CLEANUP(DNS_R_SIGINVALID);
943
0
  }
944
945
31
  if (msg->fuzzing) {
946
31
    now = msg->fuzztime;
947
31
  } else {
948
0
    now = isc_stdtime_now();
949
0
  }
950
951
31
  if (isc_serial_lt((uint32_t)now, sig.timesigned)) {
952
5
    msg->sig0status = dns_tsigerror_badtime;
953
5
    CLEANUP(DNS_R_SIGFUTURE);
954
26
  } else if (isc_serial_lt(sig.timeexpire, (uint32_t)now)) {
955
10
    msg->sig0status = dns_tsigerror_badtime;
956
10
    CLEANUP(DNS_R_SIGEXPIRED);
957
0
  }
958
959
16
  if (!dns_name_equal(dst_key_name(key), &sig.signer)) {
960
0
    msg->sig0status = dns_tsigerror_badkey;
961
0
    CLEANUP(DNS_R_SIGINVALID);
962
0
  }
963
964
16
  CHECK(dst_context_create(key, mctx, DNS_LOGCATEGORY_DNSSEC, false,
965
16
         &ctx));
966
967
  /*
968
   * Digest the SIG(0) record, except for the signature.
969
   */
970
16
  dns_rdata_toregion(&rdata, &r);
971
16
  r.length -= sig.siglen;
972
16
  CHECK(dst_context_adddata(ctx, &r));
973
974
  /*
975
   * If this is a response, digest the query.
976
   */
977
16
  if (is_response(msg)) {
978
0
    CHECK(dst_context_adddata(ctx, &msg->query));
979
0
  }
980
981
  /*
982
   * Extract the header.
983
   */
984
16
  memmove(header, source_r.base, DNS_MESSAGE_HEADERLEN);
985
986
  /*
987
   * Decrement the additional field counter.
988
   */
989
16
  memmove(&addcount, &header[DNS_MESSAGE_HEADERLEN - 2], 2);
990
16
  addcount_n = ntohs(addcount);
991
16
  addcount = htons((uint16_t)(addcount_n - 1));
992
16
  memmove(&header[DNS_MESSAGE_HEADERLEN - 2], &addcount, 2);
993
994
  /*
995
   * Digest the modified header.
996
   */
997
16
  header_r.base = (unsigned char *)header;
998
16
  header_r.length = DNS_MESSAGE_HEADERLEN;
999
16
  CHECK(dst_context_adddata(ctx, &header_r));
1000
1001
  /*
1002
   * Digest all non-SIG(0) records.
1003
   */
1004
16
  r.base = source_r.base + DNS_MESSAGE_HEADERLEN;
1005
16
  r.length = msg->sigstart - DNS_MESSAGE_HEADERLEN;
1006
16
  CHECK(dst_context_adddata(ctx, &r));
1007
1008
16
  sig_r.base = sig.signature;
1009
16
  sig_r.length = sig.siglen;
1010
16
  result = dst_context_verify(ctx, &sig_r);
1011
16
  if (result != ISC_R_SUCCESS) {
1012
15
    msg->sig0status = dns_tsigerror_badsig;
1013
15
    goto cleanup;
1014
15
  }
1015
1016
1
  msg->verified_sig = 1;
1017
1
  msg->sig0status = dns_rcode_noerror;
1018
1019
1
  dst_context_destroy(&ctx);
1020
1
  dns_rdata_freestruct(&sig);
1021
1022
1
  return ISC_R_SUCCESS;
1023
1024
93
cleanup:
1025
93
  if (signeedsfree) {
1026
93
    dns_rdata_freestruct(&sig);
1027
93
  }
1028
93
  if (ctx != NULL) {
1029
15
    dst_context_destroy(&ctx);
1030
15
  }
1031
1032
93
  return result;
1033
16
}
1034
1035
/*%
1036
 * Does this key ('rdata') self sign the rrset ('rdataset')?
1037
 */
1038
bool
1039
dns_dnssec_selfsigns(dns_rdata_t *rdata, const dns_name_t *name,
1040
         dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
1041
0
         bool ignoretime, isc_mem_t *mctx) {
1042
0
  INSIST(rdataset->type == dns_rdatatype_key ||
1043
0
         rdataset->type == dns_rdatatype_dnskey);
1044
0
  if (rdataset->type == dns_rdatatype_key) {
1045
0
    INSIST(sigrdataset->type == dns_rdatatype_sig);
1046
0
    INSIST(sigrdataset->covers == dns_rdatatype_key);
1047
0
  } else {
1048
0
    INSIST(sigrdataset->type == dns_rdatatype_rrsig);
1049
0
    INSIST(sigrdataset->covers == dns_rdatatype_dnskey);
1050
0
  }
1051
1052
0
  return dns_dnssec_signs(rdata, name, rdataset, sigrdataset, ignoretime,
1053
0
        mctx);
1054
0
}
1055
1056
bool
1057
dns_dnssec_signs(dns_rdata_t *rdata, const dns_name_t *name,
1058
     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset,
1059
0
     bool ignoretime, isc_mem_t *mctx) {
1060
0
  dst_key_t *dstkey = NULL;
1061
0
  dns_keytag_t keytag;
1062
0
  dns_rdata_dnskey_t key;
1063
0
  dns_rdata_rrsig_t sig;
1064
0
  isc_result_t result;
1065
1066
0
  INSIST(sigrdataset->type == dns_rdatatype_rrsig);
1067
0
  if (sigrdataset->covers != rdataset->type) {
1068
0
    return false;
1069
0
  }
1070
1071
0
  result = dns_dnssec_keyfromrdata(name, rdata, mctx, &dstkey);
1072
0
  if (result != ISC_R_SUCCESS) {
1073
0
    return false;
1074
0
  }
1075
0
  result = dns_rdata_tostruct(rdata, &key, NULL);
1076
0
  RUNTIME_CHECK(result == ISC_R_SUCCESS);
1077
1078
0
  keytag = dst_key_id(dstkey);
1079
0
  DNS_RDATASET_FOREACH(sigrdataset) {
1080
0
    dns_rdata_t sigrdata = DNS_RDATA_INIT;
1081
0
    dns_rdataset_current(sigrdataset, &sigrdata);
1082
0
    result = dns_rdata_tostruct(&sigrdata, &sig, NULL);
1083
0
    RUNTIME_CHECK(result == ISC_R_SUCCESS);
1084
1085
0
    if (sig.algorithm == key.algorithm && sig.keyid == keytag) {
1086
0
      result = dns_dnssec_verify(name, rdataset, dstkey,
1087
0
               ignoretime, mctx, &sigrdata,
1088
0
               NULL, NULL);
1089
0
      if (result == ISC_R_SUCCESS) {
1090
0
        dst_key_free(&dstkey);
1091
0
        return true;
1092
0
      }
1093
0
    }
1094
0
  }
1095
0
  dst_key_free(&dstkey);
1096
0
  return false;
1097
0
}
1098
1099
bool
1100
100
dns_dnssec_iszonekey(dns_rdata_dnskey_t *key) {
1101
100
  return (key->flags & DNS_KEYOWNER_ZONE) != 0 &&
1102
54
         (key->protocol == DNS_KEYPROTO_DNSSEC ||
1103
29
    key->protocol == DNS_KEYPROTO_ANY);
1104
100
}
1105
1106
bool
1107
50
dns_dnssec_haszonekey(dns_rdataset_t *keyset) {
1108
50
  REQUIRE(keyset != NULL);
1109
1110
50
  if (keyset->type != dns_rdatatype_dnskey) {
1111
0
    return false;
1112
0
  }
1113
1114
100
  DNS_RDATASET_FOREACH(keyset) {
1115
100
    dns_rdata_t rdata = DNS_RDATA_INIT;
1116
100
    dns_rdata_dnskey_t key;
1117
1118
100
    dns_rdataset_current(keyset, &rdata);
1119
100
    dns_rdata_tostruct(&rdata, &key, NULL); /* can't fail */
1120
1121
100
    if (dns_dnssec_iszonekey(&key)) {
1122
31
      return true;
1123
31
    }
1124
100
  }
1125
1126
19
  return false;
1127
50
}
1128
1129
void
1130
dns_dnsseckey_create(isc_mem_t *mctx, dst_key_t **dstkey,
1131
0
         dns_dnsseckey_t **dkp) {
1132
0
  isc_result_t result;
1133
0
  dns_dnsseckey_t *dk;
1134
0
  int major, minor;
1135
1136
0
  REQUIRE(dkp != NULL && *dkp == NULL);
1137
0
  dk = isc_mem_get(mctx, sizeof(dns_dnsseckey_t));
1138
1139
0
  dk->key = *dstkey;
1140
0
  *dstkey = NULL;
1141
0
  dk->force_publish = false;
1142
0
  dk->force_sign = false;
1143
0
  dk->hint_publish = false;
1144
0
  dk->hint_sign = false;
1145
0
  dk->hint_revoke = false;
1146
0
  dk->hint_remove = false;
1147
0
  dk->first_sign = false;
1148
0
  dk->is_active = false;
1149
0
  dk->pubkey = false;
1150
0
  dk->purge = false;
1151
0
  dk->prepublish = 0;
1152
0
  dk->source = dns_keysource_unknown;
1153
0
  dk->index = 0;
1154
1155
  /* KSK or ZSK? */
1156
0
  result = dst_key_getbool(dk->key, DST_BOOL_KSK, &dk->ksk);
1157
0
  if (result != ISC_R_SUCCESS) {
1158
0
    dk->ksk = ((dst_key_flags(dk->key) & DNS_KEYFLAG_KSK) != 0);
1159
0
  }
1160
0
  result = dst_key_getbool(dk->key, DST_BOOL_ZSK, &dk->zsk);
1161
0
  if (result != ISC_R_SUCCESS) {
1162
0
    dk->zsk = ((dst_key_flags(dk->key) & DNS_KEYFLAG_KSK) == 0);
1163
0
  }
1164
1165
  /* Is this an old-style key? */
1166
0
  result = dst_key_getprivateformat(dk->key, &major, &minor);
1167
0
  INSIST(result == ISC_R_SUCCESS);
1168
1169
  /* Smart signing started with key format 1.3 */
1170
0
  dk->legacy = (major == 1 && minor <= 2);
1171
1172
0
  ISC_LINK_INIT(dk, link);
1173
0
  *dkp = dk;
1174
0
}
1175
1176
void
1177
0
dns_dnsseckey_destroy(isc_mem_t *mctx, dns_dnsseckey_t **dkp) {
1178
0
  dns_dnsseckey_t *dk;
1179
1180
0
  REQUIRE(dkp != NULL && *dkp != NULL);
1181
0
  dk = *dkp;
1182
0
  *dkp = NULL;
1183
0
  if (dk->key != NULL) {
1184
0
    dst_key_free(&dk->key);
1185
0
  }
1186
0
  isc_mem_put(mctx, dk, sizeof(dns_dnsseckey_t));
1187
0
}
1188
1189
void
1190
0
dns_dnssec_get_hints(dns_dnsseckey_t *key, isc_stdtime_t now) {
1191
0
  isc_stdtime_t publish = 0, active = 0, revoke = 0, remove = 0;
1192
1193
0
  REQUIRE(key != NULL && key->key != NULL);
1194
1195
0
  key->hint_publish = dst_key_is_published(key->key, now, &publish);
1196
0
  key->hint_sign = dst_key_is_signing(key->key, DST_BOOL_ZSK, now,
1197
0
              &active);
1198
0
  key->hint_revoke = dst_key_is_revoked(key->key, now, &revoke);
1199
0
  key->hint_remove = dst_key_is_removed(key->key, now, &remove);
1200
1201
  /*
1202
   * Activation date is set (maybe in the future), but publication date
1203
   * isn't. Most likely the user wants to publish now and activate later.
1204
   * Most likely because this is true for most rollovers, except for:
1205
   * 1. The unpopular ZSK Double-RRSIG method.
1206
   * 2. When introducing a new algorithm.
1207
   * These two cases are rare enough that we will set hint_publish
1208
   * anyway when hint_sign is set, because BIND 9 natively does not
1209
   * support the ZSK Double-RRSIG method, and when introducing a new
1210
   * algorithm, we strive to publish its signatures and DNSKEY records
1211
   * at the same time.
1212
   */
1213
0
  if (key->hint_sign && publish == 0) {
1214
0
    key->hint_publish = true;
1215
0
  }
1216
1217
  /*
1218
   * If activation date is in the future, make note of how far off.
1219
   */
1220
0
  if (key->hint_publish && active > now) {
1221
0
    key->prepublish = active - now;
1222
0
  }
1223
1224
  /*
1225
   * Metadata says revoke.  If the key is published, we *have to* sign
1226
   * with it per RFC5011 -- even if it was not active before.
1227
   *
1228
   * If it hasn't already been done, we should also revoke it now.
1229
   */
1230
0
  if (key->hint_publish && key->hint_revoke) {
1231
0
    uint32_t flags;
1232
0
    key->hint_sign = true;
1233
0
    flags = dst_key_flags(key->key);
1234
0
    if ((flags & DNS_KEYFLAG_REVOKE) == 0) {
1235
0
      flags |= DNS_KEYFLAG_REVOKE;
1236
0
      dst_key_setflags(key->key, flags);
1237
0
    }
1238
0
  }
1239
1240
  /*
1241
   * Metadata says delete, so don't publish this key or sign with it
1242
   * (note that signatures of a removed key may still be reused).
1243
   */
1244
0
  if (key->hint_remove) {
1245
0
    key->hint_publish = false;
1246
0
    key->hint_sign = false;
1247
0
  }
1248
0
}
1249
1250
static isc_result_t
1251
findmatchingkeys(const char *directory, bool rrtypekey, char *namebuf,
1252
     unsigned int len, isc_mem_t *mctx, isc_stdtime_t now,
1253
0
     dns_dnsseckeylist_t *list) {
1254
0
  isc_result_t result;
1255
0
  isc_dir_t dir;
1256
0
  bool dir_open = false, match = false;
1257
0
  unsigned int i;
1258
0
  dns_dnsseckey_t *key = NULL;
1259
0
  dst_key_t *dstkey = NULL;
1260
1261
0
  isc_dir_init(&dir);
1262
0
  if (directory == NULL) {
1263
0
    directory = ".";
1264
0
  }
1265
1266
0
  CHECK(isc_dir_open(&dir, directory));
1267
0
  dir_open = true;
1268
1269
0
  while (isc_dir_read(&dir) == ISC_R_SUCCESS) {
1270
0
    if (dir.entry.name[0] != 'K' || dir.entry.length < len + 1 ||
1271
0
        dir.entry.name[len + 1] != '+' ||
1272
0
        strncasecmp(dir.entry.name + 1, namebuf, len) != 0)
1273
0
    {
1274
0
      continue;
1275
0
    }
1276
1277
0
    for (i = len + 1 + 1; i < dir.entry.length; i++) {
1278
0
      if (!isdigit((unsigned char)dir.entry.name[i])) {
1279
0
        break;
1280
0
      }
1281
0
    }
1282
1283
    /*
1284
     * Did we not read exactly 3 digits?
1285
     * Did we overflow?
1286
     * Did we correctly terminate?
1287
     */
1288
0
    if (i != len + 1 + 1 + 3 || i >= dir.entry.length ||
1289
0
        dir.entry.name[i] != '+')
1290
0
    {
1291
0
      continue;
1292
0
    }
1293
1294
0
    for (i++; i < dir.entry.length; i++) {
1295
0
      if (!isdigit((unsigned char)dir.entry.name[i])) {
1296
0
        break;
1297
0
      }
1298
0
    }
1299
1300
    /*
1301
     * Did we not read exactly 5 more digits?
1302
     * Did we overflow?
1303
     * Did we correctly terminate?
1304
     */
1305
0
    if (i != len + 1 + 1 + 3 + 1 + 5 || i >= dir.entry.length ||
1306
0
        strcmp(dir.entry.name + i, ".private") != 0)
1307
0
    {
1308
0
      continue;
1309
0
    }
1310
1311
0
    int type = DST_TYPE_PUBLIC | DST_TYPE_PRIVATE | DST_TYPE_STATE;
1312
0
    if (rrtypekey) {
1313
0
      type |= DST_TYPE_KEY;
1314
0
    }
1315
0
    dstkey = NULL;
1316
0
    result = dst_key_fromnamedfile(dir.entry.name, directory, type,
1317
0
                 mctx, &dstkey);
1318
0
    if (result == DST_R_BADKEYTYPE) {
1319
0
      continue;
1320
0
    }
1321
0
    if (result != ISC_R_SUCCESS) {
1322
0
      isc_log_write(DNS_LOGCATEGORY_GENERAL,
1323
0
              DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
1324
0
              "dns_dnssec_findmatchingkeys: "
1325
0
              "error reading key file %s: %s",
1326
0
              dir.entry.name,
1327
0
              isc_result_totext(result));
1328
0
      continue;
1329
0
    }
1330
1331
0
    dns_dnsseckey_create(mctx, &dstkey, &key);
1332
0
    key->source = dns_keysource_repository;
1333
0
    dns_dnssec_get_hints(key, now);
1334
1335
0
    if (key->legacy) {
1336
0
      dns_dnsseckey_destroy(mctx, &key);
1337
0
    } else {
1338
0
      ISC_LIST_APPEND(*list, key, link);
1339
0
      match = true;
1340
0
      key = NULL;
1341
0
    }
1342
0
  }
1343
0
  result = match ? ISC_R_SUCCESS : ISC_R_NOTFOUND;
1344
1345
0
cleanup:
1346
0
  if (dir_open) {
1347
0
    isc_dir_close(&dir);
1348
0
  }
1349
0
  if (dstkey != NULL) {
1350
0
    dst_key_free(&dstkey);
1351
0
  }
1352
0
  return result;
1353
0
}
1354
1355
/*%
1356
 * Get a list of KEY or DNSKEY keys from the key repository. If rrtypekey
1357
 * is true KEY keys will be returned otherwise DNSSEC keys.
1358
 */
1359
isc_result_t
1360
dns_dnssec_findmatchingkeys(const dns_name_t *origin, dns_kasp_t *kasp,
1361
          const char *keydir, dns_keystorelist_t *keystores,
1362
          isc_stdtime_t now, bool rrtypekey, isc_mem_t *mctx,
1363
0
          dns_dnsseckeylist_t *keylist) {
1364
0
  isc_result_t result = ISC_R_SUCCESS;
1365
0
  dns_dnsseckeylist_t list;
1366
0
  char namebuf[DNS_NAME_FORMATSIZE];
1367
0
  isc_buffer_t b;
1368
0
  unsigned int len;
1369
1370
0
  REQUIRE(keylist != NULL);
1371
0
  ISC_LIST_INIT(list);
1372
1373
0
  isc_buffer_init(&b, namebuf, sizeof(namebuf) - 1);
1374
0
  CHECK(dns_name_tofilenametext(origin, false, &b));
1375
0
  len = isc_buffer_usedlength(&b);
1376
0
  namebuf[len] = '\0';
1377
1378
0
  if (kasp == NULL || (strcmp(dns_kasp_getname(kasp), "none") == 0) ||
1379
0
      (strcmp(dns_kasp_getname(kasp), "insecure") == 0))
1380
0
  {
1381
0
    CHECK(findmatchingkeys(keydir, rrtypekey, namebuf, len, mctx,
1382
0
               now, &list));
1383
0
  } else if (keystores != NULL) {
1384
0
    ISC_LIST_FOREACH(*keystores, keystore, link) {
1385
0
      ISC_LIST_FOREACH(dns_kasp_keys(kasp), kkey, link) {
1386
0
        if (dns_kasp_key_keystore(kkey) == keystore) {
1387
0
          const char *directory =
1388
0
            dns_keystore_directory(keystore,
1389
0
                       keydir);
1390
0
          CHECK(findmatchingkeys(
1391
0
            directory, rrtypekey, namebuf,
1392
0
            len, mctx, now, &list));
1393
0
          break;
1394
0
        }
1395
0
      }
1396
0
    }
1397
0
  }
1398
1399
0
  if (!ISC_LIST_EMPTY(list)) {
1400
0
    result = ISC_R_SUCCESS;
1401
0
    ISC_LIST_APPENDLIST(*keylist, list, link);
1402
0
  } else {
1403
0
    result = ISC_R_NOTFOUND;
1404
0
  }
1405
1406
0
cleanup:
1407
0
  ISC_LIST_FOREACH(list, key, link) {
1408
0
    ISC_LIST_UNLINK(list, key, link);
1409
0
    INSIST(key->key != NULL);
1410
0
    dst_key_free(&key->key);
1411
0
    dns_dnsseckey_destroy(mctx, &key);
1412
0
  }
1413
0
  return result;
1414
0
}
1415
1416
/*%
1417
 * Add 'newkey' to 'keylist' if it's not already there.
1418
 *
1419
 * If 'savekeys' is true, then we need to preserve all
1420
 * the keys in the keyset, regardless of whether they have
1421
 * metadata indicating they should be deactivated or removed.
1422
 */
1423
static void
1424
addkey(dns_dnsseckeylist_t *keylist, dst_key_t **newkey, bool savekeys,
1425
0
       bool pubkey_only, isc_mem_t *mctx) {
1426
0
  dns_dnsseckey_t *key = NULL;
1427
1428
  /* Skip duplicates */
1429
0
  ISC_LIST_FOREACH(*keylist, k, link) {
1430
0
    if (dst_key_id(k->key) == dst_key_id(*newkey) &&
1431
0
        dst_key_alg(k->key) == dst_key_alg(*newkey) &&
1432
0
        dns_name_equal(dst_key_name(k->key), dst_key_name(*newkey)))
1433
0
    {
1434
0
      key = k;
1435
0
      break;
1436
0
    }
1437
0
  }
1438
1439
0
  if (key != NULL) {
1440
    /*
1441
     * Found a match. If we already had a private key, then
1442
     * the new key can't be an improvement. If the existing
1443
     * key was public-only but the new key is too, then it's
1444
     * still not an improvement. Mark the old key as having
1445
     * been found in the zone and stop.
1446
     */
1447
0
    if (dst_key_isprivate(key->key) || !dst_key_isprivate(*newkey))
1448
0
    {
1449
0
      key->source = dns_keysource_zoneapex;
1450
0
      return;
1451
0
    }
1452
1453
    /*
1454
     * However, if the old key was public-only, and the new key
1455
     * is private, then we're throwing away the old key.
1456
     */
1457
0
    dst_key_free(&key->key);
1458
0
    ISC_LIST_UNLINK(*keylist, key, link);
1459
0
    dns_dnsseckey_destroy(mctx, &key);
1460
0
  }
1461
1462
  /* Store the new key. */
1463
0
  dns_dnsseckey_create(mctx, newkey, &key);
1464
0
  key->source = dns_keysource_zoneapex;
1465
0
  key->pubkey = pubkey_only;
1466
0
  if (key->legacy || savekeys) {
1467
0
    key->force_publish = true;
1468
0
    key->force_sign = dst_key_isprivate(key->key);
1469
0
  }
1470
0
  ISC_LIST_APPEND(*keylist, key, link);
1471
0
  *newkey = NULL;
1472
0
}
1473
1474
/*%
1475
 * Mark all keys which signed the DNSKEY/SOA RRsets as "active",
1476
 * for future reference.
1477
 */
1478
static isc_result_t
1479
0
mark_active_keys(dns_dnsseckeylist_t *keylist, dns_rdataset_t *rrsigs) {
1480
0
  isc_result_t result = ISC_R_SUCCESS;
1481
0
  dns_rdata_t rdata = DNS_RDATA_INIT;
1482
0
  dns_rdataset_t sigs;
1483
1484
0
  REQUIRE(rrsigs != NULL && dns_rdataset_isassociated(rrsigs));
1485
1486
0
  dns_rdataset_init(&sigs);
1487
0
  dns_rdataset_clone(rrsigs, &sigs);
1488
0
  ISC_LIST_FOREACH(*keylist, key, link) {
1489
0
    uint16_t keyid, sigid;
1490
0
    dst_algorithm_t keyalg, sigalg;
1491
0
    keyid = dst_key_id(key->key);
1492
0
    keyalg = dst_key_alg(key->key);
1493
1494
0
    DNS_RDATASET_FOREACH(&sigs) {
1495
0
      dns_rdata_rrsig_t sig;
1496
1497
0
      dns_rdata_reset(&rdata);
1498
0
      dns_rdataset_current(&sigs, &rdata);
1499
0
      result = dns_rdata_tostruct(&rdata, &sig, NULL);
1500
0
      RUNTIME_CHECK(result == ISC_R_SUCCESS);
1501
0
      sigalg = dst_algorithm_fromdata(
1502
0
        sig.algorithm, sig.signature, sig.siglen);
1503
0
      sigid = sig.keyid;
1504
0
      if (keyid == sigid && keyalg == sigalg) {
1505
0
        key->is_active = true;
1506
0
        break;
1507
0
      }
1508
0
    }
1509
0
  }
1510
1511
0
  dns_rdataset_cleanup(&sigs);
1512
0
  return result;
1513
0
}
1514
1515
static isc_result_t
1516
keyfromfile(dns_kasp_t *kasp, const char *keydir, dst_key_t *key, int type,
1517
0
      isc_mem_t *mctx, dst_key_t **savekey) {
1518
0
  const char *directory = keydir;
1519
0
  isc_result_t result = ISC_R_NOTFOUND;
1520
1521
0
  if (kasp == NULL || (strcmp(dns_kasp_getname(kasp), "none") == 0) ||
1522
0
      (strcmp(dns_kasp_getname(kasp), "insecure") == 0))
1523
0
  {
1524
0
    result = dst_key_fromfile(dst_key_name(key), dst_key_id(key),
1525
0
            dst_key_alg(key), type, directory,
1526
0
            mctx, savekey);
1527
0
  } else {
1528
0
    ISC_LIST_FOREACH(dns_kasp_keys(kasp), kkey, link) {
1529
0
      dns_keystore_t *ks = dns_kasp_key_keystore(kkey);
1530
0
      directory = dns_keystore_directory(ks, keydir);
1531
0
      result = dst_key_fromfile(dst_key_name(key),
1532
0
              dst_key_id(key),
1533
0
              dst_key_alg(key), type,
1534
0
              directory, mctx, savekey);
1535
0
      if (result == ISC_R_SUCCESS) {
1536
0
        break;
1537
0
      }
1538
0
    }
1539
0
  }
1540
1541
0
  return result;
1542
0
}
1543
1544
/*%
1545
 * Add the contents of a DNSKEY rdataset 'keyset' to 'keylist'.
1546
 */
1547
isc_result_t
1548
dns_dnssec_keylistfromrdataset(const dns_name_t *origin, dns_kasp_t *kasp,
1549
             const char *directory, isc_mem_t *mctx,
1550
             dns_rdataset_t *keyset, dns_rdataset_t *keysigs,
1551
             dns_rdataset_t *soasigs, bool savekeys,
1552
0
             bool publickey, dns_dnsseckeylist_t *keylist) {
1553
0
  dns_rdataset_t keys;
1554
0
  dst_key_t *dnskey = NULL, *pubkey = NULL, *privkey = NULL;
1555
0
  isc_result_t result;
1556
1557
0
  REQUIRE(keyset != NULL && dns_rdataset_isassociated(keyset));
1558
1559
0
  dns_rdataset_init(&keys);
1560
1561
0
  dns_rdataset_clone(keyset, &keys);
1562
0
  DNS_RDATASET_FOREACH(&keys) {
1563
0
    dns_rdata_t rdata = DNS_RDATA_INIT;
1564
0
    dst_algorithm_t algorithm;
1565
0
    dns_rdata_dnskey_t keystruct;
1566
1567
0
    dns_rdataset_current(&keys, &rdata);
1568
1569
0
    REQUIRE(rdata.type == dns_rdatatype_key ||
1570
0
      rdata.type == dns_rdatatype_dnskey);
1571
0
    REQUIRE(rdata.length > 3);
1572
1573
0
    result = dns_rdata_tostruct(&rdata, &keystruct, NULL);
1574
0
    RUNTIME_CHECK(result == ISC_R_SUCCESS);
1575
1576
0
    algorithm = dst_algorithm_fromdata(
1577
0
      keystruct.algorithm, keystruct.data, keystruct.datalen);
1578
1579
    /* Skip unsupported algorithms */
1580
0
    if (!dst_algorithm_supported(algorithm)) {
1581
0
      goto skip;
1582
0
    }
1583
1584
0
    CHECK(dns_dnssec_keyfromrdata(origin, &rdata, mctx, &dnskey));
1585
0
    dst_key_setttl(dnskey, keys.ttl);
1586
1587
0
    if (!is_zone_key(dnskey)) {
1588
0
      goto skip;
1589
0
    }
1590
1591
    /* Corrupted .key file? */
1592
0
    if (!dns_name_equal(origin, dst_key_name(dnskey))) {
1593
0
      goto skip;
1594
0
    }
1595
1596
0
    if (publickey) {
1597
0
      addkey(keylist, &dnskey, savekeys, true, mctx);
1598
0
      goto skip;
1599
0
    }
1600
1601
    /* Try to read the public key. */
1602
0
    result = keyfromfile(kasp, directory, dnskey,
1603
0
             DST_TYPE_PUBLIC | DST_TYPE_STATE, mctx,
1604
0
             &pubkey);
1605
0
    if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) {
1606
0
      result = ISC_R_SUCCESS;
1607
0
    }
1608
0
    CHECK(result);
1609
1610
0
    if (kasp != NULL && dns_kasp_offlineksk(kasp) &&
1611
0
        (dst_key_flags(dnskey) & DNS_KEYFLAG_KSK) != 0)
1612
0
    {
1613
0
      result = ISC_R_NOPERM;
1614
0
      goto addkey;
1615
0
    }
1616
1617
    /* Now read the private key. */
1618
0
    result = keyfromfile(kasp, directory, dnskey,
1619
0
             DST_TYPE_PUBLIC | DST_TYPE_PRIVATE |
1620
0
               DST_TYPE_STATE,
1621
0
             mctx, &privkey);
1622
1623
    /*
1624
     * If the key was revoked and the private file
1625
     * doesn't exist, maybe it was revoked internally
1626
     * by named.  Try loading the unrevoked version.
1627
     */
1628
0
    if (result == ISC_R_FILENOTFOUND) {
1629
0
      uint32_t flags;
1630
0
      flags = dst_key_flags(dnskey);
1631
0
      if ((flags & DNS_KEYFLAG_REVOKE) != 0) {
1632
0
        dst_key_setflags(dnskey,
1633
0
             flags & ~DNS_KEYFLAG_REVOKE);
1634
0
        result = keyfromfile(kasp, directory, dnskey,
1635
0
                 DST_TYPE_PUBLIC |
1636
0
                   DST_TYPE_PRIVATE |
1637
0
                   DST_TYPE_STATE,
1638
0
                 mctx, &privkey);
1639
0
        if (result == ISC_R_SUCCESS &&
1640
0
            dst_key_pubcompare(dnskey, privkey, false))
1641
0
        {
1642
0
          dst_key_setflags(privkey, flags);
1643
0
        }
1644
0
        dst_key_setflags(dnskey, flags);
1645
0
      }
1646
0
    }
1647
1648
0
    if (result != ISC_R_SUCCESS) {
1649
0
      char filename[DNS_NAME_FORMATSIZE +
1650
0
              DNS_SECALG_FORMATSIZE +
1651
0
              sizeof("key file for //65535")];
1652
0
      isc_result_t result2;
1653
0
      isc_buffer_t buf;
1654
1655
0
      isc_buffer_init(&buf, filename, NAME_MAX);
1656
0
      result2 = dst_key_getfilename(
1657
0
        dst_key_name(dnskey), dst_key_id(dnskey),
1658
0
        dst_key_alg(dnskey),
1659
0
        DST_TYPE_PUBLIC | DST_TYPE_PRIVATE |
1660
0
          DST_TYPE_STATE,
1661
0
        NULL, mctx, &buf);
1662
0
      if (result2 != ISC_R_SUCCESS) {
1663
0
        char namebuf[DNS_NAME_FORMATSIZE];
1664
0
        char algbuf[DNS_SECALG_FORMATSIZE];
1665
1666
0
        dns_name_format(dst_key_name(dnskey), namebuf,
1667
0
            sizeof(namebuf));
1668
0
        dns_secalg_format(dst_key_alg(dnskey), algbuf,
1669
0
              sizeof(algbuf));
1670
0
        snprintf(filename, sizeof(filename) - 1,
1671
0
           "key file for %s/%s/%d", namebuf,
1672
0
           algbuf, dst_key_id(dnskey));
1673
0
      }
1674
1675
0
      isc_log_write(DNS_LOGCATEGORY_GENERAL,
1676
0
              DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
1677
0
              "dns_dnssec_keylistfromrdataset: error "
1678
0
              "reading %s: %s",
1679
0
              filename, isc_result_totext(result));
1680
0
    }
1681
1682
0
  addkey:
1683
0
    if (result == ISC_R_FILENOTFOUND || result == ISC_R_NOPERM) {
1684
0
      if (pubkey != NULL) {
1685
0
        addkey(keylist, &pubkey, savekeys, true, mctx);
1686
0
      } else {
1687
0
        addkey(keylist, &dnskey, savekeys, false, mctx);
1688
0
      }
1689
0
      goto skip;
1690
0
    }
1691
0
    CHECK(result);
1692
1693
    /*
1694
     * Whatever the key's default TTL may have
1695
     * been, the rdataset TTL takes priority.
1696
     */
1697
0
    dst_key_setttl(privkey, dst_key_getttl(dnskey));
1698
1699
0
    addkey(keylist, &privkey, savekeys, false, mctx);
1700
0
  skip:
1701
0
    if (dnskey != NULL) {
1702
0
      dst_key_free(&dnskey);
1703
0
    }
1704
0
    if (pubkey != NULL) {
1705
0
      dst_key_free(&pubkey);
1706
0
    }
1707
0
    if (privkey != NULL) {
1708
0
      dst_key_free(&privkey);
1709
0
    }
1710
0
  }
1711
1712
0
  if (keysigs != NULL && dns_rdataset_isassociated(keysigs)) {
1713
0
    CHECK(mark_active_keys(keylist, keysigs));
1714
0
  }
1715
1716
0
  if (soasigs != NULL && dns_rdataset_isassociated(soasigs)) {
1717
0
    CHECK(mark_active_keys(keylist, soasigs));
1718
0
  }
1719
1720
0
  result = ISC_R_SUCCESS;
1721
1722
0
cleanup:
1723
0
  dns_rdataset_cleanup(&keys);
1724
0
  if (dnskey != NULL) {
1725
0
    dst_key_free(&dnskey);
1726
0
  }
1727
0
  if (pubkey != NULL) {
1728
0
    dst_key_free(&pubkey);
1729
0
  }
1730
0
  if (privkey != NULL) {
1731
0
    dst_key_free(&privkey);
1732
0
  }
1733
0
  return result;
1734
0
}
1735
1736
isc_result_t
1737
dns_dnssec_make_dnskey(dst_key_t *key, unsigned char *buf, int bufsize,
1738
0
           dns_rdata_t *target) {
1739
0
  isc_buffer_t b;
1740
0
  isc_region_t r;
1741
1742
0
  isc_buffer_init(&b, buf, bufsize);
1743
0
  RETERR(dst_key_todns(key, &b));
1744
1745
0
  dns_rdata_reset(target);
1746
0
  isc_buffer_usedregion(&b, &r);
1747
0
  dns_rdata_fromregion(target, dst_key_class(key), dns_rdatatype_dnskey,
1748
0
           &r);
1749
0
  return ISC_R_SUCCESS;
1750
0
}
1751
1752
static void
1753
addrdata(dns_rdata_t *rdata, dns_diff_t *diff, const dns_name_t *origin,
1754
0
   dns_ttl_t ttl, isc_mem_t *mctx) {
1755
0
  dns_difftuple_t *tuple = NULL;
1756
1757
0
  dns_difftuple_create(mctx, DNS_DIFFOP_ADD, origin, ttl, rdata, &tuple);
1758
0
  dns_diff_appendminimal(diff, &tuple);
1759
0
}
1760
1761
static void
1762
delrdata(dns_rdata_t *rdata, dns_diff_t *diff, const dns_name_t *origin,
1763
0
   dns_ttl_t ttl, isc_mem_t *mctx) {
1764
0
  dns_difftuple_t *tuple = NULL;
1765
1766
0
  dns_difftuple_create(mctx, DNS_DIFFOP_DEL, origin, ttl, rdata, &tuple);
1767
0
  dns_diff_appendminimal(diff, &tuple);
1768
0
}
1769
1770
static isc_result_t
1771
publish_key(dns_diff_t *diff, dns_dnsseckey_t *key, const dns_name_t *origin,
1772
      dns_ttl_t ttl, isc_mem_t *mctx,
1773
0
      void (*report)(const char *, ...) ISC_FORMAT_PRINTF(1, 2)) {
1774
0
  isc_result_t result = ISC_R_SUCCESS;
1775
0
  unsigned char buf[DNS_RDATA_MAXLENGTH];
1776
0
  char keystr[DST_KEY_FORMATSIZE];
1777
0
  dns_rdata_t dnskey = DNS_RDATA_INIT;
1778
1779
0
  dns_rdata_reset(&dnskey);
1780
0
  CHECK(dns_dnssec_make_dnskey(key->key, buf, sizeof(buf), &dnskey));
1781
0
  dst_key_format(key->key, keystr, sizeof(keystr));
1782
1783
0
  report("Fetching %s (%s) from key %s.", keystr,
1784
0
         key->ksk ? (key->zsk ? "CSK" : "KSK") : "ZSK",
1785
0
         key->source == dns_keysource_user ? "file" : "repository");
1786
1787
0
  if (key->prepublish && ttl > key->prepublish) {
1788
0
    isc_stdtime_t now;
1789
1790
0
    report("Key %s: Delaying activation to match the DNSKEY TTL "
1791
0
           "(%u).",
1792
0
           keystr, ttl);
1793
1794
0
    now = isc_stdtime_now();
1795
0
    dst_key_settime(key->key, DST_TIME_ACTIVATE, now + ttl);
1796
0
  }
1797
1798
  /* publish key */
1799
0
  addrdata(&dnskey, diff, origin, ttl, mctx);
1800
1801
0
cleanup:
1802
0
  return result;
1803
0
}
1804
1805
static isc_result_t
1806
remove_key(dns_diff_t *diff, dns_dnsseckey_t *key, const dns_name_t *origin,
1807
     dns_ttl_t ttl, isc_mem_t *mctx, const char *reason,
1808
0
     void (*report)(const char *, ...) ISC_FORMAT_PRINTF(1, 2)) {
1809
0
  isc_result_t result = ISC_R_SUCCESS;
1810
0
  unsigned char buf[DNS_RDATA_MAXLENGTH];
1811
0
  dns_rdata_t dnskey = DNS_RDATA_INIT;
1812
0
  char alg[80];
1813
0
  char namebuf[DNS_NAME_FORMATSIZE];
1814
1815
0
  dns_secalg_format(dst_key_alg(key->key), alg, sizeof(alg));
1816
0
  dns_name_format(dst_key_name(key->key), namebuf, sizeof(namebuf));
1817
0
  report("Removing %s key %s/%d/%s from DNSKEY RRset.", reason, namebuf,
1818
0
         dst_key_id(key->key), alg);
1819
1820
0
  CHECK(dns_dnssec_make_dnskey(key->key, buf, sizeof(buf), &dnskey));
1821
0
  delrdata(&dnskey, diff, origin, ttl, mctx);
1822
1823
0
cleanup:
1824
0
  return result;
1825
0
}
1826
1827
static bool
1828
0
exists(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
1829
0
  dns_rdataset_t trdataset = DNS_RDATASET_INIT;
1830
0
  dns_rdataset_clone(rdataset, &trdataset);
1831
1832
0
  DNS_RDATASET_FOREACH(&trdataset) {
1833
0
    dns_rdata_t current = DNS_RDATA_INIT;
1834
1835
0
    dns_rdataset_current(&trdataset, &current);
1836
0
    if (dns_rdata_compare(rdata, &current) == 0) {
1837
0
      dns_rdataset_disassociate(&trdataset);
1838
0
      return true;
1839
0
    }
1840
0
  }
1841
0
  dns_rdataset_disassociate(&trdataset);
1842
0
  return false;
1843
0
}
1844
1845
static isc_result_t
1846
add_cds(dns_dnsseckey_t *key, dns_rdata_t *keyrdata, const char *keystr,
1847
  dns_rdataset_t *cds, unsigned int digesttype, dns_ttl_t ttl,
1848
0
  dns_diff_t *diff, isc_mem_t *mctx) {
1849
0
  isc_result_t r;
1850
0
  unsigned char dsbuf[DNS_DS_BUFFERSIZE];
1851
0
  dns_rdata_t cdsrdata = DNS_RDATA_INIT;
1852
0
  dns_name_t *origin = dst_key_name(key->key);
1853
1854
0
  r = dns_ds_buildrdata(origin, keyrdata, digesttype, dsbuf,
1855
0
            sizeof(dsbuf), &cdsrdata);
1856
0
  if (r != ISC_R_SUCCESS) {
1857
0
    char algbuf[DNS_DSDIGEST_FORMATSIZE];
1858
0
    dns_dsdigest_format(digesttype, algbuf,
1859
0
            DNS_DSDIGEST_FORMATSIZE);
1860
0
    isc_log_write(DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_DNSSEC,
1861
0
            ISC_LOG_ERROR,
1862
0
            "build rdata CDS (%s) for key %s failed", algbuf,
1863
0
            keystr);
1864
0
    return r;
1865
0
  }
1866
1867
0
  cdsrdata.type = dns_rdatatype_cds;
1868
0
  if (!dns_rdataset_isassociated(cds) || !exists(cds, &cdsrdata)) {
1869
0
    char algbuf[DNS_DSDIGEST_FORMATSIZE];
1870
0
    dns_dsdigest_format(digesttype, algbuf,
1871
0
            DNS_DSDIGEST_FORMATSIZE);
1872
0
    isc_log_write(DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_DNSSEC,
1873
0
            ISC_LOG_INFO,
1874
0
            "CDS (%s) for key %s is now published", algbuf,
1875
0
            keystr);
1876
0
    addrdata(&cdsrdata, diff, origin, ttl, mctx);
1877
0
    return ISC_R_SUCCESS;
1878
0
  }
1879
0
  return DNS_R_UNCHANGED;
1880
0
}
1881
1882
static bool
1883
0
contains_digest(dns_kasp_digestlist_t *digests, unsigned int digesttype) {
1884
0
  ISC_LIST_FOREACH(*digests, alg, link) {
1885
0
    if (digesttype == alg->digest) {
1886
0
      return true;
1887
0
    }
1888
0
  }
1889
1890
0
  return false;
1891
0
}
1892
1893
static isc_result_t
1894
delete_cds(dns_dnsseckey_t *key, dns_rdata_t *keyrdata, const char *keystr,
1895
     dns_rdataset_t *cds, unsigned int digesttype, dns_diff_t *diff,
1896
0
     isc_mem_t *mctx) {
1897
0
  unsigned char dsbuf[DNS_DS_BUFFERSIZE];
1898
0
  dns_rdata_t cdsrdata = DNS_RDATA_INIT;
1899
0
  dns_name_t *origin = dst_key_name(key->key);
1900
1901
0
  RETERR(dns_ds_buildrdata(origin, keyrdata, digesttype, dsbuf,
1902
0
         sizeof(dsbuf), &cdsrdata));
1903
1904
0
  cdsrdata.type = dns_rdatatype_cds;
1905
0
  if (exists(cds, &cdsrdata)) {
1906
0
    char algbuf[DNS_DSDIGEST_FORMATSIZE];
1907
0
    dns_dsdigest_format(digesttype, algbuf,
1908
0
            DNS_DSDIGEST_FORMATSIZE);
1909
0
    isc_log_write(DNS_LOGCATEGORY_GENERAL, DNS_LOGMODULE_DNSSEC,
1910
0
            ISC_LOG_INFO,
1911
0
            "CDS (%s) for key %s is now deleted", algbuf,
1912
0
            keystr);
1913
0
    delrdata(&cdsrdata, diff, origin, cds->ttl, mctx);
1914
0
    return ISC_R_SUCCESS;
1915
0
  }
1916
0
  return DNS_R_UNCHANGED;
1917
0
}
1918
1919
isc_result_t
1920
dns_dnssec_syncupdate(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *rmkeys,
1921
          dns_rdataset_t *cds, dns_rdataset_t *cdnskey,
1922
          isc_stdtime_t now, dns_kasp_digestlist_t *digests,
1923
          bool gencdnskey, dns_ttl_t ttl, dns_diff_t *diff,
1924
0
          isc_mem_t *mctx) {
1925
0
  unsigned char keybuf[DNS_RDATA_MAXLENGTH];
1926
0
  isc_result_t result = DNS_R_UNCHANGED;
1927
0
  dns_ttl_t cdsttl = ttl;
1928
0
  dns_ttl_t cdnskeyttl = ttl;
1929
0
  bool changed = false;
1930
1931
0
  REQUIRE(digests != NULL);
1932
0
  REQUIRE(keys != NULL);
1933
0
  REQUIRE(rmkeys != NULL);
1934
1935
0
  if (dns_rdataset_isassociated(cds)) {
1936
0
    cdsttl = cds->ttl;
1937
0
  }
1938
1939
0
  if (dns_rdataset_isassociated(cdnskey)) {
1940
0
    cdnskeyttl = cdnskey->ttl;
1941
0
  }
1942
1943
0
  ISC_LIST_FOREACH(*keys, key, link) {
1944
0
    dns_rdata_t cdnskeyrdata = DNS_RDATA_INIT;
1945
0
    dns_name_t *origin = dst_key_name(key->key);
1946
1947
0
    CHECK(dns_dnssec_make_dnskey(key->key, keybuf, sizeof(keybuf),
1948
0
               &cdnskeyrdata));
1949
0
    cdnskeyrdata.type = dns_rdatatype_cdnskey;
1950
1951
0
    if (syncpublish(key->key, now)) {
1952
0
      char keystr[DST_KEY_FORMATSIZE];
1953
0
      dst_key_format(key->key, keystr, sizeof(keystr));
1954
1955
0
      ISC_LIST_FOREACH(*digests, alg, link) {
1956
0
        result = add_cds(key, &cdnskeyrdata,
1957
0
             (const char *)keystr, cds,
1958
0
             alg->digest, cdsttl, diff,
1959
0
             mctx);
1960
0
        if (result == ISC_R_SUCCESS) {
1961
0
          changed = true;
1962
0
        } else if (result != DNS_R_UNCHANGED) {
1963
0
          goto cleanup;
1964
0
        }
1965
0
      }
1966
1967
0
      if (gencdnskey &&
1968
0
          (!dns_rdataset_isassociated(cdnskey) ||
1969
0
           !exists(cdnskey, &cdnskeyrdata)))
1970
0
      {
1971
0
        isc_log_write(
1972
0
          DNS_LOGCATEGORY_GENERAL,
1973
0
          DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
1974
0
          "CDNSKEY for key %s is now published",
1975
0
          keystr);
1976
0
        addrdata(&cdnskeyrdata, diff, origin,
1977
0
           cdnskeyttl, mctx);
1978
0
        changed = true;
1979
0
      }
1980
0
    }
1981
1982
0
    if (dns_rdataset_isassociated(cds)) {
1983
0
      char keystr[DST_KEY_FORMATSIZE];
1984
0
      dst_key_format(key->key, keystr, sizeof(keystr));
1985
1986
      /* Delete all possible CDS records */
1987
0
      for (dns_dsdigest_t digest = DNS_DSDIGEST_SHA1;
1988
0
           digest < DNS_DSDIGEST_TOTAL; digest++)
1989
0
      {
1990
0
        if (syncdelete(key->key, now) ||
1991
0
            !contains_digest(digests, digest))
1992
0
        {
1993
0
          result = delete_cds(
1994
0
            key, &cdnskeyrdata,
1995
0
            (const char *)keystr, cds,
1996
0
            digest, diff, mctx);
1997
0
          switch (result) {
1998
0
          case ISC_R_SUCCESS:
1999
0
            changed = true;
2000
0
            break;
2001
0
          case DNS_R_UNCHANGED:
2002
0
          case ISC_R_NOTIMPLEMENTED:
2003
            /*
2004
             * Either the digest is not
2005
             * supported and we cannot
2006
             * construct the CDS for it, or
2007
             * the CDS with this digest is
2008
             * not present in the CDS RRset.
2009
             */
2010
0
            break;
2011
0
          default:
2012
0
            goto cleanup;
2013
0
          }
2014
0
        }
2015
0
      }
2016
0
    }
2017
2018
0
    if (dns_rdataset_isassociated(cdnskey) &&
2019
0
        exists(cdnskey, &cdnskeyrdata))
2020
0
    {
2021
0
      if (syncdelete(key->key, now) || !gencdnskey) {
2022
0
        char keystr[DST_KEY_FORMATSIZE];
2023
0
        dst_key_format(key->key, keystr,
2024
0
                 sizeof(keystr));
2025
2026
0
        isc_log_write(
2027
0
          DNS_LOGCATEGORY_GENERAL,
2028
0
          DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
2029
0
          "CDNSKEY for key %s is now deleted",
2030
0
          keystr);
2031
0
        delrdata(&cdnskeyrdata, diff, origin,
2032
0
           cdnskey->ttl, mctx);
2033
0
        changed = true;
2034
0
      }
2035
0
    }
2036
0
  }
2037
2038
0
  if (!dns_rdataset_isassociated(cds) &&
2039
0
      !dns_rdataset_isassociated(cdnskey))
2040
0
  {
2041
0
    if (changed) {
2042
0
      return ISC_R_SUCCESS;
2043
0
    }
2044
0
    return DNS_R_UNCHANGED;
2045
0
  }
2046
2047
  /*
2048
   * Unconditionally remove CDS/DNSKEY records for removed keys.
2049
   */
2050
0
  ISC_LIST_FOREACH(*rmkeys, key, link) {
2051
0
    dns_rdata_t cdnskeyrdata = DNS_RDATA_INIT;
2052
0
    dns_name_t *origin = dst_key_name(key->key);
2053
2054
0
    char keystr[DST_KEY_FORMATSIZE];
2055
0
    dst_key_format(key->key, keystr, sizeof(keystr));
2056
2057
0
    CHECK(dns_dnssec_make_dnskey(key->key, keybuf, sizeof(keybuf),
2058
0
               &cdnskeyrdata));
2059
2060
0
    if (dns_rdataset_isassociated(cds)) {
2061
0
      for (dns_dsdigest_t digest = DNS_DSDIGEST_SHA1;
2062
0
           digest < DNS_DSDIGEST_TOTAL; digest++)
2063
0
      {
2064
0
        result = delete_cds(key, &cdnskeyrdata,
2065
0
                (const char *)keystr, cds,
2066
0
                digest, diff, mctx);
2067
0
        switch (result) {
2068
0
        case ISC_R_SUCCESS:
2069
0
          changed = true;
2070
0
          break;
2071
0
        case DNS_R_UNCHANGED:
2072
0
        case ISC_R_NOTIMPLEMENTED:
2073
          /*
2074
           * Either the digest is not
2075
           * supported and we cannot
2076
           * construct the CDS for it, or
2077
           * the CDS with this digest is
2078
           * not present in the CDS RRset.
2079
           */
2080
0
          break;
2081
0
        default:
2082
0
          goto cleanup;
2083
0
        }
2084
0
      }
2085
0
    }
2086
2087
0
    if (dns_rdataset_isassociated(cdnskey)) {
2088
0
      if (exists(cdnskey, &cdnskeyrdata)) {
2089
0
        isc_log_write(
2090
0
          DNS_LOGCATEGORY_GENERAL,
2091
0
          DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
2092
0
          "CDNSKEY for key %s is now deleted",
2093
0
          keystr);
2094
0
        delrdata(&cdnskeyrdata, diff, origin,
2095
0
           cdnskey->ttl, mctx);
2096
0
        changed = true;
2097
0
      }
2098
0
    }
2099
0
  }
2100
2101
0
  if (changed) {
2102
0
    return ISC_R_SUCCESS;
2103
0
  }
2104
0
  return DNS_R_UNCHANGED;
2105
2106
0
cleanup:
2107
0
  return result;
2108
0
}
2109
2110
isc_result_t
2111
dns_dnssec_syncdelete(dns_rdataset_t *cds, dns_rdataset_t *cdnskey,
2112
          dns_name_t *origin, dns_rdataclass_t zclass,
2113
          dns_ttl_t ttl, dns_diff_t *diff, isc_mem_t *mctx,
2114
0
          bool expect_cds_delete, bool expect_cdnskey_delete) {
2115
0
  unsigned char dsbuf[5] = { 0, 0, 0, 0, 0 };  /* CDS DELETE rdata */
2116
0
  unsigned char keybuf[5] = { 0, 0, 3, 0, 0 }; /* CDNSKEY DELETE rdata */
2117
0
  char namebuf[DNS_NAME_FORMATSIZE];
2118
0
  dns_rdata_t cds_delete = DNS_RDATA_INIT;
2119
0
  dns_rdata_t cdnskey_delete = DNS_RDATA_INIT;
2120
0
  isc_region_t r;
2121
0
  bool changed = false;
2122
2123
0
  r.base = keybuf;
2124
0
  r.length = sizeof(keybuf);
2125
0
  dns_rdata_fromregion(&cdnskey_delete, zclass, dns_rdatatype_cdnskey,
2126
0
           &r);
2127
2128
0
  r.base = dsbuf;
2129
0
  r.length = sizeof(dsbuf);
2130
0
  dns_rdata_fromregion(&cds_delete, zclass, dns_rdatatype_cds, &r);
2131
2132
0
  dns_name_format(origin, namebuf, sizeof(namebuf));
2133
2134
0
  if (expect_cds_delete) {
2135
0
    if (!dns_rdataset_isassociated(cds) ||
2136
0
        !exists(cds, &cds_delete))
2137
0
    {
2138
0
      isc_log_write(DNS_LOGCATEGORY_GENERAL,
2139
0
              DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
2140
0
              "CDS (DELETE) for zone %s is now "
2141
0
              "published",
2142
0
              namebuf);
2143
0
      addrdata(&cds_delete, diff, origin, ttl, mctx);
2144
0
      changed = true;
2145
0
    }
2146
0
  } else {
2147
0
    if (dns_rdataset_isassociated(cds) && exists(cds, &cds_delete))
2148
0
    {
2149
0
      isc_log_write(DNS_LOGCATEGORY_GENERAL,
2150
0
              DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
2151
0
              "CDS (DELETE) for zone %s is now "
2152
0
              "deleted",
2153
0
              namebuf);
2154
0
      delrdata(&cds_delete, diff, origin, cds->ttl, mctx);
2155
0
      changed = true;
2156
0
    }
2157
0
  }
2158
2159
0
  if (expect_cdnskey_delete) {
2160
0
    if (!dns_rdataset_isassociated(cdnskey) ||
2161
0
        !exists(cdnskey, &cdnskey_delete))
2162
0
    {
2163
0
      isc_log_write(DNS_LOGCATEGORY_GENERAL,
2164
0
              DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
2165
0
              "CDNSKEY (DELETE) for zone %s is now "
2166
0
              "published",
2167
0
              namebuf);
2168
0
      addrdata(&cdnskey_delete, diff, origin, ttl, mctx);
2169
0
      changed = true;
2170
0
    }
2171
0
  } else {
2172
0
    if (dns_rdataset_isassociated(cdnskey) &&
2173
0
        exists(cdnskey, &cdnskey_delete))
2174
0
    {
2175
0
      isc_log_write(DNS_LOGCATEGORY_GENERAL,
2176
0
              DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
2177
0
              "CDNSKEY (DELETE) for zone %s is now "
2178
0
              "deleted",
2179
0
              namebuf);
2180
0
      delrdata(&cdnskey_delete, diff, origin, cdnskey->ttl,
2181
0
         mctx);
2182
0
      changed = true;
2183
0
    }
2184
0
  }
2185
2186
0
  if (changed) {
2187
0
    return ISC_R_SUCCESS;
2188
0
  }
2189
0
  return DNS_R_UNCHANGED;
2190
0
}
2191
2192
/*
2193
 * Update 'keys' with information from 'newkeys'.
2194
 *
2195
 * If 'removed' is not NULL, any keys that are being removed from
2196
 * the zone will be added to the list for post-removal processing.
2197
 */
2198
isc_result_t
2199
dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys,
2200
          dns_dnsseckeylist_t *removed, const dns_name_t *origin,
2201
          dns_ttl_t hint_ttl, dns_diff_t *diff, isc_mem_t *mctx,
2202
          void (*report)(const char *, ...)
2203
0
            ISC_FORMAT_PRINTF(1, 2)) {
2204
0
  isc_result_t result;
2205
0
  bool found_ttl = false;
2206
0
  dns_ttl_t ttl = hint_ttl;
2207
2208
  /*
2209
   * First, look through the existing key list to find keys
2210
   * supplied from the command line which are not in the zone.
2211
   * Update the zone to include them.
2212
   *
2213
   * Also, if there are keys published in the zone already,
2214
   * use their TTL for all subsequent published keys.
2215
   */
2216
0
  ISC_LIST_FOREACH(*keys, key, link) {
2217
0
    if (key->source == dns_keysource_user &&
2218
0
        (key->hint_publish || key->force_publish))
2219
0
    {
2220
0
      CHECK(publish_key(diff, key, origin, ttl, mctx,
2221
0
            report));
2222
0
    }
2223
0
    if (key->source == dns_keysource_zoneapex) {
2224
0
      ttl = dst_key_getttl(key->key);
2225
0
      found_ttl = true;
2226
0
    }
2227
0
  }
2228
2229
  /*
2230
   * If there were no existing keys, use the smallest nonzero
2231
   * TTL of the keys found in the repository.
2232
   */
2233
0
  if (!found_ttl && !ISC_LIST_EMPTY(*newkeys)) {
2234
0
    dns_ttl_t shortest = 0;
2235
2236
0
    ISC_LIST_FOREACH(*newkeys, key, link) {
2237
0
      dns_ttl_t thisttl = dst_key_getttl(key->key);
2238
0
      if (thisttl != 0 &&
2239
0
          (shortest == 0 || thisttl < shortest))
2240
0
      {
2241
0
        shortest = thisttl;
2242
0
      }
2243
0
    }
2244
2245
0
    if (shortest != 0) {
2246
0
      ttl = shortest;
2247
0
    }
2248
0
  }
2249
2250
  /*
2251
   * Second, scan the list of newly found keys looking for matches
2252
   * with known keys, and update accordingly.
2253
   */
2254
0
  ISC_LIST_FOREACH(*newkeys, key1, link) {
2255
0
    bool key_revoked = false;
2256
0
    char keystr1[DST_KEY_FORMATSIZE];
2257
0
    char keystr2[DST_KEY_FORMATSIZE];
2258
0
    dns_dnsseckey_t *key2 = NULL;
2259
2260
0
    ISC_LIST_FOREACH(*keys, k2, link) {
2261
0
      int f1 = dst_key_flags(key1->key);
2262
0
      int f2 = dst_key_flags(k2->key);
2263
0
      int nr1 = f1 & ~DNS_KEYFLAG_REVOKE;
2264
0
      int nr2 = f2 & ~DNS_KEYFLAG_REVOKE;
2265
0
      if (nr1 == nr2 &&
2266
0
          dst_key_alg(key1->key) == dst_key_alg(k2->key) &&
2267
0
          dst_key_pubcompare(key1->key, k2->key, true))
2268
0
      {
2269
0
        int r1 = dst_key_flags(key1->key) &
2270
0
           DNS_KEYFLAG_REVOKE;
2271
0
        int r2 = dst_key_flags(k2->key) &
2272
0
           DNS_KEYFLAG_REVOKE;
2273
0
        key_revoked = (r1 != r2);
2274
0
        key2 = k2;
2275
0
        break;
2276
0
      }
2277
0
    }
2278
2279
    /* Printable version of key1 (the newly acquired key) */
2280
0
    dst_key_format(key1->key, keystr1, sizeof(keystr1));
2281
2282
    /* No match found in keys; add the new key. */
2283
0
    if (key2 == NULL) {
2284
0
      ISC_LIST_UNLINK(*newkeys, key1, link);
2285
0
      ISC_LIST_APPEND(*keys, key1, link);
2286
2287
0
      if (key1->source != dns_keysource_zoneapex &&
2288
0
          (key1->hint_publish || key1->force_publish))
2289
0
      {
2290
0
        CHECK(publish_key(diff, key1, origin, ttl, mctx,
2291
0
              report));
2292
0
        isc_log_write(
2293
0
          DNS_LOGCATEGORY_DNSSEC,
2294
0
          DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
2295
0
          "DNSKEY %s (%s) is now published",
2296
0
          keystr1,
2297
0
          key1->ksk ? (key1->zsk ? "CSK" : "KSK")
2298
0
              : "ZSK");
2299
0
        if (key1->hint_sign || key1->force_sign) {
2300
0
          key1->first_sign = true;
2301
0
          isc_log_write(
2302
0
            DNS_LOGCATEGORY_DNSSEC,
2303
0
            DNS_LOGMODULE_DNSSEC,
2304
0
            ISC_LOG_INFO,
2305
0
            "DNSKEY %s (%s) is now "
2306
0
            "active",
2307
0
            keystr1,
2308
0
            key1->ksk ? (key1->zsk ? "CSK"
2309
0
                       : "KSK")
2310
0
                : "ZSK");
2311
0
        }
2312
0
      }
2313
2314
0
      continue;
2315
0
    }
2316
2317
    /* Printable version of key2 (the old key, if any) */
2318
0
    dst_key_format(key2->key, keystr2, sizeof(keystr2));
2319
2320
    /* Copy key metadata. */
2321
0
    dst_key_copy_metadata(key2->key, key1->key);
2322
2323
    /* Match found: remove or update it as needed */
2324
0
    if (key1->hint_remove) {
2325
0
      CHECK(remove_key(diff, key2, origin, ttl, mctx,
2326
0
           "expired", report));
2327
0
      ISC_LIST_UNLINK(*keys, key2, link);
2328
2329
0
      if (removed != NULL) {
2330
0
        ISC_LIST_APPEND(*removed, key2, link);
2331
0
        isc_log_write(
2332
0
          DNS_LOGCATEGORY_DNSSEC,
2333
0
          DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
2334
0
          "DNSKEY %s (%s) is now deleted",
2335
0
          keystr2,
2336
0
          key2->ksk ? (key2->zsk ? "CSK" : "KSK")
2337
0
              : "ZSK");
2338
0
      } else {
2339
0
        dns_dnsseckey_destroy(mctx, &key2);
2340
0
      }
2341
0
    } else if (key_revoked &&
2342
0
         (dst_key_flags(key1->key) & DNS_KEYFLAG_REVOKE) != 0)
2343
0
    {
2344
      /*
2345
       * A previously valid key has been revoked.
2346
       * We need to remove the old version and pull
2347
       * in the new one.
2348
       */
2349
0
      CHECK(remove_key(diff, key2, origin, ttl, mctx,
2350
0
           "revoked", report));
2351
0
      ISC_LIST_UNLINK(*keys, key2, link);
2352
0
      if (removed != NULL) {
2353
0
        ISC_LIST_APPEND(*removed, key2, link);
2354
0
        isc_log_write(
2355
0
          DNS_LOGCATEGORY_DNSSEC,
2356
0
          DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
2357
0
          "DNSKEY %s (%s) is now revoked; "
2358
0
          "new ID is %05d",
2359
0
          keystr2,
2360
0
          key2->ksk ? (key2->zsk ? "CSK" : "KSK")
2361
0
              : "ZSK",
2362
0
          dst_key_id(key1->key));
2363
0
      } else {
2364
0
        dns_dnsseckey_destroy(mctx, &key2);
2365
0
      }
2366
2367
0
      CHECK(publish_key(diff, key1, origin, ttl, mctx,
2368
0
            report));
2369
0
      ISC_LIST_UNLINK(*newkeys, key1, link);
2370
0
      ISC_LIST_APPEND(*keys, key1, link);
2371
2372
      /*
2373
       * XXX: The revoke flag is only defined for trust
2374
       * anchors.  Setting the flag on a non-KSK is legal,
2375
       * but not defined in any RFC.  It seems reasonable
2376
       * to treat it the same as a KSK: keep it in the
2377
       * zone, sign the DNSKEY set with it, but not
2378
       * sign other records with it.
2379
       */
2380
0
      key1->ksk = true;
2381
0
      continue;
2382
0
    } else {
2383
0
      if (!key2->is_active &&
2384
0
          (key1->hint_sign || key1->force_sign))
2385
0
      {
2386
0
        key2->first_sign = true;
2387
0
        isc_log_write(
2388
0
          DNS_LOGCATEGORY_DNSSEC,
2389
0
          DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
2390
0
          "DNSKEY %s (%s) is now active", keystr1,
2391
0
          key1->ksk ? (key1->zsk ? "CSK" : "KSK")
2392
0
              : "ZSK");
2393
0
      } else if (key2->is_active && !key1->hint_sign &&
2394
0
           !key1->force_sign)
2395
0
      {
2396
0
        isc_log_write(
2397
0
          DNS_LOGCATEGORY_DNSSEC,
2398
0
          DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
2399
0
          "DNSKEY %s (%s) is now inactive",
2400
0
          keystr1,
2401
0
          key1->ksk ? (key1->zsk ? "CSK" : "KSK")
2402
0
              : "ZSK");
2403
0
      }
2404
2405
0
      key2->hint_sign = key1->hint_sign;
2406
0
      key2->hint_publish = key1->hint_publish;
2407
0
    }
2408
0
  }
2409
2410
  /* Free any leftover keys in newkeys */
2411
0
  ISC_LIST_FOREACH(*newkeys, key1, link) {
2412
0
    ISC_LIST_UNLINK(*newkeys, key1, link);
2413
0
    dns_dnsseckey_destroy(mctx, &key1);
2414
0
  }
2415
2416
0
  result = ISC_R_SUCCESS;
2417
2418
0
cleanup:
2419
0
  return result;
2420
0
}
2421
2422
isc_result_t
2423
dns_dnssec_matchdskey(dns_name_t *name, dns_rdata_t *dsrdata,
2424
0
          dns_rdataset_t *keyset, dns_rdata_t *keyrdata) {
2425
0
  isc_result_t result;
2426
0
  unsigned char buf[DNS_DS_BUFFERSIZE];
2427
0
  dns_keytag_t keytag;
2428
0
  dns_rdata_dnskey_t key;
2429
0
  dns_rdata_ds_t ds;
2430
0
  isc_region_t r;
2431
2432
0
  result = dns_rdata_tostruct(dsrdata, &ds, NULL);
2433
0
  RUNTIME_CHECK(result == ISC_R_SUCCESS);
2434
2435
0
  DNS_RDATASET_FOREACH(keyset) {
2436
0
    dns_rdata_t newdsrdata = DNS_RDATA_INIT;
2437
2438
0
    dns_rdata_reset(keyrdata);
2439
0
    dns_rdataset_current(keyset, keyrdata);
2440
2441
0
    result = dns_rdata_tostruct(keyrdata, &key, NULL);
2442
0
    RUNTIME_CHECK(result == ISC_R_SUCCESS);
2443
2444
0
    dns_rdata_toregion(keyrdata, &r);
2445
0
    keytag = dst_region_computeid(&r);
2446
2447
0
    if (ds.key_tag != keytag || ds.algorithm != key.algorithm) {
2448
0
      continue;
2449
0
    }
2450
2451
0
    result = dns_ds_buildrdata(name, keyrdata, ds.digest_type, buf,
2452
0
             sizeof(buf), &newdsrdata);
2453
0
    if (result != ISC_R_SUCCESS) {
2454
0
      continue;
2455
0
    }
2456
2457
0
    if (dns_rdata_compare(dsrdata, &newdsrdata) == 0) {
2458
0
      return ISC_R_SUCCESS;
2459
0
    }
2460
0
  }
2461
2462
0
  return ISC_R_NOTFOUND;
2463
0
}