]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Properly detect bottom of zone when sign_a_node() is not called
authorMark Andrews <marka@isc.org>
Fri, 23 Nov 2018 04:03:58 +0000 (15:03 +1100)
committerMark Andrews <marka@isc.org>
Fri, 7 Dec 2018 00:20:16 +0000 (11:20 +1100)
bin/tests/system/autosign/clean.sh
bin/tests/system/autosign/ns3/delzsk.example.db.in [new file with mode: 0644]
bin/tests/system/autosign/ns3/keygen.sh
bin/tests/system/autosign/ns3/named.conf.in
bin/tests/system/autosign/tests.sh
lib/dns/zone.c

index 91879592b214fe13e759300d6ad88e882d9b8200..359409af39c6ddec6c1fd631e7c9967d1dd2575d 100644 (file)
@@ -17,7 +17,7 @@ rm -f */named.run
 rm -f */named.conf
 rm -f */trusted.conf */private.conf
 rm -f activate-now-publish-1day.key
-rm -f active.key inact.key del.key unpub.key standby.key rev.key
+rm -f active.key inact.key del.key delzsk.key unpub.key standby.key rev.key
 rm -f delayksk.key delayzsk.key autoksk.key autozsk.key
 rm -f dig.out.*
 rm -f digcomp.out.test*
@@ -36,6 +36,7 @@ rm -f ns3/inacksk2.example.db
 rm -f ns3/inacksk3.example.db
 rm -f ns3/inaczsk2.example.db
 rm -f ns3/inaczsk3.example.db
+rm -f ns3/delzsk.example.db
 rm -f ns3/kg.out ns3/s.out ns3/st.out
 rm -f ns3/kskonly.example.db
 rm -f ns3/nozsk.example.db ns3/inaczsk.example.db
diff --git a/bin/tests/system/autosign/ns3/delzsk.example.db.in b/bin/tests/system/autosign/ns3/delzsk.example.db.in
new file mode 100644 (file)
index 0000000..241de31
--- /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.
+
+$TTL 300       ; 5 minutes
+@                      IN SOA  mname1. . (
+                               2000010101 ; serial
+                               20         ; refresh (20 seconds)
+                               20         ; retry (20 seconds)
+                               1814400    ; expire (3 weeks)
+                               3600       ; minimum (1 hour)
+                               )
+                       NS      ns
+ns                     A       10.53.0.3
+
+sub                    NS      ns.sub
+                       DS      12345 8 1 0000000000000000000000000000000000000000
+ns.sub                 A       10.53.0.3
index b33dead98fd95cf8f0905318d268abf82430b0a4..a113ff570efda65af7fac426709ed032ce2cd981 100644 (file)
@@ -314,3 +314,14 @@ ksk=`$KEYGEN -a NSEC3RSASHA1 -3 -q -fk $zone 2> kg.out` || dumpit kg.out
 $KEYGEN -a NSEC3RSASHA1 -3 -q $zone > kg.out 2>&1 || dumpit kg.out
 $KEYGEN -a NSEC3RSASHA1 -3 -q -P now -A now+3600 $zone > kg.out 2>&1 || dumpit kg.out
 $DSFROMKEY $ksk.key > dsset-${zone}$TP
+
+#
+# A zone that starts with an active KSK + ZSK and an inactive ZSK, with the
+# latter getting deleted during the test.
+#
+setup delzsk.example
+cp $infile $zonefile
+ksk=`$KEYGEN -a NSEC3RSASHA1 -3 -q -fk $zone 2> kg.out` || dumpit kg.out
+$KEYGEN -a NSEC3RSASHA1 -3 -q $zone > kg.out 2>&1 || dumpit kg.out
+zsk=`$KEYGEN -a NSEC3RSASHA1 -3 -q -I now-1w $zone 2>kg.out` || dumpit kg.out
+echo $zsk > ../delzsk.key
index 06e575fcf8df34fe7f9fbb0f1570350194c0b640..529e39d0b88ce945aa3c8a3cf91efca0de88e0ad 100644 (file)
@@ -282,4 +282,11 @@ zone "inaczsk3.example" {
        auto-dnssec maintain;
 };
 
+zone "delzsk.example." {
+       type master;
+       file "delzsk.example.db";
+       allow-update { any; };
+       auto-dnssec maintain;
+};
+
 include "trusted.conf";
index 53805a98d74d1cadac3ad3424e4f046ad34c5f90..8c4aa99d83d7a4214c069de7104a5c95e993a580 100755 (executable)
@@ -1395,5 +1395,59 @@ n=`expr $n + 1`
 if [ $ret != 0 ]; then echo_i "failed"; fi
 status=`expr $status + $ret`
 
