Coverage Report

Created: 2025-12-14 06:31

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