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