]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
3185. [func] New 'rndc signing' option for auto-dnssec zones:
authorEvan Hunt <each@isc.org>
Fri, 28 Oct 2011 06:20:07 +0000 (06:20 +0000)
committerEvan Hunt <each@isc.org>
Fri, 28 Oct 2011 06:20:07 +0000 (06:20 +0000)
 - 'rndc signing -list' displays the current
   state of signing operations
 - 'rndc signing -clear' clears the signing state
      records for keys that have fully signed the zone
 - 'rndc signing -nsec3param' sets the NSEC3
   parameters for the zone
The 'rndc keydone' syntax is removed. [RT #23729]

23 files changed:
CHANGES
bin/named/control.c
bin/named/include/named/control.h
bin/named/include/named/server.h
bin/named/server.c
bin/named/update.c
bin/rndc/rndc.c
bin/tests/system/autosign/tests.sh
bin/tests/system/dnssec/clean.sh
bin/tests/system/dnssec/ns3/named.conf
bin/tests/system/dnssec/tests.sh
bin/tests/system/inline/clean.sh
bin/tests/system/inline/tests.sh
doc/arm/Bv9ARM-book.xml
lib/dns/include/dns/events.h
lib/dns/include/dns/nsec3.h
lib/dns/include/dns/private.h
lib/dns/include/dns/zone.h
lib/dns/nsec3.c
lib/dns/private.c
lib/dns/tests/Makefile.in
lib/dns/tests/private_test.c [new file with mode: 0644]
lib/dns/zone.c

diff --git a/CHANGES b/CHANGES
index f1c1fdb2a0471f4b26cdc38338ea6ffdfff1aa48..2e90fb9347e2bef5e453a4db68706e9d8522ae59 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,12 @@
+3185.  [func]          New 'rndc signing' option for auto-dnssec zones:
+                        - 'rndc signing -list' displays the current
+                          state of signing operations
+                        - 'rndc signing -clear' clears the signing state
+                          records for keys that have fully signed the zone
+                        - 'rndc signing -nsec3param' sets the NSEC3
+                          parameters for the zone
+                       The 'rndc keydone' syntax is removed. [RT #23729]
+
 3184.  [bug]           named had excessive cpu usage when a redirect zone was
                        configured. [RT #26013]
 
index 006aba2115601ba7e6661536bcfdd02c9cdbcf3d..8a67b97ec07bc3edb6535a1e9945668350d4ea8f 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: control.c,v 1.45 2011/10/25 01:54:18 marka Exp $ */
+/* $Id: control.c,v 1.46 2011/10/28 06:20:04 each Exp $ */
 
 /*! \file */
 
@@ -205,8 +205,8 @@ ns_control_docommand(isccc_sexpr_t *message, isc_buffer_t *text) {
                result = ns_server_add_zone(ns_g_server, command);
        } else if (command_compare(command, NS_COMMAND_DELZONE)) {
                result = ns_server_del_zone(ns_g_server, command);
-       } else if (command_compare(command, NS_COMMAND_KEYDONE)) {
-               result = ns_server_keydone(ns_g_server, command);
+       } else if (command_compare(command, NS_COMMAND_SIGNING)) {
+               result = ns_server_signing(ns_g_server, command, text);
        } else {
                isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
                              NS_LOGMODULE_CONTROL, ISC_LOG_WARNING,
index 31ca427de5cbd5227a515e0f30b7b5f4f3856f55..064ec50e2ae0729fa47f15f47ba6bfeacaaad0cc 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: control.h,v 1.35 2011/10/25 01:54:19 marka Exp $ */
+/* $Id: control.h,v 1.36 2011/10/28 06:20:04 each Exp $ */
 
 #ifndef NAMED_CONTROL_H
 #define NAMED_CONTROL_H 1
@@ -64,7 +64,7 @@
 #define NS_COMMAND_ADDZONE     "addzone"
 #define NS_COMMAND_DELZONE     "delzone"
 #define NS_COMMAND_SYNC                "sync"
-#define NS_COMMAND_KEYDONE     "keydone"
+#define NS_COMMAND_SIGNING     "signing"
 
 isc_result_t
 ns_controls_create(ns_server_t *server, ns_controls_t **ctrlsp);
index 332bef738ca7ca154a34952c53c3bf30efa70f2f..e05222aaaa6e75b4c3d2d2c372c312d57fb019f7 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: server.h,v 1.114 2011/10/25 01:54:19 marka Exp $ */
+/* $Id: server.h,v 1.115 2011/10/28 06:20:04 each Exp $ */
 
 #ifndef NAMED_SERVER_H
 #define NAMED_SERVER_H 1
@@ -343,9 +343,8 @@ isc_result_t
 ns_server_del_zone(ns_server_t *server, char *args);
 
 /*%
- * Deletes the matching key done private record from the zone.
+ * Lists the status of the signing records for a given zone.
  */
 isc_result_t
-ns_server_keydone(ns_server_t *server, char *args);
-
+ns_server_signing(ns_server_t *server, char *args, isc_buffer_t *text);
 #endif /* NAMED_SERVER_H */
index 18fa5317b367fe67b93d429ded21d2aa8b455181..9b71eae6f62c405802119f09c745d909f76d5264 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: server.c,v 1.623 2011/10/25 01:54:19 marka Exp $ */
+/* $Id: server.c,v 1.624 2011/10/28 06:20:04 each Exp $ */
 
 /*! \file */
 
@@ -34,6 +34,7 @@
 #include <isc/entropy.h>
 #include <isc/file.h>
 #include <isc/hash.h>
+#include <isc/hex.h>
 #include <isc/httpd.h>
 #include <isc/lex.h>
 #include <isc/parseint.h>
@@ -73,6 +74,7 @@
 #include <dns/order.h>
 #include <dns/peer.h>
 #include <dns/portlist.h>
+#include <dns/private.h>
 #include <dns/rbt.h>
 #include <dns/rdataclass.h>
 #include <dns/rdataset.h>
@@ -7858,46 +7860,142 @@ newzone_cfgctx_destroy(void **cfgp) {
        *cfgp = NULL;
 }
 
-/*
- * Act on a "keydone" command from the command channel.
- */
 isc_result_t
-ns_server_keydone(ns_server_t *server, char *args) {
-       isc_result_t result;
+ns_server_signing(ns_server_t *server, char *args, isc_buffer_t *text) {
+       isc_result_t result = ISC_R_SUCCESS;
        dns_zone_t *zone = NULL;
-       const char *ptr = NULL;
-
+       dns_name_t *origin;
+       dns_db_t *db = NULL;
+       dns_dbnode_t *node = NULL;
+       dns_dbversion_t *version = NULL;
+       dns_rdatatype_t privatetype;
+       dns_rdataset_t privset;
+       isc_boolean_t first = ISC_TRUE;
+       isc_boolean_t list = ISC_FALSE, clear = ISC_FALSE;
+       isc_boolean_t chain = ISC_FALSE;
+       char keystr[DNS_SECALG_FORMATSIZE + 7];
+       isc_uint8_t hash = 0, flags = 0, iter = 0, saltlen = 0;
+       unsigned char salt[255];
+       const char *ptr;
+       size_t n;
+
+       dns_rdataset_init(&privset);
+
+       (void) next_token(&args, " \t");
        ptr = next_token(&args, " \t");
-       if (ptr == NULL)
-               return (ISC_R_UNEXPECTEDEND);
+       if (strcasecmp(ptr, "-list") == 0)
+               list = ISC_TRUE;
+       else if (strcasecmp(ptr, "-clear") == 0) {
+               clear = ISC_TRUE;
+               ptr = next_token(&args, " \t");
+               memcpy(keystr, ptr, sizeof(keystr));
+       } else if(strcasecmp(ptr, "-nsec3param") == 0) {
+               const char *hashstr, *flagstr, *iterstr;
+               isc_buffer_t buf;
+               char nbuf[512];
 
-       ptr = next_token(&args, " \t");
-       if (ptr == NULL)
-               return (ISC_R_UNEXPECTEDEND);
-       /*
-        * Is the rdata sane?
-        */
-       if (strspn(ptr, "0123456789ABCDEFabcdef") != 10U ||
-           strncmp(ptr, "00", 2) == 0 || strcmp(ptr + 6, "0001") != 0)
-               return (DNS_R_SYNTAX);
+               chain = ISC_TRUE;
+               hashstr = next_token(&args, " \t");
 
-       /*
-        * Find the zone.
-        */
-       result = zone_from_args(server, args, &zone, NULL, ISC_FALSE);
-       if (result != ISC_R_SUCCESS)
-               return (result);
+               if (strcasecmp(hashstr, "none") == 0)
+                       hash = 0;
+               else {
+                       flagstr = next_token(&args, " \t");
+                       iterstr = next_token(&args, " \t");
+                       n = snprintf(nbuf, sizeof(nbuf), "%s %s %s",
+                                    hashstr, flagstr, iterstr);
+                       if (n == sizeof(nbuf))
+                               return (ISC_R_NOSPACE);
+                       n = sscanf(nbuf, "%hhd %hhd %hhd",
+                                  &hash, &flags, &iter);
+                       if (n != 3)
+                               return (ISC_R_BADNUMBER);
+
+                       ptr = next_token(&args, " \t");
+                       isc_buffer_init(&buf, salt, sizeof(salt));
+                       CHECK(isc_hex_decodestring(ptr, &buf));
+                       saltlen = isc_buffer_usedlength(&buf);
+               }
+       } else
+               CHECK(ISC_R_NOTFOUND);
+
+       CHECK(zone_from_args(server, args, &zone, NULL, ISC_FALSE));
        if (zone == NULL)
-               return(ISC_R_NOTFOUND);
+               CHECK(ISC_R_UNEXPECTEDEND);
 
-       if (dns_zone_gettype(zone) != dns_zone_master) {
-               result = DNS_R_NOTMASTER;
-               goto cleanup;
-       }
+       if (clear) {
+               result = dns_zone_keydone(zone, keystr);
+               if (result == ISC_R_SUCCESS) {
+                       isc_buffer_putstr(text, "request queued");
+                       isc_buffer_putuint8(text, 0);
+               } else
+                       CHECK(result);
+       } else if (chain) {
+               result = dns_zone_setnsec3param(zone, hash, flags, iter,
+                                               saltlen, salt, ISC_TRUE);
+               if (result == ISC_R_SUCCESS) {
+                       isc_buffer_putstr(text, "request queued");
+                       isc_buffer_putuint8(text, 0);
+               } else
+                       CHECK(result);
+       } else {
+               privatetype = dns_zone_getprivatetype(zone);
+               origin = dns_zone_getorigin(zone);
+               CHECK(dns_zone_getdb(zone, &db));
+               CHECK(dns_db_findnode(db, origin, ISC_FALSE, &node));
+               dns_db_currentversion(db, &version);
+
+               result = dns_db_findrdataset(db, node, version, privatetype,
+                                            dns_rdatatype_none, 0,
+                                            &privset, NULL);
+               if (result == ISC_R_NOTFOUND) {
+                       isc_buffer_putstr(text, "No signing records found");
+                       isc_buffer_putuint8(text, 0);
+                       result = ISC_R_SUCCESS;
+                       goto cleanup;
+               }
+
+               for (result = dns_rdataset_first(&privset);
+                    result == ISC_R_SUCCESS;
+                    result = dns_rdataset_next(&privset))
+               {
+                       dns_rdata_t priv = DNS_RDATA_INIT;
+                       char output[BUFSIZ];
+                       isc_buffer_t buf;
+
+                       dns_rdataset_current(&privset, &priv);
 
-       result = dns_zone_keydone(zone, ptr);
+                       isc_buffer_init(&buf, output, sizeof(output));
+                       CHECK(dns_private_totext(&priv, &buf));
+
+                       if (!first)
+                               isc_buffer_putstr(text, "\n");
+                       first = ISC_FALSE;
+
+                       n = snprintf((char *)isc_buffer_used(text),
+                                    isc_buffer_availablelength(text),
+                                    "%s", output);
+                       if (n >= isc_buffer_availablelength(text))
+                               CHECK(ISC_R_NOSPACE);
+
+                       isc_buffer_add(text, n);
+               }
+
+               if (result == ISC_R_NOMORE)
+                       result = ISC_R_SUCCESS;
+       }
 
  cleanup:
-       dns_zone_detach(&zone);
+       if (dns_rdataset_isassociated(&privset))
+               dns_rdataset_disassociate(&privset);
+       if (node != NULL)
+               dns_db_detachnode(db, &node);
+       if (version != NULL)
+               dns_db_closeversion(db, &version, ISC_FALSE);
+       if (db != NULL)
+               dns_db_detach(&db);
+       if (zone != NULL)
+               dns_zone_detach(&zone);
+
        return (result);
 }
index c51ff43f9eec72e234673fd4803068d0abdd63b0..d83fcbae35e725437500b935118f213b5ba047f4 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: update.c,v 1.197 2011/08/31 06:49:09 marka Exp $ */
+/* $Id: update.c,v 1.198 2011/10/28 06:20:04 each Exp $ */
 
 #include <config.h>
 
@@ -3068,7 +3068,7 @@ update_action(isc_task_t *task, isc_event_t *event) {
                         * remove any NSEC chain present will also be removed.
                         */
                         CHECK(dns_nsec3param_deletechains(db, ver, zone,
-                                                          &diff));
+                                                          ISC_TRUE, &diff));
                } else if (has_dnskey && isdnssec(db, ver, privatetype)) {
                        isc_uint32_t interval;
                        dns_update_log_t log;
index b39c5fbb3b6e2140d2a1bbc0abe5444f3aa3a044..75f9328222a0ec938101c99e1e6b4bc11903ee1e 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rndc.c,v 1.135 2011/10/25 01:54:19 marka Exp $ */
+/* $Id: rndc.c,v 1.136 2011/10/28 06:20:05 each Exp $ */
 
 /*! \file */
 
@@ -154,9 +154,15 @@ command is one of the following:\n\
                Add zone to given view. Requires new-zone-file option.\n\
   delzone [\"file\"] zone [class [view]]\n\
                Removes zone from given view. Requires new-zone-file option.\n\
-  keydone rdata zone [class [view]]\n\
-               Remove the private record with the corresponding rdata from\n\
-               the given zone.\n\
+  signing -list zone [class [view]]\n\
+               List the private records showing the state of DNSSEC\n\
+               signing in the given zone.\n\
+  signing -clear <keyid>/<algorithm> zone [class [view]]\n\
+               Remove the private record that indicating the given key\n\
+               has finished signing the given zone.\n\
+  signing -clear all zone [class [view]]\n\
+               Remove the private records for all keys that have\n\
+               finished signing the given zone.\n\
 \n\
 * == not yet implemented\n\
 Version: %s\n",
index e16bcc7b9aa0f3363f8121c7cb743ea808d088f6..ef69cea785f6fe0b7fe5aa9d109d24c881a40717 100644 (file)
@@ -14,7 +14,7 @@
 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: tests.sh,v 1.36 2011/10/20 21:20:01 marka Exp $
+# $Id: tests.sh,v 1.37 2011/10/28 06:20:05 each Exp $
 
 SYSTEMTESTTOP=..
 . $SYSTEMTESTTOP/conf.sh
@@ -126,7 +126,7 @@ zone nsec3.example.
 update add nsec3.example. 3600 NSEC3PARAM 1 0 10 BEEF
 send
 zone autonsec3.example.
-update add autonsec3.example. 3600 NSEC3PARAM 1 1 10 BEEF
+update add autonsec3.example. 3600 NSEC3PARAM 1 0 20 DEAF
 send
 zone nsec3.optout.example.
 update add nsec3.optout.example. 3600 NSEC3PARAM 1 0 10 BEEF
@@ -140,6 +140,7 @@ send
 END
 
 # try to convert nsec.example; this should fail due to non-NSEC key
+echo "I:preset nsec3param in unsigned zone via nsupdate ($n)"
 $NSUPDATE > nsupdate.out 2>&1 <<END
 server 10.53.0.3 5300
 zone nsec.example.
@@ -155,6 +156,27 @@ n=`expr $n + 1`
 if [ $ret != 0 ]; then echo "I:failed"; fi
 status=`expr $status + $ret`
 
+echo "I:checking for nsec3param signing record ($n)"
+ret=0
+$RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 signing -list autonsec3.example. > signing.out.test$n 2>&1
+grep "Pending NSEC3 chain 1 0 20 DEAF" signing.out.test$n > /dev/null || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:resetting nsec3param via rndc signing ($n)"
+ret=0
+$RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 signing -clear all autonsec3.example. > /dev/null 2>&1
+$RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 signing -nsec3param 1 1 10 beef autonsec3.example. > /dev/null 2>&1
+sleep 1
+$RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 signing -list autonsec3.example. > signing.out.test$n 2>&1
+grep "Pending NSEC3 chain 1 1 10 BEEF" signing.out.test$n > /dev/null || ret=1
+num=`grep "Pending " signing.out.test$n | wc -l`
+[ $num -eq 1 ] || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
 echo "I:signing preset nsec3 zone"
 zsk=`cat autozsk.key`
 ksk=`cat autoksk.key`
@@ -275,6 +297,22 @@ n=`expr $n + 1`
 if [ $ret != 0 ]; then echo "I:failed"; fi
 status=`expr $status + $ret`
 
+echo "I:checking NSEC3->NSEC conversion with 'rndc signing -nsec3param none' ($n)"
+ret=0
+$RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 signing -nsec3param none autonsec3.example. > /dev/null 2>&1
+sleep 2
+# this command should result in an empty file:
+$DIG $DIGOPTS +noall +answer autonsec3.example. nsec3param @10.53.0.3 > dig.out.ns3.nx.test$n || ret=1
+grep "NSEC3PARAM" dig.out.ns3.nx.test$n > /dev/null && ret=1
+$DIG $DIGOPTS +noauth q.autonsec3.example. @10.53.0.3 a > dig.out.ns3.test$n || ret=1
+$DIG $DIGOPTS +noauth q.autonsec3.example. @10.53.0.4 a > dig.out.ns4.test$n || ret=1
+$PERL ../digcomp.pl dig.out.ns3.test$n dig.out.ns4.test$n || ret=1
+grep "flags:.*ad.*QUERY" dig.out.ns4.test$n > /dev/null || ret=1
+grep "status: NXDOMAIN" dig.out.ns4.test$n > /dev/null || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
 echo "I:checking TTLs of imported DNSKEYs (no default) ($n)"
 ret=0
 $DIG $DIGOPTS +tcp +noall +answer dnskey ttl1.example. @10.53.0.3 > dig.out.ns3.test$n || ret=1
index 89922138bb1717c8e1e2600ce5db546398e00181..5c2f062905f441e253c947cb3b78eefde2c0e1ab 100644 (file)
@@ -15,7 +15,7 @@
 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: clean.sh,v 1.43 2011/10/11 19:26:06 each Exp $
+# $Id: clean.sh,v 1.44 2011/10/28 06:20:05 each Exp $
 
 rm -f */K* */keyset-* */dsset-* */dlvset-* */signedkey-* */*.signed
 rm -f */trusted.conf */managed.conf */tmp* */*.jnl */*.bk
@@ -59,3 +59,4 @@ rm -f ns3/ttlpatch.example.db ns3/ttlpatch.example.db.signed
 rm -f ns3/ttlpatch.example.db.patched
 rm -f ns3/split-smart.example.db
 rm -f nosign.before
+rm -f signing.out*
index 2ed281d8d786e13926be86a2c8a3ae6ac4554ef7..060edca4613def50f9acc49e193e225b490c29a9 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: named.conf,v 1.48 2011/05/23 20:10:02 each Exp $ */
+/* $Id: named.conf,v 1.49 2011/10/28 06:20:05 each Exp $ */
 
 // NS3
 
@@ -35,6 +35,15 @@ options {
        dnssec-validation yes;
 };
 
+key rndc_key {
+        secret "1234abcd8765";
+        algorithm hmac-md5;
+};
+
+controls {
+        inet 10.53.0.3 port 9953 allow { any; } keys { rndc_key; };
+};
+
 zone "." {
        type hint;
        file "../../common/root.hint";
index 8f0d6eca8ff90e7707d33e1593347ace1ea29ade..58f9a0310a03519a1978f56d4701cfd791d68b0c 100644 (file)
@@ -15,7 +15,7 @@
 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: tests.sh,v 1.100 2011/10/26 05:32:56 marka Exp $
+# $Id: tests.sh,v 1.101 2011/10/28 06:20:05 each Exp $
 
 SYSTEMTESTTOP=..
 . $SYSTEMTESTTOP/conf.sh
@@ -1330,6 +1330,33 @@ n=`expr $n + 1`
 if [ $ret != 0 ]; then echo "I:failed"; fi
 status=`expr $status + $ret`
 
+echo "I:check rndc signing -list output ($n)"
+$RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 signing -list dynamic.example 2>&1 > signing.out
+grep "No signing records found" signing.out > /dev/null 2>&1 || {
+        ret=1
+        sed 's/^/I:ns3 /' signing.out
+}
+$RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 signing -list update-nsec3.example 2>&1 > signing.out
+grep "Done signing with key .*/NSEC3RSASHA1" signing.out > /dev/null 2>&1 || {
+        ret=1
+        sed 's/^/I:ns3 /' signing.out
+}
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:clear signing records ($n)"
+$RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 signing -clear all update-nsec3.example > /dev/null || ret=1
+sleep 1
+$RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 signing -list update-nsec3.example 2>&1 > signing.out
+grep "No signing records found" signing.out > /dev/null 2>&1 || {
+        ret=1
+        sed 's/^/I:ns3 /' signing.out
+}
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
 echo "I:checking that a insecure zone beneath a cname resolves ($n)"
 ret=0
 $DIG $DIGOPTS soa insecure.below-cname.example. @10.53.0.4 > dig.out.ns4.test$n || ret=1
index bca624b4a01de5553bcd8a4025806da9175596d2..65db2cbb3111918cf1161f43ccf4c067bc32c093 100644 (file)
@@ -12,7 +12,7 @@
 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: clean.sh,v 1.4 2011/10/25 01:54:19 marka Exp $
+# $Id: clean.sh,v 1.5 2011/10/28 06:20:05 each Exp $
 
 rm -f */named.memstats
 rm -f */named.run
@@ -43,3 +43,4 @@ rm -f ns5/bits.bk.signed
 rm -f ns5/bits.bk.signed.jnl
 rm -f random.data
 rm -f dig.out.ns*.test*
+rm -f signing.out*
index 3dc32dd9343bd9238b0b0ccdfd26a2b53aec67bc..bb93632b519d2a6dcfb723888cb5a3b9fd69b326 100644 (file)
@@ -14,7 +14,7 @@
 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: tests.sh,v 1.5 2011/10/26 20:56:45 marka Exp $
+# $Id: tests.sh,v 1.6 2011/10/28 06:20:05 each Exp $
 
 SYSTEMTESTTOP=..
 . $SYSTEMTESTTOP/conf.sh
@@ -31,11 +31,9 @@ ret=0
 for i in 1 2 3 4 5 6 7 8 9 10
 do
        ret=0
-       $DIG $DIGOPTS @10.53.0.3 -p 5300 bits TYPE65534 > dig.out.ns3.test$n
-       grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
-       grep "ANSWER: 3," dig.out.ns3.test$n > /dev/null || ret=1
-       records=`grep 'TYPE65534.*05[0-9A-F][0-9A-F][0-9A-F][0-9A-F]0001$' dig.out.ns3.test$n | wc -l`
-       [ $records = 2 ] || ret=1
+       $RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 signing -list bits > signing.out.test$n 2>&1
+       keys=`grep '^Done signing' signing.out.test$n | wc -l`
+       [ $keys = 2 ] || ret=1
        if [ $ret = 0 ]; then break; fi
        sleep 1
 done
@@ -43,22 +41,21 @@ if [ $ret != 0 ]; then echo "I:failed"; fi
 status=`expr $status + $ret`
 
 n=`expr $n + 1`
-echo "I:checking removal of private type record via 'rndc keydone' ($n)"
+echo "I:checking removal of private type record via 'rndc signing -clear' ($n)"
 ret=0
-$DIG $DIGOPTS @10.53.0.3 -p 5300 bits TYPE65534 > dig.out.ns3.test$n
-records=`sed -n -e 's/.*TYPE65534.*\(05[0-9A-F][0-9A-F][0-9A-F][0-9A-F]0001\)$/\1/p' dig.out.ns3.test$n`
-for record in $records
-do
-       $RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 keydone "${record}" bits || ret=1
+$RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 signing -list bits > signing.out.test$n 2>&1
+keys=`sed -n -e 's/Done signing with key \(.*\)$/\1/p' signing.out.test$n`
+for key in $keys; do
+       $RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 signing -clear ${key} bits > /dev/null || ret=1
        break;  # We only want to remove 1 record for now.
 done 2>&1 |sed 's/^/I:ns3 /'
 
 for i in 1 2 3 4 5 6 7 8 9 10
 do
        ans=0
-       $DIG $DIGOPTS @10.53.0.3 -p 5300 bits TYPE65534 > dig.out.ns3.test$n
-       grep "ANSWER: 2," dig.out.ns3.test$n > /dev/null || ans=1
-       [ $ans = 1 ] || break
+       $RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 signing -list bits > signing.out.test$n 2>&1
+        num=`grep "Done signing with" signing.out.test$n | wc -l`
+       [ $num = 1 ] && break
        sleep 1
 done
 [ $ans = 0 ] || ret=1
@@ -77,21 +74,15 @@ if [ $ret != 0 ]; then echo "I:failed"; fi
 status=`expr $status + $ret`
 
 n=`expr $n + 1`
-echo "I:checking removal of remaining private type record via 'rndc keydone' ($n)"
+echo "I:checking removal of remaining private type record via 'rndc signing -clear all' ($n)"
 ret=0
-$DIG $DIGOPTS @10.53.0.3 -p 5300 bits TYPE65534 > dig.out.ns3.test$n
-records=`sed -n -e 's/.*TYPE65534.*\(05[0-9A-F][0-9A-F][0-9A-F][0-9A-F]0001\)$/\1/p' dig.out.ns3.test$n`
-for record in $records
-do
-       $RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 keydone "${record}" bits || ret=1
-done 2>&1 |sed 's/^/I:ns3 /'
+$RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 signing -clear all bits > /dev/null || ret=1
 
 for i in 1 2 3 4 5 6 7 8 9 10
 do
        ans=0
-       $DIG $DIGOPTS @10.53.0.3 -p 5300 bits TYPE65534 > dig.out.ns3.test$n
-       grep "ANSWER: 0," dig.out.ns3.test$n > /dev/null || ans=1
-       grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ans=1
+       $RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 signing -list bits > signing.out.test$n 2>&1
+       grep "No signing records found" signing.out.test$n > /dev/null || ans=1
        [ $ans = 1 ] || break
        sleep 1
 done
@@ -180,11 +171,9 @@ ret=0
 for i in 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10
 do
        ret=0
-       $DIG $DIGOPTS @10.53.0.3 -p 5300 noixfr TYPE65534 > dig.out.ns3.test$n
-       grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
-       grep "ANSWER: 3," dig.out.ns3.test$n > /dev/null || ret=1
-       records=`grep "TYPE65534.*05[0-9A-F][0-9A-F][0-9A-F][0-9A-F]0001" dig.out.ns3.test$n | wc -l`
-       [ $records = 2 ] || ret=1
+       $RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 signing -list noixfr > signing.out.test$n 2>&1
+       keys=`grep '^Done signing' signing.out.test$n | wc -l`
+       [ $keys = 2 ] || ret=1
        if [ $ret = 0 ]; then break; fi
        sleep 1
 done
@@ -260,33 +249,30 @@ ret=0
 for i in 1 2 3 4 5 6 7 8 9 10
 do
        ret=0
-       $DIG $DIGOPTS @10.53.0.3 -p 5300 master TYPE65534 > dig.out.ns3.test$n
-       grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
-       grep "ANSWER: 3," dig.out.ns3.test$n > /dev/null || ret=1
-       records=`grep 'TYPE65534.*05[0-9A-F][0-9A-F][0-9A-F][0-9A-F]0001$' dig.out.ns3.test$n | wc -l`
-       [ $records = 2 ] || ret=1
+       $RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 signing -list master  > signing.out.test$n 2>&1
+       keys=`grep '^Done signing' signing.out.test$n | wc -l`
+       [ $keys = 2 ] || ret=1
        if [ $ret = 0 ]; then break; fi
        sleep 1
 done
 if [ $ret != 0 ]; then echo "I:failed"; fi
 
 n=`expr $n + 1`
-echo "I:checking removal of private type record via 'rndc keydone' (master) ($n)"
+echo "I:checking removal of private type record via 'rndc signing -clear' (master) ($n)"
 ret=0
-$DIG $DIGOPTS @10.53.0.3 -p 5300 master TYPE65534 > dig.out.ns3.test$n
-records=`sed -n -e 's/.*TYPE65534.*\(05[0-9A-F][0-9A-F][0-9A-F][0-9A-F]0001\)$/\1/p' dig.out.ns3.test$n`
-for record in $records
-do
-       $RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 keydone "${record}" master || ret=1
+$RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 signing -list master > signing.out.test$n 2>&1
+keys=`sed -n -e 's/Done signing with key \(.*\)$/\1/p' signing.out.test$n`
+for key in $keys; do
+       $RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 signing -clear ${key} master > /dev/null || ret=1
        break;  # We only want to remove 1 record for now.
 done 2>&1 |sed 's/^/I:ns3 /'
 
 for i in 1 2 3 4 5 6 7 8 9
 do
        ans=0
-       $DIG $DIGOPTS @10.53.0.3 -p 5300 master TYPE65534 > dig.out.ns3.test$n
-       grep "ANSWER: 2," dig.out.ns3.test$n > /dev/null || ans=1
-       [ $ans = 1 ] || break
+       $RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 signing -list master > signing.out.test$n 2>&1
+        num=`grep "Done signing with" signing.out.test$n | wc -l`
+       [ $num = 1 ] && break
        sleep 1
 done
 [ $ans = 0 ] || ret=1
@@ -305,21 +291,14 @@ if [ $ret != 0 ]; then echo "I:failed"; fi
 status=`expr $status + $ret`
 
 n=`expr $n + 1`
-echo "I:checking removal of remaining private type record via 'rndc keydone' (master) ($n)"
+echo "I:checking removal of remaining private type record via 'rndc signing -clear' (master) ($n)"
 ret=0
-$DIG $DIGOPTS @10.53.0.3 -p 5300 master TYPE65534 > dig.out.ns3.test$n
-records=`sed -n -e 's/.*TYPE65534.*\(05[0-9A-F][0-9A-F][0-9A-F][0-9A-F]0001\)$/\1/p' dig.out.ns3.test$n`
-for record in $records
-do
-       $RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 keydone "${record}" master || ret=1
-done 2>&1 |sed 's/^/I:ns3 /'
-
-for i in 1 2 3 4 5 6 7 8 9
+$RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 signing -clear all master > /dev/null || ret=1
+for i in 1 2 3 4 5 6 7 8 9 10
 do
        ans=0
-       $DIG $DIGOPTS @10.53.0.3 -p 5300 master TYPE65534 > dig.out.ns3.test$n
-       grep "ANSWER: 0," dig.out.ns3.test$n > /dev/null || ans=1
-       grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ans=1
+       $RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 signing -list master > signing.out.test$n 2>&1
+       grep "No signing records found" signing.out.test$n > /dev/null || ans=1
        [ $ans = 1 ] || break
        sleep 1
 done
@@ -366,11 +345,9 @@ ret=0
 for i in 1 2 3 4 5 6 7 8 9 10
 do
        ret=0
-       $DIG $DIGOPTS @10.53.0.3 -p 5300 dynamic TYPE65534 > dig.out.ns3.test$n
-       grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1
-       grep "ANSWER: 3," dig.out.ns3.test$n > /dev/null || ret=1
-       records=`grep 'TYPE65534.*05[0-9A-F][0-9A-F][0-9A-F][0-9A-F]0001$' dig.out.ns3.test$n | wc -l`
-       [ $records = 2 ] || ret=1
+       $RNDC -c ../common/rndc.conf -s 10.53.0.3 -p 9953 signing -list dynamic > signing.out.test$n 2>&1
+       keys=`grep '^Done signing' signing.out.test$n | wc -l`
+       [ $keys = 2 ] || ret=1
        if [ $ret = 0 ]; then break; fi
        sleep 1
 done
index dc375203a8386302ce3b20e69b3b61f6cbc3e52a..1e6bcffde3b14854e5478a828c034179725c9624 100644 (file)
@@ -18,7 +18,7 @@
  - PERFORMANCE OF THIS SOFTWARE.
 -->
 
-<!-- File: $Id: Bv9ARM-book.xml,v 1.508 2011/10/26 15:23:37 each Exp $ -->
+<!-- File: $Id: Bv9ARM-book.xml,v 1.509 2011/10/28 06:20:05 each Exp $ -->
 <book xmlns:xi="http://www.w3.org/2001/XInclude">
   <title>BIND 9 Administrator Reference Manual</title>
 
@@ -1556,23 +1556,50 @@ zone "eng.example.com" {
                   </varlistentry>
 
                   <varlistentry>
-                    <term><userinput>keydone
-                        <replaceable>rdata</replaceable>
+                    <term><userinput>signing
+                        <optional>( -list | -clear <replaceable>keyid/algorithm</replaceable> | -clear <literal>all</literal> | -nsec3param ( <replaceable>parameters</replaceable> | <literal>none</literal> ) ) </optional>
                         <replaceable>zone</replaceable>
                         <optional><replaceable>class</replaceable>
                         <optional><replaceable>view</replaceable></optional></optional>
                     </userinput></term>
                     <listitem>
                       <para>
-                       Remove the <command>sig-signing-type</command> record
-                       which matches the <replaceable>rdata</replaceable>
-                       (in hexadecimal) from the specified zone.  Only
-                       <replaceable>rdata</replaceable> that
-                       indicate that named has finished signing the zone
-                       with the corresponding key will be removed. (i.e.
-                       the first two characters are not "00", the
-                       last four characters are "0001" and the total
-                       length is 10 hexadecimal characters.
+                        List, edit, or remove the DNSSEC signing state for 
+                        the specified zone.  The status of ongoing DNSSEC
+                        operations (such as signing or generating
+                        NSEC3 chains) is stored in the zone in the form
+                        of DNS resource records of type
+                        <command>sig-signing-type</command>. 
+                        <command>rndc signing -list</command> converts
+                        these records into a human-readable form,
+                        indicating which keys are currently signing
+                        or have finished signing the zone, and which NSEC3
+                        NSEC3 chains are being created or removed.
+                      </para>
+                      <para>
+                        <command>rndc signing -clear</command> can remove
+                        a single key (specified in the same format that
+                        <command>rndc signing -list</command> uses to
+                        display it), or all keys.  In either case, only
+                        completed keys are removed; any record indicating
+                        that a key has not yet finished signing the zone
+                        will be retained.
+                      </para>
+                      <para>
+                        <command>rndc signing -nsec3param</command> sets
+                        the NSEC3 parameters for a zone.  This is the
+                        only supported mechanism for using NSEC3 with
+                        <command>inline-signing</command> zones.
+                        Parameters are specified in the same format as
+                        an NSEC3PARAM resource record: hash algorithm,
+                        flags, iterations, salt.  For example, to set an
+                        NSEC3 chain using the SHA-1 hash algorithm,
+                        no opt-out flag, 10 iterations, and a salt value
+                        of "FFFF", use:
+                        <command>rndc signing -nsec3param 1 0 10 FFFF</command>.
+                        <command>rndc signing -nsec3param none</command>
+                        removes an existing NSEC3 chain and replaces it
+                        with NSEC.
                       </para>
                     </listitem>
                   </varlistentry>
@@ -8730,8 +8757,8 @@ avoid-v6-udp-ports { 40000; range 50000 60000; };
                  These records can be removed from the zone once named
                  has completed signing the zone with the matching key
                  using <command>nsupdate</command> or
-                 <command>rndc keydone</command>.
-                 <command>rndc keydone</command> is the only supported
+                 <command>rndc signing -clear</command>.
+                 <command>rndc signing -clear</command> is the only supported
                  way to remove these records from
                  <command>inline-signing</command> zones.
                </para>
index 3ff3576f1a547c41a11fdc85d2456e140102b861..fd2144f64937850a40c6c0ad88be359efd60e91e 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: events.h,v 1.60 2011/10/25 01:54:22 marka Exp $ */
+/* $Id: events.h,v 1.61 2011/10/28 06:20:06 each Exp $ */
 
 #ifndef DNS_EVENTS_H
 #define DNS_EVENTS_H 1
@@ -78,6 +78,7 @@
 #define DNS_EVENT_ZONESECUREDB                 (ISC_EVENTCLASS_DNS + 48)
 #define DNS_EVENT_ZONELOAD                     (ISC_EVENTCLASS_DNS + 49)
 #define DNS_EVENT_KEYDONE                      (ISC_EVENTCLASS_DNS + 50)
+#define DNS_EVENT_SETNSEC3PARAM                        (ISC_EVENTCLASS_DNS + 51)
 
 #define DNS_EVENT_FIRSTEVENT                   (ISC_EVENTCLASS_DNS + 0)
 #define DNS_EVENT_LASTEVENT                    (ISC_EVENTCLASS_DNS + 65535)
index 7ed1dd9e829fcff9d78b13a575c3745be397a014..35e963ff85f6e678cf993092d0215fe76507dc2c 100644 (file)
@@ -14,7 +14,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: nsec3.h,v 1.12 2010/05/18 02:38:10 tbox Exp $ */
+/* $Id: nsec3.h,v 1.13 2011/10/28 06:20:06 each Exp $ */
 
 #ifndef DNS_NSEC3_H
 #define DNS_NSEC3_H 1
@@ -241,7 +241,8 @@ dns_nsec3param_toprivate(dns_rdata_t *src, dns_rdata_t *target,
 
 isc_result_t
 dns_nsec3param_deletechains(dns_db_t *db, dns_dbversion_t *ver,
-                           dns_zone_t *zone, dns_diff_t *diff);
+                           dns_zone_t *zone, isc_boolean_t nonsec,
+                           dns_diff_t *diff);
 
 /*%<
  * Mark NSEC3PARAM for deletion.
index 0df13d89aa7200b858da94adcb35d59ff22d85c8..ddc8f40099a2c8eb80190b8502277c685da44e45 100644 (file)
@@ -14,7 +14,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: private.h,v 1.3 2009/10/09 23:48:09 tbox Exp $ */
+/* $Id: private.h,v 1.4 2011/10/28 06:20:06 each Exp $ */
 
 #include <isc/lang.h>
 #include <isc/types.h>
@@ -50,6 +50,23 @@ dns_private_chains(dns_db_t *db, dns_dbversion_t *ver,
  * \li other on error
  */
 
+isc_result_t
+dns_private_totext(dns_rdata_t *private, isc_buffer_t *buffer);
+/*%<
+ * Convert a private-type RR 'private' to human-readable form,
+ * and place the result in 'buffer'.  The text should indicate
+ * which action the private-type record specifies and whether the
+ * action has been completed.
+ *
+ * Requires:
+ * \li 'private' is a valid rdata containing at least five bytes
+ * \li 'buffer' is a valid buffer
+ *
+ * Returns:
+ * \li         ISC_R_SUCCESS
+ * \li other on error
+ */
+
 ISC_LANG_ENDDECLS
 
 #endif
index c4efe075fd0fed82394310d1c3225f238965257a..55a279a4b471ba870d126226b02b957659f6a28c 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: zone.h,v 1.195 2011/10/25 01:54:22 marka Exp $ */
+/* $Id: zone.h,v 1.196 2011/10/28 06:20:06 each Exp $ */
 
 #ifndef DNS_ZONE_H
 #define DNS_ZONE_H 1
@@ -1981,6 +1981,20 @@ dns_zone_getraw(dns_zone_t *zone, dns_zone_t **raw);
 isc_result_t
 dns_zone_keydone(dns_zone_t *zone, const char *data);
 
+isc_result_t
+dns_zone_setnsec3param(dns_zone_t *zone, isc_uint8_t hash, isc_uint8_t flags,
+                      isc_uint8_t iter, isc_uint8_t saltlen,
+                      unsigned char *salt, isc_boolean_t replace);
+/*%
+ * Set the NSEC3 parameters for the zone.
+ *
+ * If 'replace' is ISC_TRUE, then the existing NSEC3 chain, if any, will
+ * be replaced with the new one.  If 'hash' is zero, then the replacement
+ * chain will be NSEC rather than NSEC3.
+ *
+ * Requires:
+ * \li 'zone' to be valid.
+ */
 ISC_LANG_ENDDECLS
 
 #endif /* DNS_ZONE_H */
index 4df286b5df53e0648d539417af9f5fd7f6b96dce..2403fe8d08e5703d423c79bc56a1b9e2713d2093 100644 (file)
@@ -14,7 +14,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: nsec3.c,v 1.23 2011/06/10 01:51:09 each Exp $ */
+/* $Id: nsec3.c,v 1.24 2011/10/28 06:20:06 each Exp $ */
 
 #include <config.h>
 
@@ -1054,7 +1054,8 @@ rr_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
 #ifdef BIND9
 isc_result_t
 dns_nsec3param_deletechains(dns_db_t *db, dns_dbversion_t *ver,
-                           dns_zone_t *zone, dns_diff_t *diff)
+                           dns_zone_t *zone, isc_boolean_t nonsec,
+                           dns_diff_t *diff)
 {
        dns_dbnode_t *node = NULL;
        dns_difftuple_t *tuple = NULL;
@@ -1098,7 +1099,9 @@ dns_nsec3param_deletechains(dns_db_t *db, dns_dbversion_t *ver,
 
                dns_nsec3param_toprivate(&rdata, &private, privatetype,
                                         buf, sizeof(buf));
-               buf[2] = DNS_NSEC3FLAG_REMOVE | DNS_NSEC3FLAG_NONSEC;
+               buf[2] = DNS_NSEC3FLAG_REMOVE;
+               if (nonsec)
+                       buf[2] |= DNS_NSEC3FLAG_NONSEC;
 
                CHECK(rr_exists(db, ver, origin, &private, &flag));
 
@@ -1129,15 +1132,14 @@ dns_nsec3param_deletechains(dns_db_t *db, dns_dbversion_t *ver,
        for (result = dns_rdataset_first(&rdataset);
             result == ISC_R_SUCCESS;
             result = dns_rdataset_next(&rdataset)) {
+               dns_rdata_reset(&rdata);
                dns_rdataset_current(&rdataset, &rdata);
                INSIST(rdata.length <= sizeof(buf));
                memcpy(buf, rdata.data, rdata.length);
 
-               if (buf[0] != 0 ||
-                   buf[2] == (DNS_NSEC3FLAG_REMOVE | DNS_NSEC3FLAG_NONSEC)) {
-                       dns_rdata_reset(&rdata);
+               if (buf[0] != 0 || (buf[2] & DNS_NSEC3FLAG_REMOVE) != 0 ||
+                   (nonsec && (buf[2] & DNS_NSEC3FLAG_NONSEC) != 0))
                        continue;
-               }
 
                CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL, origin,
                                           0, &rdata, &tuple));
@@ -1145,7 +1147,9 @@ dns_nsec3param_deletechains(dns_db_t *db, dns_dbversion_t *ver,
                INSIST(tuple == NULL);
 
                rdata.data = buf;
-               buf[2] = DNS_NSEC3FLAG_REMOVE | DNS_NSEC3FLAG_NONSEC;
+               buf[2] = DNS_NSEC3FLAG_REMOVE;
+               if (nonsec)
+                       buf[2] |= DNS_NSEC3FLAG_NONSEC;
 
                CHECK(rr_exists(db, ver, origin, &rdata, &flag));
 
@@ -1155,7 +1159,6 @@ dns_nsec3param_deletechains(dns_db_t *db, dns_dbversion_t *ver,
                        CHECK(do_one_tuple(&tuple, db, ver, diff));
                        INSIST(tuple == NULL);
                }
-               dns_rdata_reset(&rdata);
        }
        if (result != ISC_R_NOMORE)
                goto failure;
index 21f45c7b5cd09141028e1f37eefb943f62453c87..311f0f7c8c1d30d26b1553bc4dd7d6852b53d626 100644 (file)
@@ -14,7 +14,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: private.c,v 1.6 2011/06/10 01:51:09 each Exp $ */
+/* $Id: private.c,v 1.7 2011/10/28 06:20:06 each Exp $ */
 
 #include "config.h"
 
@@ -294,3 +294,74 @@ dns_private_chains(dns_db_t *db, dns_dbversion_t *ver,
                dns_db_detachnode(db, &node);
        return (result);
 }
+
+isc_result_t
+dns_private_totext(dns_rdata_t *private, isc_buffer_t *buf) {
+       isc_result_t result;
+
+       if (private->data[0] == 0) {
+               unsigned char nsec3buf[DNS_NSEC3PARAM_BUFFERSIZE];
+               unsigned char newbuf[DNS_NSEC3PARAM_BUFFERSIZE];
+               dns_rdata_t rdata = DNS_RDATA_INIT;
+               dns_rdata_nsec3param_t nsec3param;
+               isc_boolean_t remove, init, nonsec;
+               isc_buffer_t b;
+
+               if (!dns_nsec3param_fromprivate(private, &rdata, nsec3buf,
+                                               sizeof(nsec3buf)))
+                       CHECK(ISC_R_FAILURE);
+
+               CHECK(dns_rdata_tostruct(&rdata, &nsec3param, NULL));
+
+               remove = ISC_TF((nsec3param.flags & DNS_NSEC3FLAG_REMOVE) != 0);
+               init = ISC_TF((nsec3param.flags & DNS_NSEC3FLAG_INITIAL) != 0);
+               nonsec = ISC_TF((nsec3param.flags & DNS_NSEC3FLAG_NONSEC) != 0);
+
+               nsec3param.flags &= ~(DNS_NSEC3FLAG_CREATE|
+                                     DNS_NSEC3FLAG_REMOVE|
+                                     DNS_NSEC3FLAG_INITIAL|
+                                     DNS_NSEC3FLAG_NONSEC);
+
+               if (init)
+                       isc_buffer_putstr(buf, "Pending NSEC3 chain ");
+               else if (remove)
+                       isc_buffer_putstr(buf, "Removing NSEC3 chain ");
+               else
+                       isc_buffer_putstr(buf, "Creating NSEC3 chain ");
+
+               dns_rdata_reset(&rdata);
+               isc_buffer_init(&b, newbuf, sizeof(newbuf));
+               CHECK(dns_rdata_fromstruct(&rdata, dns_rdataclass_in,
+                                          dns_rdatatype_nsec3param,
+                                          &nsec3param, &b));
+
+               CHECK(dns_rdata_totext(&rdata, NULL, buf));
+
+               if (remove && !nonsec)
+                       isc_buffer_putstr(buf, " / creating NSEC chain");
+       } else {
+               unsigned char alg = private->data[0];
+               dns_keytag_t keyid = (private->data[2] | private->data[1] << 8);
+               char keybuf[BUFSIZ], algbuf[DNS_SECALG_FORMATSIZE];
+               isc_boolean_t remove = ISC_TF(private->data[3] != 0);
+               isc_boolean_t complete = ISC_TF(private->data[4] != 0);
+
+               if (remove && complete)
+                       isc_buffer_putstr(buf, "Done removing signatures for ");
+               else if (remove)
+                       isc_buffer_putstr(buf, "Removing signatures for ");
+               else if (complete)
+                       isc_buffer_putstr(buf, "Done signing with ");
+               else
+                       isc_buffer_putstr(buf, "Signing with ");
+
+               dns_secalg_format(alg, algbuf, sizeof(algbuf));
+               sprintf(keybuf, "key %d/%s", keyid, algbuf);
+               isc_buffer_putstr(buf, keybuf);
+       }
+
+       isc_buffer_putuint8(buf, 0);
+       result = ISC_R_SUCCESS;
+ failure:
+       return (result);
+}
index 1a3b80947d352ac8ae3978b8d33428abb3ee1cf6..d66fa2ab054b670ecc5065b147d8b76a7da89b45 100644 (file)
@@ -12,7 +12,7 @@
 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: Makefile.in,v 1.9 2011/10/12 23:09:35 marka Exp $
+# $Id: Makefile.in,v 1.10 2011/10/28 06:20:07 each Exp $
 
 srcdir =       @srcdir@
 VPATH =                @srcdir@
@@ -38,12 +38,12 @@ LIBS =              @LIBS@ @ATFLIBS@
 
 OBJS =         dnstest.@O@
 SRCS =         dnstest.c master_test.c dbiterator_test.c time_test.c \
-               update_test.c zonemgr_test.c zt_test.c
+               private_test.c update_test.c zonemgr_test.c zt_test.c
 
 SUBDIRS =
 TARGETS =      master_test@EXEEXT@ dbiterator_test@EXEEXT@ time_test@EXEEXT@ \
-               update_test@EXEEXT@ zonemgr_test@EXEEXT@ zt_test@EXEEXT@ \
-               dbversion_test@EXEEXT@
+               private_test@EXEEXT@ update_test@EXEEXT@ zonemgr_test@EXEEXT@ \
+               zt_test@EXEEXT@ dbversion_test@EXEEXT@
 
 @BIND9_MAKE_RULES@
 
@@ -57,6 +57,11 @@ time_test@EXEEXT@: time_test.@O@ dnstest.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
                        time_test.@O@ dnstest.@O@ ${DNSLIBS} \
                                ${ISCLIBS} ${LIBS}
 
+private_test@EXEEXT@: private_test.@O@ dnstest.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+       ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+                       private_test.@O@ dnstest.@O@ ${DNSLIBS} \
+                               ${ISCLIBS} ${LIBS}
+
 update_test@EXEEXT@: update_test.@O@ dnstest.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
        ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
                        update_test.@O@ dnstest.@O@ ${DNSLIBS} \
diff --git a/lib/dns/tests/private_test.c b/lib/dns/tests/private_test.c
new file mode 100644 (file)
index 0000000..7ca2e16
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: private_test.c,v 1.2 2011/10/28 06:20:07 each Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <atf-c.h>
+
+#include <unistd.h>
+
+#include <isc/buffer.h>
+
+#include <dns/nsec3.h>
+#include <dns/private.h>
+#include <dns/rdataclass.h>
+#include <dns/rdatatype.h>
+
+#include <dst/dst.h>
+
+#include "dnstest.h"
+
+static dns_rdatatype_t privatetype = 65534;
+
+typedef struct {
+       unsigned char alg;
+       dns_keytag_t keyid;
+       isc_boolean_t remove;
+       isc_boolean_t complete;
+} signing_testcase_t;
+
+typedef struct {
+       unsigned char hash;
+       unsigned char flags;
+       unsigned int iterations;
+       unsigned long salt;
+       isc_boolean_t remove;
+       isc_boolean_t pending;
+       isc_boolean_t nonsec;
+} nsec3_testcase_t;
+
+/*
+ * Helper functions
+ */
+static void
+make_signing(signing_testcase_t *testcase, dns_rdata_t *private,
+            unsigned char *buf)
+{
+       dns_rdata_init(private);
+
+       buf[0] = testcase->alg;
+       buf[1] = (testcase->keyid & 0xff00) >> 8;
+       buf[2] = (testcase->keyid & 0xff);
+       buf[3] = testcase->remove;
+       buf[4] = testcase->complete;
+       private->data = buf;
+       private->length = sizeof(buf);
+       private->type = privatetype;
+       private->rdclass = dns_rdataclass_in;
+}
+
+static void
+make_nsec3(nsec3_testcase_t *testcase, dns_rdata_t *private,
+          unsigned char *pbuf)
+{
+       dns_rdata_nsec3param_t params;
+       dns_rdata_t nsec3param = DNS_RDATA_INIT;
+       unsigned char bufdata[BUFSIZ];
+       isc_buffer_t buf;
+       isc_uint32_t salt;
+       unsigned char *sp;
+       int slen = 4;
+
+       /* for simplicity, we're using a maximum salt length of 4 */
+       salt = htonl(testcase->salt);
+       sp = (unsigned char *) &salt;
+       while (*sp == '\0' && slen > 0) {
+               slen--;
+               sp++;
+       }
+
+       params.common.rdclass = dns_rdataclass_in;
+       params.common.rdtype = dns_rdatatype_nsec3param;
+       params.hash = testcase->hash;
+       params.iterations = testcase->iterations;
+       params.salt = sp;
+       params.salt_length = slen;
+
+       params.flags = testcase->flags;
+       if (testcase->remove) {
+               params.flags |= DNS_NSEC3FLAG_REMOVE;
+               if (testcase->nonsec)
+                       params.flags |= DNS_NSEC3FLAG_NONSEC;
+       } else {
+               params.flags |= DNS_NSEC3FLAG_CREATE;
+               if (testcase->pending)
+                       params.flags |= DNS_NSEC3FLAG_INITIAL;
+       }
+
+       isc_buffer_init(&buf, bufdata, sizeof(bufdata));
+       dns_rdata_fromstruct(&nsec3param, dns_rdataclass_in,
+                            dns_rdatatype_nsec3param, &params, &buf);
+
+       dns_rdata_init(private);
+
+       dns_nsec3param_toprivate(&nsec3param, private, privatetype,
+                                pbuf, DNS_NSEC3PARAM_BUFFERSIZE + 1);
+}
+
+/*
+ * Individual unit tests
+ */
+ATF_TC(private_signing_totext);
+ATF_TC_HEAD(private_signing_totext, tc) {
+       atf_tc_set_md_var(tc, "descr",
+                         "convert private signing records to text");
+}
+ATF_TC_BODY(private_signing_totext, tc) {
+       isc_result_t result;
+       dns_rdata_t private;
+       int i;
+
+       signing_testcase_t testcases[] = {
+               { DST_ALG_RSASHA512, 12345, 0, 0 },
+               { DST_ALG_RSASHA256, 54321, 1, 0 },
+               { DST_ALG_NSEC3RSASHA1, 22222, 0, 1 },
+               { DST_ALG_RSASHA1, 33333, 1, 1 }
+       };
+       const char *results[] = {
+               "Signing with key 12345/RSASHA512",
+               "Removing signatures for key 54321/RSASHA256",
+               "Done signing with key 22222/NSEC3RSASHA1",
+               "Done removing signatures for key 33333/RSASHA1"
+       };
+       int ncases = 4;
+
+       UNUSED(tc);
+
+       result = dns_test_begin(NULL, ISC_TRUE);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       for (i = 0; i < ncases; i++) {
+               unsigned char data[5];
+               char output[BUFSIZ];
+               isc_buffer_t buf;
+
+               isc_buffer_init(&buf, output, sizeof(output));
+
+               make_signing(&testcases[i], &private, data);
+               dns_private_totext(&private, &buf);
+               ATF_CHECK_STREQ(output, results[i]);
+       }
+
+       dns_test_end();
+}
+
+ATF_TC(private_nsec3_totext);
+ATF_TC_HEAD(private_nsec3_totext, tc) {
+       atf_tc_set_md_var(tc, "descr", "convert private chain records to text");
+}
+ATF_TC_BODY(private_nsec3_totext, tc) {
+       isc_result_t result;
+       dns_rdata_t private;
+       int i;
+
+       nsec3_testcase_t testcases[] = {
+               { 1, 0, 1, 0xbeef, 0, 0, 0 },
+               { 1, 1, 10, 0xdadd, 0, 0, 0 },
+               { 1, 0, 20, 0xbead, 0, 1, 0 },
+               { 1, 0, 30, 0xdeaf, 1, 0, 0 },
+               { 1, 0, 100, 0xfeedabee, 1, 0, 1 },
+       };
+       const char *results[] = {
+               "Creating NSEC3 chain 1 0 1 BEEF",
+               "Creating NSEC3 chain 1 1 10 DADD",
+               "Pending NSEC3 chain 1 0 20 BEAD",
+               "Removing NSEC3 chain 1 0 30 DEAF / creating NSEC chain",
+               "Removing NSEC3 chain 1 0 100 FEEDABEE"
+       };
+       int ncases = 5;
+
+       UNUSED(tc);
+
+       result = dns_test_begin(NULL, ISC_TRUE);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       for (i = 0; i < ncases; i++) {
+               unsigned char data[DNS_NSEC3PARAM_BUFFERSIZE + 1];
+               char output[BUFSIZ];
+               isc_buffer_t buf;
+
+               isc_buffer_init(&buf, output, sizeof(output));
+
+               make_nsec3(&testcases[i], &private, data);
+               dns_private_totext(&private, &buf);
+               ATF_CHECK_STREQ(output, results[i]);
+       }
+
+       dns_test_end();
+}
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+       ATF_TP_ADD_TC(tp, private_signing_totext);
+       ATF_TP_ADD_TC(tp, private_nsec3_totext);
+       return (atf_no_error());
+}
+
index e263ca41a927a3fb5886abe20ff5c1e5db8e77c6..413d6bc2f7e02ee1fd06ebb47a4cb5b083ab3dc3 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: zone.c,v 1.641 2011/10/28 00:36:54 marka Exp $ */
+/* $Id: zone.c,v 1.642 2011/10/28 06:20:06 each Exp $ */
 
 /*! \file */
 
@@ -14808,7 +14808,7 @@ clean_nsec3param(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
        if (result != ISC_R_NOTFOUND)
                goto failure;
 
-       result = dns_nsec3param_deletechains(db, ver, zone, diff);
+       result = dns_nsec3param_deletechains(db, ver, zone, ISC_TRUE, diff);
 
  failure:
        if (node != NULL)
@@ -15340,9 +15340,12 @@ dns_zone_getraw(dns_zone_t *zone, dns_zone_t **raw) {
 
 struct keydone {
        isc_event_t event;
-       unsigned int data[5];
+       isc_boolean_t all;
+       unsigned char data[5];
 };
 
+#define PENDINGFLAGS (DNS_NSEC3FLAG_CREATE|DNS_NSEC3FLAG_INITIAL)
+
 static void
 keydone(isc_task_t *task, isc_event_t *event) {
        const char *me = "keydone";
@@ -15357,6 +15360,7 @@ keydone(isc_task_t *task, isc_event_t *event) {
        dns_diff_t diff;
        struct keydone *keydone = (struct keydone *)event;
        dns_update_log_t log = { update_log_cb, NULL };
+       isc_boolean_t clear_pending = ISC_FALSE;
 
        UNUSED(task);
 
@@ -15398,17 +15402,31 @@ keydone(isc_task_t *task, isc_event_t *event) {
                INSIST(!dns_rdataset_isassociated(&rdataset));
                goto failure;
        }
+
        for (result = dns_rdataset_first(&rdataset);
             result == ISC_R_SUCCESS;
             result = dns_rdataset_next(&rdataset)) {
+               isc_boolean_t found = ISC_FALSE;
+
                dns_rdataset_current(&rdataset, &rdata);
-               if (rdata.length != 5 ||
-                   memcmp(rdata.data, keydone->data, 5) != 0) {
-                       dns_rdata_reset(&rdata);
-                       continue;
-               }
-               CHECK(update_one_rr(db, newver, &diff, DNS_DIFFOP_DEL,
-                                   &zone->origin, rdataset.ttl, &rdata));
+
+               if (keydone->all) {
+                       if (rdata.length == 5 && rdata.data[0] != 0 &&
+                              rdata.data[3] == 0 && rdata.data[4] == 1)
+                               found = ISC_TRUE;
+                       else if (rdata.data[0] == 0 &&
+                                (rdata.data[2] & PENDINGFLAGS) != 0) {
+                               found = ISC_TRUE;
+                               clear_pending = ISC_TRUE;
+                       }
+               } else if (rdata.length == 5 &&
+                          memcmp(rdata.data, keydone->data, 5) == 0)
+                       found = ISC_TRUE;
+
+               if (found)
+                       CHECK(update_one_rr(db, newver, &diff, DNS_DIFFOP_DEL,
+                                           &zone->origin, rdataset.ttl,
+                                           &rdata));
                dns_rdata_reset(&rdata);
        }
 
@@ -15416,8 +15434,13 @@ keydone(isc_task_t *task, isc_event_t *event) {
                /* Write changes to journal file. */
                CHECK(update_soa_serial(db, newver, &diff, zone->mctx,
                                        zone->updatemethod));
-               CHECK(dns_update_signatures(&log, zone, db, oldver, newver,
-                                           &diff, zone->sigvalidityinterval));
+
+               result = dns_update_signatures(&log, zone, db,
+                                              oldver, newver, &diff,
+                                              zone->sigvalidityinterval);
+               if (!clear_pending)
+                       CHECK(result);
+
                CHECK(zone_journal(zone, &diff, NULL, "keydone"));
                commit = ISC_TRUE;
 
@@ -15445,11 +15468,12 @@ keydone(isc_task_t *task, isc_event_t *event) {
 }
 
 isc_result_t
-dns_zone_keydone(dns_zone_t *zone, const char *data) {
-       isc_result_t result;
+dns_zone_keydone(dns_zone_t *zone, const char *keystr) {
+       isc_result_t result = ISC_R_SUCCESS;
        isc_event_t *e;
        isc_buffer_t b;
        dns_zone_t *dummy = NULL;
+       struct keydone *kd;
 
        REQUIRE(DNS_ZONE_VALID(zone));
 
@@ -15462,11 +15486,280 @@ dns_zone_keydone(dns_zone_t *zone, const char *data) {
                goto failure;
        }
 
-       isc_buffer_init(&b, ((struct keydone*)e)->data,
-                       sizeof(((struct keydone*)e)->data));
-       result = isc_hex_decodestring(data, &b);
-       if (result != ISC_R_SUCCESS)
+       kd = (struct keydone *) e;
+       if (strcasecmp(keystr, "all") == 0)
+               kd->all = ISC_TRUE;
+       else {
+               isc_textregion_t r;
+               char *algstr;
+               dns_keytag_t keyid;
+               dns_secalg_t alg;
+               size_t n;
+
+               kd->all = ISC_FALSE;
+
+               n = sscanf(keystr, "%hd/", &keyid);
+               if (n == 0)
+                       CHECK(ISC_R_FAILURE);
+
+               algstr = strchr(keystr, '/');
+               if (algstr != NULL)
+                       algstr++;
+               else
+                       CHECK(ISC_R_FAILURE);
+
+               DE_CONST(algstr, r.base);
+               r.length = strlen(algstr);
+               result = dns_secalg_fromtext(&alg, (isc_textregion_t *) &r);
+
+               if (result != ISC_R_SUCCESS) {
+                       n = sscanf(algstr, "%hhd", &alg);
+                       if (n == 0)
+                               CHECK(result);
+               }
+
+               /* construct a private-type rdata */
+               isc_buffer_init(&b, kd->data, sizeof(kd->data));
+               isc_buffer_putuint8(&b, alg);
+               isc_buffer_putuint8(&b, (keyid & 0xff00) >> 8);
+               isc_buffer_putuint8(&b, (keyid & 0xff));
+               isc_buffer_putuint8(&b, 0);
+               isc_buffer_putuint8(&b, 1);
+       }
+
+       zone_iattach(zone, &dummy);
+       isc_task_send(zone->task, &e);
+
+ failure:
+       if (e != NULL)
+               isc_event_free(&e);
+       UNLOCK_ZONE(zone);
+       return (result);
+}
+
+struct nsec3param {
+       isc_event_t event;
+       unsigned char data[DNS_NSEC3PARAM_BUFFERSIZE + 1];
+       unsigned int length;
+       isc_boolean_t nsec;
+       isc_boolean_t replace;
+};
+
+static void
+setnsec3param(isc_task_t *task, isc_event_t *event) {
+       const char *me = "setnsec3param";
+       isc_boolean_t commit = ISC_FALSE;
+       isc_result_t result;
+       dns_dbversion_t *oldver = NULL, *newver = NULL;
+       dns_zone_t *zone;
+       dns_db_t *db = NULL;
+       dns_dbnode_t *node = NULL;
+       dns_rdataset_t prdataset, nrdataset;
+       dns_diff_t diff;
+       struct nsec3param *np = (struct nsec3param *)event;
+       dns_update_log_t log = { update_log_cb, NULL };
+       dns_rdata_t rdata;
+       isc_boolean_t nseconly;
+       isc_boolean_t exists = ISC_FALSE;
+
+       UNUSED(task);
+
+       zone = event->ev_arg;
+       INSIST(DNS_ZONE_VALID(zone));
+
+       ENTER;
+
+       dns_rdataset_init(&prdataset);
+       dns_rdataset_init(&nrdataset);
+       dns_diff_init(zone->mctx, &diff);
+
+       ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
+       if (zone->db != NULL) {
+               dns_db_attach(zone->db, &db);
+               dns_db_currentversion(db, &oldver);
+               result = dns_db_newversion(db, &newver);
+               if (result != ISC_R_SUCCESS) {
+                       dns_zone_log(zone, ISC_LOG_ERROR,
+                                    "setnsec3param:dns_db_newversion -> %s\n",
+                                    dns_result_totext(result));
+                       goto failure;
+               }
+       }
+       ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
+       if (db == NULL)
+               goto failure;
+
+       CHECK(dns_db_getoriginnode(db, &node));
+
+       /*
+        * Does a private-type record already exist for this chain?
+        */
+       result = dns_db_findrdataset(db, node, newver, zone->privatetype,
+                                    dns_rdatatype_none, 0, &prdataset, NULL);
+       if (result == ISC_R_SUCCESS) {
+               for (result = dns_rdataset_first(&prdataset);
+                    result == ISC_R_SUCCESS;
+                    result = dns_rdataset_next(&prdataset)) {
+                       dns_rdata_init(&rdata);
+                       dns_rdataset_current(&prdataset, &rdata);
+
+                       if (np->length == rdata.length &&
+                           memcmp(rdata.data, np->data, np->length) == 0) {
+                               exists = ISC_TRUE;
+                               break;
+                       }
+               }
+       } else if (result != ISC_R_NOTFOUND) {
+               INSIST(!dns_rdataset_isassociated(&prdataset));
+               goto failure;
+       }
+
+       /*
+        * Does the chain already exist?
+        */
+       result = dns_db_findrdataset(db, node, newver,
+                                    dns_rdatatype_nsec3param,
+                                    dns_rdatatype_none, 0, &nrdataset, NULL);
+       if (result == ISC_R_SUCCESS) {
+               for (result = dns_rdataset_first(&nrdataset);
+                    result == ISC_R_SUCCESS;
+                    result = dns_rdataset_next(&nrdataset)) {
+                       dns_rdata_init(&rdata);
+                       dns_rdataset_current(&nrdataset, &rdata);
+
+                       if (np->length == (rdata.length + 1) &&
+                           memcmp(rdata.data, np->data + 1,
+                                  np->length - 1) == 0)
+                       {
+                               exists = ISC_TRUE;
+                               break;
+                       }
+               }
+       } else if (result != ISC_R_NOTFOUND) {
+               INSIST(!dns_rdataset_isassociated(&nrdataset));
                goto failure;
+       }
+
+
+       /*
+        * We need to remove any existing NSEC3 chains.
+        */
+       if (!exists && np->replace && (np->length != 0 || np->nsec))
+               CHECK(dns_nsec3param_deletechains(db, newver, zone,
+                                                 !np->nsec, &diff));
+
+       if (!exists && np->length != 0) {
+               /*
+                * We're creating an NSEC3 chain.
+                *
+                * If the zone is not currently capable of supporting
+                * an NSEC3 chain, add the INITIAL flag, so these
+                * parameters can be used later when NSEC3 becomes
+                * available.
+                */
+               dns_rdata_init(&rdata);
+
+               np->data[2] |= DNS_NSEC3FLAG_CREATE;
+               result = dns_nsec_nseconly(db, newver, &nseconly);
+               if (result == ISC_R_NOTFOUND || nseconly)
+                       np->data[2] |= DNS_NSEC3FLAG_INITIAL;
+
+               rdata.length = np->length;
+               rdata.data = np->data;
+               rdata.type = zone->privatetype;
+               rdata.rdclass = zone->rdclass;
+               CHECK(update_one_rr(db, newver, &diff, DNS_DIFFOP_ADD,
+                                   &zone->origin, 0, &rdata));
+       }
+
+       if (!ISC_LIST_EMPTY(diff.tuples)) {
+               /* Write changes to journal file. */
+               CHECK(update_soa_serial(db, newver, &diff, zone->mctx,
+                                       zone->updatemethod));
+               result = dns_update_signatures(&log, zone, db,
+                                              oldver, newver, &diff,
+                                              zone->sigvalidityinterval);
+               if (result != ISC_R_NOTFOUND)
+                       CHECK(result);
+               CHECK(zone_journal(zone, &diff, NULL, "setnsec3param"));
+               commit = ISC_TRUE;
+
+               LOCK_ZONE(zone);
+               DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED);
+               zone_needdump(zone, 30);
+               UNLOCK_ZONE(zone);
+       }
+
+ failure:
+       if (dns_rdataset_isassociated(&prdataset))
+               dns_rdataset_disassociate(&prdataset);
+       if (dns_rdataset_isassociated(&nrdataset))
+               dns_rdataset_disassociate(&nrdataset);
+       if (node != NULL)
+               dns_db_detachnode(db, &node);
+       if (oldver != NULL)
+               dns_db_closeversion(db, &oldver, ISC_FALSE);
+       if (newver != NULL)
+               dns_db_closeversion(db, &newver, commit);
+       if (db != NULL)
+               dns_db_detach(&db);
+       if (commit)
+               resume_addnsec3chain(zone);
+       dns_diff_clear(&diff);
+       isc_event_free(&event);
+       dns_zone_idetach(&zone);
+}
+
+isc_result_t
+dns_zone_setnsec3param(dns_zone_t *zone, isc_uint8_t hash, isc_uint8_t flags,
+                      isc_uint8_t iter, isc_uint8_t saltlen,
+                      unsigned char *salt, isc_boolean_t replace)
+{
+       isc_result_t result;
+       dns_rdata_nsec3param_t param;
+       dns_rdata_t nrdata = DNS_RDATA_INIT;
+       dns_rdata_t prdata = DNS_RDATA_INIT;
+       unsigned char nbuf[DNS_NSEC3PARAM_BUFFERSIZE];
+       struct nsec3param *np;
+       dns_zone_t *dummy = NULL;
+       isc_buffer_t b;
+       isc_event_t *e;
+
+       REQUIRE(DNS_ZONE_VALID(zone));
+       REQUIRE(salt != NULL);
+
+       LOCK_ZONE(zone);
+
+       e = isc_event_allocate(zone->mctx, zone, DNS_EVENT_SETNSEC3PARAM,
+                              setnsec3param, zone, sizeof(struct nsec3param));
+       if (e == NULL) {
+               result = ISC_R_NOMEMORY;
+               goto failure;
+       }
+
+       np = (struct nsec3param *) e;
+       np->replace = replace;
+       if (hash == 0) {
+               np->length = 0;
+               np->nsec = ISC_TRUE;
+       } else {
+               param.common.rdclass = zone->rdclass;
+               param.common.rdtype = dns_rdatatype_nsec3param;
+               ISC_LINK_INIT(&param.common, link);
+               param.mctx = NULL;
+               param.hash = hash;
+               param.flags = flags;
+               param.iterations = iter;
+               param.salt_length = saltlen;
+               param.salt = salt;
+               isc_buffer_init(&b, nbuf, sizeof(nbuf));
+               CHECK(dns_rdata_fromstruct(&nrdata, zone->rdclass,
+                                          dns_rdatatype_nsec3param,
+                                          &param, &b));
+               dns_nsec3param_toprivate(&nrdata, &prdata, zone->privatetype,
+                                        np->data, sizeof(np->data));
+               np->length = prdata.length;
+       }
 
        zone_iattach(zone, &dummy);
        isc_task_send(zone->task, &e);