]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Introduce dnssec-policy configuration
authorMatthijs Mekking <matthijs@isc.org>
Mon, 2 Sep 2019 14:24:48 +0000 (16:24 +0200)
committerMatthijs Mekking <matthijs@isc.org>
Wed, 6 Nov 2019 21:31:44 +0000 (22:31 +0100)
This commit introduces the initial `dnssec-policy` configuration
statement. It has an initial set of options to deal with signature
and key maintenance.

Add some checks to ensure that dnssec-policy is configured at the
right locations, and that policies referenced to in zone statements
actually exist.

Add some checks that when a user adds the new `dnssec-policy`
configuration, it will no longer contain existing DNSSEC
configuration options.  Specifically: `inline-signing`,
`auto-dnssec`, `dnssec-dnskey-kskonly`, `dnssec-secure-to-insecure`,
`update-check-ksk`, `dnssec-update-mode`, `dnskey-sig-validity`,
and `sig-validity-interval`.

Test a good kasp configuration, and some bad configurations.

21 files changed:
bin/named/named.conf.docbook
bin/tests/system/checkconf/bad-kasp1.conf [new file with mode: 0644]
bin/tests/system/checkconf/bad-kasp2.conf [new file with mode: 0644]
bin/tests/system/checkconf/bad-kasp3.conf [new file with mode: 0644]
bin/tests/system/checkconf/bad-kasp4.conf [new file with mode: 0644]
bin/tests/system/checkconf/clean.sh
bin/tests/system/checkconf/good-kasp.conf [new file with mode: 0644]
bin/tests/system/checkconf/kasp-and-other-dnssec-options.conf [new file with mode: 0644]
bin/tests/system/checkconf/tests.sh
doc/arm/Bv9ARM-book.xml
doc/arm/dnssec-policy.grammar.xml [new file with mode: 0644]
doc/arm/master.zoneopt.xml
doc/arm/slave.zoneopt.xml
doc/design/dnssec-policy
doc/misc/master.zoneopt
doc/misc/options
doc/misc/slave.zoneopt
lib/bind9/check.c
lib/isccfg/include/isccfg/namedconf.h
lib/isccfg/namedconf.c
util/copyrights

