]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Add NSEC3PARAM unit test, refactor zone.c
authorMatthijs Mekking <matthijs@isc.org>
Fri, 13 Nov 2020 11:26:05 +0000 (12:26 +0100)
committerMatthijs Mekking <matthijs@isc.org>
Thu, 26 Nov 2020 09:43:59 +0000 (10:43 +0100)
Add unit test to ensure the right NSEC3PARAM event is scheduled in
'dns_zone_setnsec3param()'.  To avoid scheduling and managing actual
tasks, split up the 'dns_zone_setnsec3param()' function in two parts:

1. 'dns__zone_lookup_nsec3param()' that will check if the requested
   NSEC3 parameters already exist, and if a new salt needs to be
   generated.

2. The actual scheduling of the new NSEC3PARAM event (if needed).

lib/dns/include/dns/result.h
lib/dns/result.c
lib/dns/tests/Makefile.am
lib/dns/tests/nsec3param_test.c [new file with mode: 0644]
lib/dns/tests/testdata/nsec3param/nsec3.db.signed [new file with mode: 0644]
lib/dns/zone.c
lib/dns/zone_p.h
util/copyrights

index 7528e8bef030e444c2833957286ea80655786ae9..58e7426b3fac328a34c51fc085ba19dc26826c11 100644 (file)
 #define DNS_R_NSEC3ITERRANGE   (ISC_RESULTCLASS_DNS + 123)
 #define DNS_R_NSEC3SALTRANGE   (ISC_RESULTCLASS_DNS + 124)
 #define DNS_R_NSEC3BADALG      (ISC_RESULTCLASS_DNS + 125)
+#define DNS_R_NSEC3RESALT      (ISC_RESULTCLASS_DNS + 126)
 
-#define DNS_R_NRESULTS 126 /*%< Number of results */
+#define DNS_R_NRESULTS 127 /*%< Number of results */
 
 /*
  * DNS wire format rcodes.
index 118e2574f0b878ffa4d254ff3bebaddb7bc5084d..1c8641227b95503812fc27d313830d5261f292eb 100644 (file)
@@ -169,10 +169,11 @@ static const char *text[DNS_R_NRESULTS] = {
        "no matching key found",         /*%< 120 DNS_R_NOKEYMATCH */
        "too many keys matching",        /*%< 121 DNS_R_TOOMANYKEYS */
        "key is not actively signing",   /*%< 122 DNS_R_KEYNOTACTIVE */
+       "NSEC3 iterations out of range", /*%< 123 DNS_R_NSEC3ITERRANGE */
+       "NSEC3 salt length too high",    /*%< 124 DNS_R_NSEC3SALTRANGE */
 
-       "NSEC3 iterations out of range",       /*%< 123 DNS_R_NSEC3ITERRANGE */
-       "NSEC3 salt length too high",          /*%< 124 DNS_R_NSEC3SALTRANGE */
        "cannot use NSEC3 with key algorithm", /*%< 125 DNS_R_NSEC3BADALG */