+echo_i "checking for out-of-zone NSEC3 records after ZSK removal ($n)"
+ret=0
+# Switch the zone over to NSEC3 and wait until the transition is complete.
+$RNDCCMD 10.53.0.3 signing -nsec3param 1 1 10 12345678 delzsk.example. > signing.out.1.test$n 2>&1 || ret=1
+for i in 0 1 2 3 4 5 6 7 8 9; do
+       _ret=1
+       $DIG $DIGOPTS delzsk.example NSEC3PARAM @10.53.0.3 > dig.out.ns3.1.test$n 2>&1 || ret=1
+       grep "NSEC3PARAM.*12345678" dig.out.ns3.1.test$n > /dev/null 2>&1
+       if [ $? -eq 0 ]; then
+               _ret=0
+               break
+       fi
+       sleep 1
+done
+if [ $_ret -ne 0 ]; then
+       echo_i "timed out waiting for NSEC3 chain creation"
+       ret=1
+fi
+# Mark the inactive ZSK as pending removal.
+file="ns3/`cat delzsk.key`.key"
+$SETTIME -D now-1h $file > settime.out.test$n 2>&1 || ret=1
+# Trigger removal of the inactive ZSK and wait until its completion.
+$RNDCCMD 10.53.0.3 loadkeys delzsk.example 2>&1 | sed 's/^/ns3 /' | cat_i
+for i in 0 1 2 3 4 5 6 7 8 9; do
+       _ret=1
+       $RNDCCMD 10.53.0.3 signing -list delzsk.example > signing.out.2.test$n 2>&1
+       grep "Signing " signing.out.2.test$n > /dev/null 2>&1
+       if [ $? -ne 0 ]; then
+               if [ `cat signing.out.2.test$n | wc -l` -eq 2 ]; then
+                       _ret=0
+                       break
+               fi
+       fi
+       sleep 1
+done
+if [ $_ret -ne 0 ]; then
+       echo_i "timed out waiting for key removal"
+       ret=1
+fi
+# Check whether key removal caused NSEC3 records to be erroneously created for
+# glue records due to a secure delegation already being signed by the active key
+# (i.e. a key other than the one being removed but using the same algorithm).
+#
+# For reference:
+#
+#     $ nsec3hash 12345678 1 10 ns.sub.delzsk.example.
+#     589R358VSPJUFVAJU949JPVF74D9PTGH (salt=12345678, hash=1, iterations=10)
+#
+$DIG $DIGOPTS delzsk.example AXFR @10.53.0.3 > dig.out.ns3.3.test$n || ret=1
+grep "589R358VSPJUFVAJU949JPVF74D9PTGH" dig.out.ns3.3.test$n > /dev/null 2>&1 && ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=`expr $status + $ret`
+
 echo_i "exit status: $status"
 [ $status -eq 0 ] || exit 1
index 4d7b9e21ec00380311014d1078de8725df243f92..62c038d4bf0363e46c6be12208038f571d345dee 100644 (file)
@@ -6779,13 +6779,64 @@ add_nsec(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
        return (result);
 }
 