index ecae8014cc412c49a4d0a567e30a267f28b94506..8221d4cce5a428fb52c5891b33cfadca7647ac60 100644 (file)
@@ -842,6 +842,7 @@ view <replaceable>string</replaceable> [ <replaceable>class</replaceable> ] {
                dnskey-sig-validity <replaceable>integer</replaceable>;
                dnssec-dnskey-kskonly <replaceable>boolean</replaceable>;
                dnssec-loadkeys-interval <replaceable>integer</replaceable>;
+               dnssec-policy <replaceable>string</replaceable>;
                dnssec-secure-to-insecure <replaceable>boolean</replaceable>;
                dnssec-update-mode ( maintain | no-resign );
                file <replaceable>quoted_string</replaceable>;
@@ -943,6 +944,7 @@ zone <replaceable>string</replaceable> [ <replaceable>class</replaceable> ] {
        dnskey-sig-validity <replaceable>integer</replaceable>;
        dnssec-dnskey-kskonly <replaceable>boolean</replaceable>;
        dnssec-loadkeys-interval <replaceable>integer</replaceable>;
+       dnssec-policy <replaceable>string</replaceable>;
        dnssec-secure-to-insecure <replaceable>boolean</replaceable>;
        dnssec-update-mode ( maintain | no-resign );
        file <replaceable>quoted_string</replaceable>;
@@ -1008,6 +1010,21 @@ zone <replaceable>string</replaceable> [ <replaceable>class</replaceable> ] {
 </literallayout>
   </refsection>
 
+  <refsection><info><title>DNSSEC-POLICY</title></info>
+
+    <literallayout class="normal">
+dnssec-policy <replaceable>string</replaceable> {
+       dnskey-ttl <replaceable>ttlval</replaceable>;
+       keys { ( csk | ksk | zsk ) key-directory <replaceable>duration</replaceable> <replaceable>integer</replaceable> [ <replaceable>integer</replaceable> ] ; ... };
+       publish-safety <replaceable>duration</replaceable>;
+       retire-safety <replaceable>duration</replaceable>;
+       signatures-refresh <replaceable>duration</replaceable>;
+       signatures-validity <replaceable>duration</replaceable>;
+       signatures-validity-dnskey <replaceable>duration</replaceable>;
+};
+</literallayout>
+  </refsection>
+
   <refsection><info><title>FILES</title></info>
 
     <para><filename>/etc/named.conf</filename>
diff --git a/bin/tests/system/checkconf/bad-kasp1.conf b/bin/tests/system/checkconf/bad-kasp1.conf
new file mode 100644 (file)
index 0000000..bad8ff2
--- /dev/null
@@ -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 (file)
index 0000000..a7b44ab
--- /dev/null
@@ -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 (file)
index 0000000..104100d
--- /dev/null
@@ -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 (file)
index 0000000..efb2cbe
--- /dev/null
@@ -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";
+};
+
index 9ac839b09dc1cd4e73f7ee6545b3064e11906da5..989daff341ffa94cecb55b858ced2e3700880d63 100644 (file)
@@ -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 (file)
index 0000000..804637a
--- /dev/null
@@ -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 (file)
index 0000000..d7c1bf8
--- /dev/null
@@ -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; };
+};
+
index 6146754320caf676f2a9be1824b315de8837f744..45e6cefb4211c59273395ec8237ef9d07b5c7766 100644 (file)
@@ -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
index 96fcb0fb24c088d525bf0d20e30e7432e19832b6..47b08440ef678bf417f2e84a6b0f42ba51da5b8c 100644 (file)
@@ -3120,6 +3120,16 @@ $ORIGIN 0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa.
                </para>
              </entry>
            </row>
+           <row rowsep="0">
+             <entry colname="1">
+               <para><command>dnssec-policy</command></para>
+             </entry>
+             <entry colname="2">
+               <para>
+                 describes a DNSSEC key and signing policy for zones.
+               </para>
+             </entry>
+           </row>
            <row rowsep="0">
              <entry colname="1">
                <para><command>include</command></para>
@@ -11004,6 +11014,147 @@ example.com                 CNAME   rpz-tcp-only.
          </para>
        </section>
 
