]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Add offline-ksk option
authorMatthijs Mekking <matthijs@isc.org>
Fri, 22 Mar 2024 10:48:53 +0000 (11:48 +0100)
committerMatthijs Mekking <matthijs@isc.org>
Thu, 22 Aug 2024 06:21:52 +0000 (08:21 +0200)
Add a new configuration option to enable Offline KSK key management.

Offline KSK cannot work with CSK because it splits how keys with the
KSK and ZSK role operate. Therefore, one key cannot have both roles.
Add a configuration check to ensure this.

bin/named/config.c
bin/tests/system/checkconf/good-kasp.conf
bin/tests/system/checkconf/kasp-bad-offline-ksk.conf [new file with mode: 0644]
bin/tests/system/checkconf/tests.sh
doc/arm/reference.rst
doc/misc/dnssec-policy.default.conf
doc/misc/options
lib/dns/include/dns/kasp.h
lib/dns/kasp.c
lib/isccfg/kaspconf.c
lib/isccfg/namedconf.c

index ed3228723deeac8af562932706dbf7592ddc68b6..59f8902156e72f9b988e39e9712a67a7db67643f 100644 (file)
@@ -299,6 +299,7 @@ dnssec-policy \"default\" {\n\
        cds-digest-types { 2; };\n\
        dnskey-ttl " DNS_KASP_KEY_TTL ";\n\
        inline-signing yes;\n\
+       offline-ksk no;\n\
        publish-safety " DNS_KASP_PUBLISH_SAFETY "; \n\
        retire-safety " DNS_KASP_RETIRE_SAFETY "; \n\
        purge-keys " DNS_KASP_PURGE_KEYS "; \n\
index 42e2478f96e6e89d1df0d18af859e5c352466f34..e0a3241368e52dbf57c150e7059747719f9df1cf 100644 (file)
@@ -30,6 +30,7 @@ dnssec-policy "test" {
        };
        max-zone-ttl 86400;
        nsec3param iterations 0 optout no salt-length 8;
+       offline-ksk no;
        parent-ds-ttl 7200;
        parent-propagation-delay PT1H;
        publish-safety PT3600S;
diff --git a/bin/tests/system/checkconf/kasp-bad-offline-ksk.conf b/bin/tests/system/checkconf/kasp-bad-offline-ksk.conf
new file mode 100644 (file)
index 0000000..4a44d92
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * SPDX-License-Identifier: MPL-2.0
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0.  If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*
+ * Offline KSK is not possible with CSK
+ * (even if there are other key roles present).
+ */
+dnssec-policy "bad-offline-ksk" {
+       offline-ksk yes;
+       keys {
+               ksk lifetime P10Y algorithm rsasha256;
+               zsk lifetime P10Y algorithm rsasha256;
+               csk lifetime P10Y algorithm rsasha256;
+       };
+};
+
+zone "example.net" {
+       type primary;
+       file "example.db";
+       dnssec-policy "bad-offline-ksk";
+};
index 474507156d7a64379939685959a19917b3cd5df2..112c97e86a15e81c6ced8258923223de64b84279 100644 (file)
@@ -676,6 +676,14 @@ grep "dnssec-policy: key with algorithm rsasha256 has invalid key length 511" <c
 if [ $ret -ne 0 ]; then echo_i "failed"; fi
 status=$((status + ret))
 
+n=$((n + 1))
+echo_i "checking named-checkconf kasp offline-ksk with csk errors ($n)"
+ret=0
+$CHECKCONF kasp-bad-offline-ksk.conf >checkconf.out$n 2>&1 && ret=1
+grep "dnssec-policy: csk keys are not allowed when offline-ksk is enabled" <checkconf.out$n >/dev/null || ret=1
+if [ $ret -ne 0 ]; then echo_i "failed"; fi
+status=$((status + ret))
+
 n=$((n + 1))
 echo_i "checking named-checkconf kasp signatures refresh errors ($n)"
 ret=0
index 0a3075edc2fb25fec81a9850edddff95f7a6cee8..f427f6b02fbb77af68e646cf801aa7b5adebca55 100644 (file)
@@ -6536,6 +6536,20 @@ The following options can be specified in a :any:`dnssec-policy` statement:
    ``insecure``. In this specific case you should move the existing key files
    to the zone's ``key-directory`` from the new configuration.
 
