--- /dev/null
+/*
+ * 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.
+ */
+
+zone "bad-default-algorithm.example" {
+ type primary;
+ file "bad-default-algorithm.example.db";
+ dnssec-policy "default";
+};
--- /dev/null
+/*
+ * 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.
+ */
+
+zone "bad-default-kz.example" {
+ type primary;
+ file "bad-default-kz.example.db";
+ dnssec-policy "default";
+};
};
};
+zone "default.example" {
+ type primary;
+ file "default.example.db";
+ dnssec-policy "default";
+};
+
zone "alternative.kz.example" {
type primary;
file "alternative.kz.example.db";
mkdir ksk
mkdir zsk
+zone="default.example"
+cp template.db.in "${zone}.db"
+$KEYGEN -a 13 -fK $zone 2>keygen.out.$zone.1
+
+zone="bad-default-kz.example"
+cp template.db.in "${zone}.db"
+$KEYGEN -a 13 -fK $zone 2>keygen.out.$zone.1
+$KEYGEN -a 13 $zone 2>keygen.out.$zone.2
+
+zone="bad-default-algorithm.example"
+cp template.db.in "${zone}.db"
+$KEYGEN -a 8 -fK $zone 2>keygen.out.$zone.1
+
zone="alternative.kz.example"
cp template.db.in "${zone}.db"
$KEYGEN -a RSASHA256 -b 2048 $zone 2>keygen.out.$zone.1
f"zone '{zone}': no key file found matching dnssec-policy default-kz key:'zsk algorithm:ECDSAP256SHA256 length:256 tag-range:0-65535'"
in err
)
+
+ # Mismatch algorithm (default policy)
+ zone = "bad-default-algorithm.example"
+ out = isctest.run.cmd(
+ [CHECKCONF, "-k", "bad-default-algorithm.conf"], raise_on_exception=False
+ )
+ err = out.stdout.decode("utf-8")
+ keys = isctest.kasp.keydir_to_keylist(zone)
+ assert len(keys) == 1
+ assert (
+ f"zone '{zone}': key file '{zone}/RSASHA256/{keys[0].tag}' does not match dnssec-policy default"
+ in err
+ )
+ assert (
+ f"zone '{zone}': no key file found matching dnssec-policy default key:'csk algorithm:ECDSAP256SHA256 length:256 tag-range:0-65535'"
+ in err
+ )
+
+ # Mismatch role (default policy)
+ zone = "bad-default-kz.example"
+ out = isctest.run.cmd(
+ [CHECKCONF, "-k", "bad-default-kz.conf"], raise_on_exception=False
+ )
+ err = out.stdout.decode("utf-8")
+ keys = isctest.kasp.keydir_to_keylist(zone)
+ assert len(keys) == 2
+ assert (
+ f"zone '{zone}': key file '{zone}/ECDSAP256SHA256/{keys[0].tag}' does not match dnssec-policy default"
+ in err
+ )
+ assert (
+ f"zone '{zone}': key file '{zone}/ECDSAP256SHA256/{keys[1].tag}' does not match dnssec-policy default"
+ in err
+ )
+ assert (
+ f"zone '{zone}': no key file found matching dnssec-policy default key:'csk algorithm:ECDSAP256SHA256 length:256 tag-range:0-65535'"
+ in err
+ )
+ assert f"zone '{zone}': wrong number of key files (2, expected 1)" in err
bool check_keys) {
const char *dir = keydir;
isc_result_t ret, result = ISC_R_SUCCESS;
- bool done = false;
bool keystore = false;
const cfg_obj_t *kasps = NULL;
const cfg_obj_t *kaspobj = NULL;
+ const cfg_obj_t *obj = NULL;
+ dns_kasp_t *default_kasp = NULL;
dns_kasp_t *kasp = NULL;
dns_kasplist_t kasplist;
const cfg_obj_t *keystores = NULL;
(void)cfg_keystore_fromconfig(NULL, mctx, &kslist, NULL);
/*
- * Look for the dnssec-policy by name, which is the dnssec-policy
- * for the zone in question.
+ * dnssec-policy "default".
+ */
+ ret = cfg_kasp_builtinconfig(mctx, "default", &kslist, &kasplist,
+ &default_kasp);
+ if (ret != ISC_R_SUCCESS) {
+ cfg_obj_log(config, ISC_LOG_ERROR,
+ "failed to load the 'default' dnssec-policy: %s",
+ isc_result_totext(ret));
+ result = ret;
+ goto check;
+ }
+ dns_kasp_freeze(default_kasp);
+
+ /*
+ * dnssec-policy "insecure".
+ */
+ ret = cfg_kasp_builtinconfig(mctx, "insecure", &kslist, &kasplist,
+ &kasp);
+ if (ret != ISC_R_SUCCESS) {
+ cfg_obj_log(config, ISC_LOG_ERROR,
+ "failed to load the 'insecure' dnssec-policy: %s",
+ isc_result_totext(ret));
+ result = ret;
+ goto check;
+ }
+ dns_kasp_freeze(kasp);
+ dns_kasp_detach(&kasp);
+
+ /*
+ * Configured dnssec-policy clauses.
*/
CFG_LIST_FOREACH(kasps, element) {
cfg_obj_t *kconfig = cfg_listelt_value(element);
- kaspobj = NULL;
+ obj = NULL;
if (!cfg_obj_istuple(kconfig)) {
continue;
}
- kaspobj = cfg_tuple_get(kconfig, "name");
- if (strcmp(name, cfg_obj_asstring(kaspobj)) != 0) {
- continue;
- }
-
- ret = cfg_kasp_fromconfig(kconfig, NULL, 0, mctx, &kslist,
- &kasplist, &kasp);
+ obj = cfg_tuple_get(kconfig, "name");
+ ret = cfg_kasp_fromconfig(kconfig, default_kasp, 0, mctx,
+ &kslist, &kasplist, &kasp);
if (ret != ISC_R_SUCCESS) {
- kasp = NULL;
+ result = ret;
+ goto check;
}
- break;
+ if (strcmp(name, cfg_obj_asstring(obj)) == 0) {
+ kaspobj = obj;
+ dns_kasp_freeze(kasp);
+ }
+ dns_kasp_detach(&kasp);
}
- if (kasp == NULL) {
+
+ /*
+ * Look for the dnssec-policy by name, which is the dnssec-policy
+ * for the zone in question.
+ */
+ ret = dns_kasplist_find(&kasplist, name, &kasp);
+ if (ret != ISC_R_SUCCESS) {
+ cfg_obj_log(config, ISC_LOG_ERROR,
+ "no dnssec-policy found for zone '%s'", zname);
+ result = ISC_R_NOTFOUND;
goto check;
}
- INSIST(kaspobj != NULL);
+ INSIST(kasp != NULL);
+
+ if (kaspobj == NULL) {
+ kaspobj = kasps == NULL ? config : kasps;
+ }
+
+ if (strcmp(name, "insecure") == 0 || strcmp(name, "default") == 0) {
+ ret = keydirexist(zconfig, "key-directory", origin, dir, name,
+ keydirs, mctx);
+ if (ret != ISC_R_SUCCESS) {
+ result = ret;
+ }
+ }
/* Check key-stores of keys */
- dns_kasp_freeze(kasp);
ISC_LIST_FOREACH(dns_kasp_keys(kasp), kkey, link) {
dns_keystore_t *kks = dns_kasp_key_keystore(kkey);
dir = dns_keystore_directory(kks, keydir);
}
}
- dns_kasp_thaw(kasp);
- done = true;
-
check:
- if (!done) {
- ret = keydirexist(zconfig, "key-directory", origin, dir, name,
- keydirs, mctx);
- if (ret != ISC_R_SUCCESS) {
- result = ret;
- }
+ if (default_kasp != NULL) {
+ dns_kasp_detach(&default_kasp);
}
-
if (kasp != NULL) {
dns_kasp_detach(&kasp);
}
*\li Other errors are possible.
*/
+isc_result_t
+cfg_kasp_builtinconfig(isc_mem_t *mctx, const char *name,
+ dns_keystorelist_t *keystorelist,
+ dns_kasplist_t *kasplist, dns_kasp_t **kaspp);
+/*%<
+ * Create built-in KASP.
+ *
+ * If a 'kasplist' is provided, a lookup happens and if a KASP already exists
+ * with the same name, no new KASP is created, and no attach to 'kaspp' happens.
+ *
+ * Requires:
+ *
+ *\li 'mctx' is a valid memory context.
+ *
+ *\li kaspp != NULL && *kaspp == NULL
+ *
+ * Returns:
+ *
+ *\li #ISC_R_SUCCESS If creating and configuring the KASP succeeds.
+ *\li #ISC_R_EXISTS If 'kasplist' already has the default policy.
+ *
+ *\li Other errors are possible.
+ */
+
isc_result_t
cfg_keystore_fromconfig(const cfg_obj_t *config, isc_mem_t *mctx,
dns_keystorelist_t *keystorelist,
/* Now configure. */
INSIST(DNS_KASP_VALID(kasp));
- if (config != NULL) {
- koptions = cfg_tuple_get(config, "options");
- maps[i++] = koptions;
- }
+ koptions = cfg_tuple_get(config, "options");
+ maps[i++] = koptions;
maps[i] = NULL;
/* Configuration: Signatures */
return result;
}
+isc_result_t
+cfg_kasp_builtinconfig(isc_mem_t *mctx, const char *name,
+ dns_keystorelist_t *keystorelist,
+ dns_kasplist_t *kasplist, dns_kasp_t **kaspp) {
+ isc_result_t result;
+ dns_kasp_t *kasp = NULL;
+
+ REQUIRE(kaspp != NULL && *kaspp == NULL);
+ REQUIRE(strcmp(name, "default") == 0 || strcmp(name, "insecure") == 0);
+
+ result = dns_kasplist_find(kasplist, name, &kasp);
+ if (result == ISC_R_SUCCESS) {
+ dns_kasp_detach(&kasp);
+ return ISC_R_EXISTS;
+ }
+ if (result != ISC_R_NOTFOUND) {
+ return result;
+ }
+ result = ISC_R_SUCCESS;
+
+ /* No kasp with configured name was found in list, create new one. */
+ INSIST(kasp == NULL);
+ dns_kasp_create(mctx, name, &kasp);
+ INSIST(kasp != NULL);
+
+ /* Now configure. */
+ INSIST(DNS_KASP_VALID(kasp));
+
+ /* Configuration: Signatures */
+ dns_kasp_setsigjitter(kasp, parse_duration(DNS_KASP_SIG_JITTER));
+ dns_kasp_setsigrefresh(kasp, parse_duration(DNS_KASP_SIG_REFRESH));
+ dns_kasp_setsigvalidity_dnskey(
+ kasp, parse_duration(DNS_KASP_SIG_VALIDITY_DNSKEY));
+ dns_kasp_setsigvalidity(kasp, parse_duration(DNS_KASP_SIG_VALIDITY));
+
+ /* Configuration: Zone settings */
+ dns_kasp_setinlinesigning(kasp, true);
+ dns_kasp_setmanualmode(kasp, false);
+ dns_kasp_setzonemaxttl(kasp, parse_duration(DNS_KASP_ZONE_MAXTTL));
+ dns_kasp_setzonepropagationdelay(
+ kasp, parse_duration(DNS_KASP_ZONE_PROPDELAY));
+
+ /* Configuration: Parent settings */
+ dns_kasp_setdsttl(kasp, parse_duration(DNS_KASP_DS_TTL));
+ dns_kasp_setparentpropagationdelay(
+ kasp, parse_duration(DNS_KASP_PARENT_PROPDELAY));
+
+ /* Configuration: Keys */
+ dns_kasp_setofflineksk(kasp, false);
+ dns_kasp_setcdnskey(kasp, true);
+ dns_kasp_adddigest(kasp, DNS_DSDIGEST_SHA256);
+ dns_kasp_setdnskeyttl(kasp, parse_duration(DNS_KASP_KEY_TTL));
+ dns_kasp_setpublishsafety(kasp,
+ parse_duration(DNS_KASP_PUBLISH_SAFETY));
+ dns_kasp_setretiresafety(kasp, parse_duration(DNS_KASP_RETIRE_SAFETY));
+
+ dns_kasp_setpurgekeys(kasp, parse_duration(DNS_KASP_PURGE_KEYS));
+
+ if (strcmp(name, "default") == 0) {
+ dns_kasp_key_t *new_key = NULL;
+ dns_kasp_key_create(kasp, &new_key);
+ new_key->role |= DNS_KASP_KEY_ROLE_KSK;
+ new_key->role |= DNS_KASP_KEY_ROLE_ZSK;
+ new_key->lifetime = 0;
+ new_key->algorithm = DST_ALG_ECDSA256;
+ new_key->length = 256;
+ result = dns_keystorelist_find(keystorelist,
+ DNS_KEYSTORE_KEYDIRECTORY,
+ &new_key->keystore);
+ if (result != ISC_R_SUCCESS) {
+ goto cleanup;
+ }
+ dns_kasp_addkey(kasp, new_key);
+ }
+
+ /* Configuration: Denial of existence */
+ dns_kasp_setnsec3(kasp, false);
+
+ /* Append it to the list for future lookups. */
+ ISC_LIST_APPEND(*kasplist, kasp, link);
+ INSIST(!(ISC_LIST_EMPTY(*kasplist)));
+
+ /* Success: Attach the kasp to the pointer and return. */
+ dns_kasp_attach(kasp, kaspp);
+
+ /* Don't detach as kasp is on '*kasplist' */
+ return ISC_R_SUCCESS;
+
+cleanup:
+ /* Something bad happened, detach (destroys kasp) and return error. */
+ dns_kasp_detach(&kasp);
+ return result;
+}
+
isc_result_t
cfg_keystore_fromconfig(const cfg_obj_t *config, isc_mem_t *mctx,
dns_keystorelist_t *keystorelist,