+static isc_result_t
+check_if_bottom_of_zone(dns_db_t *db, dns_dbnode_t *node,
+                       dns_dbversion_t *version, bool *is_bottom_of_zone)
+{
+       isc_result_t result;
+       dns_rdatasetiter_t *iterator = NULL;
+       dns_rdataset_t rdataset;
+       bool seen_soa = false, seen_ns = false, seen_dname = false;
+
+       REQUIRE(is_bottom_of_zone != NULL);
+
+       result = dns_db_allrdatasets(db, node, version, 0, &iterator);
+       if (result != ISC_R_SUCCESS) {
+               if (result == ISC_R_NOTFOUND) {
+                       result = ISC_R_SUCCESS;
+               }
+               return (result);
+       }
+
+       dns_rdataset_init(&rdataset);
+       for (result = dns_rdatasetiter_first(iterator);
+            result == ISC_R_SUCCESS;
+            result = dns_rdatasetiter_next(iterator)) {
+               dns_rdatasetiter_current(iterator, &rdataset);
+               switch (rdataset.type) {
+               case dns_rdatatype_soa:
+                       seen_soa = true;
+                       break;
+               case dns_rdatatype_ns:
+                       seen_ns = true;
+                       break;
+               case dns_rdatatype_dname:
+                       seen_dname = true;
+                       break;
+               }
+               dns_rdataset_disassociate(&rdataset);
+       }
+       if (result != ISC_R_NOMORE) {
+               goto failure;
+       }
+       if ((seen_ns && !seen_soa) || seen_dname) {
+               *is_bottom_of_zone = true;
+       }
+       result = ISC_R_SUCCESS;
+
+ failure:
+       dns_rdatasetiter_destroy(&iterator);
+
+       return (result);
+}
+
 static isc_result_t
 sign_a_node(dns_db_t *db, dns_name_t *name, dns_dbnode_t *node,
            dns_dbversion_t *version, bool build_nsec3,
            bool build_nsec, dst_key_t *key,
            isc_stdtime_t inception, isc_stdtime_t expire,
            unsigned int minimum, bool is_ksk,
-           bool keyset_kskonly, bool *delegation,
+           bool keyset_kskonly, bool is_bottom_of_zone,
            dns_diff_t *diff, int32_t *signatures, isc_mem_t *mctx)
 {
        isc_result_t result;
@@ -6796,7 +6847,6 @@ sign_a_node(dns_db_t *db, dns_name_t *name, dns_dbnode_t *node,
        unsigned char data[1024];
        bool seen_soa, seen_ns, seen_rr, seen_dname, seen_nsec,
                      seen_nsec3, seen_ds;
-       bool bottom;
 
        result = dns_db_allrdatasets(db, node, version, 0, &iterator);
        if (result != ISC_R_SUCCESS) {
@@ -6831,8 +6881,6 @@ sign_a_node(dns_db_t *db, dns_name_t *name, dns_dbnode_t *node,
        }
        if (result != ISC_R_NOMORE)
                goto failure;
-       if (seen_ns && !seen_soa)
-               *delegation = true;
        /*
         * Going from insecure to NSEC3.
         * Don't generate NSEC3 records for NSEC3 records.
@@ -6848,14 +6896,12 @@ sign_a_node(dns_db_t *db, dns_name_t *name, dns_dbnode_t *node,
         * Don't generate NSEC records for NSEC3 records.
         */
        if (build_nsec && !seen_nsec3 && !seen_nsec && seen_rr) {
-               /* Build and add NSEC. */
-               bottom = (seen_ns && !seen_soa) || seen_dname;
                /*
                 * Build a NSEC record except at the origin.
                 */
                if (!dns_name_equal(name, dns_db_origin(db))) {
                        CHECK(add_nsec(db, version, name, node, minimum,
-                                      bottom, diff));
+                                      is_bottom_of_zone, diff));
                        /* Count a NSEC generation as a signature generation. */
                        (*signatures)--;
                }
@@ -6884,7 +6930,7 @@ sign_a_node(dns_db_t *db, dns_name_t *name, dns_dbnode_t *node,
                } else if (is_ksk) {
                        goto next_rdataset;
                }
-               if (*delegation &&
+               if (seen_ns && !seen_soa &&
                    rdataset.type != dns_rdatatype_ds &&
                    rdataset.type != dns_rdatatype_nsec)
                {
@@ -6909,8 +6955,6 @@ sign_a_node(dns_db_t *db, dns_name_t *name, dns_dbnode_t *node,
        }
        if (result == ISC_R_NOMORE)
                result = ISC_R_SUCCESS;
-       if (seen_dname)
-               *delegation = true;
  failure:
        if (dns_rdataset_isassociated(&rdataset))
                dns_rdataset_disassociate(&rdataset);
@@ -8429,7 +8473,7 @@ zone_sign(dns_zone_t *zone) {
        bool check_ksk, keyset_kskonly, is_ksk;
        bool with_ksk, with_zsk;
        bool commit = false;
-       bool delegation;
+       bool is_bottom_of_zone;
        bool build_nsec = false;
        bool build_nsec3 = false;
        bool first;
@@ -8554,7 +8598,7 @@ zone_sign(dns_zone_t *zone) {
                if (signing->db != db)
                        goto next_signing;
 
-               delegation = false;
+               is_bottom_of_zone = false;
 
                if (first && signing->deleteit) {
                        /*
@@ -8609,7 +8653,7 @@ zone_sign(dns_zone_t *zone) {
                                 * we skip all obscured names.
                                 */
                                dns_name_copy(found, name, NULL);
-                               delegation = true;
+                               is_bottom_of_zone = true;
                                goto next_node;
                        }
                }
@@ -8620,6 +8664,10 @@ zone_sign(dns_zone_t *zone) {
                with_ksk = false;
                with_zsk = false;
                dns_dbiterator_pause(signing->dbiterator);
+
+               CHECK(check_if_bottom_of_zone(db, node, version,
+                                             &is_bottom_of_zone));
+
                for (i = 0; !has_alg && i < nkeys; i++) {
                        bool both = false;
 
@@ -8707,7 +8755,7 @@ zone_sign(dns_zone_t *zone) {
                                          build_nsec, zone_keys[i], inception,
                                          expire, zone->minimum, is_ksk,
                                          (both && keyset_kskonly),
-                                         &delegation, zonediff.diff,
+                                         is_bottom_of_zone, zonediff.diff,
                                          &signatures, zone->mctx));
                        /*
                         * If we are adding we are done.  Look for other keys
@@ -8776,7 +8824,7 @@ zone_sign(dns_zone_t *zone) {
                                        "zone_sign:dns_dbiterator_next -> %s",
                                             dns_result_totext(result));
                                goto failure;
-                       } else if (delegation) {
+                       } else if (is_bottom_of_zone) {
                                dns_dbiterator_current(signing->dbiterator,
                                                       &node, nextname);
                                dns_db_detachnode(db, &node);