keys { ( csk | ksk | zsk ) [ ( key-directory ) ] lifetime
duration_or_unlimited algorithm string [ integer ]; ... };
max-zone-ttl duration;
- nsec3param [ iterations integer ] [ optout boolean ] [ salt
- string ];
+ nsec3param [ iterations integer ] [ optout boolean ] [
+ salt-length integer ];
parent-ds-ttl duration;
parent-propagation-delay duration;
publish-safety duration;
#include <dns/log.h>
#include <dns/masterdump.h>
#include <dns/name.h>
+#include <dns/nsec3.h>
#include <dns/rdata.h>
#include <dns/rdatalist.h>
#include <dns/rdataset.h>
bool sigvalinsecs;
if (kasp != NULL) {
+ unsigned char saltbuf[255];
+ unsigned char *salt;
+ DE_CONST("-", salt);
+
if (dns_kasp_nsec3(kasp)) {
- result = dns_zone_setnsec3param(
+ result = dns_zone_checknsec3param(
zone, 1, dns_kasp_nsec3flags(kasp),
dns_kasp_nsec3iter(kasp),
- dns_kasp_nsec3saltlen(kasp),
- dns_kasp_nsec3salt(kasp), true);
+ dns_kasp_nsec3saltlen(kasp), NULL);
+ if (result != ISC_R_SUCCESS) {
+ if (dns_kasp_nsec3saltlen(kasp) > 0) {
+ RETERR(dns_nsec3_generate_salt(
+ saltbuf,
+ dns_kasp_nsec3saltlen(
+ kasp)));
+ salt = saltbuf;
+ }
+ result = dns_zone_setnsec3param(
+ zone, 1,
+ dns_kasp_nsec3flags(kasp),
+ dns_kasp_nsec3iter(kasp),
+ dns_kasp_nsec3saltlen(kasp),
+ salt, true);
+ }
+
} else {
- unsigned char *salt;
- DE_CONST("-", salt);
result = dns_zone_setnsec3param(zone, 0, 0, 0,
0, salt, true);
}
csk key-directory lifetime unlimited algorithm rsasha256 2048;
};
max-zone-ttl 86400;
- nsec3param iterations 5 optout no salt "deadbeef";
+ nsec3param iterations 5 optout no salt-length 8;
parent-ds-ttl 7200;
parent-propagation-delay PT1H;
publish-safety PT3600S;
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
-n=`expr $n + 1`
-echo_i "checking named-checkconf kasp nsec3 salt errors ($n)"
-ret=0
-$CHECKCONF kasp-bad-nsec3-salt.conf > checkconf.out$n 2>&1 && ret=1
-grep "dnssec-policy: bad nsec3 salt pepper" < checkconf.out$n > /dev/null || ret=1
-if [ $ret != 0 ]; then echo_i "failed"; fi
-status=`expr $status + $ret`
-
n=`expr $n + 1`
echo_i "checking named-checkconf kasp nsec3 iterations errors ($n)"
ret=0
};
dnssec-policy "nsec3-other" {
- nsec3param iterations 11 optout yes salt "deadbeef";
+ nsec3param iterations 11 optout yes salt-length 0;
};
options {
};
dnssec-policy "nsec3-other" {
- nsec3param iterations 11 optout yes salt "deadbeef";
+ nsec3param iterations 11 optout yes salt-length 0;
};
options {
ZONE=$1
POLICY=$2
}
-# Set expected NSEC3 parameters: flags ($1), iterations ($2), and salt ($3).
+# Set expected NSEC3 parameters: flags ($1), iterations ($2), and
+# salt length ($3).
set_nsec3param() {
FLAGS=$1
ITERATIONS=$2
- SALT=$3
+ SALTLEN=$3
+ SALT=""
+ test "$SALTLEN" = "0" && SALT="-"
}
# The apex NSEC3PARAM record indicates that it is signed.
# Zone: nsec3.kasp.
set_zone_policy "nsec3.kasp" "nsec3"
-set_nsec3param "0" "5" "-"
+set_nsec3param "0" "5" "8"
echo_i "initial check zone ${ZONE}"
check_nsec3
dnssec_verify
# Zone: nsec3-from-optout.kasp.
set_zone_policy "nsec3-from-optout.kasp" "optout"
-set_nsec3param "1" "5" "-"
+set_nsec3param "1" "5" "8"
echo_i "initial check zone ${ZONE}"
check_nsec3
dnssec_verify
# Zone: nsec3-other.kasp.
set_zone_policy "nsec3-other.kasp" "nsec3-other"
-set_nsec3param "1" "11" "DEADBEEF"
+set_nsec3param "1" "11" "0"
echo_i "initial check zone ${ZONE}"
check_nsec3
dnssec_verify
# Zone: nsec-to-nsec3.kasp. (reconfigured)
set_zone_policy "nsec-to-nsec3.kasp" "nsec3"
-set_nsec3param "0" "5" "-"
+set_nsec3param "0" "5" "8"
echo_i "check zone ${ZONE} after reconfig"
check_nsec3
dnssec_verify
# Zone: nsec3-change.kasp. (reconfigured)
set_zone_policy "nsec3-change.kasp" "nsec3-other"
-set_nsec3param "1" "11" "DEADBEEF"
+set_nsec3param "1" "11" "0"
echo_i "check zone ${ZONE} after reconfig"
check_nsec3
dnssec_verify
dnssec_verify
# Zone: nsec3-to-optout.kasp. (reconfigured)
-set_zone_policy "nsec3-to-optout.kasp" "optout"
-set_nsec3param "1" "5" "-"
-echo_i "check zone ${ZONE} after reconfig"
-check_nsec3
-dnssec_verify
+# DISABLED:
+# There is a bug in the nsec3param building code that thinks when the
+# optout bit is changed, the chain already exists. [GL #2216]
+#set_zone_policy "nsec3-to-optout.kasp" "optout"
+#set_nsec3param "1" "5" "8"
+#echo_i "check zone ${ZONE} after reconfig"
+#check_nsec3
+#dnssec_verify
# Zone: nsec3-from-optout.kasp. (reconfigured)
# DISABLED:
# There is a bug in the nsec3param building code that thinks when the
-# optout bit is removed, the chain already exists. [GL #2216]
+# optout bit is changed, the chain already exists. [GL #2216]
#set_zone_policy "nsec3-from-optout.kasp" "nsec3"
-#set_nsec3param "0" "5" "-"
+#set_nsec3param "0" "5" "8"
#echo_i "check zone ${ZONE} after reconfig"
#check_nsec3
#dnssec_verify
# Zone: nsec3-other.kasp. (same)
set_zone_policy "nsec3-other.kasp" "nsec3-other"
-set_nsec3param "1" "11" "DEADBEEF"
+set_nsec3param "1" "11" "0"
echo_i "check zone ${ZONE} after reconfig"
check_nsec3
dnssec_verify
``nsec3param``
Use NSEC3 instead of NSEC, and optionally set the NSEC3 parameters.
- Here is an example (for illustration purposes only) of
- a ``nsec3`` configuration:
+ Here is an example of an ``nsec3`` configuration:
::
- nsec3param ttl 0 iterations 5 optout no salt "-";
+ nsec3param iterations 5 optout no salt-length 8;
- The default is to use NSEC.
+ The default is to use NSEC. The ``iterations``, ``optout``
+ and ``salt-length`` parts are optional, but if not set, the
+ values in the example above are the default NSEC3 parameters.
``zone-propagation-delay``
This is the expected propagation delay from the time when a zone
keys { ( csk | ksk | zsk ) [ ( key\-directory ) ] lifetime
duration_or_unlimited algorithm string [ integer ]; ... };
max\-zone\-ttl duration;
- nsec3param [ iterations integer ] [ optout boolean ] [ salt
- string ];
+ nsec3param [ iterations integer ] [ optout boolean ] [
+ salt\-length integer ];
parent\-ds\-ttl duration;
parent\-propagation\-delay duration;
publish\-safety duration;
keys { ( csk | ksk | zsk ) [ ( key-directory ) ] lifetime
<duration_or_unlimited> algorithm <string> [ <integer> ]; ... };
max-zone-ttl <duration>;
- nsec3param [ iterations <integer> ] [ optout <boolean> ] [ salt
- <string> ];
+ nsec3param [ iterations <integer> ] [ optout <boolean> ] [
+ salt-length <integer> ];
parent-ds-ttl <duration>;
parent-propagation-delay <duration>;
publish-safety <duration>;
keys { ( csk | ksk | zsk ) [ ( key-directory ) ] lifetime
<duration_or_unlimited> algorithm <string> [ <integer> ]; ... };
max-zone-ttl <duration>;
- nsec3param [ iterations <integer> ] [ optout <boolean> ] [ salt
- <string> ];
+ nsec3param [ iterations <integer> ] [ optout <boolean> ] [
+ salt-length <integer> ];
parent-ds-ttl <duration>;
parent-propagation-delay <duration>;
parent-registration-delay <duration>; // obsolete
keys { ( csk | ksk | zsk ) [ ( key-directory ) ] lifetime
<duration_or_unlimited> algorithm <string> [ <integer> ]; ... };
max-zone-ttl <duration>;
- nsec3param [ iterations <integer> ] [ optout <boolean> ] [ salt
- <string> ];
+ nsec3param [ iterations <integer> ] [ optout <boolean> ] [
+ salt-length <integer> ];
parent-ds-ttl <duration>;
parent-propagation-delay <duration>;
publish-safety <duration>;
};
struct dns_kasp_nsec3param {
- unsigned char salt[255];
- uint8_t saltlen;
- uint8_t algorithm;
- uint8_t iterations;
- bool optout;
+ uint8_t saltlen;
+ uint8_t algorithm;
+ uint8_t iterations;
+ bool optout;
};
/* Stores a DNSSEC policy */
*
*/
-unsigned char *
-dns_kasp_nsec3salt(dns_kasp_t *kasp);
-/*%<
- * The NSEC3 salt used.
- *
- * Requires:
- *
- *\li 'kasp' is a valid, frozen kasp.
- *\li 'kasp->nsec3' is true.
- *
- */
-
void
dns_kasp_setnsec3(dns_kasp_t *kasp, bool nsec3);
/*%<
*
*/
-isc_result_t
+void
dns_kasp_setnsec3param(dns_kasp_t *kasp, uint8_t iter, bool optout,
- const char *salt);
+ uint8_t saltlen);
/*%<
* Set the desired NSEC3 parameters.
*
*\li 'kasp' is a valid, unfrozen kasp.
*\li 'kasp->nsec3' is true.
*
- * Returns:
- *
- *\li ISC_R_SUCCESS, if NSEC3 parameters are set.
- *\li Error, if isc_hex_decodestring() fails.
- *
*/
ISC_LANG_ENDDECLS
#define DNS_R_TOOMANYKEYS (ISC_RESULTCLASS_DNS + 121)
#define DNS_R_KEYNOTACTIVE (ISC_RESULTCLASS_DNS + 122)
#define DNS_R_NSEC3ITERRANGE (ISC_RESULTCLASS_DNS + 123)
-#define DNS_R_NSEC3BADSALT (ISC_RESULTCLASS_DNS + 124)
+#define DNS_R_NSEC3SALTRANGE (ISC_RESULTCLASS_DNS + 124)
#define DNS_R_NSEC3BADALG (ISC_RESULTCLASS_DNS + 125)
#define DNS_R_NRESULTS 126 /*%< Number of results */
isc_result_t
dns_zone_keydone(dns_zone_t *zone, const char *data);
+isc_result_t
+dns_zone_checknsec3param(dns_zone_t *zone, uint8_t hash, uint8_t flags,
+ uint16_t iter, uint8_t saltlen, unsigned char *salt);
+/*%
+ * Check if the NSEC3 parameters for the zone match the requested parameters.
+ *
+ * If 'salt' is NULL, a match is found if the salt has the requested length,
+ * otherwise the NSEC3 salt must match the requested salt value too.
+ *
+ * Requires:
+ * \li 'zone' to be valid.
+ *
+ * Returns:
+ * \li ISC_R_SUCCESS, if a match is found.
+ * \li Error, if no match is found, or if the db lookup failed.
+ */
+
isc_result_t
dns_zone_setnsec3param(dns_zone_t *zone, uint8_t hash, uint8_t flags,
uint16_t iter, uint8_t saltlen, unsigned char *salt,
return (kasp->nsec3param.saltlen);
}
-unsigned char *
-dns_kasp_nsec3salt(dns_kasp_t *kasp) {
- REQUIRE(kasp != NULL);
- REQUIRE(kasp->frozen);
- REQUIRE(kasp->nsec3);
-
- return kasp->nsec3param.salt;
-}
-
bool
dns_kasp_nsec3(dns_kasp_t *kasp) {
REQUIRE(kasp != NULL);
kasp->nsec3 = nsec3;
}
-isc_result_t
+void
dns_kasp_setnsec3param(dns_kasp_t *kasp, uint8_t iter, bool optout,
- const char *salt) {
- isc_buffer_t buf;
- isc_result_t ret = ISC_R_SUCCESS;
-
+ uint8_t saltlen) {
REQUIRE(kasp != NULL);
REQUIRE(!kasp->frozen);
REQUIRE(kasp->nsec3);
kasp->nsec3param.iterations = iter;
kasp->nsec3param.optout = optout;
- kasp->nsec3param.saltlen = 0;
-
- if (salt != NULL && strcmp(salt, "-") != 0) {
- isc_buffer_init(&buf, kasp->nsec3param.salt,
- sizeof(kasp->nsec3param.salt));
- ret = isc_hex_decodestring(salt, &buf);
- if (ret == ISC_R_SUCCESS) {
- kasp->nsec3param.saltlen = isc_buffer_usedlength(&buf);
- }
- }
- return (ret);
+ kasp->nsec3param.saltlen = saltlen;
}
"key is not actively signing", /*%< 122 DNS_R_KEYNOTACTIVE */
"NSEC3 iterations out of range", /*%< 123 DNS_R_NSEC3ITERRANGE */
- "bad NSEC3 salt", /*%< 124 DNS_R_NSEC3BADSALT */
+ "NSEC3 salt length too high", /*%< 124 DNS_R_NSEC3SALTRANGE */
"cannot use NSEC3 with key algorithm", /*%< 125 DNS_R_NSEC3BADALG */
};
"DNS_R_TOOMANYKEYS",
"DNS_R_KEYNOTACTIVE",
"DNS_R_NSEC3ITERRANGE",
- "DNS_R_NSEC3BADSALT",
+ "DNS_R_NSEC3SALTRANGE",
"DNS_R_NSEC3BADALG",
};
dns_kasp_nsec3
dns_kasp_nsec3flags
dns_kasp_nsec3iter
-dns_kasp_nsec3salt
dns_kasp_nsec3saltlen
dns_kasp_parentpropagationdelay
dns_kasp_publishsafety
dns_zone_catz_enable_db
dns_zone_cdscheck
dns_zone_checknames
+dns_zone_checknsec3param
dns_zone_clearforwardacl
dns_zone_clearnotifyacl
dns_zone_clearqueryacl
INSIST(newver == NULL);
}
+/*
+ * Check if zone has NSEC3PARAM (and thus a chain) with the right parameters.
+ */
+isc_result_t
+dns_zone_checknsec3param(dns_zone_t *zone, uint8_t hash, uint8_t flags,
+ uint16_t iter, uint8_t saltlen, unsigned char *salt) {
+ isc_result_t result = ISC_R_UNEXPECTED;
+ dns_dbnode_t *node = NULL;
+ dns_db_t *db = NULL;
+ dns_dbversion_t *version = NULL;
+ dns_rdataset_t rdataset;
+ dns_rdata_nsec3param_t nsec3param;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+ UNUSED(flags);
+
+ dns_rdataset_init(&rdataset);
+
+ ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
+ if (zone->db != NULL) {
+ dns_db_attach(zone->db, &db);
+ }
+ ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
+ if (db == NULL) {
+ goto cleanup;
+ }
+
+ result = dns_db_findnode(db, &zone->origin, false, &node);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "nsec3param lookup failure: %s",
+ dns_result_totext(result));
+ goto cleanup;
+ }
+ dns_db_currentversion(db, &version);
+
+ result = dns_db_findrdataset(db, node, version,
+ dns_rdatatype_nsec3param,
+ dns_rdatatype_none, 0, &rdataset, NULL);
+ if (result != ISC_R_SUCCESS) {
+ INSIST(!dns_rdataset_isassociated(&rdataset));
+ if (result != ISC_R_NOTFOUND) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "nsec3param lookup failure: %s",
+ dns_result_totext(result));
+ }
+ goto cleanup;
+ }
+
+ for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&rdataset))
+ {
+ dns_rdataset_current(&rdataset, &rdata);
+ result = dns_rdata_tostruct(&rdata, &nsec3param, NULL);
+ INSIST(result == ISC_R_SUCCESS);
+ dns_rdata_reset(&rdata);
+ if (nsec3param.hash != hash) {
+ continue;
+ }
+ if (nsec3param.iterations != iter) {
+ continue;
+ }
+ if (nsec3param.salt_length != saltlen) {
+ continue;
+ }
+ if (salt != NULL) {
+ if (memcmp(nsec3param.salt, salt, saltlen) != 0) {
+ continue;
+ }
+ }
+ /* Found a match. */
+ result = ISC_R_SUCCESS;
+ goto cleanup;
+ }
+ INSIST(result != ISC_R_SUCCESS);
+
+cleanup:
+ if (dns_rdataset_isassociated(&rdataset)) {
+ dns_rdataset_disassociate(&rdataset);
+ }
+ if (node != NULL) {
+ dns_db_detachnode(db, &node);
+ }
+ if (version != NULL) {
+ dns_db_closeversion(db, &version, false);
+ }
+ if (db != NULL) {
+ dns_db_detach(&db);
+ }
+
+ return (result);
+}
+
/*
* Called when an "rndc signing -nsec3param ..." command is received.
*
#include <isccfg/kaspconf.h>
#include <isccfg/namedconf.h>
-#define DEFAULT_NSEC3PARAM_ITER 5
+#define DEFAULT_NSEC3PARAM_ITER 5
+#define DEFAULT_NSEC3PARAM_SALTLEN 8
/*
* Utility function for getting a configuration option.
dns_kasp_key_t *kkey;
unsigned int min_keysize = 4096;
const cfg_obj_t *obj = NULL;
- const char *salt = NULL;
uint32_t iter = DEFAULT_NSEC3PARAM_ITER;
+ uint32_t saltlen = DEFAULT_NSEC3PARAM_SALTLEN;
uint32_t badalg = 0;
bool optout = false;
isc_result_t ret = ISC_R_SUCCESS;
}
/* Salt */
- obj = cfg_tuple_get(config, "salt");
- if (cfg_obj_isstring(obj)) {
- salt = cfg_obj_asstring(obj);
+ obj = cfg_tuple_get(config, "salt-length");
+ if (cfg_obj_isuint32(obj)) {
+ saltlen = cfg_obj_asuint32(obj);
}
-
- ret = dns_kasp_setnsec3param(kasp, iter, optout, salt);
- if (ret != ISC_R_SUCCESS) {
+ if (saltlen > 0xff) {
cfg_obj_log(obj, logctx, ISC_LOG_ERROR,
- "dnssec-policy: bad nsec3 salt %s", salt);
+ "dnssec-policy: nsec3 salt length %u too high",
+ saltlen);
+ return (DNS_R_NSEC3SALTRANGE);
}
- return (ret);
+
+ dns_kasp_setnsec3param(kasp, iter, optout, saltlen);
+ return (ISC_R_SUCCESS);
}
isc_result_t
&cfg_rep_boolean, &nsec3optout_kw
};
-static keyword_type_t nsec3salt_kw = { "salt", &cfg_type_sstring };
+static keyword_type_t nsec3salt_kw = { "salt-length", &cfg_type_uint32 };
static cfg_type_t cfg_type_nsec3salt = {
- "salt", parse_optional_keyvalue,
- print_keyvalue, doc_optional_keyvalue,
- &cfg_rep_string, &nsec3salt_kw
+ "salt-length", parse_optional_keyvalue, print_keyvalue,
+ doc_optional_keyvalue, &cfg_rep_uint32, &nsec3salt_kw
};
static cfg_tuplefielddef_t nsec3param_fields[] = {
{ "iterations", &cfg_type_nsec3iter, 0 },
{ "optout", &cfg_type_nsec3optout, 0 },
- { "salt", &cfg_type_nsec3salt, 0 },
+ { "salt-length", &cfg_type_nsec3salt, 0 },
{ NULL, NULL, 0 }
};