1 /* $NetBSD: keymgr.c,v 1.10 2023/06/26 22:03:00 christos Exp $ */
2
3 /*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * SPDX-License-Identifier: MPL-2.0
7 *
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this
10 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11 *
12 * See the COPYRIGHT file distributed with this work for additional
13 * information regarding copyright ownership.
14 */
15
16 /*! \file */
17
18 #include <inttypes.h>
19 #include <stdbool.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22
23 #include <isc/buffer.h>
24 #include <isc/dir.h>
25 #include <isc/mem.h>
26 #include <isc/print.h>
27 #include <isc/string.h>
28 #include <isc/util.h>
29
30 #include <dns/dnssec.h>
31 #include <dns/kasp.h>
32 #include <dns/keymgr.h>
33 #include <dns/keyvalues.h>
34 #include <dns/log.h>
35 #include <dns/result.h>
36
37 #include <dst/dst.h>
38 #include <dst/result.h>
39
40 #define RETERR(x) \
41 do { \
42 result = (x); \
43 if (result != ISC_R_SUCCESS) \
44 goto failure; \
45 } while (0)
46
47 /*
48 * Set key state to `target` state and change last changed
49 * to `time`, only if key state has not been set before.
50 */
51 #define INITIALIZE_STATE(key, state, timing, target, time) \
52 do { \
53 dst_key_state_t s; \
54 if (dst_key_getstate((key), (state), &s) == ISC_R_NOTFOUND) { \
55 dst_key_setstate((key), (state), (target)); \
56 dst_key_settime((key), (timing), time); \
57 } \
58 } while (0)
59
60 /* Shorter keywords for better readability. */
61 #define HIDDEN DST_KEY_STATE_HIDDEN
62 #define RUMOURED DST_KEY_STATE_RUMOURED
63 #define OMNIPRESENT DST_KEY_STATE_OMNIPRESENT
64 #define UNRETENTIVE DST_KEY_STATE_UNRETENTIVE
65 #define NA DST_KEY_STATE_NA
66
67 /* Quickly get key state timing metadata. */
68 #define NUM_KEYSTATES (DST_MAX_KEYSTATES)
69 static int keystatetimes[NUM_KEYSTATES] = { DST_TIME_DNSKEY, DST_TIME_ZRRSIG,
70 DST_TIME_KRRSIG, DST_TIME_DS };
71 /* Readable key state types and values. */
72 static const char *keystatetags[NUM_KEYSTATES] = { "DNSKEY", "ZRRSIG", "KRRSIG",
73 "DS" };
74 static const char *keystatestrings[4] = { "HIDDEN", "RUMOURED", "OMNIPRESENT",
75 "UNRETENTIVE" };
76
77 /*
78 * Print key role.
79 *
80 */
81 static const char *
keymgr_keyrole(dst_key_t * key)82 keymgr_keyrole(dst_key_t *key) {
83 bool ksk = false, zsk = false;
84 isc_result_t ret;
85 ret = dst_key_getbool(key, DST_BOOL_KSK, &ksk);
86 if (ret != ISC_R_SUCCESS) {
87 return ("UNKNOWN");
88 }
89 ret = dst_key_getbool(key, DST_BOOL_ZSK, &zsk);
90 if (ret != ISC_R_SUCCESS) {
91 return ("UNKNOWN");
92 }
93 if (ksk && zsk) {
94 return ("CSK");
95 } else if (ksk) {
96 return ("KSK");
97 } else if (zsk) {
98 return ("ZSK");
99 }
100 return ("NOSIGN");
101 }
102
103 /*
104 * Set the remove time on key given its retire time.
105 *
106 */
107 static void
keymgr_settime_remove(dns_dnsseckey_t * key,dns_kasp_t * kasp)108 keymgr_settime_remove(dns_dnsseckey_t *key, dns_kasp_t *kasp) {
109 isc_stdtime_t retire = 0, remove = 0, ksk_remove = 0, zsk_remove = 0;
110 bool zsk = false, ksk = false;
111 isc_result_t ret;
112
113 REQUIRE(key != NULL);
114 REQUIRE(key->key != NULL);
115
116 ret = dst_key_gettime(key->key, DST_TIME_INACTIVE, &retire);
117 if (ret != ISC_R_SUCCESS) {
118 return;
119 }
120
121 ret = dst_key_getbool(key->key, DST_BOOL_ZSK, &zsk);
122 if (ret == ISC_R_SUCCESS && zsk) {
123 /* ZSK: Iret = Dsgn + Dprp + TTLsig */
124 zsk_remove = retire + dns_kasp_zonemaxttl(kasp) +
125 dns_kasp_zonepropagationdelay(kasp) +
126 dns_kasp_retiresafety(kasp) +
127 dns_kasp_signdelay(kasp);
128 }
129 ret = dst_key_getbool(key->key, DST_BOOL_KSK, &ksk);
130 if (ret == ISC_R_SUCCESS && ksk) {
131 /* KSK: Iret = DprpP + TTLds */
132 ksk_remove = retire + dns_kasp_dsttl(kasp) +
133 dns_kasp_parentpropagationdelay(kasp) +
134 dns_kasp_retiresafety(kasp);
135 }
136
137 remove = ksk_remove > zsk_remove ? ksk_remove : zsk_remove;
138 dst_key_settime(key->key, DST_TIME_DELETE, remove);
139 }
140
141 /*
142 * Set the SyncPublish time (when the DS may be submitted to the parent)
143 *
144 */
145 static void
keymgr_settime_syncpublish(dns_dnsseckey_t * key,dns_kasp_t * kasp,bool first)146 keymgr_settime_syncpublish(dns_dnsseckey_t *key, dns_kasp_t *kasp, bool first) {
147 isc_stdtime_t published, syncpublish;
148 bool ksk = false;
149 isc_result_t ret;
150
151 REQUIRE(key != NULL);
152 REQUIRE(key->key != NULL);
153
154 ret = dst_key_gettime(key->key, DST_TIME_PUBLISH, &published);
155 if (ret != ISC_R_SUCCESS) {
156 return;
157 }
158
159 ret = dst_key_getbool(key->key, DST_BOOL_KSK, &ksk);
160 if (ret != ISC_R_SUCCESS || !ksk) {
161 return;
162 }
163
164 syncpublish = published + dst_key_getttl(key->key) +
165 dns_kasp_zonepropagationdelay(kasp) +
166 dns_kasp_publishsafety(kasp);
167 if (first) {
168 /* Also need to wait until the signatures are omnipresent. */
169 isc_stdtime_t zrrsig_present;
170 zrrsig_present = published + dns_kasp_zonemaxttl(kasp) +
171 dns_kasp_zonepropagationdelay(kasp) +
172 dns_kasp_publishsafety(kasp);
173 if (zrrsig_present > syncpublish) {
174 syncpublish = zrrsig_present;
175 }
176 }
177 dst_key_settime(key->key, DST_TIME_SYNCPUBLISH, syncpublish);
178 }
179
180 /*
181 * Calculate prepublication time of a successor key of 'key'.
182 * This function can have side effects:
183 * 1. If there is no active time set, which would be super weird, set it now.
184 * 2. If there is no published time set, also super weird, set it now.
185 * 3. If there is no syncpublished time set, set it now.
186 * 4. If the lifetime is not set, it will be set now.
187 * 5. If there should be a retire time and it is not set, it will be set now.
188 * 6. The removed time is adjusted accordingly.
189 *
190 * This returns when the successor key needs to be published in the zone.
191 * A special value of 0 means there is no need for a successor.
192 *
193 */
194 static isc_stdtime_t
keymgr_prepublication_time(dns_dnsseckey_t * key,dns_kasp_t * kasp,uint32_t lifetime,isc_stdtime_t now)195 keymgr_prepublication_time(dns_dnsseckey_t *key, dns_kasp_t *kasp,
196 uint32_t lifetime, isc_stdtime_t now) {
197 isc_result_t ret;
198 isc_stdtime_t active, retire, pub, prepub;
199 bool zsk = false, ksk = false;
200
201 REQUIRE(key != NULL);
202 REQUIRE(key->key != NULL);
203
204 active = 0;
205 pub = 0;
206 retire = 0;
207
208 /*
209 * An active key must have publish and activate timing
210 * metadata.
211 */
212 ret = dst_key_gettime(key->key, DST_TIME_ACTIVATE, &active);
213 if (ret != ISC_R_SUCCESS) {
214 /* Super weird, but if it happens, set it to now. */
215 dst_key_settime(key->key, DST_TIME_ACTIVATE, now);
216 active = now;
217 }
218 ret = dst_key_gettime(key->key, DST_TIME_PUBLISH, &pub);
219 if (ret != ISC_R_SUCCESS) {
220 /* Super weird, but if it happens, set it to now. */
221 dst_key_settime(key->key, DST_TIME_PUBLISH, now);
222 pub = now;
223 }
224
225 /*
226 * Calculate prepublication time.
227 */
228 prepub = dst_key_getttl(key->key) + dns_kasp_publishsafety(kasp) +
229 dns_kasp_zonepropagationdelay(kasp);
230 ret = dst_key_getbool(key->key, DST_BOOL_KSK, &ksk);
231 if (ret == ISC_R_SUCCESS && ksk) {
232 isc_stdtime_t syncpub;
233
234 /*
235 * Set PublishCDS if not set.
236 */
237 ret = dst_key_gettime(key->key, DST_TIME_SYNCPUBLISH, &syncpub);
238 if (ret != ISC_R_SUCCESS) {
239 uint32_t tag;
240 isc_stdtime_t syncpub1, syncpub2;
241
242 syncpub1 = pub + prepub;
243 syncpub2 = 0;
244 ret = dst_key_getnum(key->key, DST_NUM_PREDECESSOR,
245 &tag);
246 if (ret != ISC_R_SUCCESS) {
247 /*
248 * No predecessor, wait for zone to be
249 * completely signed.
250 */
251 syncpub2 = pub + dns_kasp_zonemaxttl(kasp) +
252 dns_kasp_publishsafety(kasp) +
253 dns_kasp_zonepropagationdelay(kasp);
254 }
255
256 syncpub = syncpub1 > syncpub2 ? syncpub1 : syncpub2;
257 dst_key_settime(key->key, DST_TIME_SYNCPUBLISH,
258 syncpub);
259 }
260 }
261
262 /*
263 * Not sure what to do when dst_key_getbool() fails here. Extending
264 * the prepublication time anyway is arguably the safest thing to do,
265 * so ignore the result code.
266 */
267 (void)dst_key_getbool(key->key, DST_BOOL_ZSK, &zsk);
268
269 ret = dst_key_gettime(key->key, DST_TIME_INACTIVE, &retire);
270 if (ret != ISC_R_SUCCESS) {
271 uint32_t klifetime = 0;
272
273 ret = dst_key_getnum(key->key, DST_NUM_LIFETIME, &klifetime);
274 if (ret != ISC_R_SUCCESS) {
275 dst_key_setnum(key->key, DST_NUM_LIFETIME, lifetime);
276 klifetime = lifetime;
277 }
278 if (klifetime == 0) {
279 /*
280 * No inactive time and no lifetime,
281 * so no need to start a rollover.
282 */
283 return (0);
284 }
285
286 retire = active + klifetime;
287 dst_key_settime(key->key, DST_TIME_INACTIVE, retire);
288 }
289
290 /*
291 * Update remove time.
292 */
293 keymgr_settime_remove(key, kasp);
294
295 /*
296 * Publish successor 'prepub' time before the 'retire' time of 'key'.
297 */
298 if (prepub > retire) {
299 /* We should have already prepublished the new key. */
300 return (now);
301 }
302 return (retire - prepub);
303 }
304
305 static void
keymgr_key_retire(dns_dnsseckey_t * key,dns_kasp_t * kasp,isc_stdtime_t now)306 keymgr_key_retire(dns_dnsseckey_t *key, dns_kasp_t *kasp, isc_stdtime_t now) {
307 char keystr[DST_KEY_FORMATSIZE];
308 isc_result_t ret;
309 isc_stdtime_t retire;
310 dst_key_state_t s;
311 bool ksk = false, zsk = false;
312
313 REQUIRE(key != NULL);
314 REQUIRE(key->key != NULL);
315
316 /* This key wants to retire and hide in a corner. */
317 ret = dst_key_gettime(key->key, DST_TIME_INACTIVE, &retire);
318 if (ret != ISC_R_SUCCESS || (retire > now)) {
319 dst_key_settime(key->key, DST_TIME_INACTIVE, now);
320 }
321 dst_key_setstate(key->key, DST_KEY_GOAL, HIDDEN);
322 keymgr_settime_remove(key, kasp);
323
324 /* This key may not have key states set yet. Pretend as if they are
325 * in the OMNIPRESENT state.
326 */
327 if (dst_key_getstate(key->key, DST_KEY_DNSKEY, &s) != ISC_R_SUCCESS) {
328 dst_key_setstate(key->key, DST_KEY_DNSKEY, OMNIPRESENT);
329 dst_key_settime(key->key, DST_TIME_DNSKEY, now);
330 }
331
332 ret = dst_key_getbool(key->key, DST_BOOL_KSK, &ksk);
333 if (ret == ISC_R_SUCCESS && ksk) {
334 if (dst_key_getstate(key->key, DST_KEY_KRRSIG, &s) !=
335 ISC_R_SUCCESS)
336 {
337 dst_key_setstate(key->key, DST_KEY_KRRSIG, OMNIPRESENT);
338 dst_key_settime(key->key, DST_TIME_KRRSIG, now);
339 }
340 if (dst_key_getstate(key->key, DST_KEY_DS, &s) != ISC_R_SUCCESS)
341 {
342 dst_key_setstate(key->key, DST_KEY_DS, OMNIPRESENT);
343 dst_key_settime(key->key, DST_TIME_DS, now);
344 }
345 }
346 ret = dst_key_getbool(key->key, DST_BOOL_ZSK, &zsk);
347 if (ret == ISC_R_SUCCESS && zsk) {
348 if (dst_key_getstate(key->key, DST_KEY_ZRRSIG, &s) !=
349 ISC_R_SUCCESS)
350 {
351 dst_key_setstate(key->key, DST_KEY_ZRRSIG, OMNIPRESENT);
352 dst_key_settime(key->key, DST_TIME_ZRRSIG, now);
353 }
354 }
355
356 dst_key_format(key->key, keystr, sizeof(keystr));
357 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_DNSSEC,
358 ISC_LOG_INFO, "keymgr: retire DNSKEY %s (%s)", keystr,
359 keymgr_keyrole(key->key));
360 }
361
362 /*
363 * Check if a dnsseckey matches kasp key configuration. A dnsseckey matches
364 * if it has the same algorithm and size, and if it has the same role as the
365 * kasp key configuration.
366 *
367 */
368 static bool
keymgr_dnsseckey_kaspkey_match(dns_dnsseckey_t * dkey,dns_kasp_key_t * kkey)369 keymgr_dnsseckey_kaspkey_match(dns_dnsseckey_t *dkey, dns_kasp_key_t *kkey) {
370 dst_key_t *key;
371 isc_result_t ret;
372 bool role = false;
373
374 REQUIRE(dkey != NULL);
375 REQUIRE(kkey != NULL);
376
377 key = dkey->key;
378
379 /* Matching algorithms? */
380 if (dst_key_alg(key) != dns_kasp_key_algorithm(kkey)) {
381 return (false);
382 }
383 /* Matching length? */
384 if (dst_key_size(key) != dns_kasp_key_size(kkey)) {
385 return (false);
386 }
387 /* Matching role? */
388 ret = dst_key_getbool(key, DST_BOOL_KSK, &role);
389 if (ret != ISC_R_SUCCESS || role != dns_kasp_key_ksk(kkey)) {
390 return (false);
391 }
392 ret = dst_key_getbool(key, DST_BOOL_ZSK, &role);
393 if (ret != ISC_R_SUCCESS || role != dns_kasp_key_zsk(kkey)) {
394 return (false);
395 }
396
397 /* Found a match. */
398 return (true);
399 }
400
401 static bool
keymgr_keyid_conflict(dst_key_t * newkey,dns_dnsseckeylist_t * keys)402 keymgr_keyid_conflict(dst_key_t *newkey, dns_dnsseckeylist_t *keys) {
403 uint16_t id = dst_key_id(newkey);
404 uint32_t rid = dst_key_rid(newkey);
405 uint32_t alg = dst_key_alg(newkey);
406
407 for (dns_dnsseckey_t *dkey = ISC_LIST_HEAD(*keys); dkey != NULL;
408 dkey = ISC_LIST_NEXT(dkey, link))
409 {
410 if (dst_key_alg(dkey->key) != alg) {
411 continue;
412 }
413 if (dst_key_id(dkey->key) == id ||
414 dst_key_rid(dkey->key) == id ||
415 dst_key_id(dkey->key) == rid ||
416 dst_key_rid(dkey->key) == rid)
417 {
418 return (true);
419 }
420 }
421 return (false);
422 }
423
424 /*
425 * Create a new key for 'origin' given the kasp key configuration 'kkey'.
426 * This will check for key id collisions with keys in 'keylist'.
427 * The created key will be stored in 'dst_key'.
428 *
429 */
430 static isc_result_t
keymgr_createkey(dns_kasp_key_t * kkey,const dns_name_t * origin,dns_rdataclass_t rdclass,isc_mem_t * mctx,dns_dnsseckeylist_t * keylist,dns_dnsseckeylist_t * newkeys,dst_key_t ** dst_key)431 keymgr_createkey(dns_kasp_key_t *kkey, const dns_name_t *origin,
432 dns_rdataclass_t rdclass, isc_mem_t *mctx,
433 dns_dnsseckeylist_t *keylist, dns_dnsseckeylist_t *newkeys,
434 dst_key_t **dst_key) {
435 bool conflict = false;
436 int keyflags = DNS_KEYOWNER_ZONE;
437 isc_result_t result = ISC_R_SUCCESS;
438 dst_key_t *newkey = NULL;
439
440 do {
441 uint32_t algo = dns_kasp_key_algorithm(kkey);
442 int size = dns_kasp_key_size(kkey);
443
444 if (dns_kasp_key_ksk(kkey)) {
445 keyflags |= DNS_KEYFLAG_KSK;
446 }
447 RETERR(dst_key_generate(origin, algo, size, 0, keyflags,
448 DNS_KEYPROTO_DNSSEC, rdclass, mctx,
449 &newkey, NULL));
450
451 /* Key collision? */
452 conflict = keymgr_keyid_conflict(newkey, keylist);
453 if (!conflict) {
454 conflict = keymgr_keyid_conflict(newkey, newkeys);
455 }
456 if (conflict) {
457 /* Try again. */
458 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
459 DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
460 "keymgr: key collision id %d",
461 dst_key_id(newkey));
462 dst_key_free(&newkey);
463 }
464 } while (conflict);
465
466 INSIST(!conflict);
467 dst_key_setnum(newkey, DST_NUM_LIFETIME, dns_kasp_key_lifetime(kkey));
468 dst_key_setbool(newkey, DST_BOOL_KSK, dns_kasp_key_ksk(kkey));
469 dst_key_setbool(newkey, DST_BOOL_ZSK, dns_kasp_key_zsk(kkey));
470 *dst_key = newkey;
471 return (ISC_R_SUCCESS);
472
473 failure:
474 return (result);
475 }
476
477 /*
478 * Return the desired state for this record 'type'. The desired state depends
479 * on whether the key wants to be active, or wants to retire. This implements
480 * the edges of our state machine:
481 *
482 * ----> OMNIPRESENT ----
483 * | |
484 * | \|/
485 *
486 * RUMOURED <----> UNRETENTIVE
487 *
488 * /|\ |
489 * | |
490 * ---- HIDDEN <----
491 *
492 * A key that wants to be active eventually wants to have its record types
493 * in the OMNIPRESENT state (that is, all resolvers that know about these
494 * type of records know about these records specifically).
495 *
496 * A key that wants to be retired eventually wants to have its record types
497 * in the HIDDEN state (that is, all resolvers that know about these type
498 * of records specifically don't know about these records).
499 *
500 */
501 static dst_key_state_t
keymgr_desiredstate(dns_dnsseckey_t * key,dst_key_state_t state)502 keymgr_desiredstate(dns_dnsseckey_t *key, dst_key_state_t state) {
503 dst_key_state_t goal;
504
505 if (dst_key_getstate(key->key, DST_KEY_GOAL, &goal) != ISC_R_SUCCESS) {
506 /* No goal? No movement. */
507 return (state);
508 }
509
510 if (goal == HIDDEN) {
511 switch (state) {
512 case RUMOURED:
513 case OMNIPRESENT:
514 return (UNRETENTIVE);
515 case HIDDEN:
516 case UNRETENTIVE:
517 return (HIDDEN);
518 default:
519 return (state);
520 }
521 } else if (goal == OMNIPRESENT) {
522 switch (state) {
523 case RUMOURED:
524 case OMNIPRESENT:
525 return (OMNIPRESENT);
526 case HIDDEN:
527 case UNRETENTIVE:
528 return (RUMOURED);
529 default:
530 return (state);
531 }
532 }
533
534 /* Unknown goal. */
535 return (state);
536 }
537
538 /*
539 * Check if 'key' matches specific 'states'.
540 * A state in 'states' that is NA matches any state.
541 * A state in 'states' that is HIDDEN also matches if the state is not set.
542 * If 'next_state' is set (not NA), we are pretending as if record 'type' of
543 * 'subject' key already transitioned to the 'next state'.
544 *
545 */
546 static bool
keymgr_key_match_state(dst_key_t * key,dst_key_t * subject,int type,dst_key_state_t next_state,dst_key_state_t states[NUM_KEYSTATES])547 keymgr_key_match_state(dst_key_t *key, dst_key_t *subject, int type,
548 dst_key_state_t next_state,
549 dst_key_state_t states[NUM_KEYSTATES]) {
550 REQUIRE(key != NULL);
551
552 for (int i = 0; i < NUM_KEYSTATES; i++) {
553 dst_key_state_t state;
554 if (states[i] == NA) {
555 continue;
556 }
557 if (next_state != NA && i == type &&
558 dst_key_id(key) == dst_key_id(subject))
559 {
560 /* Check next state rather than current state. */
561 state = next_state;
562 } else if (dst_key_getstate(key, i, &state) != ISC_R_SUCCESS) {
563 /* This is fine only if expected state is HIDDEN. */
564 if (states[i] != HIDDEN) {
565 return (false);
566 }
567 continue;
568 }
569 if (state != states[i]) {
570 return (false);
571 }
572 }
573 /* Match. */
574 return (true);
575 }
576
577 /*
578 * Key d directly depends on k if d is the direct predecessor of k.
579 */
580 static bool
keymgr_direct_dep(dst_key_t * d,dst_key_t * k)581 keymgr_direct_dep(dst_key_t *d, dst_key_t *k) {
582 uint32_t s, p;
583
584 if (dst_key_getnum(d, DST_NUM_SUCCESSOR, &s) != ISC_R_SUCCESS) {
585 return (false);
586 }
587 if (dst_key_getnum(k, DST_NUM_PREDECESSOR, &p) != ISC_R_SUCCESS) {
588 return (false);
589 }
590 return (dst_key_id(d) == p && dst_key_id(k) == s);
591 }
592
593 /*
594 * Determine which key (if any) has a dependency on k.
595 */
596 static bool
keymgr_dep(dst_key_t * k,dns_dnsseckeylist_t * keyring,uint32_t * dep)597 keymgr_dep(dst_key_t *k, dns_dnsseckeylist_t *keyring, uint32_t *dep) {
598 for (dns_dnsseckey_t *d = ISC_LIST_HEAD(*keyring); d != NULL;
599 d = ISC_LIST_NEXT(d, link))
600 {
601 /*
602 * Check if k is a direct successor of d, e.g. d depends on k.
603 */
604 if (keymgr_direct_dep(d->key, k)) {
605 if (dep != NULL) {
606 *dep = dst_key_id(d->key);
607 }
608 return (true);
609 }
610 }
611 return (false);
612 }
613
614 /*
615 * Check if a 'z' is a successor of 'x'.
616 * This implements Equation(2) of "Flexible and Robust Key Rollover".
617 */
618 static bool
keymgr_key_is_successor(dst_key_t * x,dst_key_t * z,dst_key_t * key,int type,dst_key_state_t next_state,dns_dnsseckeylist_t * keyring)619 keymgr_key_is_successor(dst_key_t *x, dst_key_t *z, dst_key_t *key, int type,
620 dst_key_state_t next_state,
621 dns_dnsseckeylist_t *keyring) {
622 uint32_t dep_x;
623 uint32_t dep_z;
624
625 /*
626 * The successor relation requires that the predecessor key must not
627 * have any other keys relying on it. In other words, there must be
628 * nothing depending on x.
629 */
630 if (keymgr_dep(x, keyring, &dep_x)) {
631 return (false);
632 }
633
634 /*
635 * If there is no keys relying on key z, then z is not a successor.
636 */
637 if (!keymgr_dep(z, keyring, &dep_z)) {
638 return (false);
639 }
640
641 /*
642 * x depends on z, thus key z is a direct successor of key x.
643 */
644 if (dst_key_id(x) == dep_z) {
645 return (true);
646 }
647
648 /*
649 * It is possible to roll keys faster than the time required to finish
650 * the rollover procedure. For example, consider the keys x, y, z.
651 * Key x is currently published and is going to be replaced by y. The
652 * DNSKEY for x is removed from the zone and at the same moment the
653 * DNSKEY for y is introduced. Key y is a direct dependency for key x
654 * and is therefore the successor of x. However, before the new DNSKEY
655 * has been propagated, key z will replace key y. The DNSKEY for y is
656 * removed and moves into the same state as key x. Key y now directly
657 * depends on key z, and key z will be a new successor key for x.
658 */
659 dst_key_state_t zst[NUM_KEYSTATES] = { NA, NA, NA, NA };
660 for (int i = 0; i < NUM_KEYSTATES; i++) {
661 dst_key_state_t state;
662 if (dst_key_getstate(z, i, &state) != ISC_R_SUCCESS) {
663 continue;
664 }
665 zst[i] = state;
666 }
667
668 for (dns_dnsseckey_t *y = ISC_LIST_HEAD(*keyring); y != NULL;
669 y = ISC_LIST_NEXT(y, link))
670 {
671 if (dst_key_id(y->key) == dst_key_id(z)) {
672 continue;
673 }
674
675 if (dst_key_id(y->key) != dep_z) {
676 continue;
677 }
678 /*
679 * This is another key y, that depends on key z. It may be
680 * part of the successor relation if the key states match
681 * those of key z.
682 */
683
684 if (keymgr_key_match_state(y->key, key, type, next_state, zst))
685 {
686 /*
687 * If y is a successor of x, then z is also a
688 * successor of x.
689 */
690 return (keymgr_key_is_successor(x, y->key, key, type,
691 next_state, keyring));
692 }
693 }
694
695 return (false);
696 }
697
698 /*
699 * Check if a key exists in 'keyring' that matches 'states'.
700 *
701 * If 'match_algorithms', the key must also match the algorithm of 'key'.
702 * If 'next_state' is not NA, we are actually looking for a key as if
703 * 'key' already transitioned to the next state.
704 * If 'check_successor', we also want to make sure there is a successor
705 * relationship with the found key that matches 'states2'.
706 */
707 static bool
keymgr_key_exists_with_state(dns_dnsseckeylist_t * keyring,dns_dnsseckey_t * key,int type,dst_key_state_t next_state,dst_key_state_t states[NUM_KEYSTATES],dst_key_state_t states2[NUM_KEYSTATES],bool check_successor,bool match_algorithms)708 keymgr_key_exists_with_state(dns_dnsseckeylist_t *keyring, dns_dnsseckey_t *key,
709 int type, dst_key_state_t next_state,
710 dst_key_state_t states[NUM_KEYSTATES],
711 dst_key_state_t states2[NUM_KEYSTATES],
712 bool check_successor, bool match_algorithms) {
713 for (dns_dnsseckey_t *dkey = ISC_LIST_HEAD(*keyring); dkey != NULL;
714 dkey = ISC_LIST_NEXT(dkey, link))
715 {
716 if (match_algorithms &&
717 (dst_key_alg(dkey->key) != dst_key_alg(key->key)))
718 {
719 continue;
720 }
721
722 if (!keymgr_key_match_state(dkey->key, key->key, type,
723 next_state, states))
724 {
725 continue;
726 }
727
728 /* Found a match. */
729 if (!check_successor) {
730 return (true);
731 }
732
733 /*
734 * We have to make sure that the key we are checking, also
735 * has a successor relationship with another key.
736 */
737 for (dns_dnsseckey_t *skey = ISC_LIST_HEAD(*keyring);
738 skey != NULL; skey = ISC_LIST_NEXT(skey, link))
739 {
740 if (skey == dkey) {
741 continue;
742 }
743
744 if (!keymgr_key_match_state(skey->key, key->key, type,
745 next_state, states2))
746 {
747 continue;
748 }
749
750 /*
751 * Found a possible successor, check.
752 */
753 if (keymgr_key_is_successor(dkey->key, skey->key,
754 key->key, type, next_state,
755 keyring))
756 {
757 return (true);
758 }
759 }
760 }
761 /* No match. */
762 return (false);
763 }
764
765 /*
766 * Check if a key has a successor.
767 */
768 static bool
keymgr_key_has_successor(dns_dnsseckey_t * predecessor,dns_dnsseckeylist_t * keyring)769 keymgr_key_has_successor(dns_dnsseckey_t *predecessor,
770 dns_dnsseckeylist_t *keyring) {
771 for (dns_dnsseckey_t *successor = ISC_LIST_HEAD(*keyring);
772 successor != NULL; successor = ISC_LIST_NEXT(successor, link))
773 {
774 if (keymgr_direct_dep(predecessor->key, successor->key)) {
775 return (true);
776 }
777 }
778 return (false);
779 }
780
781 /*
782 * Check if all keys have their DS hidden. If not, then there must be at
783 * least one key with an OMNIPRESENT DNSKEY.
784 *
785 * If 'next_state' is not NA, we are actually looking for a key as if
786 * 'key' already transitioned to the next state.
787 * If 'match_algorithms', only consider keys with same algorithm of 'key'.
788 *
789 */
790 static bool
keymgr_ds_hidden_or_chained(dns_dnsseckeylist_t * keyring,dns_dnsseckey_t * key,int type,dst_key_state_t next_state,bool match_algorithms,bool must_be_hidden)791 keymgr_ds_hidden_or_chained(dns_dnsseckeylist_t *keyring, dns_dnsseckey_t *key,
792 int type, dst_key_state_t next_state,
793 bool match_algorithms, bool must_be_hidden) {
794 /* (3e) */
795 dst_key_state_t dnskey_chained[NUM_KEYSTATES] = { OMNIPRESENT, NA,
796 OMNIPRESENT, NA };
797 dst_key_state_t ds_hidden[NUM_KEYSTATES] = { NA, NA, NA, HIDDEN };
798 /* successor n/a */
799 dst_key_state_t na[NUM_KEYSTATES] = { NA, NA, NA, NA };
800
801 for (dns_dnsseckey_t *dkey = ISC_LIST_HEAD(*keyring); dkey != NULL;
802 dkey = ISC_LIST_NEXT(dkey, link))
803 {
804 if (match_algorithms &&
805 (dst_key_alg(dkey->key) != dst_key_alg(key->key)))
806 {
807 continue;
808 }
809
810 if (keymgr_key_match_state(dkey->key, key->key, type,
811 next_state, ds_hidden))
812 {
813 /* This key has its DS hidden. */
814 continue;
815 }
816
817 if (must_be_hidden) {
818 return (false);
819 }
820
821 /*
822 * This key does not have its DS hidden. There must be at
823 * least one key with the same algorithm that provides a
824 * chain of trust (can be this key).
825 */
826 if (keymgr_key_match_state(dkey->key, key->key, type,
827 next_state, dnskey_chained))
828 {
829 /* This DNSKEY and KRRSIG are OMNIPRESENT. */
830 continue;
831 }
832
833 /*
834 * Perhaps another key provides a chain of trust.
835 */
836 dnskey_chained[DST_KEY_DS] = OMNIPRESENT;
837 if (!keymgr_key_exists_with_state(keyring, key, type,
838 next_state, dnskey_chained,
839 na, false, match_algorithms))
840 {
841 /* There is no chain of trust. */
842 return (false);
843 }
844 }
845 /* All good. */
846 return (true);
847 }
848
849 /*
850 * Check if all keys have their DNSKEY hidden. If not, then there must be at
851 * least one key with an OMNIPRESENT ZRRSIG.
852 *
853 * If 'next_state' is not NA, we are actually looking for a key as if
854 * 'key' already transitioned to the next state.
855 * If 'match_algorithms', only consider keys with same algorithm of 'key'.
856 *
857 */
858 static bool
keymgr_dnskey_hidden_or_chained(dns_dnsseckeylist_t * keyring,dns_dnsseckey_t * key,int type,dst_key_state_t next_state,bool match_algorithms)859 keymgr_dnskey_hidden_or_chained(dns_dnsseckeylist_t *keyring,
860 dns_dnsseckey_t *key, int type,
861 dst_key_state_t next_state,
862 bool match_algorithms) {
863 /* (3i) */
864 dst_key_state_t rrsig_chained[NUM_KEYSTATES] = { OMNIPRESENT,
865 OMNIPRESENT, NA, NA };
866 dst_key_state_t dnskey_hidden[NUM_KEYSTATES] = { HIDDEN, NA, NA, NA };
867 /* successor n/a */
868 dst_key_state_t na[NUM_KEYSTATES] = { NA, NA, NA, NA };
869
870 for (dns_dnsseckey_t *dkey = ISC_LIST_HEAD(*keyring); dkey != NULL;
871 dkey = ISC_LIST_NEXT(dkey, link))
872 {
873 if (match_algorithms &&
874 (dst_key_alg(dkey->key) != dst_key_alg(key->key)))
875 {
876 continue;
877 }
878
879 if (keymgr_key_match_state(dkey->key, key->key, type,
880 next_state, dnskey_hidden))
881 {
882 /* This key has its DNSKEY hidden. */
883 continue;
884 }
885
886 /*
887 * This key does not have its DNSKEY hidden. There must be at
888 * least one key with the same algorithm that has its RRSIG
889 * records OMNIPRESENT.
890 */
891 (void)dst_key_getstate(dkey->key, DST_KEY_DNSKEY,
892 &rrsig_chained[DST_KEY_DNSKEY]);
893 if (!keymgr_key_exists_with_state(keyring, key, type,
894 next_state, rrsig_chained, na,
895 false, match_algorithms))
896 {
897 /* There is no chain of trust. */
898 return (false);
899 }
900 }
901 /* All good. */
902 return (true);
903 }
904
905 /*
906 * Check for existence of DS.
907 *
908 */
909 static bool
keymgr_have_ds(dns_dnsseckeylist_t * keyring,dns_dnsseckey_t * key,int type,dst_key_state_t next_state,bool secure_to_insecure)910 keymgr_have_ds(dns_dnsseckeylist_t *keyring, dns_dnsseckey_t *key, int type,
911 dst_key_state_t next_state, bool secure_to_insecure) {
912 /* (3a) */
913 dst_key_state_t states[2][NUM_KEYSTATES] = {
914 /* DNSKEY, ZRRSIG, KRRSIG, DS */
915 { NA, NA, NA, OMNIPRESENT }, /* DS present */
916 { NA, NA, NA, RUMOURED } /* DS introducing */
917 };
918 /* successor n/a */
919 dst_key_state_t na[NUM_KEYSTATES] = { NA, NA, NA, NA };
920
921 /*
922 * Equation (3a):
923 * There is a key with the DS in either RUMOURD or OMNIPRESENT state.
924 */
925 return (keymgr_key_exists_with_state(keyring, key, type, next_state,
926 states[0], na, false, false) ||
927 keymgr_key_exists_with_state(keyring, key, type, next_state,
928 states[1], na, false, false) ||
929 (secure_to_insecure &&
930 keymgr_key_exists_with_state(keyring, key, type, next_state,
931 na, na, false, false)));
932 }
933
934 /*
935 * Check for existence of DNSKEY, or at least a good DNSKEY state.
936 * See equations what are good DNSKEY states.
937 *
938 */
939 static bool
keymgr_have_dnskey(dns_dnsseckeylist_t * keyring,dns_dnsseckey_t * key,int type,dst_key_state_t next_state)940 keymgr_have_dnskey(dns_dnsseckeylist_t *keyring, dns_dnsseckey_t *key, int type,
941 dst_key_state_t next_state) {
942 dst_key_state_t states[9][NUM_KEYSTATES] = {
943 /* DNSKEY, ZRRSIG, KRRSIG, DS */
944 { OMNIPRESENT, NA, OMNIPRESENT, OMNIPRESENT }, /* (3b) */
945
946 { OMNIPRESENT, NA, OMNIPRESENT, UNRETENTIVE }, /* (3c)p */
947 { OMNIPRESENT, NA, OMNIPRESENT, RUMOURED }, /* (3c)s */
948
949 { UNRETENTIVE, NA, UNRETENTIVE, OMNIPRESENT }, /* (3d)p */
950 { OMNIPRESENT, NA, UNRETENTIVE, OMNIPRESENT }, /* (3d)p */
951 { UNRETENTIVE, NA, OMNIPRESENT, OMNIPRESENT }, /* (3d)p */
952 { RUMOURED, NA, RUMOURED, OMNIPRESENT }, /* (3d)s */
953 { OMNIPRESENT, NA, RUMOURED, OMNIPRESENT }, /* (3d)s */
954 { RUMOURED, NA, OMNIPRESENT, OMNIPRESENT }, /* (3d)s */
955 };
956 /* successor n/a */
957 dst_key_state_t na[NUM_KEYSTATES] = { NA, NA, NA, NA };
958
959 return (
960 /*
961 * Equation (3b):
962 * There is a key with the same algorithm with its DNSKEY,
963 * KRRSIG and DS records in OMNIPRESENT state.
964 */
965 keymgr_key_exists_with_state(keyring, key, type, next_state,
966 states[0], na, false, true) ||
967 /*
968 * Equation (3c):
969 * There are two or more keys with an OMNIPRESENT DNSKEY and
970 * the DS records get swapped. These keys must be in a
971 * successor relation.
972 */
973 keymgr_key_exists_with_state(keyring, key, type, next_state,
974 states[1], states[2], true,
975 true) ||
976 /*
977 * Equation (3d):
978 * There are two or more keys with an OMNIPRESENT DS and
979 * the DNSKEY records and its KRRSIG records get swapped.
980 * These keys must be in a successor relation. Since the
981 * state for DNSKEY and KRRSIG move independently, we have
982 * to check all combinations for DNSKEY and KRRSIG in
983 * OMNIPRESENT/UNRETENTIVE state for the predecessor, and
984 * OMNIPRESENT/RUMOURED state for the successor.
985 */
986 keymgr_key_exists_with_state(keyring, key, type, next_state,
987 states[3], states[6], true,
988 true) ||
989 keymgr_key_exists_with_state(keyring, key, type, next_state,
990 states[3], states[7], true,
991 true) ||
992 keymgr_key_exists_with_state(keyring, key, type, next_state,
993 states[3], states[8], true,
994 true) ||
995 keymgr_key_exists_with_state(keyring, key, type, next_state,
996 states[4], states[6], true,
997 true) ||
998 keymgr_key_exists_with_state(keyring, key, type, next_state,
999 states[4], states[7], true,
1000 true) ||
1001 keymgr_key_exists_with_state(keyring, key, type, next_state,
1002 states[4], states[8], true,
1003 true) ||
1004 keymgr_key_exists_with_state(keyring, key, type, next_state,
1005 states[5], states[6], true,
1006 true) ||
1007 keymgr_key_exists_with_state(keyring, key, type, next_state,
1008 states[5], states[7], true,
1009 true) ||
1010 keymgr_key_exists_with_state(keyring, key, type, next_state,
1011 states[5], states[8], true,
1012 true) ||
1013 /*
1014 * Equation (3e):
1015 * The key may be in any state as long as all keys have their
1016 * DS HIDDEN, or when their DS is not HIDDEN, there must be a
1017 * key with its DS in the same state and its DNSKEY omnipresent.
1018 * In other words, if a DS record for the same algorithm is
1019 * is still available to some validators, there must be a
1020 * chain of trust for those validators.
1021 */
1022 keymgr_ds_hidden_or_chained(keyring, key, type, next_state,
1023 true, false));
1024 }
1025
1026 /*
1027 * Check for existence of RRSIG (zsk), or a good RRSIG state.
1028 * See equations what are good RRSIG states.
1029 *
1030 */
1031 static bool
keymgr_have_rrsig(dns_dnsseckeylist_t * keyring,dns_dnsseckey_t * key,int type,dst_key_state_t next_state)1032 keymgr_have_rrsig(dns_dnsseckeylist_t *keyring, dns_dnsseckey_t *key, int type,
1033 dst_key_state_t next_state) {
1034 dst_key_state_t states[11][NUM_KEYSTATES] = {
1035 /* DNSKEY, ZRRSIG, KRRSIG, DS */
1036 { OMNIPRESENT, OMNIPRESENT, NA, NA }, /* (3f) */
1037 { UNRETENTIVE, OMNIPRESENT, NA, NA }, /* (3g)p */
1038 { RUMOURED, OMNIPRESENT, NA, NA }, /* (3g)s */
1039 { OMNIPRESENT, UNRETENTIVE, NA, NA }, /* (3h)p */
1040 { OMNIPRESENT, RUMOURED, NA, NA }, /* (3h)s */
1041 };
1042 /* successor n/a */
1043 dst_key_state_t na[NUM_KEYSTATES] = { NA, NA, NA, NA };
1044
1045 return (
1046 /*
1047 * If all DS records are hidden than this rule can be ignored.
1048 */
1049 keymgr_ds_hidden_or_chained(keyring, key, type, next_state,
1050 true, true) ||
1051 /*
1052 * Equation (3f):
1053 * There is a key with the same algorithm with its DNSKEY and
1054 * ZRRSIG records in OMNIPRESENT state.
1055 */
1056 keymgr_key_exists_with_state(keyring, key, type, next_state,
1057 states[0], na, false, true) ||
1058 /*
1059 * Equation (3g):
1060 * There are two or more keys with OMNIPRESENT ZRRSIG
1061 * records and the DNSKEY records get swapped. These keys
1062 * must be in a successor relation.
1063 */
1064 keymgr_key_exists_with_state(keyring, key, type, next_state,
1065 states[1], states[2], true,
1066 true) ||
1067 /*
1068 * Equation (3h):
1069 * There are two or more keys with an OMNIPRESENT DNSKEY
1070 * and the ZRRSIG records get swapped. These keys must be in
1071 * a successor relation.
1072 */
1073 keymgr_key_exists_with_state(keyring, key, type, next_state,
1074 states[3], states[4], true,
1075 true) ||
1076 /*
1077 * Equation (3i):
1078 * If no DNSKEYs are published, the state of the signatures is
1079 * irrelevant. In case a DNSKEY is published however, there
1080 * must be a path that can be validated from there.
1081 */
1082 keymgr_dnskey_hidden_or_chained(keyring, key, type, next_state,
1083 true));
1084 }
1085
1086 /*
1087 * Check if a transition in the state machine is allowed by the policy.
1088 * This means when we do rollovers, we want to follow the rules of the
1089 * 1. Pre-publish rollover method (in case of a ZSK)
1090 * - First introduce the DNSKEY record.
1091 * - Only if the DNSKEY record is OMNIPRESENT, introduce ZRRSIG records.
1092 *
1093 * 2. Double-KSK rollover method (in case of a KSK)
1094 * - First introduce the DNSKEY record, as well as the KRRSIG records.
1095 * - Only if the DNSKEY record is OMNIPRESENT, suggest to introduce the DS.
1096 */
1097 static bool
keymgr_policy_approval(dns_dnsseckeylist_t * keyring,dns_dnsseckey_t * key,int type,dst_key_state_t next)1098 keymgr_policy_approval(dns_dnsseckeylist_t *keyring, dns_dnsseckey_t *key,
1099 int type, dst_key_state_t next) {
1100 dst_key_state_t dnskeystate = HIDDEN;
1101 dst_key_state_t ksk_present[NUM_KEYSTATES] = { OMNIPRESENT, NA,
1102 OMNIPRESENT,
1103 OMNIPRESENT };
1104 dst_key_state_t ds_rumoured[NUM_KEYSTATES] = { OMNIPRESENT, NA,
1105 OMNIPRESENT, RUMOURED };
1106 dst_key_state_t ds_retired[NUM_KEYSTATES] = { OMNIPRESENT, NA,
1107 OMNIPRESENT,
1108 UNRETENTIVE };
1109 dst_key_state_t ksk_rumoured[NUM_KEYSTATES] = { RUMOURED, NA, NA,
1110 OMNIPRESENT };
1111 dst_key_state_t ksk_retired[NUM_KEYSTATES] = { UNRETENTIVE, NA, NA,
1112 OMNIPRESENT };
1113 /* successor n/a */
1114 dst_key_state_t na[NUM_KEYSTATES] = { NA, NA, NA, NA };
1115
1116 if (next != RUMOURED) {
1117 /*
1118 * Local policy only adds an extra barrier on transitions to
1119 * the RUMOURED state.
1120 */
1121 return (true);
1122 }
1123
1124 switch (type) {
1125 case DST_KEY_DNSKEY:
1126 /* No restrictions. */
1127 return (true);
1128 case DST_KEY_ZRRSIG:
1129 /* Make sure the DNSKEY record is OMNIPRESENT. */
1130 (void)dst_key_getstate(key->key, DST_KEY_DNSKEY, &dnskeystate);
1131 if (dnskeystate == OMNIPRESENT) {
1132 return (true);
1133 }
1134 /*
1135 * Or are we introducing a new key for this algorithm? Because
1136 * in that case allow publishing the RRSIG records before the
1137 * DNSKEY.
1138 */
1139 return (!(keymgr_key_exists_with_state(keyring, key, type, next,
1140 ksk_present, na, false,
1141 true) ||
1142 keymgr_key_exists_with_state(keyring, key, type, next,
1143 ds_retired, ds_rumoured,
1144 true, true) ||
1145 keymgr_key_exists_with_state(
1146 keyring, key, type, next, ksk_retired,
1147 ksk_rumoured, true, true)));
1148 case DST_KEY_KRRSIG:
1149 /* Only introduce if the DNSKEY is also introduced. */
1150 (void)dst_key_getstate(key->key, DST_KEY_DNSKEY, &dnskeystate);
1151 return (dnskeystate != HIDDEN);
1152 case DST_KEY_DS:
1153 /* Make sure the DNSKEY record is OMNIPRESENT. */
1154 (void)dst_key_getstate(key->key, DST_KEY_DNSKEY, &dnskeystate);
1155 return (dnskeystate == OMNIPRESENT);
1156 default:
1157 return (false);
1158 }
1159 }
1160
1161 /*
1162 * Check if a transition in the state machine is DNSSEC safe.
1163 * This implements Equation(1) of "Flexible and Robust Key Rollover".
1164 *
1165 */
1166 static bool
keymgr_transition_allowed(dns_dnsseckeylist_t * keyring,dns_dnsseckey_t * key,int type,dst_key_state_t next_state,bool secure_to_insecure)1167 keymgr_transition_allowed(dns_dnsseckeylist_t *keyring, dns_dnsseckey_t *key,
1168 int type, dst_key_state_t next_state,
1169 bool secure_to_insecure) {
1170 /* Debug logging. */
1171 if (isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(1))) {
1172 bool rule1a, rule1b, rule2a, rule2b, rule3a, rule3b;
1173 char keystr[DST_KEY_FORMATSIZE];
1174 dst_key_format(key->key, keystr, sizeof(keystr));
1175 rule1a = keymgr_have_ds(keyring, key, type, NA,
1176 secure_to_insecure);
1177 rule1b = keymgr_have_ds(keyring, key, type, next_state,
1178 secure_to_insecure);
1179 rule2a = keymgr_have_dnskey(keyring, key, type, NA);
1180 rule2b = keymgr_have_dnskey(keyring, key, type, next_state);
1181 rule3a = keymgr_have_rrsig(keyring, key, type, NA);
1182 rule3b = keymgr_have_rrsig(keyring, key, type, next_state);
1183 isc_log_write(
1184 dns_lctx, DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_DNSSEC,
1185 ISC_LOG_DEBUG(1),
1186 "keymgr: dnssec evaluation of %s %s record %s: "
1187 "rule1=(~%s or %s) rule2=(~%s or %s) "
1188 "rule3=(~%s or %s)",
1189 keymgr_keyrole(key->key), keystr, keystatetags[type],
1190 rule1a ? "true" : "false", rule1b ? "true" : "false",
1191 rule2a ? "true" : "false", rule2b ? "true" : "false",
1192 rule3a ? "true" : "false", rule3b ? "true" : "false");
1193 }
1194
1195 return (
1196 /*
1197 * Rule 1: There must be a DS at all times.
1198 * First check the current situation: if the rule check fails,
1199 * we allow the transition to attempt to move us out of the
1200 * invalid state. If the rule check passes, also check if
1201 * the next state is also still a valid situation.
1202 */
1203 (!keymgr_have_ds(keyring, key, type, NA, secure_to_insecure) ||
1204 keymgr_have_ds(keyring, key, type, next_state,
1205 secure_to_insecure)) &&
1206 /*
1207 * Rule 2: There must be a DNSKEY at all times. Again, first
1208 * check the current situation, then assess the next state.
1209 */
1210 (!keymgr_have_dnskey(keyring, key, type, NA) ||
1211 keymgr_have_dnskey(keyring, key, type, next_state)) &&
1212 /*
1213 * Rule 3: There must be RRSIG records at all times. Again,
1214 * first check the current situation, then assess the next
1215 * state.
1216 */
1217 (!keymgr_have_rrsig(keyring, key, type, NA) ||
1218 keymgr_have_rrsig(keyring, key, type, next_state)));
1219 }
1220
1221 /*
1222 * Calculate the time when it is safe to do the next transition.
1223 *
1224 */
1225 static void
keymgr_transition_time(dns_dnsseckey_t * key,int type,dst_key_state_t next_state,dns_kasp_t * kasp,isc_stdtime_t now,isc_stdtime_t * when)1226 keymgr_transition_time(dns_dnsseckey_t *key, int type,
1227 dst_key_state_t next_state, dns_kasp_t *kasp,
1228 isc_stdtime_t now, isc_stdtime_t *when) {
1229 isc_result_t ret;
1230 isc_stdtime_t lastchange, dstime, nexttime = now;
1231
1232 /*
1233 * No need to wait if we move things into an uncertain state.
1234 */
1235 if (next_state == RUMOURED || next_state == UNRETENTIVE) {
1236 *when = now;
1237 return;
1238 }
1239
1240 ret = dst_key_gettime(key->key, keystatetimes[type], &lastchange);
1241 if (ret != ISC_R_SUCCESS) {
1242 /* No last change, for safety purposes let's set it to now. */
1243 dst_key_settime(key->key, keystatetimes[type], now);
1244 lastchange = now;
1245 }
1246
1247 switch (type) {
1248 case DST_KEY_DNSKEY:
1249 case DST_KEY_KRRSIG:
1250 switch (next_state) {
1251 case OMNIPRESENT:
1252 /*
1253 * RFC 7583: The publication interval (Ipub) is the
1254 * amount of time that must elapse after the
1255 * publication of a DNSKEY (plus RRSIG (KSK)) before
1256 * it can be assumed that any resolvers that have the
1257 * relevant RRset cached have a copy of the new
1258 * information. This is the sum of the propagation
1259 * delay (Dprp) and the DNSKEY TTL (TTLkey). This
1260 * translates to zone-propagation-delay + dnskey-ttl.
1261 * We will also add the publish-safety interval.
1262 */
1263 nexttime = lastchange + dst_key_getttl(key->key) +
1264 dns_kasp_zonepropagationdelay(kasp) +
1265 dns_kasp_publishsafety(kasp);
1266 break;
1267 case HIDDEN:
1268 /*
1269 * Same as OMNIPRESENT but without the publish-safety
1270 * interval.
1271 */
1272 nexttime = lastchange + dst_key_getttl(key->key) +
1273 dns_kasp_zonepropagationdelay(kasp);
1274 break;
1275 default:
1276 nexttime = now;
1277 break;
1278 }
1279 break;
1280 case DST_KEY_ZRRSIG:
1281 switch (next_state) {
1282 case OMNIPRESENT:
1283 case HIDDEN:
1284 /*
1285 * RFC 7583: The retire interval (Iret) is the amount
1286 * of time that must elapse after a DNSKEY or
1287 * associated data enters the retire state for any
1288 * dependent information (RRSIG ZSK) to be purged from
1289 * validating resolver caches. This is defined as:
1290 *
1291 * Iret = Dsgn + Dprp + TTLsig
1292 *
1293 * Where Dsgn is the Dsgn is the delay needed to
1294 * ensure that all existing RRsets have been re-signed
1295 * with the new key, Dprp is the propagation delay and
1296 * TTLsig is the maximum TTL of all zone RRSIG
1297 * records. This translates to:
1298 *
1299 * Dsgn + zone-propagation-delay + max-zone-ttl.
1300 *
1301 * We will also add the retire-safety interval.
1302 */
1303 nexttime = lastchange + dns_kasp_zonemaxttl(kasp) +
1304 dns_kasp_zonepropagationdelay(kasp) +
1305 dns_kasp_retiresafety(kasp);
1306 /*
1307 * Only add the sign delay Dsgn if there is an actual
1308 * predecessor or successor key.
1309 */
1310 uint32_t tag;
1311 ret = dst_key_getnum(key->key, DST_NUM_PREDECESSOR,
1312 &tag);
1313 if (ret != ISC_R_SUCCESS) {
1314 ret = dst_key_getnum(key->key,
1315 DST_NUM_SUCCESSOR, &tag);
1316 }
1317 if (ret == ISC_R_SUCCESS) {
1318 nexttime += dns_kasp_signdelay(kasp);
1319 }
1320 break;
1321 default:
1322 nexttime = now;
1323 break;
1324 }
1325 break;
1326 case DST_KEY_DS:
1327 switch (next_state) {
1328 /*
1329 * RFC 7583: The successor DS record is published in
1330 * the parent zone and after the registration delay
1331 * (Dreg), the time taken after the DS record has been
1332 * submitted to the parent zone manager for it to be
1333 * placed in the zone. Key N (the predecessor) must
1334 * remain in the zone until any caches that contain a
1335 * copy of the DS RRset have a copy containing the new
1336 * DS record. This interval is the retire interval
1337 * (Iret), given by:
1338 *
1339 * Iret = DprpP + TTLds
1340 *
1341 * This translates to:
1342 *
1343 * parent-propagation-delay + parent-ds-ttl.
1344 *
1345 * We will also add the retire-safety interval.
1346 */
1347 case OMNIPRESENT:
1348 /* Make sure DS has been seen in the parent. */
1349 ret = dst_key_gettime(key->key, DST_TIME_DSPUBLISH,
1350 &dstime);
1351 if (ret != ISC_R_SUCCESS || dstime > now) {
1352 /* Not yet, try again in an hour. */
1353 nexttime = now + 3600;
1354 } else {
1355 nexttime =
1356 dstime + dns_kasp_dsttl(kasp) +
1357 dns_kasp_parentpropagationdelay(kasp) +
1358 dns_kasp_retiresafety(kasp);
1359 }
1360 break;
1361 case HIDDEN:
1362 /* Make sure DS has been withdrawn from the parent. */
1363 ret = dst_key_gettime(key->key, DST_TIME_DSDELETE,
1364 &dstime);
1365 if (ret != ISC_R_SUCCESS || dstime > now) {
1366 /* Not yet, try again in an hour. */
1367 nexttime = now + 3600;
1368 } else {
1369 nexttime =
1370 dstime + dns_kasp_dsttl(kasp) +
1371 dns_kasp_parentpropagationdelay(kasp) +
1372 dns_kasp_retiresafety(kasp);
1373 }
1374 break;
1375 default:
1376 nexttime = now;
1377 break;
1378 }
1379 break;
1380 default:
1381 UNREACHABLE();
1382 break;
1383 }
1384
1385 *when = nexttime;
1386 }
1387
1388 /*
1389 * Update keys.
1390 * This implements Algorithm (1) of "Flexible and Robust Key Rollover".
1391 *
1392 */
1393 static isc_result_t
keymgr_update(dns_dnsseckeylist_t * keyring,dns_kasp_t * kasp,isc_stdtime_t now,isc_stdtime_t * nexttime,bool secure_to_insecure)1394 keymgr_update(dns_dnsseckeylist_t *keyring, dns_kasp_t *kasp, isc_stdtime_t now,
1395 isc_stdtime_t *nexttime, bool secure_to_insecure) {
1396 bool changed;
1397
1398 /* Repeat until nothing changed. */
1399 transition:
1400 changed = false;
1401
1402 /* For all keys in the zone. */
1403 for (dns_dnsseckey_t *dkey = ISC_LIST_HEAD(*keyring); dkey != NULL;
1404 dkey = ISC_LIST_NEXT(dkey, link))
1405 {
1406 char keystr[DST_KEY_FORMATSIZE];
1407 dst_key_format(dkey->key, keystr, sizeof(keystr));
1408
1409 /* For all records related to this key. */
1410 for (int i = 0; i < NUM_KEYSTATES; i++) {
1411 isc_result_t ret;
1412 isc_stdtime_t when;
1413 dst_key_state_t state, next_state;
1414
1415 ret = dst_key_getstate(dkey->key, i, &state);
1416 if (ret == ISC_R_NOTFOUND) {
1417 /*
1418 * This record type is not applicable for this
1419 * key, continue to the next record type.
1420 */
1421 continue;
1422 }
1423
1424 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
1425 DNS_LOGMODULE_DNSSEC, ISC_LOG_DEBUG(1),
1426 "keymgr: examine %s %s type %s "
1427 "in state %s",
1428 keymgr_keyrole(dkey->key), keystr,
1429 keystatetags[i], keystatestrings[state]);
1430
1431 /* Get the desired next state. */
1432 next_state = keymgr_desiredstate(dkey, state);
1433 if (state == next_state) {
1434 /*
1435 * This record is in a stable state.
1436 * No change needed, continue with the next
1437 * record type.
1438 */
1439 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
1440 DNS_LOGMODULE_DNSSEC,
1441 ISC_LOG_DEBUG(1),
1442 "keymgr: %s %s type %s in "
1443 "stable state %s",
1444 keymgr_keyrole(dkey->key), keystr,
1445 keystatetags[i],
1446 keystatestrings[state]);
1447 continue;
1448 }
1449
1450 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
1451 DNS_LOGMODULE_DNSSEC, ISC_LOG_DEBUG(1),
1452 "keymgr: can we transition %s %s type %s "
1453 "state %s to state %s?",
1454 keymgr_keyrole(dkey->key), keystr,
1455 keystatetags[i], keystatestrings[state],
1456 keystatestrings[next_state]);
1457
1458 /* Is the transition allowed according to policy? */
1459 if (!keymgr_policy_approval(keyring, dkey, i,
1460 next_state))
1461 {
1462 /* No, please respect rollover methods. */
1463 isc_log_write(
1464 dns_lctx, DNS_LOGCATEGORY_DNSSEC,
1465 DNS_LOGMODULE_DNSSEC, ISC_LOG_DEBUG(1),
1466 "keymgr: policy says no to %s %s type "
1467 "%s "
1468 "state %s to state %s",
1469 keymgr_keyrole(dkey->key), keystr,
1470 keystatetags[i], keystatestrings[state],
1471 keystatestrings[next_state]);
1472
1473 continue;
1474 }
1475
1476 /* Is the transition DNSSEC safe? */
1477 if (!keymgr_transition_allowed(keyring, dkey, i,
1478 next_state,
1479 secure_to_insecure))
1480 {
1481 /* No, this would make the zone bogus. */
1482 isc_log_write(
1483 dns_lctx, DNS_LOGCATEGORY_DNSSEC,
1484 DNS_LOGMODULE_DNSSEC, ISC_LOG_DEBUG(1),
1485 "keymgr: dnssec says no to %s %s type "
1486 "%s "
1487 "state %s to state %s",
1488 keymgr_keyrole(dkey->key), keystr,
1489 keystatetags[i], keystatestrings[state],
1490 keystatestrings[next_state]);
1491 continue;
1492 }
1493
1494 /* Is it time to make the transition? */
1495 when = now;
1496 keymgr_transition_time(dkey, i, next_state, kasp, now,
1497 &when);
1498 if (when > now) {
1499 /* Not yet. */
1500 isc_log_write(
1501 dns_lctx, DNS_LOGCATEGORY_DNSSEC,
1502 DNS_LOGMODULE_DNSSEC, ISC_LOG_DEBUG(1),
1503 "keymgr: time says no to %s %s type %s "
1504 "state %s to state %s (wait %u "
1505 "seconds)",
1506 keymgr_keyrole(dkey->key), keystr,
1507 keystatetags[i], keystatestrings[state],
1508 keystatestrings[next_state],
1509 when - now);
1510 if (*nexttime == 0 || *nexttime > when) {
1511 *nexttime = when;
1512 }
1513 continue;
1514 }
1515
1516 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
1517 DNS_LOGMODULE_DNSSEC, ISC_LOG_DEBUG(1),
1518 "keymgr: transition %s %s type %s "
1519 "state %s to state %s!",
1520 keymgr_keyrole(dkey->key), keystr,
1521 keystatetags[i], keystatestrings[state],
1522 keystatestrings[next_state]);
1523
1524 /* It is safe to make the transition. */
1525 dst_key_setstate(dkey->key, i, next_state);
1526 dst_key_settime(dkey->key, keystatetimes[i], now);
1527 INSIST(dst_key_ismodified(dkey->key));
1528 changed = true;
1529 }
1530 }
1531
1532 /* We changed something, continue processing. */
1533 if (changed) {
1534 goto transition;
1535 }
1536
1537 return (ISC_R_SUCCESS);
1538 }
1539
1540 /*
1541 * See if this key needs to be initialized with properties. A key created
1542 * and derived from a dnssec-policy will have the required metadata available,
1543 * otherwise these may be missing and need to be initialized. The key states
1544 * will be initialized according to existing timing metadata.
1545 *
1546 */
1547 static void
keymgr_key_init(dns_dnsseckey_t * key,dns_kasp_t * kasp,isc_stdtime_t now,bool csk)1548 keymgr_key_init(dns_dnsseckey_t *key, dns_kasp_t *kasp, isc_stdtime_t now,
1549 bool csk) {
1550 bool ksk, zsk;
1551 isc_result_t ret;
1552 isc_stdtime_t active = 0, pub = 0, syncpub = 0, retire = 0, remove = 0;
1553 dst_key_state_t dnskey_state = HIDDEN;
1554 dst_key_state_t ds_state = HIDDEN;
1555 dst_key_state_t zrrsig_state = HIDDEN;
1556 dst_key_state_t goal_state = HIDDEN;
1557
1558 REQUIRE(key != NULL);
1559 REQUIRE(key->key != NULL);
1560
1561 /* Initialize role. */
1562 ret = dst_key_getbool(key->key, DST_BOOL_KSK, &ksk);
1563 if (ret != ISC_R_SUCCESS) {
1564 ksk = ((dst_key_flags(key->key) & DNS_KEYFLAG_KSK) != 0);
1565 dst_key_setbool(key->key, DST_BOOL_KSK, (ksk || csk));
1566 }
1567 ret = dst_key_getbool(key->key, DST_BOOL_ZSK, &zsk);
1568 if (ret != ISC_R_SUCCESS) {
1569 zsk = ((dst_key_flags(key->key) & DNS_KEYFLAG_KSK) == 0);
1570 dst_key_setbool(key->key, DST_BOOL_ZSK, (zsk || csk));
1571 }
1572
1573 /* Get time metadata. */
1574 ret = dst_key_gettime(key->key, DST_TIME_ACTIVATE, &active);
1575 if (active <= now && ret == ISC_R_SUCCESS) {
1576 dns_ttl_t zone_ttl = dns_kasp_zonemaxttl(kasp);
1577 zone_ttl += dns_kasp_zonepropagationdelay(kasp);
1578 if ((active + zone_ttl) <= now) {
1579 zrrsig_state = OMNIPRESENT;
1580 } else {
1581 zrrsig_state = RUMOURED;
1582 }
1583 goal_state = OMNIPRESENT;
1584 }
1585 ret = dst_key_gettime(key->key, DST_TIME_PUBLISH, &pub);
1586 if (pub <= now && ret == ISC_R_SUCCESS) {
1587 dns_ttl_t key_ttl = dst_key_getttl(key->key);
1588 key_ttl += dns_kasp_zonepropagationdelay(kasp);
1589 if ((pub + key_ttl) <= now) {
1590 dnskey_state = OMNIPRESENT;
1591 } else {
1592 dnskey_state = RUMOURED;
1593 }
1594 goal_state = OMNIPRESENT;
1595 }
1596 ret = dst_key_gettime(key->key, DST_TIME_SYNCPUBLISH, &syncpub);
1597 if (syncpub <= now && ret == ISC_R_SUCCESS) {
1598 dns_ttl_t ds_ttl = dns_kasp_dsttl(kasp);
1599 ds_ttl += dns_kasp_parentpropagationdelay(kasp);
1600 if ((syncpub + ds_ttl) <= now) {
1601 ds_state = OMNIPRESENT;
1602 } else {
1603 ds_state = RUMOURED;
1604 }
1605 goal_state = OMNIPRESENT;
1606 }
1607 ret = dst_key_gettime(key->key, DST_TIME_INACTIVE, &retire);
1608 if (retire <= now && ret == ISC_R_SUCCESS) {
1609 dns_ttl_t zone_ttl = dns_kasp_zonemaxttl(kasp);
1610 zone_ttl += dns_kasp_zonepropagationdelay(kasp);
1611 if ((retire + zone_ttl) <= now) {
1612 zrrsig_state = HIDDEN;
1613 } else {
1614 zrrsig_state = UNRETENTIVE;
1615 }
1616 ds_state = UNRETENTIVE;
1617 goal_state = HIDDEN;
1618 }
1619 ret = dst_key_gettime(key->key, DST_TIME_DELETE, &remove);
1620 if (remove <= now && ret == ISC_R_SUCCESS) {
1621 dns_ttl_t key_ttl = dst_key_getttl(key->key);
1622 key_ttl += dns_kasp_zonepropagationdelay(kasp);
1623 if ((remove + key_ttl) <= now) {
1624 dnskey_state = HIDDEN;
1625 } else {
1626 dnskey_state = UNRETENTIVE;
1627 }
1628 zrrsig_state = HIDDEN;
1629 ds_state = HIDDEN;
1630 goal_state = HIDDEN;
1631 }
1632
1633 /* Set goal if not already set. */
1634 if (dst_key_getstate(key->key, DST_KEY_GOAL, &goal_state) !=
1635 ISC_R_SUCCESS)
1636 {
1637 dst_key_setstate(key->key, DST_KEY_GOAL, goal_state);
1638 }
1639
1640 /* Set key states for all keys that do not have them. */
1641 INITIALIZE_STATE(key->key, DST_KEY_DNSKEY, DST_TIME_DNSKEY,
1642 dnskey_state, now);
1643 if (ksk || csk) {
1644 INITIALIZE_STATE(key->key, DST_KEY_KRRSIG, DST_TIME_KRRSIG,
1645 dnskey_state, now);
1646 INITIALIZE_STATE(key->key, DST_KEY_DS, DST_TIME_DS, ds_state,
1647 now);
1648 }
1649 if (zsk || csk) {
1650 INITIALIZE_STATE(key->key, DST_KEY_ZRRSIG, DST_TIME_ZRRSIG,
1651 zrrsig_state, now);
1652 }
1653 }
1654
1655 static isc_result_t
keymgr_key_rollover(dns_kasp_key_t * kaspkey,dns_dnsseckey_t * active_key,dns_dnsseckeylist_t * keyring,dns_dnsseckeylist_t * newkeys,const dns_name_t * origin,dns_rdataclass_t rdclass,dns_kasp_t * kasp,uint32_t lifetime,bool rollover,isc_stdtime_t now,isc_stdtime_t * nexttime,isc_mem_t * mctx)1656 keymgr_key_rollover(dns_kasp_key_t *kaspkey, dns_dnsseckey_t *active_key,
1657 dns_dnsseckeylist_t *keyring, dns_dnsseckeylist_t *newkeys,
1658 const dns_name_t *origin, dns_rdataclass_t rdclass,
1659 dns_kasp_t *kasp, uint32_t lifetime, bool rollover,
1660 isc_stdtime_t now, isc_stdtime_t *nexttime,
1661 isc_mem_t *mctx) {
1662 char keystr[DST_KEY_FORMATSIZE];
1663 isc_stdtime_t retire = 0, active = 0, prepub = 0;
1664 dns_dnsseckey_t *new_key = NULL;
1665 dns_dnsseckey_t *candidate = NULL;
1666 dst_key_t *dst_key = NULL;
1667
1668 /* Do we need to create a successor for the active key? */
1669 if (active_key != NULL) {
1670 if (isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(1))) {
1671 dst_key_format(active_key->key, keystr, sizeof(keystr));
1672 isc_log_write(
1673 dns_lctx, DNS_LOGCATEGORY_DNSSEC,
1674 DNS_LOGMODULE_DNSSEC, ISC_LOG_DEBUG(1),
1675 "keymgr: DNSKEY %s (%s) is active in policy %s",
1676 keystr, keymgr_keyrole(active_key->key),
1677 dns_kasp_getname(kasp));
1678 }
1679
1680 /*
1681 * Calculate when the successor needs to be published
1682 * in the zone.
1683 */
1684 prepub = keymgr_prepublication_time(active_key, kasp, lifetime,
1685 now);
1686 if (prepub == 0 || prepub > now) {
1687 if (isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(1))) {
1688 dst_key_format(active_key->key, keystr,
1689 sizeof(keystr));
1690 isc_log_write(
1691 dns_lctx, DNS_LOGCATEGORY_DNSSEC,
1692 DNS_LOGMODULE_DNSSEC, ISC_LOG_DEBUG(1),
1693 "keymgr: new successor needed for "
1694 "DNSKEY %s (%s) (policy %s) in %u "
1695 "seconds",
1696 keystr, keymgr_keyrole(active_key->key),
1697 dns_kasp_getname(kasp), (prepub - now));
1698 }
1699
1700 /* No need to start rollover now. */
1701 if (*nexttime == 0 || prepub < *nexttime) {
1702 *nexttime = prepub;
1703 }
1704 return (ISC_R_SUCCESS);
1705 }
1706
1707 if (keymgr_key_has_successor(active_key, keyring)) {
1708 /* Key already has successor. */
1709 if (isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(1))) {
1710 dst_key_format(active_key->key, keystr,
1711 sizeof(keystr));
1712 isc_log_write(
1713 dns_lctx, DNS_LOGCATEGORY_DNSSEC,
1714 DNS_LOGMODULE_DNSSEC, ISC_LOG_DEBUG(1),
1715 "keymgr: key DNSKEY %s (%s) (policy "
1716 "%s) already has successor",
1717 keystr, keymgr_keyrole(active_key->key),
1718 dns_kasp_getname(kasp));
1719 }
1720 return (ISC_R_SUCCESS);
1721 }
1722
1723 if (isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(1))) {
1724 dst_key_format(active_key->key, keystr, sizeof(keystr));
1725 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
1726 DNS_LOGMODULE_DNSSEC, ISC_LOG_DEBUG(1),
1727 "keymgr: need successor for DNSKEY %s "
1728 "(%s) (policy %s)",
1729 keystr, keymgr_keyrole(active_key->key),
1730 dns_kasp_getname(kasp));
1731 }
1732
1733 /*
1734 * If rollover is not allowed, warn.
1735 */
1736 if (!rollover) {
1737 dst_key_format(active_key->key, keystr, sizeof(keystr));
1738 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
1739 DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
1740 "keymgr: DNSKEY %s (%s) is offline in "
1741 "policy %s, cannot start rollover",
1742 keystr, keymgr_keyrole(active_key->key),
1743 dns_kasp_getname(kasp));
1744 return (ISC_R_SUCCESS);
1745 }
1746 } else if (isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(1))) {
1747 char namestr[DNS_NAME_FORMATSIZE];
1748 dns_name_format(origin, namestr, sizeof(namestr));
1749 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
1750 DNS_LOGMODULE_DNSSEC, ISC_LOG_DEBUG(1),
1751 "keymgr: no active key found for %s (policy %s)",
1752 namestr, dns_kasp_getname(kasp));
1753 }
1754
1755 /* It is time to do key rollover, we need a new key. */
1756
1757 /*
1758 * Check if there is a key available in pool because keys
1759 * may have been pregenerated with dnssec-keygen.
1760 */
1761 for (candidate = ISC_LIST_HEAD(*keyring); candidate != NULL;
1762 candidate = ISC_LIST_NEXT(candidate, link))
1763 {
1764 if (keymgr_dnsseckey_kaspkey_match(candidate, kaspkey) &&
1765 dst_key_is_unused(candidate->key))
1766 {
1767 /* Found a candidate in keyring. */
1768 break;
1769 }
1770 }
1771
1772 if (candidate == NULL) {
1773 /* No key available in keyring, create a new one. */
1774 bool csk = (dns_kasp_key_ksk(kaspkey) &&
1775 dns_kasp_key_zsk(kaspkey));
1776
1777 isc_result_t result = keymgr_createkey(kaspkey, origin, rdclass,
1778 mctx, keyring, newkeys,
1779 &dst_key);
1780 if (result != ISC_R_SUCCESS) {
1781 return (result);
1782 }
1783 dst_key_setttl(dst_key, dns_kasp_dnskeyttl(kasp));
1784 dst_key_settime(dst_key, DST_TIME_CREATED, now);
1785 result = dns_dnsseckey_create(mctx, &dst_key, &new_key);
1786 if (result != ISC_R_SUCCESS) {
1787 return (result);
1788 }
1789 keymgr_key_init(new_key, kasp, now, csk);
1790 } else {
1791 new_key = candidate;
1792 }
1793 dst_key_setnum(new_key->key, DST_NUM_LIFETIME, lifetime);
1794
1795 /* Got a key. */
1796 if (active_key == NULL) {
1797 /*
1798 * If there is no active key found yet for this kasp
1799 * key configuration, immediately make this key active.
1800 */
1801 dst_key_settime(new_key->key, DST_TIME_PUBLISH, now);
1802 dst_key_settime(new_key->key, DST_TIME_ACTIVATE, now);
1803 keymgr_settime_syncpublish(new_key, kasp, true);
1804 active = now;
1805 } else {
1806 /*
1807 * This is a successor. Mark the relationship.
1808 */
1809 isc_stdtime_t created;
1810 (void)dst_key_gettime(new_key->key, DST_TIME_CREATED, &created);
1811
1812 dst_key_setnum(new_key->key, DST_NUM_PREDECESSOR,
1813 dst_key_id(active_key->key));
1814 dst_key_setnum(active_key->key, DST_NUM_SUCCESSOR,
1815 dst_key_id(new_key->key));
1816 (void)dst_key_gettime(active_key->key, DST_TIME_INACTIVE,
1817 &retire);
1818 active = retire;
1819
1820 /*
1821 * If prepublication time and/or retire time are
1822 * in the past (before the new key was created), use
1823 * creation time as published and active time,
1824 * effectively immediately making the key active.
1825 */
1826 if (prepub < created) {
1827 active += (created - prepub);
1828 prepub = created;
1829 }
1830 if (active < created) {
1831 active = created;
1832 }
1833 dst_key_settime(new_key->key, DST_TIME_PUBLISH, prepub);
1834 dst_key_settime(new_key->key, DST_TIME_ACTIVATE, active);
1835 keymgr_settime_syncpublish(new_key, kasp, false);
1836
1837 /*
1838 * Retire predecessor.
1839 */
1840 dst_key_setstate(active_key->key, DST_KEY_GOAL, HIDDEN);
1841 }
1842
1843 /* This key wants to be present. */
1844 dst_key_setstate(new_key->key, DST_KEY_GOAL, OMNIPRESENT);
1845
1846 /* Do we need to set retire time? */
1847 if (lifetime > 0) {
1848 dst_key_settime(new_key->key, DST_TIME_INACTIVE,
1849 (active + lifetime));
1850 keymgr_settime_remove(new_key, kasp);
1851 }
1852
1853 /* Append dnsseckey to list of new keys. */
1854 dns_dnssec_get_hints(new_key, now);
1855 new_key->source = dns_keysource_repository;
1856 INSIST(!new_key->legacy);
1857 if (candidate == NULL) {
1858 ISC_LIST_APPEND(*newkeys, new_key, link);
1859 }
1860
1861 /* Logging. */
1862 dst_key_format(new_key->key, keystr, sizeof(keystr));
1863 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_DNSSEC,
1864 ISC_LOG_INFO, "keymgr: DNSKEY %s (%s) %s for policy %s",
1865 keystr, keymgr_keyrole(new_key->key),
1866 (candidate != NULL) ? "selected" : "created",
1867 dns_kasp_getname(kasp));
1868 return (ISC_R_SUCCESS);
1869 }
1870
1871 static bool
keymgr_key_may_be_purged(dst_key_t * key,uint32_t after,isc_stdtime_t now)1872 keymgr_key_may_be_purged(dst_key_t *key, uint32_t after, isc_stdtime_t now) {
1873 bool ksk = false;
1874 bool zsk = false;
1875 dst_key_state_t hidden[NUM_KEYSTATES] = { HIDDEN, NA, NA, NA };
1876 isc_stdtime_t lastchange = 0;
1877
1878 char keystr[DST_KEY_FORMATSIZE];
1879 dst_key_format(key, keystr, sizeof(keystr));
1880
1881 /* If 'purge-keys' is disabled, always retain keys. */
1882 if (after == 0) {
1883 return (false);
1884 }
1885
1886 /* Don't purge keys with goal OMNIPRESENT */
1887 if (dst_key_goal(key) == OMNIPRESENT) {
1888 return (false);
1889 }
1890
1891 /* Don't purge unused keys. */
1892 if (dst_key_is_unused(key)) {
1893 return (false);
1894 }
1895
1896 /* If this key is completely HIDDEN it may be purged. */
1897 (void)dst_key_getbool(key, DST_BOOL_KSK, &ksk);
1898 (void)dst_key_getbool(key, DST_BOOL_ZSK, &zsk);
1899 if (ksk) {
1900 hidden[DST_KEY_KRRSIG] = HIDDEN;
1901 hidden[DST_KEY_DS] = HIDDEN;
1902 }
1903 if (zsk) {
1904 hidden[DST_KEY_ZRRSIG] = HIDDEN;
1905 }
1906 if (!keymgr_key_match_state(key, key, 0, NA, hidden)) {
1907 return (false);
1908 }
1909
1910 /*
1911 * Check 'purge-keys' interval. If the interval has passed since
1912 * the last key change, it may be purged.
1913 */
1914 for (int i = 0; i < NUM_KEYSTATES; i++) {
1915 isc_stdtime_t change = 0;
1916 (void)dst_key_gettime(key, keystatetimes[i], &change);
1917 if (change > lastchange) {
1918 lastchange = change;
1919 }
1920 }
1921
1922 return ((lastchange + after) < now);
1923 }
1924
1925 static void
keymgr_purge_keyfile(dst_key_t * key,const char * dir,int type)1926 keymgr_purge_keyfile(dst_key_t *key, const char *dir, int type) {
1927 isc_result_t ret;
1928 isc_buffer_t fileb;
1929 char filename[NAME_MAX];
1930
1931 /*
1932 * Make the filename.
1933 */
1934 isc_buffer_init(&fileb, filename, sizeof(filename));
1935 ret = dst_key_buildfilename(key, type, dir, &fileb);
1936 if (ret != ISC_R_SUCCESS) {
1937 char keystr[DST_KEY_FORMATSIZE];
1938 dst_key_format(key, keystr, sizeof(keystr));
1939 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
1940 DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
1941 "keymgr: failed to purge DNSKEY %s (%s): cannot "
1942 "build filename (%s)",
1943 keystr, keymgr_keyrole(key),
1944 isc_result_totext(ret));
1945 return;
1946 }
1947
1948 if (unlink(filename) < 0) {
1949 char keystr[DST_KEY_FORMATSIZE];
1950 dst_key_format(key, keystr, sizeof(keystr));
1951 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
1952 DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING,
1953 "keymgr: failed to purge DNSKEY %s (%s): unlink "
1954 "'%s' failed",
1955 keystr, keymgr_keyrole(key), filename);
1956 }
1957 }
1958
1959 /*
1960 * Examine 'keys' and match 'kasp' policy.
1961 *
1962 */
1963 isc_result_t
dns_keymgr_run(const dns_name_t * origin,dns_rdataclass_t rdclass,const char * directory,isc_mem_t * mctx,dns_dnsseckeylist_t * keyring,dns_dnsseckeylist_t * dnskeys,dns_kasp_t * kasp,isc_stdtime_t now,isc_stdtime_t * nexttime)1964 dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
1965 const char *directory, isc_mem_t *mctx,
1966 dns_dnsseckeylist_t *keyring, dns_dnsseckeylist_t *dnskeys,
1967 dns_kasp_t *kasp, isc_stdtime_t now, isc_stdtime_t *nexttime) {
1968 isc_result_t result = ISC_R_SUCCESS;
1969 dns_dnsseckeylist_t newkeys;
1970 dns_kasp_key_t *kkey;
1971 dns_dnsseckey_t *newkey = NULL;
1972 isc_dir_t dir;
1973 bool dir_open = false;
1974 bool secure_to_insecure = false;
1975 int numkeys = 0;
1976 int options = (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC | DST_TYPE_STATE);
1977 char keystr[DST_KEY_FORMATSIZE];
1978
1979 REQUIRE(DNS_KASP_VALID(kasp));
1980 REQUIRE(keyring != NULL);
1981
1982 ISC_LIST_INIT(newkeys);
1983
1984 isc_dir_init(&dir);
1985 if (directory == NULL) {
1986 directory = ".";
1987 }
1988
1989 RETERR(isc_dir_open(&dir, directory));
1990 dir_open = true;
1991
1992 *nexttime = 0;
1993
1994 /* Debug logging: what keys are available in the keyring? */
1995 if (isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(1))) {
1996 if (ISC_LIST_EMPTY(*keyring)) {
1997 char namebuf[DNS_NAME_FORMATSIZE];
1998 dns_name_format(origin, namebuf, sizeof(namebuf));
1999 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
2000 DNS_LOGMODULE_DNSSEC, ISC_LOG_DEBUG(1),
2001 "keymgr: keyring empty (zone %s policy "
2002 "%s)",
2003 namebuf, dns_kasp_getname(kasp));
2004 }
2005
2006 for (dns_dnsseckey_t *dkey = ISC_LIST_HEAD(*keyring);
2007 dkey != NULL; dkey = ISC_LIST_NEXT(dkey, link))
2008 {
2009 dst_key_format(dkey->key, keystr, sizeof(keystr));
2010 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
2011 DNS_LOGMODULE_DNSSEC, ISC_LOG_DEBUG(1),
2012 "keymgr: keyring: %s (policy %s)", keystr,
2013 dns_kasp_getname(kasp));
2014 }
2015 for (dns_dnsseckey_t *dkey = ISC_LIST_HEAD(*dnskeys);
2016 dkey != NULL; dkey = ISC_LIST_NEXT(dkey, link))
2017 {
2018 dst_key_format(dkey->key, keystr, sizeof(keystr));
2019 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
2020 DNS_LOGMODULE_DNSSEC, ISC_LOG_DEBUG(1),
2021 "keymgr: dnskeys: %s (policy %s)", keystr,
2022 dns_kasp_getname(kasp));
2023 }
2024 }
2025
2026 for (dns_dnsseckey_t *dkey = ISC_LIST_HEAD(*dnskeys); dkey != NULL;
2027 dkey = ISC_LIST_NEXT(dkey, link))
2028 {
2029 numkeys++;
2030 }
2031
2032 /* Do we need to remove keys? */
2033 for (dns_dnsseckey_t *dkey = ISC_LIST_HEAD(*keyring); dkey != NULL;
2034 dkey = ISC_LIST_NEXT(dkey, link))
2035 {
2036 bool found_match = false;
2037
2038 keymgr_key_init(dkey, kasp, now, (numkeys == 1));
2039
2040 for (kkey = ISC_LIST_HEAD(dns_kasp_keys(kasp)); kkey != NULL;
2041 kkey = ISC_LIST_NEXT(kkey, link))
2042 {
2043 if (keymgr_dnsseckey_kaspkey_match(dkey, kkey)) {
2044 found_match = true;
2045 break;
2046 }
2047 }
2048
2049 /* No match, so retire unwanted retire key. */
2050 if (!found_match) {
2051 keymgr_key_retire(dkey, kasp, now);
2052 }
2053
2054 /* Check purge-keys interval. */
2055 if (keymgr_key_may_be_purged(dkey->key,
2056 dns_kasp_purgekeys(kasp), now))
2057 {
2058 dst_key_format(dkey->key, keystr, sizeof(keystr));
2059 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
2060 DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO,
2061 "keymgr: purge DNSKEY %s (%s) according "
2062 "to policy %s",
2063 keystr, keymgr_keyrole(dkey->key),
2064 dns_kasp_getname(kasp));
2065
2066 keymgr_purge_keyfile(dkey->key, directory,
2067 DST_TYPE_PUBLIC);
2068 keymgr_purge_keyfile(dkey->key, directory,
2069 DST_TYPE_PRIVATE);
2070 keymgr_purge_keyfile(dkey->key, directory,
2071 DST_TYPE_STATE);
2072
2073 dkey->purge = true;
2074 }
2075 }
2076
2077 /* Create keys according to the policy, if come in short. */
2078 for (kkey = ISC_LIST_HEAD(dns_kasp_keys(kasp)); kkey != NULL;
2079 kkey = ISC_LIST_NEXT(kkey, link))
2080 {
2081 uint32_t lifetime = dns_kasp_key_lifetime(kkey);
2082 dns_dnsseckey_t *active_key = NULL;
2083 bool rollover_allowed = true;
2084
2085 /* Do we have keys available for this kasp key? */
2086 for (dns_dnsseckey_t *dkey = ISC_LIST_HEAD(*keyring);
2087 dkey != NULL; dkey = ISC_LIST_NEXT(dkey, link))
2088 {
2089 if (keymgr_dnsseckey_kaspkey_match(dkey, kkey)) {
2090 /* Found a match. */
2091 dst_key_format(dkey->key, keystr,
2092 sizeof(keystr));
2093 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
2094 DNS_LOGMODULE_DNSSEC,
2095 ISC_LOG_DEBUG(1),
2096 "keymgr: DNSKEY %s (%s) matches "
2097 "policy %s",
2098 keystr, keymgr_keyrole(dkey->key),
2099 dns_kasp_getname(kasp));
2100
2101 /* Initialize lifetime if not set. */
2102 uint32_t l;
2103 if (dst_key_getnum(dkey->key, DST_NUM_LIFETIME,
2104 &l) != ISC_R_SUCCESS)
2105 {
2106 dst_key_setnum(dkey->key,
2107 DST_NUM_LIFETIME,
2108 lifetime);
2109 }
2110
2111 if (active_key) {
2112 /* We already have an active key that
2113 * matches the kasp policy.
2114 */
2115 if (!dst_key_is_unused(dkey->key) &&
2116 (dst_key_goal(dkey->key) ==
2117 OMNIPRESENT) &&
2118 !keymgr_dep(dkey->key, keyring,
2119 NULL) &&
2120 !keymgr_dep(active_key->key,
2121 keyring, NULL))
2122 {
2123 /*
2124 * Multiple signing keys match
2125 * the kasp key configuration.
2126 * Retire excess keys in use.
2127 */
2128 keymgr_key_retire(dkey, kasp,
2129 now);
2130 }
2131 continue;
2132 }
2133
2134 /*
2135 * Save the matched key only if it is active
2136 * or desires to be active.
2137 */
2138 if (dst_key_goal(dkey->key) == OMNIPRESENT ||
2139 dst_key_is_active(dkey->key, now))
2140 {
2141 active_key = dkey;
2142 }
2143 }
2144 }
2145
2146 if (active_key == NULL) {
2147 /*
2148 * We didn't found an active key, perhaps the .private
2149 * key file is offline. If so, we don't want to create
2150 * a successor key. Check if we have an appropriate
2151 * state file.
2152 */
2153 for (dns_dnsseckey_t *dnskey = ISC_LIST_HEAD(*dnskeys);
2154 dnskey != NULL;
2155 dnskey = ISC_LIST_NEXT(dnskey, link))
2156 {
2157 if (keymgr_dnsseckey_kaspkey_match(dnskey,
2158 kkey))
2159 {
2160 /* Found a match. */
2161 dst_key_format(dnskey->key, keystr,
2162 sizeof(keystr));
2163 isc_log_write(
2164 dns_lctx,
2165 DNS_LOGCATEGORY_DNSSEC,
2166 DNS_LOGMODULE_DNSSEC,
2167 ISC_LOG_DEBUG(1),
2168 "keymgr: DNSKEY %s (%s) "
2169 "offline, policy %s",
2170 keystr,
2171 keymgr_keyrole(dnskey->key),
2172 dns_kasp_getname(kasp));
2173 rollover_allowed = false;
2174 active_key = dnskey;
2175 break;
2176 }
2177 }
2178 }
2179
2180 /* See if this key requires a rollover. */
2181 RETERR(keymgr_key_rollover(
2182 kkey, active_key, keyring, &newkeys, origin, rdclass,
2183 kasp, lifetime, rollover_allowed, now, nexttime, mctx));
2184 }
2185
2186 /* Walked all kasp key configurations. Append new keys. */
2187 if (!ISC_LIST_EMPTY(newkeys)) {
2188 ISC_LIST_APPENDLIST(*keyring, newkeys, link);
2189 }
2190
2191 /*
2192 * If the policy has an empty key list, this means the zone is going
2193 * back to unsigned.
2194 */
2195 secure_to_insecure = dns_kasp_keylist_empty(kasp);
2196
2197 /* Read to update key states. */
2198 keymgr_update(keyring, kasp, now, nexttime, secure_to_insecure);
2199
2200 /* Store key states and update hints. */
2201 for (dns_dnsseckey_t *dkey = ISC_LIST_HEAD(*keyring); dkey != NULL;
2202 dkey = ISC_LIST_NEXT(dkey, link))
2203 {
2204 if (dst_key_ismodified(dkey->key) && !dkey->purge) {
2205 dns_dnssec_get_hints(dkey, now);
2206 RETERR(dst_key_tofile(dkey->key, options, directory));
2207 dst_key_setmodified(dkey->key, false);
2208 }
2209 }
2210
2211 result = ISC_R_SUCCESS;
2212
2213 failure:
2214 if (dir_open) {
2215 isc_dir_close(&dir);
2216 }
2217
2218 if (result != ISC_R_SUCCESS) {
2219 while ((newkey = ISC_LIST_HEAD(newkeys)) != NULL) {
2220 ISC_LIST_UNLINK(newkeys, newkey, link);
2221 INSIST(newkey->key != NULL);
2222 dst_key_free(&newkey->key);
2223 dns_dnsseckey_destroy(mctx, &newkey);
2224 }
2225 }
2226
2227 if (isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(3))) {
2228 char namebuf[DNS_NAME_FORMATSIZE];
2229 dns_name_format(origin, namebuf, sizeof(namebuf));
2230 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
2231 DNS_LOGMODULE_DNSSEC, ISC_LOG_DEBUG(3),
2232 "keymgr: %s done", namebuf);
2233 }
2234 return (result);
2235 }
2236
2237 static isc_result_t
keymgr_checkds(dns_kasp_t * kasp,dns_dnsseckeylist_t * keyring,const char * directory,isc_stdtime_t now,isc_stdtime_t when,bool dspublish,dns_keytag_t id,unsigned int alg,bool check_id)2238 keymgr_checkds(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring,
2239 const char *directory, isc_stdtime_t now, isc_stdtime_t when,
2240 bool dspublish, dns_keytag_t id, unsigned int alg,
2241 bool check_id) {
2242 int options = (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC | DST_TYPE_STATE);
2243 isc_dir_t dir;
2244 isc_result_t result;
2245 dns_dnsseckey_t *ksk_key = NULL;
2246
2247 REQUIRE(DNS_KASP_VALID(kasp));
2248 REQUIRE(keyring != NULL);
2249
2250 for (dns_dnsseckey_t *dkey = ISC_LIST_HEAD(*keyring); dkey != NULL;
2251 dkey = ISC_LIST_NEXT(dkey, link))
2252 {
2253 isc_result_t ret;
2254 bool ksk = false;
2255
2256 ret = dst_key_getbool(dkey->key, DST_BOOL_KSK, &ksk);
2257 if (ret == ISC_R_SUCCESS && ksk) {
2258 if (check_id && dst_key_id(dkey->key) != id) {
2259 continue;
2260 }
2261 if (alg > 0 && dst_key_alg(dkey->key) != alg) {
2262 continue;
2263 }
2264
2265 if (ksk_key != NULL) {
2266 /*
2267 * Only checkds for one key at a time.
2268 */
2269 return (DNS_R_TOOMANYKEYS);
2270 }
2271
2272 ksk_key = dkey;
2273 }
2274 }
2275
2276 if (ksk_key == NULL) {
2277 return (DNS_R_NOKEYMATCH);
2278 }
2279
2280 if (dspublish) {
2281 dst_key_state_t s;
2282 dst_key_settime(ksk_key->key, DST_TIME_DSPUBLISH, when);
2283 result = dst_key_getstate(ksk_key->key, DST_KEY_DS, &s);
2284 if (result != ISC_R_SUCCESS || s != RUMOURED) {
2285 dst_key_setstate(ksk_key->key, DST_KEY_DS, RUMOURED);
2286 }
2287 } else {
2288 dst_key_state_t s;
2289 dst_key_settime(ksk_key->key, DST_TIME_DSDELETE, when);
2290 result = dst_key_getstate(ksk_key->key, DST_KEY_DS, &s);
2291 if (result != ISC_R_SUCCESS || s != UNRETENTIVE) {
2292 dst_key_setstate(ksk_key->key, DST_KEY_DS, UNRETENTIVE);
2293 }
2294 }
2295
2296 if (isc_log_wouldlog(dns_lctx, ISC_LOG_NOTICE)) {
2297 char keystr[DST_KEY_FORMATSIZE];
2298 char timestr[26]; /* Minimal buf as per ctime_r() spec. */
2299
2300 dst_key_format(ksk_key->key, keystr, sizeof(keystr));
2301 isc_stdtime_tostring(when, timestr, sizeof(timestr));
2302 isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
2303 DNS_LOGMODULE_DNSSEC, ISC_LOG_NOTICE,
2304 "keymgr: checkds DS for key %s seen %s at %s",
2305 keystr, dspublish ? "published" : "withdrawn",
2306 timestr);
2307 }
2308
2309 /* Store key state and update hints. */
2310 isc_dir_init(&dir);
2311 if (directory == NULL) {
2312 directory = ".";
2313 }
2314 result = isc_dir_open(&dir, directory);
2315 if (result != ISC_R_SUCCESS) {
2316 return (result);
2317 }
2318
2319 dns_dnssec_get_hints(ksk_key, now);
2320 result = dst_key_tofile(ksk_key->key, options, directory);
2321 if (result == ISC_R_SUCCESS) {
2322 dst_key_setmodified(ksk_key->key, false);
2323 }
2324 isc_dir_close(&dir);
2325
2326 return (result);
2327 }
2328
2329 isc_result_t
dns_keymgr_checkds(dns_kasp_t * kasp,dns_dnsseckeylist_t * keyring,const char * directory,isc_stdtime_t now,isc_stdtime_t when,bool dspublish)2330 dns_keymgr_checkds(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring,
2331 const char *directory, isc_stdtime_t now, isc_stdtime_t when,
2332 bool dspublish) {
2333 return (keymgr_checkds(kasp, keyring, directory, now, when, dspublish,
2334 0, 0, false));
2335 }
2336
2337 isc_result_t
dns_keymgr_checkds_id(dns_kasp_t * kasp,dns_dnsseckeylist_t * keyring,const char * directory,isc_stdtime_t now,isc_stdtime_t when,bool dspublish,dns_keytag_t id,unsigned int alg)2338 dns_keymgr_checkds_id(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring,
2339 const char *directory, isc_stdtime_t now,
2340 isc_stdtime_t when, bool dspublish, dns_keytag_t id,
2341 unsigned int alg) {
2342 return (keymgr_checkds(kasp, keyring, directory, now, when, dspublish,
2343 id, alg, true));
2344 }
2345
2346 static void
keytime_status(dst_key_t * key,isc_stdtime_t now,isc_buffer_t * buf,const char * pre,int ks,int kt)2347 keytime_status(dst_key_t *key, isc_stdtime_t now, isc_buffer_t *buf,
2348 const char *pre, int ks, int kt) {
2349 char timestr[26]; /* Minimal buf as per ctime_r() spec. */
2350 isc_result_t ret;
2351 isc_stdtime_t when = 0;
2352 dst_key_state_t state = NA;
2353
2354 isc_buffer_printf(buf, "%s", pre);
2355 (void)dst_key_getstate(key, ks, &state);
2356 ret = dst_key_gettime(key, kt, &when);
2357 if (state == RUMOURED || state == OMNIPRESENT) {
2358 isc_buffer_printf(buf, "yes - since ");
2359 } else if (now < when) {
2360 isc_buffer_printf(buf, "no - scheduled ");
2361 } else {
2362 isc_buffer_printf(buf, "no\n");
2363 return;
2364 }
2365 if (ret == ISC_R_SUCCESS) {
2366 isc_stdtime_tostring(when, timestr, sizeof(timestr));
2367 isc_buffer_printf(buf, "%s\n", timestr);
2368 }
2369 }
2370
2371 static void
rollover_status(dns_dnsseckey_t * dkey,dns_kasp_t * kasp,isc_stdtime_t now,isc_buffer_t * buf,bool zsk)2372 rollover_status(dns_dnsseckey_t *dkey, dns_kasp_t *kasp, isc_stdtime_t now,
2373 isc_buffer_t *buf, bool zsk) {
2374 char timestr[26]; /* Minimal buf as per ctime_r() spec. */
2375 isc_result_t ret = ISC_R_SUCCESS;
2376 isc_stdtime_t active_time = 0;
2377 dst_key_state_t state = NA, goal = NA;
2378 int rrsig, active, retire;
2379 dst_key_t *key = dkey->key;
2380
2381 if (zsk) {
2382 rrsig = DST_KEY_ZRRSIG;
2383 active = DST_TIME_ACTIVATE;
2384 retire = DST_TIME_INACTIVE;
2385 } else {
2386 rrsig = DST_KEY_KRRSIG;
2387 active = DST_TIME_PUBLISH;
2388 retire = DST_TIME_DELETE;
2389 }
2390
2391 isc_buffer_printf(buf, "\n");
2392
2393 (void)dst_key_getstate(key, DST_KEY_GOAL, &goal);
2394 (void)dst_key_getstate(key, rrsig, &state);
2395 (void)dst_key_gettime(key, active, &active_time);
2396 if (active_time == 0) {
2397 // only interested in keys that were once active.
2398 return;
2399 }
2400
2401 if (goal == HIDDEN && (state == UNRETENTIVE || state == HIDDEN)) {
2402 isc_stdtime_t remove_time = 0;
2403 // is the key removed yet?
2404 state = NA;
2405 (void)dst_key_getstate(key, DST_KEY_DNSKEY, &state);
2406 if (state == RUMOURED || state == OMNIPRESENT) {
2407 ret = dst_key_gettime(key, DST_TIME_DELETE,
2408 &remove_time);
2409 if (ret == ISC_R_SUCCESS) {
2410 isc_buffer_printf(buf, " Key is retired, will "
2411 "be removed on ");
2412 isc_stdtime_tostring(remove_time, timestr,
2413 sizeof(timestr));
2414 isc_buffer_printf(buf, "%s", timestr);
2415 }
2416 } else {
2417 isc_buffer_printf(
2418 buf, " Key has been removed from the zone");
2419 }
2420 } else {
2421 isc_stdtime_t retire_time = 0;
2422 uint32_t lifetime = 0;
2423 (void)dst_key_getnum(key, DST_NUM_LIFETIME, &lifetime);
2424 ret = dst_key_gettime(key, retire, &retire_time);
2425 if (ret == ISC_R_SUCCESS) {
2426 if (now < retire_time) {
2427 if (goal == OMNIPRESENT) {
2428 isc_buffer_printf(buf,
2429 " Next rollover "
2430 "scheduled on ");
2431 retire_time = keymgr_prepublication_time(
2432 dkey, kasp, lifetime, now);
2433 } else {
2434 isc_buffer_printf(
2435 buf, " Key will retire on ");
2436 }
2437 } else {
2438 isc_buffer_printf(buf,
2439 " Rollover is due since ");
2440 }
2441 isc_stdtime_tostring(retire_time, timestr,
2442 sizeof(timestr));
2443 isc_buffer_printf(buf, "%s", timestr);
2444 } else {
2445 isc_buffer_printf(buf, " No rollover scheduled");
2446 }
2447 }
2448 isc_buffer_printf(buf, "\n");
2449 }
2450
2451 static void
keystate_status(dst_key_t * key,isc_buffer_t * buf,const char * pre,int ks)2452 keystate_status(dst_key_t *key, isc_buffer_t *buf, const char *pre, int ks) {
2453 dst_key_state_t state = NA;
2454
2455 (void)dst_key_getstate(key, ks, &state);
2456 switch (state) {
2457 case HIDDEN:
2458 isc_buffer_printf(buf, " - %shidden\n", pre);
2459 break;
2460 case RUMOURED:
2461 isc_buffer_printf(buf, " - %srumoured\n", pre);
2462 break;
2463 case OMNIPRESENT:
2464 isc_buffer_printf(buf, " - %somnipresent\n", pre);
2465 break;
2466 case UNRETENTIVE:
2467 isc_buffer_printf(buf, " - %sunretentive\n", pre);
2468 break;
2469 case NA:
2470 default:
2471 /* print nothing */
2472 break;
2473 }
2474 }
2475
2476 void
dns_keymgr_status(dns_kasp_t * kasp,dns_dnsseckeylist_t * keyring,isc_stdtime_t now,char * out,size_t out_len)2477 dns_keymgr_status(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring,
2478 isc_stdtime_t now, char *out, size_t out_len) {
2479 isc_buffer_t buf;
2480 char timestr[26]; /* Minimal buf as per ctime_r() spec. */
2481
2482 REQUIRE(DNS_KASP_VALID(kasp));
2483 REQUIRE(keyring != NULL);
2484 REQUIRE(out != NULL);
2485
2486 isc_buffer_init(&buf, out, out_len);
2487
2488 // policy name
2489 isc_buffer_printf(&buf, "dnssec-policy: %s\n", dns_kasp_getname(kasp));
2490 isc_buffer_printf(&buf, "current time: ");
2491 isc_stdtime_tostring(now, timestr, sizeof(timestr));
2492 isc_buffer_printf(&buf, "%s\n", timestr);
2493
2494 for (dns_dnsseckey_t *dkey = ISC_LIST_HEAD(*keyring); dkey != NULL;
2495 dkey = ISC_LIST_NEXT(dkey, link))
2496 {
2497 char algstr[DNS_NAME_FORMATSIZE];
2498 bool ksk = false, zsk = false;
2499 isc_result_t ret;
2500
2501 if (dst_key_is_unused(dkey->key)) {
2502 continue;
2503 }
2504
2505 // key data
2506 dns_secalg_format((dns_secalg_t)dst_key_alg(dkey->key), algstr,
2507 sizeof(algstr));
2508 isc_buffer_printf(&buf, "\nkey: %d (%s), %s\n",
2509 dst_key_id(dkey->key), algstr,
2510 keymgr_keyrole(dkey->key));
2511
2512 // publish status
2513 keytime_status(dkey->key, now, &buf,
2514 " published: ", DST_KEY_DNSKEY,
2515 DST_TIME_PUBLISH);
2516
2517 // signing status
2518 ret = dst_key_getbool(dkey->key, DST_BOOL_KSK, &ksk);
2519 if (ret == ISC_R_SUCCESS && ksk) {
2520 keytime_status(dkey->key, now, &buf,
2521 " key signing: ", DST_KEY_KRRSIG,
2522 DST_TIME_PUBLISH);
2523 }
2524 ret = dst_key_getbool(dkey->key, DST_BOOL_ZSK, &zsk);
2525 if (ret == ISC_R_SUCCESS && zsk) {
2526 keytime_status(dkey->key, now, &buf,
2527 " zone signing: ", DST_KEY_ZRRSIG,
2528 DST_TIME_ACTIVATE);
2529 }
2530
2531 // rollover status
2532 rollover_status(dkey, kasp, now, &buf, zsk);
2533
2534 // key states
2535 keystate_status(dkey->key, &buf,
2536 "goal: ", DST_KEY_GOAL);
2537 keystate_status(dkey->key, &buf,
2538 "dnskey: ", DST_KEY_DNSKEY);
2539 keystate_status(dkey->key, &buf,
2540 "ds: ", DST_KEY_DS);
2541 keystate_status(dkey->key, &buf,
2542 "zone rrsig: ", DST_KEY_ZRRSIG);
2543 keystate_status(dkey->key, &buf,
2544 "key rrsig: ", DST_KEY_KRRSIG);
2545 }
2546 }
2547
2548 isc_result_t
dns_keymgr_rollover(dns_kasp_t * kasp,dns_dnsseckeylist_t * keyring,const char * directory,isc_stdtime_t now,isc_stdtime_t when,dns_keytag_t id,unsigned int algorithm)2549 dns_keymgr_rollover(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring,
2550 const char *directory, isc_stdtime_t now,
2551 isc_stdtime_t when, dns_keytag_t id,
2552 unsigned int algorithm) {
2553 int options = (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC | DST_TYPE_STATE);
2554 isc_dir_t dir;
2555 isc_result_t result;
2556 dns_dnsseckey_t *key = NULL;
2557 isc_stdtime_t active, retire, prepub;
2558
2559 REQUIRE(DNS_KASP_VALID(kasp));
2560 REQUIRE(keyring != NULL);
2561
2562 for (dns_dnsseckey_t *dkey = ISC_LIST_HEAD(*keyring); dkey != NULL;
2563 dkey = ISC_LIST_NEXT(dkey, link))
2564 {
2565 if (dst_key_id(dkey->key) != id) {
2566 continue;
2567 }
2568 if (algorithm > 0 && dst_key_alg(dkey->key) != algorithm) {
2569 continue;
2570 }
2571 if (key != NULL) {
2572 /*
2573 * Only rollover for one key at a time.
2574 */
2575 return (DNS_R_TOOMANYKEYS);
2576 }
2577 key = dkey;
2578 }
2579
2580 if (key == NULL) {
2581 return (DNS_R_NOKEYMATCH);
2582 }
2583
2584 result = dst_key_gettime(key->key, DST_TIME_ACTIVATE, &active);
2585 if (result != ISC_R_SUCCESS || active > now) {
2586 return (DNS_R_KEYNOTACTIVE);
2587 }
2588
2589 result = dst_key_gettime(key->key, DST_TIME_INACTIVE, &retire);
2590 if (result != ISC_R_SUCCESS) {
2591 /**
2592 * Default to as if this key was not scheduled to
2593 * become retired, as if it had unlimited lifetime.
2594 */
2595 retire = 0;
2596 }
2597
2598 /**
2599 * Usually when is set to now, which is before the scheduled
2600 * prepublication time, meaning we reduce the lifetime of the
2601 * key. But in some cases, the lifetime can also be extended.
2602 * We accept it, but we can return an error here if that
2603 * turns out to be unintuitive behavior.
2604 */
2605 prepub = dst_key_getttl(key->key) + dns_kasp_publishsafety(kasp) +
2606 dns_kasp_zonepropagationdelay(kasp);
2607 retire = when + prepub;
2608
2609 dst_key_settime(key->key, DST_TIME_INACTIVE, retire);
2610 dst_key_setnum(key->key, DST_NUM_LIFETIME, (retire - active));
2611
2612 /* Store key state and update hints. */
2613 isc_dir_init(&dir);
2614 if (directory == NULL) {
2615 directory = ".";
2616 }
2617 result = isc_dir_open(&dir, directory);
2618 if (result != ISC_R_SUCCESS) {
2619 return (result);
2620 }
2621
2622 dns_dnssec_get_hints(key, now);
2623 result = dst_key_tofile(key->key, options, directory);
2624 if (result == ISC_R_SUCCESS) {
2625 dst_key_setmodified(key->key, false);
2626 }
2627 isc_dir_close(&dir);
2628
2629 return (result);
2630 }
2631