]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Implement named-checkconf -k (check keys)
authorMatthijs Mekking <matthijs@isc.org>
Thu, 28 Aug 2025 08:28:02 +0000 (10:28 +0200)
committerMichał Kępień <michal@isc.org>
Mon, 29 Sep 2025 13:13:26 +0000 (15:13 +0200)
With named-checkconf -k you can check your configuration including
checking the dnssec-policy keys against the configured keystores. If
there is a mismatch in the key files versus the policy, named-checkconf
will fail. This is useful for running before migrating to dnssec-policy.

For logging purposes, introduce a function that writes the identifying
information about a policy key into a string.

Allow a dnssec key to be initialized outside the keymgr code.

Add 'log_errors' to 'cfg_kasp_fromconfig' to avoid duplicate error
logs.

(cherry picked from commit 9fe520ece9121a81dc3e77d11a9a93ae29468399)

12 files changed:
bin/check/named-checkconf.c
bin/check/named-checkconf.rst
bin/dnssec/dnssectool.c
bin/named/server.c
lib/dns/include/dns/kasp.h
lib/dns/include/dns/keymgr.h
lib/dns/kasp.c
lib/dns/keymgr.c
lib/isccfg/check.c
lib/isccfg/include/isccfg/check.h
lib/isccfg/include/isccfg/kaspconf.h
lib/isccfg/kaspconf.c

