]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
2691. [func] dnssec-signzone: retain the existing NSEC or NSEC3
authorEvan Hunt <each@isc.org>
Fri, 25 Sep 2009 06:47:50 +0000 (06:47 +0000)
committerEvan Hunt <each@isc.org>
Fri, 25 Sep 2009 06:47:50 +0000 (06:47 +0000)
chain when re-signing a previously-signed zone.
Use -u to modify NSEC3 parameters or switch
between NSEC and NSEC3. [RT #20304]

CHANGES
bin/dnssec/dnssec-signzone.c
bin/dnssec/dnssec-signzone.docbook
bin/tests/system/dnssec/ns3/sign.sh

diff --git a/CHANGES b/CHANGES
index 7906b30071655a0e27e83dd42b8d761ff0a20e92..f3926a5c9fdcc94c458e424f93b4ad8bb62fb8c8 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,8 @@
+2691.  [func]          dnssec-signzone: retain the existing NSEC or NSEC3
+                       chain when re-signing a previously-signed zone.
+                       Use -u to modify NSEC3 parameters or switch
+                       between NSEC and NSEC3. [RT #20304]
+
 2690.  [bug]           win32: fix isc_thread_key_getspecific() prototype.
                        [RT #20315]
 
index d7d170219f14df5511c739dad7ce1db3311375b3..aed0b4b05e81d89798a763dc68023ecee4417877 100644 (file)
@@ -29,7 +29,7 @@
  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: dnssec-signzone.c,v 1.234 2009/09/24 04:36:28 each Exp $ */
+/* $Id: dnssec-signzone.c,v 1.235 2009/09/25 06:47:50 each Exp $ */
 
 /*! \file */
 
@@ -147,6 +147,10 @@ static dns_dbiterator_t *gdbiter;  /* The database iterator */
 static dns_rdataclass_t gclass;                /* The class */
 static dns_name_t *gorigin;            /* The database origin */
 static int nsec3flags = 0;
+static dns_iterations_t nsec3iter = 100U;
+static unsigned char saltbuf[255];
+static unsigned char *salt = saltbuf;
+static size_t salt_length = 0;
 static isc_task_t *master = NULL;
 static unsigned int ntasks = 0;
 static isc_boolean_t shuttingdown = ISC_FALSE, finished = ISC_FALSE;
@@ -161,6 +165,7 @@ static unsigned int serialformat = SOA_SERIAL_KEEP;
 static unsigned int hash_length = 0;
 static isc_boolean_t unknownalg = ISC_FALSE;
 static isc_boolean_t disable_zone_check = ISC_FALSE;
+static isc_boolean_t update_chain = ISC_FALSE;
 static isc_boolean_t set_keyttl = ISC_FALSE;
 static dns_ttl_t keyttl;
 static isc_boolean_t smartsign = ISC_FALSE;
@@ -2001,8 +2006,8 @@ nsecify(void) {
                        type = rdataset.type;
                        covers = rdataset.covers;
                        dns_rdataset_disassociate(&rdataset);
-                       result = dns_db_deleterdataset(gdb, node, gversion, type,
-                                                      covers);
+                       result = dns_db_deleterdataset(gdb, node, gversion,
+                                                      type, covers);
                        check_result(result,
                                     "dns_db_deleterdataset(nsec3param/rrsig)");
                }
@@ -2019,6 +2024,7 @@ nsecify(void) {
 
        result = dns_dbiterator_current(dbiter, &node, name);
        check_dns_dbiterator_current(result);
+
        /*
         * Delete any NSEC3PARAM records at the apex.
         */
@@ -2354,6 +2360,7 @@ nsec3ify(unsigned int hashalg, unsigned int iterations,
 
        result = dns_dbiterator_current(dbiter, &node, name);
        check_dns_dbiterator_current(result);
+
        /*
         * Delete any NSEC records at the apex.
         */
@@ -2366,7 +2373,12 @@ nsec3ify(unsigned int hashalg, unsigned int iterations,
                type = rdataset.type;
                covers = rdataset.covers;
                dns_rdataset_disassociate(&rdataset);
-               if (type == dns_rdatatype_nsec || covers == dns_rdatatype_nsec) {
+               if (type == dns_rdatatype_nsec ||
+                   covers == dns_rdatatype_nsec) {
+                       if (!update_chain)
+                               fatal("Zone contains NSEC records.  Use -u "
+                                     "to update to NSEC3.");
+
                        result = dns_db_deleterdataset(gdb, node, gversion,
                                                       type, covers);
                        check_result(result,
@@ -3012,6 +3024,100 @@ warnifallksk(dns_db_t *db) {
        }
 }
 
+static void
+set_nsec3params(isc_boolean_t update_chain, isc_boolean_t set_salt,
+               isc_boolean_t set_optout, isc_boolean_t set_iter)
+{
+       isc_result_t result;
+       dns_dbversion_t *ver = NULL;
+       dns_dbnode_t *node = NULL;
+       dns_rdataset_t rdataset;
+       dns_rdata_t rdata = DNS_RDATA_INIT;
+       dns_rdata_nsec3_t nsec3;
+       dns_fixedname_t fname;
+       dns_name_t *hashname;
+       unsigned char orig_salt[256];
+       size_t orig_saltlen;
+       dns_hash_t orig_hash;
+       isc_uint16_t orig_iter;
+
+       dns_db_currentversion(gdb, &ver);
+
+       orig_saltlen = sizeof(orig_salt);
+       result = dns_db_getnsec3parameters(gdb, ver, &orig_hash, NULL, 
+                                          &orig_iter, orig_salt,
+                                          &orig_saltlen);
+       if (result != ISC_R_SUCCESS)
+               goto cleanup;
+
+       nsec_datatype = dns_rdatatype_nsec3;
+
+       if (!update_chain && set_salt) {
+               if (salt_length != orig_saltlen ||
+                   memcmp(saltbuf, orig_salt, salt_length) != 0)
+                       fatal("An NSEC3 chain exists with a different salt. "
+                             "Use -u to update it.");
+       } else if (!set_salt) {
+               salt_length = orig_saltlen;
+               memcpy(saltbuf, orig_salt, orig_saltlen);
+               salt = saltbuf;
+       }
+
+       if (!update_chain && set_iter) {
+               if (nsec3iter != orig_iter)
+                       fatal("An NSEC3 chain exists with different "
+                             "iterations. Use -u to update it.");
+       } else if (!set_iter)
+               nsec3iter = orig_iter;
+
+       /*
+        * Find an NSEC3 record to get the current OPTOUT value.
+        * (This assumes all NSEC3 records agree.)
+        */
+
+       dns_fixedname_init(&fname);
+        hashname = dns_fixedname_name(&fname);
+       result = dns_nsec3_hashname(&fname, NULL, NULL,
+                                   gorigin, gorigin, dns_hash_sha1,
+                                   orig_iter, orig_salt, orig_saltlen);
+       check_result(result, "dns_nsec3_hashname");
+
+       result = dns_db_findnsec3node(gdb, hashname, ISC_FALSE, &node);
+       if (result != ISC_R_SUCCESS)
+               goto cleanup;
+
+       dns_rdataset_init(&rdataset);
+       result = dns_db_findrdataset(gdb, node, ver, dns_rdatatype_nsec3,
+                                    0, 0, &rdataset, NULL);
+       if (result != ISC_R_SUCCESS)
+                goto cleanup;
+
+       result = dns_rdataset_first(&rdataset);
+       check_result(result, "dns_rdataset_first");
+       dns_rdataset_current(&rdataset, &rdata);
+       result = dns_rdata_tostruct(&rdata, &nsec3, NULL);
+       check_result(result, "dns_rdata_tostruct");
+
+       if (!update_chain && set_optout) {
+               if (nsec3flags != nsec3.flags)
+                       fatal("An NSEC3 chain exists with%s OPTOUT. "
+                             "Use -u -%s to %s it.",
+                             OPTOUT(nsec3.flags) ? "" : "out",
+                             OPTOUT(nsec3.flags) ? "AA" : "A",
+                             OPTOUT(nsec3.flags) ? "clear" : "set");
+       } else if (!set_optout)
+               nsec3flags = nsec3.flags;
+
+       dns_rdata_freestruct(&nsec3);
+
+ cleanup:
+        if (dns_rdataset_isassociated(&rdataset))
+                dns_rdataset_disassociate(&rdataset);
+        if (node != NULL)
+                dns_db_detachnode(gdb, &node);
+        dns_db_closeversion(gdb, &ver, ISC_FALSE);
+}
+
 static void
 writeset(const char *prefix, dns_rdatatype_t type) {
        char *filename;
@@ -3177,9 +3283,9 @@ usage(void) {
        fprintf(stderr, "Version: %s\n", VERSION);
 
        fprintf(stderr, "Options: (default value in parenthesis) \n");
-       fprintf(stderr, "\t-S:\tsmart signing: automatically finds key\n"
-                       "\t\tfiles for the zone and determines they are to\n"
-                       "\t\tbe used\n");
+       fprintf(stderr, "\t-S:\tsmart signing: automatically finds key files\n"
+                       "\t\tfor the zone and determines how they are to "
+                       "be used\n");
        fprintf(stderr, "\t-K directory:\n");
        fprintf(stderr, "\t\tdirectory to find key files (.)\n");
        fprintf(stderr, "\t-d directory:\n");
@@ -3221,6 +3327,8 @@ usage(void) {
        fprintf(stderr, "\t-T TTL:\tTTL for newly added DNSKEYs");
        fprintf(stderr, "\t-t:\t");
        fprintf(stderr, "print statistics\n");
+       fprintf(stderr, "\t-u:\t");
+       fprintf(stderr, "update or replace an existing NSEC/NSEC3 chain\n");
        fprintf(stderr, "\t-C:\tgenerate a keyset file, for compatibility\n"
                        "\t\twith older versions of dnssec-signzone -g\n");
        fprintf(stderr, "\t-n ncpus (number of cpus present)\n");
@@ -3293,14 +3401,14 @@ main(int argc, char *argv[]) {
        isc_task_t **tasks = NULL;
        isc_buffer_t b;
        int len;
-       unsigned int iterations = 100U;
-       const unsigned char *salt = NULL;
-       size_t salt_length = 0;
-       unsigned char saltbuf[255];
        hashlist_t hashlist;
        isc_boolean_t make_keyset = ISC_FALSE;
-
-#define CMDLINE_FLAGS "3:AaCc:Dd:e:f:FghH:i:I:j:K:k:l:m:n:N:o:O:pPr:s:ST:tUv:z"
+       isc_boolean_t set_salt = ISC_FALSE;
+       isc_boolean_t set_optout = ISC_FALSE;
+       isc_boolean_t set_iter = ISC_FALSE;
+  
+#define CMDLINE_FLAGS \
+       "3:AaCc:Dd:e:f:FghH:i:I:j:K:k:l:m:n:N:o:O:pPr:s:ST:tuUv:z"
 
        /*
         * Process memory debugging argument first.
@@ -3340,7 +3448,9 @@ main(int argc, char *argv[]) {
        while ((ch = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) {
                switch (ch) {
                case '3':
-                       if (strcmp(isc_commandline_argument, "-")) {
+                       set_salt = ISC_TRUE;
+                       nsec_datatype = dns_rdatatype_nsec3;
+                       if (strcmp(isc_commandline_argument, "-") != 0) {
                                isc_buffer_t target;
                                char *sarg;
 
@@ -3350,17 +3460,16 @@ main(int argc, char *argv[]) {
                                result = isc_hex_decodestring(sarg, &target);
                                check_result(result,
                                             "isc_hex_decodestring(salt)");
-                               salt = saltbuf;
                                salt_length = isc_buffer_usedlength(&target);
-                       } else {
-                               salt = saltbuf;
-                               salt_length = 0;
                        }
-                       nsec_datatype = dns_rdatatype_nsec3;
                        break;
 
                case 'A':
-                       nsec3flags |= DNS_NSEC3FLAG_OPTOUT;
+                       set_optout = ISC_TRUE;
+                       if (OPTOUT(nsec3flags))
+                               nsec3flags &= ~DNS_NSEC3FLAG_OPTOUT;
+                       else
+                               nsec3flags |= DNS_NSEC3FLAG_OPTOUT;
                        break;
 
                case 'a':
@@ -3398,11 +3507,11 @@ main(int argc, char *argv[]) {
                        break;
 
                case 'H':
-                       iterations = strtoul(isc_commandline_argument,
-                                            &endp, 0);
+                       set_iter = ISC_TRUE;
+                       nsec3iter = strtoul(isc_commandline_argument, &endp, 0);
                        if (*endp != '\0')
                                fatal("iterations must be numeric");
-                       if (iterations > 0xffffU)
+                       if (nsec3iter  > 0xffffU)
                                fatal("iterations too big");
                        break;
 
@@ -3504,6 +3613,10 @@ main(int argc, char *argv[]) {
                        unknownalg = ISC_TRUE;
                        break;
 
+               case 'u':
+                       update_chain = ISC_TRUE;
+                       break;
+
                case 'v':
                        endp = NULL;
                        verbose = strtol(isc_commandline_argument, &endp, 0);
@@ -3622,7 +3735,8 @@ main(int argc, char *argv[]) {
                else if (strcasecmp(serialformatstr, "unixtime") == 0)
                        serialformat = SOA_SERIAL_UNIXTIME;
                else
-                       fatal("unknown soa serial format: %s\n", serialformatstr);
+                       fatal("unknown soa serial format: %s\n",
+                             serialformatstr);
        }
 
        result = dns_master_stylecreate(&dsstyle,  DNS_STYLEFLAG_NO_TTL,
@@ -3639,6 +3753,15 @@ main(int argc, char *argv[]) {
        if (!set_keyttl)
                keyttl = soa_ttl;
 
+       /*
+        * Check for any existing NSEC3 parameters in the zone,
+        * and use them as defaults if -u was not specified.
+        */
+       if (update_chain && !set_optout && !set_iter && !set_salt)
+               nsec_datatype = dns_rdatatype_nsec;
+       else
+               set_nsec3params(update_chain, set_salt, set_optout, set_iter);
+
        if (IS_NSEC3) {
                isc_boolean_t answer;
                hash_length = dns_nsec3_hashlength(dns_hash_sha1);
@@ -3769,7 +3892,7 @@ main(int argc, char *argv[]) {
                unsigned int max;
                result = dns_nsec3_maxiterations(gdb, NULL, mctx, &max);
                check_result(result, "dns_nsec3_maxiterations()");
-               if (iterations > max)
+               if (nsec3iter > max)
                        fatal("NSEC3 iterations too big for weakest DNSKEY "
                              "strength. Maximum iterations allowed %u.", max);
        }
@@ -3794,7 +3917,7 @@ main(int argc, char *argv[]) {
        }
 
        if (IS_NSEC3)
-               nsec3ify(dns_hash_sha1, iterations, salt, salt_length,
+               nsec3ify(dns_hash_sha1, nsec3iter, salt, salt_length,
                         &hashlist);
        else
                nsecify();
index d6e5bb79a942f956d34d8487f1f158101a4536a1..75ac03e7dcf02be5d555e471d2721c4cfecf641b 100644 (file)
@@ -18,7 +18,7 @@
  - PERFORMANCE OF THIS SOFTWARE.
 -->
 
-<!-- $Id: dnssec-signzone.docbook,v 1.36 2009/09/02 06:29:00 each Exp $ -->
+<!-- $Id: dnssec-signzone.docbook,v 1.37 2009/09/25 06:47:50 each Exp $ -->
 <refentry id="man.dnssec-signzone">
   <refentryinfo>
     <date>June 05, 2009</date>
@@ -80,6 +80,7 @@
       <arg><option>-s <replaceable class="parameter">start-time</replaceable></option></arg>
       <arg><option>-T <replaceable class="parameter">ttl</replaceable></option></arg>
       <arg><option>-t</option></arg>
+      <arg><option>-u</option></arg>
       <arg><option>-v <replaceable class="parameter">level</replaceable></option></arg>
       <arg><option>-z</option></arg>
       <arg><option>-3 <replaceable class="parameter">salt</replaceable></option></arg>
         </listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term>-u</term>
+        <listitem>
+          <para>
+            Update NSEC/NSEC3 chain when re-signing a previously signed
+            zone.  With this option, a zone signed with NSEC can be
+            switched to NSEC3, or a zone signed with NSEC3 can
+            be switch to NSEC or to NSEC3 with different parameters.
+            Without this option, <command>dnssec-signzone</command> will
+            retain the existing chain when re-signing.
+          </para>
+        </listitem>
+      </varlistentry>
+
       <varlistentry>
         <term>-v <replaceable class="parameter">level</replaceable></term>
         <listitem>
            NSEC3 records and do not generate NSEC3 records for insecure
            delegations.
           </para>
+          <para>
+           Using this option twice (i.e., <option>-AA</option>)
+           turns the OPTOUT flag off for all records.  This is useful
+           when using the <option>-u</option> option to modify an NSEC3
+           chain which previously had OPTOUT set.
+          </para>
         </listitem>
       </varlistentry>
 
index 84ebd21c33629ae4e2cc88107e25dac5fa3e1a4d..cc91ef6213920de53db6b2dffba11be282e4140f 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: sign.sh,v 1.27 2009/06/04 02:56:47 tbox Exp $
+# $Id: sign.sh,v 1.28 2009/09/25 06:47:50 each Exp $
 
 SYSTEMTESTTOP=../..
 . $SYSTEMTESTTOP/conf.sh
@@ -213,12 +213,12 @@ cat $infile $keyname.key >$zonefile
 
 $SIGNER -P -r $RANDFILE -o $zone $zonefile > /dev/null
 mv $zonefile.signed $zonefile
-$SIGNER -P -3 - -r $RANDFILE -o $zone $zonefile > /dev/null
+$SIGNER -P -u3 - -r $RANDFILE -o $zone $zonefile > /dev/null
 mv $zonefile.signed $zonefile
-$SIGNER -P -3 AAAA -r $RANDFILE -o $zone $zonefile > /dev/null
+$SIGNER -P -u3 AAAA -r $RANDFILE -o $zone $zonefile > /dev/null
 mv $zonefile.signed $zonefile
-$SIGNER -P -3 BBBB -r $RANDFILE -o $zone $zonefile > /dev/null
+$SIGNER -P -u3 BBBB -r $RANDFILE -o $zone $zonefile > /dev/null
 mv $zonefile.signed $zonefile
-$SIGNER -P -3 CCCC -r $RANDFILE -o $zone $zonefile > /dev/null
+$SIGNER -P -u3 CCCC -r $RANDFILE -o $zone $zonefile > /dev/null
 mv $zonefile.signed $zonefile
-$SIGNER -P -3 DDDD -r $RANDFILE -o $zone $zonefile > /dev/null
+$SIGNER -P -u3 DDDD -r $RANDFILE -o $zone $zonefile > /dev/null