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