diff --git a/CHANGES b/CHANGES
index c3cd92603c..bced985a9c 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,7 @@
+3686. [func] "dnssec-signzone -Q" drops signatures from keys
+ that are still published but no longer active.
+ [RT #34990]
+
3685. [bug] "rndc refresh" didn't work correctly with slave
zones using inline-signing. [RT #35105]
diff --git a/bin/dnssec/dnssec-signzone.c b/bin/dnssec/dnssec-signzone.c
index 5a2e25417f..3826c07a98 100644
--- a/bin/dnssec/dnssec-signzone.c
+++ b/bin/dnssec/dnssec-signzone.c
@@ -175,7 +175,8 @@ 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;
-static isc_boolean_t remove_orphans = ISC_FALSE;
+static isc_boolean_t remove_orphansigs = ISC_FALSE;
+static isc_boolean_t remove_inactkeysigs = ISC_FALSE;
static isc_boolean_t output_dnssec_only = ISC_FALSE;
static isc_boolean_t output_stdout = ISC_FALSE;
@@ -554,9 +555,14 @@ signset(dns_diff_t *del, dns_diff_t *add, dns_dbnode_t *node, dns_name_t *name,
"private dnskey not found\n",
sigstr);
} else if (key == NULL || future) {
- keep = (!expired && !remove_orphans);
+ keep = (!expired && !remove_orphansigs);
vbprintf(2, "\trrsig by %s %s - dnskey not found\n",
keep ? "retained" : "dropped", sigstr);
+ } else if (!dns_dnssec_keyactive(key->key, now) &&
+ remove_inactkeysigs) {
+ keep = ISC_FALSE;
+ vbprintf(2, "\trrsig by %s dropped - key inactive\n",
+ sigstr);
} else if (issigningkey(key)) {
wassignedby[key->index] = ISC_TRUE;
@@ -571,7 +577,7 @@ signset(dns_diff_t *del, dns_diff_t *add, dns_dbnode_t *node, dns_name_t *name,
"ttl change" : "failed to verify");
resign = ISC_TRUE;
}
- } else if (!ispublishedkey(key) && remove_orphans) {
+ } else if (!ispublishedkey(key) && remove_orphansigs) {
vbprintf(2, "\trrsig by %s dropped - dnskey removed\n",
sigstr);
} else if (iszonekey(key)) {
@@ -2949,6 +2955,9 @@ usage(void) {
fprintf(stderr, "use pseudorandom data (faster but less secure)\n");
fprintf(stderr, "\t-P:\t");
fprintf(stderr, "disable post-sign verification\n");
+ fprintf(stderr, "\t-Q:\t");
+ fprintf(stderr, "remove signatures from keys that are no "
+ "longer active\n");
fprintf(stderr, "\t-R:\t");
fprintf(stderr, "remove signatures from keys that no longer exist\n");
fprintf(stderr, "\t-T TTL:\tTTL for newly added DNSKEYs\n");
@@ -3049,11 +3058,12 @@ main(int argc, char *argv[]) {
isc_boolean_t make_keyset = ISC_FALSE;
isc_boolean_t set_salt = ISC_FALSE;
isc_boolean_t set_optout = ISC_FALSE;
- isc_boolean_t set_iter = ISC_FALSE;
+ isc_boolean_t set_iter = ISC_FALSE;
isc_boolean_t nonsecify = ISC_FALSE;
+ /* Unused letters: Bb G J M q Yy (and F is reserved). */
#define CMDLINE_FLAGS \
- "3:AaCc:Dd:E:e:f:FghH:i:I:j:K:k:L:l:m:n:N:o:O:PpRr:s:ST:tuUv:X:xzZ:"
+ "3:AaCc:Dd:E:e:f:FghH:i:I:j:K:k:L:l:m:n:N:o:O:PpQRr:s:ST:tuUv:X:xzZ:"
/*
* Process memory debugging argument first.
@@ -3256,8 +3266,12 @@ main(int argc, char *argv[]) {
pseudorandom = ISC_TRUE;
break;
+ case 'Q':
+ remove_inactkeysigs = ISC_TRUE;
+ break;
+
case 'R':
- remove_orphans = ISC_TRUE;
+ remove_orphansigs = ISC_TRUE;
break;
case 'r':
@@ -3343,8 +3357,7 @@ main(int argc, char *argv[]) {
result = dst_lib_init2(mctx, ectx, engine, eflags);
if (result != ISC_R_SUCCESS)
fatal("could not initialize dst: %s",
- isc_result_totext(result));
-
+ isc_result_totext(result));
isc_stdtime_get(&now);
if (startstr != NULL) {
diff --git a/bin/dnssec/dnssec-signzone.docbook b/bin/dnssec/dnssec-signzone.docbook
index 3769968549..a1adafd042 100644
--- a/bin/dnssec/dnssec-signzone.docbook
+++ b/bin/dnssec/dnssec-signzone.docbook
@@ -490,10 +490,10 @@
- -R
+ -Q
- Remove signatures from keys that no longer exist.
+ Remove signatures from keys that are no longer active.
Normally, when a previously-signed zone is passed as input
@@ -501,9 +501,26 @@
replaced with a new one, signatures from the old key
that are still within their validity period are retained.
This allows the zone to continue to validate with cached
- copies of the old DNSKEY RRset. The forces
- dnssec-signzone to remove all orphaned
- signatures.
+ copies of the old DNSKEY RRset. The
+ forces dnssec-signzone to remove
+ signatures from keys that are no longer active. This
+ enables ZSK rollover using the procedure described in
+ RFC 4641, section 4.2.1.1 ("Pre-Publish Key Rollover").
+
+
+
+
+ -R
+
+
+ Remove signatures from keys that are no longer published.
+
+
+ This option is similar to , except it
+ forces dnssec-signzone to signatures from
+ keys that are no longer published. This enables ZSK rollover
+ using the procedure described in RFC 4641, section 4.2.1.2
+ ("Double Signature Zone Signing Key Rollover").
@@ -766,7 +783,7 @@ db.example.com.signed
dnssec-keygen8
,
BIND 9 Administrator Reference Manual,
- RFC 4033.
+ RFC 4033, RFC 4641.
diff --git a/bin/tests/system/dnssec/tests.sh b/bin/tests/system/dnssec/tests.sh
index 2553ad8bad..0336ea98d7 100644
--- a/bin/tests/system/dnssec/tests.sh
+++ b/bin/tests/system/dnssec/tests.sh
@@ -1366,6 +1366,36 @@ n=`expr $n + 1`
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
+echo "I:checking dnssec-signzone keeps valid signatures from inactive keys ($n)"
+ret=0
+zone=example
+(
+cd signer
+cp -f example.db.in example.db
+$SIGNER -SD -o example example.db > /dev/null 2>&1
+echo '$INCLUDE "example.db.signed"' >> example.db
+# now retire key2 and resign the zone
+$SETTIME -I now $key2 > /dev/null 2>&1
+$SIGNER -SD -o example example.db > /dev/null 2>&1
+) || ret=1
+grep " $keyid2 " signer/example.db.signed > /dev/null 2>&1 || ret=1
+grep " $keyid3 " signer/example.db.signed > /dev/null 2>&1 || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+echo "I:checking dnssec-signzone -R purges signatures from inactive keys ($n)"
+ret=0
+(
+cd signer
+$SIGNER -SDQ -o example example.db > /dev/null 2>&1
+) || ret=1
+grep " $keyid2 " signer/example.db.signed > /dev/null 2>&1 && ret=1
+grep " $keyid3 " signer/example.db.signed > /dev/null 2>&1 || ret=1
+n=`expr $n + 1`
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
echo "I:checking dnssec-signzone retains unexpired signatures ($n)"
ret=0
(
diff --git a/lib/dns/dnssec.c b/lib/dns/dnssec.c
index cf9740406a..2a4ab4f6cf 100644
--- a/lib/dns/dnssec.c
+++ b/lib/dns/dnssec.c
@@ -609,8 +609,8 @@ dns_dnssec_verify(dns_name_t *name, dns_rdataset_t *set, dst_key_t *key,
return (result);
}
-static isc_boolean_t
-key_active(dst_key_t *key, isc_stdtime_t now) {
+isc_boolean_t
+dns_dnssec_keyactive(dst_key_t *key, isc_stdtime_t now) {
isc_result_t result;
isc_stdtime_t publish, active, revoke, inactive, delete;
isc_boolean_t pubset = ISC_FALSE, actset = ISC_FALSE;
@@ -764,7 +764,7 @@ dns_dnssec_findzonekeys2(dns_db_t *db, dns_dbversion_t *ver,
/*
* If a key is marked inactive, skip it
*/
- if (!key_active(keys[count], now)) {
+ if (!dns_dnssec_keyactive(keys[count], now)) {
dst_key_setinactive(pubkey, ISC_TRUE);
dst_key_free(&keys[count]);
keys[count] = pubkey;
diff --git a/lib/dns/include/dns/dnssec.h b/lib/dns/include/dns/dnssec.h
index e443f91b63..0625e89c1e 100644
--- a/lib/dns/include/dns/dnssec.h
+++ b/lib/dns/include/dns/dnssec.h
@@ -174,6 +174,7 @@ dns_dnssec_findzonekeys(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node,
dns_name_t *name, isc_mem_t *mctx,
unsigned int maxkeys, dst_key_t **keys,
unsigned int *nkeys);
+
isc_result_t
dns_dnssec_findzonekeys2(dns_db_t *db, dns_dbversion_t *ver,
dns_dbnode_t *node, dns_name_t *name,
@@ -186,6 +187,20 @@ dns_dnssec_findzonekeys2(dns_db_t *db, dns_dbversion_t *ver,
*/
/*@}*/
+isc_boolean_t
+dns_dnssec_keyactive(dst_key_t *key, isc_stdtime_t now);
+/*%<
+ *
+ * Returns ISC_TRUE if 'key' is active as of the time specified
+ * in 'now' (i.e., if the activation date has passed, inactivation or
+ * deletion date has not yet been reached, and the key is not revoked
+ * -- or if it is a legacy key without metadata). Otherwise returns
+ * ISC_FALSE.
+ *
+ * Requires:
+ *\li 'key' is a valid key
+ */
+
isc_result_t
dns_dnssec_signmessage(dns_message_t *msg, dst_key_t *key);
/*%<
diff --git a/lib/dns/win32/libdns.def.in b/lib/dns/win32/libdns.def.in
index 4d6f0c8ff8..ede70a5ee2 100644
--- a/lib/dns/win32/libdns.def.in
+++ b/lib/dns/win32/libdns.def.in
@@ -214,6 +214,7 @@ dns_dns64_unlink
dns_dnssec_findmatchingkeys
dns_dnssec_findzonekeys
dns_dnssec_findzonekeys2
+dns_dnssec_keyactive
dns_dnssec_keyfromrdata
dns_dnssec_keylistfromrdataset
dns_dnssec_selfsigns