]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
[master] tag initializing keys
authorEvan Hunt <each@isc.org>
Fri, 27 Oct 2017 22:45:18 +0000 (15:45 -0700)
committerEvan Hunt <each@isc.org>
Fri, 27 Oct 2017 22:49:44 +0000 (15:49 -0700)
4798. [func] Keys specified in "managed-keys" statements
are tagged as "initializing" until they have been
updated by a key refresh query. If initialization
fails it will be visible from "rndc secroots".
[RT #46267]

24 files changed:
CHANGES
bin/named/server.c
bin/tests/system/mkeys/README
bin/tests/system/mkeys/clean.sh
bin/tests/system/mkeys/ns1/named1.conf
bin/tests/system/mkeys/ns1/named2.conf
bin/tests/system/mkeys/ns1/named3.conf [new file with mode: 0644]
bin/tests/system/mkeys/ns1/sign.sh
bin/tests/system/mkeys/ns2/named.args
bin/tests/system/mkeys/ns4/named.conf [new file with mode: 0644]
bin/tests/system/mkeys/ns5/named.conf [new file with mode: 0644]
bin/tests/system/mkeys/ns5/named1.args [new file with mode: 0644]
bin/tests/system/mkeys/ns5/named2.args [new file with mode: 0644]
bin/tests/system/mkeys/setup.sh
bin/tests/system/mkeys/tests.sh
doc/arm/notes.xml
lib/dns/client.c
lib/dns/include/dns/keytable.h
lib/dns/include/dns/resolver.h
lib/dns/keytable.c
lib/dns/resolver.c
lib/dns/tests/keytable_test.c
lib/dns/win32/libdns.def.in
lib/dns/zone.c

diff --git a/CHANGES b/CHANGES
index 8e0575b08ea43c81f209dea785a922fe8141f30d..0f4513d0b66f51052050802e39c7df2bd1479826 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,9 @@
+4798.  [func]          Keys specified in "managed-keys" statements
+                       are tagged as "initializing" until they have been
+                       updated by a key refresh query. If initialization
+                       fails it will be visible from "rndc secroots".
+                       [RT #46267]
+
 4797.  [func]          Removed "isc-hmac-fixup", as the versions of BIND that
                        had the bug it worked around are long past end of
                        life. [RT #46411]
index a8ce5e01e54626001d2cefe064ba0858b85c48b1..0a4ade0e7c1a39a07336f0b03d2cb93fd444b929 100644 (file)
@@ -805,6 +805,11 @@ dstkey_fromconfig(const cfg_obj_t *vconfig, const cfg_obj_t *key,
        return (result);
 }
 
+/*
+ * Load keys from configuration into key table. If 'keyname' is specified,
+ * only load keys matching that name. If 'managed' is true, load the key as
+ * an initializing key.
+ */
 static isc_result_t
 load_view_keys(const cfg_obj_t *keys, const cfg_obj_t *vconfig,
               dns_view_t *view, isc_boolean_t managed,
@@ -820,12 +825,14 @@ load_view_keys(const cfg_obj_t *keys, const cfg_obj_t *vconfig,
 
        for (elt = cfg_list_first(keys);
             elt != NULL;
-            elt = cfg_list_next(elt)) {
+            elt = cfg_list_next(elt))
+       {
                keylist = cfg_listelt_value(elt);
 
                for (elt2 = cfg_list_first(keylist);
                     elt2 != NULL;
-                    elt2 = cfg_list_next(elt2)) {
+                    elt2 = cfg_list_next(elt2))
+               {
                        key = cfg_listelt_value(elt2);
                        result = dstkey_fromconfig(vconfig, key, managed,
                                                   &dstkey, mctx);
@@ -833,8 +840,9 @@ load_view_keys(const cfg_obj_t *keys, const cfg_obj_t *vconfig,
                                result = ISC_R_SUCCESS;
                                continue;
                        }
-                       if (result != ISC_R_SUCCESS)
+                       if (result != ISC_R_SUCCESS) {
                                goto cleanup;
+                       }
 
                        /*
                         * If keyname was specified, we only add that key.
@@ -846,17 +854,27 @@ load_view_keys(const cfg_obj_t *keys, const cfg_obj_t *vconfig,
                                continue;
                        }
 
-                       CHECK(dns_keytable_add(secroots, managed, &dstkey));
+                       /*
+                        * This key is taken from the configuration, so
+                        * if it's a managed key then it's an
+                        * initializing key; that's why 'managed'
+                        * is duplicated below.
+                        */
+                       CHECK(dns_keytable_add2(secroots, managed,
+                                               managed, &dstkey));
                }
        }
 
  cleanup:
-       if (dstkey != NULL)
+       if (dstkey != NULL) {
                dst_key_free(&dstkey);
-       if (secroots != NULL)
+       }
+       if (secroots != NULL) {
                dns_keytable_detach(&secroots);
-       if (result == DST_R_NOCRYPTO)
+       }
+       if (result == DST_R_NOCRYPTO) {
                result = ISC_R_SUCCESS;
+       }
        return (result);
 }
 
@@ -1026,7 +1044,7 @@ configure_view_dnsseckeys(dns_view_t *view, const cfg_obj_t *vconfig,
        }
 
        /*
-        * Add key zone for managed-keys.
+        * Add key zone for managed keys.
         */
        obj = NULL;
        (void)named_config_get(maps, "managed-keys-directory", &obj);
@@ -1050,6 +1068,7 @@ configure_view_dnsseckeys(dns_view_t *view, const cfg_obj_t *vconfig,
                        goto cleanup;
                }
        }
+
        CHECK(add_keydata_zone(view, directory, named_g_mctx));
 
   cleanup:
@@ -6443,16 +6462,19 @@ dotat(dns_keytable_t *keytable, dns_keynode_t *keynode, void *arg) {
                }
                nextnode = NULL;
                (void)dns_keytable_nextkeynode(keytable, keynode, &nextnode);
-               if (keynode != firstnode)
+               if (keynode != firstnode) {
                        dns_keytable_detachkeynode(keytable, &keynode);
+               }
                keynode = nextnode;
        } while (keynode != NULL);
 
-       if (n == 0)
+       if (n == 0) {
                return;
+       }
 
-       if (n > 1)
+       if (n > 1) {
                qsort(ids, n, sizeof(ids[0]), cid);
+       }
 
        /*
         * Encoded as "_ta-xxxx\(-xxxx\)*" where xxxx is the hex version of
@@ -6460,22 +6482,25 @@ dotat(dns_keytable_t *keytable, dns_keynode_t *keynode, void *arg) {
         */
        label[0] = 0;
        r.base = label;
-       r.length = sizeof(label);;
+       r.length = sizeof(label);
        m = snprintf(r.base, r.length, "_ta");
-       if (m < 0 || (unsigned)m > r.length)
+       if (m < 0 || (unsigned)m > r.length) {
                return;
+       }
        isc_textregion_consume(&r, m);
        for (i = 0; i < n; i++) {
                m = snprintf(r.base, r.length, "-%04x", ids[i]);
-               if (m < 0 || (unsigned)m > r.length)
+               if (m < 0 || (unsigned)m > r.length) {
                        return;
+               }
                isc_textregion_consume(&r, m);
        }
        dns_fixedname_init(&fixed);
        tatname = dns_fixedname_name(&fixed);
        result = dns_name_fromstring2(tatname, label, name, 0, NULL);
-       if (result != ISC_R_SUCCESS)
+       if (result != ISC_R_SUCCESS) {
                return;
+       }
 
        dns_name_format(tatname, namebuf, sizeof(namebuf));
        isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
@@ -6484,8 +6509,9 @@ dotat(dns_keytable_t *keytable, dns_keynode_t *keynode, void *arg) {
                     view->name, namebuf);
 
        tat = isc_mem_get(dotat_arg->view->mctx, sizeof(*tat));
-       if (tat == NULL)
+       if (tat == NULL) {
                return;
+       }
 
        tat->mctx = NULL;
        tat->task = NULL;
index 8682940f8c702e85c17d95bd4695a65c73976918..40310a2d70eb2801b74b18a75e0047a28a0d9fbd 100644 (file)
@@ -16,16 +16,8 @@ is used so it will send TAT queries once per second.
 
 ns3 is a validator with a broken key in managed-keys.
 
-Tests TODO:
+ns4 is a validator with a deliberately broken managed-keys.bind and
+managed-keys.jnl, causing RFC 5011 initialization to fail.
 
-- initial working KSK
-
-TODO: test using delv with new trusted key too
-
-- introduce a REVOKE bit
-
-- later remove a signature
-
-- corrupt a signature
-
-TODO: also same things with dlv auto updates of trust anchor
+ns5 is a validator which is prevented from getting a response from the
+root server, causing key refresh queries to fail.
index a02f05b77702f6b458d230ed163cf8a722a51f1f..609da5e49b172bc691d1fe3b62cd329bc82f9e3e 100644 (file)
@@ -10,8 +10,10 @@ rm -f */K* */*.signed */trusted.conf */*.jnl */*.bk
 rm -f dsset-. ns1/dsset-.
 rm -f ns*/named.lock
 rm -f */managed-keys.bind* */named.secroots
-rm -f */managed.conf ns1/managed.key ns1/managed.key.id
+rm -f */managed*.conf ns1/managed.key ns1/managed.key.id
 rm -f */named.memstats */named.run
 rm -f dig.out* delv.out* rndc.out* signer.out*
 rm -f ns1/named.secroots ns1/root.db.signed* ns1/root.db.tmp
 rm -f ns1/named.conf
+rm -rf ns4/nope
+rm -f ns5/named.args
index 0f17bdc16b0b5094925c6b93cddc45e1a5bc88a9..5f9eeaf91e0cae1dc047a3896723206a4ea86d4b 100644 (file)
 
 controls { /* empty */ };
 
+acl allowed {
+       ! 10.53.0.5;
+       any;
+};
+
 options {
        query-source address 10.53.0.1;
        notify-source 10.53.0.1;
@@ -22,6 +27,7 @@ options {
        notify no;
        dnssec-enable yes;
        dnssec-validation yes;
+       allow-query { allowed; };
 };
 
 key rndc_key {
index a033e10d816f67c691810109e33ea115ae6cf996..42f6712859b0301503cbdb0ebbe0ac3c46a97ad7 100644 (file)
 
 controls { /* empty */ };
 
+acl allowed {
+       ! 10.53.0.5;
+       any;
+};
+
 options {
        query-source address 10.53.0.1;
        notify-source 10.53.0.1;
@@ -22,6 +27,7 @@ options {
        notify no;
        dnssec-enable yes;
        dnssec-validation yes;
+       allow-query { allowed; };
 };
 
 key rndc_key {
diff --git a/bin/tests/system/mkeys/ns1/named3.conf b/bin/tests/system/mkeys/ns1/named3.conf
new file mode 100644 (file)
index 0000000..614c49c
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015-2017  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/.
+ */
+
+// NS1
+
+controls { /* empty */ };
+
+options {
+       query-source address 10.53.0.1;
+       notify-source 10.53.0.1;
+       transfer-source 10.53.0.1;
+       port 5300;
+       pid-file "named.pid";
+       listen-on { 10.53.0.1; };
+       listen-on-v6 { none; };
+       recursion no;
+       notify no;
+       dnssec-enable yes;
+       dnssec-validation yes;
+};
+
+key rndc_key {
+       secret "1234abcd8765";
+       algorithm hmac-sha256;
+};
+
+controls {
+       inet 10.53.0.1 port 9953 allow { any; } keys { rndc_key; };
+};
+
+zone "." {
+       type master;
+       file "root.db.signed";
+};
index fb134742d267ccee18bd3e8c54f5a7b29085fb41..054422de55e07af58c3ec040ff8e9f959fe0539e 100644 (file)
@@ -28,6 +28,8 @@ managed-keys {
 EOF
 ' > managed.conf
 cp managed.conf ../ns2/managed.conf
+cp managed.conf ../ns4/managed.conf
+cp managed.conf ../ns5/managed.conf
 
 # Configure a trusted key statement (used by delve)
 cat $keyname.key | grep -v '^; ' | $PERL -n -e '
index d222b7faea7e49228501e7bf6206f4e0a1efb175..71e466df4050fdafd6af54ff3e66d374176ffa98 100644 (file)
@@ -1 +1 @@
--m record,size,mctx -T clienttest -c named.conf -d 99 -X named.lock -g -T mkeytimers=2/20/40
+-m record,size,mctx -T clienttest -c named.conf -d 99 -X named.lock -g -T mkeytimers=2/20/40 -T tat=1
diff --git a/bin/tests/system/mkeys/ns4/named.conf b/bin/tests/system/mkeys/ns4/named.conf
new file mode 100644 (file)
index 0000000..ad3979d
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2017  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/.
+ */
+
+// NS4
+
+controls { /* empty */ };
+
+options {
+       query-source address 10.53.0.4;
+       notify-source 10.53.0.4;
+       transfer-source 10.53.0.4;
+       port 5300;
+       pid-file "named.pid";
+       listen-on { 10.53.0.4; };
+       listen-on-v6 { none; };
+       recursion yes;
+       notify no;
+       dnssec-enable yes;
+       dnssec-validation auto;
+       bindkeys-file "managed.conf";
+       managed-keys-directory "nope";
+};
+
+key rndc_key {
+       secret "1234abcd8765";
+       algorithm hmac-sha256;
+};
+
+controls {
+       inet 10.53.0.4 port 9953 allow { any; } keys { rndc_key; };
+};
+
+zone "." {
+       type hint;
+       file "../../common/root.hint";
+};
diff --git a/bin/tests/system/mkeys/ns5/named.conf b/bin/tests/system/mkeys/ns5/named.conf
new file mode 100644 (file)
index 0000000..9820492
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017  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/.
+ */
+
+// NS5
+
+options {
+       query-source address 10.53.0.5;
+       notify-source 10.53.0.5;
+       transfer-source 10.53.0.5;
+       port 5300;
+       pid-file "named.pid";
+       listen-on { 10.53.0.5; };
+       listen-on-v6 { none; };
+       recursion yes;
+       notify no;
+       dnssec-enable yes;
+       dnssec-validation auto;
+       bindkeys-file "managed.conf";
+};
+
+key rndc_key {
+       secret "1234abcd8765";
+       algorithm hmac-sha256;
+};
+
+controls {
+       inet 10.53.0.5 port 9953 allow { any; } keys { rndc_key; };
+};
+
+zone "." {
+       type hint;
+       file "../../common/root.hint";
+};
diff --git a/bin/tests/system/mkeys/ns5/named1.args b/bin/tests/system/mkeys/ns5/named1.args
new file mode 100644 (file)
index 0000000..efb102a
--- /dev/null
@@ -0,0 +1 @@
+-m record,size,mctx -T clienttest -c named.conf -d 99 -X named.lock -g
diff --git a/bin/tests/system/mkeys/ns5/named2.args b/bin/tests/system/mkeys/ns5/named2.args
new file mode 100644 (file)
index 0000000..d222b7f
--- /dev/null
@@ -0,0 +1 @@
+-m record,size,mctx -T clienttest -c named.conf -d 99 -X named.lock -g -T mkeytimers=2/20/40
index d555c4e93e232799b829777bedddc78f0cd28675..5636491072eb4abc7c86c726db145f7bece232c0 100644 (file)
@@ -14,5 +14,14 @@ $SHELL clean.sh
 test -r $RANDFILE || $GENRANDOM 800 $RANDFILE
 
 cp ns1/named1.conf ns1/named.conf
+cp ns5/named1.args ns5/named.args
 
-cd ns1 && $SHELL sign.sh
+( cd ns1 && $SHELL sign.sh )
+
+cp ns2/managed.conf ns2/managed1.conf
+
+cd ns4
+mkdir nope
+touch nope/managed-keys.bind
+touch nope/managed.keys.bind.jnl
+chmod 444 nope/*
index b9806f3431f4463e97846d1da9e8b70a419cd9c0..5a3d7a2e961dd3d6125ba7c77745e22213a40f5d 100644 (file)
@@ -215,9 +215,36 @@ t2=`grep "trust pending" ns2/managed-keys.bind`
 if [ $ret != 0 ]; then echo "I:failed"; fi
 status=`expr $status + $ret`
 
-echo "I: reinitialize trust anchors"
+echo "I: reinitialize trust anchors, add second key to bind.keys"
 $PERL $SYSTEMTESTTOP/stop.pl --use-rndc . ns2
 rm -f ns2/managed-keys.bind*
+cat ns1/$standby1.key | grep -v '^; ' | $PERL -n -e '
+local ($dn, $class, $type, $flags, $proto, $alg, @rest) = split;
+local $key = join("", @rest);
+local $originalkey = `grep initial-key ns2/managed1.conf`;
+print <<EOF
+managed-keys {
+    $originalkey
+    "$dn" initial-key $flags $proto $alg "$key";
+};
+EOF
+' > ns2/managed.conf
+$PERL $SYSTEMTESTTOP/start.pl --noclean --restart . ns2
+
+n=`expr $n + 1`
+echo "I: check that no key from bind.keys is marked as an initializing key ($n)"
+ret=0
+sleep 3
+$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 secroots | sed 's/^/I: ns2 /'
+sleep 1
+grep '; initializing' ns2/named.secroots > /dev/null 2>&1 && ret=1
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I: reinitialize trust anchors, revert to one key in bind.keys"
+$PERL $SYSTEMTESTTOP/stop.pl --use-rndc . ns2
+rm -f ns2/managed-keys.bind*
+mv ns2/managed1.conf ns2/managed.conf
 $PERL $SYSTEMTESTTOP/start.pl --noclean --restart . ns2
 
 n=`expr $n + 1`
@@ -446,7 +473,6 @@ rm -f ${revoked}.key ${revoked}.private
 $SETTIME -D none -R none -K ns1 `cat ns1/managed.key` > /dev/null
 $SETTIME -D now -K ns1 $standby1 > /dev/null
 $SETTIME -D now -K ns1 $standby2 > /dev/null
-$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 flush | sed 's/^/I: ns1 /'
 sleep 1
 $SIGNER -Sg -K ns1 -N unixtime -r $RANDFILE -o . ns1/root.db > /dev/null 2>&-
 $RNDC -c ../common/rndc.conf -s 10.53.0.1 -p 9953 reload . | sed 's/^/I: ns1 /'
@@ -454,6 +480,7 @@ sleep 3
 $RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 managed-keys refresh | sed 's/^/I: ns2 /'
 sleep 1
 $RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 managed-keys status > rndc.out.$n 2>&1
+$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 flush | sed 's/^/I: ns1 /'
 $DIG $DIGOPTS +noauth example. @10.53.0.2 txt > dig.out.ns2.test$n || ret=1
 grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null || ret=1
 grep "example..*.RRSIG..*TXT" dig.out.ns2.test$n > /dev/null || ret=1
@@ -537,14 +564,14 @@ status=`expr $status + $ret`
 n=`expr $n + 1`
 echo "I: check that trust-anchor-telemetry queries are logged ($n)"
 ret=0
-grep "sending trust-anchor-telemetry query '_ta-[0-9a-f]*/NULL" ns3/named.run > /dev/null || ret=1
+grep "sending trust-anchor-telemetry query '_ta-[0-9a-f]*/NULL" ns2/named.run > /dev/null || ret=1
 if [ $ret != 0 ]; then echo "I:failed"; fi
 status=`expr $status + $ret`
 
 n=`expr $n + 1`
 echo "I: check that trust-anchor-telemetry queries are received ($n)"
 ret=0
-grep "query '_ta-[0-9a-f]*/NULL/IN' approved" ns1/named.run > /dev/null || ret=1
+grep "query '_ta-[0-9a-f][0-9a-f]*/NULL/IN' approved" ns1/named.run > /dev/null || ret=1
 if [ $ret != 0 ]; then echo "I:failed"; fi
 status=`expr $status + $ret`
 
@@ -562,5 +589,82 @@ grep "name: \." rndc.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 trust-anchor-telemetry queries contain the correct key ($n)"
+ret=0
+# convert the hexadecimal key from the TAT query into decimal and
+# compare against the known key.
+tathex=`grep "query '_ta-[0-9a-f][0-9a-f]*/NULL/IN' approved" ns1/named.run | awk '{print $6; exit 0}' | sed -e 's/(_ta-\([0-9a-f][0-9a-f]*\)):/\1/'`
+tatkey=`$PERL -e 'printf("%d\n", hex(@ARGV[0]));' $tathex`
+realkey=`$RNDC -c ../common/rndc.conf -s 10.53.0.2 -p 9953 secroots - | grep '; managed' | sed 's#.*SHA256/\([0-9][0-9]*\) ; managed.*#\1#'`
+[ "$tatkey" -eq "$realkey" ] || ret=1
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+n=`expr $n + 1`
+echo "I: check initialization fails if managed-keys can't be created ($n)"
+ret=0
+$RNDC -c ../common/rndc.conf -s 10.53.0.4 -p 9953 secroots | sed 's/^/I: ns4 /'
+grep '; initializing managed' ns4/named.secroots > /dev/null 2>&1 || ret=1
+grep '; managed' ns4/named.secroots > /dev/null 2>&1 && ret=1
+grep '; trusted' ns4/named.secroots > /dev/null 2>&1 && ret=1
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+n=`expr $n + 1`
+echo "I: check failure to contact root servers does not prevent key refreshes after restart ($n)"
+ret=0
+# By the time we get here, ns5 should have attempted refreshing its managed
+# keys.  These attempts should fail as ns1 is configured to REFUSE all queries
+# from ns5.  Note that named1.args does not contain "-T mkeytimers"; this is to
+# ensure key refresh retry will be scheduled to one actual hour after the first
+# key refresh failure instead of just a few seconds, in order to prevent races
+# between the next scheduled key refresh time and startup time of restarted ns5.
+$PERL $SYSTEMTESTTOP/stop.pl --use-rndc . ns5
+$PERL $SYSTEMTESTTOP/start.pl --noclean --restart . ns5
+sleep 2
+# ns5/named.run will contain logs from both the old instance and the new
+# instance.  In order for the test to pass, both must attempt a fetch.
+count=`grep -c "Creating key fetch" ns5/named.run`
+[ $count -lt 2 ] && ret=1
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+n=`expr $n + 1`
+echo "I: check key refreshes are resumed after root servers become available ($n)"
+ret=0
+$PERL $SYSTEMTESTTOP/stop.pl --use-rndc . ns5
+# Prevent previous check from affecting this one
+rm -f ns2/managed-keys.bind*
+# named2.args adds "-T mkeytimers=2/20/40" to named1.args as we need to wait for
+# an "hour" until keys are refreshed again after initial failure
+cp ns5/named2.args ns5/named.args
+$PERL $SYSTEMTESTTOP/start.pl --noclean --restart . ns5
+sleep 2
+$RNDC -c ../common/rndc.conf -s 10.53.0.5 -p 9953 secroots | sed 's/^/I: ns4 /'
+sleep 1
+grep '; initializing managed' ns5/named.secroots > /dev/null 2>&1 || ret=1
+# ns1 should still REFUSE queries from ns5, so resolving should be impossible
+$DIG $DIGOPTS +noauth example. @10.53.0.5 txt > dig.out.ns5.a.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns5.a.test$n > /dev/null && ret=1
+grep "example..*.RRSIG..*TXT" dig.out.ns5.a.test$n > /dev/null && ret=1
+grep "status: SERVFAIL" dig.out.ns5.a.test$n > /dev/null || ret=1
+# Allow queries from ns5 to ns1
+cp ns1/named3.conf ns1/named.conf
+rm -f ns1/root.db.signed.jnl
+$RNDC -c ../common/rndc.conf -s 10.53.0.1 -p 9953 reconfig
+sleep 3
+$RNDC -c ../common/rndc.conf -s 10.53.0.5 -p 9953 secroots | sed 's/^/I: ns4 /'
+sleep 1
+grep '; managed' ns5/named.secroots > /dev/null 2>&1 || ret=1
+# ns1 should not longer REFUSE queries from ns5, so managed keys should be
+# correctly refreshed and resolving should succeed
+$DIG $DIGOPTS +noauth example. @10.53.0.5 txt > dig.out.ns5.b.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns5.b.test$n > /dev/null || ret=1
+grep "example..*.RRSIG..*TXT" dig.out.ns5.b.test$n > /dev/null || ret=1
+grep "status: NOERROR" dig.out.ns5.b.test$n > /dev/null || 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 a7ce6ed018776b18b8227ff4a48391b9a8f378ee..296a0f574be7553c10eff95ac4ddba4b28817b19 100644 (file)
          are not writable by the effective user ID. [RT #46077]
        </para>
       </listitem>
+      <listitem>
+       <para>
+         Initializing keys specified in a <command>managed-keys</command>
+         statement or by <command>dnssec-validation auto;</command> are
+         now tagged as "initializing", until they have been updated by a
+         key refresh query. If key maintenance fails to initialize,
+         this will be visible when running <command>rndc secroots</command>.
+         [RT #46267]
+       </para>
+      </listitem>
       <listitem>
        <para>
          Previously, <command>update-policy local;</command> accepted
index 1d8269912e00ea6f0b267f9d8df3a8e57cb6bc64..9a8d9b3819f75f019faf5cd6befe4e78a9f2ff73 100644 (file)
@@ -1546,7 +1546,7 @@ dns_client_addtrustedkey(dns_client_t *client, dns_rdataclass_t rdclass,
        if (result != ISC_R_SUCCESS)
                goto cleanup;
 
-       result = dns_keytable_add(secroots, ISC_FALSE, &dstkey);
+       result = dns_keytable_add2(secroots, ISC_FALSE, ISC_FALSE, &dstkey);
 
  cleanup:
        if (dstkey != NULL)
index 62c55a978857d795ba321bb78b313e5d09c26110..fd089b6a54713a3822438ab096f8340a413cee1d 100644 (file)
@@ -102,10 +102,18 @@ dns_keytable_detach(dns_keytable_t **keytablep);
 
 isc_result_t
 dns_keytable_add(dns_keytable_t *keytable, isc_boolean_t managed,
-                dst_key_t **keyp);
+                dst_key_t **keyp) ISC_DEPRECATED;
+isc_result_t
+dns_keytable_add2(dns_keytable_t *keytable, isc_boolean_t managed,
+                isc_boolean_t initial, dst_key_t **keyp);
 /*%<
  * Add '*keyp' to 'keytable' (using the name in '*keyp').
- * The value of keynode->managed is set to 'managed'
+ * The value of keynode->managed is set to 'managed', and the
+ * value of keynode->initial is set to 'initial'. (Note: 'initial'
+ * should only be used when adding managed-keys from configuration.
+ * This indicates the key is in "initializing" state, and has not yet
+ * been confirmed with a key refresh query.  Once a key refresh query
+ * has validated, we update the keynode with inital == ISC_FALSE.)
  *
  * Notes:
  *
@@ -117,6 +125,8 @@ dns_keytable_add(dns_keytable_t *keytable, isc_boolean_t managed,
  *
  *\li  'keytable' points to a valid keytable.
  *
+ *\li  if 'initial' is true then 'managed' must also be true.
+ *
  *\li  keyp != NULL && *keyp is a valid dst_key_t *.
  *
  * Ensures:
@@ -402,6 +412,19 @@ dns_keynode_managed(dns_keynode_t *keynode);
  * Is this flagged as a managed key?
  */
 
+isc_boolean_t
+dns_keynode_initial(dns_keynode_t *keynode);
+/*%<
+ * Is this flagged as an initializing key?
+ */
+
+void
+dns_keynode_trust(dns_keynode_t *keynode);
+/*%<
+ * Sets keynode->initial to ISC_FALSE in order to mark the key as
+ * trusted: no longer an initializing key.
+ */
+
 isc_result_t
 dns_keynode_create(isc_mem_t *mctx, dns_keynode_t **target);
 /*%<
index 1e6aba528eda36130cfaaa5ab7c7b0982850222d..8544dbe8103947a69e024ca3b421ffbd5f96e433 100644 (file)
@@ -614,6 +614,12 @@ dns_resolver_setnonbackofftries(dns_resolver_t *resolver, unsigned int tries);
 
 unsigned int
 dns_resolver_getoptions(dns_resolver_t *resolver);
+/*%<
+ * Get the resolver options.
+ *
+ * Requires:
+ * \li resolver to be valid.
+ */
 
 void
 dns_resolver_addbadcache(dns_resolver_t *resolver, const dns_name_t *name,
index 86324cf18b2b43c7f08ebe0b3fd128a7973c7396..c6093a8a1c93d420f2ceacdb6827dd8ed33ccbe8 100644 (file)
@@ -47,6 +47,7 @@ struct dns_keynode {
        isc_refcount_t          refcount;
        dst_key_t *             key;
        isc_boolean_t           managed;
+       isc_boolean_t           initial;
        struct dns_keynode *    next;
 };
 
@@ -164,83 +165,169 @@ dns_keytable_detach(dns_keytable_t **keytablep) {
        *keytablep = NULL;
 }
 
+/*%
+ * Search "node" for either a null key node or a key node for the exact same
+ * key as the one supplied in "keyp" and, if found, update it accordingly.
+ */
 static isc_result_t
-insert(dns_keytable_t *keytable, isc_boolean_t managed,
-       const dns_name_t *keyname, dst_key_t **keyp)
+update_keynode(dst_key_t **keyp, dns_rbtnode_t *node, isc_boolean_t initial) {
+       dns_keynode_t *knode;
+
+       REQUIRE(keyp != NULL && *keyp != NULL);
+       REQUIRE(node != NULL);
+
+       for (knode = node->data; knode != NULL; knode = knode->next) {
+               if (knode->key == NULL) {
+                       /*
+                        * Null key node found.  Attach the supplied key to it,
+                        * making it a non-null key node and transferring key
+                        * ownership to the keytable.
+                        */
+                       knode->key = *keyp;
+                       *keyp = NULL;
+                       return (ISC_R_SUCCESS);
+               } else if (dst_key_compare(knode->key, *keyp)) {
+                       /*
+                        * Key node found for the supplied key.  Free the
+                        * supplied copy of the key and update the found key
+                        * node's flags if necessary.
+                        */
+                       dst_key_free(keyp);
+                       if (!initial) {
+                               dns_keynode_trust(knode);
+                       }
+                       return (ISC_R_SUCCESS);
+               }
+       }
+
+       return (ISC_R_NOTFOUND);
+}
+
+/*%
+ * Create a key node for "keyp" (or a null key node if "keyp" is NULL), set
+ * "managed" and "initial" as requested and make the created key node the first
+ * one attached to "node" in "keytable".
+ */
+static isc_result_t
+prepend_keynode(dst_key_t **keyp, dns_rbtnode_t *node,
+               dns_keytable_t *keytable, isc_boolean_t managed,
+               isc_boolean_t initial)
 {
-       isc_result_t result;
        dns_keynode_t *knode = NULL;
-       dns_rbtnode_t *node;
+       isc_result_t result;
 
        REQUIRE(keyp == NULL || *keyp != NULL);
        REQUIRE(VALID_KEYTABLE(keytable));
+       REQUIRE(!initial || managed);
 
        result = dns_keynode_create(keytable->mctx, &knode);
-       if (result != ISC_R_SUCCESS)
+       if (result != ISC_R_SUCCESS) {
                return (result);
+       }
 
-       knode->managed = managed;
+       /*
+        * If a key was supplied, transfer its ownership to the keytable.
+        */
+       if (keyp) {
+               knode->key = *keyp;
+               *keyp = NULL;
+       }
 
-       RWLOCK(&keytable->rwlock, isc_rwlocktype_write);
+       knode->managed = managed;
+       knode->initial = initial;
+       knode->next = node->data;
+       node->data = knode;
 
-       node = NULL;
-       result = dns_rbt_addnode(keytable->table, keyname, &node);
+       return (ISC_R_SUCCESS);
+}
 
-       if (keyp != NULL) {
-               if (result == ISC_R_EXISTS) {
-                       /* Key already in table? */
-                       dns_keynode_t *k;
-                       for (k = node->data; k != NULL; k = k->next) {
-                               if (k->key == NULL) {
-                                       k->key = *keyp;
-                                       *keyp = NULL; /* transfer ownership */
-                                       break;
-                               }
-                               if (dst_key_compare(k->key, *keyp) == ISC_TRUE)
-                                       break;
-                       }
+/*%
+ * Add key "keyp" at "keyname" in "keytable".  If the key already exists at the
+ * requested name, update its flags.  If "keyp" is NULL, add a null key to
+ * indicate that "keyname" should be treated as a secure domain without
+ * supplying key data which would allow the domain to be validated.
+ */
+static isc_result_t
+insert(dns_keytable_t *keytable, isc_boolean_t managed, isc_boolean_t initial,
+       const dns_name_t *keyname, dst_key_t **keyp)
+{
+       dns_rbtnode_t *node = NULL;
+       isc_result_t result;
 
-                       if (k == NULL)
-                               result = ISC_R_SUCCESS;
-                       else if (*keyp != NULL)
-                               dst_key_free(keyp);
-               }
+       REQUIRE(VALID_KEYTABLE(keytable));
 
-               if (result == ISC_R_SUCCESS) {
-                       knode->key = *keyp;
-                       knode->next = node->data;
-                       *keyp = NULL;
-               }
-       }
+       RWLOCK(&keytable->rwlock, isc_rwlocktype_write);
 
+       result = dns_rbt_addnode(keytable->table, keyname, &node);
        if (result == ISC_R_SUCCESS) {
-               node->data = knode;
-               knode = NULL;
+               /*
+                * There was no node for "keyname" in "keytable" yet, so one
+                * was created.  Create a new key node for the supplied key (or
+                * a null key node if "keyp" is NULL) and attach it to the
+                * created node.
+                */
+               result = prepend_keynode(keyp, node, keytable, managed,
+                                        initial);
+       } else if (result == ISC_R_EXISTS) {
+               /*
+                * A node already exists for "keyname" in "keytable".
+                */
+               if (keyp == NULL) {
+                       /*
+                        * We were told to add a null key at "keyname", which
+                        * means there is nothing left to do as there is either
+                        * a null key at this node already or there is a
+                        * non-null key node which would not be affected.
+                        * Reset result to reflect the fact that the node for
+                        * "keyname" is already marked as secure.
+                        */
+                       result = ISC_R_SUCCESS;
+               } else {
+                       /*
+                        * We were told to add the key supplied in "keyp" at
+                        * "keyname".  Try to find an already existing key node
+                        * we could reuse for the supplied key (i.e. a null key
+                        * node or a key node for the exact same key) and, if
+                        * found, update it accordingly.
+                        */
+                       result = update_keynode(keyp, node, initial);
+                       if (result == ISC_R_NOTFOUND) {
+                               /*
+                                * The node for "keyname" only contains key
+                                * nodes for keys different than the supplied
+                                * one.  Create a new key node for the supplied
+                                * key and prepend it before the others.
+                                */
+                               result = prepend_keynode(keyp, node, keytable,
+                                                        managed, initial);
+                       }
+               }
        }
 
-       /* Key was already there?  That's the same as a success */
-       if (result == ISC_R_EXISTS)
-               result = ISC_R_SUCCESS;
-
        RWUNLOCK(&keytable->rwlock, isc_rwlocktype_write);
 
-       if (knode != NULL)
-               dns_keynode_detach(keytable->mctx, &knode);
-
        return (result);
 }
 
 isc_result_t
 dns_keytable_add(dns_keytable_t *keytable, isc_boolean_t managed,
                 dst_key_t **keyp)
+{
+       return (dns_keytable_add2(keytable, managed, ISC_FALSE, keyp));
+}
+
+isc_result_t
+dns_keytable_add2(dns_keytable_t *keytable, isc_boolean_t managed,
+                 isc_boolean_t initial, dst_key_t **keyp)
 {
        REQUIRE(keyp != NULL && *keyp != NULL);
-       return (insert(keytable, managed, dst_key_name(*keyp), keyp));
+       REQUIRE(!initial || managed);
+       return (insert(keytable, managed, initial, dst_key_name(*keyp), keyp));
 }
 
 isc_result_t
 dns_keytable_marksecure(dns_keytable_t *keytable, const dns_name_t *name) {
-       return (insert(keytable, ISC_TRUE, name, NULL));
+       return (insert(keytable, ISC_TRUE, ISC_FALSE, name, NULL));
 }
 
 isc_result_t
@@ -644,8 +731,9 @@ dns_keytable_totext(dns_keytable_t *keytable, isc_buffer_t **text) {
                        if (knode->key == NULL)
                                continue;
                        dst_key_format(knode->key, pbuf, sizeof(pbuf));
-                       snprintf(obuf, sizeof(obuf), "%s ; %s\n", pbuf,
-                               knode->managed ? "managed" : "trusted");
+                       snprintf(obuf, sizeof(obuf), "%s ; %s%s\n", pbuf,
+                                knode->initial ? "initializing " : "",
+                                knode->managed ? "managed" : "trusted");
                        result = putstr(text, obuf);
                        if (result != ISC_R_SUCCESS)
                                break;
@@ -703,11 +791,6 @@ dns_keytable_forall(dns_keytable_t *keytable,
 
 dst_key_t *
 dns_keynode_key(dns_keynode_t *keynode) {
-
-       /*
-        * Get the DST key associated with keynode.
-        */
-
        REQUIRE(VALID_KEYNODE(keynode));
 
        return (keynode->key);
@@ -715,14 +798,25 @@ dns_keynode_key(dns_keynode_t *keynode) {
 
 isc_boolean_t
 dns_keynode_managed(dns_keynode_t *keynode) {
-       /*
-        * Is this a managed key?
-        */
        REQUIRE(VALID_KEYNODE(keynode));
 
        return (keynode->managed);
 }
 
+isc_boolean_t
+dns_keynode_initial(dns_keynode_t *keynode) {
+       REQUIRE(VALID_KEYNODE(keynode));
+
+       return (keynode->initial);
+}
+
+void
+dns_keynode_trust(dns_keynode_t *keynode) {
+       REQUIRE(VALID_KEYNODE(keynode));
+
+       keynode->initial = ISC_FALSE;
+}
+
 isc_result_t
 dns_keynode_create(isc_mem_t *mctx, dns_keynode_t **target) {
        isc_result_t result;
@@ -736,6 +830,7 @@ dns_keynode_create(isc_mem_t *mctx, dns_keynode_t **target) {
 
        knode->magic = KEYNODE_MAGIC;
        knode->managed = ISC_FALSE;
+       knode->initial = ISC_FALSE;
        knode->key = NULL;
        knode->next = NULL;
 
index cf71b054a431284cbe2d07820903aa7f4be73e13..1f620dd9a9235cbff51d18329d834919afdf1a3b 100644 (file)
@@ -10595,8 +10595,8 @@ dns_resolver_addbadcache(dns_resolver_t *resolver, const dns_name_t *name,
        if (!fuzzing_resolver)
 #endif
        {
-               (void) dns_badcache_add(resolver->badcache, name, type,
-                                       ISC_FALSE, 0, expire);
+               dns_badcache_add(resolver->badcache, name, type,
+                                ISC_FALSE, 0, expire);
        }
 }
 
index 52219b699cd855a13fc638f2e523e70d8d74b2fd..605734021938dcf939d12b5fce65a662a6d315f7 100644 (file)
@@ -126,7 +126,12 @@ create_tables() {
 
        /* Add a normal key */
        create_key(257, 3, 5, "example.com", keystr1, &key);
-       ATF_REQUIRE_EQ(dns_keytable_add(keytable, ISC_FALSE, &key),
+       ATF_REQUIRE_EQ(dns_keytable_add2(keytable, ISC_FALSE, ISC_FALSE, &key),
+                      ISC_R_SUCCESS);
+
+       /* Add an initializing managed key */
+       create_key(257, 3, 5, "managed.com", keystr1, &key);
+       ATF_REQUIRE_EQ(dns_keytable_add2(keytable, ISC_TRUE, ISC_TRUE, &key),
                       ISC_R_SUCCESS);
 
        /* Add a null key */
@@ -185,7 +190,7 @@ ATF_TC_BODY(add, tc) {
         * nextkeynode() should still return NOTFOUND.
         */
        create_key(257, 3, 5, "example.com", keystr1, &key);
-       ATF_REQUIRE_EQ(dns_keytable_add(keytable, ISC_FALSE, &key),
+       ATF_REQUIRE_EQ(dns_keytable_add2(keytable, ISC_FALSE, ISC_FALSE, &key),
                       ISC_R_SUCCESS);
        ATF_REQUIRE_EQ(dns_keytable_nextkeynode(keytable, keynode,
                                                &next_keynode), ISC_R_NOTFOUND);
@@ -193,23 +198,129 @@ ATF_TC_BODY(add, tc) {
        /* Add another key (different keydata) */
        dns_keytable_detachkeynode(keytable, &keynode);
        create_key(257, 3, 5, "example.com", keystr2, &key);
-       ATF_REQUIRE_EQ(dns_keytable_add(keytable, ISC_FALSE, &key),
+       ATF_REQUIRE_EQ(dns_keytable_add2(keytable, ISC_FALSE, ISC_FALSE, &key),
                       ISC_R_SUCCESS);
        ATF_REQUIRE_EQ(dns_keytable_find(keytable, str2name("example.com"),
                                         &keynode), ISC_R_SUCCESS);
        ATF_REQUIRE_EQ(dns_keytable_nextkeynode(keytable, keynode,
                                                &next_keynode), ISC_R_SUCCESS);
        dns_keytable_detachkeynode(keytable, &next_keynode);
+       dns_keytable_detachkeynode(keytable, &keynode);
+
+       /*
+        * Get the keynode for the managed.com key.  There's no other key for
+        * the name, so nextkeynode() should return NOTFOUND.  Ensure the
+        * retrieved key is an initializing key, then mark it as trusted using
+        * dns_keynode_trust() and ensure the latter works as expected.
+        */
+       ATF_REQUIRE_EQ(dns_keytable_find(keytable, str2name("managed.com"),
+                                        &keynode), ISC_R_SUCCESS);
+       ATF_REQUIRE_EQ(dns_keytable_nextkeynode(keytable, keynode,
+                                               &next_keynode), ISC_R_NOTFOUND);
+       ATF_REQUIRE_EQ(dns_keynode_initial(keynode), ISC_TRUE);
+       dns_keynode_trust(keynode);
+       ATF_REQUIRE_EQ(dns_keynode_initial(keynode), ISC_FALSE);
+       dns_keytable_detachkeynode(keytable, &keynode);
+
+       /*
+        * Add a different managed key for managed.com, marking it as an
+        * initializing key.  Ensure nextkeynode() no longer returns
+        * ISC_R_NOTFOUND and that the added key is an initializing key.
+        */
+       create_key(257, 3, 5, "managed.com", keystr2, &key);
+       ATF_REQUIRE_EQ(dns_keytable_add2(keytable, ISC_TRUE, ISC_TRUE, &key),
+                      ISC_R_SUCCESS);
+       ATF_REQUIRE_EQ(dns_keytable_find(keytable, str2name("managed.com"),
+                                        &keynode), ISC_R_SUCCESS);
+       ATF_REQUIRE_EQ(dns_keytable_nextkeynode(keytable, keynode,
+                                               &next_keynode), ISC_R_SUCCESS);
+       ATF_REQUIRE_EQ(dns_keynode_initial(keynode), ISC_TRUE);
+       dns_keytable_detachkeynode(keytable, &next_keynode);
+       dns_keytable_detachkeynode(keytable, &keynode);
+
+       /*
+        * Add the same managed key again, but this time mark it as a
+        * non-initializing key.  Ensure the previously added key is upgraded
+        * to a non-initializing key and make sure there are still two key
+        * nodes for managed.com, both containing non-initializing keys.
+        */
+       create_key(257, 3, 5, "managed.com", keystr2, &key);
+       ATF_REQUIRE_EQ(dns_keytable_add2(keytable, ISC_TRUE, ISC_FALSE, &key),
+                      ISC_R_SUCCESS);
+       ATF_REQUIRE_EQ(dns_keytable_find(keytable, str2name("managed.com"),
+                                        &keynode), ISC_R_SUCCESS);
+       ATF_REQUIRE_EQ(dns_keynode_initial(keynode), ISC_FALSE);
+       ATF_REQUIRE_EQ(dns_keytable_nextkeynode(keytable, keynode,
+                                               &next_keynode), ISC_R_SUCCESS);
+       dns_keytable_detachkeynode(keytable, &keynode);
+       keynode = next_keynode;
+       next_keynode = NULL;
+       ATF_REQUIRE_EQ(dns_keynode_initial(keynode), ISC_FALSE);
+       ATF_REQUIRE_EQ(dns_keytable_nextkeynode(keytable, keynode,
+                                               &next_keynode), ISC_R_NOTFOUND);
+       dns_keytable_detachkeynode(keytable, &keynode);
+
+       /*
+        * Add a managed key at a new node, two.com, marking it as an
+        * initializing key.  Ensure nextkeynode() returns ISC_R_NOTFOUND and
+        * that the added key is an initializing key.
+        */
+       create_key(257, 3, 5, "two.com", keystr1, &key);
+       ATF_REQUIRE_EQ(dns_keytable_add2(keytable, ISC_TRUE, ISC_TRUE, &key),
+                      ISC_R_SUCCESS);
+       ATF_REQUIRE_EQ(dns_keytable_find(keytable, str2name("two.com"),
+                                        &keynode), ISC_R_SUCCESS);
+       ATF_REQUIRE_EQ(dns_keytable_nextkeynode(keytable, keynode,
+                                               &next_keynode), ISC_R_NOTFOUND);
+       ATF_REQUIRE_EQ(dns_keynode_initial(keynode), ISC_TRUE);
+       dns_keytable_detachkeynode(keytable, &keynode);
+
+       /*
+        * Add a different managed key for two.com, marking it as a
+        * non-initializing key.  Ensure nextkeynode() no longer returns
+        * ISC_R_NOTFOUND and that the added key is not an initializing key.
+        */
+       create_key(257, 3, 5, "two.com", keystr2, &key);
+       ATF_REQUIRE_EQ(dns_keytable_add2(keytable, ISC_TRUE, ISC_FALSE, &key),
+                      ISC_R_SUCCESS);
+       ATF_REQUIRE_EQ(dns_keytable_find(keytable, str2name("two.com"),
+                                        &keynode), ISC_R_SUCCESS);
+       ATF_REQUIRE_EQ(dns_keytable_nextkeynode(keytable, keynode,
+                                               &next_keynode), ISC_R_SUCCESS);
+       ATF_REQUIRE_EQ(dns_keynode_initial(keynode), ISC_FALSE);
+       dns_keytable_detachkeynode(keytable, &next_keynode);
+       dns_keytable_detachkeynode(keytable, &keynode);
+
+       /*
+        * Add the first managed key again, but this time mark it as a
+        * non-initializing key.  Ensure the previously added key is upgraded
+        * to a non-initializing key and make sure there are still two key
+        * nodes for two.com, both containing non-initializing keys.
+        */
+       create_key(257, 3, 5, "two.com", keystr1, &key);
+       ATF_REQUIRE_EQ(dns_keytable_add2(keytable, ISC_TRUE, ISC_FALSE, &key),
+                      ISC_R_SUCCESS);
+       ATF_REQUIRE_EQ(dns_keytable_find(keytable, str2name("two.com"),
+                                        &keynode), ISC_R_SUCCESS);
+       ATF_REQUIRE_EQ(dns_keynode_initial(keynode), ISC_FALSE);
+       ATF_REQUIRE_EQ(dns_keytable_nextkeynode(keytable, keynode,
+                                               &next_keynode), ISC_R_SUCCESS);
+       dns_keytable_detachkeynode(keytable, &keynode);
+       keynode = next_keynode;
+       next_keynode = NULL;
+       ATF_REQUIRE_EQ(dns_keynode_initial(keynode), ISC_FALSE);
+       ATF_REQUIRE_EQ(dns_keytable_nextkeynode(keytable, keynode,
+                                               &next_keynode), ISC_R_NOTFOUND);
+       dns_keytable_detachkeynode(keytable, &keynode);
 
        /*
         * Add a normal key to a name that has a null key.  The null key node
         * will be updated with the normal key.
         */
-       dns_keytable_detachkeynode(keytable, &keynode);
        ATF_REQUIRE_EQ(dns_keytable_find(keytable, str2name("null.example"),
                                         &null_keynode), ISC_R_SUCCESS);
        create_key(257, 3, 5, "null.example", keystr2, &key);
-       ATF_REQUIRE_EQ(dns_keytable_add(keytable, ISC_FALSE, &key),
+       ATF_REQUIRE_EQ(dns_keytable_add2(keytable, ISC_FALSE, ISC_FALSE, &key),
                       ISC_R_SUCCESS);
        ATF_REQUIRE_EQ(dns_keytable_find(keytable, str2name("null.example"),
                                         &keynode), ISC_R_SUCCESS);
@@ -523,7 +634,7 @@ ATF_TC_BODY(nta, tc) {
        ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
 
        create_key(257, 3, 5, "example", keystr1, &key);
-       result = dns_keytable_add(keytable, ISC_FALSE, &key);
+       result = dns_keytable_add2(keytable, ISC_FALSE, ISC_FALSE, &key);
        ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
 
        isc_stdtime_get(&now);
index 6747ade8ee1c4c4f6f1a8dbd8e342abf0b331784..cd5e85ed8c12db646191b0675acc5a93a8d16a64 100644 (file)
@@ -431,10 +431,13 @@ dns_keynode_attach
 dns_keynode_create
 dns_keynode_detach
 dns_keynode_detachall
+dns_keynode_initial
 dns_keynode_key
 dns_keynode_managed
+dns_keynode_trust
 dns_keyring_restore
 dns_keytable_add
+dns_keytable_add2
 dns_keytable_attach
 dns_keytable_attachkeynode
 dns_keytable_create
index 4e608d0cf799c12b9aa2ff24097ff3ebe0584d33..c0a95979170333dd75fd3ecad5262aeed4cb25bd 100644 (file)
@@ -3891,7 +3891,8 @@ compute_tag(dns_name_t *name, dns_rdata_dnskey_t *dnskey, isc_mem_t *mctx,
  */
 static void
 trust_key(dns_zone_t *zone, dns_name_t *keyname,
-         dns_rdata_dnskey_t *dnskey, isc_mem_t *mctx)
+         dns_rdata_dnskey_t *dnskey, isc_boolean_t initial,
+         isc_mem_t *mctx)
 {
        isc_result_t result;
        dns_rdata_t rdata = DNS_RDATA_INIT;
@@ -3910,7 +3911,7 @@ trust_key(dns_zone_t *zone, dns_name_t *keyname,
                goto failure;
 
        CHECK(dns_dnssec_keyfromrdata(keyname, &rdata, mctx, &dstkey));
-       CHECK(dns_keytable_add(sr, ISC_TRUE, &dstkey));
+       CHECK(dns_keytable_add2(sr, ISC_TRUE, initial, &dstkey));
        dns_keytable_detach(&sr);
 
   failure:
@@ -3996,7 +3997,8 @@ load_secroots(dns_zone_t *zone, dns_name_t *name, dns_rdataset_t *rdataset) {
 
                /* Add to keytables. */
                trusted++;
-               trust_key(zone, name, &dnskey, mctx);
+               trust_key(zone, name, &dnskey,
+                         ISC_TF(keydata.addhd == 0), mctx);
        }
 
        if (trusted == 0 && pending != 0) {
@@ -4731,8 +4733,9 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
 
        case dns_zone_key:
                result = sync_keyzone(zone, db);
-               if (result != ISC_R_SUCCESS)
+               if (result != ISC_R_SUCCESS) {
                        goto cleanup;
+               }
                break;
 
        default:
@@ -4882,9 +4885,17 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
        return (result);
 
  cleanup:
+       if (zone->type == dns_zone_key && result != ISC_R_SUCCESS) {
+               dns_zone_log(zone, ISC_LOG_ERROR,
+                            "failed to initialize managed-keys (%s): "
+                            "DNSSEC validation is at risk",
+                            isc_result_totext(result));
+       }
+
        for (inc = ISC_LIST_HEAD(zone->newincludes);
             inc != NULL;
-            inc = ISC_LIST_HEAD(zone->newincludes)) {
+            inc = ISC_LIST_HEAD(zone->newincludes))
+       {
                ISC_LIST_UNLINK(zone->newincludes, inc, link);
                isc_mem_free(zone->mctx, inc->name);
                isc_mem_put(zone->mctx, inc, sizeof(*inc));
@@ -9045,7 +9056,7 @@ keyfetch_done(isc_task_t *task, isc_event_t *event) {
        dst_key_t *dstkey;
        isc_stdtime_t now;
        int pending = 0;
-       isc_boolean_t secure = ISC_FALSE;
+       isc_boolean_t secure = ISC_FALSE, initial = ISC_FALSE;
        isc_boolean_t free_needed;
 
        UNUSED(task);
@@ -9122,7 +9133,8 @@ keyfetch_done(isc_task_t *task, isc_event_t *event) {
         */
        for (result = dns_rdataset_first(&kfetch->dnskeysigset);
             result == ISC_R_SUCCESS;
-            result = dns_rdataset_next(&kfetch->dnskeysigset)) {
+            result = dns_rdataset_next(&kfetch->dnskeysigset))
+       {
                dns_keynode_t *keynode = NULL;
 
                dns_rdata_reset(&sigrr);
@@ -9141,7 +9153,8 @@ keyfetch_done(isc_task_t *task, isc_event_t *event) {
                                break;
 
                        if (dst_key_alg(dstkey) == sig.algorithm &&
-                           dst_key_id(dstkey) == sig.keyid) {
+                           dst_key_id(dstkey) == sig.keyid)
+                       {
                                result = dns_dnssec_verify2(keyname,
                                                    &kfetch->dnskeyset,
                                                    dstkey, ISC_FALSE,
@@ -9159,6 +9172,9 @@ keyfetch_done(isc_task_t *task, isc_event_t *event) {
                                                dns_trust_secure;
                                        kfetch->dnskeysigset.trust =
                                                dns_trust_secure;
+                                       secure = ISC_TRUE;
+                                       initial = dns_keynode_initial(keynode);
+                                       dns_keynode_trust(keynode);
                                        break;
                                }
                        }
@@ -9169,11 +9185,11 @@ keyfetch_done(isc_task_t *task, isc_event_t *event) {
                        keynode = nextnode;
                }
 
-               if (keynode != NULL)
+               if (keynode != NULL) {
                        dns_keytable_detachkeynode(secroots, &keynode);
+               }
 
-               if (kfetch->dnskeyset.trust == dns_trust_secure) {
-                       secure = ISC_TRUE;
+               if (secure) {
                        break;
                }
        }
@@ -9182,7 +9198,6 @@ keyfetch_done(isc_task_t *task, isc_event_t *event) {
         * If we were not able to verify the answer using the current
         * trusted keys then all we can do is look at any revoked keys.
         */
-
        if (!secure) {
                dns_zone_log(zone, ISC_LOG_DEBUG(3),
                             "DNSKEY set for zone '%s' could not be verified "
@@ -9422,10 +9437,13 @@ keyfetch_done(isc_task_t *task, isc_event_t *event) {
                                        trustkey = ISC_TRUE;
                                        dns_zone_log(zone, ISC_LOG_INFO,
                                                     "Key %d for zone %s "
-                                                    "acceptance timer "
-                                                    "complete: "
-                                                    "key now trusted",
-                                                    keytag, namebuf);
+                                                    "is now trusted (%s)",
+                                                    keytag, namebuf,
+                                                    initial
+                                                     ? "initializing key "
+                                                       "verified"
+                                                     : "acceptance timer "
+                                                       "complete");
                                }
                        } else if (keydata.addhd > now) {
                                /*
@@ -9524,7 +9542,7 @@ keyfetch_done(isc_task_t *task, isc_event_t *event) {
                        /* Trust this key. */
                        result = dns_rdata_tostruct(&dnskeyrr, &dnskey, NULL);
                        RUNTIME_CHECK(result == ISC_R_SUCCESS);
-                       trust_key(zone, keyname, &dnskey, mctx);
+                       trust_key(zone, keyname, &dnskey, ISC_FALSE, mctx);
                }
 
                if (secure && !deletekey) {
@@ -9546,7 +9564,6 @@ keyfetch_done(isc_task_t *task, isc_event_t *event) {
                fail_secure(zone, keyname);
 
  done:
-
        if (!ISC_LIST_EMPTY(diff.tuples)) {
                /* Write changes to journal file. */
                CHECK(update_soa_serial(kfetch->db, ver, &diff, mctx,
@@ -9559,7 +9576,12 @@ keyfetch_done(isc_task_t *task, isc_event_t *event) {
        }
 
  failure:
-
+       if (result != ISC_R_SUCCESS) {
+               dns_zone_log(zone, ISC_LOG_ERROR,
+                            "error during managed-keys processing (%s): "
+                            "DNSSEC validation may be at risk",
+                            isc_result_totext(result));
+       }
        dns_diff_clear(&diff);
        if (ver != NULL)
                dns_db_closeversion(kfetch->db, &ver, commit);
@@ -9669,7 +9691,7 @@ zone_refreshkeys(dns_zone_t *zone) {
                        }
 
                        /* Acceptance timer expired? */
-                       if (kd.addhd != 0 && kd.addhd < now)
+                       if (kd.addhd < now)
                                timer = kd.addhd;
 
                        /* Or do we just need to refresh the keyset? */