diff --git a/bin/named/named.conf.docbook b/bin/named/named.conf.docbook
index ecae8014cc..8221d4cce5 100644
--- a/bin/named/named.conf.docbook
+++ b/bin/named/named.conf.docbook
@@ -842,6 +842,7 @@ view string [ class ] {
dnskey-sig-validity integer;
dnssec-dnskey-kskonly boolean;
dnssec-loadkeys-interval integer;
+ dnssec-policy string;
dnssec-secure-to-insecure boolean;
dnssec-update-mode ( maintain | no-resign );
file quoted_string;
@@ -943,6 +944,7 @@ zone string [ class ] {
dnskey-sig-validity integer;
dnssec-dnskey-kskonly boolean;
dnssec-loadkeys-interval integer;
+ dnssec-policy string;
dnssec-secure-to-insecure boolean;
dnssec-update-mode ( maintain | no-resign );
file quoted_string;
@@ -1008,6 +1010,21 @@ zone string [ class ] {
+ DNSSEC-POLICY
+
+
+dnssec-policy string {
+ dnskey-ttl ttlval;
+ keys { ( csk | ksk | zsk ) key-directory duration integer [ integer ] ; ... };
+ publish-safety duration;
+ retire-safety duration;
+ signatures-refresh duration;
+ signatures-validity duration;
+ signatures-validity-dnskey duration;
+};
+
+
+
FILES
/etc/named.conf
diff --git a/bin/tests/system/checkconf/bad-kasp1.conf b/bin/tests/system/checkconf/bad-kasp1.conf
new file mode 100644
index 0000000000..bad8ff2090
--- /dev/null
+++ b/bin/tests/system/checkconf/bad-kasp1.conf
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * 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 http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+options {
+ dnssec-policy "notatzonelevel";
+};
+
+zone "example.net" {
+ type master;
+ file "example.db";
+};
+
diff --git a/bin/tests/system/checkconf/bad-kasp2.conf b/bin/tests/system/checkconf/bad-kasp2.conf
new file mode 100644
index 0000000000..a7b44ab6d0
--- /dev/null
+++ b/bin/tests/system/checkconf/bad-kasp2.conf
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * 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 http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+include "good-kasp.conf";
+
+// Bad zone configuration because this has dnssec-policy and other DNSSEC sign
+// configuration options (auto-dnssec).
+zone "example.net" {
+ type master;
+ file "example.db";
+ dnssec-policy "test";
+ auto-dnssec maintain;
+ allow-update { any; };
+};
diff --git a/bin/tests/system/checkconf/bad-kasp3.conf b/bin/tests/system/checkconf/bad-kasp3.conf
new file mode 100644
index 0000000000..104100dc59
--- /dev/null
+++ b/bin/tests/system/checkconf/bad-kasp3.conf
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * 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 http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+include "good-kasp.conf";
+
+// Bad zone configuration because this has dnssec-policy with no matching
+// dnssec-policy configuration (good-kasp.conf has "test", zone refers to
+// "nosuchpolicy".
+zone "example.net" {
+ type master;
+ file "example.db";
+ dnssec-policy "nosuchpolicy";
+};
+
diff --git a/bin/tests/system/checkconf/bad-kasp4.conf b/bin/tests/system/checkconf/bad-kasp4.conf
new file mode 100644
index 0000000000..efb2cbefa8
--- /dev/null
+++ b/bin/tests/system/checkconf/bad-kasp4.conf
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * 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 http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+// Bad kasp configuration because this has an invalid duration for
+// signatures-refresh.
+dnssec-policy "badduration" {
+ signatures-refresh PT20Sabcd;
+};
+
+zone "example.net" {
+ type master;
+ file "example.db";
+ dnssec-policy "badduration";
+};
+
diff --git a/bin/tests/system/checkconf/clean.sh b/bin/tests/system/checkconf/clean.sh
index 9ac839b09d..989daff341 100644
--- a/bin/tests/system/checkconf/clean.sh
+++ b/bin/tests/system/checkconf/clean.sh
@@ -10,6 +10,7 @@
# information regarding copyright ownership.
rm -f good.conf.in good.conf.out badzero.conf *.out
+rm -f good-kasp.conf.in
rm -rf test.keydir
rm -f checkconf.out*
rm -f diff.out*
diff --git a/bin/tests/system/checkconf/good-kasp.conf b/bin/tests/system/checkconf/good-kasp.conf
new file mode 100644
index 0000000000..804637a345
--- /dev/null
+++ b/bin/tests/system/checkconf/good-kasp.conf
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * 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 http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+/*
+ * This is just a random selection of DNSSEC configuration options.
+ */
+
+/* cut here */
+dnssec-policy "test" {
+ dnskey-ttl 3600;
+ keys {
+ ksk key-directory P1Y 13 256;
+ zsk key-directory P30D 13;
+ csk key-directory P30D 8 2048;
+ };
+ publish-safety PT3600S;
+ retire-safety PT3600S;
+ signatures-refresh P3D;
+ signatures-validity P2W;
+ signatures-validity-dnskey P14D;
+ zone-max-ttl 86400;
+ zone-propagation-delay PT5M;
+ parent-ds-ttl 7200;
+ parent-propagation-delay PT1H;
+ parent-registration-delay P1D;
+};
+options {
+ dnssec-policy "default";
+};
+zone "example1" {
+ type master;
+ dnssec-policy "test";
+ file "example1.db";
+};
+zone "example2" {
+ type master;
+ dnssec-policy "default";
+ file "example2.db";
+};
diff --git a/bin/tests/system/checkconf/kasp-and-other-dnssec-options.conf b/bin/tests/system/checkconf/kasp-and-other-dnssec-options.conf
new file mode 100644
index 0000000000..d7c1bf8123
--- /dev/null
+++ b/bin/tests/system/checkconf/kasp-and-other-dnssec-options.conf
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * 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 http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+include "good-kasp.conf";
+
+zone "nsec3.net" {
+ type master;
+ file "nsec3.db";
+ dnssec-policy "test";
+ auto-dnssec maintain;
+ dnskey-sig-validity 3600;
+ dnssec-dnskey-kskonly yes;
+ dnssec-secure-to-insecure yes;
+ dnssec-update-mode maintain;
+ inline-signing yes;
+ sig-validity-interval 3600;
+ update-check-ksk yes;
+ allow-update { any; };
+};
+
diff --git a/bin/tests/system/checkconf/tests.sh b/bin/tests/system/checkconf/tests.sh
index 6146754320..45e6cefb42 100644
--- a/bin/tests/system/checkconf/tests.sh
+++ b/bin/tests/system/checkconf/tests.sh
@@ -466,5 +466,38 @@ grep "'geoip-use-ecs' is obsolete" < checkconf.out$n > /dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; ret=1; fi
status=`expr $status + $ret`
+n=`expr $n + 1`
+echo_i "checking named-checkconf kasp warnings ($n)"
+ret=0
+$CHECKCONF kasp-and-other-dnssec-options.conf > checkconf.out$n 2>&1
+grep "'auto-dnssec maintain;' cannot be configured if dnssec-policy is also set" < checkconf.out$n > /dev/null || ret=1
+grep "dnskey-sig-validity: cannot be configured if dnssec-policy is also set" < checkconf.out$n > /dev/null || ret=1
+grep "dnssec-dnskey-kskonly: cannot be configured if dnssec-policy is also set" < checkconf.out$n > /dev/null || ret=1
+grep "dnssec-secure-to-insecure: cannot be configured if dnssec-policy is also set" < checkconf.out$n > /dev/null || ret=1
+grep "dnssec-update-mode: cannot be configured if dnssec-policy is also set" < checkconf.out$n > /dev/null || ret=1
+grep "inline-signing: cannot be configured if dnssec-policy is also set" < checkconf.out$n > /dev/null || ret=1
+grep "sig-validity-interval: cannot be configured if dnssec-policy is also set" < checkconf.out$n > /dev/null || ret=1
+grep "update-check-ksk: cannot be configured if dnssec-policy is also set" < checkconf.out$n > /dev/null || ret=1
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=`expr $status + $ret`
+
+n=`expr $n + 1`
+echo_i "check that a good 'kasp' configuration is accepted ($n)"
+ret=0
+$CHECKCONF good-kasp.conf > checkconf.out$n 2>/dev/null || ret=1
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=`expr $status + $ret`
+
+n=`expr $n + 1`
+echo_i "checking that named-checkconf prints a known good kasp config ($n)"
+ret=0
+awk 'BEGIN { ok = 0; } /cut here/ { ok = 1; getline } ok == 1 { print }' good-kasp.conf > good-kasp.conf.in
+[ -s good-kasp.conf.in ] || ret=1
+$CHECKCONF -p good-kasp.conf.in | grep -v '^good-kasp.conf.in:' > good-kasp.conf.out 2>&1 || ret=1
+cmp good-kasp.conf.in good-kasp.conf.out || ret=1
+
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=`expr $status + $ret`
+
echo_i "exit status: $status"
[ $status -eq 0 ] || exit 1
diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml
index 96fcb0fb24..47b08440ef 100644
--- a/doc/arm/Bv9ARM-book.xml
+++ b/doc/arm/Bv9ARM-book.xml
@@ -3120,6 +3120,16 @@ $ORIGIN 0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.
+
+
+ dnssec-policy
+
+
+
+ describes a DNSSEC key and signing policy for zones.
+
+
+
include
@@ -11004,6 +11014,147 @@ example.com CNAME rpz-tcp-only.
+ dnssec-policy Statement Grammar
+
+
+
+ dnssec-policy Statement Definition
+ and Usage
+
+
+ The dnssec-policy statement defines a key and
+ signing policy (KASP) for zones.
+
+
+ KASP is used to determine how one or more zones need to be signed
+ with DNSSEC. For example, how often RRSIG records need to be
+ refreshed, or what cryptographic algorithms to use.
+
+
+ You can configure multiple policies. To attach a policy to a zone
+ simply add dnssec-policy "policy_name"
+ option to the zone statement with a matching
+ policy name.
+
+
+
+
+
+ dnskey-ttl
+
+
+ The TTL of the DNSKEY resource records.
+ Default is 3600 seconds.
+
+
+
+
+
+ keys
+
+
+ A list of keys to use. Each line represents one key. Here is
+ an example (for illustration purposes only) of some possible
+ keys in a dnssec-policy:
+
+
+keys {
+ ksk key-directory P5Y 8 2048;
+ zsk key-directory P30D 8;
+ csk key-directory P6MT12H3M15S 13;
+};
+
+
+
+ This example lists three keys. The first token determines
+ what RRsets the key will sign. If set to
+ ksk the key will sign the DNSKEY, CDS,
+ and CDNSKEY RRsets, if set to zsk the
+ key will sign the other RRsets, and if set to
+ csk the key will sign all RRsets.
+
+
+ The following part determines where the key will be stored.
+ Currently keys can only be stored in the configured
+ key-directory.
+
+
+ The third token tells how long the key may be used. In the
+ example the first key has a lifetime of 5 years, the second
+ key may be used for 30 days and the third key has a rather
+ peculiar lifetime of 6 months, 12 hours, 3 minutes and 15
+ seconds.
+
+
+ The last token(s) are the key's algorithm and algorithm length.
+ The length may be omitted as shown in the example for the
+ second and third key.
+
+
+
+
+
+ publish-safety
+
+
+ A margin that is added to the publish interval in key timing
+ equations to give some extra time to cover unforeseen events.
+ Default is PT5M (5 minutes).
+
+
+
+
+
+ retire-safety
+
+
+ A margin that is added to the retire interval in key timing
+ equations to give some extra time to cover unforeseen events.
+ Default is PT5M (5 minutes).
+
+
+
+
+
+ signatures-refresh
+
+
+ This determines when a RRSIG record needs to be refreshed.
+ The signatures is renewed when the time until the expiration
+ time is closer than signatures-refresh.
+ signatures-resign interval.
+ Default is P5D (5 days), meaning a
+ signature that will expire in 5 days or sooner will be
+ refreshed.
+
+
+
+
+
+ signatures-validity
+
+
+ The validity period of an RRSIG record (minus the inception
+ offset and jitter). Default is P2W
+ (2 weeks).
+
+
+
+
+
+ signatures-validity-dnskey
+
+
+ Like signatures-validity but for DNSKEY
+ records. Default is P2W (2 weeks).
+
+
+
+
+
+
+
+
managed-keys Statement Grammar
@@ -11878,6 +12029,17 @@ view "external" {
+
+ dnssec-policy
+
+
+ The key and signing policy for this zone. Set to
+ "default" if you want to make use
+ of the default policy.
+
+
+
+
dnssec-update-mode
diff --git a/doc/arm/dnssec-policy.grammar.xml b/doc/arm/dnssec-policy.grammar.xml
new file mode 100644
index 0000000000..68e27d964c
--- /dev/null
+++ b/doc/arm/dnssec-policy.grammar.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+dnssec-policy string {
+ dnskey-ttl ttlval;
+ keys { ( csk | ksk | zsk ) key-directory duration integer [ integer ] ; ... };
+ publish-safety duration;
+ retire-safety duration;
+ signatures-refresh duration;
+ signatures-validity duration;
+ signatures-validity-dnskey duration;
+};
+
+
diff --git a/doc/arm/master.zoneopt.xml b/doc/arm/master.zoneopt.xml
index 0ed86ecc75..054b440492 100644
--- a/doc/arm/master.zoneopt.xml
+++ b/doc/arm/master.zoneopt.xml
@@ -36,6 +36,7 @@
dnskey-sig-validity integer;
dnssec-dnskey-kskonly boolean;
dnssec-loadkeys-interval integer;
+ dnssec-policy string;
dnssec-secure-to-insecure boolean;
dnssec-update-mode ( maintain | no-resign );
file quoted_string;
diff --git a/doc/arm/slave.zoneopt.xml b/doc/arm/slave.zoneopt.xml
index 63c0a4acf1..e78f296119 100644
--- a/doc/arm/slave.zoneopt.xml
+++ b/doc/arm/slave.zoneopt.xml
@@ -29,6 +29,7 @@
dnskey-sig-validity integer;
dnssec-dnskey-kskonly boolean;
dnssec-loadkeys-interval integer;
+ dnssec-policy string;
dnssec-update-mode ( maintain | no-resign );
file quoted_string;
forward ( first | only );
diff --git a/doc/design/dnssec-policy b/doc/design/dnssec-policy
index 2079c8edc2..3e695a2c39 100644
--- a/doc/design/dnssec-policy
+++ b/doc/design/dnssec-policy
@@ -122,7 +122,6 @@ dnssec-policy "nsec3" {
description "policy for zones that require zone walking mitigation";
// Signatures
- signatures-resign PT2H;
signatures-refresh P3D;
signatures-validity P14D;
signatures-validity-dnskey P14D;
diff --git a/doc/misc/master.zoneopt b/doc/misc/master.zoneopt
index aa55ed33e8..694d84eb69 100644
--- a/doc/misc/master.zoneopt
+++ b/doc/misc/master.zoneopt
@@ -23,6 +23,7 @@ zone [ ] {
dnskey-sig-validity ;
dnssec-dnskey-kskonly ;
dnssec-loadkeys-interval ;
+ dnssec-policy ;
dnssec-secure-to-insecure ;
dnssec-update-mode ( maintain | no-resign );
file ;
diff --git a/doc/misc/options b/doc/misc/options
index 509cc38cf9..6f5674692c 100644
--- a/doc/misc/options
+++ b/doc/misc/options
@@ -25,6 +25,17 @@ dnssec-keys { ( static-key |
initial-key )
; ... }; // may occur multiple times
+dnssec-policy {
+ dnskey-ttl ;
+ keys { ( csk | ksk | zsk ) key-directory
+ [ ]; ... };
+ publish-safety ;
+ retire-safety ;
+ signatures-refresh ;
+ signatures-validity ;
+ signatures-validity-dnskey ;
+}; // may occur multiple times
+
dyndb {
}; // may occur multiple times
diff --git a/doc/misc/slave.zoneopt b/doc/misc/slave.zoneopt
index 750392f254..2dc3fd535c 100644
--- a/doc/misc/slave.zoneopt
+++ b/doc/misc/slave.zoneopt
@@ -16,6 +16,7 @@ zone [ ] {
dnskey-sig-validity ;
dnssec-dnskey-kskonly ;
dnssec-loadkeys-interval ;
+ dnssec-policy ;
dnssec-update-mode ( maintain | no-resign );
file ;
forward ( first | only );
diff --git a/lib/bind9/check.c b/lib/bind9/check.c
index 86d7482157..73fb59bf82 100644
--- a/lib/bind9/check.c
+++ b/lib/bind9/check.c
@@ -856,6 +856,7 @@ check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx,
const char *str;
isc_buffer_t b;
uint32_t lifetime = 3600;
+ bool has_dnssecpolicy = false;
const char *ccalg = "siphash24";
/*
@@ -948,6 +949,44 @@ check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx,
}
}
+ /*
+ * Check dnssec-policy at the view/options level
+ */
+ obj = NULL;
+ (void)cfg_map_get(options, "dnssec-policy", &obj);
+ if (obj != NULL) {
+ bool bad_kasp = true;
+ if (optlevel == optlevel_zone && cfg_obj_isstring(obj)) {
+ bad_kasp = false;
+ } else if (optlevel == optlevel_config) {
+ if (cfg_obj_islist(obj)) {
+ for (element = cfg_list_first(obj);
+ element != NULL;
+ element = cfg_list_next(element))
+ {
+ if (!cfg_obj_istuple(
+ cfg_listelt_value(element)))
+ {
+ break;
+ }
+ }
+ bad_kasp = false;
+ }
+ }
+
+ if (bad_kasp) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "dnssec-policy may only be activated at "
+ "the top level and referenced to at the "
+ "zone level");
+ if (result == ISC_R_SUCCESS) {
+ result = ISC_R_FAILURE;
+ }
+ }
+
+ has_dnssecpolicy = true;
+ }
+
obj = NULL;
cfg_map_get(options, "max-rsa-exponent-size", &obj);
if (obj != NULL) {
@@ -996,6 +1035,13 @@ check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx,
result = ISC_R_RANGE;
}
}
+
+ if (has_dnssecpolicy) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "sig-validity-interval: cannot be "
+ "configured if dnssec-policy is also set");
+ result = ISC_R_FAILURE;
+ }
}
obj = NULL;
@@ -1012,6 +1058,12 @@ check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx,
result = ISC_R_RANGE;
}
+ if (has_dnssecpolicy) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "dnskey-sig-validity: cannot be "
+ "configured if dnssec-policy is also set");
+ result = ISC_R_FAILURE;
+ }
}
obj = NULL;
@@ -1117,8 +1169,9 @@ check_options(const cfg_obj_t *options, isc_log_t *logctx, isc_mem_t *mctx,
if (result == ISC_R_SUCCESS && tresult != ISC_R_SUCCESS)
result = tresult;
}
- if (symtab != NULL)
+ if (symtab != NULL) {
isc_symtab_destroy(&symtab);
+ }
}
/*
@@ -1858,6 +1911,7 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
bool dlz;
dns_masterformat_t masterformat;
bool ddns = false;
+ bool has_dnssecpolicy = false;
const void *clauses = NULL;
const char *option = NULL;
static const char *acls[] = {
@@ -2070,6 +2124,42 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
if (check_nonzero(zoptions, logctx) != ISC_R_SUCCESS)
result = ISC_R_FAILURE;
+ /*
+ * Check if a dnssec-policy is set.
+ */
+ obj = NULL;
+ (void)cfg_map_get(zoptions, "dnssec-policy", &obj);
+ if (obj != NULL) {
+ const cfg_obj_t *kasps = NULL;
+ const char* kaspname = cfg_obj_asstring(obj);
+
+ if (strcmp(kaspname, "default") == 0) {
+ has_dnssecpolicy = true;
+ } else {
+ (void)cfg_map_get(config, "dnssec-policy", &kasps);
+ for (element = cfg_list_first(kasps); element != NULL;
+ element = cfg_list_next(element))
+ {
+ const char* kn = cfg_obj_asstring(
+ cfg_tuple_get(cfg_listelt_value(element),
+ "name"));
+ if (strcmp(kaspname, kn) == 0) {
+ has_dnssecpolicy = true;
+ }
+ }
+ }
+
+ if (!has_dnssecpolicy) {
+ cfg_obj_log(zconfig, logctx, ISC_LOG_ERROR,
+ "zone '%s': option 'dnssec-policy %s' "
+ "has no matching dnssec-policy config",
+ znamestr, kaspname);
+ if (result == ISC_R_SUCCESS) {
+ result = ISC_R_FAILURE;
+ }
+ }
+ }
+
/*
* Check validity of the zone options.
*/
@@ -2256,19 +2346,36 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
if (res1 == ISC_R_SUCCESS)
signing = cfg_obj_asboolean(obj);
+ if (signing && has_dnssecpolicy) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "inline-signing: cannot be configured if "
+ "dnssec-policy is also set");
+ result = ISC_R_FAILURE;
+ }
+
obj = NULL;
arg = "off";
res3 = cfg_map_get(zoptions, "auto-dnssec", &obj);
- if (res3 == ISC_R_SUCCESS)
+ if (res3 == ISC_R_SUCCESS) {
arg = cfg_obj_asstring(obj);
- if (strcasecmp(arg, "off") != 0 && !ddns && !signing) {
- cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
- "'auto-dnssec %s;' requires%s "
- "inline-signing to be configured for "
- "the zone", arg,
- (ztype == CFG_ZONE_MASTER) ?
- " dynamic DNS or" : "");
- result = ISC_R_FAILURE;
+ }
+ if (strcasecmp(arg, "off") != 0) {
+ if (!ddns && !signing) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "'auto-dnssec %s;' requires%s "
+ "inline-signing to be configured "
+ "for the zone", arg,
+ (ztype == CFG_ZONE_MASTER) ?
+ " dynamic DNS or" : "");
+ result = ISC_R_FAILURE;
+ }
+ if (has_dnssecpolicy) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "'auto-dnssec %s;' cannot be "
+ "configured if dnssec-policy is "
+ "also set", arg);
+ result = ISC_R_FAILURE;
+ }
}
obj = NULL;
@@ -2293,6 +2400,21 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
"inline-signing when used in slave zone");
result = ISC_R_FAILURE;
}
+ if (res1 == ISC_R_SUCCESS && has_dnssecpolicy) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "dnssec-dnskey-kskonly: cannot be "
+ "configured if dnssec-policy is also set");
+ result = ISC_R_FAILURE;
+ }
+
+ obj = NULL;
+ res1 = cfg_map_get(zoptions, "dnssec-secure-to-insecure", &obj);
+ if (res1 == ISC_R_SUCCESS && has_dnssecpolicy) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "dnssec-secure-to-insecure: cannot be "
+ "configured if dnssec-policy is also set");
+ result = ISC_R_FAILURE;
+ }
obj = NULL;
res1 = cfg_map_get(zoptions, "dnssec-loadkeys-interval", &obj);
@@ -2315,6 +2437,21 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
"inline-signing when used in slave zone");
result = ISC_R_FAILURE;
}
+ if (res1 == ISC_R_SUCCESS && has_dnssecpolicy) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "update-check-ksk: cannot be configured "
+ "if dnssec-policy is also set");
+ result = ISC_R_FAILURE;
+ }
+
+ obj = NULL;
+ res1 = cfg_map_get(zoptions, "dnssec-update-mode", &obj);
+ if (res1 == ISC_R_SUCCESS && has_dnssecpolicy) {
+ cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
+ "dnssec-update-mode: cannot be configured "
+ "if dnssec-policy is also set");
+ result = ISC_R_FAILURE;
+ }
}
/*
diff --git a/lib/isccfg/include/isccfg/namedconf.h b/lib/isccfg/include/isccfg/namedconf.h
index f75e56191f..f4f2c39ba1 100644
--- a/lib/isccfg/include/isccfg/namedconf.h
+++ b/lib/isccfg/include/isccfg/namedconf.h
@@ -49,4 +49,7 @@ LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_keyref;
/*%< Zone options */
LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_zoneopts;
+/*%< DNSSEC Key and Signing Policy options */
+LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_dnssecpolicyopts;
+
#endif /* ISCCFG_NAMEDCONF_H */
diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c
index 3282a8b01f..100cb0979d 100644
--- a/lib/isccfg/namedconf.c
+++ b/lib/isccfg/namedconf.c
@@ -18,6 +18,7 @@
#include
#include
+#include
#include
#include
#include
@@ -82,6 +83,7 @@ static cfg_type_t cfg_type_controls_sockaddr;
static cfg_type_t cfg_type_destinationlist;
static cfg_type_t cfg_type_dialuptype;
static cfg_type_t cfg_type_dlz;
+static cfg_type_t cfg_type_dnssecpolicy;
static cfg_type_t cfg_type_dnstap;
static cfg_type_t cfg_type_dnstapoutput;
static cfg_type_t cfg_type_dyndb;
@@ -410,6 +412,20 @@ static cfg_type_t cfg_type_zone = {
&cfg_rep_tuple, zone_fields
};
+/*%
+ * A dnssec-policy statement.
+ */
+static cfg_tuplefielddef_t dnssecpolicy_fields[] = {
+ { "name", &cfg_type_astring, 0 },
+ { "options", &cfg_type_dnssecpolicyopts, 0 },
+ { NULL, NULL, 0 }
+};
+
+static cfg_type_t cfg_type_dnssecpolicy = {
+ "dnssec-policy", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, dnssecpolicy_fields
+};
+
/*%
* A "category" clause in the "logging" statement.
*/
@@ -465,6 +481,40 @@ static cfg_type_t cfg_type_managedkey = {
&cfg_rep_tuple, managedkey_fields
};
+/*%
+ * DNSSEC key roles.
+ */
+static const char *dnsseckeyrole_enums[] = { "csk", "ksk", "zsk", NULL };
+static cfg_type_t cfg_type_dnsseckeyrole = {
+ "dnssec-key-role", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
+ &cfg_rep_string, &dnsseckeyrole_enums
+};
+
+/*%
+ * DNSSEC key storage types.
+ */
+static const char *dnsseckeystore_enums[] = { "key-directory", NULL };
+static cfg_type_t cfg_type_dnsseckeystore = {
+ "dnssec-key-storage", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
+ &cfg_rep_string, &dnsseckeystore_enums
+};
+
+/*%
+ * A dnssec key, as used in the "keys" statement in a "dnssec-policy".
+ */
+static cfg_tuplefielddef_t kaspkey_fields[] = {
+ { "role", &cfg_type_dnsseckeyrole, 0 },
+ { "keystore-type", &cfg_type_dnsseckeystore, 0 },
+ { "lifetime", &cfg_type_duration, 0 },
+ { "algorithm", &cfg_type_uint32, 0 },
+ { "length", &cfg_type_optional_uint32, 0 },
+ { NULL, NULL, 0 }
+};
+static cfg_type_t cfg_type_kaspkey = {
+ "kaspkey", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple,
+ &cfg_rep_tuple, kaspkey_fields
+};
+
static keyword_type_t wild_class_kw = { "class", &cfg_type_ustring };
static cfg_type_t cfg_type_optional_wild_class = {
@@ -637,6 +687,14 @@ static cfg_type_t cfg_type_dnsseckeys = {
cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_managedkey
};
+/*%
+ * A list of key entries, used in a DNSSEC Key and Signing Policy.
+ */
+static cfg_type_t cfg_type_kaspkeys = {
+ "kaspkeys", cfg_parse_bracketed_list, cfg_print_bracketed_list,
+ cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_kaspkey
+};
+
static const char *forwardtype_enums[] = { "first", "only", NULL };
static cfg_type_t cfg_type_forwardtype = {
"forwardtype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum,
@@ -962,6 +1020,7 @@ static cfg_clausedef_t
namedconf_clauses[] = {
{ "acl", &cfg_type_acl, CFG_CLAUSEFLAG_MULTI },
{ "controls", &cfg_type_controls, CFG_CLAUSEFLAG_MULTI },
+ { "dnssec-policy", &cfg_type_dnssecpolicy, CFG_CLAUSEFLAG_MULTI },
{ "logging", &cfg_type_logging, 0 },
{ "lwres", &cfg_type_bracketed_text,
CFG_CLAUSEFLAG_MULTI | CFG_CLAUSEFLAG_OBSOLETE },
@@ -1997,6 +2056,21 @@ static cfg_type_t cfg_type_validityinterval = {
&cfg_rep_tuple, validityinterval_fields
};
+/*%
+ * Clauses that can be found in a 'dnssec-policy' statement.
+ */
+static cfg_clausedef_t
+dnssecpolicy_clauses[] = {
+ { "dnskey-ttl", &cfg_type_duration, 0 },
+ { "keys", &cfg_type_kaspkeys, 0 },
+ { "publish-safety", &cfg_type_duration, 0 },
+ { "retire-safety", &cfg_type_duration, 0 },
+ { "signatures-refresh", &cfg_type_duration, 0 },
+ { "signatures-validity", &cfg_type_duration, 0 },
+ { "signatures-validity-dnskey", &cfg_type_duration, 0 },
+ { NULL, NULL, 0 }
+};
+
/*%
* Clauses that can be found in a 'zone' statement,
* with defaults in the 'view' or 'options' statement.
@@ -2241,6 +2315,9 @@ zone_only_clauses[] = {
{ "dlz", &cfg_type_astring,
CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_REDIRECT
},
+ { "dnssec-policy", &cfg_type_astring,
+ CFG_ZONE_MASTER | CFG_ZONE_SLAVE
+ },
{ "file", &cfg_type_qstring,
CFG_ZONE_MASTER | CFG_ZONE_SLAVE | CFG_ZONE_MIRROR |
CFG_ZONE_STUB | CFG_ZONE_HINT | CFG_ZONE_REDIRECT
@@ -2345,6 +2422,16 @@ LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_zoneopts = {
"zoneopts", cfg_parse_map, cfg_print_map,
cfg_doc_map, &cfg_rep_map, zone_clausesets };
+/*% The "dnssec-policy" statement syntax. */
+static cfg_clausedef_t *
+dnssecpolicy_clausesets[] = {
+ dnssecpolicy_clauses,
+ NULL
+};
+LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_dnssecpolicyopts = {
+ "dnssecpolicyopts", cfg_parse_map, cfg_print_map,
+ cfg_doc_map, &cfg_rep_map, dnssecpolicy_clausesets };
+
/*% The "dynamically loadable zones" statement syntax. */
static cfg_clausedef_t
diff --git a/util/copyrights b/util/copyrights
index 31f059b23b..1f7fef1d1d 100644
--- a/util/copyrights
+++ b/util/copyrights
@@ -1410,6 +1410,7 @@
./doc/arm/delegation-only.zoneopt.xml SGML 2018,2019
./doc/arm/dlz.xml SGML 2012,2013,2014,2015,2016,2018,2019
./doc/arm/dnssec-keys.grammar.xml SGML 2019
+./doc/arm/dnssec-policy.grammar.xml SGML 2019
./doc/arm/dnssec.xml SGML 2010,2011,2015,2016,2017,2018,2019
./doc/arm/dyndb.xml SGML 2015,2016,2018,2019
./doc/arm/forward.zoneopt.xml SGML 2018,2019