Coverage Report

Created: 2025-11-11 07:02

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