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;