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