if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
+echo_i "checking for out-of-zone NSEC3 records after ZSK removal ($n)"
+ret=0
+# Switch the zone over to NSEC3 and wait until the transition is complete.
+$RNDCCMD 10.53.0.3 signing -nsec3param 1 1 10 12345678 delzsk.example. > signing.out.1.test$n 2>&1 || ret=1
+for i in 0 1 2 3 4 5 6 7 8 9; do
+ _ret=1
+ $DIG $DIGOPTS delzsk.example NSEC3PARAM @10.53.0.3 > dig.out.ns3.1.test$n 2>&1 || ret=1
+ grep "NSEC3PARAM.*12345678" dig.out.ns3.1.test$n > /dev/null 2>&1
+ if [ $? -eq 0 ]; then
+ _ret=0
+ break
+ fi
+ sleep 1
+done
+if [ $_ret -ne 0 ]; then
+ echo_i "timed out waiting for NSEC3 chain creation"
+ ret=1
+fi
+# Mark the inactive ZSK as pending removal.
+file="ns3/`cat delzsk.key`.key"
+$SETTIME -D now-1h $file > settime.out.test$n 2>&1 || ret=1
+# Trigger removal of the inactive ZSK and wait until its completion.
+$RNDCCMD 10.53.0.3 loadkeys delzsk.example 2>&1 | sed 's/^/ns3 /' | cat_i
+for i in 0 1 2 3 4 5 6 7 8 9; do
+ _ret=1
+ $RNDCCMD 10.53.0.3 signing -list delzsk.example > signing.out.2.test$n 2>&1
+ grep "Signing " signing.out.2.test$n > /dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ if [ `cat signing.out.2.test$n | wc -l` -eq 2 ]; then
+ _ret=0
+ break
+ fi
+ fi
+ sleep 1
+done
+if [ $_ret -ne 0 ]; then
+ echo_i "timed out waiting for key removal"
+ ret=1
+fi
+# Check whether key removal caused NSEC3 records to be erroneously created for
+# glue records due to a secure delegation already being signed by the active key
+# (i.e. a key other than the one being removed but using the same algorithm).
+#
+# For reference:
+#
+# $ nsec3hash 12345678 1 10 ns.sub.delzsk.example.
+# 589R358VSPJUFVAJU949JPVF74D9PTGH (salt=12345678, hash=1, iterations=10)
+#
+$DIG $DIGOPTS delzsk.example AXFR @10.53.0.3 > dig.out.ns3.3.test$n || ret=1
+grep "589R358VSPJUFVAJU949JPVF74D9PTGH" dig.out.ns3.3.test$n > /dev/null 2>&1 && ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo_i "failed"; fi
+status=`expr $status + $ret`
+
echo_i "exit status: $status"
[ $status -eq 0 ] || exit 1
return (result);
}
+static isc_result_t
+check_if_bottom_of_zone(dns_db_t *db, dns_dbnode_t *node,
+ dns_dbversion_t *version, bool *is_bottom_of_zone)
+{
+ isc_result_t result;
+ dns_rdatasetiter_t *iterator = NULL;
+ dns_rdataset_t rdataset;
+ bool seen_soa = false, seen_ns = false, seen_dname = false;
+
+ REQUIRE(is_bottom_of_zone != NULL);
+
+ result = dns_db_allrdatasets(db, node, version, 0, &iterator);
+ if (result != ISC_R_SUCCESS) {
+ if (result == ISC_R_NOTFOUND) {
+ result = ISC_R_SUCCESS;
+ }
+ return (result);
+ }
+
+ dns_rdataset_init(&rdataset);
+ for (result = dns_rdatasetiter_first(iterator);
+ result == ISC_R_SUCCESS;
+ result = dns_rdatasetiter_next(iterator)) {
+ dns_rdatasetiter_current(iterator, &rdataset);
+ switch (rdataset.type) {
+ case dns_rdatatype_soa:
+ seen_soa = true;
+ break;
+ case dns_rdatatype_ns:
+ seen_ns = true;
+ break;
+ case dns_rdatatype_dname:
+ seen_dname = true;
+ break;
+ }
+ dns_rdataset_disassociate(&rdataset);
+ }
+ if (result != ISC_R_NOMORE) {
+ goto failure;
+ }
+ if ((seen_ns && !seen_soa) || seen_dname) {
+ *is_bottom_of_zone = true;
+ }
+ result = ISC_R_SUCCESS;
+
+ failure:
+ dns_rdatasetiter_destroy(&iterator);
+
+ return (result);
+}
+
static isc_result_t
sign_a_node(dns_db_t *db, dns_name_t *name, dns_dbnode_t *node,
dns_dbversion_t *version, bool build_nsec3,
bool build_nsec, dst_key_t *key,
isc_stdtime_t inception, isc_stdtime_t expire,
unsigned int minimum, bool is_ksk,
- bool keyset_kskonly, bool *delegation,
+ bool keyset_kskonly, bool is_bottom_of_zone,
dns_diff_t *diff, int32_t *signatures, isc_mem_t *mctx)
{
isc_result_t result;
unsigned char data[1024];
bool seen_soa, seen_ns, seen_rr, seen_dname, seen_nsec,
seen_nsec3, seen_ds;
- bool bottom;
result = dns_db_allrdatasets(db, node, version, 0, &iterator);
if (result != ISC_R_SUCCESS) {
}
if (result != ISC_R_NOMORE)
goto failure;
- if (seen_ns && !seen_soa)
- *delegation = true;
/*
* Going from insecure to NSEC3.
* Don't generate NSEC3 records for NSEC3 records.
* Don't generate NSEC records for NSEC3 records.
*/
if (build_nsec && !seen_nsec3 && !seen_nsec && seen_rr) {
- /* Build and add NSEC. */
- bottom = (seen_ns && !seen_soa) || seen_dname;
/*
* Build a NSEC record except at the origin.
*/
if (!dns_name_equal(name, dns_db_origin(db))) {
CHECK(add_nsec(db, version, name, node, minimum,
- bottom, diff));
+ is_bottom_of_zone, diff));
/* Count a NSEC generation as a signature generation. */
(*signatures)--;
}
} else if (is_ksk) {
goto next_rdataset;
}
- if (*delegation &&
+ if (seen_ns && !seen_soa &&
rdataset.type != dns_rdatatype_ds &&
rdataset.type != dns_rdatatype_nsec)
{
}
if (result == ISC_R_NOMORE)
result = ISC_R_SUCCESS;
- if (seen_dname)
- *delegation = true;
failure:
if (dns_rdataset_isassociated(&rdataset))
dns_rdataset_disassociate(&rdataset);
bool check_ksk, keyset_kskonly, is_ksk;
bool with_ksk, with_zsk;
bool commit = false;
- bool delegation;
+ bool is_bottom_of_zone;
bool build_nsec = false;
bool build_nsec3 = false;
bool first;
if (signing->db != db)
goto next_signing;
- delegation = false;
+ is_bottom_of_zone = false;
if (first && signing->deleteit) {
/*
* we skip all obscured names.
*/
dns_name_copy(found, name, NULL);
- delegation = true;
+ is_bottom_of_zone = true;
goto next_node;
}
}
with_ksk = false;
with_zsk = false;
dns_dbiterator_pause(signing->dbiterator);
+
+ CHECK(check_if_bottom_of_zone(db, node, version,
+ &is_bottom_of_zone));
+
for (i = 0; !has_alg && i < nkeys; i++) {
bool both = false;
build_nsec, zone_keys[i], inception,
expire, zone->minimum, is_ksk,
(both && keyset_kskonly),
- &delegation, zonediff.diff,
+ is_bottom_of_zone, zonediff.diff,
&signatures, zone->mctx));
/*
* If we are adding we are done. Look for other keys
"zone_sign:dns_dbiterator_next -> %s",
dns_result_totext(result));
goto failure;
- } else if (delegation) {
+ } else if (is_bottom_of_zone) {
dns_dbiterator_current(signing->dbiterator,
&node, nextname);
dns_db_detachnode(db, &node);