+       <section xml:id="dnssec_policy_grammar"><info><title><command>dnssec-policy</command> Statement Grammar</title></info>
+       <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="dnssec-policy.grammar.xml"/>
+       </section>
+
+       <section xml:id="dnssec_policy"><info><title><command>dnssec-policy</command> Statement Definition
+           and Usage</title></info>
+
+         <para>
+           The <command>dnssec-policy</command> statement defines a key and
+           signing policy (KASP) for zones.
+         </para>
+         <para>
+           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.
+         </para>
+         <para>
+           You can configure multiple policies.  To attach a policy to a zone
+           simply add <userinput>dnssec-policy "policy_name"</userinput>
+           option to the <command>zone</command> statement with a matching
+           policy name.
+         </para>
+
+         <variablelist>
+
+           <varlistentry>
+             <term><command>dnskey-ttl</command></term>
+             <listitem>
+               <para>
+               The TTL of the DNSKEY resource records.
+               Default is <constant>3600</constant> seconds.
+               </para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><command>keys</command></term>
+             <listitem>
+               <para>
+               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 <command>dnssec-policy</command>:
+               </para>
+
+<programlisting>keys {
+       ksk key-directory P5Y 8 2048;
+       zsk key-directory P30D 8;
+       csk key-directory P6MT12H3M15S 13;
+};
+</programlisting>
+
+               <para>
+               This example lists three keys. The first token determines
+               what RRsets the key will sign. If set to
+               <userinput>ksk</userinput> the key will sign the DNSKEY, CDS,
+               and CDNSKEY RRsets, if set to <userinput>zsk</userinput> the
+               key will sign the other RRsets, and if set to
+               <userinput>csk</userinput> the key will sign all RRsets.
+               </para>
+               <para>
+               The following part determines where the key will be stored.
+               Currently keys can only be stored in the configured
+               <command>key-directory</command>.
+               </para>
+               <para>
+               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.
+               </para>
+               <para>
+               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.
+               </para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><command>publish-safety</command></term>
+             <listitem>
+               <para>
+               A margin that is added to the publish interval in key timing
+               equations to give some extra time to cover unforeseen events.
+               Default is <constant>PT5M</constant> (5 minutes).
+               </para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><command>retire-safety</command></term>
+             <listitem>
+               <para>
+               A margin that is added to the retire interval in key timing
+               equations to give some extra time to cover unforeseen events.
+               Default is <constant>PT5M</constant> (5 minutes).
+               </para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><command>signatures-refresh</command></term>
+             <listitem>
+               <para>
+               This determines when a RRSIG record needs to be refreshed.
+               The signatures is renewed when the time until the expiration
+               time is closer than <command>signatures-refresh</command>.
+               <command>signatures-resign</command> interval.
+               Default is <constant>P5D</constant> (5 days), meaning a
+               signature that will expire in 5 days or sooner will be
+               refreshed.
+               </para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><command>signatures-validity</command></term>
+             <listitem>
+               <para>
+               The validity period of an RRSIG record (minus the inception
+               offset and jitter). Default is <constant>P2W</constant>
+               (2 weeks).
+               </para>
+             </listitem>
+           </varlistentry>
+
+           <varlistentry>
+             <term><command>signatures-validity-dnskey</command></term>
+             <listitem>
+               <para>
+               Like <command>signatures-validity</command> but for DNSKEY
+               records. Default is <constant>P2W</constant> (2 weeks).
+               </para>
+             </listitem>
+           </varlistentry>
+
+         </variablelist>
+
+       </section>
+
        <section xml:id="managed-keys"><info><title><command>managed-keys</command> Statement Grammar</title></info>
        <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="managed-keys.grammar.xml"/>
        </section>
