return (result);
}
+
+isc_result_t
+dns_keymgr_offline(const dns_name_t *origin, dns_dnsseckeylist_t *keyring,
+ dns_kasp_t *kasp, isc_stdtime_t now,
+ isc_stdtime_t *nexttime) {
+ isc_result_t result = ISC_R_SUCCESS;
+ int options = (DST_TYPE_PRIVATE | DST_TYPE_PUBLIC | DST_TYPE_STATE);
+ char keystr[DST_KEY_FORMATSIZE];
+
+ *nexttime = 0;
+
+ /* Store key states and update hints. */
+ for (dns_dnsseckey_t *dkey = ISC_LIST_HEAD(*keyring); dkey != NULL;
+ dkey = ISC_LIST_NEXT(dkey, link))
+ {
+ bool modified;
+ bool ksk = false, zsk = false;
+ isc_stdtime_t active = 0, published = 0, inactive = 0,
+ remove = 0;
+ isc_stdtime_t lastchange = 0, nextchange = 0;
+ dst_key_state_t dnskey_state = HIDDEN, zrrsig_state = HIDDEN,
+ goal_state = HIDDEN;
+ dst_key_state_t current_dnskey, current_zrrsig, current_goal;
+
+ (void)dst_key_role(dkey->key, &ksk, &zsk);
+ if (ksk || !zsk) {
+ continue;
+ }
+
+ keymgr_key_init(dkey, kasp, now, false);
+
+ /* Get current metadata */
+ RETERR(dst_key_getstate(dkey->key, DST_KEY_DNSKEY,
+ ¤t_dnskey));
+ RETERR(dst_key_getstate(dkey->key, DST_KEY_ZRRSIG,
+ ¤t_zrrsig));
+ RETERR(dst_key_getstate(dkey->key, DST_KEY_GOAL,
+ ¤t_goal));
+ RETERR(dst_key_gettime(dkey->key, DST_TIME_PUBLISH,
+ &published));
+ RETERR(dst_key_gettime(dkey->key, DST_TIME_ACTIVATE, &active));
+ RETERR(dst_key_gettime(dkey->key, DST_TIME_INACTIVE,
+ &inactive));
+ RETERR(dst_key_gettime(dkey->key, DST_TIME_DELETE, &remove));
+
+ /* Determine key states from the metadata. */
+ if (active <= now) {
+ dns_ttl_t ttlsig = dns_kasp_zonemaxttl(kasp, true);
+ ttlsig += dns_kasp_zonepropagationdelay(kasp);
+ if ((active + ttlsig) <= now) {
+ zrrsig_state = OMNIPRESENT;
+ } else {
+ zrrsig_state = RUMOURED;
+ (void)dst_key_gettime(dkey->key,
+ DST_TIME_ZRRSIG,
+ &lastchange);
+ nextchange = lastchange + ttlsig +
+ dns_kasp_retiresafety(kasp);
+ }
+ goal_state = OMNIPRESENT;
+ }
+
+ if (published <= now) {
+ dns_ttl_t key_ttl = dst_key_getttl(dkey->key);
+ key_ttl += dns_kasp_zonepropagationdelay(kasp);
+ if ((published + key_ttl) <= now) {
+ dnskey_state = OMNIPRESENT;
+ } else {
+ dnskey_state = RUMOURED;
+ (void)dst_key_gettime(dkey->key,
+ DST_TIME_DNSKEY,
+ &lastchange);
+ nextchange = lastchange + key_ttl +
+ dns_kasp_publishsafety(kasp);
+ }
+ goal_state = OMNIPRESENT;
+ }
+
+ if (inactive <= now) {
+ dns_ttl_t ttlsig = dns_kasp_zonemaxttl(kasp, true);
+ ttlsig += dns_kasp_zonepropagationdelay(kasp);
+ if ((inactive + ttlsig) <= now) {
+ zrrsig_state = HIDDEN;
+ } else {
+ zrrsig_state = UNRETENTIVE;
+ (void)dst_key_gettime(dkey->key,
+ DST_TIME_ZRRSIG,
+ &lastchange);
+ nextchange = lastchange + ttlsig +
+ dns_kasp_retiresafety(kasp);
+ }
+ goal_state = HIDDEN;
+ }
+
+ if (remove <= now) {
+ dns_ttl_t key_ttl = dst_key_getttl(dkey->key);
+ key_ttl += dns_kasp_zonepropagationdelay(kasp);
+ if ((remove + key_ttl) <= now) {
+ dnskey_state = HIDDEN;
+ } else {
+ dnskey_state = UNRETENTIVE;
+ (void)dst_key_gettime(dkey->key,
+ DST_TIME_DNSKEY,
+ &lastchange);
+ nextchange =
+ lastchange + key_ttl +
+ dns_kasp_zonepropagationdelay(kasp);
+ }
+ zrrsig_state = HIDDEN;
+ goal_state = HIDDEN;
+ }
+
+ if ((*nexttime == 0 || *nexttime > nextchange) &&
+ nextchange > 0)
+ {
+ *nexttime = nextchange;
+ }
+
+ /* Update key states if necessary. */
+ if (goal_state != current_goal) {
+ dst_key_setstate(dkey->key, DST_KEY_GOAL, goal_state);
+ }
+ if (dnskey_state != current_dnskey) {
+ dst_key_setstate(dkey->key, DST_KEY_DNSKEY,
+ dnskey_state);
+ dst_key_settime(dkey->key, DST_TIME_DNSKEY, now);
+ }
+ if (zrrsig_state != current_zrrsig) {
+ dst_key_setstate(dkey->key, DST_KEY_ZRRSIG,
+ zrrsig_state);
+ dst_key_settime(dkey->key, DST_TIME_ZRRSIG, now);
+ if (zrrsig_state == RUMOURED) {
+ dkey->first_sign = true;
+ }
+ }
+ modified = dst_key_ismodified(dkey->key);
+
+ if (modified) {
+ const char *directory = dst_key_directory(dkey->key);
+ if (directory == NULL) {
+ directory = ".";
+ }
+
+ dns_dnssec_get_hints(dkey, now);
+
+ RETERR(dst_key_tofile(dkey->key, options, directory));
+ dst_key_setmodified(dkey->key, false);
+
+ if (!isc_log_wouldlog(ISC_LOG_DEBUG(3))) {
+ continue;
+ }
+ dst_key_format(dkey->key, keystr, sizeof(keystr));
+ isc_log_write(DNS_LOGCATEGORY_DNSSEC,
+ DNS_LOGMODULE_DNSSEC, ISC_LOG_DEBUG(3),
+ "keymgr: DNSKEY %s (%s) "
+ "saved to directory %s, policy %s",
+ keystr, keymgr_keyrole(dkey->key),
+ directory, dns_kasp_getname(kasp));
+ }
+ dst_key_setmodified(dkey->key, false);
+ }
+
+ result = ISC_R_SUCCESS;
+
+failure:
+ if (isc_log_wouldlog(ISC_LOG_DEBUG(3))) {
+ char namebuf[DNS_NAME_FORMATSIZE];
+ dns_name_format(origin, namebuf, sizeof(namebuf));
+ isc_log_write(DNS_LOGCATEGORY_DNSSEC, DNS_LOGMODULE_DNSSEC,
+ ISC_LOG_DEBUG(3), "keymgr: %s (offline-ksk) done",
+ namebuf);
+ }
+ return (result);
+}
isc_result_totext(result));
}
- if (kasp != NULL) {
+ if (kasp != NULL && !offlineksk) {
/*
* Check DS at parental agents. Clear ongoing checks.
*/
goto failure;
}
}
+ } else if (offlineksk) {
+ /*
+ * With offline-ksk enabled we don't run the keymgr.
+ * Instead we derive the states from the timing metadata.
+ */
+ dns_zone_lock_keyfiles(zone);
+ result = dns_keymgr_offline(&zone->origin, &keys, kasp, now,
+ &nexttime);
+ dns_zone_unlock_keyfiles(zone);
}
KASP_UNLOCK(kasp);
bool sane_diff, sane_dnskey;
isc_stdtime_t when;
+ result = dns_dnssec_updatekeys(&dnskeys, &keys, &rmkeys,
+ &zone->origin, ttl, &diff, mctx,
+ dnssec_report);
+ /*
+ * Keys couldn't be updated for some reason;
+ * try again later.
+ */
+ if (result != ISC_R_SUCCESS) {
+ dnssec_log(zone, ISC_LOG_ERROR,
+ "zone_rekey:couldn't update zone keys: %s",
+ isc_result_totext(result));
+ goto failure;
+ }
+
+ if (offlineksk) {
+ /* We can skip a lot of things */
+ goto post_sync;
+ }
+
/*
* Publish CDS/CDNSKEY DELETE records if the zone is
* transitioning from secure to insecure.
digests = dns_kasp_digests(zone->defaultkasp);
}
- result = dns_dnssec_updatekeys(&dnskeys, &keys, &rmkeys,
- &zone->origin, ttl, &diff, mctx,
- dnssec_report);
- /*
- * Keys couldn't be updated for some reason;
- * try again later.
- */
- if (result != ISC_R_SUCCESS) {
- dnssec_log(zone, ISC_LOG_ERROR,
- "zone_rekey:couldn't update zone keys: %s",
- isc_result_totext(result));
- goto failure;
- }
-
/*
* Update CDS / CDNSKEY records.
*/
goto failure;
}
+ post_sync:
/*
* See if any pre-existing keys have newly become active;
* also, see if any new key is for a new algorithm, as in that