]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Update key states in offline-ksk mode
authorMatthijs Mekking <matthijs@isc.org>
Wed, 19 Jun 2024 11:41:07 +0000 (13:41 +0200)
committerMatthijs Mekking <matthijs@isc.org>
Thu, 22 Aug 2024 06:21:52 +0000 (08:21 +0200)
With offline-ksk enabled, we don't run the keymgr because the key
timings are determined by the SKR. We do update the key states but
we derive them from the timing metadata.

Then, we can skip a other tasks in offline-ksk mode, like DS checking
at the parent and CDS synchronization, because the CDS and CDNSKEY
RRsets also come from the SKR.

lib/dns/include/dns/keymgr.h
lib/dns/keymgr.c
lib/dns/zone.c

index eadb0ea877b551d67954b061a21f5d1ff3734442..61cf3df7aa712a06b06eb87a75b0c7c161d66f03 100644 (file)
@@ -52,6 +52,29 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
  *\li          On error, keypool is unchanged
  */
 
+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);
+/*%<
+ * Manage keys in 'keyring' when in offline-ksk mode, and update timing data
+ * according to the metadata in the key files. KSKs are skipped.
+ *
+ * Update key states and store changes back to disk. Store when to run next
+ * in 'nexttime'.
+ *
+ *     Requires:
+ *\li          'origin' is a valid FQDN.
+ *\li          'mctx' is a valid memory context.
+ *\li          'keyring' is not NULL.
+ *\li          'kasp' is not NULL.
+ *
+ *     Returns:
+ *\li          #ISC_R_SUCCESS
+ *\li          any error returned by dst_key_getstate(), dst_key_gettime(),
+ *             isc_dir_open(), or dst_key_to_file().
+ */
+
 isc_result_t
 dns_keymgr_checkds(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring,
                   isc_stdtime_t now, isc_stdtime_t when, bool dspublish);
index 35e3a835658543e89adcb4218d211c1dd56618da..9e0f808dd8d27f211f10ea7e07a54a529b1acf06 100644 (file)
@@ -2661,3 +2661,177 @@ dns_keymgr_rollover(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring,
 
        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,
+                                       &current_dnskey));
+               RETERR(dst_key_getstate(dkey->key, DST_KEY_ZRRSIG,
+                                       &current_zrrsig));
+               RETERR(dst_key_getstate(dkey->key, DST_KEY_GOAL,
+                                       &current_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);
+}
index 33c2dca11220fe1eeb9eecdd60e366d4a5b52a64..e64a96869b3f54ed779d342bfa839f38528b2412 100644 (file)
@@ -22177,7 +22177,7 @@ zone_rekey(dns_zone_t *zone) {
                           isc_result_totext(result));
        }
 
-       if (kasp != NULL) {
+       if (kasp != NULL && !offlineksk) {
                /*
                 * Check DS at parental agents. Clear ongoing checks.
                 */
@@ -22217,6 +22217,15 @@ zone_rekey(dns_zone_t *zone) {
                                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);
@@ -22235,6 +22244,25 @@ zone_rekey(dns_zone_t *zone) {
                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.
@@ -22300,20 +22328,6 @@ zone_rekey(dns_zone_t *zone) {
                        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.
                 */
@@ -22366,6 +22380,7 @@ zone_rekey(dns_zone_t *zone) {
                        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