+.. namedconf:statement:: offline-ksk
+   :tags: dnssec
+   :short: Specifies whether the DNSKEY, CDS, and CDNSKEY RRsets are being signed offline.
+
+    If enabled, BIND 9 does not generate signatures for the DNSKEY, CDS, and
+    CDNSKEY RRsets. Instead, the signed DNSKEY, CDS and CDNSKEY RRsets are
+    looked up from Signed Key Response (SKR) files.
+
+    Any existing DNSKEY, CDS, and CDNSKEY RRsets in the unsigned version of the
+    zone are filtered and replaced with RRsets from the SKR file.
+
+    This feature is off by default. Configuring ``offline-ksk`` in conjunction
+    with a CSK is a configuration error.
+
 .. namedconf:statement:: purge-keys
    :tags: dnssec
    :short: Specifies the amount of time after which DNSSEC keys that have been deleted from the zone can be removed from disk.
index a6f526c743db7a290fc49f039e5871ed5aa31440..d5571bac0410c7e38b723fdb6a032a7cb1cd88f9 100644 (file)
@@ -13,6 +13,7 @@
 
 dnssec-policy "default" {
        // Keys
+       offline-ksk no;
        keys {
                csk key-directory lifetime unlimited algorithm 13;
        };
index ff3c95ddf6ac1cf4c044e90bb17b4a8ca73943e5..0785c4d7bf18172c6106aacbac8464f22b086e67 100644 (file)
@@ -18,6 +18,7 @@ dnssec-policy <string> {
        keys { ( csk | ksk | zsk ) [ key-directory | key-store <string> ] lifetime <duration_or_unlimited> algorithm <string> [ <integer> ]; ... };
        max-zone-ttl <duration>;
        nsec3param [ iterations <integer> ] [ optout <boolean> ] [ salt-length <integer> ];
+       offline-ksk <boolean>;
        parent-ds-ttl <duration>;
        parent-propagation-delay <duration>;
        publish-safety <duration>;
index d0187f80453272c5e3ac054e35b67980ad1dd9fa..26af4695465af2bd531d9cff4cfb5636fc701028 100644 (file)
@@ -90,6 +90,7 @@ struct dns_kasp {
        uint32_t signatures_validity_dnskey;
 
        /* Configuration: Keys */
+       bool                  offlineksk;
        bool                  cdnskey;
        dns_kasp_digestlist_t digests;
        dns_kasp_keylist_t    keys;
@@ -809,6 +810,28 @@ dns_kasp_setnsec3param(dns_kasp_t *kasp, uint8_t iter, bool optout,
  *
  */
 
+bool
+dns_kasp_offlineksk(dns_kasp_t *kasp);
+/*%<
+ * Should we be using Offline KSK key management?
+ *
+ * Requires:
+ *
+ *\li  'kasp' is a valid, frozen kasp.
+ *
+ */
+
+void
+dns_kasp_setofflineksk(dns_kasp_t *kasp, bool offlineksk);
+/*%<
+ * Enable/disable Offline KSK.
+ *
+ * Requires:
+ *
+ *\li  'kasp' is a valid, unfrozen kasp.
+ *
+ */
+
 bool
 dns_kasp_cdnskey(dns_kasp_t *kasp);
 /*%<
@@ -823,7 +846,7 @@ dns_kasp_cdnskey(dns_kasp_t *kasp);
 void
 dns_kasp_setcdnskey(dns_kasp_t *kasp, bool cdnskey);
 /*%<
- * Set to enable publication of CDNSKEY records.
+ * Enable/disable publication of CDNSKEY records.
  *
  * Requires:
  *
index 4a85a0170ea01526926d84639d9a87cef6a315de..50ecba05d6fca127fb466695f2ff4ee22dcae110 100644 (file)
@@ -594,6 +594,22 @@ dns_kasp_setnsec3param(dns_kasp_t *kasp, uint8_t iter, bool optout,
        kasp->nsec3param.saltlen = saltlen;
 }
 
+bool
+dns_kasp_offlineksk(dns_kasp_t *kasp) {
+       REQUIRE(kasp != NULL);
+       REQUIRE(kasp->frozen);
+
+       return kasp->offlineksk;
+}
+
+void
+dns_kasp_setofflineksk(dns_kasp_t *kasp, bool offlineksk) {
+       REQUIRE(kasp != NULL);
+       REQUIRE(!kasp->frozen);
+
+       kasp->offlineksk = offlineksk;
+}
+
 bool
 dns_kasp_cdnskey(dns_kasp_t *kasp) {
        REQUIRE(kasp != NULL);
index 98a49f7004fc2ad7a10ccbd1af0951f685952031..b6da87a235f8f1312e065e8696cc6400f18f2512 100644 (file)
@@ -112,7 +112,8 @@ get_string(const cfg_obj_t **maps, const char *option) {
  */
 static isc_result_t
 cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
-                      bool check_algorithms, dns_keystorelist_t *keystorelist,
+                      bool check_algorithms, bool offline_ksk,
+                      dns_keystorelist_t *keystorelist,
                       uint32_t ksk_min_lifetime, uint32_t zsk_min_lifetime) {
        isc_result_t result;
        dns_kasp_key_t *key = NULL;
@@ -125,6 +126,7 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
 
        if (config == NULL) {
                /* We are creating a key reference for the default kasp. */
+               INSIST(!offline_ksk);
                key->role |= DNS_KASP_KEY_ROLE_KSK | DNS_KASP_KEY_ROLE_ZSK;
                key->lifetime = 0; /* unlimited */
                key->algorithm = DNS_KEYALG_ECDSA256;
@@ -148,6 +150,14 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
                } else if (strcmp(rolestr, "zsk") == 0) {
                        key->role |= DNS_KASP_KEY_ROLE_ZSK;
                } else if (strcmp(rolestr, "csk") == 0) {
+                       if (offline_ksk) {
+                               cfg_obj_log(
+                                       config, ISC_LOG_ERROR,
+                                       "dnssec-policy: csk keys are not "
+                                       "allowed when offline-ksk is enabled");
+                               result = ISC_R_FAILURE;
+                               goto cleanup;
+                       }
                        key->role |= DNS_KASP_KEY_ROLE_KSK;
                        key->role |= DNS_KASP_KEY_ROLE_ZSK;
                }
@@ -416,6 +426,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;
 
        REQUIRE(config != NULL);
        REQUIRE(kaspp != NULL && *kaspp == NULL);
@@ -537,6 +548,13 @@ cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
        dns_kasp_setparentpropagationdelay(kasp, parentpropdelay);
 
        /* Configuration: Keys */
+       obj = NULL;
+       (void)confget(maps, "offline-ksk", &obj);
+       if (obj != NULL) {
+               offline_ksk = cfg_obj_asboolean(obj);
+       }
+       dns_kasp_setofflineksk(kasp, offline_ksk);
+
        obj = NULL;
        (void)confget(maps, "cdnskey", &obj);
        if (obj != NULL) {
@@ -592,8 +610,9 @@ cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
                {
                        cfg_obj_t *kobj = cfg_listelt_value(element);
                        result = cfg_kaspkey_fromconfig(
-                               kobj, kasp, check_algorithms, keystorelist,
-                               ksk_min_lifetime, zsk_min_lifetime);
+                               kobj, kasp, check_algorithms, offline_ksk,
+                               keystorelist, ksk_min_lifetime,
+                               zsk_min_lifetime);
                        if (result != ISC_R_SUCCESS) {
                                cfg_obj_log(kobj, ISC_LOG_ERROR,
                                            "dnssec-policy: failed to "
index 21496e0bc7267b4b4b681b824ca0f90b82ca5542..d70e0eb651192095326c75bc1a5cfd8f4cf741c2 100644 (file)
@@ -2278,6 +2278,7 @@ static cfg_clausedef_t dnssecpolicy_clauses[] = {
        { "keys", &cfg_type_kaspkeys, 0 },
        { "max-zone-ttl", &cfg_type_duration, 0 },
        { "nsec3param", &cfg_type_nsec3, 0 },
+       { "offline-ksk", &cfg_type_boolean, 0 },
        { "parent-ds-ttl", &cfg_type_duration, 0 },
        { "parent-propagation-delay", &cfg_type_duration, 0 },
        { "parent-registration-delay", &cfg_type_duration,