index ce0a9805319e1f2c2df9e9df157e24cd4e6c3e74..2737e60a2ea83285944d40f6ac9179217b3d7446 100644 (file)
@@ -60,7 +60,7 @@ usage(void);
 static void
 usage(void) {
        fprintf(stderr,
-               "usage: %s [-achijlvz] [-p [-x]] [-t directory] "
+               "usage: %s [-achijklvz] [-p [-x]] [-t directory] "
                "[named.conf]\n",
                program);
        exit(EXIT_SUCCESS);
@@ -606,7 +606,7 @@ main(int argc, char **argv) {
        /*
         * Process memory debugging argument first.
         */
-#define CMDLINE_FLAGS "acdhijlm:t:pvxz"
+#define CMDLINE_FLAGS "acdhijklm:t:pvxz"
        while ((c = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
                switch (c) {
                case 'm':
@@ -653,6 +653,10 @@ main(int argc, char **argv) {
                        nomerge = false;
                        break;
 
+               case 'k':
+                       checkflags |= BIND_CHECK_KEYS;
+                       break;
+
                case 'l':
                        list_zones = true;
                        break;
index 41dad390fadd03a3b74c1a19d93319ca419227b7..658e0cdba528637dfcdc23515bc1fe2b895926c3 100644 (file)
@@ -21,7 +21,7 @@ named-checkconf - named configuration file syntax checking tool
 Synopsis
 ~~~~~~~~
 
-:program:`named-checkconf` [**-achjlvz**] [**-p** [**-x** ]] [**-t** directory] {filename}
+:program:`named-checkconf` [**-achjklvz**] [**-p** [**-x** ]] [**-t** directory] {filename}
 
 Description
 ~~~~~~~~~~~
@@ -56,6 +56,12 @@ Options
 
    When loading a zonefile, this option instructs :iscman:`named` to read the journal if it exists.
 
+.. option:: -k
+
+   Check the `dnssec-policy`'s DNSSEC keys against the key files in
+   the `key-directory`.  This is useful when checking a `named.conf`
+   to ensure a DNSSEC policy matches the existing keys.
+
 .. option:: -l
 
    This option lists all the configured zones. Each line of output contains the zone
index f7faa1304679fd95a3eaa73b8397200feeb99204..723abd8f25578f51163caa1ad792f6a911f21ebb 100644 (file)
@@ -628,6 +628,9 @@ kasp_from_conf(cfg_obj_t *config, isc_mem_t *mctx, isc_log_t *lctx,
        const cfg_obj_t *keystores = NULL;
        dns_keystore_t *ks = NULL, *ks_next;
        dns_keystorelist_t kslist;
+       unsigned int options = (ISCCFG_KASPCONF_CHECK_ALGORITHMS |
+                               ISCCFG_KASPCONF_CHECK_KEYLIST |
+                               ISCCFG_KASPCONF_LOG_ERRORS);
 
        ISC_LIST_INIT(kasplist);
        ISC_LIST_INIT(kslist);
@@ -668,7 +671,7 @@ kasp_from_conf(cfg_obj_t *config, isc_mem_t *mctx, isc_log_t *lctx,
                        continue;
                }
 
-               result = cfg_kasp_fromconfig(kconfig, NULL, true, mctx, lctx,
+               result = cfg_kasp_fromconfig(kconfig, NULL, options, mctx, lctx,
                                             &kslist, &kasplist, &kasp);
                if (result != ISC_R_SUCCESS) {
                        fatal("failed to configure dnssec-policy '%s': %s",
index 6145e9181e1f25db996a7df0b84d0e426994abb7..29e1e5c8ce64f938947b17aefddf828ee36f4e2e 100644 (file)
@@ -8442,6 +8442,9 @@ load_configuration(const char *filename, named_server_t *server,
        dns_kasp_t *kasp_next = NULL;
        dns_kasp_t *default_kasp = NULL;
        dns_kasplist_t tmpkasplist, kasplist;
+       unsigned int kaspopts = (ISCCFG_KASPCONF_CHECK_ALGORITHMS |
+                                ISCCFG_KASPCONF_CHECK_KEYLIST |
+                                ISCCFG_KASPCONF_LOG_ERRORS);
        dns_keystore_t *keystore = NULL;
        dns_keystore_t *keystore_next = NULL;
        dns_keystorelist_t tmpkeystorelist, keystorelist;
@@ -9275,7 +9278,7 @@ load_configuration(const char *filename, named_server_t *server,
                cfg_obj_t *kconfig = cfg_listelt_value(element);
 
                kasp = NULL;
-               result = cfg_kasp_fromconfig(kconfig, default_kasp, true,
+               result = cfg_kasp_fromconfig(kconfig, default_kasp, kaspopts,
                                             named_g_mctx, named_g_lctx,
                                             &keystorelist, &kasplist, &kasp);
                if (result != ISC_R_SUCCESS) {
@@ -9304,7 +9307,7 @@ load_configuration(const char *filename, named_server_t *server,
        {
                cfg_obj_t *kconfig = cfg_listelt_value(element);
                kasp = NULL;
-               result = cfg_kasp_fromconfig(kconfig, default_kasp, true,
+               result = cfg_kasp_fromconfig(kconfig, default_kasp, kaspopts,
                                             named_g_mctx, named_g_lctx,
                                             &keystorelist, &kasplist, &kasp);
                if (result != ISC_R_SUCCESS) {
index 4309e3390b2851e8fd5a21dc07b9aacb696fd636..9eec8d3edd8b7438e3409d4d1b6d5891c54ffb41 100644 (file)
@@ -32,6 +32,7 @@
 
 #include <dns/dnssec.h>
 #include <dns/keystore.h>
+#include <dns/name.h>
 #include <dns/types.h>
 
 ISC_LANG_BEGINDECLS
@@ -140,6 +141,8 @@ struct dns_kasp {
 #define DNS_KASP_KEY_ROLE_KSK 0x01
 #define DNS_KASP_KEY_ROLE_ZSK 0x02
 
+#define DNS_KASP_KEY_FORMATSIZE (DNS_NAME_FORMATSIZE + 64)
+
 isc_result_t
 dns_kasp_create(isc_mem_t *mctx, const char *name, dns_kasp_t **kaspp);
 /*%<
@@ -786,6 +789,17 @@ dns_kasp_key_match(dns_kasp_key_t *key, dns_dnsseckey_t *dkey);
  *\li  False, otherwise.
  */
 
+void
+dns_kasp_key_format(dns_kasp_key_t *key, char *cp, unsigned int size);
+/*%<
+ * Write the identifying information about the policy key (role,
+ * algorithm, tag range) into a string 'cp' of size 'size'.
+ * Requires:
+ *
+ *\li  key != NULL
+ *\li  cp != NULL
+ */
+
 bool
 dns_kasp_nsec3(dns_kasp_t *kasp);
 /*%<
index 30d05b78cd2f35302bdf6018bbf8e4e957edbb6c..2433383c4b12b455a6dc7151ca39e3ef2825056e 100644 (file)
@@ -41,6 +41,21 @@ dns_keymgr_settime_syncpublish(dst_key_t *key, dns_kasp_t *kasp, bool first);
  *\li           'kasp' is a valid DNSSEC policy.
  */
 
+void
+dns_keymgr_key_init(dns_dnsseckey_t *key, dns_kasp_t *kasp, isc_stdtime_t now,
+                   bool csk);
+/*
+ * Initialize this key's properties if not already present.  A key created
+ * and derived from a dnssec-policy will have the required metadata available,
+ * otherwise these may be missing and need to be initialized.  The key states
+ * will be initialized according to existing timing metadata. If 'csk' is
+ * set to true, the key is considered a combined signing key (CSK).
+ *
+ *      Requires:
+ *\li           'key' is a valid DNSSEC key.
+ *\li           'kasp' is a valid DNSSEC policy.
+ */
+
 isc_result_t
 dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
               isc_mem_t *mctx, dns_dnsseckeylist_t *keyring,
index f63b59e859ee593034eca07121bbd927e653a37f..e5d9f077902bb5990470214ce0a1900277f33910 100644 (file)
@@ -575,6 +575,21 @@ dns_kasp_key_match(dns_kasp_key_t *key, dns_dnsseckey_t *dkey) {
        return true;
 }
 
+void
+dns_kasp_key_format(dns_kasp_key_t *key, char *cp, unsigned int size) {
+       REQUIRE(key != NULL);
+       REQUIRE(cp != NULL);
+
+       char algstr[DNS_NAME_FORMATSIZE];
+       bool csk = dns_kasp_key_ksk(key) && dns_kasp_key_zsk(key);
+       const char *rolestr = (csk ? "csk"
+                                  : (dns_kasp_key_ksk(key) ? "ksk" : "zsk"));
+
+       dns_secalg_format((dns_secalg_t)key->algorithm, algstr, sizeof(algstr));
+       snprintf(cp, size, "%s algorithm:%s length:%u tag-range:%u-%u", rolestr,
+                algstr, dns_kasp_key_size(key), key->tag_min, key->tag_max);
+}
+
 uint8_t
 dns_kasp_nsec3iter(dns_kasp_t *kasp) {
        REQUIRE(kasp != NULL);
index 4f8f7cad765b04444aa7ec9e8bcfd18ba434997d..d1dd0edef948288fd4de308da758195aa1695b4f 100644 (file)
@@ -1667,16 +1667,9 @@ transition:
        return result;
 }
 
-/*
- * See if this key needs to be initialized with properties.  A key created
- * and derived from a dnssec-policy will have the required metadata available,
- * otherwise these may be missing and need to be initialized.  The key states
- * will be initialized according to existing timing metadata.
- *
- */
-static void
-keymgr_key_init(dns_dnsseckey_t *key, dns_kasp_t *kasp, isc_stdtime_t now,
-               bool csk) {
+void
+dns_keymgr_key_init(dns_dnsseckey_t *key, dns_kasp_t *kasp, isc_stdtime_t now,
+                   bool csk) {
        bool ksk, zsk;
        isc_result_t ret;
        isc_stdtime_t active = 0, pub = 0, syncpub = 0, retire = 0, remove = 0;
@@ -1960,7 +1953,7 @@ keymgr_key_rollover(dns_kasp_key_t *kaspkey, dns_dnsseckey_t *active_key,
                dst_key_setttl(dst_key, dns_kasp_dnskeyttl(kasp));
                dst_key_settime(dst_key, DST_TIME_CREATED, now);
                dns_dnsseckey_create(mctx, &dst_key, &new_key);
-               keymgr_key_init(new_key, kasp, now, csk);
+               dns_keymgr_key_init(new_key, kasp, now, csk);
        }
        dst_key_setnum(new_key->key, DST_NUM_LIFETIME, lifetime);
 
@@ -2247,7 +2240,7 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
        {
                bool found_match = false;
 
-               keymgr_key_init(dkey, kasp, now, numkeys == 1);
+               dns_keymgr_key_init(dkey, kasp, now, numkeys == 1);
 
                for (kkey = ISC_LIST_HEAD(dns_kasp_keys(kasp)); kkey != NULL;
                     kkey = ISC_LIST_NEXT(kkey, link))
@@ -2884,7 +2877,7 @@ dns_keymgr_offline(const dns_name_t *origin, dns_dnsseckeylist_t *keyring,
                        continue;
                }
 
-               keymgr_key_init(dkey, kasp, now, false);
+               dns_keymgr_key_init(dkey, kasp, now, false);
 
                /* Get current metadata */
                RETERR(dst_key_getstate(dkey->key, DST_KEY_DNSKEY,
index c2461a5e8c2976628e7a1b9bdaac5c87eb35b48e..251dceb55e9588ccf3b2646ef00cf09f74295fa7 100644 (file)
@@ -47,6 +47,7 @@
 #include <dns/dnstap.h>
 #include <dns/fixedname.h>
 #include <dns/kasp.h>
+#include <dns/keymgr.h>
 #include <dns/keystore.h>
 #include <dns/keyvalues.h>
 #include <dns/peer.h>
@@ -1525,6 +1526,11 @@ check_options(const cfg_obj_t *options, const cfg_obj_t *config,
        if (obj != NULL) {
                bool bad_kasp = false;
                bool bad_name = false;
+               unsigned int kaspopts = (ISCCFG_KASPCONF_CHECK_KEYLIST |
+                                        ISCCFG_KASPCONF_LOG_ERRORS);
+               if (check_algorithms) {
+                       kaspopts |= ISCCFG_KASPCONF_CHECK_ALGORITHMS;
+               }
 
                if (optlevel != optlevel_config && !cfg_obj_isstring(obj)) {
                        bad_kasp = true;
@@ -1553,9 +1559,8 @@ check_options(const cfg_obj_t *options, const cfg_obj_t *config,
                                        }
 
                                        ret = cfg_kasp_fromconfig(
-                                               kconfig, NULL, check_algorithms,
-                                               mctx, logctx, &kslist, &list,
-                                               &kasp);
+                                               kconfig, NULL, kaspopts, mctx,
+                                               logctx, &kslist, &list, &kasp);
                                        if (ret != ISC_R_SUCCESS) {
                                                if (result == ISC_R_SUCCESS) {
                                                        result = ret;
@@ -3021,33 +3026,32 @@ cleanup:
 
 static isc_result_t
 check_keydir(const cfg_obj_t *config, const cfg_obj_t *zconfig,
-            dns_name_t *zname, const char *name, const char *keydir,
-            isc_symtab_t *keydirs, isc_log_t *logctx, isc_mem_t *mctx) {
+            dns_name_t *origin, const char *zname, const char *name,
+            const char *keydir, isc_symtab_t *keydirs, isc_log_t *logctx,
+            isc_mem_t *mctx, bool check_keys) {
        const char *dir = keydir;
        const cfg_listelt_t *element;
        isc_result_t ret, result = ISC_R_SUCCESS;
-       bool do_cleanup = false;
        bool done = false;
        bool keystore = false;
-
        const cfg_obj_t *kasps = NULL;
        dns_kasp_t *kasp = NULL, *kasp_next = NULL;
+       const cfg_obj_t *kaspobj = NULL;
        dns_kasplist_t kasplist;
 
        const cfg_obj_t *keystores = NULL;
        dns_keystore_t *ks = NULL, *ks_next = NULL;
        dns_keystorelist_t kslist;
+       isc_time_t timenow;
+       isc_stdtime_t now;
+
+       timenow = isc_time_now();
+       now = isc_time_seconds(&timenow);
 
-       /* If no dnssec-policy or key-store, use the dir (key-directory) */
        (void)cfg_map_get(config, "dnssec-policy", &kasps);
        (void)cfg_map_get(config, "key-store", &keystores);
-       if (kasps == NULL || keystores == NULL) {
-               goto check;
-       }
-
        ISC_LIST_INIT(kasplist);
        ISC_LIST_INIT(kslist);
-       do_cleanup = true;
 
        /*
         * Build the keystore list.
@@ -3069,7 +3073,7 @@ check_keydir(const cfg_obj_t *config, const cfg_obj_t *zconfig,
             element = cfg_list_next(element))
        {
                cfg_obj_t *kconfig = cfg_listelt_value(element);
-               const cfg_obj_t *kaspobj = NULL;
+               kaspobj = NULL;
 
                if (!cfg_obj_istuple(kconfig)) {
                        continue;
@@ -3080,7 +3084,7 @@ check_keydir(const cfg_obj_t *config, const cfg_obj_t *zconfig,
                        continue;
                }
 
-               ret = cfg_kasp_fromconfig(kconfig, NULL, false, mctx, logctx,
+               ret = cfg_kasp_fromconfig(kconfig, NULL, 0, mctx, logctx,
                                          &kslist, &kasplist, &kasp);
                if (ret != ISC_R_SUCCESS) {
                        kasp = NULL;
@@ -3090,6 +3094,7 @@ check_keydir(const cfg_obj_t *config, const cfg_obj_t *zconfig,
        if (kasp == NULL) {
                goto check;
        }
+       INSIST(kaspobj != NULL);
 
        /* Check key-stores of keys */
        dns_kasp_freeze(kasp);
@@ -3104,39 +3109,133 @@ check_keydir(const cfg_obj_t *config, const cfg_obj_t *zconfig,
                ret = keydirexist(zconfig,
                                  keystore ? "key-store directory"
                                           : "key-directory",
-                                 zname, dir, name, keydirs, logctx, mctx);
+                                 origin, dir, name, keydirs, logctx, mctx);
+               if (ret != ISC_R_SUCCESS) {
+                       result = ret;
+               }
+       }
+
+       if (check_keys) {
+               /* Find matching key files. */
+               dns_dnsseckeylist_t keys;
+               int numkaspkeys = 0;
+               int numkeyfiles = 0;
+
+               ISC_LIST_INIT(keys);
+               ret = dns_dnssec_findmatchingkeys(origin, kasp, keydir, &kslist,
+                                                 now, mctx, &keys);
                if (ret != ISC_R_SUCCESS) {
                        result = ret;
                }
+
+               for (dns_dnsseckey_t *dkey = ISC_LIST_HEAD(keys); dkey != NULL;
+                    dkey = ISC_LIST_NEXT(dkey, link))
+               {
+                       numkeyfiles++;
+               }
+
+               for (dns_dnsseckey_t *dkey = ISC_LIST_HEAD(keys); dkey != NULL;
+                    dkey = ISC_LIST_NEXT(dkey, link))
+               {
+                       bool found_match = false;
+
+                       dns_keymgr_key_init(dkey, kasp, now, numkeyfiles == 1);
+
+                       for (dns_kasp_key_t *kkey =
+                                    ISC_LIST_HEAD(dns_kasp_keys(kasp));
+                            kkey != NULL; kkey = ISC_LIST_NEXT(kkey, link))
+                       {
+                               if (dns_kasp_key_match(kkey, dkey)) {
+                                       found_match = true;
+                                       break;
+                               }
+                       }
+
+                       if (!found_match) {
+                               char keystr[DST_KEY_FORMATSIZE];
+                               dst_key_format(dkey->key, keystr,
+                                              sizeof(keystr));
+                               cfg_obj_log(kaspobj, logctx, ISC_LOG_ERROR,
+                                           "zone '%s': key file '%s' does not "
+                                           "match dnssec-policy %s",
+                                           zname, keystr,
+                                           dns_kasp_getname(kasp));
+                               result = ISC_R_NOTFOUND;
+                       }
+               }
+
+               for (dns_kasp_key_t *kkey = ISC_LIST_HEAD(dns_kasp_keys(kasp));
+                    kkey != NULL; kkey = ISC_LIST_NEXT(kkey, link))
+               {
+                       bool found_match = false;
+
+                       numkaspkeys++;
+
+                       for (dns_dnsseckey_t *dkey = ISC_LIST_HEAD(keys);
+                            dkey != NULL; dkey = ISC_LIST_NEXT(dkey, link))
+                       {
+                               if (dns_kasp_key_match(kkey, dkey)) {
+                                       found_match = true;
+                                       break;
+                               }
+                       }
+
+                       if (!found_match) {
+                               char keystr[DNS_KASP_KEY_FORMATSIZE];
+                               dns_kasp_key_format(kkey, keystr,
+                                                   sizeof(keystr));
+
+                               cfg_obj_log(
+                                       kaspobj, logctx, ISC_LOG_ERROR,
+                                       "zone '%s': no key file found matching "
+                                       "dnssec-policy %s key:'%s'",
+                                       zname, dns_kasp_getname(kasp), keystr);
+                               result = ISC_R_NOTFOUND;
+                       }
+               }
+
+               if (numkaspkeys != numkeyfiles) {
+                       cfg_obj_log(kaspobj, logctx, ISC_LOG_ERROR,
+                                   "zone '%s': wrong number of key files (%d, "
+                                   "expected %d)",
+                                   zname, numkeyfiles, numkaspkeys);
+                       result = ISC_R_FAILURE;
+               }
+
+               dns_dnsseckey_t *dkey_next = NULL;
+               for (dns_dnsseckey_t *dkey = ISC_LIST_HEAD(keys); dkey != NULL;
+                    dkey = dkey_next)
+               {
+                       dkey_next = ISC_LIST_NEXT(dkey, link);
+                       ISC_LIST_UNLINK(keys, dkey, link);
+                       dns_dnsseckey_destroy(mctx, &dkey);
+               }
        }
+
        dns_kasp_thaw(kasp);
        done = true;
 
 check:
        if (!done) {
-               ret = keydirexist(zconfig, "key-directory", zname, dir, name,
+               ret = keydirexist(zconfig, "key-directory", origin, dir, name,
                                  keydirs, logctx, mctx);
                if (ret != ISC_R_SUCCESS) {
                        result = ret;
                }
        }
 
-       if (do_cleanup) {
-               if (kasp != NULL) {
-                       dns_kasp_detach(&kasp);
-               }
-               for (kasp = ISC_LIST_HEAD(kasplist); kasp != NULL;
-                    kasp = kasp_next)
-               {
-                       kasp_next = ISC_LIST_NEXT(kasp, link);
-                       ISC_LIST_UNLINK(kasplist, kasp, link);
-                       dns_kasp_detach(&kasp);
-               }
-               for (ks = ISC_LIST_HEAD(kslist); ks != NULL; ks = ks_next) {
-                       ks_next = ISC_LIST_NEXT(ks, link);
-                       ISC_LIST_UNLINK(kslist, ks, link);
-                       dns_keystore_detach(&ks);
-               }
+       if (kasp != NULL) {
+               dns_kasp_detach(&kasp);
+       }
+       for (kasp = ISC_LIST_HEAD(kasplist); kasp != NULL; kasp = kasp_next) {
+               kasp_next = ISC_LIST_NEXT(kasp, link);
+               ISC_LIST_UNLINK(kasplist, kasp, link);
+               dns_kasp_detach(&kasp);
+       }
+       for (ks = ISC_LIST_HEAD(kslist); ks != NULL; ks = ks_next) {
+               ks_next = ISC_LIST_NEXT(ks, link);
+               ISC_LIST_UNLINK(kslist, ks, link);
+               dns_keystore_detach(&ks);
        }
 
        return result;
@@ -3147,7 +3246,8 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
               const cfg_obj_t *config, isc_symtab_t *symtab,
               isc_symtab_t *files, isc_symtab_t *keydirs, isc_symtab_t *inview,
               const char *viewname, dns_rdataclass_t defclass,
-              cfg_aclconfctx_t *actx, isc_log_t *logctx, isc_mem_t *mctx) {
+              unsigned int flags, cfg_aclconfctx_t *actx, isc_log_t *logctx,
+              isc_mem_t *mctx) {
        const char *znamestr;
        const char *typestr = NULL;
        const char *target = NULL;
@@ -3170,6 +3270,7 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
        bool ddns = false;
        bool has_dnssecpolicy = false;
        bool kasp_inlinesigning = false;
+       bool check_keys = (flags & BIND_CHECK_KEYS) != 0;
        const void *clauses = NULL;
        const char *option = NULL;
        const char *kaspname = NULL;
@@ -3995,8 +4096,9 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
         */
        if (zname != NULL) {
                if (has_dnssecpolicy) {
-                       tresult = check_keydir(config, zconfig, zname, kaspname,
-                                              dir, keydirs, logctx, mctx);
+                       tresult = check_keydir(config, zconfig, zname, znamestr,
+                                              kaspname, dir, keydirs, logctx,
+                                              mctx, check_keys);
                } else {
                        tresult = keydirexist(zconfig, "key-directory", zname,
                                              dir, kaspname, keydirs, logctx,
@@ -5518,7 +5620,7 @@ check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions,
 
                tresult = check_zoneconf(zone, voptions, config, symtab, files,
                                         keydirs, inview, viewname, vclass,
-                                        actx, logctx, mctx);
+                                        flags, actx, logctx, mctx);
                if (tresult != ISC_R_SUCCESS) {
                        result = ISC_R_FAILURE;
                }
index aa38a8c4b5710eba60eebcc226ed501f3edb31a0..7f374dfa4c170e083889f060c6e58c95a109ac23 100644 (file)
  * Check the dnssec-policy DNSSEC algorithms against those
  * supported by the crypto provider.
  */
+#define BIND_CHECK_KEYS 0x00000004
+/*%<
+ * Check the dnssec-policy DNSSEC keys against the key files
+ * in the key stores.
+ */
 
 ISC_LANG_BEGINDECLS
 
index ccc1cecc5d9d49208a96b97bd1b839b12382f88d..2c162f8ccc078a77edec1652f75486422a2bd50e 100644 (file)
 
 #include <isccfg/cfg.h>
 
+#define ISCCFG_KASPCONF_CHECK_ALGORITHMS 0x01
+#define ISCCFG_KASPCONF_CHECK_KEYLIST   0x02
+#define ISCCFG_KASPCONF_LOG_ERRORS      0x04
+
 /***
  *** Functions
  ***/
@@ -25,7 +29,7 @@ ISC_LANG_BEGINDECLS
 
 isc_result_t
 cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
-                   bool check_algorithms, isc_mem_t *mctx, isc_log_t *logctx,
+                   unsigned int options, isc_mem_t *mctx, isc_log_t *logctx,
                    dns_keystorelist_t *keystorelist, dns_kasplist_t *kasplist,
                    dns_kasp_t **kaspp);
 /*%<
@@ -38,8 +42,16 @@ cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
  *
  * The 'keystorelist' is where to lookup key stores if KASP keys are using them.
  *
- * If 'check_algorithms' is true then the dnssec-policy DNSSEC key
- * algorithms are checked against those supported by the crypto provider.
+ * If 'options' has ISCCFG_KASPCONF_CHECK_ALGORITHMS set, then the dnssec-policy
+ * DNSSEC key algorithms are checked against those supported by the crypto
+ * provider.
+ *
+ * If 'options' has ISCCFG_KASPCONF_CHECK_KEYLIST set, then this function
+ * insists that the key list is not empty, unless the policy is "insecure"
+ * (then the key list must be empty).
+ *
+ * If 'options' has ISCCFG_KASPCONF_LOG_ERRORS set, then configuration errors
+ * and warnings are logged to the global logging context.
  *
  * Requires:
  *
index f0860a9329b40a2de69f11968f41342d031ed0ce..d103cfe3891557e45d9e1c1e7d0196f8129318a8 100644 (file)
@@ -112,8 +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, isc_log_t *logctx,
-                      bool offline_ksk, dns_keystorelist_t *keystorelist,
+                      bool check_algorithms, bool log_errors, bool offline_ksk,
+                      isc_log_t *logctx, dns_keystorelist_t *keystorelist,
                       uint32_t ksk_min_lifetime, uint32_t zsk_min_lifetime) {
        isc_result_t result;
        dns_kasp_key_t *key = NULL;
@@ -152,10 +152,14 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
                        key->role |= DNS_KASP_KEY_ROLE_ZSK;
                } else if (strcmp(rolestr, "csk") == 0) {
                        if (offline_ksk) {
-                               cfg_obj_log(
-                                       config, logctx, ISC_LOG_ERROR,
-                                       "dnssec-policy: csk keys are not "
-                                       "allowed when offline-ksk is enabled");
+                               if (log_errors) {
+                                       cfg_obj_log(config, logctx,
+                                                   ISC_LOG_ERROR,
+                                                   "dnssec-policy: csk keys "
+                                                   "are not "
+                                                   "allowed when offline-ksk "
+                                                   "is enabled");
+                               }
                                result = ISC_R_FAILURE;
                                goto cleanup;
                        }
@@ -173,14 +177,20 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
                result = dns_keystorelist_find(keystorelist, keydir,
                                               &key->keystore);
                if (result == ISC_R_NOTFOUND) {
-                       cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
-                                   "dnssec-policy: keystore %s does not exist",
-                                   keydir);
+                       if (log_errors) {
+                               cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+                                           "dnssec-policy: keystore %s does "
+                                           "not exist",
+                                           keydir);
+                       }
                        result = ISC_R_FAILURE;
                        goto cleanup;
                } else if (result != ISC_R_SUCCESS) {
-                       cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
-                                   "dnssec-policy: bad keystore %s", keydir);
+                       if (log_errors) {
+                               cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+                                           "dnssec-policy: bad keystore %s",
+                                           keydir);
+                       }
                        result = ISC_R_FAILURE;
                        goto cleanup;
                }
@@ -193,9 +203,13 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
                }
                if (key->lifetime > 0) {
                        if (key->lifetime < 30 * (24 * 3600)) {
-                               cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
-                                           "dnssec-policy: key lifetime is "
-                                           "shorter than 30 days");
+                               if (log_errors) {
+                                       cfg_obj_log(obj, logctx,
+                                                   ISC_LOG_WARNING,
+                                                   "dnssec-policy: key "
+                                                   "lifetime is "
+                                                   "shorter than 30 days");
+                               }
                        }
                        if ((key->role & DNS_KASP_KEY_ROLE_KSK) != 0 &&
                            key->lifetime <= ksk_min_lifetime)
@@ -208,10 +222,14 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
                                error = true;
                        }
                        if (error) {
-                               cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
-                                           "dnssec-policy: key lifetime is "
-                                           "shorter than the time it takes to "
-                                           "do a rollover");
+                               if (log_errors) {
+                                       cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+                                                   "dnssec-policy: key "
+                                                   "lifetime is "
+                                                   "shorter than the time it "
+                                                   "takes to "
+                                                   "do a rollover");
+                               }
                                result = ISC_R_FAILURE;
                                goto cleanup;
                        }
@@ -223,9 +241,11 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
                result = dns_secalg_fromtext(&key->algorithm,
                                             (isc_textregion_t *)&alg);
                if (result != ISC_R_SUCCESS) {
-                       cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
-                                   "dnssec-policy: bad algorithm %s",
-                                   alg.base);
+                       if (log_errors) {
+                               cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+                                           "dnssec-policy: bad algorithm %s",
+                                           alg.base);
+                       }
                        result = DNS_R_BADALG;
                        goto cleanup;
                }
@@ -234,10 +254,13 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
                    (key->algorithm == DNS_KEYALG_RSASHA1 ||
                     key->algorithm == DNS_KEYALG_NSEC3RSASHA1))
                {
-                       cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
-                                   "dnssec-policy: algorithm %s not supported "
-                                   "in FIPS mode",
-                                   alg.base);
+                       if (log_errors) {
+                               cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+                                           "dnssec-policy: algorithm %s not "
+                                           "supported "
+                                           "in FIPS mode",
+                                           alg.base);
+                       }
                        result = DNS_R_BADALG;
                        goto cleanup;
                }
@@ -245,9 +268,12 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
                if (check_algorithms &&
                    !dst_algorithm_supported(key->algorithm))
                {
-                       cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
-                                   "dnssec-policy: algorithm %s not supported",
-                                   alg.base);
+                       if (log_errors) {
+                               cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+                                           "dnssec-policy: algorithm %s not "
+                                           "supported",
+                                           alg.base);
+                       }
                        result = DNS_R_BADALG;
                        goto cleanup;
                }
@@ -255,10 +281,13 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
                switch (key->algorithm) {
                case DST_ALG_RSASHA1:
                case DST_ALG_NSEC3RSASHA1:
-                       cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
-                                   "dnssec-policy: DNSSEC algorithm %s is "
-                                   "deprecated",
-                                   alg.base);
+                       if (log_errors) {
+                               cfg_obj_log(
+                                       obj, logctx, ISC_LOG_WARNING,
+                                       "dnssec-policy: DNSSEC algorithm %s is "
+                                       "deprecated",
+                                       alg.base);
+                       }
                        break;
                default:
                        break;
@@ -280,11 +309,16 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
                                        min = DNS_KEYALG_RSASHA512 ? 1024 : 512;
                                }
                                if (size < min || size > 4096) {
-                                       cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
-                                                   "dnssec-policy: key with "
-                                                   "algorithm %s has invalid "
-                                                   "key length %u",
-                                                   alg.base, size);
+                                       if (log_errors) {
+                                               cfg_obj_log(obj, logctx,
+                                                           ISC_LOG_ERROR,
+                                                           "dnssec-policy: "
+                                                           "key with "
+                                                           "algorithm %s has "
+                                                           "invalid "
+                                                           "key length %u",
+                                                           alg.base, size);
+                                       }
                                        result = ISC_R_RANGE;
                                        goto cleanup;
                                }
@@ -293,11 +327,16 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
                        case DNS_KEYALG_ECDSA384:
                        case DNS_KEYALG_ED25519:
                        case DNS_KEYALG_ED448:
-                               cfg_obj_log(obj, logctx, ISC_LOG_WARNING,
-                                           "dnssec-policy: key algorithm %s "
-                                           "has predefined length; ignoring "
-                                           "length value %u",
-                                           alg.base, size);
+                               if (log_errors) {
+                                       cfg_obj_log(obj, logctx,
+                                                   ISC_LOG_WARNING,
+                                                   "dnssec-policy: key "
+                                                   "algorithm %s "
+                                                   "has predefined length; "
+                                                   "ignoring "
+                                                   "length value %u",
+                                                   alg.base, size);
+                               }
                        default:
                                break;
                        }
@@ -311,25 +350,31 @@ cfg_kaspkey_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
                        obj = cfg_tuple_get(tagrange, "tag-min");
                        tag_min = cfg_obj_asuint32(obj);
                        if (tag_min > 0xffff) {
-                               cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
-                                           "dnssec-policy: tag-min "
-                                           "too big");
+                               if (log_errors) {
+                                       cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+                                                   "dnssec-policy: tag-min "
+                                                   "too big");
+                               }
                                result = ISC_R_RANGE;
                                goto cleanup;
                        }
                        obj = cfg_tuple_get(tagrange, "tag-max");
                        tag_max = cfg_obj_asuint32(obj);
                        if (tag_max > 0xffff) {
-                               cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
-                                           "dnssec-policy: tag-max "
-                                           "too big");
+                               if (log_errors) {
+                                       cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+                                                   "dnssec-policy: tag-max "
+                                                   "too big");
+                               }
                                result = ISC_R_RANGE;
                                goto cleanup;
                        }
                        if (tag_min >= tag_max) {
-                               cfg_obj_log(
-                                       obj, logctx, ISC_LOG_ERROR,
-                                       "dnssec-policy: tag-min >= tag_max");
+                               if (log_errors) {
+                                       cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+                                                   "dnssec-policy: tag-min >= "
+                                                   "tag_max");
+                               }
                                result = ISC_R_RANGE;
                                goto cleanup;
                        }
@@ -349,7 +394,7 @@ cleanup:
 
 static isc_result_t
 cfg_nsec3param_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
-                         isc_log_t *logctx) {
+                         bool log_errors, isc_log_t *logctx) {
        dns_kasp_key_t *kkey;
        unsigned int min_keysize = 4096;
        const cfg_obj_t *obj = NULL;
@@ -386,18 +431,22 @@ cfg_nsec3param_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
        if (badalg > 0) {
                char algstr[DNS_SECALG_FORMATSIZE];
                dns_secalg_format((dns_secalg_t)badalg, algstr, sizeof(algstr));
-               cfg_obj_log(
-                       obj, logctx, ISC_LOG_ERROR,
-                       "dnssec-policy: cannot use nsec3 with algorithm '%s'",
-                       algstr);
+               if (log_errors) {
+                       cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+                                   "dnssec-policy: cannot use nsec3 with "
+                                   "algorithm '%s'",
+                                   algstr);
+               }
                return DNS_R_NSEC3BADALG;
        }
 
        if (iter != DEFAULT_NSEC3PARAM_ITER) {
-               cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
-                           "dnssec-policy: nsec3 iterations value %u "
-                           "not allowed, must be zero",
-                           iter);
+               if (log_errors) {
+                       cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+                                   "dnssec-policy: nsec3 iterations value %u "
+                                   "not allowed, must be zero",
+                                   iter);
+               }
                return DNS_R_NSEC3ITERRANGE;
        }
 
@@ -413,9 +462,12 @@ cfg_nsec3param_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
                saltlen = cfg_obj_asuint32(obj);
        }
        if (saltlen > 0xff) {
-               cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
-                           "dnssec-policy: nsec3 salt length %u too high",
-                           saltlen);
+               if (log_errors) {
+                       cfg_obj_log(
+                               obj, logctx, ISC_LOG_ERROR,
+                               "dnssec-policy: nsec3 salt length %u too high",
+                               saltlen);
+               }
                return DNS_R_NSEC3SALTRANGE;
        }
 
@@ -424,7 +476,8 @@ cfg_nsec3param_fromconfig(const cfg_obj_t *config, dns_kasp_t *kasp,
 }
 
 static isc_result_t
-add_digest(dns_kasp_t *kasp, const cfg_obj_t *digest, isc_log_t *logctx) {
+add_digest(dns_kasp_t *kasp, const cfg_obj_t *digest, bool log_errors,
+          isc_log_t *logctx) {
        isc_result_t result = ISC_R_SUCCESS;
        isc_textregion_t r;
        dns_dsdigest_t alg;
@@ -434,21 +487,28 @@ add_digest(dns_kasp_t *kasp, const cfg_obj_t *digest, isc_log_t *logctx) {
        r.length = strlen(str);
        result = dns_dsdigest_fromtext(&alg, &r);
        if (result != ISC_R_SUCCESS) {
-               cfg_obj_log(digest, logctx, ISC_LOG_ERROR,
-                           "dnssec-policy: bad cds digest-type %s", str);
+               if (log_errors) {
+                       cfg_obj_log(digest, logctx, ISC_LOG_ERROR,
+                                   "dnssec-policy: bad cds digest-type %s",
+                                   str);
+               }
                result = DNS_R_BADALG;
        } else if (!dst_ds_digest_supported(alg)) {
-               cfg_obj_log(digest, logctx, ISC_LOG_ERROR,
-                           "dnssec-policy: unsupported cds "
-                           "digest-type %s",
-                           str);
+               if (log_errors) {
+                       cfg_obj_log(digest, logctx, ISC_LOG_ERROR,
+                                   "dnssec-policy: unsupported cds "
+                                   "digest-type %s",
+                                   str);
+               }
                result = DST_R_UNSUPPORTEDALG;
        } else {
                if (alg == DNS_DSDIGEST_SHA1) {
-                       cfg_obj_log(
-                               digest, logctx, ISC_LOG_WARNING,
-                               "dnssec-policy: deprecated CDS digest-type %s",
-                               str);
+                       if (log_errors) {
+                               cfg_obj_log(digest, logctx, ISC_LOG_WARNING,
+                                           "dnssec-policy: deprecated CDS "
+                                           "digest-type %s",
+                                           str);
+                       }
                }
                dns_kasp_adddigest(kasp, alg);
        }
@@ -457,7 +517,7 @@ add_digest(dns_kasp_t *kasp, const cfg_obj_t *digest, isc_log_t *logctx) {
 
 isc_result_t
 cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
-                   bool check_algorithms, isc_mem_t *mctx, isc_log_t *logctx,
+                   unsigned int options, isc_mem_t *mctx, isc_log_t *logctx,
                    dns_keystorelist_t *keystorelist, dns_kasplist_t *kasplist,
                    dns_kasp_t **kaspp) {
        isc_result_t result;
@@ -479,6 +539,10 @@ cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
        uint32_t ipub = 0, iret = 0;
        uint32_t ksk_min_lifetime = 0, zsk_min_lifetime = 0;
        bool offline_ksk = false, manual_mode = false;
+       bool check_algorithms = (options & ISCCFG_KASPCONF_CHECK_ALGORITHMS) !=
+                               0;
+       bool check_keylist = (options & ISCCFG_KASPCONF_CHECK_KEYLIST) != 0;
+       bool log_errors = (options & ISCCFG_KASPCONF_LOG_ERRORS) != 0;
 
        REQUIRE(config != NULL);
        REQUIRE(kaspp != NULL && *kaspp == NULL);
@@ -492,10 +556,12 @@ cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
        result = dns_kasplist_find(kasplist, kaspname, &kasp);
 
        if (result == ISC_R_SUCCESS) {
-               cfg_obj_log(
-                       config, logctx, ISC_LOG_ERROR,
-                       "dnssec-policy: duplicately named policy found '%s'",
-                       kaspname);
+               if (log_errors) {
+                       cfg_obj_log(config, logctx, ISC_LOG_ERROR,
+                                   "dnssec-policy: duplicately named policy "
+                                   "found '%s'",
+                                   kaspname);
+               }
                dns_kasp_detach(&kasp);
                return ISC_R_EXISTS;
        }
@@ -532,42 +598,51 @@ cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
        sigvalidity = get_duration(maps, "signatures-validity-dnskey",
                                   DNS_KASP_SIG_VALIDITY_DNSKEY);
        if (sigrefresh >= (sigvalidity * 0.9)) {
-               cfg_obj_log(
-                       config, logctx, ISC_LOG_ERROR,
-                       "dnssec-policy: policy '%s' signatures-refresh must be "
-                       "at most 90%% of the signatures-validity-dnskey",
-                       kaspname);
+               if (log_errors) {
+                       cfg_obj_log(config, logctx, ISC_LOG_ERROR,
+                                   "dnssec-policy: policy '%s' "
+                                   "signatures-refresh must be "
+                                   "at most 90%% of the "
+                                   "signatures-validity-dnskey",
+                                   kaspname);
+               }
                result = ISC_R_FAILURE;
        }
        dns_kasp_setsigvalidity_dnskey(kasp, sigvalidity);
 
        if (sigjitter > sigvalidity) {
-               cfg_obj_log(
-                       config, logctx, ISC_LOG_ERROR,
-                       "dnssec-policy: policy '%s' signatures-jitter cannot "
-                       "be larger than signatures-validity-dnskey",
-                       kaspname);
+               if (log_errors) {
+                       cfg_obj_log(config, logctx, ISC_LOG_ERROR,
+                                   "dnssec-policy: policy '%s' "
+                                   "signatures-jitter cannot "
+                                   "be larger than signatures-validity-dnskey",
+                                   kaspname);
+               }
                result = ISC_R_FAILURE;
        }
 
        sigvalidity = get_duration(maps, "signatures-validity",
                                   DNS_KASP_SIG_VALIDITY);
        if (sigrefresh >= (sigvalidity * 0.9)) {
-               cfg_obj_log(
-                       config, logctx, ISC_LOG_ERROR,
-                       "dnssec-policy: policy '%s' signatures-refresh must be "
-                       "at most 90%% of the signatures-validity",
-                       kaspname);
+               if (log_errors) {
+                       cfg_obj_log(config, logctx, ISC_LOG_ERROR,
+                                   "dnssec-policy: policy '%s' "
+                                   "signatures-refresh must be "
+                                   "at most 90%% of the signatures-validity",
+                                   kaspname);
+               }
                result = ISC_R_FAILURE;
        }
        dns_kasp_setsigvalidity(kasp, sigvalidity);
 
        if (sigjitter > sigvalidity) {
-               cfg_obj_log(
-                       config, logctx, ISC_LOG_ERROR,
-                       "dnssec-policy: policy '%s' signatures-jitter cannot "
-                       "be larger than signatures-validity",
-                       kaspname);
+               if (log_errors) {
+                       cfg_obj_log(config, logctx, ISC_LOG_ERROR,
+                                   "dnssec-policy: policy '%s' "
+                                   "signatures-jitter cannot "
+                                   "be larger than signatures-validity",
+                                   kaspname);
+               }
                result = ISC_R_FAILURE;
        }
 
@@ -628,7 +703,7 @@ cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
                     element = cfg_list_next(element))
                {
                        result = add_digest(kasp, cfg_listelt_value(element),
-                                           logctx);
+                                           log_errors, logctx);
                        if (result != ISC_R_SUCCESS) {
                                goto cleanup;
                        }
@@ -670,14 +745,16 @@ 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, logctx,
-                               offline_ksk, keystorelist, ksk_min_lifetime,
-                               zsk_min_lifetime);
+                               kobj, kasp, check_algorithms, log_errors,
+                               offline_ksk, logctx, keystorelist,
+                               ksk_min_lifetime, zsk_min_lifetime);
                        if (result != ISC_R_SUCCESS) {
-                               cfg_obj_log(kobj, logctx, ISC_LOG_ERROR,
-                                           "dnssec-policy: failed to "
-                                           "configure keys (%s)",
-                                           isc_result_totext(result));
+                               if (log_errors) {
+                                       cfg_obj_log(kobj, logctx, ISC_LOG_ERROR,
+                                                   "dnssec-policy: failed to "
+                                                   "configure keys (%s)",
+                                                   isc_result_totext(result));
+                               }
                                goto cleanup;
                        }
                }
@@ -712,19 +789,22 @@ cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
                        if (role[i] !=
                            (DNS_KASP_KEY_ROLE_ZSK | DNS_KASP_KEY_ROLE_KSK))
                        {
-                               cfg_obj_log(keys, logctx, ISC_LOG_ERROR,
-                                           "dnssec-policy: algorithm %zu "
-                                           "requires both KSK and ZSK roles",
-                                           i);
+                               if (log_errors) {
+                                       cfg_obj_log(keys, logctx, ISC_LOG_ERROR,
+                                                   "dnssec-policy: algorithm "
+                                                   "%zu requires both KSK and "
+                                                   "ZSK roles",
+                                                   i);
+                               }
                                result = ISC_R_FAILURE;
                        }
-                       if (warn[i][0]) {
+                       if (warn[i][0] && log_errors) {
                                cfg_obj_log(keys, logctx, ISC_LOG_WARNING,
                                            "dnssec-policy: algorithm %zu has "
                                            "multiple keys with ZSK role",
                                            i);
                        }
-                       if (warn[i][1]) {
+                       if (warn[i][1] && log_errors) {
                                cfg_obj_log(keys, logctx, ISC_LOG_WARNING,
                                            "dnssec-policy: algorithm %zu has "
                                            "multiple keys with KSK role",
@@ -767,20 +847,23 @@ cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
                                keystorelist, DNS_KEYSTORE_KEYDIRECTORY,
                                &new_key->keystore);
                        if (result != ISC_R_SUCCESS) {
-                               cfg_obj_log(config, logctx, ISC_LOG_ERROR,
-                                           "dnssec-policy: failed to "
-                                           "find keystore (%s)",
-                                           isc_result_totext(result));
+                               if (log_errors) {
+                                       cfg_obj_log(config, logctx,
+                                                   ISC_LOG_ERROR,
+                                                   "dnssec-policy: failed to "
+                                                   "find keystore (%s)",
+                                                   isc_result_totext(result));
+                               }
                                goto cleanup;
                        }
                        dns_kasp_addkey(kasp, new_key);
                }
        }
 
-       if (strcmp(kaspname, "insecure") == 0) {
+       if (strcmp(kaspname, "insecure") == 0 && check_keylist) {
                /* "dnssec-policy insecure": key list must be empty */
                INSIST(dns_kasp_keylist_empty(kasp));
-       } else if (default_kasp != NULL) {
+       } else if (default_kasp != NULL && check_keylist) {
                /* There must be keys configured. */
                INSIST(!(dns_kasp_keylist_empty(kasp)));
        }
@@ -798,7 +881,8 @@ cfg_kasp_fromconfig(const cfg_obj_t *config, dns_kasp_t *default_kasp,
                }
        } else {
                dns_kasp_setnsec3(kasp, true);
-               result = cfg_nsec3param_fromconfig(nsec3, kasp, logctx);
+               result = cfg_nsec3param_fromconfig(nsec3, kasp, log_errors,
+                                                  logctx);
                if (result != ISC_R_SUCCESS) {
                        goto cleanup;
                }