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