diff --git a/CHANGES b/CHANGES
index fac1565025..a17ba33d5c 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,7 @@
+5366. [bug] Fix a race condition with the keymgr when the same
+ zone plus dnssec-policy is configured in multiple
+ views. [GL #1653]
+
5365. [bug] Algorithm rollover was stuck on submitting DS
because keymgr thought it would move to an invalid
state. Fixed by when checking the current key,
diff --git a/bin/tests/system/kasp/ns4/example1.db.in b/bin/tests/system/kasp/ns4/example1.db.in
new file mode 100644
index 0000000000..ea4a911f07
--- /dev/null
+++ b/bin/tests/system/kasp/ns4/example1.db.in
@@ -0,0 +1,22 @@
+; 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 http://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300
+@ IN SOA mname1. . (
+ 1 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+
+ NS ns4
+ns4 A 10.53.0.4
+
+view TXT "view1"
diff --git a/bin/tests/system/kasp/ns4/example2.db.in b/bin/tests/system/kasp/ns4/example2.db.in
new file mode 100644
index 0000000000..90004d3391
--- /dev/null
+++ b/bin/tests/system/kasp/ns4/example2.db.in
@@ -0,0 +1,22 @@
+; 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 http://mozilla.org/MPL/2.0/.
+;
+; See the COPYRIGHT file distributed with this work for additional
+; information regarding copyright ownership.
+
+$TTL 300
+@ IN SOA mname1. . (
+ 1 ; serial
+ 20 ; refresh (20 seconds)
+ 20 ; retry (20 seconds)
+ 1814400 ; expire (3 weeks)
+ 3600 ; minimum (1 hour)
+ )
+
+ NS ns4
+ns4 A 10.53.0.4
+
+view TXT "view2"
diff --git a/bin/tests/system/kasp/ns4/named.conf.in b/bin/tests/system/kasp/ns4/named.conf.in
index c8d4094f85..8d209aef63 100644
--- a/bin/tests/system/kasp/ns4/named.conf.in
+++ b/bin/tests/system/kasp/ns4/named.conf.in
@@ -26,6 +26,16 @@ key "sha256" {
secret "R16NojROxtxH/xbDl//ehDsHm5DjWTQ2YXV+hGC2iBY=";
};
+key "keyforview1" {
+ algorithm "hmac-sha1";
+ secret "YPfMoAk6h+3iN8MDRQC004iSNHY=";
+};
+
+key "keyforview2" {
+ algorithm "hmac-sha1";
+ secret "4xILSZQnuO1UKubXHkYUsvBRPu8=";
+};
+
dnssec-policy "test" {
keys {
csk key-directory lifetime 0 algorithm 14;
@@ -115,3 +125,21 @@ view "none" {
file "none.none.signed.db";
};
};
+
+view "example1" {
+ match-clients { key "keyforview1"; };
+
+ zone "example.net" {
+ type master;
+ file "example1.db";
+ };
+};
+
+view "example2" {
+ match-clients { key "keyforview2"; };
+
+ zone "example.net" {
+ type master;
+ file "example2.db";
+ };
+};
diff --git a/bin/tests/system/kasp/ns4/setup.sh b/bin/tests/system/kasp/ns4/setup.sh
index ca830dd028..4b02fd3fa0 100644
--- a/bin/tests/system/kasp/ns4/setup.sh
+++ b/bin/tests/system/kasp/ns4/setup.sh
@@ -26,3 +26,6 @@ do
zonefile="${zone}.db"
cp template.db.in $zonefile
done
+
+cp example1.db.in example1.db
+cp example2.db.in example2.db
diff --git a/bin/tests/system/kasp/tests.sh b/bin/tests/system/kasp/tests.sh
index 30b82679a3..24bd5f21ef 100644
--- a/bin/tests/system/kasp/tests.sh
+++ b/bin/tests/system/kasp/tests.sh
@@ -28,6 +28,8 @@ TSIG=""
SHA1="FrSt77yPTFx6hTs4i2tKLB9LmE0="
SHA224="hXfwwwiag2QGqblopofai9NuW28q/1rH4CaTnA=="
SHA256="R16NojROxtxH/xbDl//ehDsHm5DjWTQ2YXV+hGC2iBY="
+VIEW1="YPfMoAk6h+3iN8MDRQC004iSNHY="
+VIEW2="4xILSZQnuO1UKubXHkYUsvBRPu8="
###############################################################################
# Key properties #
@@ -1799,6 +1801,7 @@ dnssec_verify
# ns4/override.none.signed
# ns5/override.override.unsigned
# ns5/override.none.unsigned
+# ns4/example.net (both views)
set_keyrole "KEY1" "csk"
set_keylifetime "KEY1" "0"
set_keyalgorithm "KEY1" "14" "ECDSAP384SHA384" "384"
@@ -1850,6 +1853,39 @@ check_apex
check_subdomain
dnssec_verify
+set_keydir "ns4"
+set_zone "example.net"
+set_server "ns4" "10.53.0.4"
+TSIG="hmac-sha1:keyforview1:$VIEW1"
+check_keys
+check_apex
+dnssec_verify
+n=$((n+1))
+# check subdomain
+echo_i "check TXT example.net (view example1) rrset is signed correctly ($n)"
+ret=0
+dig_with_opts "view.${ZONE}" "@${SERVER}" TXT > "dig.out.$DIR.test$n.txt" || log_error "dig view.${ZONE} TXT failed"
+grep "status: NOERROR" "dig.out.$DIR.test$n.txt" > /dev/null || log_error "mismatch status in DNS response"
+grep "view.${ZONE}\..*${DEFAULT_TTL}.*IN.*TXT.*view1" "dig.out.$DIR.test$n.txt" > /dev/null || log_error "missing view.${ZONE} TXT record in response"
+check_signatures TXT "dig.out.$DIR.test$n.txt" "ZSK"
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
+TSIG="hmac-sha1:keyforview2:$VIEW2"
+check_keys
+check_apex
+dnssec_verify
+n=$((n+1))
+# check subdomain
+echo_i "check TXT example.net (view example2) rrset is signed correctly ($n)"
+ret=0
+dig_with_opts "view.${ZONE}" "@${SERVER}" TXT > "dig.out.$DIR.test$n.txt" || log_error "dig view.${ZONE} TXT failed"
+grep "status: NOERROR" "dig.out.$DIR.test$n.txt" > /dev/null || log_error "mismatch status in DNS response"
+grep "view.${ZONE}\..*${DEFAULT_TTL}.*IN.*TXT.*view2" "dig.out.$DIR.test$n.txt" > /dev/null || log_error "missing view.${ZONE} TXT record in response"
+check_signatures TXT "dig.out.$DIR.test$n.txt" "ZSK"
+test "$ret" -eq 0 || echo_i "failed"
+status=$((status+ret))
+
# Clear TSIG.
TSIG=""
diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml
index a006816a29..108732fb27 100644
--- a/doc/arm/Bv9ARM-book.xml
+++ b/doc/arm/Bv9ARM-book.xml
@@ -11132,6 +11132,13 @@ example.com CNAME rpz-tcp-only.
roll, which cryptographic algorithms to use, and how often RRSIG
records need to be refreshed.
+
+ Keys are not shared among zones, which means that one set of keys
+ per zone will be generated even if they have the same policy.
+ If multiple views are configured with different versions of the
+ same zone, each separate version will use the same set of signing
+ keys.
+
Multiple key and signing policies can be configured. To
attach a policy to a zone, add a dnssec-policy
diff --git a/lib/dns/kasp.c b/lib/dns/kasp.c
index 1d9bbb27f4..69c069e5f7 100644
--- a/lib/dns/kasp.c
+++ b/lib/dns/kasp.c
@@ -90,6 +90,7 @@ destroy(dns_kasp_t *kasp) {
}
INSIST(ISC_LIST_EMPTY(kasp->keys));
+ isc_mutex_destroy(&kasp->lock);
isc_mem_free(kasp->mctx, kasp->name);
isc_mem_putanddetach(&kasp->mctx, kasp, sizeof(*kasp));
}
diff --git a/lib/dns/zone.c b/lib/dns/zone.c
index ff02549c78..04f4b8e74b 100644
--- a/lib/dns/zone.c
+++ b/lib/dns/zone.c
@@ -7279,6 +7279,7 @@ signed_with_good_key(dns_zone_t *zone, dns_db_t *db, dns_dbnode_t *node,
int zsk_count = 0;
bool approved;
+ LOCK(&kasp->lock);
for (kkey = ISC_LIST_HEAD(dns_kasp_keys(kasp)); kkey != NULL;
kkey = ISC_LIST_NEXT(kkey, link))
{
@@ -7289,6 +7290,7 @@ signed_with_good_key(dns_zone_t *zone, dns_db_t *db, dns_dbnode_t *node,
zsk_count++;
}
}
+ UNLOCK(&kasp->lock);
if (type == dns_rdatatype_dnskey ||
type == dns_rdatatype_cdnskey || type == dns_rdatatype_cds)
@@ -19423,6 +19425,10 @@ zone_rekey(dns_zone_t *zone) {
kasp = dns_zone_getkasp(zone);
fullsign = DNS_ZONEKEY_OPTION(zone, DNS_ZONEKEY_FULLSIGN);
+ if (kasp != NULL) {
+ LOCK(&kasp->lock);
+ }
+
result = dns_dnssec_findmatchingkeys(&zone->origin, dir, now, mctx,
&keys);
if (result != ISC_R_SUCCESS) {
@@ -19431,9 +19437,9 @@ zone_rekey(dns_zone_t *zone) {
isc_result_totext(result));
}
- if (kasp && (result == ISC_R_SUCCESS || result == ISC_R_NOTFOUND)) {
+ if (kasp != NULL &&
+ (result == ISC_R_SUCCESS || result == ISC_R_NOTFOUND)) {
ttl = dns_kasp_dnskeyttl(kasp);
-
result = dns_keymgr_run(&zone->origin, zone->rdclass, dir, mctx,
&keys, kasp, now, &nexttime);
if (result != ISC_R_SUCCESS) {
@@ -19444,6 +19450,10 @@ zone_rekey(dns_zone_t *zone) {
}
}
+ if (kasp != NULL) {
+ UNLOCK(&kasp->lock);
+ }
+
if (result == ISC_R_SUCCESS) {
result = dns_dnssec_updatekeys(&dnskeys, &keys, &rmkeys,
&zone->origin, ttl, &diff, mctx,