+       "NSEC3 resalt",                        /*%< 126 DNS_R_NSEC3RESALT */
 };
 
 static const char *ids[DNS_R_NRESULTS] = {
@@ -306,6 +307,7 @@ static const char *ids[DNS_R_NRESULTS] = {
        "DNS_R_NSEC3ITERRANGE",
        "DNS_R_NSEC3SALTRANGE",
        "DNS_R_NSEC3BADALG",
+       "DNS_R_NSEC3RESALT",
 };
 
 static const char *rcode_text[DNS_R_NRCODERESULTS] = {
index 3322b892288ef7f16afd9e68b06e805c8b1093fd..d28608bb5fb793c87bc0852d8cf5a81fbdfeb7e9 100644 (file)
@@ -30,6 +30,7 @@ check_PROGRAMS =              \
        keytable_test           \
        name_test               \
        nsec3_test              \
+       nsec3param_test         \
        peer_test               \
        private_test            \
        rbt_serialize_test      \
diff --git a/lib/dns/tests/nsec3param_test.c b/lib/dns/tests/nsec3param_test.c
new file mode 100644 (file)
index 0000000..7cb46f2
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, you can obtain one at https://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#if HAVE_CMOCKA
+
+#include <sched.h> /* IWYU pragma: keep */
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define UNIT_TESTING
+#include <cmocka.h>
+
+#include <isc/hex.h>
+#include <isc/string.h>
+#include <isc/util.h>
+
+#include <dns/db.h>
+#include <dns/nsec3.h>
+#include <dns/result.h>
+
+#include "../zone_p.h"
+#include "dnstest.h"
+
+#define HASH   1
+#define FLAGS  0
+#define ITER   5
+#define SALTLEN 4
+#define SALT   "FEDCBA98"
+
+static int
+_setup(void **state) {
+       isc_result_t result;
+
+       UNUSED(state);
+
+       result = dns_test_begin(NULL, false);
+       assert_int_equal(result, ISC_R_SUCCESS);
+
+       return (0);
+}
+
+static int
+_teardown(void **state) {
+       UNUSED(state);
+
+       dns_test_end();
+
+       return (0);
+}
+
+/*%
+ * Structures containing parameters for nsec3param_salttotext_test().
+ */
+typedef struct {
+       dns_hash_t hash;
+       unsigned char flags;
+       dns_iterations_t iterations;
+       unsigned char salt_length;
+       const char *salt;
+} nsec3param_rdata_test_params_t;
+
+typedef struct {
+       nsec3param_rdata_test_params_t lookup;
+       nsec3param_rdata_test_params_t expect;
+       bool resalt;
+       isc_result_t expected_result;
+} nsec3param_change_test_params_t;
+
+static void
+decode_salt(const char *string, unsigned char *salt, size_t saltlen) {
+       isc_buffer_t buf;
+       isc_result_t result;
+
+       isc_buffer_init(&buf, salt, saltlen);
+       result = isc_hex_decodestring(string, &buf);
+       assert_int_equal(result, ISC_R_SUCCESS);
+}
+
+static void
+copy_params(nsec3param_rdata_test_params_t from, dns_rdata_nsec3param_t *to,
+           unsigned char *saltbuf, size_t saltlen) {
+       to->hash = from.hash;
+       to->flags = from.flags;
+       to->iterations = from.iterations;
+       to->salt_length = from.salt_length;
+       if (from.salt == NULL) {
+               to->salt = NULL;
+       } else if (strcmp(from.salt, "-") == 0) {
+               DE_CONST("-", to->salt);
+       } else {
+               decode_salt(from.salt, saltbuf, saltlen);
+               to->salt = saltbuf;
+       }
+}
+
+static nsec3param_rdata_test_params_t
+rdata_fromparams(uint8_t hash, uint8_t flags, uint16_t iter, uint8_t saltlen,
+                const char *salt) {
+       nsec3param_rdata_test_params_t nsec3param;
+       nsec3param.hash = hash;
+       nsec3param.flags = flags;
+       nsec3param.iterations = iter;
+       nsec3param.salt_length = saltlen;
+       nsec3param.salt = salt;
+       return (nsec3param);
+}
+
+/*%
+ * Check whether zone_lookup_nsec3param() finds the correct NSEC3PARAM
+ * and sets the correct parameters to use in dns_zone_setnsec3param().
+ */
+static void
+nsec3param_change_test(const nsec3param_change_test_params_t *test) {
+       dns_zone_t *zone = NULL;
+       dns_rdata_nsec3param_t param, lookup, expect;
+       isc_result_t result;
+       unsigned char lookupsalt[255];
+       unsigned char expectsalt[255];
+       unsigned char saltbuf[255];
+
+       /*
+        * Prepare a zone along with its signing keys.
+        */
+       result = dns_test_makezone("nsec3", &zone, NULL, false);
+       assert_int_equal(result, ISC_R_SUCCESS);
+
+       result = dns_zone_setfile(zone, "testdata/nsec3param/nsec3.db.signed",
+                                 dns_masterformat_text,
+                                 &dns_master_style_default);
+       assert_int_equal(result, ISC_R_SUCCESS);
+
+       result = dns_zone_load(zone, false);
+       assert_int_equal(result, ISC_R_SUCCESS);
+
+       /*
+        * Copy parameters.
+        */
+       copy_params(test->lookup, &lookup, lookupsalt, sizeof(lookupsalt));
+       copy_params(test->expect, &expect, expectsalt, sizeof(expectsalt));
+
+       /*
+        * Test dns__zone_lookup_nsec3param().
+        */
+       result = dns__zone_lookup_nsec3param(zone, &lookup, &param, saltbuf,
+                                            test->resalt);
+
+       assert_int_equal(param.hash, expect.hash);
+       assert_int_equal(param.flags, expect.flags);
+       assert_int_equal(param.iterations, expect.iterations);
+       assert_int_equal(param.salt_length, expect.salt_length);
+       assert_non_null(param.salt);
+       if (expect.salt != NULL) {
+               int ret = memcmp(param.salt, expect.salt, expect.salt_length);
+               assert_true(ret == 0);
+       } else {
+               /*
+                * We don't know what the new salt is, but we can compare it
+                * to the previous salt and test that it has changed.
+                */
+               unsigned char salt[SALTLEN];
+               int ret;
+               decode_salt(SALT, salt, SALTLEN);
+               ret = memcmp(param.salt, salt, SALTLEN);
+               assert_false(ret == 0);
+       }
+
+       /*
+        * Detach.
+        */
+       dns_zone_detach(&zone);
+}
+
+static void
+nsec3param_change(void **state) {
+       size_t i;
+
+       /*
+        * Define tests.
+        */
+       const nsec3param_change_test_params_t tests[] = {
+               /*
+                * 1. Change nothing (don't care about salt).
+                * This should return ISC_R_SUCCESS because we are already
+                * using these NSEC3 parameters.
+                */
+               { rdata_fromparams(HASH, FLAGS, ITER, SALTLEN, NULL),
+                 rdata_fromparams(HASH, FLAGS, ITER, SALTLEN, SALT), false,
+                 ISC_R_SUCCESS },
+               /*
+                * 2. Change nothing, but force a resalt.
+                * This should change the salt. Set 'expect.salt' to NULL to
+                * test a new salt has been generated.
+                */
+               { rdata_fromparams(HASH, FLAGS, ITER, SALTLEN, NULL),
+                 rdata_fromparams(HASH, FLAGS, ITER, SALTLEN, NULL), true,
+                 DNS_R_NSEC3RESALT },
+               /*
+                * 3. Change iterations.
+                * The NSEC3 paarameters are not found, and there is no
+                * need to resalt because an explicit salt has been set,
+                * and resalt is not enforced.
+                */
+               { rdata_fromparams(HASH, FLAGS, 10, SALTLEN, SALT),
+                 rdata_fromparams(HASH, FLAGS, 10, SALTLEN, SALT), false,
+                 ISC_R_NOTFOUND },
+               /*
+                * 4. Change iterations, don't care about the salt.
+                * We don't care about the salt. Since we need to change the
+                * NSEC3 parameters, we will also resalt.
+                */
+               { rdata_fromparams(HASH, FLAGS, 10, SALTLEN, NULL),
+                 rdata_fromparams(HASH, FLAGS, 10, SALTLEN, NULL), false,
+                 DNS_R_NSEC3RESALT },
+               /*
+                * 5. Change salt length.
+                * Changing salt length means we need to resalt.
+                */
+               { rdata_fromparams(HASH, FLAGS, ITER, 16, NULL),
+                 rdata_fromparams(HASH, FLAGS, ITER, 16, NULL), false,
+                 DNS_R_NSEC3RESALT },
+               /*
+                * 6. Set explicit salt.
+                * A different salt, so the NSEC3 parameters are not found.
+                * No need to resalt because an explicit salt is available.
+                */
+               { rdata_fromparams(HASH, FLAGS, ITER, 4, "12345678"),
+                 rdata_fromparams(HASH, FLAGS, ITER, 4, "12345678"), false,
+                 ISC_R_NOTFOUND },
+               /*
+                * 7. Same salt.
+                * Nothing changed, so expect ISC_R_SUCCESS as a result.
+                */
+               { rdata_fromparams(HASH, FLAGS, ITER, SALTLEN, SALT),
+                 rdata_fromparams(HASH, FLAGS, ITER, SALTLEN, SALT), false,
+                 ISC_R_SUCCESS },
+               /*
+                * 8. Same salt, and force resalt.
+                * Nothing changed, but a resalt is enforced.
+                */
+               { rdata_fromparams(HASH, FLAGS, ITER, SALTLEN, SALT),
+                 rdata_fromparams(HASH, FLAGS, ITER, SALTLEN, NULL), true,
+                 DNS_R_NSEC3RESALT },
+               /*
+                * 9. No salt.
+                * Change parameters to use no salt. These parameters are
+                * not found, and no new salt needs to be generated.
+                */
+               { rdata_fromparams(HASH, FLAGS, ITER, 0, NULL),
+                 rdata_fromparams(HASH, FLAGS, ITER, 0, "-"), true,
+                 ISC_R_NOTFOUND },
+               /*
+                * 10. No salt, explicit.
+                * Same as above, but set no salt explicitly.
+                */
+               { rdata_fromparams(HASH, FLAGS, ITER, 0, "-"),
+                 rdata_fromparams(HASH, FLAGS, ITER, 0, "-"), true,
+                 ISC_R_NOTFOUND },
+       };
+
+       UNUSED(state);
+
+       /*
+        * Run tests.
+        */
+       for (i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
+               nsec3param_change_test(&tests[i]);
+       }
+}
+
+int
+main(void) {
+       const struct CMUnitTest tests[] = {
+               cmocka_unit_test_setup_teardown(nsec3param_change, _setup,
+                                               _teardown),
+       };
+
+       return (cmocka_run_group_tests(tests, NULL, NULL));
+}
+
+#else /* HAVE_CMOCKA */
+
+#include <stdio.h>
+
+int
+main(void) {
+       printf("1..0 # Skipped: cmocka not available\n");
+       return (0);
+}
+
+#endif /* if HAVE_CMOCKA */
diff --git a/lib/dns/tests/testdata/nsec3param/nsec3.db.signed b/lib/dns/tests/testdata/nsec3param/nsec3.db.signed
new file mode 100644 (file)
index 0000000..aeced0e
--- /dev/null
@@ -0,0 +1,73 @@
+; File written on Mon Nov 16 16:04:21 2020
+; dnssec_signzone version 9.16.8
+nsec3.                 1000    IN SOA  nsec3. postmaster.nsec3. (
+                                       1993050801 ; serial
+                                       3600       ; refresh (1 hour)
+                                       1800       ; retry (30 minutes)
+                                       604800     ; expire (1 week)
+                                       3600       ; minimum (1 hour)
+                                       )
+                       1000    RRSIG   SOA 13 1 1000 (
+                                       20201216140421 20201116140421 40382 nsec3.
+                                       qh61ZPgQaNLAoIQvAoTLbR3sLBY7XATaMGSS
+                                       fYOssQWvgAzpAzhalmF/cSXmQ/RZQOyIdpVg
+                                       v3rgyTxA2vGNnA== )
+                       1000    NS      ns1.nsec3.
+                       1000    NS      ns2.nsec3.
+                       1000    RRSIG   NS 13 1 1000 (
+                                       20201216140421 20201116140421 40382 nsec3.
+                                       4Le+e5Lu/taEvrvrmBn/z+QP4zhzUqwO6v70
+                                       WYrzCggUls8+fUd2unBHDPWag1oSKfNpGGWA
+                                       crihrs4RhMPfZA== )
+                       1000    DNSKEY  257 3 13 (
+                                       VKkttSi/v3lAyzUYnykwdwowXfDOQ7wdN9BT
+                                       +eb8fVfgRApvuun9hjUBlv7ogriU/GAb60B8
+                                       juj9bXZADT+OGg==
+                                       ) ; KSK; alg = ECDSAP256SHA256 ; key id = 40382
+                       1000    RRSIG   DNSKEY 13 1 1000 (
+                                       20201216140421 20201116140421 40382 nsec3.
+                                       ZnBqGgWvHwjjQBSIRPXe2fx6+MsQp1QQdzJ0
+                                       QaEyaOmud5JPatUXaV9eFRcPNCsi+2HZSZVp
+                                       vsAGUCge7w6u9A== )
+                       0       NSEC3PARAM 1 0 5 FEDCBA98
+                       0       RRSIG   NSEC3PARAM 13 1 0 (
+                                       20201216140421 20201116140421 40382 nsec3.
+                                       WPTD+5vr54YtvGqCUJHPvGdF7Wd4piZYltcs
+                                       cztBRfdM7FRJ/zvrDS72rt6zm0TYSXzawqt/
+                                       MiwOkYKv2vxfUg== )
+ns2.nsec3.             1000    IN A    1.2.3.5
+                       1000    RRSIG   A 13 2 1000 (
+                                       20201216140421 20201116140421 40382 nsec3.
+                                       l9Mc2Y5JFmllSxJj3GUdH6RtEsYfhjJU39sa
+                                       vAVa4zxv6S9vU+vLvTA05aQ+DPLvKTX+WNH7
+                                       dDa+Yy5ffBs68g== )
+QVCH33BSJ0Q2C74FEDFDBCFQHO255NEB.nsec3.        3600 IN NSEC3 1 0 5 FEDCBA98 (
+                                       STH5N5QDVC5DGEN5VGUC7JGALSM3R8AP
+                                       A RRSIG )
+                       3600    RRSIG   NSEC3 13 2 3600 (
+                                       20201216140421 20201116140421 40382 nsec3.
+                                       F/wKQtv+RlBHG1WCz0CkHlTSoUiRx0z+qBI1
+                                       GTHoXSjgG1NSHqTI4C32AasZSMp+uuF2R8KW
+                                       9z4gOLucl0Xmfg== )
+STH5N5QDVC5DGEN5VGUC7JGALSM3R8AP.nsec3.        3600 IN NSEC3 1 0 5 FEDCBA98 (
+                                       A084TNR6VJ2ND5K1U0AI4HO4EPVKBG4U
+                                       NS SOA RRSIG DNSKEY NSEC3PARAM )
+                       3600    RRSIG   NSEC3 13 2 3600 (
+                                       20201216140421 20201116140421 40382 nsec3.
+                                       9TgGFGY3vwkxMFlXy3oKMgHPqvcPozKDHZzc
+                                       Ny6eJn3TXNX5bLhiT5rw5+CCtyOEQmn3pf0X
+                                       njK7jZBAcBV+5Q== )
+A084TNR6VJ2ND5K1U0AI4HO4EPVKBG4U.nsec3.        3600 IN NSEC3 1 0 5 FEDCBA98 (
+                                       QVCH33BSJ0Q2C74FEDFDBCFQHO255NEB
+                                       A RRSIG )
+                       3600    RRSIG   NSEC3 13 2 3600 (
+                                       20201216140421 20201116140421 40382 nsec3.
+                                       auf+5lrkMESIfdFK8bf4yg1a+NLGWzgUmohS
+                                       ydcKaJz0XcnULegatWdfE75jmZoDeqKNpwdL
+                                       5lQ77GF4cEh1OQ== )
+ns1.nsec3.             1000    IN A    1.2.3.4
+                       1000    RRSIG   A 13 2 1000 (
+                                       20201216140421 20201116140421 40382 nsec3.
+                                       yAmr1EE8qe+Jl+wQXOdj/uSjMFUmns0D1lx6
+                                       zAVe9BaQwvF3wR7ZUk/u9G0RrUBchmEj0+yq
+                                       KEsw32Tru4Romg== )
index 629992cc3808e7b96a634dd9601edcc57cc73985..112e8a439442a5f127d4038a72764e865f5125a2 100644 (file)
@@ -21052,6 +21052,25 @@ failure:
        INSIST(newver == NULL);
 }
 
+static void
+salt2text(unsigned char *salt, uint8_t saltlen, unsigned char *text,
+         unsigned int textlen) {
+       isc_region_t r;
+       isc_buffer_t buf;
+       isc_result_t result;
+
+       r.base = salt;
+       r.length = (unsigned int)saltlen;
+
+       isc_buffer_init(&buf, text, textlen);
+       result = isc_hex_totext(&r, 2, "", &buf);
+       if (result == ISC_R_SUCCESS) {
+               text[saltlen * 2] = 0;
+       } else {
+               text[0] = 0;
+       }
+}
+
 /*
  * Check if zone has NSEC3PARAM (and thus a chain) with the right parameters.
  *
@@ -21061,9 +21080,10 @@ failure:
  * Returns  ISC_R_SUCCESS, if a match is found, or an error if no match is
  * found, or if the db lookup failed.
  */
-static isc_result_t
-zone_has_nsec3param(dns_zone_t *zone, uint8_t hash, uint8_t flags,
-                   uint16_t iter, uint8_t saltlen, unsigned char *salt) {
+isc_result_t
+dns__zone_lookup_nsec3param(dns_zone_t *zone, dns_rdata_nsec3param_t *lookup,
+                           dns_rdata_nsec3param_t *param,
+                           unsigned char saltbuf[255], bool resalt) {
        isc_result_t result = ISC_R_UNEXPECTED;
        dns_dbnode_t *node = NULL;
        dns_db_t *db = NULL;
@@ -21073,7 +21093,6 @@ zone_has_nsec3param(dns_zone_t *zone, uint8_t hash, uint8_t flags,
        dns_rdata_t rdata = DNS_RDATA_INIT;
 
        REQUIRE(DNS_ZONE_VALID(zone));
-       UNUSED(flags);
 
        dns_rdataset_init(&rdataset);
 
@@ -21083,7 +21102,7 @@ zone_has_nsec3param(dns_zone_t *zone, uint8_t hash, uint8_t flags,
        }
        ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
        if (db == NULL) {
-               goto cleanup;
+               goto setparam;
        }
 
        result = dns_db_findnode(db, &zone->origin, false, &node);
@@ -21091,7 +21110,7 @@ zone_has_nsec3param(dns_zone_t *zone, uint8_t hash, uint8_t flags,
                dns_zone_log(zone, ISC_LOG_ERROR,
                             "nsec3param lookup failure: %s",
                             dns_result_totext(result));
-               goto cleanup;
+               goto setparam;
        }
        dns_db_currentversion(db, &version);
 
@@ -21105,7 +21124,7 @@ zone_has_nsec3param(dns_zone_t *zone, uint8_t hash, uint8_t flags,
                                     "nsec3param lookup failure: %s",
                                     dns_result_totext(result));
                }
-               goto cleanup;
+               goto setparam;
        }
 
        for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS;
@@ -21115,27 +21134,76 @@ zone_has_nsec3param(dns_zone_t *zone, uint8_t hash, uint8_t flags,
                result = dns_rdata_tostruct(&rdata, &nsec3param, NULL);
                INSIST(result == ISC_R_SUCCESS);
                dns_rdata_reset(&rdata);
-               if (nsec3param.hash != hash) {
+
+               /* Check parameters. */
+               if (nsec3param.hash != lookup->hash) {
                        continue;
                }
-               if (nsec3param.iterations != iter) {
+               if (nsec3param.iterations != lookup->iterations) {
                        continue;
                }
-               if (nsec3param.salt_length != saltlen) {
+               if (nsec3param.salt_length != lookup->salt_length) {
                        continue;
                }
-               if (salt != NULL) {
-                       if (memcmp(nsec3param.salt, salt, saltlen) != 0) {
+               if (lookup->salt != NULL) {
+                       if (memcmp(nsec3param.salt, lookup->salt,
+                                  lookup->salt_length) != 0) {
                                continue;
                        }
                }
                /* Found a match. */
                result = ISC_R_SUCCESS;
-               goto cleanup;
+               param->hash = nsec3param.hash;
+               param->flags = nsec3param.flags;
+               param->iterations = nsec3param.iterations;
+               param->salt_length = nsec3param.salt_length;
+               param->salt = nsec3param.salt;
+               break;
+       }
+
+setparam:
+       if (result != ISC_R_SUCCESS) {
+               /* Found no match. */
+               result = ISC_R_NOTFOUND;
+               param->hash = lookup->hash;
+               param->flags = lookup->flags;
+               param->iterations = lookup->iterations;
+               param->salt_length = lookup->salt_length;
+               param->salt = lookup->salt;
+       }
+
+       if (param->salt_length == 0) {
+               DE_CONST("-", param->salt);
+       } else if (resalt || param->salt == NULL) {
+               unsigned char *newsalt;
+               unsigned char salttext[255 * 2 + 1];
+               do {
+                       /* Generate a new salt. */
+                       result = dns_nsec3_generate_salt(saltbuf,
+                                                        param->salt_length);
+                       if (result != ISC_R_SUCCESS) {
+                               break;
+                       }
+                       newsalt = saltbuf;
+                       salt2text(newsalt, param->salt_length, salttext,
+                                 sizeof(salttext));
+                       dnssec_log(zone, ISC_LOG_INFO, "generated salt: %s",
+                                  salttext);
+                       /* Check for salt conflict. */
+                       if (param->salt != NULL &&
+                           memcmp(newsalt, param->salt, param->salt_length) ==
+                                   0)
+                       {
+                               result = ISC_R_SUCCESS;
+                       } else {
+                               param->salt = newsalt;
+                               result = DNS_R_NSEC3RESALT;
+                       }
+               } while (result == ISC_R_SUCCESS);
+
+               INSIST(result != ISC_R_SUCCESS);
        }
-       INSIST(result != ISC_R_SUCCESS);
 
-cleanup:
        if (dns_rdataset_isassociated(&rdataset)) {
                dns_rdataset_disassociate(&rdataset);
        }
@@ -21152,25 +21220,6 @@ cleanup:
        return (result);
 }
 
-static void
-salt2text(unsigned char *salt, uint8_t saltlen, unsigned char *text,
-         unsigned int textlen) {
-       isc_region_t r;
-       isc_buffer_t buf;
-       isc_result_t result;
-
-       r.base = salt;
-       r.length = (unsigned int)saltlen;
-
-       isc_buffer_init(&buf, text, textlen);
-       result = isc_hex_totext(&r, 2, "", &buf);
-       if (result == ISC_R_SUCCESS) {
-               text[saltlen * 2] = 0;
-       } else {
-               text[0] = 0;
-       }
-}
-
 /*
  * Called when an "rndc signing -nsec3param ..." command is received, or the
  * 'dnssec-policy' has changed.
@@ -21196,59 +21245,41 @@ dns_zone_setnsec3param(dns_zone_t *zone, uint8_t hash, uint8_t flags,
                       uint16_t iter, uint8_t saltlen, unsigned char *salt,
                       bool replace, bool resalt) {
        isc_result_t result = ISC_R_SUCCESS;
-       dns_rdata_nsec3param_t param;
+       dns_rdata_nsec3param_t param, lookup;
        dns_rdata_t nrdata = DNS_RDATA_INIT;
        dns_rdata_t prdata = DNS_RDATA_INIT;
        unsigned char nbuf[DNS_NSEC3PARAM_BUFFERSIZE];
+       unsigned char saltbuf[255];
        struct np3event *npe;
        nsec3param_t *np;
        dns_zone_t *dummy = NULL;
        isc_buffer_t b;
        isc_event_t *e = NULL;
-       unsigned char saltbuf[255];
-       unsigned char salttext[255 * 2 + 1];
 
        REQUIRE(DNS_ZONE_VALID(zone));
 
        LOCK_ZONE(zone);
 
-       result = zone_has_nsec3param(zone, hash, flags, iter, saltlen, salt);
-       if (result == ISC_R_SUCCESS) {
-               /*
-                * The right NSEC3 parameters are already set, no need to
-                * set again, unless resalting is enforced.
-                */
-               if (!resalt) {
-                       result = ISC_R_EXISTS;
-                       goto failure;
+       /*
+        * First check if the requested NSEC3 parameters are already set,
+        * if so, no need to set again.
+        */
+       if (hash != 0) {
+               lookup.hash = hash;
+               lookup.flags = flags;
+               lookup.iterations = iter;
+               lookup.salt_length = saltlen;
+               lookup.salt = salt;
+               param.salt = NULL;
+               result = dns__zone_lookup_nsec3param(zone, &lookup, &param,
+                                                    saltbuf, resalt);
+               if (result == ISC_R_SUCCESS) {
+                       UNLOCK_ZONE(zone);
+                       return (ISC_R_SUCCESS);
                }
+               INSIST(param.salt != NULL);
        }
 
-       if (saltlen == 0) {
-               DE_CONST("-", salt);
-               salttext[0] = '-';
-               salttext[1] = 0;
-       } else if (resalt || salt == NULL) {
-               do {
-                       /* Generate a new salt. */
-                       CHECK(dns_nsec3_generate_salt(saltbuf, saltlen));
-                       if (result != ISC_R_SUCCESS) {
-                               goto failure;
-                       }
-                       salt = saltbuf;
-                       salt2text(salt, saltlen, salttext, sizeof(salttext));
-                       dnssec_log(zone, ISC_LOG_INFO, "generated salt: %s",
-                                  salttext);
-                       /*
-                        * Check for NSEC3 param conflicts, this is done to
-                        * avoid salt collision.
-                        */
-                       result = zone_has_nsec3param(zone, hash, flags, iter,
-                                                    saltlen, salt);
-               } while (result == ISC_R_SUCCESS);
-       }
-       INSIST(salt != NULL);
-
        e = isc_event_allocate(zone->mctx, zone, DNS_EVENT_SETNSEC3PARAM,
                               setnsec3param, zone, sizeof(struct np3event));
 
@@ -21265,11 +21296,7 @@ dns_zone_setnsec3param(dns_zone_t *zone, uint8_t hash, uint8_t flags,
                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;
+               /* nsec3 specific param set in dns__zone_lookup_nsec3param() */
                isc_buffer_init(&b, nbuf, sizeof(nbuf));
                CHECK(dns_rdata_fromstruct(&nrdata, zone->rdclass,
                                           dns_rdatatype_nsec3param, &param,
@@ -21280,10 +21307,13 @@ dns_zone_setnsec3param(dns_zone_t *zone, uint8_t hash, uint8_t flags,
                np->nsec = false;
 
                if (isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(3))) {
-                       salt2text(salt, saltlen, salttext, sizeof(salttext));
+                       unsigned char salttext[255 * 2 + 1];
+                       salt2text(param.salt, param.salt_length, salttext,
+                                 sizeof(salttext));
                        dnssec_log(zone, ISC_LOG_DEBUG(3),
-                                  "setnsec3param:nsec3 %u %u %u %s", hash,
-                                  flags, iter, salttext);
+                                  "setnsec3param:nsec3 %u %u %u %s",
+                                  param.hash, param.flags, param.iterations,
+                                  salttext);
                }
        }
 
index 90f0b8476cd9a38961b1408f221abdb022bb72c1..0c1c40d109ff96f1c60828c2b5ff44a8175748dd 100644 (file)
@@ -41,6 +41,11 @@ dns__zone_updatesigs(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *version,
                     isc_stdtime_t now, bool check_ksk, bool keyset_kskonly,
                     dns__zonediff_t *zonediff);
 
+isc_result_t
+dns__zone_lookup_nsec3param(dns_zone_t *zone, dns_rdata_nsec3param_t *lookup,
+                           dns_rdata_nsec3param_t *param,
+                           unsigned char saltbuf[255], bool resalt);
+
 ISC_LANG_ENDDECLS
 
 #endif /* DNS_ZONE_P_H */
index ef18d6f35b6e0b511cb4983233c36bbc0da380b7..065652da3072d4472101dcd97788453756800d97 100644 (file)
 ./lib/dns/tests/mkraw.pl                       PERL    2011,2012,2016,2018,2019,2020
 ./lib/dns/tests/name_test.c                    C       2014,2015,2016,2017,2018,2019,2020
 ./lib/dns/tests/nsec3_test.c                   C       2012,2014,2015,2016,2017,2018,2019,2020
+./lib/dns/tests/nsec3param_test.c              C       2020
 ./lib/dns/tests/peer_test.c                    C       2014,2016,2018,2019,2020
 ./lib/dns/tests/private_test.c                 C       2011,2012,2016,2018,2019,2020
 ./lib/dns/tests/rbt_serialize_test.c           C       2014,2015,2016,2018,2019,2020