From 63c5b453e0feab71d1647f4cff00d2e1b5da61ed Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Mon, 17 Feb 2025 12:05:25 +0100 Subject: [PATCH 01/13] Add manual-mode config option Add a new option 'manual-mode' to 'dnssec-policy'. The intended use is that if it is enabled, it will not automatically move to the next state transition (RUMOURED, UNRETENTIVE), only after manual confirmation. The intended state transition should be logged. --- bin/named/config.c | 2 ++ bin/tests/system/checkconf/good.conf.j2 | 1 + doc/arm/reference.rst | 10 ++++++++++ doc/misc/dnssec-policy.default.conf | 1 + doc/misc/options | 1 + lib/dns/include/dns/kasp.h | 25 +++++++++++++++++++++++++ lib/dns/kasp.c | 16 ++++++++++++++++ lib/isccfg/kaspconf.c | 9 ++++++++- lib/isccfg/namedconf.c | 1 + 9 files changed, 65 insertions(+), 1 deletion(-) diff --git a/bin/named/config.c b/bin/named/config.c index cb58713c8a..380c8ebc51 100644 --- a/bin/named/config.c +++ b/bin/named/config.c @@ -309,6 +309,7 @@ dnssec-policy \"default\" {\n\ cds-digest-types { 2; };\n\ dnskey-ttl " DNS_KASP_KEY_TTL ";\n\ inline-signing yes;\n\ + manual-mode no;\n\ offline-ksk no;\n\ publish-safety " DNS_KASP_PUBLISH_SAFETY "; \n\ retire-safety " DNS_KASP_RETIRE_SAFETY "; \n\ @@ -327,6 +328,7 @@ dnssec-policy \"insecure\" {\n\ max-zone-ttl 0; \n\ keys { };\n\ inline-signing yes;\n\ + manual-mode no;\n\ };\n\ \n\ " diff --git a/bin/tests/system/checkconf/good.conf.j2 b/bin/tests/system/checkconf/good.conf.j2 index 876b086787..fc33cb6503 100644 --- a/bin/tests/system/checkconf/good.conf.j2 +++ b/bin/tests/system/checkconf/good.conf.j2 @@ -27,6 +27,7 @@ dnssec-policy "test" { zsk lifetime P30D algorithm 13; csk key-store "hsm" lifetime P30D algorithm 8 2048; }; + manual-mode no; max-zone-ttl 86400; nsec3param ; parent-ds-ttl 7200; diff --git a/doc/arm/reference.rst b/doc/arm/reference.rst index 0592c64bf7..c0fb31ecad 100644 --- a/doc/arm/reference.rst +++ b/doc/arm/reference.rst @@ -6408,6 +6408,16 @@ keys ``insecure``. In this specific case, the existing key files should be moved to the zone's ``key-directory`` from the new configuration. +.. namedconf:statement:: manual-mode + :tags: dnssec + :short: Run key management in a manual mode. + + If enabled, BIND 9 does not automatically start and progress key rollovers, + instead the change is logged. Only after manual confirmation with + :option:`rndc dnssec -step ` the change is made. + + This feature is off by default. + .. namedconf:statement:: offline-ksk :tags: dnssec :short: Specifies whether the DNSKEY, CDS, and CDNSKEY RRsets are being signed offline. diff --git a/doc/misc/dnssec-policy.default.conf b/doc/misc/dnssec-policy.default.conf index d5571bac04..ce99f978fe 100644 --- a/doc/misc/dnssec-policy.default.conf +++ b/doc/misc/dnssec-policy.default.conf @@ -33,6 +33,7 @@ dnssec-policy "default" { signatures-validity-dnskey 14d; // Zone parameters + manual-mode no; inline-signing yes; max-zone-ttl 86400; zone-propagation-delay 300; diff --git a/doc/misc/options b/doc/misc/options index 3215fc7af7..5bb047d95a 100644 --- a/doc/misc/options +++ b/doc/misc/options @@ -16,6 +16,7 @@ dnssec-policy { dnskey-ttl ; inline-signing ; keys { ( csk | ksk | zsk ) [ key-directory | key-store ] lifetime algorithm [ tag-range ] [ ]; ... }; + manual-mode ; max-zone-ttl ; nsec3param [ iterations ] [ optout ] [ salt-length ]; offline-ksk ; diff --git a/lib/dns/include/dns/kasp.h b/lib/dns/include/dns/kasp.h index e2b0ea94df..999e08ddcb 100644 --- a/lib/dns/include/dns/kasp.h +++ b/lib/dns/include/dns/kasp.h @@ -108,6 +108,7 @@ struct dns_kasp { dns_ttl_t zone_max_ttl; uint32_t zone_propagation_delay; bool inline_signing; + bool manual_mode; /* Parent settings */ dns_ttl_t parent_ds_ttl; @@ -439,6 +440,30 @@ dns_kasp_setinlinesigning(dns_kasp_t *kasp, bool value); *\li 'kasp' is a valid, thawed kasp. */ +bool +dns_kasp_manualmode(dns_kasp_t *kasp); +/*%< + * Should we use manual-mode for this DNSSEC policy? + * + * Requires: + * + *\li 'kasp' is a valid, frozen kasp. + * + * Returns: + * + *\li true or false. + */ + +void +dns_kasp_setmanualmode(dns_kasp_t *kasp, bool value); +/*%< + * Set manual-mode. + * + * Requires: + * + *\li 'kasp' is a valid, thawed kasp. + */ + dns_ttl_t dns_kasp_zonemaxttl(dns_kasp_t *kasp, bool fallback); /*%< diff --git a/lib/dns/kasp.c b/lib/dns/kasp.c index 722c069d3a..884e3e33ec 100644 --- a/lib/dns/kasp.c +++ b/lib/dns/kasp.c @@ -273,6 +273,22 @@ dns_kasp_setinlinesigning(dns_kasp_t *kasp, bool value) { kasp->inline_signing = value; } +bool +dns_kasp_manualmode(dns_kasp_t *kasp) { + REQUIRE(DNS_KASP_VALID(kasp)); + REQUIRE(kasp->frozen); + + return kasp->manual_mode; +} + +void +dns_kasp_setmanualmode(dns_kasp_t *kasp, bool value) { + REQUIRE(DNS_KASP_VALID(kasp)); + REQUIRE(!kasp->frozen); + + kasp->manual_mode = value; +} + dns_ttl_t dns_kasp_zonemaxttl(dns_kasp_t *kasp, bool fallback) { REQUIRE(DNS_KASP_VALID(kasp)); diff --git a/lib/isccfg/kaspconf.c b/lib/isccfg/kaspconf.c index 4bc62c0ba4..d83e0af46b 100644 --- a/lib/isccfg/kaspconf.c +++ b/lib/isccfg/kaspconf.c @@ -473,7 +473,7 @@ cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp, uint32_t zonepropdelay = 0, parentpropdelay = 0; uint32_t ipub = 0, iret = 0; uint32_t ksk_min_lifetime = 0, zsk_min_lifetime = 0; - bool offline_ksk = false; + bool offline_ksk = false, manual_mode = false; REQUIRE(config != NULL); REQUIRE(kaspp != NULL && *kaspp == NULL); @@ -578,6 +578,13 @@ cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp, dns_kasp_setinlinesigning(kasp, true); } + obj = NULL; + (void)confget(maps, "manual-mode", &obj); + if (obj != NULL) { + manual_mode = cfg_obj_asboolean(obj); + } + dns_kasp_setmanualmode(kasp, manual_mode); + maxttl = get_duration(maps, "max-zone-ttl", DNS_KASP_ZONE_MAXTTL); dns_kasp_setzonemaxttl(kasp, maxttl); diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index 67824c75e8..6d204ebeeb 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -2213,6 +2213,7 @@ static cfg_clausedef_t dnssecpolicy_clauses[] = { { "dnskey-ttl", &cfg_type_duration, 0 }, { "inline-signing", &cfg_type_boolean, 0 }, { "keys", &cfg_type_kaspkeys, 0 }, + { "manual-mode", &cfg_type_boolean, 0 }, { "max-zone-ttl", &cfg_type_duration, 0 }, { "nsec3param", &cfg_type_nsec3, 0 }, { "offline-ksk", &cfg_type_boolean, 0 }, From aa49850b5e509daad29db41d4a34807d70458952 Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Wed, 19 Mar 2025 17:10:25 +0100 Subject: [PATCH 02/13] Implement manual-mode for kasp When a key retire, key generation/introduction, or a state transition to RUMOURED/UNRETENTIVE should happen, instead they are logged. When those logs look good, you can run 'rndc dnssec -step' to run the keymgr and apply those steps. --- bin/named/server.c | 17 ++-- lib/dns/include/dns/keymgr.h | 12 ++- lib/dns/include/dns/zone.h | 6 +- lib/dns/keymgr.c | 164 ++++++++++++++++++++++++++--------- lib/dns/zone.c | 25 +++++- 5 files changed, 173 insertions(+), 51 deletions(-) diff --git a/bin/named/server.c b/bin/named/server.c index 7afd9af9cf..84fb21ec21 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -6612,7 +6612,7 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig, * Ensure that zone keys are reloaded on reconfig */ if (dns_zone_getkasp(zone) != NULL) { - dns_zone_rekey(zone, fullsign); + dns_zone_rekey(zone, fullsign, false); } cleanup: @@ -12026,7 +12026,7 @@ named_server_rekey(named_server_t *server, isc_lex_t *lex, if (dns_zone_getkasp(zone) == NULL) { result = ISC_R_NOPERM; } else { - dns_zone_rekey(zone, fullsign); + dns_zone_rekey(zone, fullsign, false); } dns_zone_detach(&zone); @@ -14358,6 +14358,8 @@ named_server_dnssec(named_server_t *server, isc_lex_t *lex, dns_dnsseckeylist_t keys; char *ptr, *zonetext = NULL; const char *msg = NULL; + /* variables for -step */ + bool forcestep = false; /* variables for -checkds */ bool checkds = false, dspublish = false; /* variables for -rollover */ @@ -14401,6 +14403,8 @@ named_server_dnssec(named_server_t *server, isc_lex_t *lex, rollover = true; } else if (strcasecmp(ptr, "-checkds") == 0) { checkds = true; + } else if (strcasecmp(ptr, "-step") == 0) { + forcestep = true; } else { CHECK(DNS_R_SYNTAX); } @@ -14557,7 +14561,7 @@ named_server_dnssec(named_server_t *server, isc_lex_t *lex, * Rekey after checkds command because the next key * event may have changed. */ - dns_zone_rekey(zone, false); + dns_zone_rekey(zone, false, false); if (use_keyid) { char tagbuf[6]; @@ -14607,7 +14611,7 @@ named_server_dnssec(named_server_t *server, isc_lex_t *lex, * Rekey after rollover command because the next key * event may have changed. */ - dns_zone_rekey(zone, false); + dns_zone_rekey(zone, false, false); if (use_keyid) { char tagbuf[6]; @@ -14631,7 +14635,10 @@ named_server_dnssec(named_server_t *server, isc_lex_t *lex, CHECK(putstr(text, isc_result_totext(ret))); break; } + } else if (forcestep) { + dns_zone_rekey(zone, false, true); } + CHECK(putnull(text)); cleanup: @@ -16094,7 +16101,7 @@ named_server_skr(named_server_t *server, isc_lex_t *lex, isc_buffer_t **text) { CHECK(putnull(text)); } else { /* Schedule a rekey */ - dns_zone_rekey(zone, false); + dns_zone_rekey(zone, false, false); } cleanup: diff --git a/lib/dns/include/dns/keymgr.h b/lib/dns/include/dns/keymgr.h index bf24457e3c..b8cbf2d355 100644 --- a/lib/dns/include/dns/keymgr.h +++ b/lib/dns/include/dns/keymgr.h @@ -21,6 +21,11 @@ #include +#define DNS_KEYMGRATTR_NONE 0x00 /*%< No ordering. */ +#define DNS_KEYMGRATTR_S2I 0x01 /*%< Secure to insecure. */ +#define DNS_KEYMGRATTR_NOROLL 0x02 /*%< No rollover allowed. */ +#define DNS_KEYMGRATTR_FORCESTEP 0x04 /*%< Force next step in manual-mode */ + void dns_keymgr_settime_syncpublish(dst_key_t *key, dns_kasp_t *kasp, bool first); /*%< @@ -36,7 +41,8 @@ isc_result_t dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass, isc_mem_t *mctx, dns_dnsseckeylist_t *keyring, dns_dnsseckeylist_t *dnskeys, const char *keydir, - dns_kasp_t *kasp, isc_stdtime_t now, isc_stdtime_t *nexttime); + dns_kasp_t *kasp, uint8_t options, isc_stdtime_t now, + isc_stdtime_t *nexttime); /*%< * Manage keys in 'keyring' and update timing data according to 'kasp' policy. * Create new keys for 'origin' if necessary. Append all such keys, along @@ -45,6 +51,10 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass, * Update key states and store changes back to disk. Store when to run next * in 'nexttime'. * + * If 'options' has DNS_KEYMGRATTR_FORCESTEP set, the next steps in the process + * are allowed, even if 'kasp' has 'manual-mode' enabled. Other options should + * not be set in 'options'. + * * Requires: *\li 'origin' is a valid FQDN. *\li 'mctx' is a valid memory context. diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h index 193121b920..39c1183045 100644 --- a/lib/dns/include/dns/zone.h +++ b/lib/dns/include/dns/zone.h @@ -104,6 +104,7 @@ typedef enum { DNS_ZONEOPT_CHECKSVCB = 1 << 30, /*%< check SVBC records */ DNS_ZONEOPT_ZONEVERSION = 1U << 31, /*%< enable zoneversion */ DNS_ZONEOPT_FULLSIGN = 1ULL << 32, /*%< fully sign zone */ + DNS_ZONEOPT_FORCEKEYMGR = 1ULL << 33, /*%< force keymgr step */ DNS_ZONEOPT___MAX = UINT64_MAX, /* trick to make the ENUM 64-bit wide */ } dns_zoneopt_t; @@ -2210,7 +2211,7 @@ dns_zone_getprivatetype(dns_zone_t *zone); */ void -dns_zone_rekey(dns_zone_t *zone, bool fullsign); +dns_zone_rekey(dns_zone_t *zone, bool fullsign, bool forcekeymgr); /*%< * Update the zone's DNSKEY set from the key repository. * @@ -2218,6 +2219,9 @@ dns_zone_rekey(dns_zone_t *zone, bool fullsign); * the zone with the new key. Otherwise, if there are no keys or * if the new keys are for algorithms that have already signed the * zone, then the zone can be re-signed incrementally. + * + * If 'forcekeymgr' is true, trigger a rekey event and allow the + * next steps in the run to happen. */ isc_result_t diff --git a/lib/dns/keymgr.c b/lib/dns/keymgr.c index 3a18b26224..e9ab2a866a 100644 --- a/lib/dns/keymgr.c +++ b/lib/dns/keymgr.c @@ -342,7 +342,8 @@ keymgr_prepublication_time(dns_dnsseckey_t *key, dns_kasp_t *kasp, } static void -keymgr_key_retire(dns_dnsseckey_t *key, dns_kasp_t *kasp, isc_stdtime_t now) { +keymgr_key_retire(dns_dnsseckey_t *key, dns_kasp_t *kasp, uint8_t opts, + isc_stdtime_t now) { char keystr[DST_KEY_FORMATSIZE]; isc_result_t ret; isc_stdtime_t retire; @@ -352,17 +353,39 @@ keymgr_key_retire(dns_dnsseckey_t *key, dns_kasp_t *kasp, isc_stdtime_t now) { REQUIRE(key != NULL); REQUIRE(key->key != NULL); - /* This key wants to retire and hide in a corner. */ + dst_key_format(key->key, keystr, sizeof(keystr)); + + ret = dst_key_getstate(key->key, DST_KEY_GOAL, &s); + INSIST(ret == ISC_R_SUCCESS); + + if (dns_kasp_manualmode(kasp) && + (opts & DNS_KEYMGRATTR_FORCESTEP) == 0 && s != HIDDEN) + { + isc_log_write(DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_DNSSEC, + ISC_LOG_INFO, + "keymgr-manual-mode: block retire DNSKEY " + "%s (%s)", + keystr, keymgr_keyrole(key->key)); + return; + } else { + /* This key wants to retire and hide in a corner. */ + isc_log_write(DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_DNSSEC, + ISC_LOG_INFO, "keymgr: retire DNSKEY %s (%s)", + keystr, keymgr_keyrole(key->key)); + + dst_key_setstate(key->key, DST_KEY_GOAL, HIDDEN); + } + + /* + * This key may not have key states set yet. Pretend as if they are + * in the OMNIPRESENT state. + */ ret = dst_key_gettime(key->key, DST_TIME_INACTIVE, &retire); if (ret != ISC_R_SUCCESS || (retire > now)) { dst_key_settime(key->key, DST_TIME_INACTIVE, now); } - dst_key_setstate(key->key, DST_KEY_GOAL, HIDDEN); keymgr_settime_remove(key, kasp); - /* This key may not have key states set yet. Pretend as if they are - * in the OMNIPRESENT state. - */ if (dst_key_getstate(key->key, DST_KEY_DNSKEY, &s) != ISC_R_SUCCESS) { dst_key_setstate(key->key, DST_KEY_DNSKEY, OMNIPRESENT); dst_key_settime(key->key, DST_TIME_DNSKEY, now); @@ -391,11 +414,6 @@ keymgr_key_retire(dns_dnsseckey_t *key, dns_kasp_t *kasp, isc_stdtime_t now) { dst_key_settime(key->key, DST_TIME_ZRRSIG, now); } } - - dst_key_format(key->key, keystr, sizeof(keystr)); - isc_log_write(DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_DNSSEC, - ISC_LOG_INFO, "keymgr: retire DNSKEY %s (%s)", keystr, - keymgr_keyrole(key->key)); } /* Update lifetime and retire and remove time accordingly. */ @@ -963,7 +981,7 @@ keymgr_dnskey_hidden_or_chained(dns_dnsseckeylist_t *keyring, */ static bool keymgr_have_ds(dns_dnsseckeylist_t *keyring, dns_dnsseckey_t *key, int type, - dst_key_state_t next_state, bool secure_to_insecure) { + dst_key_state_t next_state, uint8_t opts) { /* (3a) */ dst_key_state_t states[2][NUM_KEYSTATES] = { /* DNSKEY, ZRRSIG, KRRSIG, DS */ @@ -981,7 +999,7 @@ keymgr_have_ds(dns_dnsseckeylist_t *keyring, dns_dnsseckey_t *key, int type, states[0], na, false, false) || keymgr_key_exists_with_state(keyring, key, type, next_state, states[1], na, false, false) || - (secure_to_insecure && + ((opts & DNS_KEYMGRATTR_S2I) != 0 && keymgr_key_exists_with_state(keyring, key, type, next_state, na, na, false, false)); } @@ -1220,17 +1238,14 @@ keymgr_policy_approval(dns_dnsseckeylist_t *keyring, dns_dnsseckey_t *key, */ static bool keymgr_transition_allowed(dns_dnsseckeylist_t *keyring, dns_dnsseckey_t *key, - int type, dst_key_state_t next_state, - bool secure_to_insecure) { + int type, dst_key_state_t next_state, uint8_t opts) { /* Debug logging. */ if (isc_log_wouldlog(ISC_LOG_DEBUG(1))) { bool rule1a, rule1b, rule2a, rule2b, rule3a, rule3b; char keystr[DST_KEY_FORMATSIZE]; dst_key_format(key->key, keystr, sizeof(keystr)); - rule1a = keymgr_have_ds(keyring, key, type, NA, - secure_to_insecure); - rule1b = keymgr_have_ds(keyring, key, type, next_state, - secure_to_insecure); + rule1a = keymgr_have_ds(keyring, key, type, NA, opts); + rule1b = keymgr_have_ds(keyring, key, type, next_state, opts); rule2a = keymgr_have_dnskey(keyring, key, type, NA); rule2b = keymgr_have_dnskey(keyring, key, type, next_state); rule3a = keymgr_have_rrsig(keyring, key, type, NA); @@ -1255,9 +1270,8 @@ keymgr_transition_allowed(dns_dnsseckeylist_t *keyring, dns_dnsseckey_t *key, * invalid state. If the rule check passes, also check if * the next state is also still a valid situation. */ - (!keymgr_have_ds(keyring, key, type, NA, secure_to_insecure) || - keymgr_have_ds(keyring, key, type, next_state, - secure_to_insecure)) && + (!keymgr_have_ds(keyring, key, type, NA, opts) || + keymgr_have_ds(keyring, key, type, next_state, opts)) && /* * Rule 2: There must be a DNSKEY at all times. Again, first * check the current situation, then assess the next state. @@ -1448,8 +1462,9 @@ keymgr_transition_time(dns_dnsseckey_t *key, int type, */ static isc_result_t keymgr_update(dns_dnsseckeylist_t *keyring, dns_kasp_t *kasp, isc_stdtime_t now, - isc_stdtime_t *nexttime, bool secure_to_insecure) { + isc_stdtime_t *nexttime, uint8_t opts) { bool changed; + bool force = ((opts & DNS_KEYMGRATTR_FORCESTEP) != 0); /* Repeat until nothing changed. */ transition: @@ -1534,8 +1549,7 @@ transition: /* Is the transition DNSSEC safe? */ if (!keymgr_transition_allowed(keyring, dkey, i, - next_state, - secure_to_insecure)) + next_state, opts)) { /* No, this would make the zone bogus. */ isc_log_write( @@ -1572,6 +1586,28 @@ transition: continue; } + /* + * Are we allowed to make the transition automatically? + */ + if (next_state != OMNIPRESENT && next_state != HIDDEN) { + if (dns_kasp_manualmode(kasp) && !force) { + isc_log_write( + DNS_LOGCATEGORY_DNSSEC, + DNS_LOGMODULE_DNSSEC, + ISC_LOG_INFO, + "keymgr-manual-mode: block " + "transition " + "%s %s type %s " + "state %s to state %s", + keymgr_keyrole(dkey->key), + keystr, keystatetags[i], + keystatestrings[state], + keystatestrings[next_state]); + continue; + } + } + + /* It is safe to make the transition. */ isc_log_write(DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_DNSSEC, ISC_LOG_DEBUG(1), "keymgr: transition %s %s type %s " @@ -1580,7 +1616,6 @@ transition: keystatetags[i], keystatestrings[state], keystatestrings[next_state]); - /* It is safe to make the transition. */ dst_key_setstate(dkey->key, i, next_state); dst_key_settime(dkey->key, keystatetimes[i], now); INSIST(dst_key_ismodified(dkey->key)); @@ -1590,6 +1625,8 @@ transition: /* We changed something, continue processing. */ if (changed) { + /* No longer force for the next run */ + force = false; goto transition; } @@ -1716,9 +1753,10 @@ keymgr_key_rollover(dns_kasp_key_t *kaspkey, dns_dnsseckey_t *active_key, dns_dnsseckeylist_t *keyring, dns_dnsseckeylist_t *newkeys, const dns_name_t *origin, dns_rdataclass_t rdclass, dns_kasp_t *kasp, const char *keydir, uint32_t lifetime, - bool rollover, isc_stdtime_t now, isc_stdtime_t *nexttime, + uint8_t opts, isc_stdtime_t now, isc_stdtime_t *nexttime, isc_mem_t *mctx) { char keystr[DST_KEY_FORMATSIZE]; + char namestr[DNS_NAME_FORMATSIZE]; isc_stdtime_t retire = 0, active = 0, prepub = 0; dns_dnsseckey_t *new_key = NULL; dst_key_t *dst_key = NULL; @@ -1795,7 +1833,7 @@ keymgr_key_rollover(dns_kasp_key_t *kaspkey, dns_dnsseckey_t *active_key, /* * If rollover is not allowed, warn. */ - if (!rollover) { + if ((opts & DNS_KEYMGRATTR_NOROLL) != 0) { dst_key_format(active_key->key, keystr, sizeof(keystr)); isc_log_write(DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_DNSSEC, ISC_LOG_WARNING, @@ -1806,7 +1844,6 @@ keymgr_key_rollover(dns_kasp_key_t *kaspkey, dns_dnsseckey_t *active_key, return ISC_R_SUCCESS; } } else if (isc_log_wouldlog(ISC_LOG_DEBUG(1))) { - char namestr[DNS_NAME_FORMATSIZE]; dns_name_format(origin, namestr, sizeof(namestr)); isc_log_write(DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_DNSSEC, ISC_LOG_DEBUG(1), @@ -1830,6 +1867,49 @@ keymgr_key_rollover(dns_kasp_key_t *kaspkey, dns_dnsseckey_t *active_key, } } + if (dns_kasp_manualmode(kasp) && (opts & DNS_KEYMGRATTR_FORCESTEP) == 0) + { + if (active_key != NULL && new_key != NULL) { + char keystr2[DST_KEY_FORMATSIZE]; + dst_key_format(active_key->key, keystr, sizeof(keystr)); + dst_key_format(new_key->key, keystr2, sizeof(keystr2)); + dns_name_format(origin, namestr, sizeof(namestr)); + isc_log_write( + DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_DNSSEC, + ISC_LOG_INFO, + "keymgr-manual-mode: block %s rollover for key " + "%s to key %s (policy %s)", + keymgr_keyrole(active_key->key), keystr, + keystr2, dns_kasp_getname(kasp)); + } else if (active_key != NULL) { + dst_key_format(active_key->key, keystr, sizeof(keystr)); + dns_name_format(origin, namestr, sizeof(namestr)); + isc_log_write(DNS_LOGCATEGORY_DNSSEC, + DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO, + "keymgr-manual-mode: block %s rollover " + "for key %s (policy %s)", + keymgr_keyrole(active_key->key), keystr, + dns_kasp_getname(kasp)); + } else if (new_key != NULL) { + dst_key_format(new_key->key, keystr, sizeof(keystr)); + dns_name_format(origin, namestr, sizeof(namestr)); + isc_log_write(DNS_LOGCATEGORY_DNSSEC, + DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO, + "keymgr-manual-mode: block %s " + "introduction %s (policy %s)", + keymgr_keyrole(new_key->key), keystr, + dns_kasp_getname(kasp)); + } else { + dns_name_format(origin, namestr, sizeof(namestr)); + isc_log_write(DNS_LOGCATEGORY_DNSSEC, + DNS_LOGMODULE_DNSSEC, ISC_LOG_INFO, + "keymgr-manual-mode: block new key " + "generation for zone %s (policy %s)", + namestr, dns_kasp_getname(kasp)); + } + return ISC_R_SUCCESS; + } + if (new_key == NULL) { /* No key available in keyring, create a new one. */ bool csk = (dns_kasp_key_ksk(kaspkey) && @@ -2039,10 +2119,10 @@ isc_result_t dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass, isc_mem_t *mctx, dns_dnsseckeylist_t *keyring, dns_dnsseckeylist_t *dnskeys, const char *keydir, - dns_kasp_t *kasp, isc_stdtime_t now, isc_stdtime_t *nexttime) { + dns_kasp_t *kasp, uint8_t opts, isc_stdtime_t now, + isc_stdtime_t *nexttime) { isc_result_t result = ISC_R_SUCCESS; dns_dnsseckeylist_t newkeys; - bool secure_to_insecure = false; int numkeys = 0; int options = (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC | DST_TYPE_STATE); char keystr[DST_KEY_FORMATSIZE]; @@ -2103,7 +2183,7 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass, /* No match, so retire unwanted retire key. */ if (!found_match) { - keymgr_key_retire(dkey, kasp, now); + keymgr_key_retire(dkey, kasp, opts, now); } /* Check purge-keys interval. */ @@ -2129,7 +2209,6 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass, ISC_LIST_FOREACH(dns_kasp_keys(kasp), kkey, link) { uint32_t lifetime = dns_kasp_key_lifetime(kkey); dns_dnsseckey_t *active_key = NULL; - bool rollover_allowed = true; /* Do we have keys available for this kasp key? */ ISC_LIST_FOREACH(*keyring, dkey, link) { @@ -2168,7 +2247,7 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass, * Retire excess keys in use. */ keymgr_key_retire(dkey, kasp, - now); + opts, now); } continue; } @@ -2206,7 +2285,7 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass, keystr, keymgr_keyrole(dnskey->key), dns_kasp_getname(kasp)); - rollover_allowed = false; + opts |= DNS_KEYMGRATTR_NOROLL; active_key = dnskey; break; } @@ -2214,10 +2293,11 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass, } /* See if this key requires a rollover. */ - RETERR(keymgr_key_rollover(kkey, active_key, keyring, &newkeys, - origin, rdclass, kasp, keydir, - lifetime, rollover_allowed, now, - nexttime, mctx)); + RETERR(keymgr_key_rollover( + kkey, active_key, keyring, &newkeys, origin, rdclass, + kasp, keydir, lifetime, opts, now, nexttime, mctx)); + + opts &= ~DNS_KEYMGRATTR_NOROLL; } /* Walked all kasp key configurations. Append new keys. */ @@ -2229,10 +2309,12 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass, * If the policy has an empty key list, this means the zone is going * back to unsigned. */ - secure_to_insecure = dns_kasp_keylist_empty(kasp); + if (dns_kasp_keylist_empty(kasp)) { + opts |= DNS_KEYMGRATTR_S2I; + } /* Read to update key states. */ - keymgr_update(keyring, kasp, now, nexttime, secure_to_insecure); + keymgr_update(keyring, kasp, now, nexttime, opts); /* Store key states and update hints. */ ISC_LIST_FOREACH(*keyring, dkey, link) { diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 0ca4efad23..2ccfe722ca 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -21211,7 +21211,7 @@ checkds_done(void *arg) { /* Rekey after checkds. */ if (rekey) { - dns_zone_rekey(zone, false); + dns_zone_rekey(zone, false, false); } failure: @@ -22233,6 +22233,7 @@ zone_rekey(dns_zone_t *zone) { bool newalg = false; bool fullsign; bool offlineksk = false; + uint8_t options = 0; uint32_t sigval = 0; dns_ttl_t ttl = 3600; const char *dir = NULL; @@ -22351,6 +22352,14 @@ zone_rekey(dns_zone_t *zone) { */ fullsign = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_FULLSIGN); + /* + * True when called from "rndc dnssec -step". Indicates the zone + * is allowed to do the next step(s) in the keymgr process. + */ + if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_FORCEKEYMGR)) { + options |= DNS_KEYMGRATTR_FORCESTEP; + } + if (offlineksk) { /* Lookup the correct bundle in the SKR. */ LOCK_ZONE(zone); @@ -22456,7 +22465,7 @@ zone_rekey(dns_zone_t *zone) { dns_zone_lock_keyfiles(zone); result = dns_keymgr_run(&zone->origin, zone->rdclass, mctx, &keys, &dnskeys, dir, - kasp, now, &nexttime); + kasp, options, now, &nexttime); dns_zone_unlock_keyfiles(zone); if (result != ISC_R_SUCCESS) { @@ -22936,6 +22945,13 @@ failure: 0); isc_time_nowplusinterval(&zone->refreshkeytime, &ival); } + + /* + * Clear forcekeymgr flag, if it was set, so we don't do + * another force next time. + */ + DNS_ZONE_CLROPTION(zone, DNS_ZONEOPT_FORCEKEYMGR); + UNLOCK_ZONE(zone); dns_diff_clear(&diff); @@ -22974,7 +22990,7 @@ failure: } void -dns_zone_rekey(dns_zone_t *zone, bool fullsign) { +dns_zone_rekey(dns_zone_t *zone, bool fullsign, bool forcekeymgr) { isc_time_t now; if (zone->type == dns_zone_primary && zone->loop != NULL) { @@ -22983,6 +22999,9 @@ dns_zone_rekey(dns_zone_t *zone, bool fullsign) { if (fullsign) { DNS_ZONE_SETOPTION(zone, DNS_ZONEOPT_FULLSIGN); } + if (forcekeymgr) { + DNS_ZONE_SETOPTION(zone, DNS_ZONEOPT_FORCEKEYMGR); + } now = isc_time_now(); zone->refreshkeytime = now; From a0dc0434e55e8b996f283db4b711921aeb8424c0 Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Thu, 24 Jul 2025 11:14:16 +0200 Subject: [PATCH 03/13] Detect if keymgr made changes If so we also want to tickle the apex because DNSKEY/CDNSKEY/CDS RRsets may need to be re-signed. Note that this may be overzealous, because if state transitions happen just because of timing events (RUMOURED -> OMNIPRESENT, UNRETENTIVE -> HIDDEN) this would have to cause changes in the zone DNSSEC records. --- lib/dns/keymgr.c | 14 ++++++++------ lib/dns/zone.c | 9 +++++++-- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/lib/dns/keymgr.c b/lib/dns/keymgr.c index e9ab2a866a..935d989c4d 100644 --- a/lib/dns/keymgr.c +++ b/lib/dns/keymgr.c @@ -1463,6 +1463,7 @@ keymgr_transition_time(dns_dnsseckey_t *key, int type, static isc_result_t keymgr_update(dns_dnsseckeylist_t *keyring, dns_kasp_t *kasp, isc_stdtime_t now, isc_stdtime_t *nexttime, uint8_t opts) { + isc_result_t result = DNS_R_UNCHANGED; bool changed; bool force = ((opts & DNS_KEYMGRATTR_FORCESTEP) != 0); @@ -1625,12 +1626,13 @@ transition: /* We changed something, continue processing. */ if (changed) { + result = ISC_R_SUCCESS; /* No longer force for the next run */ force = false; goto transition; } - return ISC_R_SUCCESS; + return result; } /* @@ -2121,7 +2123,7 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass, dns_dnsseckeylist_t *dnskeys, const char *keydir, dns_kasp_t *kasp, uint8_t opts, isc_stdtime_t now, isc_stdtime_t *nexttime) { - isc_result_t result = ISC_R_SUCCESS; + isc_result_t result = DNS_R_UNCHANGED; dns_dnsseckeylist_t newkeys; int numkeys = 0; int options = (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC | DST_TYPE_STATE); @@ -2314,7 +2316,7 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass, } /* Read to update key states. */ - keymgr_update(keyring, kasp, now, nexttime, opts); + isc_result_t retval = keymgr_update(keyring, kasp, now, nexttime, opts); /* Store key states and update hints. */ ISC_LIST_FOREACH(*keyring, dkey, link) { @@ -2322,6 +2324,7 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass, if (dst_key_getttl(dkey->key) != dns_kasp_dnskeyttl(kasp)) { dst_key_setttl(dkey->key, dns_kasp_dnskeyttl(kasp)); modified = true; + retval = ISC_R_SUCCESS; } if (modified && !dkey->purge) { const char *directory = dst_key_directory(dkey->key); @@ -2347,10 +2350,9 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass, dst_key_setmodified(dkey->key, false); } - result = ISC_R_SUCCESS; - + result = retval; failure: - if (result != ISC_R_SUCCESS) { + if (result != ISC_R_SUCCESS && result != DNS_R_UNCHANGED) { ISC_LIST_FOREACH(newkeys, newkey, link) { ISC_LIST_UNLINK(newkeys, newkey, link); INSIST(newkey->key != NULL); diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 2ccfe722ca..edd6f5d143 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -22233,6 +22233,7 @@ zone_rekey(dns_zone_t *zone) { bool newalg = false; bool fullsign; bool offlineksk = false; + bool kasp_change = false; uint8_t options = 0; uint32_t sigval = 0; dns_ttl_t ttl = 3600; @@ -22468,7 +22469,11 @@ zone_rekey(dns_zone_t *zone) { kasp, options, now, &nexttime); dns_zone_unlock_keyfiles(zone); - if (result != ISC_R_SUCCESS) { + if (result == ISC_R_SUCCESS) { + kasp_change = true; + } else if (result == DNS_R_UNCHANGED) { + result = ISC_R_SUCCESS; + } else { dnssec_log(zone, ISC_LOG_ERROR, "zone_rekey:dns_keymgr_run " "failed: %s", @@ -22686,7 +22691,7 @@ zone_rekey(dns_zone_t *zone) { "allowed"); } - if (newactive || fullsign || sane_diff) { + if (newactive || fullsign || sane_diff || kasp_change) { CHECK(dns_diff_apply(&diff, db, ver)); CHECK(clean_nsec3param(zone, db, ver, &diff)); CHECK(add_signing_records(db, zone->privatetype, ver, From 02460a009f2a0baf738bdbe7fccc60fe002451fb Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Tue, 22 Jul 2025 10:59:13 +0200 Subject: [PATCH 04/13] Prepare rollover system tests for manual-mode For the algorithm, CSK, KSK, ZSK rollovers, enabling DNSSEC and going insecure, add new zones to be tested in manual-mode. --- .../system/rollover-algo-csk/ns6/csk1.conf.j2 | 22 +- .../system/rollover-algo-csk/ns6/csk2.conf.j2 | 22 +- .../rollover-algo-csk/ns6/named.conf.j2 | 39 +- bin/tests/system/rollover-algo-csk/setup.sh | 222 ++++---- .../tests_rollover_algo_csk_initial.py | 15 +- .../rollover-algo-ksk-zsk/ns6/kasp.conf.j2 | 46 +- .../rollover-algo-ksk-zsk/ns6/named.conf.j2 | 40 +- .../system/rollover-algo-ksk-zsk/setup.sh | 320 +++++------ .../tests_rollover_algo_ksk_zsk_initial.py | 16 +- .../rollover-csk-roll1/ns3/kasp.conf.j2 | 26 +- .../rollover-csk-roll1/ns3/named.conf.j2 | 53 +- bin/tests/system/rollover-csk-roll1/setup.sh | 522 +++++++++--------- .../rollover-csk-roll2/ns3/kasp.conf.j2 | 26 +- .../rollover-csk-roll2/ns3/named.conf.j2 | 47 +- bin/tests/system/rollover-csk-roll2/setup.sh | 494 ++++++++--------- .../rollover-enable-dnssec/ns3/kasp.conf.j2 | 23 +- .../rollover-enable-dnssec/ns3/named.conf.j2 | 29 +- .../system/rollover-enable-dnssec/setup.sh | 106 ++-- .../rollover-ksk-3crowd/ns3/named.conf.j2 | 2 +- .../tests_rollover_three_is_a_crowd.py | 2 +- .../rollover-ksk-doubleksk/ns3/kasp.conf.j2 | 27 +- .../rollover-ksk-doubleksk/ns3/named.conf.j2 | 40 +- .../system/rollover-ksk-doubleksk/setup.sh | 384 ++++++------- .../tests_rollover_ksk_doubleksk.py | 2 +- .../rollover-zsk-prepub/ns3/kasp.conf.j2 | 23 +- .../rollover-zsk-prepub/ns3/named.conf.j2 | 40 +- bin/tests/system/rollover-zsk-prepub/setup.sh | 334 +++++------ .../tests_rollover_zsk_prepublication.py | 2 +- 28 files changed, 1592 insertions(+), 1332 deletions(-) diff --git a/bin/tests/system/rollover-algo-csk/ns6/csk1.conf.j2 b/bin/tests/system/rollover-algo-csk/ns6/csk1.conf.j2 index a5ff042db8..0af722acbf 100644 --- a/bin/tests/system/rollover-algo-csk/ns6/csk1.conf.j2 +++ b/bin/tests/system/rollover-algo-csk/ns6/csk1.conf.j2 @@ -11,7 +11,27 @@ * information regarding copyright ownership. */ -dnssec-policy "csk-algoroll" { +dnssec-policy "csk-algoroll-kasp" { + signatures-refresh P5D; + signatures-validity 30d; + signatures-validity-dnskey 30d; + + keys { + csk lifetime unlimited algorithm rsasha256; + }; + + dnskey-ttl 1h; + publish-safety PT1H; + retire-safety 2h; + zone-propagation-delay 3600; + max-zone-ttl 6h; + parent-propagation-delay pt1h; + parent-ds-ttl 7200; +}; + +dnssec-policy "csk-algoroll-manual" { + manual-mode yes; + signatures-refresh P5D; signatures-validity 30d; signatures-validity-dnskey 30d; diff --git a/bin/tests/system/rollover-algo-csk/ns6/csk2.conf.j2 b/bin/tests/system/rollover-algo-csk/ns6/csk2.conf.j2 index 6d290c3c32..5afdd1e774 100644 --- a/bin/tests/system/rollover-algo-csk/ns6/csk2.conf.j2 +++ b/bin/tests/system/rollover-algo-csk/ns6/csk2.conf.j2 @@ -11,7 +11,27 @@ * information regarding copyright ownership. */ -dnssec-policy "csk-algoroll" { +dnssec-policy "csk-algoroll-kasp" { + signatures-refresh P5D; + signatures-validity 30d; + signatures-validity-dnskey 30d; + + keys { + csk lifetime unlimited algorithm @DEFAULT_ALGORITHM@; + }; + + dnskey-ttl 1h; + publish-safety PT1H; + retire-safety 2h; + zone-propagation-delay 3600; + max-zone-ttl 6h; + parent-propagation-delay pt1h; + parent-ds-ttl 7200; +}; + +dnssec-policy "csk-algoroll-manual" { + manual-mode yes; + signatures-refresh P5D; signatures-validity 30d; signatures-validity-dnskey 30d; diff --git a/bin/tests/system/rollover-algo-csk/ns6/named.conf.j2 b/bin/tests/system/rollover-algo-csk/ns6/named.conf.j2 index d5e785bb27..8bcf2bf149 100644 --- a/bin/tests/system/rollover-algo-csk/ns6/named.conf.j2 +++ b/bin/tests/system/rollover-algo-csk/ns6/named.conf.j2 @@ -13,44 +13,47 @@ {% set csk_roll = csk_roll | default(False) %} {% set _csk_file = "csk1.conf" if not csk_roll else "csk2.conf" %} +{% set zones = ["kasp", "manual"] %} include "@_csk_file@"; include "named.common.conf"; -zone "step1.csk-algorithm-roll.kasp" { +{% for tld in zones %} +zone "step1.csk-algorithm-roll.@tld@" { type primary; - file "step1.csk-algorithm-roll.kasp.db"; - dnssec-policy "csk-algoroll"; + file "step1.csk-algorithm-roll.@tld@.db"; + dnssec-policy "csk-algoroll-@tld@"; }; {% if csk_roll %} -zone "step2.csk-algorithm-roll.kasp" { +zone "step2.csk-algorithm-roll.@tld@" { type primary; - file "step2.csk-algorithm-roll.kasp.db"; - dnssec-policy "csk-algoroll"; + file "step2.csk-algorithm-roll.@tld@.db"; + dnssec-policy "csk-algoroll-@tld@"; }; -zone "step3.csk-algorithm-roll.kasp" { +zone "step3.csk-algorithm-roll.@tld@" { type primary; - file "step3.csk-algorithm-roll.kasp.db"; - dnssec-policy "csk-algoroll"; + file "step3.csk-algorithm-roll.@tld@.db"; + dnssec-policy "csk-algoroll-@tld@"; }; -zone "step4.csk-algorithm-roll.kasp" { +zone "step4.csk-algorithm-roll.@tld@" { type primary; - file "step4.csk-algorithm-roll.kasp.db"; - dnssec-policy "csk-algoroll"; + file "step4.csk-algorithm-roll.@tld@.db"; + dnssec-policy "csk-algoroll-@tld@"; }; -zone "step5.csk-algorithm-roll.kasp" { +zone "step5.csk-algorithm-roll.@tld@" { type primary; - file "step5.csk-algorithm-roll.kasp.db"; - dnssec-policy "csk-algoroll"; + file "step5.csk-algorithm-roll.@tld@.db"; + dnssec-policy "csk-algoroll-@tld@"; }; -zone "step6.csk-algorithm-roll.kasp" { +zone "step6.csk-algorithm-roll.@tld@" { type primary; - file "step6.csk-algorithm-roll.kasp.db"; - dnssec-policy "csk-algoroll"; + file "step6.csk-algorithm-roll.@tld@.db"; + dnssec-policy "csk-algoroll-@tld@"; }; {% endif %} +{% endfor %} diff --git a/bin/tests/system/rollover-algo-csk/setup.sh b/bin/tests/system/rollover-algo-csk/setup.sh index 65318e6b94..200da1388e 100644 --- a/bin/tests/system/rollover-algo-csk/setup.sh +++ b/bin/tests/system/rollover-algo-csk/setup.sh @@ -30,121 +30,123 @@ O="OMNIPRESENT" U="UNRETENTIVE" # -# The zones at csk-algorithm-roll.kasp represent the various steps of a CSK +# The zones at csk-algorithm-roll.$tld represent the various steps of a CSK # algorithm rollover. # -# Step 1: -# Introduce the first key. This will immediately be active. -setup step1.csk-algorithm-roll.kasp -echo "$zone" >>zones -TactN="now-7d" -TsbmN="now-161h" -csktimes="-P ${TactN} -A ${TactN}" -CSK=$($KEYGEN -k csk-algoroll -l csk1.conf $csktimes $zone 2>keygen.out.$zone.1) -$SETTIME -s -g $O -k $O $TactN -r $O $TactN -z $O $TactN -d $O $TactN "$CSK" >settime.out.$zone.1 2>&1 -cat template.db.in "${CSK}.key" >"$infile" -private_type_record $zone 5 "$CSK" >>"$infile" -cp $infile $zonefile -$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 +for tld in kasp manual; do + # Step 1: + # Introduce the first key. This will immediately be active. + setup step1.csk-algorithm-roll.$tld + echo "$zone" >>zones + TactN="now-7d" + TsbmN="now-161h" + csktimes="-P ${TactN} -A ${TactN}" + CSK=$($KEYGEN -k csk-algoroll-$tld -l csk1.conf $csktimes $zone 2>keygen.out.$zone.1) + $SETTIME -s -g $O -k $O $TactN -r $O $TactN -z $O $TactN -d $O $TactN "$CSK" >settime.out.$zone.1 2>&1 + cat template.db.in "${CSK}.key" >"$infile" + private_type_record $zone 5 "$CSK" >>"$infile" + cp $infile $zonefile + $SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 2: -# After the publication interval has passed the DNSKEY is OMNIPRESENT. -setup step2.csk-algorithm-roll.kasp -# The time passed since the new algorithm keys have been introduced is 3 hours. -TpubN1="now-3h" -# Tsbm(N+1) = TpubN1 + Ipub = now + TTLsig + Dprp = now - 3h + 6h + 1h = now + 4h -TsbmN1="now+4h" -csktimes="-P ${TactN} -A ${TactN} -P sync ${TsbmN} -I now" -newtimes="-P ${TpubN1} -A ${TpubN1}" -CSK1=$($KEYGEN -k csk-algoroll -l csk1.conf $csktimes $zone 2>keygen.out.$zone.1) -CSK2=$($KEYGEN -k csk-algoroll -l csk2.conf $newtimes $zone 2>keygen.out.$zone.2) -$SETTIME -s -g $H -k $O $TactN -r $O $TactN -z $O $TactN -d $O $TactN "$CSK1" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $O -k $R $TpubN1 -r $R $TpubN1 -z $R $TpubN1 -d $H $TpubN1 "$CSK2" >settime.out.$zone.2 2>&1 -# Fake lifetime of old algorithm keys. -echo "Lifetime: 0" >>"${CSK1}.state" -cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile" -private_type_record $zone 5 "$CSK1" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile" -cp $infile $zonefile -$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 2: + # After the publication interval has passed the DNSKEY is OMNIPRESENT. + setup step2.csk-algorithm-roll.$tld + # The time passed since the new algorithm keys have been introduced is 3 hours. + TpubN1="now-3h" + # Tsbm(N+1) = TpubN1 + Ipub = now + TTLsig + Dprp = now - 3h + 6h + 1h = now + 4h + TsbmN1="now+4h" + csktimes="-P ${TactN} -A ${TactN} -P sync ${TsbmN} -I now" + newtimes="-P ${TpubN1} -A ${TpubN1}" + CSK1=$($KEYGEN -k csk-algoroll-$tld -l csk1.conf $csktimes $zone 2>keygen.out.$zone.1) + CSK2=$($KEYGEN -k csk-algoroll-$tld -l csk2.conf $newtimes $zone 2>keygen.out.$zone.2) + $SETTIME -s -g $H -k $O $TactN -r $O $TactN -z $O $TactN -d $O $TactN "$CSK1" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $O -k $R $TpubN1 -r $R $TpubN1 -z $R $TpubN1 -d $H $TpubN1 "$CSK2" >settime.out.$zone.2 2>&1 + # Fake lifetime of old algorithm keys. + echo "Lifetime: 0" >>"${CSK1}.state" + cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile" + private_type_record $zone 5 "$CSK1" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile" + cp $infile $zonefile + $SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 3: -# The zone signatures are also OMNIPRESENT. -setup step3.csk-algorithm-roll.kasp -# The time passed since the new algorithm keys have been introduced is 7 hours. -TpubN1="now-7h" -TsbmN1="now" -ckstimes="-P ${TactN} -A ${TactN} -P sync ${TsbmN} -I ${TsbmN1}" -newtimes="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}" -CSK1=$($KEYGEN -k csk-algoroll -l csk1.conf $csktimes $zone 2>keygen.out.$zone.1) -CSK2=$($KEYGEN -k csk-algoroll -l csk2.conf $newtimes $zone 2>keygen.out.$zone.2) -$SETTIME -s -g $H -k $O $TactN -r $O $TactN -z $O $TactN -d $O $TactN "$CSK1" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $O -k $O $TpubN1 -r $O $TpubN1 -z $R $TpubN1 -d $H $TpubN1 "$CSK2" >settime.out.$zone.2 2>&1 -# Fake lifetime of old algorithm keys. -echo "Lifetime: 0" >>"${CSK1}.state" -cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile" -private_type_record $zone 5 "$CSK1" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile" -cp $infile $zonefile -$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 3: + # The zone signatures are also OMNIPRESENT. + setup step3.csk-algorithm-roll.$tld + # The time passed since the new algorithm keys have been introduced is 7 hours. + TpubN1="now-7h" + TsbmN1="now" + ckstimes="-P ${TactN} -A ${TactN} -P sync ${TsbmN} -I ${TsbmN1}" + newtimes="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}" + CSK1=$($KEYGEN -k csk-algoroll-$tld -l csk1.conf $csktimes $zone 2>keygen.out.$zone.1) + CSK2=$($KEYGEN -k csk-algoroll-$tld -l csk2.conf $newtimes $zone 2>keygen.out.$zone.2) + $SETTIME -s -g $H -k $O $TactN -r $O $TactN -z $O $TactN -d $O $TactN "$CSK1" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $O -k $O $TpubN1 -r $O $TpubN1 -z $R $TpubN1 -d $H $TpubN1 "$CSK2" >settime.out.$zone.2 2>&1 + # Fake lifetime of old algorithm keys. + echo "Lifetime: 0" >>"${CSK1}.state" + cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile" + private_type_record $zone 5 "$CSK1" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile" + cp $infile $zonefile + $SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 4: -# The DS is swapped and can become OMNIPRESENT. -setup step4.csk-algorithm-roll.kasp -# The time passed since the DS has been swapped is 3 hours. -TpubN1="now-10h" -TsbmN1="now-3h" -csktimes="-P ${TactN} -A ${TactN} -P sync ${TsbmN} -I ${TsbmN1}" -newtimes="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}" -CSK1=$($KEYGEN -k csk-algoroll -l csk1.conf $csktimes $zone 2>keygen.out.$zone.1) -CSK2=$($KEYGEN -k csk-algoroll -l csk2.conf $newtimes $zone 2>keygen.out.$zone.2) -$SETTIME -s -g $H -k $O $TactN -r $O $TactN -z $O $TsbmN1 -d $U $TsbmN1 -D ds $TsbmN1 "$CSK1" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $O -k $O $TpubN1 -r $O $TpubN1 -z $O $TsbmN1 -d $R $TsbmN1 -P ds $TsbmN1 "$CSK2" >settime.out.$zone.2 2>&1 -# Fake lifetime of old algorithm keys. -echo "Lifetime: 0" >>"${CSK1}.state" -cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile" -private_type_record $zone 5 "$CSK1" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile" -cp $infile $zonefile -$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 4: + # The DS is swapped and can become OMNIPRESENT. + setup step4.csk-algorithm-roll.$tld + # The time passed since the DS has been swapped is 3 hours. + TpubN1="now-10h" + TsbmN1="now-3h" + csktimes="-P ${TactN} -A ${TactN} -P sync ${TsbmN} -I ${TsbmN1}" + newtimes="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}" + CSK1=$($KEYGEN -k csk-algoroll-$tld -l csk1.conf $csktimes $zone 2>keygen.out.$zone.1) + CSK2=$($KEYGEN -k csk-algoroll-$tld -l csk2.conf $newtimes $zone 2>keygen.out.$zone.2) + $SETTIME -s -g $H -k $O $TactN -r $O $TactN -z $O $TsbmN1 -d $U $TsbmN1 -D ds $TsbmN1 "$CSK1" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $O -k $O $TpubN1 -r $O $TpubN1 -z $O $TsbmN1 -d $R $TsbmN1 -P ds $TsbmN1 "$CSK2" >settime.out.$zone.2 2>&1 + # Fake lifetime of old algorithm keys. + echo "Lifetime: 0" >>"${CSK1}.state" + cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile" + private_type_record $zone 5 "$CSK1" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile" + cp $infile $zonefile + $SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 5: -# The DNSKEY is removed long enough to be HIDDEN. -setup step5.csk-algorithm-roll.kasp -# The time passed since the DNSKEY has been removed is 2 hours. -TpubN1="now-12h" -TsbmN1="now-5h" -csktimes="-P ${TactN} -A ${TactN} -P sync ${TsbmN} -I ${TsbmN1}" -newtimes="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}" -CSK1=$($KEYGEN -k csk-algoroll -l csk1.conf $csktimes $zone 2>keygen.out.$zone.1) -CSK2=$($KEYGEN -k csk-algoroll -l csk2.conf $newtimes $zone 2>keygen.out.$zone.2) -$SETTIME -s -g $H -k $U $TactN -r $U $TactN -z $U $TsbmN1 -d $H $TsbmN1 "$CSK1" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $O -k $O $TpubN1 -r $O $TpubN1 -z $O $TsbmN1 -d $O $TsbmN1 "$CSK2" >settime.out.$zone.2 2>&1 -# Fake lifetime of old algorithm keys. -echo "Lifetime: 0" >>"${CSK1}.state" -cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile" -private_type_record $zone 5 "$CSK1" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile" -cp $infile $zonefile -$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 5: + # The DNSKEY is removed long enough to be HIDDEN. + setup step5.csk-algorithm-roll.$tld + # The time passed since the DNSKEY has been removed is 2 hours. + TpubN1="now-12h" + TsbmN1="now-5h" + csktimes="-P ${TactN} -A ${TactN} -P sync ${TsbmN} -I ${TsbmN1}" + newtimes="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}" + CSK1=$($KEYGEN -k csk-algoroll-$tld -l csk1.conf $csktimes $zone 2>keygen.out.$zone.1) + CSK2=$($KEYGEN -k csk-algoroll-$tld -l csk2.conf $newtimes $zone 2>keygen.out.$zone.2) + $SETTIME -s -g $H -k $U $TactN -r $U $TactN -z $U $TsbmN1 -d $H $TsbmN1 "$CSK1" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $O -k $O $TpubN1 -r $O $TpubN1 -z $O $TsbmN1 -d $O $TsbmN1 "$CSK2" >settime.out.$zone.2 2>&1 + # Fake lifetime of old algorithm keys. + echo "Lifetime: 0" >>"${CSK1}.state" + cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile" + private_type_record $zone 5 "$CSK1" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile" + cp $infile $zonefile + $SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 6: -# The RRSIGs have been removed long enough to be HIDDEN. -setup step6.csk-algorithm-roll.kasp -# Additional time passed: 7h. -TpubN1="now-19h" -TsbmN1="now-12h" -csktimes="-P ${TactN} -A ${TactN} -P sync ${TsbmN} -I ${TsbmN1}" -newtimes="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}" -CSK1=$($KEYGEN -k csk-algoroll -l csk1.conf $csktimes $zone 2>keygen.out.$zone.1) -CSK2=$($KEYGEN -k csk-algoroll -l csk2.conf $newtimes $zone 2>keygen.out.$zone.2) -$SETTIME -s -g $H -k $H $TactN -r $U $TactN -z $U $TactN -d $H $TsbmN1 "$CSK1" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -z $O $TsubN1 -d $O $TsbmN1 "$CSK2" >settime.out.$zone.2 2>&1 -# Fake lifetime of old algorithm keys. -echo "Lifetime: 0" >>"${CSK1}.state" -cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile" -private_type_record $zone 5 "$CSK1" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile" -cp $infile $zonefile -$SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 6: + # The RRSIGs have been removed long enough to be HIDDEN. + setup step6.csk-algorithm-roll.$tld + # Additional time passed: 7h. + TpubN1="now-19h" + TsbmN1="now-12h" + csktimes="-P ${TactN} -A ${TactN} -P sync ${TsbmN} -I ${TsbmN1}" + newtimes="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}" + CSK1=$($KEYGEN -k csk-algoroll-$tld -l csk1.conf $csktimes $zone 2>keygen.out.$zone.1) + CSK2=$($KEYGEN -k csk-algoroll-$tld -l csk2.conf $newtimes $zone 2>keygen.out.$zone.2) + $SETTIME -s -g $H -k $H $TactN -r $U $TactN -z $U $TactN -d $H $TsbmN1 "$CSK1" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -z $O $TsubN1 -d $O $TsbmN1 "$CSK2" >settime.out.$zone.2 2>&1 + # Fake lifetime of old algorithm keys. + echo "Lifetime: 0" >>"${CSK1}.state" + cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile" + private_type_record $zone 5 "$CSK1" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile" + cp $infile $zonefile + $SIGNER -S -x -z -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 +done diff --git a/bin/tests/system/rollover-algo-csk/tests_rollover_algo_csk_initial.py b/bin/tests/system/rollover-algo-csk/tests_rollover_algo_csk_initial.py index 9db1f819fa..d8178f623e 100644 --- a/bin/tests/system/rollover-algo-csk/tests_rollover_algo_csk_initial.py +++ b/bin/tests/system/rollover-algo-csk/tests_rollover_algo_csk_initial.py @@ -11,7 +11,10 @@ # pylint: disable=redefined-outer-name,unused-import +import pytest + import isctest +from isctest.util import param from rollover.common import ( pytestmark, CDSS, @@ -21,10 +24,16 @@ from rollover.common import ( ) -def test_algoroll_csk_initial(ns6): +@pytest.mark.parametrize( + "tld, policy", + [ + param("kasp", "csk-algoroll"), + param("manual", "csk-algoroll-manual"), + ], +) +def test_algoroll_csk_initial(ns6, tld, policy): config = ALGOROLL_CONFIG - policy = "csk-algoroll" - zone = "step1.csk-algorithm-roll.kasp" + zone = f"step1.csk-algorithm-roll.{tld}" isctest.kasp.wait_keymgr_done(ns6, zone) diff --git a/bin/tests/system/rollover-algo-ksk-zsk/ns6/kasp.conf.j2 b/bin/tests/system/rollover-algo-ksk-zsk/ns6/kasp.conf.j2 index ac3089fe90..4c85e1a03a 100644 --- a/bin/tests/system/rollover-algo-ksk-zsk/ns6/kasp.conf.j2 +++ b/bin/tests/system/rollover-algo-ksk-zsk/ns6/kasp.conf.j2 @@ -11,7 +11,7 @@ * information regarding copyright ownership. */ -dnssec-policy "rsasha256" { +dnssec-policy "rsasha256-kasp" { signatures-refresh P5D; signatures-validity 30d; signatures-validity-dnskey 30d; @@ -30,7 +30,49 @@ dnssec-policy "rsasha256" { parent-ds-ttl 7200; }; -dnssec-policy "ecdsa256" { +dnssec-policy "rsasha256-manual" { + manual-mode yes; + + signatures-refresh P5D; + signatures-validity 30d; + signatures-validity-dnskey 30d; + + keys { + ksk lifetime unlimited algorithm rsasha256; + zsk lifetime unlimited algorithm rsasha256; + }; + + dnskey-ttl 1h; + publish-safety PT1H; + retire-safety 2h; + zone-propagation-delay 3600; + max-zone-ttl 6h; + parent-propagation-delay pt1h; + parent-ds-ttl 7200; +}; + +dnssec-policy "ecdsa256-kasp" { + signatures-refresh P5D; + signatures-validity 30d; + signatures-validity-dnskey 30d; + + keys { + ksk lifetime unlimited algorithm ecdsa256; + zsk lifetime unlimited algorithm ecdsa256; + }; + + dnskey-ttl 1h; + publish-safety PT1H; + retire-safety 2h; + zone-propagation-delay 3600; + max-zone-ttl 6h; + parent-propagation-delay pt1h; + parent-ds-ttl 7200; +}; + +dnssec-policy "ecdsa256-manual" { + manual-mode yes; + signatures-refresh P5D; signatures-validity 30d; signatures-validity-dnskey 30d; diff --git a/bin/tests/system/rollover-algo-ksk-zsk/ns6/named.conf.j2 b/bin/tests/system/rollover-algo-ksk-zsk/ns6/named.conf.j2 index 02ce2368c5..b338623caa 100644 --- a/bin/tests/system/rollover-algo-ksk-zsk/ns6/named.conf.j2 +++ b/bin/tests/system/rollover-algo-ksk-zsk/ns6/named.conf.j2 @@ -13,44 +13,48 @@ {% set alg_roll = alg_roll | default(False) %} {% set policy = "rsasha256" if not alg_roll else "ecdsa256" %} +{% set zones = ["kasp", "manual"] %} include "kasp.conf"; include "named.common.conf"; -zone "step1.algorithm-roll.kasp" { +{% for tld in zones %} +zone "step1.algorithm-roll.@tld@" { type primary; - file "step1.algorithm-roll.kasp.db"; - dnssec-policy @policy@; + file "step1.algorithm-roll.@tld@.db"; + dnssec-policy @policy@-@tld@; }; {% if alg_roll %} -zone "step2.algorithm-roll.kasp" { +zone "step2.algorithm-roll.@tld@" { type primary; - file "step2.algorithm-roll.kasp.db"; - dnssec-policy "ecdsa256"; + file "step2.algorithm-roll.@tld@.db"; + dnssec-policy "ecdsa256-@tld@"; }; -zone "step3.algorithm-roll.kasp" { +zone "step3.algorithm-roll.@tld@" { type primary; - file "step3.algorithm-roll.kasp.db"; - dnssec-policy "ecdsa256"; + file "step3.algorithm-roll.@tld@.db"; + dnssec-policy "ecdsa256-@tld@"; }; -zone "step4.algorithm-roll.kasp" { +zone "step4.algorithm-roll.@tld@" { type primary; - file "step4.algorithm-roll.kasp.db"; - dnssec-policy "ecdsa256"; + file "step4.algorithm-roll.@tld@.db"; + dnssec-policy "ecdsa256-@tld@"; }; -zone "step5.algorithm-roll.kasp" { +zone "step5.algorithm-roll.@tld@" { type primary; - file "step5.algorithm-roll.kasp.db"; - dnssec-policy "ecdsa256"; + file "step5.algorithm-roll.@tld@.db"; + dnssec-policy "ecdsa256-@tld@"; }; -zone "step6.algorithm-roll.kasp" { +zone "step6.algorithm-roll.@tld@" { type primary; - file "step6.algorithm-roll.kasp.db"; - dnssec-policy "ecdsa256"; + file "step6.algorithm-roll.@tld@.db"; + dnssec-policy "ecdsa256-@tld@"; }; + {% endif %} +{% endfor %} diff --git a/bin/tests/system/rollover-algo-ksk-zsk/setup.sh b/bin/tests/system/rollover-algo-ksk-zsk/setup.sh index 5f7a370f14..db27d74e71 100644 --- a/bin/tests/system/rollover-algo-ksk-zsk/setup.sh +++ b/bin/tests/system/rollover-algo-ksk-zsk/setup.sh @@ -30,170 +30,172 @@ O="OMNIPRESENT" U="UNRETENTIVE" # -# The zones at algorithm-roll.kasp represent the various steps of a ZSK/KSK +# The zones at algorithm-roll.$tld represent the various steps of a ZSK/KSK # algorithm rollover. # -# Step 1: -# Introduce the first key. This will immediately be active. -setup step1.algorithm-roll.kasp -echo "$zone" >>zones -TactN="now-7d" -TsbmN="now-161h" -ksktimes="-P ${TactN} -A ${TactN}" -zsktimes="-P ${TactN} -A ${TactN}" -KSK=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksktimes $zone 2>keygen.out.$zone.1) -ZSK=$($KEYGEN -a RSASHA256 -L 3600 $zsktimes $zone 2>keygen.out.$zone.2) -$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" >settime.out.$zone.2 2>&1 -cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile" -private_type_record $zone 8 "$KSK" >>"$infile" -private_type_record $zone 8 "$ZSK" >>"$infile" -cp $infile $zonefile -$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 +for tld in kasp manual; do + # Step 1: + # Introduce the first key. This will immediately be active. + setup step1.algorithm-roll.$tld + echo "$zone" >>zones + TactN="now-7d" + TsbmN="now-161h" + ksktimes="-P ${TactN} -A ${TactN}" + zsktimes="-P ${TactN} -A ${TactN}" + KSK=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksktimes $zone 2>keygen.out.$zone.1) + ZSK=$($KEYGEN -a RSASHA256 -L 3600 $zsktimes $zone 2>keygen.out.$zone.2) + $SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" >settime.out.$zone.2 2>&1 + cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile" + private_type_record $zone 8 "$KSK" >>"$infile" + private_type_record $zone 8 "$ZSK" >>"$infile" + cp $infile $zonefile + $SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 2: -# After the publication interval has passed the DNSKEY is OMNIPRESENT. -setup step2.algorithm-roll.kasp -# The time passed since the new algorithm keys have been introduced is 3 hours. -TpubN1="now-3h" -# Tsbm(N+1) = TpubN1 + Ipub = now + TTLsig + Dprp = now - 3h + 6h + 1h = now + 4h -TsbmN1="now+4h" -ksk1times="-P ${TactN} -A ${TactN} -P sync ${TsbmN} -I ${TsbmN1}" -zsk1times="-P ${TactN} -A ${TactN} -I ${TsbmN1}" -ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}" -zsk2times="-P ${TpubN1} -A ${TpubN1}" -KSK1=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksk1times $zone 2>keygen.out.$zone.1) -ZSK1=$($KEYGEN -a RSASHA256 -L 3600 $zsk1times $zone 2>keygen.out.$zone.2) -KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksk2times $zone 2>keygen.out.$zone.3) -ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsk2times $zone 2>keygen.out.$zone.4) -$SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $O $TactN "$KSK1" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $H -k $O $TactN -z $O $TactN "$ZSK1" >settime.out.$zone.2 2>&1 -$SETTIME -s -g $O -k $R $TpubN1 -r $R $TpubN1 -d $H $TpubN1 "$KSK2" >settime.out.$zone.3 2>&1 -$SETTIME -s -g $O -k $R $TpubN1 -z $R $TpubN1 "$ZSK2" >settime.out.$zone.4 2>&1 -# Fake lifetime of old algorithm keys. -echo "Lifetime: 0" >>"${KSK1}.state" -echo "Lifetime: 0" >>"${ZSK1}.state" -cat template.db.in "${KSK1}.key" "${ZSK1}.key" "${KSK2}.key" "${ZSK2}.key" >"$infile" -private_type_record $zone 8 "$KSK1" >>"$infile" -private_type_record $zone 8 "$ZSK1" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >>"$infile" -cp $infile $zonefile -$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 2: + # After the publication interval has passed the DNSKEY is OMNIPRESENT. + setup step2.algorithm-roll.$tld + # The time passed since the new algorithm keys have been introduced is 3 hours. + TpubN1="now-3h" + # Tsbm(N+1) = TpubN1 + Ipub = now + TTLsig + Dprp = now - 3h + 6h + 1h = now + 4h + TsbmN1="now+4h" + ksk1times="-P ${TactN} -A ${TactN} -P sync ${TsbmN} -I ${TsbmN1}" + zsk1times="-P ${TactN} -A ${TactN} -I ${TsbmN1}" + ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}" + zsk2times="-P ${TpubN1} -A ${TpubN1}" + KSK1=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksk1times $zone 2>keygen.out.$zone.1) + ZSK1=$($KEYGEN -a RSASHA256 -L 3600 $zsk1times $zone 2>keygen.out.$zone.2) + KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksk2times $zone 2>keygen.out.$zone.3) + ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsk2times $zone 2>keygen.out.$zone.4) + $SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $O $TactN "$KSK1" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $H -k $O $TactN -z $O $TactN "$ZSK1" >settime.out.$zone.2 2>&1 + $SETTIME -s -g $O -k $R $TpubN1 -r $R $TpubN1 -d $H $TpubN1 "$KSK2" >settime.out.$zone.3 2>&1 + $SETTIME -s -g $O -k $R $TpubN1 -z $R $TpubN1 "$ZSK2" >settime.out.$zone.4 2>&1 + # Fake lifetime of old algorithm keys. + echo "Lifetime: 0" >>"${KSK1}.state" + echo "Lifetime: 0" >>"${ZSK1}.state" + cat template.db.in "${KSK1}.key" "${ZSK1}.key" "${KSK2}.key" "${ZSK2}.key" >"$infile" + private_type_record $zone 8 "$KSK1" >>"$infile" + private_type_record $zone 8 "$ZSK1" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >>"$infile" + cp $infile $zonefile + $SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 3: -# The zone signatures are also OMNIPRESENT. -setup step3.algorithm-roll.kasp -# The time passed since the new algorithm keys have been introduced is 7 hours. -TpubN1="now-7h" -TsbmN1="now" -ksk1times="-P ${TactN} -A ${TactN} -P sync ${TsbmN} -I ${TsbmN1}" -zsk1times="-P ${TactN} -A ${TactN} -I ${TsbmN1}" -ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}" -zsk2times="-P ${TpubN1} -A ${TpubN1}" -KSK1=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksk1times $zone 2>keygen.out.$zone.1) -ZSK1=$($KEYGEN -a RSASHA256 -L 3600 $zsk1times $zone 2>keygen.out.$zone.2) -KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksk2times $zone 2>keygen.out.$zone.3) -ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsk2times $zone 2>keygen.out.$zone.4) -$SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $O $TactN "$KSK1" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $H -k $O $TactN -z $O $TactN "$ZSK1" >settime.out.$zone.2 2>&1 -$SETTIME -s -g $O -k $O $TpubN1 -r $O $TpubN1 -d $H $TpubN1 "$KSK2" >settime.out.$zone.3 2>&1 -$SETTIME -s -g $O -k $O $TpubN1 -z $R $TpubN1 "$ZSK2" >settime.out.$zone.4 2>&1 -# Fake lifetime of old algorithm keys. -echo "Lifetime: 0" >>"${KSK1}.state" -echo "Lifetime: 0" >>"${ZSK1}.state" -cat template.db.in "${KSK1}.key" "${ZSK1}.key" "${KSK2}.key" "${ZSK2}.key" >"$infile" -private_type_record $zone 8 "$KSK1" >>"$infile" -private_type_record $zone 8 "$ZSK1" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >>"$infile" -cp $infile $zonefile -$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 3: + # The zone signatures are also OMNIPRESENT. + setup step3.algorithm-roll.$tld + # The time passed since the new algorithm keys have been introduced is 7 hours. + TpubN1="now-7h" + TsbmN1="now" + ksk1times="-P ${TactN} -A ${TactN} -P sync ${TsbmN} -I ${TsbmN1}" + zsk1times="-P ${TactN} -A ${TactN} -I ${TsbmN1}" + ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}" + zsk2times="-P ${TpubN1} -A ${TpubN1}" + KSK1=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksk1times $zone 2>keygen.out.$zone.1) + ZSK1=$($KEYGEN -a RSASHA256 -L 3600 $zsk1times $zone 2>keygen.out.$zone.2) + KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksk2times $zone 2>keygen.out.$zone.3) + ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsk2times $zone 2>keygen.out.$zone.4) + $SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $O $TactN "$KSK1" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $H -k $O $TactN -z $O $TactN "$ZSK1" >settime.out.$zone.2 2>&1 + $SETTIME -s -g $O -k $O $TpubN1 -r $O $TpubN1 -d $H $TpubN1 "$KSK2" >settime.out.$zone.3 2>&1 + $SETTIME -s -g $O -k $O $TpubN1 -z $R $TpubN1 "$ZSK2" >settime.out.$zone.4 2>&1 + # Fake lifetime of old algorithm keys. + echo "Lifetime: 0" >>"${KSK1}.state" + echo "Lifetime: 0" >>"${ZSK1}.state" + cat template.db.in "${KSK1}.key" "${ZSK1}.key" "${KSK2}.key" "${ZSK2}.key" >"$infile" + private_type_record $zone 8 "$KSK1" >>"$infile" + private_type_record $zone 8 "$ZSK1" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >>"$infile" + cp $infile $zonefile + $SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 4: -# The DS is swapped and can become OMNIPRESENT. -setup step4.algorithm-roll.kasp -# The time passed since the DS has been swapped is 3 hours. -TpubN1="now-10h" -TsbmN1="now-3h" -ksk1times="-P ${TactN} -A ${TactN} -P sync ${TsbmN} -I ${TsbmN1}" -zsk1times="-P ${TactN} -A ${TactN} -I ${TsbmN1}" -ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}" -zsk2times="-P ${TpubN1} -A ${TpubN1}" -KSK1=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksk1times $zone 2>keygen.out.$zone.1) -ZSK1=$($KEYGEN -a RSASHA256 -L 3600 $zsk1times $zone 2>keygen.out.$zone.2) -KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksk2times $zone 2>keygen.out.$zone.3) -ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsk2times $zone 2>keygen.out.$zone.4) -$SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $U $TsbmN1 -D ds $TsbmN1 "$KSK1" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $H -k $O $TactN -z $O $TactN "$ZSK1" >settime.out.$zone.2 2>&1 -$SETTIME -s -g $O -k $O $TpubN1 -r $O $TpubN1 -d $R $TsbmN1 -P ds $TsbmN1 "$KSK2" >settime.out.$zone.3 2>&1 -$SETTIME -s -g $O -k $O $TpubN1 -z $R $TpubN1 "$ZSK2" >settime.out.$zone.4 2>&1 -# Fake lifetime of old algorithm keys. -echo "Lifetime: 0" >>"${KSK1}.state" -echo "Lifetime: 0" >>"${ZSK1}.state" -cat template.db.in "${KSK1}.key" "${ZSK1}.key" "${KSK2}.key" "${ZSK2}.key" >"$infile" -private_type_record $zone 8 "$KSK1" >>"$infile" -private_type_record $zone 8 "$ZSK1" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >>"$infile" -cp $infile $zonefile -$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 4: + # The DS is swapped and can become OMNIPRESENT. + setup step4.algorithm-roll.$tld + # The time passed since the DS has been swapped is 3 hours. + TpubN1="now-10h" + TsbmN1="now-3h" + ksk1times="-P ${TactN} -A ${TactN} -P sync ${TsbmN} -I ${TsbmN1}" + zsk1times="-P ${TactN} -A ${TactN} -I ${TsbmN1}" + ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}" + zsk2times="-P ${TpubN1} -A ${TpubN1}" + KSK1=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksk1times $zone 2>keygen.out.$zone.1) + ZSK1=$($KEYGEN -a RSASHA256 -L 3600 $zsk1times $zone 2>keygen.out.$zone.2) + KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksk2times $zone 2>keygen.out.$zone.3) + ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsk2times $zone 2>keygen.out.$zone.4) + $SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $U $TsbmN1 -D ds $TsbmN1 "$KSK1" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $H -k $O $TactN -z $O $TactN "$ZSK1" >settime.out.$zone.2 2>&1 + $SETTIME -s -g $O -k $O $TpubN1 -r $O $TpubN1 -d $R $TsbmN1 -P ds $TsbmN1 "$KSK2" >settime.out.$zone.3 2>&1 + $SETTIME -s -g $O -k $O $TpubN1 -z $R $TpubN1 "$ZSK2" >settime.out.$zone.4 2>&1 + # Fake lifetime of old algorithm keys. + echo "Lifetime: 0" >>"${KSK1}.state" + echo "Lifetime: 0" >>"${ZSK1}.state" + cat template.db.in "${KSK1}.key" "${ZSK1}.key" "${KSK2}.key" "${ZSK2}.key" >"$infile" + private_type_record $zone 8 "$KSK1" >>"$infile" + private_type_record $zone 8 "$ZSK1" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >>"$infile" + cp $infile $zonefile + $SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 5: -# The DNSKEY is removed long enough to be HIDDEN. -setup step5.algorithm-roll.kasp -# The time passed since the DNSKEY has been removed is 2 hours. -TpubN1="now-12h" -TsbmN1="now-5h" -ksk1times="-P ${TactN} -A ${TactN} -P sync ${TsbmN} -I ${TsbmN1}" -zsk1times="-P ${TactN} -A ${TactN} -I ${TsbmN1}" -ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}" -zsk2times="-P ${TpubN1} -A ${TpubN1}" -KSK1=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksk1times $zone 2>keygen.out.$zone.1) -ZSK1=$($KEYGEN -a RSASHA256 -L 3600 $zsk1times $zone 2>keygen.out.$zone.2) -KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksk2times $zone 2>keygen.out.$zone.3) -ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsk2times $zone 2>keygen.out.$zone.4) -$SETTIME -s -g $H -k $U $TsbmN1 -r $U $TsbmN1 -d $H $TsbmN1 "$KSK1" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $H -k $U $TsbmN1 -z $U $TsbmN1 "$ZSK1" >settime.out.$zone.2 2>&1 -$SETTIME -s -g $O -k $O $TpubN1 -r $O $TpubN1 -d $O $TsbmN1 "$KSK2" >settime.out.$zone.3 2>&1 -$SETTIME -s -g $O -k $O $TpubN1 -z $R $TpubN1 "$ZSK2" >settime.out.$zone.4 2>&1 -# Fake lifetime of old algorithm keys. -echo "Lifetime: 0" >>"${KSK1}.state" -echo "Lifetime: 0" >>"${ZSK1}.state" -cat template.db.in "${KSK1}.key" "${ZSK1}.key" "${KSK2}.key" "${ZSK2}.key" >"$infile" -private_type_record $zone 8 "$KSK1" >>"$infile" -private_type_record $zone 8 "$ZSK1" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >>"$infile" -cp $infile $zonefile -$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 5: + # The DNSKEY is removed long enough to be HIDDEN. + setup step5.algorithm-roll.$tld + # The time passed since the DNSKEY has been removed is 2 hours. + TpubN1="now-12h" + TsbmN1="now-5h" + ksk1times="-P ${TactN} -A ${TactN} -P sync ${TsbmN} -I ${TsbmN1}" + zsk1times="-P ${TactN} -A ${TactN} -I ${TsbmN1}" + ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}" + zsk2times="-P ${TpubN1} -A ${TpubN1}" + KSK1=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksk1times $zone 2>keygen.out.$zone.1) + ZSK1=$($KEYGEN -a RSASHA256 -L 3600 $zsk1times $zone 2>keygen.out.$zone.2) + KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksk2times $zone 2>keygen.out.$zone.3) + ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsk2times $zone 2>keygen.out.$zone.4) + $SETTIME -s -g $H -k $U $TsbmN1 -r $U $TsbmN1 -d $H $TsbmN1 "$KSK1" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $H -k $U $TsbmN1 -z $U $TsbmN1 "$ZSK1" >settime.out.$zone.2 2>&1 + $SETTIME -s -g $O -k $O $TpubN1 -r $O $TpubN1 -d $O $TsbmN1 "$KSK2" >settime.out.$zone.3 2>&1 + $SETTIME -s -g $O -k $O $TpubN1 -z $R $TpubN1 "$ZSK2" >settime.out.$zone.4 2>&1 + # Fake lifetime of old algorithm keys. + echo "Lifetime: 0" >>"${KSK1}.state" + echo "Lifetime: 0" >>"${ZSK1}.state" + cat template.db.in "${KSK1}.key" "${ZSK1}.key" "${KSK2}.key" "${ZSK2}.key" >"$infile" + private_type_record $zone 8 "$KSK1" >>"$infile" + private_type_record $zone 8 "$ZSK1" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >>"$infile" + cp $infile $zonefile + $SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 6: -# The RRSIGs have been removed long enough to be HIDDEN. -setup step6.algorithm-roll.kasp -# Additional time passed: 7h. -TpubN1="now-19h" -TsbmN1="now-12h" -ksk1times="-P ${TactN} -A ${TactN} -P sync ${TsbmN} -I ${TsbmN1}" -zsk1times="-P ${TactN} -A ${TactN} -I ${TsbmN1}" -ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}" -zsk2times="-P ${TpubN1} -A ${TpubN1}" -KSK1=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksk1times $zone 2>keygen.out.$zone.1) -ZSK1=$($KEYGEN -a RSASHA256 -L 3600 $zsk1times $zone 2>keygen.out.$zone.2) -KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksk2times $zone 2>keygen.out.$zone.3) -ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsk2times $zone 2>keygen.out.$zone.4) -$SETTIME -s -g $H -k $H $TsbmN1 -r $U $TsbmN1 -d $H $TsbmN1 "$KSK1" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $H -k $H $TsbmN1 -z $U $TsbmN1 "$ZSK1" >settime.out.$zone.2 2>&1 -$SETTIME -s -g $O -k $O $TpubN1 -r $O $TpubN1 -d $O $TsbmN1 "$KSK2" >settime.out.$zone.3 2>&1 -$SETTIME -s -g $O -k $O $TpubN1 -z $R $TpubN1 "$ZSK2" >settime.out.$zone.4 2>&1 -# Fake lifetime of old algorithm keys. -echo "Lifetime: 0" >>"${KSK1}.state" -echo "Lifetime: 0" >>"${ZSK1}.state" -cat template.db.in "${KSK1}.key" "${ZSK1}.key" "${KSK2}.key" "${ZSK2}.key" >"$infile" -private_type_record $zone 8 "$KSK1" >>"$infile" -private_type_record $zone 8 "$ZSK1" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >>"$infile" -cp $infile $zonefile -$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 6: + # The RRSIGs have been removed long enough to be HIDDEN. + setup step6.algorithm-roll.$tld + # Additional time passed: 7h. + TpubN1="now-19h" + TsbmN1="now-12h" + ksk1times="-P ${TactN} -A ${TactN} -P sync ${TsbmN} -I ${TsbmN1}" + zsk1times="-P ${TactN} -A ${TactN} -I ${TsbmN1}" + ksk2times="-P ${TpubN1} -A ${TpubN1} -P sync ${TsbmN1}" + zsk2times="-P ${TpubN1} -A ${TpubN1}" + KSK1=$($KEYGEN -a RSASHA256 -L 3600 -f KSK $ksk1times $zone 2>keygen.out.$zone.1) + ZSK1=$($KEYGEN -a RSASHA256 -L 3600 $zsk1times $zone 2>keygen.out.$zone.2) + KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $ksk2times $zone 2>keygen.out.$zone.3) + ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $zsk2times $zone 2>keygen.out.$zone.4) + $SETTIME -s -g $H -k $H $TsbmN1 -r $U $TsbmN1 -d $H $TsbmN1 "$KSK1" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $H -k $H $TsbmN1 -z $U $TsbmN1 "$ZSK1" >settime.out.$zone.2 2>&1 + $SETTIME -s -g $O -k $O $TpubN1 -r $O $TpubN1 -d $O $TsbmN1 "$KSK2" >settime.out.$zone.3 2>&1 + $SETTIME -s -g $O -k $O $TpubN1 -z $R $TpubN1 "$ZSK2" >settime.out.$zone.4 2>&1 + # Fake lifetime of old algorithm keys. + echo "Lifetime: 0" >>"${KSK1}.state" + echo "Lifetime: 0" >>"${ZSK1}.state" + cat template.db.in "${KSK1}.key" "${ZSK1}.key" "${KSK2}.key" "${ZSK2}.key" >"$infile" + private_type_record $zone 8 "$KSK1" >>"$infile" + private_type_record $zone 8 "$ZSK1" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >>"$infile" + cp $infile $zonefile + $SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 +done diff --git a/bin/tests/system/rollover-algo-ksk-zsk/tests_rollover_algo_ksk_zsk_initial.py b/bin/tests/system/rollover-algo-ksk-zsk/tests_rollover_algo_ksk_zsk_initial.py index d1e54a05a7..1617a40b5b 100644 --- a/bin/tests/system/rollover-algo-ksk-zsk/tests_rollover_algo_ksk_zsk_initial.py +++ b/bin/tests/system/rollover-algo-ksk-zsk/tests_rollover_algo_ksk_zsk_initial.py @@ -11,7 +11,10 @@ # pylint: disable=unused-import +import pytest + import isctest +from isctest.util import param from rollover.common import ( pytestmark, CDSS, @@ -21,10 +24,17 @@ from rollover.common import ( ) -def test_algoroll_ksk_zsk_initial(ns6): +@pytest.mark.parametrize( + "tld", + [ + param("kasp"), + param("manual"), + ], +) +def test_algoroll_ksk_zsk_initial(ns6, tld): config = ALGOROLL_CONFIG - policy = "rsasha256" - zone = "step1.algorithm-roll.kasp" + policy = f"rsasha256-{tld}" + zone = f"step1.algorithm-roll.{tld}" isctest.kasp.wait_keymgr_done(ns6, zone) diff --git a/bin/tests/system/rollover-csk-roll1/ns3/kasp.conf.j2 b/bin/tests/system/rollover-csk-roll1/ns3/kasp.conf.j2 index 30427737fc..e6defeded2 100644 --- a/bin/tests/system/rollover-csk-roll1/ns3/kasp.conf.j2 +++ b/bin/tests/system/rollover-csk-roll1/ns3/kasp.conf.j2 @@ -11,7 +11,31 @@ * information regarding copyright ownership. */ -dnssec-policy "csk-roll1" { +dnssec-policy "csk-roll1-autosign" { + signatures-refresh P5D; + signatures-validity 30d; + signatures-validity-dnskey 30d; + + dnskey-ttl 1h; + publish-safety PT1H; + retire-safety 2h; + purge-keys PT1H; + + cds-digest-types { "sha-384"; }; // use a different digest type for testing purposes + keys { + csk key-directory lifetime P6M algorithm @DEFAULT_ALGORITHM@; + }; + + zone-propagation-delay 1h; + max-zone-ttl P1D; + + parent-ds-ttl 1h; + parent-propagation-delay 1h; +}; + +dnssec-policy "csk-roll1-manual" { + manual-mode yes; + signatures-refresh P5D; signatures-validity 30d; signatures-validity-dnskey 30d; diff --git a/bin/tests/system/rollover-csk-roll1/ns3/named.conf.j2 b/bin/tests/system/rollover-csk-roll1/ns3/named.conf.j2 index 2c4764e280..93c9882531 100644 --- a/bin/tests/system/rollover-csk-roll1/ns3/named.conf.j2 +++ b/bin/tests/system/rollover-csk-roll1/ns3/named.conf.j2 @@ -11,46 +11,51 @@ * information regarding copyright ownership. */ +{% set zones = ["autosign", "manual"] %} + include "kasp.conf"; include "named.common.conf"; -zone "step1.csk-roll1.autosign" { +{% for tld in zones %} +zone "step1.csk-roll1.@tld@" { type primary; - file "step1.csk-roll1.autosign.db"; - dnssec-policy "csk-roll1"; + file "step1.csk-roll1.@tld@.db"; + dnssec-policy "csk-roll1-@tld@"; }; -zone "step2.csk-roll1.autosign" { +zone "step2.csk-roll1.@tld@" { type primary; - file "step2.csk-roll1.autosign.db"; - dnssec-policy "csk-roll1"; + file "step2.csk-roll1.@tld@.db"; + dnssec-policy "csk-roll1-@tld@"; }; -zone "step3.csk-roll1.autosign" { +zone "step3.csk-roll1.@tld@" { type primary; - file "step3.csk-roll1.autosign.db"; - dnssec-policy "csk-roll1"; + file "step3.csk-roll1.@tld@.db"; + dnssec-policy "csk-roll1-@tld@"; }; -zone "step4.csk-roll1.autosign" { +zone "step4.csk-roll1.@tld@" { type primary; - file "step4.csk-roll1.autosign.db"; - dnssec-policy "csk-roll1"; + file "step4.csk-roll1.@tld@.db"; + dnssec-policy "csk-roll1-@tld@"; }; -zone "step5.csk-roll1.autosign" { +zone "step5.csk-roll1.@tld@" { type primary; - file "step5.csk-roll1.autosign.db"; - dnssec-policy "csk-roll1"; + file "step5.csk-roll1.@tld@.db"; + dnssec-policy "csk-roll1-@tld@"; }; -zone "step6.csk-roll1.autosign" { +zone "step6.csk-roll1.@tld@" { type primary; - file "step6.csk-roll1.autosign.db"; - dnssec-policy "csk-roll1"; + file "step6.csk-roll1.@tld@.db"; + dnssec-policy "csk-roll1-@tld@"; }; -zone "step7.csk-roll1.autosign" { +zone "step7.csk-roll1.@tld@" { type primary; - file "step7.csk-roll1.autosign.db"; - dnssec-policy "csk-roll1"; + file "step7.csk-roll1.@tld@.db"; + dnssec-policy "csk-roll1-@tld@"; }; -zone "step8.csk-roll1.autosign" { +zone "step8.csk-roll1.@tld@" { type primary; - file "step8.csk-roll1.autosign.db"; - dnssec-policy "csk-roll1"; + file "step8.csk-roll1.@tld@.db"; + dnssec-policy "csk-roll1-@tld@"; }; + +{% endfor %} diff --git a/bin/tests/system/rollover-csk-roll1/setup.sh b/bin/tests/system/rollover-csk-roll1/setup.sh index 755876feda..088add4121 100644 --- a/bin/tests/system/rollover-csk-roll1/setup.sh +++ b/bin/tests/system/rollover-csk-roll1/setup.sh @@ -40,273 +40,275 @@ O="OMNIPRESENT" U="UNRETENTIVE" # -# The zones at csk-roll1.autosign represent the various steps of a CSK rollover +# The zones at csk-roll1.$tld represent the various steps of a CSK rollover # (which is essentially a ZSK Pre-Publication / KSK Double-KSK rollover). # -# Step 1: -# Introduce the first key. This will immediately be active. -setup step1.csk-roll1.autosign -TactN="now-7d" -keytimes="-P ${TactN} -A ${TactN}" -CSK=$($KEYGEN -k csk-roll1 -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) -$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN -z $O $TactN "$CSK" >settime.out.$zone.1 2>&1 -cat template.db.in "${CSK}.key" >"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >>"$infile" -cp $infile $zonefile -$SIGNER -S -z -x -G "cdnskey,cds:sha-384" -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 +for tld in autosign manual; do + # Step 1: + # Introduce the first key. This will immediately be active. + setup step1.csk-roll1.$tld + TactN="now-7d" + keytimes="-P ${TactN} -A ${TactN}" + CSK=$($KEYGEN -k csk-roll1-$tld -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) + $SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN -z $O $TactN "$CSK" >settime.out.$zone.1 2>&1 + cat template.db.in "${CSK}.key" >"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >>"$infile" + cp $infile $zonefile + $SIGNER -S -z -x -G "cdnskey,cds:sha-384" -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 2: -# It is time to introduce the new CSK. -setup step2.csk-roll1.autosign -# According to RFC 7583: -# KSK: Tpub(N+1) <= Tact(N) + Lksk - IpubC -# ZSK: Tpub(N+1) <= Tact(N) + Lzsk - Ipub -# IpubC = DprpC + TTLkey (+publish-safety) -# Ipub = IpubC -# Lcsk = Lksk = Lzsk -# -# Lcsk: 6mo (186d, 4464h) -# Dreg: N/A -# DprpC: 1h -# TTLkey: 1h -# publish-safety: 1h -# Ipub: 3h -# -# Tact(N) = now - Lcsk + Ipub = now - 186d + 3h -# = now - 4464h + 3h = now - 4461h -TactN="now-4461h" -keytimes="-P ${TactN} -A ${TactN}" -CSK=$($KEYGEN -k csk-roll1 -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) -$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN -z $O $TactN "$CSK" >settime.out.$zone.1 2>&1 -cat template.db.in "${CSK}.key" >"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >>"$infile" -cp $infile $zonefile -$SIGNER -S -z -x -G "cdnskey,cds:sha-384" -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 2: + # It is time to introduce the new CSK. + setup step2.csk-roll1.$tld + # According to RFC 7583: + # KSK: Tpub(N+1) <= Tact(N) + Lksk - IpubC + # ZSK: Tpub(N+1) <= Tact(N) + Lzsk - Ipub + # IpubC = DprpC + TTLkey (+publish-safety) + # Ipub = IpubC + # Lcsk = Lksk = Lzsk + # + # Lcsk: 6mo (186d, 4464h) + # Dreg: N/A + # DprpC: 1h + # TTLkey: 1h + # publish-safety: 1h + # Ipub: 3h + # + # Tact(N) = now - Lcsk + Ipub = now - 186d + 3h + # = now - 4464h + 3h = now - 4461h + TactN="now-4461h" + keytimes="-P ${TactN} -A ${TactN}" + CSK=$($KEYGEN -k csk-roll1-$tld -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) + $SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN -z $O $TactN "$CSK" >settime.out.$zone.1 2>&1 + cat template.db.in "${CSK}.key" >"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >>"$infile" + cp $infile $zonefile + $SIGNER -S -z -x -G "cdnskey,cds:sha-384" -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 3: -# It is time to submit the DS and to roll signatures. -setup step3.csk-roll1.autosign -# According to RFC 7583: -# -# Tsbm(N+1) >= Trdy(N+1) -# KSK: Tact(N+1) = Tsbm(N+1) -# ZSK: Tact(N+1) = Tpub(N+1) + Ipub = Tsbm(N+1) -# KSK: Iret = DprpP + TTLds (+retire-safety) -# ZSK: IretZ = Dsgn + Dprp + TTLsig (+retire-safety) -# -# Lcsk: 186d -# Dprp: 1h -# DprpP: 1h -# Dreg: N/A -# Dsgn: 25d -# TTLds: 1h -# TTLsig: 1d -# retire-safety: 2h -# Iret: 4h -# IretZ: 26d3h -# Ipub: 3h -# -# Tpub(N) = now - Lcsk = now - 186d -# Tact(N) = now - Lcsk + Dprp + TTLsig = now - 4439h -# Tret(N) = now -# Trem(N) = now + IretZ = now + 26d3h = now + 627h -# Tpub(N+1) = now - Ipub = now - 3h -# Tact(N+1) = Tret(N) -# Tret(N+1) = now + Lcsk = now + 186d = now + 186d -# Trem(N+1) = now + Lcsk + IretZ = now + 186d + 26d3h = -# = now + 5091h -TpubN="now-186d" -TactN="now-4439h" -TretN="now" -TremN="now+627h" -TpubN1="now-3h" -TactN1="${TretN}" -TretN1="now+186d" -TremN1="now+5091h" -keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}" -newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" -CSK1=$($KEYGEN -k csk-roll1 -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) -CSK2=$($KEYGEN -k csk-roll1 -l kasp.conf $newtimes $zone 2>keygen.out.$zone.2) -$SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $O $TactN -z $O $TactN "$CSK1" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $O -k $R $TpubN1 -r $R $TpubN1 -d $H $TpubN1 -z $H $TpubN1 "$CSK2" >settime.out.$zone.2 2>&1 -# Set key rollover relationship. -key_successor $CSK1 $CSK2 -# Sign zone. -cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile" -cp $infile $zonefile -$SIGNER -S -z -x -G "cdnskey,cds:sha-384" -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 3: + # It is time to submit the DS and to roll signatures. + setup step3.csk-roll1.$tld + # According to RFC 7583: + # + # Tsbm(N+1) >= Trdy(N+1) + # KSK: Tact(N+1) = Tsbm(N+1) + # ZSK: Tact(N+1) = Tpub(N+1) + Ipub = Tsbm(N+1) + # KSK: Iret = DprpP + TTLds (+retire-safety) + # ZSK: IretZ = Dsgn + Dprp + TTLsig (+retire-safety) + # + # Lcsk: 186d + # Dprp: 1h + # DprpP: 1h + # Dreg: N/A + # Dsgn: 25d + # TTLds: 1h + # TTLsig: 1d + # retire-safety: 2h + # Iret: 4h + # IretZ: 26d3h + # Ipub: 3h + # + # Tpub(N) = now - Lcsk = now - 186d + # Tact(N) = now - Lcsk + Dprp + TTLsig = now - 4439h + # Tret(N) = now + # Trem(N) = now + IretZ = now + 26d3h = now + 627h + # Tpub(N+1) = now - Ipub = now - 3h + # Tact(N+1) = Tret(N) + # Tret(N+1) = now + Lcsk = now + 186d = now + 186d + # Trem(N+1) = now + Lcsk + IretZ = now + 186d + 26d3h = + # = now + 5091h + TpubN="now-186d" + TactN="now-4439h" + TretN="now" + TremN="now+627h" + TpubN1="now-3h" + TactN1="${TretN}" + TretN1="now+186d" + TremN1="now+5091h" + keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}" + newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" + CSK1=$($KEYGEN -k csk-roll1-$tld -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) + CSK2=$($KEYGEN -k csk-roll1-$tld -l kasp.conf $newtimes $zone 2>keygen.out.$zone.2) + $SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $O $TactN -z $O $TactN "$CSK1" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $O -k $R $TpubN1 -r $R $TpubN1 -d $H $TpubN1 -z $H $TpubN1 "$CSK2" >settime.out.$zone.2 2>&1 + # Set key rollover relationship. + key_successor $CSK1 $CSK2 + # Sign zone. + cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile" + cp $infile $zonefile + $SIGNER -S -z -x -G "cdnskey,cds:sha-384" -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 4: -# Some time later all the ZRRSIG records should be from the new CSK, and the -# DS should be swapped. The ZRRSIG records are all replaced after IretZ -# (which is 26d3h). The DS is swapped after Iret (which is 4h). -# In other words, the DS is swapped before all zone signatures are replaced. -setup step4.csk-roll1.autosign -# According to RFC 7583: -# Trem(N) = Tret(N) - Iret + IretZ -# now = Tsbm(N+1) + Iret -# -# Lcsk: 186d -# Iret: 4h -# IretZ: 26d3h -# -# Tpub(N) = now - Iret - Lcsk = now - 4h - 186d = now - 4468h -# Tret(N) = now - Iret = now - 4h = now - 4h -# Trem(N) = now - Iret + IretZ = now - 4h + 26d3h -# = now + 623h -# Tpub(N+1) = now - Iret - IpubC = now - 4h - 3h = now - 7h -# Tact(N+1) = Tret(N) -# Tret(N+1) = now - Iret + Lcsk = now - 4h + 186d = now + 4460h -# Trem(N+1) = now - Iret + Lcsk + IretZ = now - 4h + 186d + 26d3h -# = now + 5087h -TpubN="now-4468h" -TactN="now-4443h" -TretN="now-4h" -TremN="now+623h" -TpubN1="now-7h" -TactN1="${TretN}" -TretN1="now+4460h" -TremN1="now+5087h" -keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}" -newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" -CSK1=$($KEYGEN -k csk-roll1 -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) -CSK2=$($KEYGEN -k csk-roll1 -l kasp.conf $newtimes $zone 2>keygen.out.$zone.2) -$SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $U $TactN1 -z $U $TactN1 -D ds $TactN1 "$CSK1" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -d $R $TactN1 -z $R $TactN1 -P ds $TactN1 "$CSK2" >settime.out.$zone.2 2>&1 -# Set key rollover relationship. -key_successor $CSK1 $CSK2 -# Sign zone. -cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile" -cp $infile $zonefile -$SIGNER -S -z -x -G "cdnskey,cds:sha-384" -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 4: + # Some time later all the ZRRSIG records should be from the new CSK, and the + # DS should be swapped. The ZRRSIG records are all replaced after IretZ + # (which is 26d3h). The DS is swapped after Iret (which is 4h). + # In other words, the DS is swapped before all zone signatures are replaced. + setup step4.csk-roll1.$tld + # According to RFC 7583: + # Trem(N) = Tret(N) - Iret + IretZ + # now = Tsbm(N+1) + Iret + # + # Lcsk: 186d + # Iret: 4h + # IretZ: 26d3h + # + # Tpub(N) = now - Iret - Lcsk = now - 4h - 186d = now - 4468h + # Tret(N) = now - Iret = now - 4h = now - 4h + # Trem(N) = now - Iret + IretZ = now - 4h + 26d3h + # = now + 623h + # Tpub(N+1) = now - Iret - IpubC = now - 4h - 3h = now - 7h + # Tact(N+1) = Tret(N) + # Tret(N+1) = now - Iret + Lcsk = now - 4h + 186d = now + 4460h + # Trem(N+1) = now - Iret + Lcsk + IretZ = now - 4h + 186d + 26d3h + # = now + 5087h + TpubN="now-4468h" + TactN="now-4443h" + TretN="now-4h" + TremN="now+623h" + TpubN1="now-7h" + TactN1="${TretN}" + TretN1="now+4460h" + TremN1="now+5087h" + keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}" + newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" + CSK1=$($KEYGEN -k csk-roll1-$tld -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) + CSK2=$($KEYGEN -k csk-roll1-$tld -l kasp.conf $newtimes $zone 2>keygen.out.$zone.2) + $SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $U $TactN1 -z $U $TactN1 -D ds $TactN1 "$CSK1" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -d $R $TactN1 -z $R $TactN1 -P ds $TactN1 "$CSK2" >settime.out.$zone.2 2>&1 + # Set key rollover relationship. + key_successor $CSK1 $CSK2 + # Sign zone. + cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile" + cp $infile $zonefile + $SIGNER -S -z -x -G "cdnskey,cds:sha-384" -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 5: -# After the DS is swapped in step 4, also the KRRSIG records can be removed. -# At this time these have all become hidden. -setup step5.csk-roll1.autosign -# Subtract DNSKEY TTL plus zone propagation delay from all the times (2h). -TpubN="now-4470h" -TactN="now-4445h" -TretN="now-6h" -TremN="now+621h" -TpubN1="now-9h" -TactN1="${TretN}" -TretN1="now+4458h" -TremN1="now+5085h" -keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}" -newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" -CSK1=$($KEYGEN -k csk-roll1 -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) -CSK2=$($KEYGEN -k csk-roll1 -l kasp.conf $newtimes $zone 2>keygen.out.$zone.2) -$SETTIME -s -g $H -k $O $TactN -r $U now-2h -d $H now-2h -z $U $TactN1 "$CSK1" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -d $O now-2h -z $R $TactN1 "$CSK2" >settime.out.$zone.2 2>&1 -# Set key rollover relationship. -key_successor $CSK1 $CSK2 -# Sign zone. -cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile" -cp $infile $zonefile -$SIGNER -S -z -x -G "cdnskey,cds:sha-384" -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 5: + # After the DS is swapped in step 4, also the KRRSIG records can be removed. + # At this time these have all become hidden. + setup step5.csk-roll1.$tld + # Subtract DNSKEY TTL plus zone propagation delay from all the times (2h). + TpubN="now-4470h" + TactN="now-4445h" + TretN="now-6h" + TremN="now+621h" + TpubN1="now-9h" + TactN1="${TretN}" + TretN1="now+4458h" + TremN1="now+5085h" + keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}" + newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" + CSK1=$($KEYGEN -k csk-roll1-$tld -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) + CSK2=$($KEYGEN -k csk-roll1-$tld -l kasp.conf $newtimes $zone 2>keygen.out.$zone.2) + $SETTIME -s -g $H -k $O $TactN -r $U now-2h -d $H now-2h -z $U $TactN1 "$CSK1" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -d $O now-2h -z $R $TactN1 "$CSK2" >settime.out.$zone.2 2>&1 + # Set key rollover relationship. + key_successor $CSK1 $CSK2 + # Sign zone. + cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile" + cp $infile $zonefile + $SIGNER -S -z -x -G "cdnskey,cds:sha-384" -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 6: -# After the retire interval has passed the predecessor DNSKEY can be -# removed from the zone. -setup step6.csk-roll1.autosign -# According to RFC 7583: -# Trem(N) = Tret(N) + IretZ -# Tret(N) = Tact(N) + Lcsk -# -# Lcsk: 186d -# Iret: 4h -# IretZ: 26d3h -# -# Tpub(N) = now - IretZ - Lcsk = now - 627h - 186d -# = now - 627h - 4464h = now - 5091h -# Tact(N) = now - 627h - 186d -# Tret(N) = now - IretZ = now - 627h -# Trem(N) = now -# Tpub(N+1) = now - IretZ - Ipub = now - 627h - 3h = now - 630h -# Tact(N+1) = Tret(N) -# Tret(N+1) = now - IretZ + Lcsk = now - 627h + 186d = now + 3837h -# Trem(N+1) = now + Lcsk = now + 186d -TpubN="now-5091h" -TactN="now-5066h" -TretN="now-627h" -TremN="now" -TpubN1="now-630h" -TactN1="${TretN}" -TretN1="now+3837h" -TremN1="now+186d" -keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}" -newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" -CSK1=$($KEYGEN -k csk-roll1 -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) -CSK2=$($KEYGEN -k csk-roll1 -l kasp.conf $newtimes $zone 2>keygen.out.$zone.2) -$SETTIME -s -g $H -k $O $TactN -r $H $TremN -d $H $TremN -z $U $TactN1 "$CSK1" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -d $O $TremN -z $R $TactN1 "$CSK2" >settime.out.$zone.2 2>&1 -# Set key rollover relationship. -key_successor $CSK1 $CSK2 -# Sign zone. -cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile" -cp $infile $zonefile -$SIGNER -S -z -x -G "cdnskey,cds:sha-384" -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 6: + # After the retire interval has passed the predecessor DNSKEY can be + # removed from the zone. + setup step6.csk-roll1.$tld + # According to RFC 7583: + # Trem(N) = Tret(N) + IretZ + # Tret(N) = Tact(N) + Lcsk + # + # Lcsk: 186d + # Iret: 4h + # IretZ: 26d3h + # + # Tpub(N) = now - IretZ - Lcsk = now - 627h - 186d + # = now - 627h - 4464h = now - 5091h + # Tact(N) = now - 627h - 186d + # Tret(N) = now - IretZ = now - 627h + # Trem(N) = now + # Tpub(N+1) = now - IretZ - Ipub = now - 627h - 3h = now - 630h + # Tact(N+1) = Tret(N) + # Tret(N+1) = now - IretZ + Lcsk = now - 627h + 186d = now + 3837h + # Trem(N+1) = now + Lcsk = now + 186d + TpubN="now-5091h" + TactN="now-5066h" + TretN="now-627h" + TremN="now" + TpubN1="now-630h" + TactN1="${TretN}" + TretN1="now+3837h" + TremN1="now+186d" + keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}" + newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" + CSK1=$($KEYGEN -k csk-roll1-$tld -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) + CSK2=$($KEYGEN -k csk-roll1-$tld -l kasp.conf $newtimes $zone 2>keygen.out.$zone.2) + $SETTIME -s -g $H -k $O $TactN -r $H $TremN -d $H $TremN -z $U $TactN1 "$CSK1" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -d $O $TremN -z $R $TactN1 "$CSK2" >settime.out.$zone.2 2>&1 + # Set key rollover relationship. + key_successor $CSK1 $CSK2 + # Sign zone. + cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile" + cp $infile $zonefile + $SIGNER -S -z -x -G "cdnskey,cds:sha-384" -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 7: -# Some time later the predecessor DNSKEY enters the HIDDEN state. -setup step7.csk-roll1.autosign -# Subtract DNSKEY TTL plus zone propagation delay from all the times (2h). -TpubN="now-5093h" -TactN="now-5068h" -TretN="now-629h" -TremN="now-2h" -TpubN1="now-632h" -TactN1="${TretN}" -TretN1="now+3835h" -TremN1="now+4462h" -keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}" -newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" -CSK1=$($KEYGEN -k csk-roll1 -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) -CSK2=$($KEYGEN -k csk-roll1 -l kasp.conf $newtimes $zone 2>keygen.out.$zone.2) -$SETTIME -s -g $H -k $U $TremN -r $H $TremN -d $H $TremN -z $H $TactN1 "$CSK1" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -d $O $TactN1 -z $O $TactN1 "$CSK2" >settime.out.$zone.2 2>&1 -# Set key rollover relationship. -key_successor $CSK1 $CSK2 -# Sign zone. -cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile" -cp $infile $zonefile -$SIGNER -S -z -x -G "cdnskey,cds:sha-384" -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 7: + # Some time later the predecessor DNSKEY enters the HIDDEN state. + setup step7.csk-roll1.$tld + # Subtract DNSKEY TTL plus zone propagation delay from all the times (2h). + TpubN="now-5093h" + TactN="now-5068h" + TretN="now-629h" + TremN="now-2h" + TpubN1="now-632h" + TactN1="${TretN}" + TretN1="now+3835h" + TremN1="now+4462h" + keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}" + newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" + CSK1=$($KEYGEN -k csk-roll1-$tld -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) + CSK2=$($KEYGEN -k csk-roll1-$tld -l kasp.conf $newtimes $zone 2>keygen.out.$zone.2) + $SETTIME -s -g $H -k $U $TremN -r $H $TremN -d $H $TremN -z $H $TactN1 "$CSK1" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -d $O $TactN1 -z $O $TactN1 "$CSK2" >settime.out.$zone.2 2>&1 + # Set key rollover relationship. + key_successor $CSK1 $CSK2 + # Sign zone. + cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile" + cp $infile $zonefile + $SIGNER -S -z -x -G "cdnskey,cds:sha-384" -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 8: -# The predecessor DNSKEY can be purged. -setup step8.csk-roll1.autosign -TpubN="now-5094h" -TactN="now-5069h" -TretN="now-630h" -TremN="now-3h" -TpubN1="now-633h" -TactN1="${TretN}" -TretN1="now+3834h" -TremN1="now+4461h" -# Subtract purge-keys interval from all the times (1h). -keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}" -newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" -CSK1=$($KEYGEN -k csk-roll1 -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) -CSK2=$($KEYGEN -k csk-roll1 -l kasp.conf $newtimes $zone 2>keygen.out.$zone.2) -$SETTIME -s -g $H -k $H $TremN -r $H $TremN -d $H $TremN -z $H $TactN1 "$CSK1" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -d $O $TactN1 -z $O $TactN1 "$CSK2" >settime.out.$zone.2 2>&1 -# Set key rollover relationship. -key_successor $CSK1 $CSK2 -# Sign zone. -cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile" -cp $infile $zonefile -$SIGNER -S -z -x -G "cdnskey,cds:sha-384" -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 8: + # The predecessor DNSKEY can be purged. + setup step8.csk-roll1.$tld + TpubN="now-5094h" + TactN="now-5069h" + TretN="now-630h" + TremN="now-3h" + TpubN1="now-633h" + TactN1="${TretN}" + TretN1="now+3834h" + TremN1="now+4461h" + # Subtract purge-keys interval from all the times (1h). + keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}" + newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" + CSK1=$($KEYGEN -k csk-roll1-$tld -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) + CSK2=$($KEYGEN -k csk-roll1-$tld -l kasp.conf $newtimes $zone 2>keygen.out.$zone.2) + $SETTIME -s -g $H -k $H $TremN -r $H $TremN -d $H $TremN -z $H $TactN1 "$CSK1" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -d $O $TactN1 -z $O $TactN1 "$CSK2" >settime.out.$zone.2 2>&1 + # Set key rollover relationship. + key_successor $CSK1 $CSK2 + # Sign zone. + cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile" + cp $infile $zonefile + $SIGNER -S -z -x -G "cdnskey,cds:sha-384" -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 +done diff --git a/bin/tests/system/rollover-csk-roll2/ns3/kasp.conf.j2 b/bin/tests/system/rollover-csk-roll2/ns3/kasp.conf.j2 index 5d70bcf42d..cf1708f3eb 100644 --- a/bin/tests/system/rollover-csk-roll2/ns3/kasp.conf.j2 +++ b/bin/tests/system/rollover-csk-roll2/ns3/kasp.conf.j2 @@ -11,7 +11,31 @@ * information regarding copyright ownership. */ -dnssec-policy "csk-roll2" { +dnssec-policy "csk-roll2-autosign" { + signatures-refresh 12h; + signatures-validity P1D; + signatures-validity-dnskey P1D; + + dnskey-ttl 1h; + publish-safety PT1H; + retire-safety 1h; + purge-keys 0; + + cds-digest-types { "sha-256"; "sha-384"; }; // use two digest type for testing purposes + keys { + csk key-directory lifetime P6M algorithm @DEFAULT_ALGORITHM@; + }; + + zone-propagation-delay PT1H; + max-zone-ttl 1d; + + parent-ds-ttl PT1H; + parent-propagation-delay P1W; +}; + +dnssec-policy "csk-roll2-manual" { + manual-mode yes; + signatures-refresh 12h; signatures-validity P1D; signatures-validity-dnskey P1D; diff --git a/bin/tests/system/rollover-csk-roll2/ns3/named.conf.j2 b/bin/tests/system/rollover-csk-roll2/ns3/named.conf.j2 index 76cbae53c8..94bba1a094 100644 --- a/bin/tests/system/rollover-csk-roll2/ns3/named.conf.j2 +++ b/bin/tests/system/rollover-csk-roll2/ns3/named.conf.j2 @@ -11,41 +11,46 @@ * information regarding copyright ownership. */ +{% set zones = ["autosign", "manual"] %} + include "kasp.conf"; include "named.common.conf"; -zone "step1.csk-roll2.autosign" { +{% for tld in zones %} +zone "step1.csk-roll2.@tld@" { type primary; - file "step1.csk-roll2.autosign.db"; - dnssec-policy "csk-roll2"; + file "step1.csk-roll2.@tld@.db"; + dnssec-policy "csk-roll2-@tld@"; }; -zone "step2.csk-roll2.autosign" { +zone "step2.csk-roll2.@tld@" { type primary; - file "step2.csk-roll2.autosign.db"; - dnssec-policy "csk-roll2"; + file "step2.csk-roll2.@tld@.db"; + dnssec-policy "csk-roll2-@tld@"; }; -zone "step3.csk-roll2.autosign" { +zone "step3.csk-roll2.@tld@" { type primary; - file "step3.csk-roll2.autosign.db"; - dnssec-policy "csk-roll2"; + file "step3.csk-roll2.@tld@.db"; + dnssec-policy "csk-roll2-@tld@"; }; -zone "step4.csk-roll2.autosign" { +zone "step4.csk-roll2.@tld@" { type primary; - file "step4.csk-roll2.autosign.db"; - dnssec-policy "csk-roll2"; + file "step4.csk-roll2.@tld@.db"; + dnssec-policy "csk-roll2-@tld@"; }; -zone "step5.csk-roll2.autosign" { +zone "step5.csk-roll2.@tld@" { type primary; - file "step5.csk-roll2.autosign.db"; - dnssec-policy "csk-roll2"; + file "step5.csk-roll2.@tld@.db"; + dnssec-policy "csk-roll2-@tld@"; }; -zone "step6.csk-roll2.autosign" { +zone "step6.csk-roll2.@tld@" { type primary; - file "step6.csk-roll2.autosign.db"; - dnssec-policy "csk-roll2"; + file "step6.csk-roll2.@tld@.db"; + dnssec-policy "csk-roll2-@tld@"; }; -zone "step7.csk-roll2.autosign" { +zone "step7.csk-roll2.@tld@" { type primary; - file "step7.csk-roll2.autosign.db"; - dnssec-policy "csk-roll2"; + file "step7.csk-roll2.@tld@.db"; + dnssec-policy "csk-roll2-@tld@"; }; + +{% endfor %} diff --git a/bin/tests/system/rollover-csk-roll2/setup.sh b/bin/tests/system/rollover-csk-roll2/setup.sh index 6121887de3..da1e2d8bfe 100644 --- a/bin/tests/system/rollover-csk-roll2/setup.sh +++ b/bin/tests/system/rollover-csk-roll2/setup.sh @@ -40,260 +40,262 @@ O="OMNIPRESENT" U="UNRETENTIVE" # -# The zones at csk-roll2.autosign represent the various steps of a CSK rollover +# The zones at csk-roll2.$tld represent the various steps of a CSK rollover # (which is essentially a ZSK Pre-Publication / KSK Double-KSK rollover). # This scenario differs from the csk-roll1 one because the zone signatures (ZRRSIG) # are replaced with the new key sooner than the DS is swapped. # -# Step 1: -# Introduce the first key. This will immediately be active. -setup step1.csk-roll2.autosign -TactN="now-7d" -keytimes="-P ${TactN} -A ${TactN}" -CSK=$($KEYGEN -k csk-roll2 -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) -$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN -z $O $TactN "$CSK" >settime.out.$zone.1 2>&1 -cat template.db.in "${CSK}.key" >"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >>"$infile" -cp $infile $zonefile -$SIGNER -S -z -x -G "cdnskey,cds:sha-256,cds:sha-384" -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 +for tld in autosign manual; do + # Step 1: + # Introduce the first key. This will immediately be active. + setup step1.csk-roll2.$tld + TactN="now-7d" + keytimes="-P ${TactN} -A ${TactN}" + CSK=$($KEYGEN -k csk-roll2-$tld -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) + $SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN -z $O $TactN "$CSK" >settime.out.$zone.1 2>&1 + cat template.db.in "${CSK}.key" >"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >>"$infile" + cp $infile $zonefile + $SIGNER -S -z -x -G "cdnskey,cds:sha-256,cds:sha-384" -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 2: -# It is time to introduce the new CSK. -setup step2.csk-roll2.autosign -# According to RFC 7583: -# KSK: Tpub(N+1) <= Tact(N) + Lksk - IpubC -# ZSK: Tpub(N+1) <= Tact(N) + Lzsk - Ipub -# IpubC = DprpC + TTLkey (+publish-safety) -# Ipub = IpubC -# Lcsk = Lksk = Lzsk -# -# Lcsk: 6mo (186d, 4464h) -# Dreg: N/A -# DprpC: 1h -# TTLkey: 1h -# publish-safety: 1h -# Ipub: 3h -# -# Tact(N) = now - Lcsk + Ipub = now - 186d + 3h -# = now - 4464h + 3h = now - 4461h -TactN="now-4461h" -keytimes="-P ${TactN} -A ${TactN}" -CSK=$($KEYGEN -k csk-roll2 -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) -$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN -z $O $TactN "$CSK" >settime.out.$zone.1 2>&1 -cat template.db.in "${CSK}.key" >"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >>"$infile" -cp $infile $zonefile -$SIGNER -S -z -x -G "cdnskey,cds:sha-256,cds:sha-384" -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 2: + # It is time to introduce the new CSK. + setup step2.csk-roll2.$tld + # According to RFC 7583: + # KSK: Tpub(N+1) <= Tact(N) + Lksk - IpubC + # ZSK: Tpub(N+1) <= Tact(N) + Lzsk - Ipub + # IpubC = DprpC + TTLkey (+publish-safety) + # Ipub = IpubC + # Lcsk = Lksk = Lzsk + # + # Lcsk: 6mo (186d, 4464h) + # Dreg: N/A + # DprpC: 1h + # TTLkey: 1h + # publish-safety: 1h + # Ipub: 3h + # + # Tact(N) = now - Lcsk + Ipub = now - 186d + 3h + # = now - 4464h + 3h = now - 4461h + TactN="now-4461h" + keytimes="-P ${TactN} -A ${TactN}" + CSK=$($KEYGEN -k csk-roll2-$tld -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) + $SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN -z $O $TactN "$CSK" >settime.out.$zone.1 2>&1 + cat template.db.in "${CSK}.key" >"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >>"$infile" + cp $infile $zonefile + $SIGNER -S -z -x -G "cdnskey,cds:sha-256,cds:sha-384" -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 3: -# It is time to submit the DS and to roll signatures. -setup step3.csk-roll2.autosign -# According to RFC 7583: -# -# Tsbm(N+1) >= Trdy(N+1) -# KSK: Tact(N+1) = Tsbm(N+1) -# ZSK: Tact(N+1) = Tpub(N+1) + Ipub = Tsbm(N+1) -# KSK: Iret = DprpP + TTLds (+retire-safety) -# ZSK: IretZ = Dsgn + Dprp + TTLsig (+retire-safety) -# -# Lcsk: 186d -# Dprp: 1h -# DprpP: 1w -# Dreg: N/A -# Dsgn: 12h -# TTLds: 1h -# TTLsig: 1d -# retire-safety: 1h -# Iret: 170h -# IretZ: 38h -# Ipub: 3h -# -# Tpub(N) = now - Lcsk = now - 186d -# Tact(N) = now - Lcsk + Dprp + TTLsig = now - 4439h -# Tret(N) = now -# Trem(N) = now + Iret = now + 170h -# Tpub(N+1) = now - Ipub = now - 3h -# Tact(N+1) = Tret(N) -# Tret(N+1) = now + Lcsk = now + 186d -# Trem(N+1) = now + Lcsk + Iret = now + 186d + 170h = -# = now + 4464h + 170h = now + 4634h -TpubN="now-186d" -TactN="now-4439h" -TretN="now" -TremN="now+170h" -TpubN1="now-3h" -TactN1="${TretN}" -TretN1="now+186d" -TremN1="now+4634h" -keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}" -newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" -CSK1=$($KEYGEN -k csk-roll2 -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) -CSK2=$($KEYGEN -k csk-roll2 -l kasp.conf $newtimes $zone 2>keygen.out.$zone.2) -$SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $O $TactN -z $O $TactN "$CSK1" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $O -k $R $TpubN1 -r $R $TpubN1 -d $H $TpubN1 -z $H $TpubN1 "$CSK2" >settime.out.$zone.2 2>&1 -# Set key rollover relationship. -key_successor $CSK1 $CSK2 -# Sign zone. -cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile" -cp $infile $zonefile -$SIGNER -S -z -x -G "cdnskey,cds:sha-256,cds:sha-384" -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 3: + # It is time to submit the DS and to roll signatures. + setup step3.csk-roll2.$tld + # According to RFC 7583: + # + # Tsbm(N+1) >= Trdy(N+1) + # KSK: Tact(N+1) = Tsbm(N+1) + # ZSK: Tact(N+1) = Tpub(N+1) + Ipub = Tsbm(N+1) + # KSK: Iret = DprpP + TTLds (+retire-safety) + # ZSK: IretZ = Dsgn + Dprp + TTLsig (+retire-safety) + # + # Lcsk: 186d + # Dprp: 1h + # DprpP: 1w + # Dreg: N/A + # Dsgn: 12h + # TTLds: 1h + # TTLsig: 1d + # retire-safety: 1h + # Iret: 170h + # IretZ: 38h + # Ipub: 3h + # + # Tpub(N) = now - Lcsk = now - 186d + # Tact(N) = now - Lcsk + Dprp + TTLsig = now - 4439h + # Tret(N) = now + # Trem(N) = now + Iret = now + 170h + # Tpub(N+1) = now - Ipub = now - 3h + # Tact(N+1) = Tret(N) + # Tret(N+1) = now + Lcsk = now + 186d + # Trem(N+1) = now + Lcsk + Iret = now + 186d + 170h = + # = now + 4464h + 170h = now + 4634h + TpubN="now-186d" + TactN="now-4439h" + TretN="now" + TremN="now+170h" + TpubN1="now-3h" + TactN1="${TretN}" + TretN1="now+186d" + TremN1="now+4634h" + keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}" + newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" + CSK1=$($KEYGEN -k csk-roll2-$tld -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) + CSK2=$($KEYGEN -k csk-roll2-$tld -l kasp.conf $newtimes $zone 2>keygen.out.$zone.2) + $SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $O $TactN -z $O $TactN "$CSK1" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $O -k $R $TpubN1 -r $R $TpubN1 -d $H $TpubN1 -z $H $TpubN1 "$CSK2" >settime.out.$zone.2 2>&1 + # Set key rollover relationship. + key_successor $CSK1 $CSK2 + # Sign zone. + cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile" + cp $infile $zonefile + $SIGNER -S -z -x -G "cdnskey,cds:sha-256,cds:sha-384" -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 4: -# Some time later all the ZRRSIG records should be from the new CSK, and the -# DS should be swapped. The ZRRSIG records are all replaced after IretZ (38h). -# The DS is swapped after Dreg + Iret (1w3h). In other words, the zone -# signatures are replaced before the DS is swapped. -setup step4.csk-roll2.autosign -# According to RFC 7583: -# Trem(N) = Tret(N) + IretZ -# -# Lcsk: 186d -# Dreg: N/A -# Iret: 170h -# IretZ: 38h -# -# Tpub(N) = now - IretZ - Lcsk = now - 38h - 186d -# = now - 38h - 4464h = now - 4502h -# Tact(N) = now - Iret - Lcsk + TTLsig = now - 4502h + 25h = now - 4477h -# Tret(N) = now - IretZ = now - 38h -# Trem(N) = now - IretZ + Iret = now - 38h + 170h = now + 132h -# Tpub(N+1) = now - IretZ - IpubC = now - 38h - 3h = now - 41h -# Tact(N+1) = Tret(N) -# Tret(N+1) = now - IretZ + Lcsk = now - 38h + 186d -# = now + 4426h -# Trem(N+1) = now - IretZ + Lcsk + Iret -# = now + 4426h + 3h = now + 4429h -TpubN="now-4502h" -TactN="now-4477h" -TretN="now-38h" -TremN="now+132h" -TpubN1="now-41h" -TactN1="${TretN}" -TretN1="now+4426h" -TremN1="now+4429h" -keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}" -newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" -CSK1=$($KEYGEN -k csk-roll2 -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) -CSK2=$($KEYGEN -k csk-roll2 -l kasp.conf $newtimes $zone 2>keygen.out.$zone.2) -$SETTIME -s -g $H -k $O $TactN -r $O $TactN -z $U $TretN -d $U $TactN1 -D ds $TactN1 "$CSK1" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -z $R $TactN1 -d $R $TactN1 -P ds $TactN1 "$CSK2" >settime.out.$zone.2 2>&1 -# Set key rollover relationship. -key_successor $CSK1 $CSK2 -# Sign zone. -cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile" -cp $infile $zonefile -$SIGNER -S -z -x -G "cdnskey,cds:sha-256,cds:sha-384" -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 4: + # Some time later all the ZRRSIG records should be from the new CSK, and the + # DS should be swapped. The ZRRSIG records are all replaced after IretZ (38h). + # The DS is swapped after Dreg + Iret (1w3h). In other words, the zone + # signatures are replaced before the DS is swapped. + setup step4.csk-roll2.$tld + # According to RFC 7583: + # Trem(N) = Tret(N) + IretZ + # + # Lcsk: 186d + # Dreg: N/A + # Iret: 170h + # IretZ: 38h + # + # Tpub(N) = now - IretZ - Lcsk = now - 38h - 186d + # = now - 38h - 4464h = now - 4502h + # Tact(N) = now - Iret - Lcsk + TTLsig = now - 4502h + 25h = now - 4477h + # Tret(N) = now - IretZ = now - 38h + # Trem(N) = now - IretZ + Iret = now - 38h + 170h = now + 132h + # Tpub(N+1) = now - IretZ - IpubC = now - 38h - 3h = now - 41h + # Tact(N+1) = Tret(N) + # Tret(N+1) = now - IretZ + Lcsk = now - 38h + 186d + # = now + 4426h + # Trem(N+1) = now - IretZ + Lcsk + Iret + # = now + 4426h + 3h = now + 4429h + TpubN="now-4502h" + TactN="now-4477h" + TretN="now-38h" + TremN="now+132h" + TpubN1="now-41h" + TactN1="${TretN}" + TretN1="now+4426h" + TremN1="now+4429h" + keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}" + newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" + CSK1=$($KEYGEN -k csk-roll2-$tld -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) + CSK2=$($KEYGEN -k csk-roll2-$tld -l kasp.conf $newtimes $zone 2>keygen.out.$zone.2) + $SETTIME -s -g $H -k $O $TactN -r $O $TactN -z $U $TretN -d $U $TactN1 -D ds $TactN1 "$CSK1" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -z $R $TactN1 -d $R $TactN1 -P ds $TactN1 "$CSK2" >settime.out.$zone.2 2>&1 + # Set key rollover relationship. + key_successor $CSK1 $CSK2 + # Sign zone. + cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile" + cp $infile $zonefile + $SIGNER -S -z -x -G "cdnskey,cds:sha-256,cds:sha-384" -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 5: -# Some time later the DS can be swapped and the old DNSKEY can be removed from -# the zone. -setup step5.csk-roll2.autosign -# Subtract Iret (170h) - IretZ (38h) = 132h. -# -# Tpub(N) = now - 4502h - 132h = now - 4634h -# Tact(N) = now - 4477h - 132h = now - 4609h -# Tret(N) = now - 38h - 132h = now - 170h -# Trem(N) = now + 132h - 132h = now -# Tpub(N+1) = now - 41h - 132h = now - 173h -# Tact(N+1) = Tret(N) -# Tret(N+1) = now + 4426h - 132h = now + 4294h -# Trem(N+1) = now + 4492h - 132h = now + 4360h -TpubN="now-4634h" -TactN="now-4609h" -TretN="now-170h" -TremN="now" -TpubN1="now-173h" -TactN1="${TretN}" -TretN1="now+4294h" -TremN1="now+4360h" -keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}" -newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" -CSK1=$($KEYGEN -k csk-roll2 -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) -CSK2=$($KEYGEN -k csk-roll2 -l kasp.conf $newtimes $zone 2>keygen.out.$zone.2) -$SETTIME -s -g $H -k $O $TactN -r $O $TactN -z $H now-133h -d $U $TactN1 -D ds $TactN1 "$CSK1" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -z $O now-133h -d $R $TactN1 -P ds $TactN1 "$CSK2" >settime.out.$zone.2 2>&1 -# Set key rollover relationship. -key_successor $CSK1 $CSK2 -# Sign zone. -cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile" -cp $infile $zonefile -$SIGNER -S -z -x -G "cdnskey,cds:sha-256,cds:sha-384" -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 5: + # Some time later the DS can be swapped and the old DNSKEY can be removed from + # the zone. + setup step5.csk-roll2.$tld + # Subtract Iret (170h) - IretZ (38h) = 132h. + # + # Tpub(N) = now - 4502h - 132h = now - 4634h + # Tact(N) = now - 4477h - 132h = now - 4609h + # Tret(N) = now - 38h - 132h = now - 170h + # Trem(N) = now + 132h - 132h = now + # Tpub(N+1) = now - 41h - 132h = now - 173h + # Tact(N+1) = Tret(N) + # Tret(N+1) = now + 4426h - 132h = now + 4294h + # Trem(N+1) = now + 4492h - 132h = now + 4360h + TpubN="now-4634h" + TactN="now-4609h" + TretN="now-170h" + TremN="now" + TpubN1="now-173h" + TactN1="${TretN}" + TretN1="now+4294h" + TremN1="now+4360h" + keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}" + newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" + CSK1=$($KEYGEN -k csk-roll2-$tld -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) + CSK2=$($KEYGEN -k csk-roll2-$tld -l kasp.conf $newtimes $zone 2>keygen.out.$zone.2) + $SETTIME -s -g $H -k $O $TactN -r $O $TactN -z $H now-133h -d $U $TactN1 -D ds $TactN1 "$CSK1" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -z $O now-133h -d $R $TactN1 -P ds $TactN1 "$CSK2" >settime.out.$zone.2 2>&1 + # Set key rollover relationship. + key_successor $CSK1 $CSK2 + # Sign zone. + cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile" + cp $infile $zonefile + $SIGNER -S -z -x -G "cdnskey,cds:sha-256,cds:sha-384" -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 6: -# Some time later the predecessor DNSKEY enters the HIDDEN state. -setup step6.csk-roll2.autosign -# Subtract DNSKEY TTL plus zone propagation delay (2h). -# -# Tpub(N) = now - 4634h - 2h = now - 4636h -# Tact(N) = now - 4609h - 2h = now - 4611h -# Tret(N) = now - 170h - 2h = now - 172h -# Trem(N) = now - 2h -# Tpub(N+1) = now - 173h - 2h = now - 175h -# Tact(N+1) = Tret(N) -# Tret(N+1) = now + 4294h - 2h = now + 4292h -# Trem(N+1) = now + 4360h - 2h = now + 4358h -TpubN="now-4636h" -TactN="now-4611h" -TretN="now-172h" -TremN="now-2h" -TpubN1="now-175h" -TactN1="${TretN}" -TretN1="now+4292h" -TremN1="now+4358h" -keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}" -newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" -CSK1=$($KEYGEN -k csk-roll2 -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) -CSK2=$($KEYGEN -k csk-roll2 -l kasp.conf $newtimes $zone 2>keygen.out.$zone.2) -$SETTIME -s -g $H -k $U $TremN -r $U $TremN -d $H $TremN -z $H now-135h "$CSK1" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -d $O $TremN -z $O now-135h "$CSK2" >settime.out.$zone.2 2>&1 -# Set key rollover relationship. -key_successor $CSK1 $CSK2 -# Sign zone. -cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile" -cp $infile $zonefile -$SIGNER -S -z -x -G "cdnskey,cds:sha-256,cds:sha-384" -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 6: + # Some time later the predecessor DNSKEY enters the HIDDEN state. + setup step6.csk-roll2.$tld + # Subtract DNSKEY TTL plus zone propagation delay (2h). + # + # Tpub(N) = now - 4634h - 2h = now - 4636h + # Tact(N) = now - 4609h - 2h = now - 4611h + # Tret(N) = now - 170h - 2h = now - 172h + # Trem(N) = now - 2h + # Tpub(N+1) = now - 173h - 2h = now - 175h + # Tact(N+1) = Tret(N) + # Tret(N+1) = now + 4294h - 2h = now + 4292h + # Trem(N+1) = now + 4360h - 2h = now + 4358h + TpubN="now-4636h" + TactN="now-4611h" + TretN="now-172h" + TremN="now-2h" + TpubN1="now-175h" + TactN1="${TretN}" + TretN1="now+4292h" + TremN1="now+4358h" + keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}" + newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" + CSK1=$($KEYGEN -k csk-roll2-$tld -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) + CSK2=$($KEYGEN -k csk-roll2-$tld -l kasp.conf $newtimes $zone 2>keygen.out.$zone.2) + $SETTIME -s -g $H -k $U $TremN -r $U $TremN -d $H $TremN -z $H now-135h "$CSK1" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -d $O $TremN -z $O now-135h "$CSK2" >settime.out.$zone.2 2>&1 + # Set key rollover relationship. + key_successor $CSK1 $CSK2 + # Sign zone. + cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile" + cp $infile $zonefile + $SIGNER -S -z -x -G "cdnskey,cds:sha-256,cds:sha-384" -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 7: -# The predecessor DNSKEY can be purged, but purge-keys is disabled. -setup step7.csk-roll2.autosign -# Subtract 90 days (default, 2160h) from all the times. -# -# Tpub(N) = now - 4636h - 2160h = now - 6796h -# Tact(N) = now - 4611h - 2160h = now - 6771h -# Tret(N) = now - 172h - 2160h = now - 2332h -# Trem(N) = now - 2h - 2160h = now - 2162h -# Tpub(N+1) = now - 175h - 2160h = now - 2335h -# Tact(N+1) = Tret(N) -# Tret(N+1) = now + 4292h - 2160h = now + 2132h -# Trem(N+1) = now + 4358h - 2160h = now + 2198h -TpubN="now-6796h" -TactN="now-6771h" -TretN="now-2332h" -TremN="now-2162h" -TpubN1="now-2335h" -TactN1="${TretN}" -TretN1="now+2132h" -TremN1="now+2198h" -keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}" -newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" -CSK1=$($KEYGEN -k csk-roll2 -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) -CSK2=$($KEYGEN -k csk-roll2 -l kasp.conf $newtimes $zone 2>keygen.out.$zone.2) -$SETTIME -s -g $H -k $U $TremN -r $U $TremN -d $H $TremN -z $H now-135h "$CSK1" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -d $O $TremN -z $O now-135h "$CSK2" >settime.out.$zone.2 2>&1 -# Set key rollover relationship. -key_successor $CSK1 $CSK2 -# Sign zone. -cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile" -cp $infile $zonefile -$SIGNER -S -z -x -G "cdnskey,cds:sha-256,cds:sha-384" -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 7: + # The predecessor DNSKEY can be purged, but purge-keys is disabled. + setup step7.csk-roll2.$tld + # Subtract 90 days (default, 2160h) from all the times. + # + # Tpub(N) = now - 4636h - 2160h = now - 6796h + # Tact(N) = now - 4611h - 2160h = now - 6771h + # Tret(N) = now - 172h - 2160h = now - 2332h + # Trem(N) = now - 2h - 2160h = now - 2162h + # Tpub(N+1) = now - 175h - 2160h = now - 2335h + # Tact(N+1) = Tret(N) + # Tret(N+1) = now + 4292h - 2160h = now + 2132h + # Trem(N+1) = now + 4358h - 2160h = now + 2198h + TpubN="now-6796h" + TactN="now-6771h" + TretN="now-2332h" + TremN="now-2162h" + TpubN1="now-2335h" + TactN1="${TretN}" + TretN1="now+2132h" + TremN1="now+2198h" + keytimes="-P ${TpubN} -P sync ${TactN} -A ${TpubN} -I ${TretN} -D ${TremN} -D sync ${TactN1}" + newtimes="-P ${TpubN1} -P sync ${TactN1} -A ${TactN1} -I ${TretN1} -D ${TremN1}" + CSK1=$($KEYGEN -k csk-roll2-$tld -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) + CSK2=$($KEYGEN -k csk-roll2-$tld -l kasp.conf $newtimes $zone 2>keygen.out.$zone.2) + $SETTIME -s -g $H -k $U $TremN -r $U $TremN -d $H $TremN -z $H now-135h "$CSK1" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -d $O $TremN -z $O now-135h "$CSK2" >settime.out.$zone.2 2>&1 + # Set key rollover relationship. + key_successor $CSK1 $CSK2 + # Sign zone. + cat template.db.in "${CSK1}.key" "${CSK2}.key" >"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK1" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK2" >>"$infile" + cp $infile $zonefile + $SIGNER -S -z -x -G "cdnskey,cds:sha-256,cds:sha-384" -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 +done diff --git a/bin/tests/system/rollover-enable-dnssec/ns3/kasp.conf.j2 b/bin/tests/system/rollover-enable-dnssec/ns3/kasp.conf.j2 index 5e3e0a3ac2..1f0c0773d2 100644 --- a/bin/tests/system/rollover-enable-dnssec/ns3/kasp.conf.j2 +++ b/bin/tests/system/rollover-enable-dnssec/ns3/kasp.conf.j2 @@ -11,7 +11,28 @@ * information regarding copyright ownership. */ -dnssec-policy "enable-dnssec" { +dnssec-policy "enable-dnssec-autosign" { + signatures-refresh P1W; + signatures-validity P2W; + signatures-validity-dnskey P2W; + + dnskey-ttl 300; + max-zone-ttl PT12H; + zone-propagation-delay PT5M; + retire-safety PT20M; + publish-safety PT5M; + + parent-propagation-delay 1h; + parent-ds-ttl 2h; + + keys { + csk lifetime unlimited algorithm @DEFAULT_ALGORITHM_NUMBER@; + }; +}; + +dnssec-policy "enable-dnssec-manual" { + manual-mode yes; + signatures-refresh P1W; signatures-validity P2W; signatures-validity-dnskey P2W; diff --git a/bin/tests/system/rollover-enable-dnssec/ns3/named.conf.j2 b/bin/tests/system/rollover-enable-dnssec/ns3/named.conf.j2 index 988790a20c..b07015d257 100644 --- a/bin/tests/system/rollover-enable-dnssec/ns3/named.conf.j2 +++ b/bin/tests/system/rollover-enable-dnssec/ns3/named.conf.j2 @@ -11,26 +11,31 @@ * information regarding copyright ownership. */ +{% set zones = ["autosign", "manual"] %} + include "kasp.conf"; include "named.common.conf"; -zone "step1.enable-dnssec.autosign" { +{% for tld in zones %} +zone "step1.enable-dnssec.@tld@" { type primary; - file "step1.enable-dnssec.autosign.db"; - dnssec-policy "enable-dnssec"; + file "step1.enable-dnssec.@tld@.db"; + dnssec-policy "enable-dnssec-@tld@"; }; -zone "step2.enable-dnssec.autosign" { +zone "step2.enable-dnssec.@tld@" { type primary; - file "step2.enable-dnssec.autosign.db"; - dnssec-policy "enable-dnssec"; + file "step2.enable-dnssec.@tld@.db"; + dnssec-policy "enable-dnssec-@tld@"; }; -zone "step3.enable-dnssec.autosign" { +zone "step3.enable-dnssec.@tld@" { type primary; - file "step3.enable-dnssec.autosign.db"; - dnssec-policy "enable-dnssec"; + file "step3.enable-dnssec.@tld@.db"; + dnssec-policy "enable-dnssec-@tld@"; }; -zone "step4.enable-dnssec.autosign" { +zone "step4.enable-dnssec.@tld@" { type primary; - file "step4.enable-dnssec.autosign.db"; - dnssec-policy "enable-dnssec"; + file "step4.enable-dnssec.@tld@.db"; + dnssec-policy "enable-dnssec-@tld@"; }; + +{% endfor %} diff --git a/bin/tests/system/rollover-enable-dnssec/setup.sh b/bin/tests/system/rollover-enable-dnssec/setup.sh index 0761de2dc4..17ee3a79f9 100644 --- a/bin/tests/system/rollover-enable-dnssec/setup.sh +++ b/bin/tests/system/rollover-enable-dnssec/setup.sh @@ -40,61 +40,63 @@ O="OMNIPRESENT" U="UNRETENTIVE" # -# The zones at enable-dnssec.autosign represent the various steps of the +# The zones at enable-dnssec.$tld represent the various steps of the # initial signing of a zone. # -# Step 1: -# This is an unsigned zone and named should perform the initial steps of -# introducing the DNSSEC records in the right order. -setup step1.enable-dnssec.autosign -cp template.db.in $zonefile +for tld in autosign manual; do + # Step 1: + # This is an unsigned zone and named should perform the initial steps of + # introducing the DNSSEC records in the right order. + setup step1.enable-dnssec.$tld + cp template.db.in $zonefile -# Step 2: -# The DNSKEY has been published long enough to become OMNIPRESENT. -setup step2.enable-dnssec.autosign -# DNSKEY TTL: 300 seconds -# zone-propagation-delay: 5 minutes (300 seconds) -# publish-safety: 5 minutes (300 seconds) -# Total: 900 seconds -TpubN="now-900s" -keytimes="-P ${TpubN} -A ${TpubN}" -CSK=$($KEYGEN -k enable-dnssec -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) -$SETTIME -s -g $O -k $R $TpubN -r $R $TpubN -d $H $TpubN -z $R $TpubN "$CSK" >settime.out.$zone.1 2>&1 -cat template.db.in "${CSK}.key" >"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >>"$infile" -cp $infile $zonefile -$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 2: + # The DNSKEY has been published long enough to become OMNIPRESENT. + setup step2.enable-dnssec.$tld + # DNSKEY TTL: 300 seconds + # zone-propagation-delay: 5 minutes (300 seconds) + # publish-safety: 5 minutes (300 seconds) + # Total: 900 seconds + TpubN="now-900s" + keytimes="-P ${TpubN} -A ${TpubN}" + CSK=$($KEYGEN -k enable-dnssec-$tld -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) + $SETTIME -s -g $O -k $R $TpubN -r $R $TpubN -d $H $TpubN -z $R $TpubN "$CSK" >settime.out.$zone.1 2>&1 + cat template.db.in "${CSK}.key" >"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >>"$infile" + cp $infile $zonefile + $SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 3: -# The zone signatures have been published long enough to become OMNIPRESENT. -setup step3.enable-dnssec.autosign -# Passed time since publication: -# max-zone-ttl: 12 hours (43200 seconds) -# zone-propagation-delay: 5 minutes (300 seconds) -TpubN="now-43500s" -# We can submit the DS now. -keytimes="-P ${TpubN} -A ${TpubN}" -CSK=$($KEYGEN -k enable-dnssec -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) -$SETTIME -s -g $O -k $O $TpubN -r $O $TpubN -d $H $TpubN -z $R $TpubN "$CSK" >settime.out.$zone.1 2>&1 -cat template.db.in "${CSK}.key" >"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >>"$infile" -cp $infile $zonefile -$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 3: + # The zone signatures have been published long enough to become OMNIPRESENT. + setup step3.enable-dnssec.$tld + # Passed time since publication: + # max-zone-ttl: 12 hours (43200 seconds) + # zone-propagation-delay: 5 minutes (300 seconds) + TpubN="now-43500s" + # We can submit the DS now. + keytimes="-P ${TpubN} -A ${TpubN}" + CSK=$($KEYGEN -k enable-dnssec-$tld -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) + $SETTIME -s -g $O -k $O $TpubN -r $O $TpubN -d $H $TpubN -z $R $TpubN "$CSK" >settime.out.$zone.1 2>&1 + cat template.db.in "${CSK}.key" >"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >>"$infile" + cp $infile $zonefile + $SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 4: -# The DS has been submitted long enough ago to become OMNIPRESENT. -setup step4.enable-dnssec.autosign -# DS TTL: 2 hour (7200 seconds) -# parent-propagation-delay: 1 hour (3600 seconds) -# Total aditional time: 10800 seconds -# 43500 + 10800 = 54300 -TpubN="now-54300s" -TsbmN="now-10800s" -keytimes="-P ${TpubN} -A ${TpubN} -P sync ${TsbmN}" -CSK=$($KEYGEN -k enable-dnssec -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) -$SETTIME -s -g $O -P ds $TsbmN -k $O $TpubN -r $O $TpubN -d $R $TpubN -z $O $TsbmN "$CSK" >settime.out.$zone.1 2>&1 -cat template.db.in "${CSK}.key" >"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >>"$infile" -cp $infile $zonefile -$SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 4: + # The DS has been submitted long enough ago to become OMNIPRESENT. + setup step4.enable-dnssec.$tld + # DS TTL: 2 hour (7200 seconds) + # parent-propagation-delay: 1 hour (3600 seconds) + # Total aditional time: 10800 seconds + # 43500 + 10800 = 54300 + TpubN="now-54300s" + TsbmN="now-10800s" + keytimes="-P ${TpubN} -A ${TpubN} -P sync ${TsbmN}" + CSK=$($KEYGEN -k enable-dnssec-$tld -l kasp.conf $keytimes $zone 2>keygen.out.$zone.1) + $SETTIME -s -g $O -P ds $TsbmN -k $O $TpubN -r $O $TpubN -d $R $TpubN -z $O $TsbmN "$CSK" >settime.out.$zone.1 2>&1 + cat template.db.in "${CSK}.key" >"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$CSK" >>"$infile" + cp $infile $zonefile + $SIGNER -S -z -x -s now-1h -e now+30d -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 +done diff --git a/bin/tests/system/rollover-ksk-3crowd/ns3/named.conf.j2 b/bin/tests/system/rollover-ksk-3crowd/ns3/named.conf.j2 index ae01f2eaeb..7775b8ebe3 100644 --- a/bin/tests/system/rollover-ksk-3crowd/ns3/named.conf.j2 +++ b/bin/tests/system/rollover-ksk-3crowd/ns3/named.conf.j2 @@ -19,5 +19,5 @@ zone "three-is-a-crowd.kasp" { file "three-is-a-crowd.kasp.db"; inline-signing yes; /* Use same policy as KSK rollover test zones. */ - dnssec-policy "ksk-doubleksk"; + dnssec-policy "ksk-doubleksk-autosign"; }; diff --git a/bin/tests/system/rollover-ksk-3crowd/tests_rollover_three_is_a_crowd.py b/bin/tests/system/rollover-ksk-3crowd/tests_rollover_three_is_a_crowd.py index 88ca2196a4..7fb3fce835 100644 --- a/bin/tests/system/rollover-ksk-3crowd/tests_rollover_three_is_a_crowd.py +++ b/bin/tests/system/rollover-ksk-3crowd/tests_rollover_three_is_a_crowd.py @@ -27,7 +27,7 @@ from rollover.common import ( CDSS = ["CDS (SHA-256)"] -POLICY = "ksk-doubleksk" +POLICY = "ksk-doubleksk-autosign" OFFSET1 = -int(timedelta(days=60).total_seconds()) OFFSET2 = -int(timedelta(hours=27).total_seconds()) TTL = int(KSK_CONFIG["dnskey-ttl"].total_seconds()) diff --git a/bin/tests/system/rollover-ksk-doubleksk/ns3/kasp.conf.j2 b/bin/tests/system/rollover-ksk-doubleksk/ns3/kasp.conf.j2 index d73934708a..c33a9f7c40 100644 --- a/bin/tests/system/rollover-ksk-doubleksk/ns3/kasp.conf.j2 +++ b/bin/tests/system/rollover-ksk-doubleksk/ns3/kasp.conf.j2 @@ -11,7 +11,32 @@ * information regarding copyright ownership. */ -dnssec-policy "ksk-doubleksk" { +dnssec-policy "ksk-doubleksk-autosign" { + signatures-refresh P1W; + signatures-validity P2W; + signatures-validity-dnskey P2W; + + dnskey-ttl 2h; + publish-safety P1D; + retire-safety P2D; + purge-keys PT1H; + + cdnskey no; + keys { + ksk key-directory lifetime P60D algorithm @DEFAULT_ALGORITHM@; + zsk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@; + }; + + zone-propagation-delay PT1H; + max-zone-ttl 1d; + + parent-ds-ttl 3600; + parent-propagation-delay PT1H; +}; + +dnssec-policy "ksk-doubleksk-manual" { + manual-mode yes; + signatures-refresh P1W; signatures-validity P2W; signatures-validity-dnskey P2W; diff --git a/bin/tests/system/rollover-ksk-doubleksk/ns3/named.conf.j2 b/bin/tests/system/rollover-ksk-doubleksk/ns3/named.conf.j2 index 63a0090fe1..7a51de9635 100644 --- a/bin/tests/system/rollover-ksk-doubleksk/ns3/named.conf.j2 +++ b/bin/tests/system/rollover-ksk-doubleksk/ns3/named.conf.j2 @@ -11,36 +11,40 @@ * information regarding copyright ownership. */ +{% set zones = ["autosign", "manual"] %} + include "kasp.conf"; include "named.common.conf"; -zone "step1.ksk-doubleksk.autosign" { +{% for tld in zones %} +zone "step1.ksk-doubleksk.@tld@" { type primary; - file "step1.ksk-doubleksk.autosign.db"; - dnssec-policy "ksk-doubleksk"; + file "step1.ksk-doubleksk.@tld@.db"; + dnssec-policy "ksk-doubleksk-@tld@"; }; -zone "step2.ksk-doubleksk.autosign" { +zone "step2.ksk-doubleksk.@tld@" { type primary; - file "step2.ksk-doubleksk.autosign.db"; - dnssec-policy "ksk-doubleksk"; + file "step2.ksk-doubleksk.@tld@.db"; + dnssec-policy "ksk-doubleksk-@tld@"; }; -zone "step3.ksk-doubleksk.autosign" { +zone "step3.ksk-doubleksk.@tld@" { type primary; - file "step3.ksk-doubleksk.autosign.db"; - dnssec-policy "ksk-doubleksk"; + file "step3.ksk-doubleksk.@tld@.db"; + dnssec-policy "ksk-doubleksk-@tld@"; }; -zone "step4.ksk-doubleksk.autosign" { +zone "step4.ksk-doubleksk.@tld@" { type primary; - file "step4.ksk-doubleksk.autosign.db"; - dnssec-policy "ksk-doubleksk"; + file "step4.ksk-doubleksk.@tld@.db"; + dnssec-policy "ksk-doubleksk-@tld@"; }; -zone "step5.ksk-doubleksk.autosign" { +zone "step5.ksk-doubleksk.@tld@" { type primary; - file "step5.ksk-doubleksk.autosign.db"; - dnssec-policy "ksk-doubleksk"; + file "step5.ksk-doubleksk.@tld@.db"; + dnssec-policy "ksk-doubleksk-@tld@"; }; -zone "step6.ksk-doubleksk.autosign" { +zone "step6.ksk-doubleksk.@tld@" { type primary; - file "step6.ksk-doubleksk.autosign.db"; - dnssec-policy "ksk-doubleksk"; + file "step6.ksk-doubleksk.@tld@.db"; + dnssec-policy "ksk-doubleksk-@tld@"; }; +{% endfor %} diff --git a/bin/tests/system/rollover-ksk-doubleksk/setup.sh b/bin/tests/system/rollover-ksk-doubleksk/setup.sh index c47c980600..cfd654bffd 100644 --- a/bin/tests/system/rollover-ksk-doubleksk/setup.sh +++ b/bin/tests/system/rollover-ksk-doubleksk/setup.sh @@ -40,202 +40,204 @@ O="OMNIPRESENT" U="UNRETENTIVE" # -# The zones at ksk-doubleksk.autosign represent the various steps of a KSK +# The zones at ksk-doubleksk.$tld represent the various steps of a KSK # Double-KSK rollover. # -# Step 1: -# Introduce the first key. This will immediately be active. -setup step1.ksk-doubleksk.autosign -TactN="now-7d" -keytimes="-P ${TactN} -A ${TactN}" -KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $keytimes $zone 2>keygen.out.$zone.1) -ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 $keytimes $zone 2>keygen.out.$zone.2) -$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" >settime.out.$zone.2 2>&1 -cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile" -cp $infile $zonefile -$SIGNER -S -x -G "cds:sha-256" -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 +for tld in autosign manual; do + # Step 1: + # Introduce the first key. This will immediately be active. + setup step1.ksk-doubleksk.$tld + TactN="now-7d" + keytimes="-P ${TactN} -A ${TactN}" + KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $keytimes $zone 2>keygen.out.$zone.1) + ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 $keytimes $zone 2>keygen.out.$zone.2) + $SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" >settime.out.$zone.2 2>&1 + cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile" + cp $infile $zonefile + $SIGNER -S -x -G "cds:sha-256" -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 2: -# It is time to submit the introduce the new KSK. -setup step2.ksk-doubleksk.autosign -# Lksk: 60d -# Dreg: n/a -# DprpC: 1h -# TTLds: 1d -# TTLkey: 2h -# publish-safety: 1d -# retire-safety: 2d -# -# According to RFC 7583: -# Tpub(N+1) <= Tact(N) + Lksk - Dreg - IpubC -# IpubC = DprpC + TTLkey (+publish-safety) -# -# IpubC = 27h -# Tact(N) = now - Lksk + Dreg + IpubC = now - 60d + 27h -# = now - 1440h + 27h = now - 1413h -TactN="now-1413h" -keytimes="-P ${TactN} -A ${TactN}" -KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $keytimes $zone 2>keygen.out.$zone.1) -ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 $keytimes $zone 2>keygen.out.$zone.2) -$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" >settime.out.$zone.2 2>&1 -cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >>"$infile" -cp $infile $zonefile -$SIGNER -S -x -G "cds:sha-256" -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 2: + # It is time to submit the introduce the new KSK. + setup step2.ksk-doubleksk.$tld + # Lksk: 60d + # Dreg: n/a + # DprpC: 1h + # TTLds: 1d + # TTLkey: 2h + # publish-safety: 1d + # retire-safety: 2d + # + # According to RFC 7583: + # Tpub(N+1) <= Tact(N) + Lksk - Dreg - IpubC + # IpubC = DprpC + TTLkey (+publish-safety) + # + # IpubC = 27h + # Tact(N) = now - Lksk + Dreg + IpubC = now - 60d + 27h + # = now - 1440h + 27h = now - 1413h + TactN="now-1413h" + keytimes="-P ${TactN} -A ${TactN}" + KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $keytimes $zone 2>keygen.out.$zone.1) + ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 $keytimes $zone 2>keygen.out.$zone.2) + $SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" >settime.out.$zone.2 2>&1 + cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >>"$infile" + cp $infile $zonefile + $SIGNER -S -x -G "cds:sha-256" -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 3: -# It is time to submit the DS. -setup step3.ksk-doubleksk.autosign -# According to RFC 7583: -# Iret = DprpP + TTLds (+retire-safety) -# -# Iret = 50h -# Tpub(N) = now - Lksk = now - 60d = now - 60d -# Tact(N) = now - 1413h -# Tret(N) = now -# Trem(N) = now + Iret = now + 50h -# Tpub(N+1) = now - IpubC = now - 27h -# Tact(N+1) = now -# Tret(N+1) = now + Lksk = now + 60d -# Trem(N+1) = now + Lksk + Iret = now + 60d + 50h -# = now + 1440h + 50h = 1490h -TpubN="now-60d" -TactN="now-1413h" -TretN="now" -TremN="now+50h" -TpubN1="now-27h" -TactN1="now" -TretN1="now+60d" -TremN1="now+1490h" -ksktimes="-P ${TpubN} -A ${TpubN} -P sync ${TactN} -I ${TretN} -D ${TremN} -D sync ${TactN1}" -newtimes="-P ${TpubN1} -A ${TactN1} -P sync ${TactN1} -I ${TretN1} -D ${TremN1}" -zsktimes="-P ${TpubN} -A ${TpubN}" -KSK1=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $ksktimes $zone 2>keygen.out.$zone.1) -KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $newtimes $zone 2>keygen.out.$zone.2) -ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 $zsktimes $zone 2>keygen.out.$zone.3) -$SETTIME -s -g $H -k $O $TpubN -r $O $TpubN -d $O $TactN "$KSK1" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $O -k $R $TpubN1 -r $R $TpubN1 -d $H $TpubN1 "$KSK2" >settime.out.$zone.2 2>&1 -$SETTIME -s -g $O -k $O $TpubN -z $O $TpubN "$ZSK" >settime.out.$zone.3 2>&1 -# Set key rollover relationship. -key_successor $KSK1 $KSK2 -# Sign zone. -cat template.db.in "${KSK1}.key" "${KSK2}.key" "${ZSK}.key" >"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK1" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >>"$infile" -cp $infile $zonefile -$SIGNER -S -x -G "cds:sha-256" -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 3: + # It is time to submit the DS. + setup step3.ksk-doubleksk.$tld + # According to RFC 7583: + # Iret = DprpP + TTLds (+retire-safety) + # + # Iret = 50h + # Tpub(N) = now - Lksk = now - 60d = now - 60d + # Tact(N) = now - 1413h + # Tret(N) = now + # Trem(N) = now + Iret = now + 50h + # Tpub(N+1) = now - IpubC = now - 27h + # Tact(N+1) = now + # Tret(N+1) = now + Lksk = now + 60d + # Trem(N+1) = now + Lksk + Iret = now + 60d + 50h + # = now + 1440h + 50h = 1490h + TpubN="now-60d" + TactN="now-1413h" + TretN="now" + TremN="now+50h" + TpubN1="now-27h" + TactN1="now" + TretN1="now+60d" + TremN1="now+1490h" + ksktimes="-P ${TpubN} -A ${TpubN} -P sync ${TactN} -I ${TretN} -D ${TremN} -D sync ${TactN1}" + newtimes="-P ${TpubN1} -A ${TactN1} -P sync ${TactN1} -I ${TretN1} -D ${TremN1}" + zsktimes="-P ${TpubN} -A ${TpubN}" + KSK1=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $ksktimes $zone 2>keygen.out.$zone.1) + KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $newtimes $zone 2>keygen.out.$zone.2) + ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 $zsktimes $zone 2>keygen.out.$zone.3) + $SETTIME -s -g $H -k $O $TpubN -r $O $TpubN -d $O $TactN "$KSK1" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $O -k $R $TpubN1 -r $R $TpubN1 -d $H $TpubN1 "$KSK2" >settime.out.$zone.2 2>&1 + $SETTIME -s -g $O -k $O $TpubN -z $O $TpubN "$ZSK" >settime.out.$zone.3 2>&1 + # Set key rollover relationship. + key_successor $KSK1 $KSK2 + # Sign zone. + cat template.db.in "${KSK1}.key" "${KSK2}.key" "${ZSK}.key" >"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK1" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >>"$infile" + cp $infile $zonefile + $SIGNER -S -x -G "cds:sha-256" -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 4: -# The DS should be swapped now. -setup step4.ksk-doubleksk.autosign -# Tpub(N) = now - Lksk - Iret = now - 60d - 50h -# = now - 1440h - 50h = now - 1490h -# Tact(N) = now - 1490h + 27h = now - 1463h -# Tret(N) = now - Iret = now - 50h -# Trem(N) = now -# Tpub(N+1) = now - Iret - IpubC = now - 50h - 27h -# = now - 77h -# Tact(N+1) = Tret(N) -# Tret(N+1) = now + Lksk - Iret = now + 60d - 50h = now + 1390h -# Trem(N+1) = now + Lksk = now + 60d -TpubN="now-1490h" -TactN="now-1463h" -TretN="now-50h" -TremN="now" -TpubN1="now-77h" -TactN1="${TretN}" -TretN1="now+1390h" -TremN1="now+60d" -ksktimes="-P ${TpubN} -A ${TpubN} -P sync ${TactN} -I ${TretN} -D ${TremN} -D sync ${TactN1}" -newtimes="-P ${TpubN1} -A ${TactN1} -P sync ${TactN1} -I ${TretN1} -D ${TremN1}" -zsktimes="-P ${TpubN} -A ${TpubN}" -KSK1=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $ksktimes $zone 2>keygen.out.$zone.1) -KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $newtimes $zone 2>keygen.out.$zone.2) -ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 $zsktimes $zone 2>keygen.out.$zone.3) -$SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $U $TretN -D ds $TretN "$KSK1" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -d $R $TactN1 -P ds $TactN1 "$KSK2" >settime.out.$zone.2 2>&1 -$SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" >settime.out.$zone.3 2>&1 -# Set key rollover relationship. -key_successor $KSK1 $KSK2 -# Sign zone. -cat template.db.in "${KSK1}.key" "${KSK2}.key" "${ZSK}.key" >"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK1" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >>"$infile" -cp $infile $zonefile -$SIGNER -S -x -G "cds:sha-256" -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 4: + # The DS should be swapped now. + setup step4.ksk-doubleksk.$tld + # Tpub(N) = now - Lksk - Iret = now - 60d - 50h + # = now - 1440h - 50h = now - 1490h + # Tact(N) = now - 1490h + 27h = now - 1463h + # Tret(N) = now - Iret = now - 50h + # Trem(N) = now + # Tpub(N+1) = now - Iret - IpubC = now - 50h - 27h + # = now - 77h + # Tact(N+1) = Tret(N) + # Tret(N+1) = now + Lksk - Iret = now + 60d - 50h = now + 1390h + # Trem(N+1) = now + Lksk = now + 60d + TpubN="now-1490h" + TactN="now-1463h" + TretN="now-50h" + TremN="now" + TpubN1="now-77h" + TactN1="${TretN}" + TretN1="now+1390h" + TremN1="now+60d" + ksktimes="-P ${TpubN} -A ${TpubN} -P sync ${TactN} -I ${TretN} -D ${TremN} -D sync ${TactN1}" + newtimes="-P ${TpubN1} -A ${TactN1} -P sync ${TactN1} -I ${TretN1} -D ${TremN1}" + zsktimes="-P ${TpubN} -A ${TpubN}" + KSK1=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $ksktimes $zone 2>keygen.out.$zone.1) + KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $newtimes $zone 2>keygen.out.$zone.2) + ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 $zsktimes $zone 2>keygen.out.$zone.3) + $SETTIME -s -g $H -k $O $TactN -r $O $TactN -d $U $TretN -D ds $TretN "$KSK1" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -d $R $TactN1 -P ds $TactN1 "$KSK2" >settime.out.$zone.2 2>&1 + $SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" >settime.out.$zone.3 2>&1 + # Set key rollover relationship. + key_successor $KSK1 $KSK2 + # Sign zone. + cat template.db.in "${KSK1}.key" "${KSK2}.key" "${ZSK}.key" >"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK1" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >>"$infile" + cp $infile $zonefile + $SIGNER -S -x -G "cds:sha-256" -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 5: -# The predecessor DNSKEY is removed long enough that is has become HIDDEN. -setup step5.ksk-doubleksk.autosign -# Subtract DNSKEY TTL + zone-propagation-delay from all the times (3h). -# Tpub(N) = now - 1490h - 3h = now - 1493h -# Tact(N) = now - 1463h - 3h = now - 1466h -# Tret(N) = now - 50h - 3h = now - 53h -# Trem(N) = now - 3h -# Tpub(N+1) = now - 77h - 3h = now - 80h -# Tact(N+1) = Tret(N) -# Tret(N+1) = now + 1390h - 3h = now + 1387h -# Trem(N+1) = now + 60d - 3h = now + 1441h -TpubN="now-1493h" -TactN="now-1466h" -TretN="now-53h" -TremN="now-3h" -TpubN1="now-80h" -TactN1="${TretN}" -TretN1="now+1387h" -TremN1="now+1441h" -ksktimes="-P ${TpubN} -A ${TpubN} -P sync ${TactN} -I ${TretN} -D ${TremN} -D sync ${TactN1}" -newtimes="-P ${TpubN1} -A ${TactN1} -P sync ${TactN1} -I ${TretN1} -D ${TremN1}" -zsktimes="-P ${TpubN} -A ${TpubN}" -KSK1=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $ksktimes $zone 2>keygen.out.$zone.1) -KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $newtimes $zone 2>keygen.out.$zone.2) -ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 $zsktimes $zone 2>keygen.out.$zone.3) -$SETTIME -s -g $H -k $U $TretN -r $U $TretN -d $H $TretN "$KSK1" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -d $O $TactN1 "$KSK2" >settime.out.$zone.2 2>&1 -$SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" >settime.out.$zone.3 2>&1 -# Set key rollover relationship. -key_successor $KSK1 $KSK2 -# Sign zone. -cat template.db.in "${KSK1}.key" "${KSK2}.key" "${ZSK}.key" >"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK1" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >>"$infile" -cp $infile $zonefile -$SIGNER -S -x -G "cds:sha-256" -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 5: + # The predecessor DNSKEY is removed long enough that is has become HIDDEN. + setup step5.ksk-doubleksk.$tld + # Subtract DNSKEY TTL + zone-propagation-delay from all the times (3h). + # Tpub(N) = now - 1490h - 3h = now - 1493h + # Tact(N) = now - 1463h - 3h = now - 1466h + # Tret(N) = now - 50h - 3h = now - 53h + # Trem(N) = now - 3h + # Tpub(N+1) = now - 77h - 3h = now - 80h + # Tact(N+1) = Tret(N) + # Tret(N+1) = now + 1390h - 3h = now + 1387h + # Trem(N+1) = now + 60d - 3h = now + 1441h + TpubN="now-1493h" + TactN="now-1466h" + TretN="now-53h" + TremN="now-3h" + TpubN1="now-80h" + TactN1="${TretN}" + TretN1="now+1387h" + TremN1="now+1441h" + ksktimes="-P ${TpubN} -A ${TpubN} -P sync ${TactN} -I ${TretN} -D ${TremN} -D sync ${TactN1}" + newtimes="-P ${TpubN1} -A ${TactN1} -P sync ${TactN1} -I ${TretN1} -D ${TremN1}" + zsktimes="-P ${TpubN} -A ${TpubN}" + KSK1=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $ksktimes $zone 2>keygen.out.$zone.1) + KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $newtimes $zone 2>keygen.out.$zone.2) + ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 $zsktimes $zone 2>keygen.out.$zone.3) + $SETTIME -s -g $H -k $U $TretN -r $U $TretN -d $H $TretN "$KSK1" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -d $O $TactN1 "$KSK2" >settime.out.$zone.2 2>&1 + $SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" >settime.out.$zone.3 2>&1 + # Set key rollover relationship. + key_successor $KSK1 $KSK2 + # Sign zone. + cat template.db.in "${KSK1}.key" "${KSK2}.key" "${ZSK}.key" >"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK1" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >>"$infile" + cp $infile $zonefile + $SIGNER -S -x -G "cds:sha-256" -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 6: -# The predecessor DNSKEY can be purged. -setup step6.ksk-doubleksk.autosign -# Subtract purge-keys interval from all the times (1h). -TpubN="now-1494h" -TactN="now-1467h" -TretN="now-54h" -TremN="now-4h" -TpubN1="now-81h" -TactN1="${TretN}" -TretN1="now+1386h" -TremN1="now+1440h" -ksktimes="-P ${TpubN} -A ${TpubN} -P sync ${TactN} -I ${TretN} -D ${TremN} -D sync ${TactN1}" -newtimes="-P ${TpubN1} -A ${TactN1} -P sync ${TactN1} -I ${TretN1} -D ${TremN1}" -zsktimes="-P ${TpubN} -A ${TpubN}" -KSK1=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $ksktimes $zone 2>keygen.out.$zone.1) -KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $newtimes $zone 2>keygen.out.$zone.2) -ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 $zsktimes $zone 2>keygen.out.$zone.3) -$SETTIME -s -g $H -k $H $TretN -r $H $TretN -d $H $TretN "$KSK1" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -d $O $TactN1 "$KSK2" >settime.out.$zone.2 2>&1 -$SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" >settime.out.$zone.3 2>&1 -# Set key rollover relationship. -key_successor $KSK1 $KSK2 -# Sign zone. -cat template.db.in "${KSK1}.key" "${KSK2}.key" "${ZSK}.key" >"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK1" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >>"$infile" -cp $infile $zonefile -$SIGNER -S -x -G "cds:sha-256" -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 6: + # The predecessor DNSKEY can be purged. + setup step6.ksk-doubleksk.$tld + # Subtract purge-keys interval from all the times (1h). + TpubN="now-1494h" + TactN="now-1467h" + TretN="now-54h" + TremN="now-4h" + TpubN1="now-81h" + TactN1="${TretN}" + TretN1="now+1386h" + TremN1="now+1440h" + ksktimes="-P ${TpubN} -A ${TpubN} -P sync ${TactN} -I ${TretN} -D ${TremN} -D sync ${TactN1}" + newtimes="-P ${TpubN1} -A ${TactN1} -P sync ${TactN1} -I ${TretN1} -D ${TremN1}" + zsktimes="-P ${TpubN} -A ${TpubN}" + KSK1=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $ksktimes $zone 2>keygen.out.$zone.1) + KSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 -f KSK $newtimes $zone 2>keygen.out.$zone.2) + ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 7200 $zsktimes $zone 2>keygen.out.$zone.3) + $SETTIME -s -g $H -k $H $TretN -r $H $TretN -d $H $TretN "$KSK1" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $O -k $O $TactN1 -r $O $TactN1 -d $O $TactN1 "$KSK2" >settime.out.$zone.2 2>&1 + $SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" >settime.out.$zone.3 2>&1 + # Set key rollover relationship. + key_successor $KSK1 $KSK2 + # Sign zone. + cat template.db.in "${KSK1}.key" "${KSK2}.key" "${ZSK}.key" >"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK1" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK2" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >>"$infile" + cp $infile $zonefile + $SIGNER -S -x -G "cds:sha-256" -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 +done diff --git a/bin/tests/system/rollover-ksk-doubleksk/tests_rollover_ksk_doubleksk.py b/bin/tests/system/rollover-ksk-doubleksk/tests_rollover_ksk_doubleksk.py index 6a12328892..60e88ba735 100644 --- a/bin/tests/system/rollover-ksk-doubleksk/tests_rollover_ksk_doubleksk.py +++ b/bin/tests/system/rollover-ksk-doubleksk/tests_rollover_ksk_doubleksk.py @@ -30,7 +30,7 @@ from rollover.common import ( CDSS = ["CDS (SHA-256)"] -POLICY = "ksk-doubleksk" +POLICY = "ksk-doubleksk-autosign" OFFSETS = {} OFFSETS["step1-p"] = -int(TIMEDELTA["P7D"].total_seconds()) OFFSETS["step2-p"] = -int(KSK_LIFETIME.total_seconds() - KSK_IPUBC.total_seconds()) diff --git a/bin/tests/system/rollover-zsk-prepub/ns3/kasp.conf.j2 b/bin/tests/system/rollover-zsk-prepub/ns3/kasp.conf.j2 index 7b92bc1632..eac3293a6e 100644 --- a/bin/tests/system/rollover-zsk-prepub/ns3/kasp.conf.j2 +++ b/bin/tests/system/rollover-zsk-prepub/ns3/kasp.conf.j2 @@ -11,7 +11,28 @@ * information regarding copyright ownership. */ -dnssec-policy "zsk-prepub" { +dnssec-policy "zsk-prepub-autosign" { + signatures-refresh P1W; + signatures-validity P2W; + signatures-validity-dnskey P2W; + + dnskey-ttl 3600; + publish-safety P1D; + retire-safety P2D; + purge-keys PT1H; + + keys { + ksk key-directory lifetime unlimited algorithm @DEFAULT_ALGORITHM@; + zsk key-directory lifetime P30D algorithm @DEFAULT_ALGORITHM@; + }; + + zone-propagation-delay PT1H; + max-zone-ttl 1d; +}; + +dnssec-policy "zsk-prepub-manual" { + manual-mode yes; + signatures-refresh P1W; signatures-validity P2W; signatures-validity-dnskey P2W; diff --git a/bin/tests/system/rollover-zsk-prepub/ns3/named.conf.j2 b/bin/tests/system/rollover-zsk-prepub/ns3/named.conf.j2 index 2e7137762b..462122eb76 100644 --- a/bin/tests/system/rollover-zsk-prepub/ns3/named.conf.j2 +++ b/bin/tests/system/rollover-zsk-prepub/ns3/named.conf.j2 @@ -11,36 +11,40 @@ * information regarding copyright ownership. */ +{% set zones = ["autosign", "manual"] %} + include "kasp.conf"; include "named.common.conf"; -zone "step1.zsk-prepub.autosign" { +{% for tld in zones %} +zone "step1.zsk-prepub.@tld@" { type primary; - file "step1.zsk-prepub.autosign.db"; - dnssec-policy "zsk-prepub"; + file "step1.zsk-prepub.@tld@.db"; + dnssec-policy "zsk-prepub-@tld@"; }; -zone "step2.zsk-prepub.autosign" { +zone "step2.zsk-prepub.@tld@" { type primary; - file "step2.zsk-prepub.autosign.db"; - dnssec-policy "zsk-prepub"; + file "step2.zsk-prepub.@tld@.db"; + dnssec-policy "zsk-prepub-@tld@"; }; -zone "step3.zsk-prepub.autosign" { +zone "step3.zsk-prepub.@tld@" { type primary; - file "step3.zsk-prepub.autosign.db"; - dnssec-policy "zsk-prepub"; + file "step3.zsk-prepub.@tld@.db"; + dnssec-policy "zsk-prepub-@tld@"; }; -zone "step4.zsk-prepub.autosign" { +zone "step4.zsk-prepub.@tld@" { type primary; - file "step4.zsk-prepub.autosign.db"; - dnssec-policy "zsk-prepub"; + file "step4.zsk-prepub.@tld@.db"; + dnssec-policy "zsk-prepub-@tld@"; }; -zone "step5.zsk-prepub.autosign" { +zone "step5.zsk-prepub.@tld@" { type primary; - file "step5.zsk-prepub.autosign.db"; - dnssec-policy "zsk-prepub"; + file "step5.zsk-prepub.@tld@.db"; + dnssec-policy "zsk-prepub-@tld@"; }; -zone "step6.zsk-prepub.autosign" { +zone "step6.zsk-prepub.@tld@" { type primary; - file "step6.zsk-prepub.autosign.db"; - dnssec-policy "zsk-prepub"; + file "step6.zsk-prepub.@tld@.db"; + dnssec-policy "zsk-prepub-@tld@"; }; +{% endfor %} diff --git a/bin/tests/system/rollover-zsk-prepub/setup.sh b/bin/tests/system/rollover-zsk-prepub/setup.sh index d9555f6e2c..86bea47159 100644 --- a/bin/tests/system/rollover-zsk-prepub/setup.sh +++ b/bin/tests/system/rollover-zsk-prepub/setup.sh @@ -40,177 +40,179 @@ O="OMNIPRESENT" U="UNRETENTIVE" # -# The zones at zsk-prepub.autosign represent the various steps of a ZSK +# The zones at zsk-prepub.$tld represent the various steps of a ZSK # Pre-Publication rollover. # -# Step 1: -# Introduce the first key. This will immediately be active. -setup step1.zsk-prepub.autosign -TactN="now-7d" -keytimes="-P ${TactN} -A ${TactN}" -KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $keytimes $zone 2>keygen.out.$zone.1) -ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $keytimes $zone 2>keygen.out.$zone.2) -$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" >settime.out.$zone.2 2>&1 -cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >>"$infile" -cp $infile $zonefile -$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 +for tld in autosign manual; do + # Step 1: + # Introduce the first key. This will immediately be active. + setup step1.zsk-prepub.$tld + TactN="now-7d" + keytimes="-P ${TactN} -A ${TactN}" + KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $keytimes $zone 2>keygen.out.$zone.1) + ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $keytimes $zone 2>keygen.out.$zone.2) + $SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" >settime.out.$zone.2 2>&1 + cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >>"$infile" + cp $infile $zonefile + $SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 2: -# It is time to pre-publish the successor ZSK. -setup step2.zsk-prepub.autosign -# According to RFC 7583: -# Tact(N) = now + Ipub - Lzsk = now + 26h - 30d -# = now + 26h - 30d = now − 694h -TactN="now-694h" -keytimes="-P ${TactN} -A ${TactN}" -KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $keytimes $zone 2>keygen.out.$zone.1) -ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $keytimes $zone 2>keygen.out.$zone.2) -$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" >settime.out.$zone.2 2>&1 -cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >>"$infile" -cp $infile $zonefile -$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 2: + # It is time to pre-publish the successor ZSK. + setup step2.zsk-prepub.$tld + # According to RFC 7583: + # Tact(N) = now + Ipub - Lzsk = now + 26h - 30d + # = now + 26h - 30d = now − 694h + TactN="now-694h" + keytimes="-P ${TactN} -A ${TactN}" + KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $keytimes $zone 2>keygen.out.$zone.1) + ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $keytimes $zone 2>keygen.out.$zone.2) + $SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $O -k $O $TactN -z $O $TactN "$ZSK" >settime.out.$zone.2 2>&1 + cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >>"$infile" + cp $infile $zonefile + $SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 3: -# After the publication interval has passed the DNSKEY of the successor ZSK -# is OMNIPRESENT and the zone can thus be signed with the successor ZSK. -setup step3.zsk-prepub.autosign -# According to RFC 7583: -# Tpub(N+1) <= Tact(N) + Lzsk - Ipub -# Tact(N+1) = Tact(N) + Lzsk -# -# Tact(N) = now - Lzsk = now - 30d -# Tpub(N+1) = now - Ipub = now - 26h -# Tact(N+1) = now -# Tret(N) = now -# Trem(N) = now + Iret = now + Dsign + Dprp + TTLsig + retire-safety = 8d1h = now + 241h -TactN="now-30d" -TpubN1="now-26h" -TactN1="now" -TremN="now+241h" -keytimes="-P ${TactN} -A ${TactN}" -oldtimes="-P ${TactN} -A ${TactN} -I ${TactN1} -D ${TremN}" -newtimes="-P ${TpubN1} -A ${TactN1}" -KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $keytimes $zone 2>keygen.out.$zone.1) -ZSK1=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $oldtimes $zone 2>keygen.out.$zone.2) -ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $newtimes $zone 2>keygen.out.$zone.3) -$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $H -k $O $TactN -z $O $TactN "$ZSK1" >settime.out.$zone.2 2>&1 -$SETTIME -s -g $O -k $R $TpubN1 -z $H $TpubN1 "$ZSK2" >settime.out.$zone.3 2>&1 -# Set key rollover relationship. -key_successor $ZSK1 $ZSK2 -# Sign zone. -cat template.db.in "${KSK}.key" "${ZSK1}.key" "${ZSK2}.key" >"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK1" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >>"$infile" -cp $infile $zonefile -$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 3: + # After the publication interval has passed the DNSKEY of the successor ZSK + # is OMNIPRESENT and the zone can thus be signed with the successor ZSK. + setup step3.zsk-prepub.$tld + # According to RFC 7583: + # Tpub(N+1) <= Tact(N) + Lzsk - Ipub + # Tact(N+1) = Tact(N) + Lzsk + # + # Tact(N) = now - Lzsk = now - 30d + # Tpub(N+1) = now - Ipub = now - 26h + # Tact(N+1) = now + # Tret(N) = now + # Trem(N) = now + Iret = now + Dsign + Dprp + TTLsig + retire-safety = 8d1h = now + 241h + TactN="now-30d" + TpubN1="now-26h" + TactN1="now" + TremN="now+241h" + keytimes="-P ${TactN} -A ${TactN}" + oldtimes="-P ${TactN} -A ${TactN} -I ${TactN1} -D ${TremN}" + newtimes="-P ${TpubN1} -A ${TactN1}" + KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $keytimes $zone 2>keygen.out.$zone.1) + ZSK1=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $oldtimes $zone 2>keygen.out.$zone.2) + ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $newtimes $zone 2>keygen.out.$zone.3) + $SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $H -k $O $TactN -z $O $TactN "$ZSK1" >settime.out.$zone.2 2>&1 + $SETTIME -s -g $O -k $R $TpubN1 -z $H $TpubN1 "$ZSK2" >settime.out.$zone.3 2>&1 + # Set key rollover relationship. + key_successor $ZSK1 $ZSK2 + # Sign zone. + cat template.db.in "${KSK}.key" "${ZSK1}.key" "${ZSK2}.key" >"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK1" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >>"$infile" + cp $infile $zonefile + $SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 4: -# After the retire interval has passed the predecessor DNSKEY can be -# removed from the zone. -setup step4.zsk-prepub.autosign -# Lzsk: 30d -# Ipub: 26h -# Dsgn: 1w -# Dprp: 1h -# TTLsig: 1d -# retire-safety: 2d -# -# According to RFC 7583: -# Iret = Dsgn + Dprp + TTLsig (+retire-safety) -# Iret = 1w + 1h + 1d + 2d = 10d1h = 241h -# -# Tact(N) = now - Iret - Lzsk -# = now - 241h - 30d = now - 241h - 720h -# = now - 961h -# Tpub(N+1) = now - Iret - Ipub -# = now - 241h - 26h -# = now - 267h -# Tact(N+1) = now - Iret = now - 241h -TactN="now-961h" -TpubN1="now-267h" -TactN1="now-241h" -TremN="now" -keytimes="-P ${TactN} -A ${TactN}" -oldtimes="-P ${TactN} -A ${TactN} -I ${TactN1} -D ${TremN}" -newtimes="-P ${TpubN1} -A ${TactN1}" -KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $keytimes $zone 2>keygen.out.$zone.1) -ZSK1=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $oldtimes $zone 2>keygen.out.$zone.2) -ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $newtimes $zone 2>keygen.out.$zone.3) -$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $H -k $O $TactN -z $U $TactN1 "$ZSK1" >settime.out.$zone.2 2>&1 -$SETTIME -s -g $O -k $O $TactN1 -z $R $TactN1 "$ZSK2" >settime.out.$zone.3 2>&1 -# Set key rollover relationship. -key_successor $ZSK1 $ZSK2 -# Sign zone. -cat template.db.in "${KSK}.key" "${ZSK1}.key" "${ZSK2}.key" >"$infile" -cp $infile $zonefile -$SIGNER -PS -x -s now-2w -e now-1mi -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 4: + # After the retire interval has passed the predecessor DNSKEY can be + # removed from the zone. + setup step4.zsk-prepub.$tld + # Lzsk: 30d + # Ipub: 26h + # Dsgn: 1w + # Dprp: 1h + # TTLsig: 1d + # retire-safety: 2d + # + # According to RFC 7583: + # Iret = Dsgn + Dprp + TTLsig (+retire-safety) + # Iret = 1w + 1h + 1d + 2d = 10d1h = 241h + # + # Tact(N) = now - Iret - Lzsk + # = now - 241h - 30d = now - 241h - 720h + # = now - 961h + # Tpub(N+1) = now - Iret - Ipub + # = now - 241h - 26h + # = now - 267h + # Tact(N+1) = now - Iret = now - 241h + TactN="now-961h" + TpubN1="now-267h" + TactN1="now-241h" + TremN="now" + keytimes="-P ${TactN} -A ${TactN}" + oldtimes="-P ${TactN} -A ${TactN} -I ${TactN1} -D ${TremN}" + newtimes="-P ${TpubN1} -A ${TactN1}" + KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $keytimes $zone 2>keygen.out.$zone.1) + ZSK1=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $oldtimes $zone 2>keygen.out.$zone.2) + ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $newtimes $zone 2>keygen.out.$zone.3) + $SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $H -k $O $TactN -z $U $TactN1 "$ZSK1" >settime.out.$zone.2 2>&1 + $SETTIME -s -g $O -k $O $TactN1 -z $R $TactN1 "$ZSK2" >settime.out.$zone.3 2>&1 + # Set key rollover relationship. + key_successor $ZSK1 $ZSK2 + # Sign zone. + cat template.db.in "${KSK}.key" "${ZSK1}.key" "${ZSK2}.key" >"$infile" + cp $infile $zonefile + $SIGNER -PS -x -s now-2w -e now-1mi -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 5: -# The predecessor DNSKEY is removed long enough that is has become HIDDEN. -setup step5.zsk-prepub.autosign -# Subtract DNSKEY TTL + zone-propagation-delay from all the times (2h). -# Tact(N) = now - 961h - 2h = now - 963h -# Tpub(N+1) = now - 267h - 2h = now - 269h -# Tact(N+1) = now - 241h - 2h = now - 243h -# Trem(N) = Tact(N+1) + Iret = now -2h -TactN="now-963h" -TremN="now-2h" -TpubN1="now-269h" -TactN1="now-243h" -TremN="now-2h" -keytimes="-P ${TactN} -A ${TactN}" -oldtimes="-P ${TactN} -A ${TactN} -I ${TactN1} -D ${TremN}" -newtimes="-P ${TpubN1} -A ${TactN1}" -KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $keytimes $zone 2>keygen.out.$zone.1) -ZSK1=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $oldtimes $zone 2>keygen.out.$zone.2) -ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $newtimes $zone 2>keygen.out.$zone.3) -$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $H -k $U $TremN -z $H $TremN "$ZSK1" >settime.out.$zone.2 2>&1 -$SETTIME -s -g $O -k $O $TactN1 -z $O $TremN "$ZSK2" >settime.out.$zone.3 2>&1 -# Set key rollover relationship. -key_successor $ZSK1 $ZSK2 -# Sign zone. -cat template.db.in "${KSK}.key" "${ZSK1}.key" "${ZSK2}.key" >"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK1" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >>"$infile" -cp $infile $zonefile -$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 5: + # The predecessor DNSKEY is removed long enough that is has become HIDDEN. + setup step5.zsk-prepub.$tld + # Subtract DNSKEY TTL + zone-propagation-delay from all the times (2h). + # Tact(N) = now - 961h - 2h = now - 963h + # Tpub(N+1) = now - 267h - 2h = now - 269h + # Tact(N+1) = now - 241h - 2h = now - 243h + # Trem(N) = Tact(N+1) + Iret = now -2h + TactN="now-963h" + TremN="now-2h" + TpubN1="now-269h" + TactN1="now-243h" + TremN="now-2h" + keytimes="-P ${TactN} -A ${TactN}" + oldtimes="-P ${TactN} -A ${TactN} -I ${TactN1} -D ${TremN}" + newtimes="-P ${TpubN1} -A ${TactN1}" + KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $keytimes $zone 2>keygen.out.$zone.1) + ZSK1=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $oldtimes $zone 2>keygen.out.$zone.2) + ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $newtimes $zone 2>keygen.out.$zone.3) + $SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $H -k $U $TremN -z $H $TremN "$ZSK1" >settime.out.$zone.2 2>&1 + $SETTIME -s -g $O -k $O $TactN1 -z $O $TremN "$ZSK2" >settime.out.$zone.3 2>&1 + # Set key rollover relationship. + key_successor $ZSK1 $ZSK2 + # Sign zone. + cat template.db.in "${KSK}.key" "${ZSK1}.key" "${ZSK2}.key" >"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK1" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >>"$infile" + cp $infile $zonefile + $SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 -# Step 6: -# The predecessor DNSKEY can be purged. -setup step6.zsk-prepub.autosign -# Subtract purge-keys interval from all the times (1h). -TactN="now-964h" -TremN="now-3h" -TpubN1="now-270h" -TactN1="now-244h" -TremN="now-3h" -keytimes="-P ${TactN} -A ${TactN}" -oldtimes="-P ${TactN} -A ${TactN} -I ${TactN1} -D ${TremN}" -newtimes="-P ${TpubN1} -A ${TactN1}" -KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $keytimes $zone 2>keygen.out.$zone.1) -ZSK1=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $oldtimes $zone 2>keygen.out.$zone.2) -ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $newtimes $zone 2>keygen.out.$zone.3) -$SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" >settime.out.$zone.1 2>&1 -$SETTIME -s -g $H -k $H $TremN -z $H $TremN "$ZSK1" >settime.out.$zone.2 2>&1 -$SETTIME -s -g $O -k $O $TactN1 -z $O $TremN "$ZSK2" >settime.out.$zone.3 2>&1 -# Set key rollover relationship. -key_successor $ZSK1 $ZSK2 -# Sign zone. -cat template.db.in "${KSK}.key" "${ZSK1}.key" "${ZSK2}.key" >"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK1" >>"$infile" -private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >>"$infile" -cp $infile $zonefile -$SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # Step 6: + # The predecessor DNSKEY can be purged. + setup step6.zsk-prepub.$tld + # Subtract purge-keys interval from all the times (1h). + TactN="now-964h" + TremN="now-3h" + TpubN1="now-270h" + TactN1="now-244h" + TremN="now-3h" + keytimes="-P ${TactN} -A ${TactN}" + oldtimes="-P ${TactN} -A ${TactN} -I ${TactN1} -D ${TremN}" + newtimes="-P ${TpubN1} -A ${TactN1}" + KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 -f KSK $keytimes $zone 2>keygen.out.$zone.1) + ZSK1=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $oldtimes $zone 2>keygen.out.$zone.2) + ZSK2=$($KEYGEN -a $DEFAULT_ALGORITHM -L 3600 $newtimes $zone 2>keygen.out.$zone.3) + $SETTIME -s -g $O -k $O $TactN -r $O $TactN -d $O $TactN "$KSK" >settime.out.$zone.1 2>&1 + $SETTIME -s -g $H -k $H $TremN -z $H $TremN "$ZSK1" >settime.out.$zone.2 2>&1 + $SETTIME -s -g $O -k $O $TactN1 -z $O $TremN "$ZSK2" >settime.out.$zone.3 2>&1 + # Set key rollover relationship. + key_successor $ZSK1 $ZSK2 + # Sign zone. + cat template.db.in "${KSK}.key" "${ZSK1}.key" "${ZSK2}.key" >"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK1" >>"$infile" + private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK2" >>"$infile" + cp $infile $zonefile + $SIGNER -S -x -s now-1h -e now+2w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 +done diff --git a/bin/tests/system/rollover-zsk-prepub/tests_rollover_zsk_prepublication.py b/bin/tests/system/rollover-zsk-prepub/tests_rollover_zsk_prepublication.py index d5550bf509..1966991e24 100644 --- a/bin/tests/system/rollover-zsk-prepub/tests_rollover_zsk_prepublication.py +++ b/bin/tests/system/rollover-zsk-prepub/tests_rollover_zsk_prepublication.py @@ -34,7 +34,7 @@ CONFIG = { "signatures-validity": TIMEDELTA["P14D"], "zone-propagation-delay": TIMEDELTA["PT1H"], } -POLICY = "zsk-prepub" +POLICY = "zsk-prepub-autosign" ZSK_LIFETIME = TIMEDELTA["P30D"] LIFETIME_POLICY = int(ZSK_LIFETIME.total_seconds()) IPUB = Ipub(CONFIG) From 927c24971108915eafb4a91a3da487c101bc7dd9 Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Thu, 24 Jul 2025 11:09:01 +0200 Subject: [PATCH 05/13] Add manual-mode parameter to isctest.kasp Key state transitions may be blocked by manual-mode, meaning key timing metadata may not be respected and can be inaccurate. For these tests use the state values to determine whether the DNSKEY/CDS/CDNSKEY RRset must be published or not. --- bin/tests/system/isctest/kasp.py | 72 ++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 18 deletions(-) diff --git a/bin/tests/system/isctest/kasp.py b/bin/tests/system/isctest/kasp.py index 3419ffefec..03dedd9aa9 100644 --- a/bin/tests/system/isctest/kasp.py +++ b/bin/tests/system/isctest/kasp.py @@ -829,7 +829,13 @@ def check_dnssecstatus(server, zone, keys, policy=None, view=None): def _check_signatures( - signatures, covers, fqdn, keys, offline_ksk=False, zsk_missing=False, smooth=False + signatures, + covers, + fqdn, + keys, + offline_ksk=False, + zsk_missing=False, + smooth=False, ): numsigs = 0 zrrsig = True @@ -917,7 +923,7 @@ def check_signatures( assert numsigs == len(signatures) -def _check_dnskeys(dnskeys, keys, cdnskey=False): +def _check_dnskeys(dnskeys, keys, cdnskey=False, manual_mode=False): now = KeyTimingMetadata.now() numkeys = 0 @@ -928,10 +934,21 @@ def _check_dnskeys(dnskeys, keys, cdnskey=False): delete_md = f"Sync{delete_md}" for key in keys: - publish = key.get_timing(publish_md, must_exist=False) - delete = key.get_timing(delete_md, must_exist=False) - published = publish is not None and now >= publish - removed = delete is not None and delete <= now + if manual_mode: + # State transitions may be blocked, preset key timings may not + # be accurate. Use the state values to determine whether the + # CDS must be published or not. + if cdnskey: + md = key.get_metadata("DSState") + else: + md = key.get_metadata("DNSKEYState") + published = md in ["omnipresent", "rumoured"] + removed = not published + else: + publish = key.get_timing(publish_md, must_exist=False) + delete = key.get_timing(delete_md, must_exist=False) + published = publish is not None and now >= publish + removed = delete is not None and delete <= now if not published or removed: for dnskey in dnskeys: @@ -954,7 +971,7 @@ def _check_dnskeys(dnskeys, keys, cdnskey=False): return numkeys -def check_dnskeys(rrset, ksks, zsks, cdnskey=False): +def check_dnskeys(rrset, ksks, zsks, cdnskey=False, manual_mode=False): # Check if the correct DNSKEY records are published. If the current time # is between the timing metadata 'publish' and 'delete', the key must have # a DNSKEY record published. If 'cdnskey' is True, check against CDNSKEY @@ -969,14 +986,14 @@ def check_dnskeys(rrset, ksks, zsks, cdnskey=False): dnskey = f"{rr.name} {rr.ttl} {rdclass} {rdtype} {rdata}" dnskeys.append(dnskey) - numkeys += _check_dnskeys(dnskeys, ksks, cdnskey=cdnskey) + numkeys += _check_dnskeys(dnskeys, ksks, cdnskey=cdnskey, manual_mode=manual_mode) if not cdnskey: - numkeys += _check_dnskeys(dnskeys, zsks) + numkeys += _check_dnskeys(dnskeys, zsks, manual_mode=manual_mode) assert numkeys == len(dnskeys) -def check_cds(cdss, keys, alg): +def check_cds(cdss, keys, alg, manual_mode=False): # Check if the correct CDS records are published. If the current time # is between the timing metadata 'publish' and 'delete', the key must have # a CDS record published. @@ -986,10 +1003,19 @@ def check_cds(cdss, keys, alg): for key in keys: assert key.is_ksk() - publish = key.get_timing("SyncPublish") - delete = key.get_timing("SyncDelete", must_exist=False) - published = now >= publish - removed = delete is not None and delete <= now + if manual_mode: + # State transitions may be blocked, preset key timings may not + # be accurate. Use the state values to determine whether the + # CDS must be published or not. + md = key.get_metadata("DSState") + published = md in ["omnipresent", "rumoured"] + removed = not published + else: + publish = key.get_timing("SyncPublish") + delete = key.get_timing("SyncDelete", must_exist=False) + published = now >= publish + removed = delete is not None and delete <= now + if not published or removed: for cds in cdss: assert not key.cds_equals(cds, alg) @@ -1069,6 +1095,7 @@ def check_apex( zsks, cdss=None, cds_delete=False, + manual_mode=False, offline_ksk=False, zsk_missing=False, tsig=None, @@ -1082,7 +1109,7 @@ def check_apex( # test dnskey query dnskeys, rrsigs = _query_rrset(server, fqdn, dns.rdatatype.DNSKEY, tsig=tsig) - check_dnskeys(dnskeys, ksks, zsks) + check_dnskeys(dnskeys, ksks, zsks, manual_mode=manual_mode) check_signatures( rrsigs, dns.rdatatype.DNSKEY, fqdn, ksks, zsks, offline_ksk=offline_ksk ) @@ -1108,7 +1135,7 @@ def check_apex( check_cdsdelete(cdnskeys, "0 3 0 AA==") else: if "CDNSKEY" in cdss: - check_dnskeys(cdnskeys, ksks, zsks, cdnskey=True) + check_dnskeys(cdnskeys, ksks, zsks, cdnskey=True, manual_mode=manual_mode) else: assert len(cdnskeys) == 0 @@ -1136,7 +1163,7 @@ def check_apex( for alg in ["SHA-256", "SHA-384"]: if f"CDS ({alg})" in cdss: - numcds += check_cds(cdsrrs, ksks, alg) + numcds += check_cds(cdsrrs, ksks, alg, manual_mode=manual_mode) else: check_cds_prohibit(cdsrrs, ksks, alg) @@ -1185,6 +1212,7 @@ def check_rollover_step(server, config, policy, step): cds_delete = step.get("cds-delete", False) check_keytimes_flag = step.get("check-keytimes", True) zone_signed = step.get("zone-signed", True) + manual_mode = step.get("manual-mode", False) isctest.log.info(f"check rollover step {zone}") @@ -1247,7 +1275,15 @@ def check_rollover_step(server, config, policy, step): check_keytimes(keys, expected) check_dnssecstatus(server, zone, keys, policy=policy) - check_apex(server, zone, ksks, zsks, cdss=cdss, cds_delete=cds_delete) + check_apex( + server, + zone, + ksks, + zsks, + cdss=cdss, + cds_delete=cds_delete, + manual_mode=manual_mode, + ) check_subdomain(server, zone, ksks, zsks, smooth=smooth) def check_next_key_event(): From c000cf70cbf26bbe86c762bd94aad7e0ecb8f564 Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Wed, 23 Jul 2025 09:27:04 +0200 Subject: [PATCH 06/13] Test manual-mode with CSK algorithm rollover Update check_rollover_step to return the found keys. This can be used to test that keymgr-manual-mode messages are correctly logged. Parametrize each test case and in case of manual-mode, execute additional checks. First a keymgr run should not change the existing key state (with exceptions of timing events such as moving from RUMOURED to OMNIPRESENT, and from UNRETENTIVE to HIDDEN). Appropriate messages must be logged. After enforcing the next step with 'rndc dnssec -step', the key state should be the same as if the step were to be taken automatically. --- bin/tests/system/isctest/kasp.py | 2 + .../tests_rollover_algo_csk_reconfig.py | 178 ++++++++++++++++-- 2 files changed, 162 insertions(+), 18 deletions(-) diff --git a/bin/tests/system/isctest/kasp.py b/bin/tests/system/isctest/kasp.py index 03dedd9aa9..b750cb1f78 100644 --- a/bin/tests/system/isctest/kasp.py +++ b/bin/tests/system/isctest/kasp.py @@ -1292,6 +1292,8 @@ def check_rollover_step(server, config, policy, step): if nextev is not None: isctest.run.retry_with_timeout(check_next_key_event, timeout=5) + return expected + def verify_update_is_signed(server, fqdn, qname, qtype, rdata, ksks, zsks, tsig=None): """ diff --git a/bin/tests/system/rollover-algo-csk/tests_rollover_algo_csk_reconfig.py b/bin/tests/system/rollover-algo-csk/tests_rollover_algo_csk_reconfig.py index e10d15a5af..38527ad5e0 100644 --- a/bin/tests/system/rollover-algo-csk/tests_rollover_algo_csk_reconfig.py +++ b/bin/tests/system/rollover-algo-csk/tests_rollover_algo_csk_reconfig.py @@ -15,6 +15,7 @@ import pytest import isctest from isctest.kasp import KeyTimingMetadata +from isctest.util import param from rollover.common import ( pytestmark, alg, @@ -28,6 +29,7 @@ from rollover.common import ( ALGOROLL_KEYTTLPROP, ALGOROLL_OFFSETS, ALGOROLL_OFFVAL, + DURATION, TIMEDELTA, ) @@ -50,11 +52,45 @@ def reconfigure(ns6, templates): TIME_PASSED = KeyTimingMetadata.now().value - start_time.value -def test_algoroll_csk_reconfig_step1(ns6, alg, size): - zone = "step1.csk-algorithm-roll.kasp" +@pytest.mark.parametrize( + "tld", + [ + param("kasp"), + param("manual"), + ], +) +def test_algoroll_csk_reconfig_step1(tld, ns6, alg, size): + zone = f"step1.csk-algorithm-roll.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns6, zone, reconfig=True) + if tld == "manual": + # Same as initial. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"csk 0 8 2048 goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{-DURATION['P7D']}", + ], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns6, CONFIG, policy, step) + + # Check logs. + tag = keys[0].key.tag + msg1 = f"keymgr-manual-mode: block retire DNSKEY {zone}/RSASHA256/{tag} (CSK)" + msg2 = f"keymgr-manual-mode: block new key generation for zone {zone} (policy {policy})" + ns6.log.expect(msg1) + ns6.log.expect(msg2) + + # Force step. + with ns6.watch_log_from_here() as watcher: + ns6.rndc(f"dnssec -step {zone}") + watcher.wait_for_line(f"keymgr: {zone} done") + + # Check state after step. step = { "zone": zone, "cdss": CDSS, @@ -67,14 +103,24 @@ def test_algoroll_csk_reconfig_step1(ns6, alg, size): # Next key event is when the ecdsa256 keys have been propagated. "nextev": ALGOROLL_IPUB, } - isctest.kasp.check_rollover_step(ns6, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns6, CONFIG, policy, step) -def test_algoroll_csk_reconfig_step2(ns6, alg, size): - zone = "step2.csk-algorithm-roll.kasp" +@pytest.mark.parametrize( + "tld", + [ + param("kasp"), + param("manual"), + ], +) +def test_algoroll_csk_reconfig_step2(tld, ns6, alg, size): + zone = f"step2.csk-algorithm-roll.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns6, zone, reconfig=True) + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + step = { "zone": zone, "cdss": CDSS, @@ -94,14 +140,58 @@ def test_algoroll_csk_reconfig_step2(ns6, alg, size): # the time passed between key creation and invoking 'rndc reconfig'. "nextev": ALGOROLL_IPUBC - ALGOROLL_IPUB - TIME_PASSED, } - isctest.kasp.check_rollover_step(ns6, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns6, CONFIG, policy, step) -def test_algoroll_csk_reconfig_step3(ns6, alg, size): - zone = "step3.csk-algorithm-roll.kasp" +@pytest.mark.parametrize( + "tld", + [ + param("kasp"), + param("manual"), + ], +) +def test_algoroll_csk_reconfig_step3(tld, ns6, alg, size): + zone = f"step3.csk-algorithm-roll.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns6, zone, reconfig=True) + if tld == "manual": + # Same as step 2, but the zone signatures have become OMNIPRESENT. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"csk 0 8 2048 goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{ALGOROLL_OFFVAL}", + f"csk 0 {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:hidden offset:{ALGOROLL_OFFSETS['step3']}", + ], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns6, CONFIG, policy, step) + + # Check logs. + tag = keys[1].key.tag + msg = f"keymgr-manual-mode: block transition CSK {zone}/ECDSAP256SHA256/{tag} type DS state HIDDEN to state RUMOURED" + ns6.log.expect(msg) + + # Force step. + with ns6.watch_log_from_here() as watcher: + ns6.rndc(f"dnssec -step {zone}") + watcher.wait_for_line(f"keymgr: {zone} done") + + # Check logs. + tag = keys[0].key.tag + msg = f"keymgr-manual-mode: block transition CSK {zone}/RSASHA256/{tag} type DS state OMNIPRESENT to state UNRETENTIVE" + if msg in ns6.log: + # Force step. + isctest.log.debug( + f"keymgr-manual-mode blocking transition CSK {zone}/RSASHA256/{tag} type DS state OMNIPRESENT to state UNRETENTIVE, step again" + ) + with ns6.watch_log_from_here() as watcher: + ns6.rndc(f"dnssec -step {zone}") + watcher.wait_for_line(f"keymgr: {zone} done") + step = { "zone": zone, "cdss": CDSS, @@ -114,14 +204,46 @@ def test_algoroll_csk_reconfig_step3(ns6, alg, size): # after the publication interval of the parent side. "nextev": ALGOROLL_IRETKSK - TIME_PASSED, } - isctest.kasp.check_rollover_step(ns6, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns6, CONFIG, policy, step) -def test_algoroll_csk_reconfig_step4(ns6, alg, size): - zone = "step4.csk-algorithm-roll.kasp" +@pytest.mark.parametrize( + "tld", + [ + param("kasp"), + param("manual"), + ], +) +def test_algoroll_csk_reconfig_step4(tld, ns6, alg, size): + zone = f"step4.csk-algorithm-roll.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns6, zone, reconfig=True) + if tld == "manual": + # Same as step 3, but the DS has become HIDDEN/OMNIPRESENT. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"csk 0 8 2048 goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:hidden offset:{ALGOROLL_OFFVAL}", + f"csk 0 {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{ALGOROLL_OFFSETS['step4']}", + ], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns6, CONFIG, policy, step) + + # Check logs. + tag = keys[0].key.tag + msg = f"keymgr-manual-mode: block transition CSK {zone}/RSASHA256/{tag} type DNSKEY state OMNIPRESENT to state UNRETENTIVE" + ns6.log.expect(msg) + + # Force step. + with ns6.watch_log_from_here() as watcher: + ns6.rndc(f"dnssec -step {zone}") + watcher.wait_for_line(f"keymgr: {zone} done") + step = { "zone": zone, "cdss": CDSS, @@ -134,14 +256,24 @@ def test_algoroll_csk_reconfig_step4(ns6, alg, size): # This happens after the DNSKEY TTL plus zone propagation delay. "nextev": ALGOROLL_KEYTTLPROP, } - isctest.kasp.check_rollover_step(ns6, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns6, CONFIG, policy, step) -def test_algoroll_csk_reconfig_step5(ns6, alg, size): - zone = "step5.csk-algorithm-roll.kasp" +@pytest.mark.parametrize( + "tld", + [ + param("kasp"), + param("manual"), + ], +) +def test_algoroll_csk_reconfig_step5(tld, ns6, alg, size): + zone = f"step5.csk-algorithm-roll.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns6, zone, reconfig=True) + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + step = { "zone": zone, "cdss": CDSS, @@ -158,14 +290,24 @@ def test_algoroll_csk_reconfig_step5(ns6, alg, size): # between key creation and invoking 'rndc reconfig'. "nextev": ALGOROLL_IRET - ALGOROLL_IRETKSK - ALGOROLL_KEYTTLPROP - TIME_PASSED, } - isctest.kasp.check_rollover_step(ns6, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns6, CONFIG, policy, step) -def test_algoroll_csk_reconfig_step6(ns6, alg, size): - zone = "step6.csk-algorithm-roll.kasp" +@pytest.mark.parametrize( + "tld", + [ + param("kasp"), + param("manual"), + ], +) +def test_algoroll_csk_reconfig_step6(tld, ns6, alg, size): + zone = f"step6.csk-algorithm-roll.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns6, zone, reconfig=True) + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + step = { "zone": zone, "cdss": CDSS, @@ -179,4 +321,4 @@ def test_algoroll_csk_reconfig_step6(ns6, alg, size): # loadkeys interval. "nextev": TIMEDELTA["PT1H"], } - isctest.kasp.check_rollover_step(ns6, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns6, CONFIG, policy, step) From 6b5c69d4313d7567c83327e07bdc79e06b95f2ff Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Wed, 23 Jul 2025 10:34:07 +0200 Subject: [PATCH 07/13] Test manual-mode with KSK/ZSK algorithm rollover Similar to the previous commit that tests CSK algorithm rollover. Parametrize each test case and in case of manual-mode, execute additional checks. First a keymgr run should not change the existing key state (with exceptions of timing events such as moving from RUMOURED to OMNIPRESENT, and from UNRETENTIVE to HIDDEN). Appropriate messages must be logged. After enforcing the next step with 'rndc dnssec -step', the key state should be the same as if the step were to be taken automatically. --- .../tests_rollover_algo_ksk_zsk_reconfig.py | 188 ++++++++++++++++-- 1 file changed, 170 insertions(+), 18 deletions(-) diff --git a/bin/tests/system/rollover-algo-ksk-zsk/tests_rollover_algo_ksk_zsk_reconfig.py b/bin/tests/system/rollover-algo-ksk-zsk/tests_rollover_algo_ksk_zsk_reconfig.py index 6058780de0..9646dce7af 100644 --- a/bin/tests/system/rollover-algo-ksk-zsk/tests_rollover_algo_ksk_zsk_reconfig.py +++ b/bin/tests/system/rollover-algo-ksk-zsk/tests_rollover_algo_ksk_zsk_reconfig.py @@ -15,6 +15,7 @@ import pytest import isctest from isctest.kasp import KeyTimingMetadata +from isctest.util import param from rollover.common import ( pytestmark, alg, @@ -28,6 +29,7 @@ from rollover.common import ( ALGOROLL_KEYTTLPROP, ALGOROLL_OFFSETS, ALGOROLL_OFFVAL, + DURATION, TIMEDELTA, ) @@ -50,11 +52,48 @@ def reconfigure(ns6, templates): TIME_PASSED = KeyTimingMetadata.now().value - start_time.value -def test_algoroll_ksk_zsk_reconfig_step1(ns6, alg, size): - zone = "step1.algorithm-roll.kasp" +@pytest.mark.parametrize( + "tld", + [ + param("kasp"), + param("manual"), + ], +) +def test_algoroll_ksk_zsk_reconfig_step1(tld, ns6, alg, size): + zone = f"step1.algorithm-roll.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns6, zone, reconfig=True) + if tld == "manual": + # Same as initial. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"ksk 0 8 2048 goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{-DURATION['P7D']}", + f"zsk 0 8 2048 goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{-DURATION['P7D']}", + ], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns6, CONFIG, policy, step) + + # Check logs. + ktag = keys[0].key.tag + ztag = keys[1].key.tag + msg1 = f"keymgr-manual-mode: block retire DNSKEY {zone}/RSASHA256/{ktag} (KSK)" + msg2 = f"keymgr-manual-mode: block retire DNSKEY {zone}/RSASHA256/{ztag} (ZSK)" + msg3 = f"keymgr-manual-mode: block new key generation for zone {zone} (policy {policy})" # twice + ns6.log.expect(msg1) + ns6.log.expect(msg2) + ns6.log.expect(msg3) + + # Force step. + with ns6.watch_log_from_here() as watcher: + ns6.rndc(f"dnssec -step {zone}") + watcher.wait_for_line(f"keymgr: {zone} done") + step = { "zone": zone, "cdss": CDSS, @@ -69,14 +108,24 @@ def test_algoroll_ksk_zsk_reconfig_step1(ns6, alg, size): # Next key event is when the ecdsa256 keys have been propagated. "nextev": ALGOROLL_IPUB, } - isctest.kasp.check_rollover_step(ns6, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns6, CONFIG, policy, step) -def test_algoroll_ksk_zsk_reconfig_step2(ns6, alg, size): - zone = "step2.algorithm-roll.kasp" +@pytest.mark.parametrize( + "tld", + [ + param("kasp"), + param("manual"), + ], +) +def test_algoroll_ksk_zsk_reconfig_step2(tld, ns6, alg, size): + zone = f"step2.algorithm-roll.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns6, zone, reconfig=True) + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + step = { "zone": zone, "cdss": CDSS, @@ -98,14 +147,60 @@ def test_algoroll_ksk_zsk_reconfig_step2(ns6, alg, size): # key creation and invoking 'rndc reconfig'. "nextev": ALGOROLL_IPUBC - ALGOROLL_IPUB - TIME_PASSED, } - isctest.kasp.check_rollover_step(ns6, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns6, CONFIG, policy, step) -def test_algoroll_ksk_zsk_reconfig_step3(ns6, alg, size): - zone = "step3.algorithm-roll.kasp" +@pytest.mark.parametrize( + "tld", + [ + param("kasp"), + param("manual"), + ], +) +def test_algoroll_ksk_zsk_reconfig_step3(tld, ns6, alg, size): + zone = f"step3.algorithm-roll.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns6, zone, reconfig=True) + if tld == "manual": + # Same as step 2, but the zone signatures have become OMNIPRESENT. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"ksk 0 8 2048 goal:hidden dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{ALGOROLL_OFFVAL}", + f"zsk 0 8 2048 goal:hidden dnskey:omnipresent zrrsig:omnipresent offset:{ALGOROLL_OFFVAL}", + f"ksk 0 {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:hidden offset:{ALGOROLL_OFFSETS['step3']}", + f"zsk 0 {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{ALGOROLL_OFFSETS['step3']}", + ], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns6, CONFIG, policy, step) + + # Check logs. + tag = keys[2].key.tag + msg = f"keymgr-manual-mode: block transition KSK {zone}/ECDSAP256SHA256/{tag} type DS state HIDDEN to state RUMOURED" + ns6.log.expect(msg) + + # Force step. + with ns6.watch_log_from_here() as watcher: + ns6.rndc(f"dnssec -step {zone}") + watcher.wait_for_line(f"keymgr: {zone} done") + + # Check logs. + tag = keys[0].key.tag + msg = f"keymgr-manual-mode: block transition KSK {zone}/RSASHA256/{tag} type DS state OMNIPRESENT to state UNRETENTIVE" + if msg in ns6.log: + # Force step. + isctest.log.debug( + f"keymgr-manual-mode blocking transition CSK {zone}/RSASHA256/{tag} type DS state OMNIPRESENT to state UNRETENTIVE, step again" + ) + with ns6.watch_log_from_here() as watcher: + ns6.rndc(f"dnssec -step {zone}") + watcher.wait_for_line(f"keymgr: {zone} done") + step = { "zone": zone, "cdss": CDSS, @@ -120,14 +215,51 @@ def test_algoroll_ksk_zsk_reconfig_step3(ns6, alg, size): # after the retire interval. "nextev": ALGOROLL_IRETKSK - TIME_PASSED, } - isctest.kasp.check_rollover_step(ns6, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns6, CONFIG, policy, step) -def test_algoroll_ksk_zsk_reconfig_step4(ns6, alg, size): - zone = "step4.algorithm-roll.kasp" +@pytest.mark.parametrize( + "tld", + [ + param("kasp"), + param("manual"), + ], +) +def test_algoroll_ksk_zsk_reconfig_step4(tld, ns6, alg, size): + zone = f"step4.algorithm-roll.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns6, zone, reconfig=True) + if tld == "manual": + # Same as step 3, but the DS has become HIDDEN/OMNIPRESENT. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"ksk 0 8 2048 goal:hidden dnskey:omnipresent krrsig:omnipresent ds:hidden offset:{ALGOROLL_OFFVAL}", + f"zsk 0 8 2048 goal:hidden dnskey:omnipresent zrrsig:omnipresent offset:{ALGOROLL_OFFVAL}", + f"ksk 0 {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{ALGOROLL_OFFSETS['step4']}", + f"zsk 0 {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{ALGOROLL_OFFSETS['step4']}", + ], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns6, CONFIG, policy, step) + + # Check logs. + ktag = keys[0].key.tag + ztag = keys[1].key.tag + msg1 = f"keymgr-manual-mode: block transition KSK {zone}/RSASHA256/{ktag} type DNSKEY state OMNIPRESENT to state UNRETENTIVE" + msg2 = f"keymgr-manual-mode: block transition ZSK {zone}/RSASHA256/{ztag} type DNSKEY state OMNIPRESENT to state UNRETENTIVE" + ns6.log.expect(msg1) + ns6.log.expect(msg2) + + # Force step. + with ns6.watch_log_from_here() as watcher: + ns6.rndc(f"dnssec -step {zone}") + watcher.wait_for_line(f"keymgr: {zone} done") + step = { "zone": zone, "cdss": CDSS, @@ -142,14 +274,24 @@ def test_algoroll_ksk_zsk_reconfig_step4(ns6, alg, size): # This happens after the DNSKEY TTL plus zone propagation delay. "nextev": ALGOROLL_KEYTTLPROP, } - isctest.kasp.check_rollover_step(ns6, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns6, CONFIG, policy, step) -def test_algoroll_ksk_zsk_reconfig_step5(ns6, alg, size): - zone = "step5.algorithm-roll.kasp" +@pytest.mark.parametrize( + "tld", + [ + param("kasp"), + param("manual"), + ], +) +def test_algoroll_ksk_zsk_reconfig_step5(tld, ns6, alg, size): + zone = f"step5.algorithm-roll.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns6, zone, reconfig=True) + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + step = { "zone": zone, "cdss": CDSS, @@ -168,14 +310,24 @@ def test_algoroll_ksk_zsk_reconfig_step5(ns6, alg, size): # between key creation and invoking 'rndc reconfig'. "nextev": ALGOROLL_IRET - ALGOROLL_IRETKSK - ALGOROLL_KEYTTLPROP - TIME_PASSED, } - isctest.kasp.check_rollover_step(ns6, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns6, CONFIG, policy, step) -def test_algoroll_ksk_zsk_reconfig_step6(ns6, alg, size): - zone = "step6.algorithm-roll.kasp" +@pytest.mark.parametrize( + "tld", + [ + param("kasp"), + param("manual"), + ], +) +def test_algoroll_ksk_zsk_reconfig_step6(tld, ns6, alg, size): + zone = f"step6.algorithm-roll.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns6, zone, reconfig=True) + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + step = { "zone": zone, "cdss": CDSS, @@ -191,4 +343,4 @@ def test_algoroll_ksk_zsk_reconfig_step6(ns6, alg, size): # loadkeys interval. "nextev": TIMEDELTA["PT1H"], } - isctest.kasp.check_rollover_step(ns6, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns6, CONFIG, policy, step) From 73ecc7223e7734e989a51b6db14d96b4aea20d68 Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Wed, 23 Jul 2025 15:04:36 +0200 Subject: [PATCH 08/13] Test manual-mode with CSK rollover (1) Similar to previous commits. Parametrize each test case and in case of manual-mode, execute additional checks. First a keymgr run should not change the existing key state (with exceptions of timing events such as moving from RUMOURED to OMNIPRESENT, and from UNRETENTIVE to HIDDEN). Appropriate messages must be logged. After enforcing the next step with 'rndc dnssec -step', the key state should be the same as if the step were to be taken automatically. --- .../tests_rollover_csk_roll1.py | 215 ++++++++++++++++-- 1 file changed, 191 insertions(+), 24 deletions(-) diff --git a/bin/tests/system/rollover-csk-roll1/tests_rollover_csk_roll1.py b/bin/tests/system/rollover-csk-roll1/tests_rollover_csk_roll1.py index abf27aca65..5f60cb048c 100644 --- a/bin/tests/system/rollover-csk-roll1/tests_rollover_csk_roll1.py +++ b/bin/tests/system/rollover-csk-roll1/tests_rollover_csk_roll1.py @@ -13,8 +13,11 @@ from datetime import timedelta +import pytest + import isctest from isctest.kasp import Ipub, Iret +from isctest.util import param from rollover.common import ( pytestmark, alg, @@ -62,11 +65,22 @@ OFFSETS["step8-p"] = OFFSETS["step7-p"] - int(CONFIG["purge-keys"].total_seconds OFFSETS["step8-s"] = OFFSETS["step7-s"] - int(CONFIG["purge-keys"].total_seconds()) -def test_csk_roll1_step1(alg, size, ns3): - zone = "step1.csk-roll1.autosign" +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_csk_roll1_step1(tld, alg, size, ns3): + zone = f"step1.csk-roll1.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns3, zone) + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + # Note that the key was already generated during setup. + step = { # Introduce the first key. This will immediately be active. "zone": zone, @@ -79,14 +93,45 @@ def test_csk_roll1_step1(alg, size, ns3): # registration delay). "nextev": CSK_LIFETIME - IPUB - timedelta(days=7), } - isctest.kasp.check_rollover_step(ns3, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) -def test_csk_roll1_step2(alg, size, ns3): - zone = "step2.csk-roll1.autosign" +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_csk_roll1_step2(tld, alg, size, ns3): + zone = f"step2.csk-roll1.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns3, zone) + if tld == "manual": + # Same as step 1. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"csk {LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step2-p']}", + ], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + # Check logs. + tag = keys[0].key.tag + msg = f"keymgr-manual-mode: block CSK rollover for key {zone}/ECDSAP256SHA256/{tag} (policy {policy})" + ns3.log.expect(msg) + + # Force step. + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line(f"keymgr: {zone} done") + step = { # Successor CSK is prepublished (signs DNSKEY RRset, but not yet # other RRsets). @@ -104,14 +149,59 @@ def test_csk_roll1_step2(alg, size, ns3): # Next key event is when the successor CSK becomes OMNIPRESENT. "nextev": IPUB, } - isctest.kasp.check_rollover_step(ns3, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) -def test_csk_roll1_step3(alg, size, ns3): - zone = "step3.csk-roll1.autosign" +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_csk_roll1_step3(tld, alg, size, ns3): + zone = f"step3.csk-roll1.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns3, zone) + if tld == "manual": + # Same as step 2, but DNSKEY has become OMNIPRESENT. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"csk {LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step3-p']}", + f"csk {LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:hidden ds:hidden offset:{OFFSETS['step3-s']}", + ], + "keyrelationships": [0, 1], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + # Check logs. + tag = keys[1].key.tag + msg = f"keymgr-manual-mode: block transition CSK {zone}/ECDSAP256SHA256/{tag} type ZRRSIG state HIDDEN to state RUMOURED" + ns3.log.expect(msg) + + # Force step. + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line(f"keymgr: {zone} done") + + # Check logs. + tag = keys[0].key.tag + msg = f"keymgr-manual-mode: block transition CSK {zone}/ECDSAP256SHA256/{tag} type ZRRSIG state OMNIPRESENT to state UNRETENTIVE" + if msg in ns3.log: + # Force step. + isctest.log.debug( + f"keymgr-manual-mode blocking transition CSK {zone}/ECDSAP256SHA256/{tag} type ZRRSIG state OMNIPRESENT to state UNRETENTIVE, step again" + ) + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line(f"keymgr: {zone} done") + step = { # Successor CSK becomes omnipresent, meaning we can start signing # the remainder of the zone with the successor CSK, and we can @@ -142,14 +232,50 @@ def test_csk_roll1_step3(alg, size, ns3): # from the predecessor ZSK. "smooth": True, } - isctest.kasp.check_rollover_step(ns3, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) -def test_csk_roll1_step4(alg, size, ns3): - zone = "step4.csk-roll1.autosign" +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_csk_roll1_step4(tld, alg, size, ns3): + zone = f"step4.csk-roll1.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns3, zone) + if tld == "manual": + # Same as step 3, but DS has become HIDDEN/OMNIPRESENT. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"csk {LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:unretentive ds:hidden offset:{OFFSETS['step4-p']}", + f"csk {LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:rumoured ds:omnipresent offset:{OFFSETS['step4-s']}", + ], + "keyrelationships": [0, 1], + "manual-mode": True, + "nextev": None, + # We already swapped the DS in the previous step, so disable ds-swap. + "ds-swap": False, + } + keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + # Check logs. + tag = keys[0].key.tag + msg = f"keymgr-manual-mode: block transition CSK {zone}/ECDSAP256SHA256/{tag} type KRRSIG state OMNIPRESENT to state UNRETENTIVE" + + ns3.log.expect(msg) + + # Force step. + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line(f"keymgr: {zone} done") + step = { "zone": zone, "cdss": CDSS, @@ -169,14 +295,24 @@ def test_csk_roll1_step4(alg, size, ns3): # We already swapped the DS in the previous step, so disable ds-swap. "ds-swap": False, } - isctest.kasp.check_rollover_step(ns3, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) -def test_csk_roll1_step5(alg, size, ns3): - zone = "step5.csk-roll1.autosign" +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_csk_roll1_step5(tld, alg, size, ns3): + zone = f"step5.csk-roll1.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns3, zone) + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + step = { "zone": zone, "cdss": CDSS, @@ -192,14 +328,25 @@ def test_csk_roll1_step5(alg, size, ns3): # CSK. "nextev": SIGNDELAY, } - isctest.kasp.check_rollover_step(ns3, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) -def test_csk_roll1_step6(alg, size, ns3): - zone = "step6.csk-roll1.autosign" +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_csk_roll1_step6(tld, alg, size, ns3): + zone = f"step6.csk-roll1.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns3, zone) + if tld == "manual": + return + step = { "zone": zone, "cdss": CDSS, @@ -217,14 +364,24 @@ def test_csk_roll1_step6(alg, size, ns3): # This is the DNSKEY TTL plus zone propagation delay. "nextev": KEYTTLPROP, } - isctest.kasp.check_rollover_step(ns3, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) -def test_csk_roll1_step7(alg, size, ns3): - zone = "step7.csk-roll1.autosign" +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_csk_roll1_step7(tld, alg, size, ns3): + zone = f"step7.csk-roll1.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns3, zone) + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + step = { "zone": zone, "cdss": CDSS, @@ -239,14 +396,24 @@ def test_csk_roll1_step7(alg, size, ns3): # minus the prepublication time. "nextev": CSK_LIFETIME - IRETZSK - IPUB - KEYTTLPROP, } - isctest.kasp.check_rollover_step(ns3, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) -def test_csk_roll1_step8(alg, size, ns3): - zone = "step8.csk-roll1.autosign" +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_csk_roll1_step8(tld, alg, size, ns3): + zone = f"step8.csk-roll1.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns3, zone) + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + step = { "zone": zone, "cdss": CDSS, @@ -255,4 +422,4 @@ def test_csk_roll1_step8(alg, size, ns3): ], "nextev": None, } - isctest.kasp.check_rollover_step(ns3, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) From e35e103d7f6f717ab349aa2c0d72ce208ec2c182 Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Thu, 24 Jul 2025 11:42:59 +0200 Subject: [PATCH 09/13] Test manual-mode with CSK rollover (2) Similar to previous commit. Parametrize each test case and in case of manual-mode, execute additional checks. First a keymgr run should not change the existing key state (with exceptions of timing events such as moving from RUMOURED to OMNIPRESENT, and from UNRETENTIVE to HIDDEN). Appropriate messages must be logged. After enforcing the next step with 'rndc dnssec -step', the key state should be the same as if the step were to be taken automatically. --- .../tests_rollover_csk_roll2.py | 197 ++++++++++++++++-- 1 file changed, 176 insertions(+), 21 deletions(-) diff --git a/bin/tests/system/rollover-csk-roll2/tests_rollover_csk_roll2.py b/bin/tests/system/rollover-csk-roll2/tests_rollover_csk_roll2.py index 1e93dfff7b..c8039453f6 100644 --- a/bin/tests/system/rollover-csk-roll2/tests_rollover_csk_roll2.py +++ b/bin/tests/system/rollover-csk-roll2/tests_rollover_csk_roll2.py @@ -13,8 +13,11 @@ from datetime import timedelta +import pytest + import isctest from isctest.kasp import Ipub, Iret +from isctest.util import param from rollover.common import ( pytestmark, alg, @@ -65,11 +68,22 @@ OFFSETS["step7-p"] = OFFSETS["step6-p"] - int(timedelta(days=90).total_seconds() OFFSETS["step7-s"] = OFFSETS["step6-s"] - int(timedelta(days=90).total_seconds()) -def test_csk_roll2_step1(alg, size, ns3): - zone = "step1.csk-roll2.autosign" +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_csk_roll2_step1(tld, alg, size, ns3): + zone = f"step1.csk-roll2.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns3, zone) + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + # Note that the key was already generated during setup. + step = { # Introduce the first key. This will immediately be active. "zone": zone, @@ -82,14 +96,45 @@ def test_csk_roll2_step1(alg, size, ns3): # registration delay). "nextev": CSK_LIFETIME - IPUB - TIMEDELTA["P7D"], } - isctest.kasp.check_rollover_step(ns3, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) -def test_csk_roll2_step2(alg, size, ns3): - zone = "step2.csk-roll2.autosign" +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_csk_roll2_step2(tld, alg, size, ns3): + zone = f"step2.csk-roll2.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns3, zone) + if tld == "manual": + # Same as step 1. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"csk {LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step2-p']}", + ], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + # Check logs. + tag = keys[0].key.tag + msg = f"keymgr-manual-mode: block CSK rollover for key {zone}/ECDSAP256SHA256/{tag} (policy {policy})" + ns3.log.expect(msg) + + # Force step. + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line(f"keymgr: {zone} done") + step = { # Successor CSK is prepublished (signs DNSKEY RRset, but not yet # other RRsets). @@ -107,14 +152,59 @@ def test_csk_roll2_step2(alg, size, ns3): # Next key event is when the successor CSK becomes OMNIPRESENT. "nextev": IPUB, } - isctest.kasp.check_rollover_step(ns3, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) -def test_csk_roll2_step3(alg, size, ns3): - zone = "step3.csk-roll2.autosign" +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_csk_roll2_step3(tld, alg, size, ns3): + zone = f"step3.csk-roll2.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns3, zone) + if tld == "manual": + # Same as step 2, but DNSKEY has become OMNIPRESENT. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"csk {LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step3-p']}", + f"csk {LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:hidden ds:hidden offset:{OFFSETS['step3-s']}", + ], + "keyrelationships": [0, 1], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + # Check logs. + tag = keys[1].key.tag + msg = f"keymgr-manual-mode: block transition CSK {zone}/ECDSAP256SHA256/{tag} type ZRRSIG state HIDDEN to state RUMOURED" + ns3.log.expect(msg) + + # Force step. + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line(f"keymgr: {zone} done") + + # Check logs. + tag = keys[0].key.tag + msg = f"keymgr-manual-mode: block transition CSK {zone}/ECDSAP256SHA256/{tag} type ZRRSIG state OMNIPRESENT to state UNRETENTIVE" + if msg in ns3.log: + # Force step. + isctest.log.debug( + f"keymgr-manual-mode blocking transition CSK {zone}/ECDSAP256SHA256/{tag} type ZRRSIG state OMNIPRESENT to state UNRETENTIVE, step again" + ) + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line(f"keymgr: {zone} done") + step = { # Successor CSK becomes omnipresent, meaning we can start signing # the remainder of the zone with the successor CSK, and we can @@ -145,14 +235,24 @@ def test_csk_roll2_step3(alg, size, ns3): # from the predecessor ZSK. "smooth": True, } - isctest.kasp.check_rollover_step(ns3, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) -def test_csk_roll2_step4(alg, size, ns3): - zone = "step4.csk-roll2.autosign" +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_csk_roll2_step4(tld, alg, size, ns3): + zone = f"step4.csk-roll2.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns3, zone) + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + step = { "zone": zone, "cdss": CDSS, @@ -174,14 +274,49 @@ def test_csk_roll2_step4(alg, size, ns3): # We already swapped the DS in the previous step, so disable ds-swap. "ds-swap": False, } - isctest.kasp.check_rollover_step(ns3, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) -def test_csk_roll2_step5(alg, size, ns3): - zone = "step5.csk-roll2.autosign" +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_csk_roll2_step5(tld, alg, size, ns3): + zone = f"step5.csk-roll2.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns3, zone) + if tld == "manual": + # Same as step 4, but DS has become HIDDEN/OMNIPRESENT. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"csk {LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:omnipresent krrsig:omnipresent zrrsig:hidden ds:hidden offset:{OFFSETS['step5-p']}", + f"csk {LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:omnipresent offset:{OFFSETS['step5-s']}", + ], + "keyrelationships": [0, 1], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + # Check logs. + tag = keys[0].key.tag + msg1 = f"keymgr-manual-mode: block transition CSK {zone}/ECDSAP256SHA256/{tag} type DNSKEY state OMNIPRESENT to state UNRETENTIVE" + msg2 = f"keymgr-manual-mode: block transition CSK {zone}/ECDSAP256SHA256/{tag} type KRRSIG state OMNIPRESENT to state UNRETENTIVE" + ns3.log.expect(msg1) + ns3.log.expect(msg2) + + # Force step. + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line(f"keymgr: {zone} done") + step = { "zone": zone, "cdss": CDSS, @@ -200,14 +335,24 @@ def test_csk_roll2_step5(alg, size, ns3): # This is the DNSKEY TTL plus zone propagation delay. "nextev": KEYTTLPROP, } - isctest.kasp.check_rollover_step(ns3, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) -def test_csk_roll2_step6(alg, size, ns3): - zone = "step6.csk-roll2.autosign" +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_csk_roll2_step6(tld, alg, size, ns3): + zone = f"step6.csk-roll2.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns3, zone) + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + step = { "zone": zone, "cdss": CDSS, @@ -223,14 +368,24 @@ def test_csk_roll2_step6(alg, size, ns3): # This is the Lcsk, minus time passed since the key was published. "nextev": CSK_LIFETIME - IRET - IPUB - KEYTTLPROP, } - isctest.kasp.check_rollover_step(ns3, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) -def test_csk_roll2_step7(alg, size, ns3): - zone = "step7.csk-roll2.autosign" +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_csk_roll2_step7(tld, alg, size, ns3): + zone = f"step7.csk-roll2.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns3, zone) + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + step = { "zone": zone, "cdss": CDSS, @@ -242,4 +397,4 @@ def test_csk_roll2_step7(alg, size, ns3): "keyrelationships": [0, 1], "nextev": None, } - isctest.kasp.check_rollover_step(ns3, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) From 6904e43510c02e8f04d6e98af6ae61ee6f6d1f8c Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Thu, 24 Jul 2025 12:05:06 +0200 Subject: [PATCH 10/13] Test manual-mode with KSK rollover Similar to previous commit. Parametrize each test case and in case of manual-mode, execute additional checks. First a keymgr run should not change the existing key state (with exceptions of timing events such as moving from RUMOURED to OMNIPRESENT, and from UNRETENTIVE to HIDDEN). Appropriate messages must be logged. After enforcing the next step with 'rndc dnssec -step', the key state should be the same as if the step were to be taken automatically. --- .../tests_rollover_ksk_doubleksk.py | 186 ++++++++++++++++-- 1 file changed, 167 insertions(+), 19 deletions(-) diff --git a/bin/tests/system/rollover-ksk-doubleksk/tests_rollover_ksk_doubleksk.py b/bin/tests/system/rollover-ksk-doubleksk/tests_rollover_ksk_doubleksk.py index 60e88ba735..90ebce96a6 100644 --- a/bin/tests/system/rollover-ksk-doubleksk/tests_rollover_ksk_doubleksk.py +++ b/bin/tests/system/rollover-ksk-doubleksk/tests_rollover_ksk_doubleksk.py @@ -13,7 +13,10 @@ from datetime import timedelta +import pytest + import isctest +from isctest.util import param from rollover.common import ( pytestmark, alg, @@ -30,7 +33,7 @@ from rollover.common import ( CDSS = ["CDS (SHA-256)"] -POLICY = "ksk-doubleksk-autosign" +POLICY = "ksk-doubleksk" OFFSETS = {} OFFSETS["step1-p"] = -int(TIMEDELTA["P7D"].total_seconds()) OFFSETS["step2-p"] = -int(KSK_LIFETIME.total_seconds() - KSK_IPUBC.total_seconds()) @@ -45,11 +48,22 @@ OFFSETS["step6-p"] = OFFSETS["step5-p"] - int(KSK_CONFIG["purge-keys"].total_sec OFFSETS["step6-s"] = OFFSETS["step5-s"] - int(KSK_CONFIG["purge-keys"].total_seconds()) -def test_ksk_doubleksk_step1(alg, size, ns3): - zone = "step1.ksk-doubleksk.autosign" +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_ksk_doubleksk_step1(tld, alg, size, ns3): + zone = f"step1.ksk-doubleksk.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns3, zone) + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + # Note that the key was already generated during setup. + step = { # Introduce the first key. This will immediately be active. "zone": zone, @@ -63,14 +77,46 @@ def test_ksk_doubleksk_step1(alg, size, ns3): # already passed). "nextev": KSK_LIFETIME - KSK_IPUB - timedelta(days=7), } - isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step) -def test_ksk_doubleksk_step2(alg, size, ns3): - zone = "step2.ksk-doubleksk.autosign" +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_ksk_doubleksk_step2(tld, alg, size, ns3): + zone = f"step2.ksk-doubleksk.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns3, zone) + if tld == "manual": + # Same as step 1. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"zsk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step2-p']}", + f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step2-p']}", + ], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step) + + # Check logs. + tag = keys[1].key.tag + msg = f"keymgr-manual-mode: block KSK rollover for key {zone}/ECDSAP256SHA256/{tag} (policy {policy})" + ns3.log.expect(msg) + + # Force step. + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line(f"keymgr: {zone} done") + step = { # Successor KSK is prepublished (and signs DNSKEY RRset). # KSK1 goal: omnipresent -> hidden @@ -88,14 +134,60 @@ def test_ksk_doubleksk_step2(alg, size, ns3): # Next key event is when the successor KSK becomes OMNIPRESENT. "nextev": KSK_IPUB, } - isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step) -def test_ksk_doubleksk_step3(alg, size, ns3): - zone = "step3.ksk-doubleksk.autosign" +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_ksk_doubleksk_step3(tld, alg, size, ns3): + zone = f"step3.ksk-doubleksk.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns3, zone) + if tld == "manual": + # Same as step 2, but DNSKEY has become OMNIPRESENT. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"zsk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step3-p']}", + f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step3-p']}", + f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:hidden offset:{OFFSETS['step3-s']}", + ], + "keyrelationships": [1, 2], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step) + + # Check logs. + tag = keys[2].key.tag + msg = f"keymgr-manual-mode: block transition KSK {zone}/ECDSAP256SHA256/{tag} type DS state HIDDEN to state RUMOURED" + ns3.log.expect(msg) + + # Force step. + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line(f"keymgr: {zone} done") + + # Check logs. + tag = keys[1].key.tag + msg = f"keymgr-manual-mode: block transition KSK {zone}/ECDSAP256SHA256/{tag} type DS state OMNIPRESENT to state UNRETENTIVE" + if msg in ns3.log: + # Force step. + isctest.log.debug( + f"keymgr-manual-mode blocking transition KSK {zone}/ECDSAP256SHA256/{tag} type DS state OMNIPRESENT to state UNRETENTIVE, step again" + ) + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line(f"keymgr: {zone} done") + step = { # The successor DNSKEY RRset has become omnipresent. The # predecessor DS can be withdrawn and the successor DS can be @@ -118,14 +210,50 @@ def test_ksk_doubleksk_step3(alg, size, ns3): # successor DS. This is the the retire interval. "nextev": KSK_IRET, } - isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step) -def test_ksk_doubleksk_step4(alg, size, ns3): - zone = "step4.ksk-doubleksk.autosign" +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_ksk_doubleksk_step4(tld, alg, size, ns3): + zone = f"step4.ksk-doubleksk.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns3, zone) + if tld == "manual": + # Same as step 3, but DS has become HIDDEN/OMNIPRESENT. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"zsk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step4-p']}", + f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:omnipresent krrsig:omnipresent ds:hidden offset:{OFFSETS['step4-p']}", + f"ksk {KSK_LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step4-s']}", + ], + "keyrelationships": [1, 2], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step) + + # Check logs. + tag = keys[1].key.tag + msg1 = f"keymgr-manual-mode: block transition KSK {zone}/ECDSAP256SHA256/{tag} type DNSKEY state OMNIPRESENT to state UNRETENTIVE" + msg2 = f"keymgr-manual-mode: block transition KSK {zone}/ECDSAP256SHA256/{tag} type KRRSIG state OMNIPRESENT to state UNRETENTIVE" + ns3.log.expect(msg1) + ns3.log.expect(msg2) + + # Force step. + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line(f"keymgr: {zone} done") + step = { # The predecessor DNSKEY may be removed, the successor DS is # omnipresent. @@ -145,14 +273,24 @@ def test_ksk_doubleksk_step4(alg, size, ns3): # This is the DNSKEY TTL plus zone propagation delay. "nextev": KSK_KEYTTLPROP, } - isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step) -def test_ksk_doubleksk_step5(alg, size, ns3): - zone = "step5.ksk-doubleksk.autosign" +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_ksk_doubleksk_step5(tld, alg, size, ns3): + zone = f"step5.ksk-doubleksk.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns3, zone) + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + step = { # The predecessor DNSKEY is long enough removed from the zone it # has become hidden. @@ -170,14 +308,24 @@ def test_ksk_doubleksk_step5(alg, size, ns3): # This is the KSK lifetime minus Ipub minus Iret minus time elapsed. "nextev": KSK_LIFETIME - KSK_IPUB - KSK_IRET - KSK_KEYTTLPROP, } - isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step) -def test_ksk_doubleksk_step6(alg, size, ns3): - zone = "step6.ksk-doubleksk.autosign" +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_ksk_doubleksk_step6(tld, alg, size, ns3): + zone = f"step6.ksk-doubleksk.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns3, zone) + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + step = { # Predecessor KSK is now purged. "zone": zone, @@ -188,4 +336,4 @@ def test_ksk_doubleksk_step6(alg, size, ns3): ], "nextev": None, } - isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns3, KSK_CONFIG, policy, step) From 0aa5dee474f737da1d16e25e55ea0380bbc2af27 Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Thu, 24 Jul 2025 14:12:23 +0200 Subject: [PATCH 11/13] Test manual-mode with ZSK rollover Similar to previous commit. Parametrize each test case and in case of manual-mode, execute additional checks. First a keymgr run should not change the existing key state (with exceptions of timing events such as moving from RUMOURED to OMNIPRESENT, and from UNRETENTIVE to HIDDEN). Appropriate messages must be logged. After enforcing the next step with 'rndc dnssec -step', the key state should be the same as if the step were to be taken automatically. --- .../tests_rollover_zsk_prepublication.py | 181 ++++++++++++++++-- 1 file changed, 162 insertions(+), 19 deletions(-) diff --git a/bin/tests/system/rollover-zsk-prepub/tests_rollover_zsk_prepublication.py b/bin/tests/system/rollover-zsk-prepub/tests_rollover_zsk_prepublication.py index 1966991e24..232be8f7f9 100644 --- a/bin/tests/system/rollover-zsk-prepub/tests_rollover_zsk_prepublication.py +++ b/bin/tests/system/rollover-zsk-prepub/tests_rollover_zsk_prepublication.py @@ -13,8 +13,11 @@ from datetime import timedelta +import pytest + import isctest from isctest.kasp import Ipub, Iret +from isctest.util import param from rollover.common import ( pytestmark, alg, @@ -34,7 +37,7 @@ CONFIG = { "signatures-validity": TIMEDELTA["P14D"], "zone-propagation-delay": TIMEDELTA["PT1H"], } -POLICY = "zsk-prepub-autosign" +POLICY = "zsk-prepub" ZSK_LIFETIME = TIMEDELTA["P30D"] LIFETIME_POLICY = int(ZSK_LIFETIME.total_seconds()) IPUB = Ipub(CONFIG) @@ -54,11 +57,22 @@ OFFSETS["step6-p"] = OFFSETS["step5-p"] - int(CONFIG["purge-keys"].total_seconds OFFSETS["step6-s"] = OFFSETS["step5-s"] - int(CONFIG["purge-keys"].total_seconds()) -def test_zsk_prepub_step1(alg, size, ns3): - zone = "step1.zsk-prepub.autosign" +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_zsk_prepub_step1(tld, alg, size, ns3): + zone = f"step1.zsk-prepub.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns3, zone) + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + # Note that the key was already generated during setup. + step = { # Introduce the first key. This will immediately be active. "zone": zone, @@ -71,14 +85,45 @@ def test_zsk_prepub_step1(alg, size, ns3): # already passed). "nextev": ZSK_LIFETIME - IPUB - timedelta(days=7), } - isctest.kasp.check_rollover_step(ns3, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) -def test_zsk_prepub_step2(alg, size, ns3): - zone = "step2.zsk-prepub.autosign" +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_zsk_prepub_step2(tld, alg, size, ns3): + zone = f"step2.zsk-prepub.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns3, zone) + if tld == "manual": + # Same as step 1. + step = { + "zone": zone, + "keyprops": [ + f"ksk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step2-p']}", + f"zsk {LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step2-p']}", + ], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + # Check logs. + tag = keys[1].key.tag + msg = f"keymgr-manual-mode: block ZSK rollover for key {zone}/ECDSAP256SHA256/{tag} (policy {policy})" + ns3.log.expect(msg) + + # Force step. + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line(f"keymgr: {zone} done") + step = { # it is time to pre-publish the successor zsk. # zsk1 goal: omnipresent -> hidden @@ -95,14 +140,59 @@ def test_zsk_prepub_step2(alg, size, ns3): # that is the dnskey ttl plus the zone propagation delay "nextev": IPUB, } - isctest.kasp.check_rollover_step(ns3, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) -def test_zsk_prepub_step3(alg, size, ns3): - zone = "step3.zsk-prepub.autosign" +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_zsk_prepub_step3(tld, alg, size, ns3): + zone = f"step3.zsk-prepub.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns3, zone) + if tld == "manual": + # Same as step 2, but DNSKEY has become OMNIPRESENT. + step = { + "zone": zone, + "keyprops": [ + f"ksk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step3-p']}", + f"zsk {LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step3-p']}", + f"zsk {LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:hidden offset:{OFFSETS['step3-s']}", + ], + "keyrelationships": [1, 2], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + # Check logs. + tag = keys[2].key.tag + msg = f"keymgr-manual-mode: block transition ZSK {zone}/ECDSAP256SHA256/{tag} type ZRRSIG state HIDDEN to state RUMOURED" + ns3.log.expect(msg) + + # Force step. + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line(f"keymgr: {zone} done") + + # Check logs. + tag = keys[1].key.tag + msg = f"keymgr-manual-mode: block transition ZSK {zone}/ECDSAP256SHA256/{tag} type ZRRSIG state OMNIPRESENT to state UNRETENTIVE" + if msg in ns3.log: + # Force step. + isctest.log.debug( + f"keymgr-manual-mode blocking transition ZSK {zone}/ECDSAP256SHA256/{tag} type ZRRSIG state OMNIPRESENT to state UNRETENTIVE, step again" + ) + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line(f"keymgr: {zone} done") + step = { # predecessor zsk is no longer actively signing. successor zsk is # now actively signing. @@ -124,14 +214,47 @@ def test_zsk_prepub_step3(alg, size, ns3): # from the predecessor zsk. "smooth": True, } - isctest.kasp.check_rollover_step(ns3, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) -def test_zsk_prepub_step4(alg, size, ns3): - zone = "step4.zsk-prepub.autosign" +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_zsk_prepub_step4(tld, alg, size, ns3): + zone = f"step4.zsk-prepub.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns3, zone) + if tld == "manual": + # Same as step 3, but zone signatures have become HIDDEN/OMNIPRESENT. + step = { + "zone": zone, + "keyprops": [ + f"ksk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent offset:{OFFSETS['step4-p']}", + f"zsk {LIFETIME_POLICY} {alg} {size} goal:hidden dnskey:omnipresent zrrsig:hidden offset:{OFFSETS['step4-p']}", + f"zsk {LIFETIME_POLICY} {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent offset:{OFFSETS['step4-s']}", + ], + "keyrelationships": [1, 2], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + # Check logs. + tag = keys[1].key.tag + msg = f"keymgr-manual-mode: block transition ZSK {zone}/ECDSAP256SHA256/{tag} type DNSKEY state OMNIPRESENT to state UNRETENTIVE" + ns3.log.expect(msg) + + # Force step. + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line(f"keymgr: {zone} done") + step = { # predecessor zsk is no longer needed. all rrsets are signed with # the successor zsk. @@ -149,14 +272,24 @@ def test_zsk_prepub_step4(alg, size, ns3): # this is the dnskey ttl plus zone propagation delay. "nextev": KEYTTLPROP, } - isctest.kasp.check_rollover_step(ns3, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) -def test_zsk_prepub_step5(alg, size, ns3): - zone = "step5.zsk-prepub.autosign" +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_zsk_prepub_step5(tld, alg, size, ns3): + zone = f"step5.zsk-prepub.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns3, zone) + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + step = { # predecessor zsk is now removed. # zsk1 dnskey: unretentive -> hidden @@ -172,14 +305,24 @@ def test_zsk_prepub_step5(alg, size, ns3): # elapsed. "nextev": ZSK_LIFETIME - IRET - IPUB - KEYTTLPROP, } - isctest.kasp.check_rollover_step(ns3, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) -def test_zsk_prepub_step6(alg, size, ns3): - zone = "step6.zsk-prepub.autosign" +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_zsk_prepub_step6(tld, alg, size, ns3): + zone = f"step6.zsk-prepub.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns3, zone) + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + step = { # predecessor zsk is now purged. "zone": zone, @@ -189,4 +332,4 @@ def test_zsk_prepub_step6(alg, size, ns3): ], "nextev": None, } - isctest.kasp.check_rollover_step(ns3, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) From 1df76e2c24e397ea5ce6d186a104150a39c5c29d Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Thu, 24 Jul 2025 14:57:35 +0200 Subject: [PATCH 12/13] Test manual-mode while enabling DNSSEC Similar to previous commit. Parametrize each test case and in case of manual-mode, execute additional checks. First a keymgr run should not change the existing key state (with exceptions of timing events such as moving from RUMOURED to OMNIPRESENT, and from UNRETENTIVE to HIDDEN). Appropriate messages must be logged. After enforcing the next step with 'rndc dnssec -step', the key state should be the same as if the step were to be taken automatically. --- .../tests_rollover_enable_dnssec.py | 107 ++++++++++++++++-- 1 file changed, 95 insertions(+), 12 deletions(-) diff --git a/bin/tests/system/rollover-enable-dnssec/tests_rollover_enable_dnssec.py b/bin/tests/system/rollover-enable-dnssec/tests_rollover_enable_dnssec.py index 9c4dd31b85..2cb805a674 100644 --- a/bin/tests/system/rollover-enable-dnssec/tests_rollover_enable_dnssec.py +++ b/bin/tests/system/rollover-enable-dnssec/tests_rollover_enable_dnssec.py @@ -11,8 +11,11 @@ # pylint: disable=redefined-outer-name,unused-import +import pytest + import isctest from isctest.kasp import Ipub, IpubC, Iret +from isctest.util import param from rollover.common import ( pytestmark, alg, @@ -44,11 +47,40 @@ OFFSETS["step3"] = -int(IRETZSK.total_seconds()) OFFSETS["step4"] = -int(IPUBC.total_seconds() + IRETKSK.total_seconds()) -def test_rollover_enable_dnssec_step1(alg, size, ns3): - zone = "step1.enable-dnssec.autosign" +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_rollover_enable_dnssec_step1(tld, alg, size, ns3): + zone = f"step1.enable-dnssec.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns3, zone) + if tld == "manual": + # Same as insecure. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [], + "manual-mode": True, + "zone-signed": False, + "nextev": None, + } + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + # Check logs. + msg = f"keymgr-manual-mode: block new key generation for zone {zone} (policy {policy})" + ns3.log.expect(msg) + + # Force step. + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line(f"keymgr: {zone} done") + step = { "zone": zone, "cdss": CDSS, @@ -59,14 +91,24 @@ def test_rollover_enable_dnssec_step1(alg, size, ns3): # after the publication interval. "nextev": IPUB, } - isctest.kasp.check_rollover_step(ns3, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) -def test_rollover_enable_dnssec_step2(alg, size, ns3): - zone = "step2.enable-dnssec.autosign" +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_rollover_enable_dnssec_step2(tld, alg, size, ns3): + zone = f"step2.enable-dnssec.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns3, zone) + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + step = { "zone": zone, "cdss": CDSS, @@ -81,14 +123,45 @@ def test_rollover_enable_dnssec_step2(alg, size, ns3): # Minus the time already elapsed. "nextev": IRETZSK - IPUB, } - isctest.kasp.check_rollover_step(ns3, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) -def test_rollover_enable_dnssec_step3(alg, size, ns3): - zone = "step3.enable-dnssec.autosign" +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_rollover_enable_dnssec_step3(tld, alg, size, ns3): + zone = f"step3.enable-dnssec.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns3, zone) + if tld == "manual": + # Same as step 2, but zone signatures have become OMNIPRESENT. + step = { + "zone": zone, + "cdss": CDSS, + "keyprops": [ + f"csk unlimited {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent zrrsig:omnipresent ds:hidden offset:{OFFSETS['step3']}", + ], + "manual-mode": True, + "nextev": None, + } + keys = isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) + + # Check logs. + tag = keys[0].key.tag + msg = f"keymgr-manual-mode: block transition CSK {zone}/ECDSAP256SHA256/{tag} type DS state HIDDEN to state RUMOURED" + ns3.log.expect(msg) + + # Force step. + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}") + watcher.wait_for_line(f"keymgr: {zone} done") + step = { "zone": zone, "cdss": CDSS, @@ -102,14 +175,24 @@ def test_rollover_enable_dnssec_step3(alg, size, ns3): # This is after the retire interval. "nextev": IRETKSK, } - isctest.kasp.check_rollover_step(ns3, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) -def test_rollover_enable_dnssec_step4(alg, size, ns3): - zone = "step4.enable-dnssec.autosign" +@pytest.mark.parametrize( + "tld", + [ + param("autosign"), + param("manual"), + ], +) +def test_rollover_enable_dnssec_step4(tld, alg, size, ns3): + zone = f"step4.enable-dnssec.{tld}" + policy = f"{POLICY}-{tld}" isctest.kasp.wait_keymgr_done(ns3, zone) + # manual-mode: Nothing changing in the zone, no 'dnssec -step' required. + step = { "zone": zone, "cdss": CDSS, @@ -122,4 +205,4 @@ def test_rollover_enable_dnssec_step4(alg, size, ns3): # established. So we fall back to the default loadkeys interval. "nextev": TIMEDELTA["PT1H"], } - isctest.kasp.check_rollover_step(ns3, CONFIG, POLICY, step) + isctest.kasp.check_rollover_step(ns3, CONFIG, policy, step) From e4529b630817d1e4a5c4d3b56b0c604f8351d1e3 Mon Sep 17 00:00:00 2001 From: Matthijs Mekking Date: Wed, 20 Aug 2025 15:41:13 +0200 Subject: [PATCH 13/13] Test manual-mode error case If we hit an error when issuing an 'rndc dnssec -step' command, and the keymgr runs again at a later scheduled time, we don't want to enforce transitions. --- bin/tests/system/kasp/ns3/named-fips.conf.in | 9 ++ .../system/kasp/ns3/policies/autosign.conf.in | 16 +++ bin/tests/system/kasp/ns3/setup.sh | 13 +++ bin/tests/system/kasp/tests_kasp.py | 110 +++++++++++++++++- 4 files changed, 146 insertions(+), 2 deletions(-) diff --git a/bin/tests/system/kasp/ns3/named-fips.conf.in b/bin/tests/system/kasp/ns3/named-fips.conf.in index 109f3ad811..665b37821e 100644 --- a/bin/tests/system/kasp/ns3/named-fips.conf.in +++ b/bin/tests/system/kasp/ns3/named-fips.conf.in @@ -286,6 +286,15 @@ zone "keyfiles-missing.autosign" { dnssec-policy "autosign"; }; +/* + * Zone that has missing key files, manual-mode. + */ +zone "keyfiles-missing.manual" { + type primary; + file "keyfiles-missing.manual.db"; + dnssec-policy "manual"; +}; + /* * Zone that has missing private KSK. */ diff --git a/bin/tests/system/kasp/ns3/policies/autosign.conf.in b/bin/tests/system/kasp/ns3/policies/autosign.conf.in index c54786247f..9ccc4e62b9 100644 --- a/bin/tests/system/kasp/ns3/policies/autosign.conf.in +++ b/bin/tests/system/kasp/ns3/policies/autosign.conf.in @@ -24,3 +24,19 @@ dnssec-policy "autosign" { zsk key-directory lifetime P1Y algorithm @DEFAULT_ALGORITHM@; }; }; + +dnssec-policy "manual" { + + signatures-refresh P1W; + signatures-validity P2W; + signatures-validity-dnskey P2W; + + dnskey-ttl 300; + + keys { + ksk key-directory lifetime P2Y algorithm @DEFAULT_ALGORITHM@; + zsk key-directory lifetime P2M algorithm @DEFAULT_ALGORITHM@; + }; + + manual-mode yes; +}; diff --git a/bin/tests/system/kasp/ns3/setup.sh b/bin/tests/system/kasp/ns3/setup.sh index 4e521aa769..756c0af19c 100644 --- a/bin/tests/system/kasp/ns3/setup.sh +++ b/bin/tests/system/kasp/ns3/setup.sh @@ -261,6 +261,19 @@ private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >>"$infile" cp $infile $zonefile $SIGNER -S -x -s now-1w -e now+1w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 +# These signatures are still good, but the key files will be removed +# before a second run of reconfiguring keys, now in manual-mode. +setup keyfiles-missing.manual +KSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 -f KSK $keytimes $zone 2>keygen.out.$zone.1) +ZSK=$($KEYGEN -a $DEFAULT_ALGORITHM -L 300 $keytimes $zone 2>keygen.out.$zone.2) +$SETTIME -s -g $O -d $O $T -k $O $T -r $O $T "$KSK" >settime.out.$zone.1 2>&1 +$SETTIME -s -g $O -k $O $T -z $O $T "$ZSK" >settime.out.$zone.2 2>&1 +cat template.db.in "${KSK}.key" "${ZSK}.key" >"$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$KSK" >>"$infile" +private_type_record $zone $DEFAULT_ALGORITHM_NUMBER "$ZSK" >>"$infile" +cp $infile $zonefile +$SIGNER -S -x -s now-1w -e now+1w -o $zone -O raw -f "${zonefile}.signed" $infile >signer.out.$zone.1 2>&1 + # These signatures are already expired, and the private ZSK is retired. setup zsk-retired.autosign zsktimes="$keytimes -I now" diff --git a/bin/tests/system/kasp/tests_kasp.py b/bin/tests/system/kasp/tests_kasp.py index f43f0dea6f..4e91565a78 100644 --- a/bin/tests/system/kasp/tests_kasp.py +++ b/bin/tests/system/kasp/tests_kasp.py @@ -118,6 +118,7 @@ lifetime = { "P1Y": int(timedelta(days=365).total_seconds()), "P30D": int(timedelta(days=30).total_seconds()), "P6M": int(timedelta(days=31 * 6).total_seconds()), + "P2M": int(timedelta(days=31 * 2).total_seconds()), } KASP_INHERIT_TSIG_SECRET = { @@ -157,10 +158,18 @@ def fips_properties(alg, bits=None): ] -def check_all(server, zone, policy, ksks, zsks, zsk_missing=False, tsig=None): +def check_all( + server, zone, policy, ksks, zsks, manual_mode=False, zsk_missing=False, tsig=None +): isctest.kasp.check_dnssecstatus(server, zone, ksks + zsks, policy=policy) isctest.kasp.check_apex( - server, zone, ksks, zsks, zsk_missing=zsk_missing, tsig=tsig + server, + zone, + ksks, + zsks, + manual_mode=manual_mode, + zsk_missing=zsk_missing, + tsig=tsig, ) isctest.kasp.check_subdomain(server, zone, ksks, zsks, tsig=tsig) @@ -1662,3 +1671,100 @@ def test_kasp_reload_restart(ns6): newttl = 400 isctest.run.retry_with_timeout(check_soa_ttl, timeout=10) + + +def test_kasp_manual_mode(ns3): + + keydir = ns3.identifier + zone = "keyfiles-missing.manual" + policy = "manual" + ttl = int(autosign_config["dnskey-ttl"].total_seconds()) + offset = -timedelta(days=30 * 6) + alg = os.environ["DEFAULT_ALGORITHM_NUMBER"] + size = os.environ["DEFAULT_BITS"] + keyprops = [ + f"ksk {lifetime['P2Y']} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent", + f"zsk {lifetime['P2M']} {alg} {size} goal:omnipresent dnskey:omnipresent zrrsig:omnipresent", + ] + + isctest.kasp.wait_keymgr_done(ns3, zone) + + isctest.log.info(f"check test case zone {zone} policy {policy}") + + # First make sure the zone is signed. + isctest.kasp.check_dnssec_verify(ns3, zone) + + # Key properties. + expected = isctest.kasp.policy_to_properties(ttl=ttl, keys=keyprops) + + # Key files. + keys = isctest.kasp.keydir_to_keylist(zone, keydir) + ksks = [k for k in keys if k.is_ksk()] + zsks = [k for k in keys if not k.is_ksk()] + isctest.kasp.check_dnssec_verify(ns3, zone) + isctest.kasp.check_keys(zone, keys, expected) + + for kp in expected: + kp.set_expected_keytimes(autosign_config, offset=offset) + + isctest.kasp.check_keytimes(keys, expected) + + check_all(ns3, zone, policy, ksks, zsks, manual_mode=True) + + # Key rollover should have been be blocked. + tag = expected[1].key.tag + blockmsg = f"keymgr-manual-mode: block ZSK rollover for key {zone}/ECDSAP256SHA256/{tag} (policy {policy})" + ns3.log.expect(blockmsg) + + # Remove files. + for key in ksks + zsks: + shutil.copyfile(key.privatefile, f"{key.privatefile}.backup") + shutil.copyfile(key.keyfile, f"{key.keyfile}.backup") + shutil.copyfile(key.statefile, f"{key.statefile}.backup") + + os.remove(key.keyfile) + os.remove(key.privatefile) + os.remove(key.statefile) + + # Force step. + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}", log=False) + watcher.wait_for_line( + f"zone {zone}/IN (signed): zone_rekey:zone_verifykeys failed: some key files are missing" + ) + + # Restore key files. + for key in ksks + zsks: + shutil.copyfile(f"{key.privatefile}.backup", key.privatefile) + shutil.copyfile(f"{key.keyfile}.backup", key.keyfile) + shutil.copyfile(f"{key.statefile}.backup", key.statefile) + + # Load keys. + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"loadkeys {zone}", log=False) + watcher.wait_for_line(blockmsg) + + # Check keys again, make sure no new keys are created. + isctest.kasp.check_keys(zone, keys, expected) + isctest.kasp.check_keytimes(keys, expected) + check_all(ns3, zone, policy, ksks, zsks, manual_mode=True) + isctest.kasp.check_dnssec_verify(ns3, zone) + + # Force step. + with ns3.watch_log_from_here() as watcher: + ns3.rndc(f"dnssec -step {zone}", log=False) + watcher.wait_for_line(f"keymgr: {zone} done") + + # Check keys again, make sure the rollover has started. + keyprops = [ + f"ksk {lifetime['P2Y']} {alg} {size} goal:omnipresent dnskey:omnipresent krrsig:omnipresent ds:omnipresent", + f"zsk {lifetime['P2M']} {alg} {size} goal:hidden dnskey:omnipresent zrrsig:omnipresent", + f"zsk {lifetime['P2M']} {alg} {size} goal:omnipresent dnskey:rumoured zrrsig:hidden", + ] + expected = isctest.kasp.policy_to_properties(ttl=ttl, keys=keyprops) + keys = isctest.kasp.keydir_to_keylist(zone, keydir) + ksks = [k for k in keys if k.is_ksk()] + zsks = [k for k in keys if not k.is_ksk()] + isctest.kasp.check_keys(zone, keys, expected) + check_all(ns3, zone, policy, ksks, zsks, manual_mode=True) + isctest.kasp.check_dnssec_verify(ns3, zone)