@@ -11878,6 +12029,17 @@ view "external" {
                </listitem>
              </varlistentry>
 
+             <varlistentry>
+               <term><command>dnssec-policy</command></term>
+               <listitem>
+                 <para>
+                   The key and signing policy for this zone.  Set to
+                   <userinput>"default"</userinput> if you want to make use
+                   of the default policy.
+                 </para>
+               </listitem>
+             </varlistentry>
+
              <varlistentry>
                <term><command>dnssec-update-mode</command></term>
                <listitem>
diff --git a/doc/arm/dnssec-policy.grammar.xml b/doc/arm/dnssec-policy.grammar.xml
new file mode 100644 (file)
index 0000000..68e27d9
--- /dev/null
@@ -0,0 +1,25 @@
+<!--
+ - 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.
+-->
+
+<!-- Generated by doc/misc/docbook-options.pl -->
+
+<programlisting>
+<command>dnssec-policy</command> <replaceable>string</replaceable> {
+    <command>dnskey-ttl</command> <replaceable>ttlval</replaceable>;
+    <command>keys</command> { ( csk | ksk | zsk ) key-directory <replaceable>duration</replaceable> <replaceable>integer</replaceable> [ <replaceable>integer</replaceable> ] ; ... };
+    <command>publish-safety</command> <replaceable>duration</replaceable>;
+    <command>retire-safety</command> <replaceable>duration</replaceable>;
+    <command>signatures-refresh</command> <replaceable>duration</replaceable>;
+    <command>signatures-validity</command> <replaceable>duration</replaceable>;
+    <command>signatures-validity-dnskey</command> <replaceable>duration</replaceable>;
+};
+</programlisting>
+
index 0ed86ecc750e1c5d09cef14ac7d9eb5b2d8f3750..054b4404922dcee95ceb414d513fadc280a227bd 100644 (file)
@@ -36,6 +36,7 @@
        <command>dnskey-sig-validity</command> <replaceable>integer</replaceable>;
        <command>dnssec-dnskey-kskonly</command> <replaceable>boolean</replaceable>;
        <command>dnssec-loadkeys-interval</command> <replaceable>integer</replaceable>;
+       <command>dnssec-policy</command> <replaceable>string</replaceable>;
        <command>dnssec-secure-to-insecure</command> <replaceable>boolean</replaceable>;
        <command>dnssec-update-mode</command> ( maintain | no-resign );
        <command>file</command> <replaceable>quoted_string</replaceable>;
index 63c0a4acf182ffc6ac7e41a386284085d0d7cbf4..e78f296119f2ca3c8dd4605d2a501fa3e8490619 100644 (file)
@@ -29,6 +29,7 @@
        <command>dnskey-sig-validity</command> <replaceable>integer</replaceable>;
        <command>dnssec-dnskey-kskonly</command> <replaceable>boolean</replaceable>;
        <command>dnssec-loadkeys-interval</command> <replaceable>integer</replaceable>;
+       <command>dnssec-policy</command> <replaceable>string</replaceable>;
        <command>dnssec-update-mode</command> ( maintain | no-resign );
        <command>file</command> <replaceable>quoted_string</replaceable>;
        <command>forward</command> ( first | only );
index 2079c8edc27cca11c74b609ad87dbb382d8f62b6..3e695a2c3955f469e73e47cfc77ec96dfbf77157 100644 (file)
@@ -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;
index aa55ed33e83a93456397790044ff61b720b80766..694d84eb69f92badae2b224f23d047db9c89f1b4 100644 (file)
@@ -23,6 +23,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>;
index 509cc38cf9a5d4d0cacfcbfb6f1086b8b7399fb4..6f5674692c785d34925b556c2e86f7fb3610c748 100644 (file)
@@ -25,6 +25,17 @@ dnssec-keys { <string> ( static-key |
     initial-key ) <integer> <integer> <integer>
     <quoted_string>; ... }; // may occur multiple times
 
+dnssec-policy <string> {
+        dnskey-ttl <ttlval>;
+        keys { ( csk | ksk | zsk ) key-directory <duration> <string>
+           [ <integer> ]; ... };
+        publish-safety <duration>;
+        retire-safety <duration>;
+        signatures-refresh <duration>;
+        signatures-validity <duration>;
+        signatures-validity-dnskey <duration>;
+}; // may occur multiple times
+
 dyndb <string> <quoted_string> {
     <unspecified-text> }; // may occur multiple times
 
index 750392f254444fca40990ea8c19141aea4580114..2dc3fd535c0b1e698f91e3a6a24345e7e90da4d4 100644 (file)
@@ -16,6 +16,7 @@ zone <string> [ <class> ] {
        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 );
index 86d74821572cf7a6dec2df85c4f12ef81d6ae9b5..73fb59bf8294012cbd1f369c8fcd2f775c4f66b4 100644 (file)
@@ -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;
+               }
        }
 
        /*
index f75e56191fe29d82686728ee2722b1d5f22b0b3a..f4f2c39ba1296c974cc5b4cffd9dee9b2c74ffd5 100644 (file)
@@ -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 */
index 3282a8b01f6bfaef794ca01955d4eed4dee7aafa..100cb0979df803df5e49abc9fea6022dffcd1e9f 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <isc/lex.h>
 #include <isc/mem.h>
+#include <isc/print.h>
 #include <isc/result.h>
 #include <isc/string.h>
 #include <isc/util.h>
@@ -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
index 31f059b23bbec69f03c8493c12256e3300d3b822..1f7fef1d1dff8c7f5d9e348a0aeb48b8b2dba9ea 100644 (file)
 ./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