diff --git a/CHANGES b/CHANGES index 0bc62636cf..df1885c0e3 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,6 @@ +3632. [bug] Signature from newly inactive keys were not being + removed. [RT #32178] + 3631. [bug] Remove spurious warning about missing signatures when qtype is SIG. [RT #34600] diff --git a/bin/dnssec/dnssectool.c b/bin/dnssec/dnssectool.c index 7c8c6ce225..dfa0711afd 100644 --- a/bin/dnssec/dnssectool.c +++ b/bin/dnssec/dnssectool.c @@ -319,11 +319,35 @@ strtotime(const char *str, isc_int64_t now, isc_int64_t base) { isc_result_t result; const char *orig = str; char *endp; + int n; if ((str[0] == '0' || str[0] == '-') && str[1] == '\0') return ((isc_stdtime_t) 0); - if (strncmp(str, "now", 3) == 0) { + /* + * We accept times in the following formats: + * now([+-]offset) + * YYYYMMDD([+-]offset) + * YYYYMMDDhhmmss([+-]offset) + * [+-]offset + */ + n = strspn(str, "0123456789"); + if ((n == 8 || n == 14) && + (str[n] == '\0' || str[n] == '-' || str[n] == '+')) + { + char timestr[15]; + + strlcpy(timestr, str, sizeof(timestr)); + timestr[n] = 0; + if (n == 8) + strlcat(timestr, "000000", sizeof(timestr)); + result = dns_time64_fromtext(timestr, &val); + if (result != ISC_R_SUCCESS) + fatal("time value %s is invalid: %s", orig, + isc_result_totext(result)); + base = val; + str += n; + } else if (strncmp(str, "now", 3) == 0) { base = now; str += 3; } @@ -338,18 +362,7 @@ strtotime(const char *str, isc_int64_t now, isc_int64_t base) { offset = strtol(str + 1, &endp, 0); offset = time_units((isc_stdtime_t) offset, endp, orig); val = base - offset; - } else if (strlen(str) == 8U) { - char timestr[15]; - sprintf(timestr, "%s000000", str); - result = dns_time64_fromtext(timestr, &val); - if (result != ISC_R_SUCCESS) - fatal("time value %s is invalid: %s", orig, - isc_result_totext(result)); - } else if (strlen(str) > 14U) { - fatal("time value %s is invalid", orig); } else { - result = dns_time64_fromtext(str, &val); - if (result != ISC_R_SUCCESS) fatal("time value %s is invalid: %s", orig, isc_result_totext(result)); } diff --git a/bin/tests/system/dnssec/clean.sh b/bin/tests/system/dnssec/clean.sh index 4e737d7336..615a8dd545 100644 --- a/bin/tests/system/dnssec/clean.sh +++ b/bin/tests/system/dnssec/clean.sh @@ -56,6 +56,7 @@ rm -f ns4/named.conf rm -f ns4/managed-keys.bind* rm -f ns3/auto-nsec.example.db ns3/auto-nsec3.example.db rm -f ns3/secure.below-cname.example.db +rm -f ns3/publish-inactive.example.db rm -f signer/example.db.after signer/example.db.before rm -f signer/example.db.changed rm -f signer/nsec3param.out diff --git a/bin/tests/system/dnssec/ns3/named.conf b/bin/tests/system/dnssec/ns3/named.conf index 6461479201..e745a7525f 100644 --- a/bin/tests/system/dnssec/ns3/named.conf +++ b/bin/tests/system/dnssec/ns3/named.conf @@ -33,6 +33,7 @@ options { notify yes; dnssec-enable yes; dnssec-validation yes; + session-keyfile "session.key"; }; key rndc_key { @@ -262,4 +263,11 @@ zone "inline.example" { auto-dnssec maintain; }; +zone "publish-inactive.example" { + type master; + file "publish-inactive.example.db"; + auto-dnssec maintain; + update-policy local; +}; + include "trusted.conf"; diff --git a/bin/tests/system/dnssec/ns3/publish-inactive.example.db.in b/bin/tests/system/dnssec/ns3/publish-inactive.example.db.in new file mode 100644 index 0000000000..16c278b1f1 --- /dev/null +++ b/bin/tests/system/dnssec/ns3/publish-inactive.example.db.in @@ -0,0 +1,31 @@ +; Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC") +; +; Permission to use, copy, modify, and/or distribute this software for any +; purpose with or without fee is hereby granted, provided that the above +; copyright notice and this permission notice appear in all copies. +; +; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH +; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, +; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +; PERFORMANCE OF THIS SOFTWARE. + +; $Id: insecure.example.db,v 1.9 2007/06/19 23:47:02 tbox Exp $ + +$TTL 300 ; 5 minutes +@ IN SOA mname1. . ( + 2000042407 ; serial + 20 ; refresh (20 seconds) + 20 ; retry (20 seconds) + 1814400 ; expire (3 weeks) + 3600 ; minimum (1 hour) + ) + NS ns +ns A 10.53.0.3 + +a A 10.0.0.1 +b A 10.0.0.2 +d A 10.0.0.4 +z A 10.0.0.26 diff --git a/bin/tests/system/dnssec/ns3/sign.sh b/bin/tests/system/dnssec/ns3/sign.sh index 36c8d30c2d..0e1764241a 100644 --- a/bin/tests/system/dnssec/ns3/sign.sh +++ b/bin/tests/system/dnssec/ns3/sign.sh @@ -437,3 +437,17 @@ $CHECKZONE -D nosign.example nosign.example.db.signed 2>&- | \ zone=inline.example. kskname=`$KEYGEN -q -3 -r $RANDFILE -fk $zone` zskname=`$KEYGEN -q -3 -r $RANDFILE $zone` + +# +# publish a new key while deactivating another key at the same time. +# +zone=publish-inactive.example +infile=publish-inactive.example.db.in +zonefile=publish-inactive.example.db +now=`date -u +%Y%m%d%H%M%S` +kskname=`$KEYGEN -q -r $RANDFILE -f KSK $zone` +kskname=`$KEYGEN -P $now+90s -A $now+3600s -q -r $RANDFILE -f KSK $zone` +kskname=`$KEYGEN -I $now+90s -q -r $RANDFILE -f KSK $zone` +zskname=`$KEYGEN -q -r $RANDFILE $zone` +cp $infile $zonefile +$SIGNER -S -r $RANDFILE -o $zone $zonefile > /dev/null 2>&1 diff --git a/bin/tests/system/dnssec/tests.sh b/bin/tests/system/dnssec/tests.sh index 40c4696759..05ba17fba3 100644 --- a/bin/tests/system/dnssec/tests.sh +++ b/bin/tests/system/dnssec/tests.sh @@ -2295,5 +2295,25 @@ n=`expr $n + 1` if [ $ret != 0 ]; then echo "I:failed"; fi status=`expr $status + $ret` +echo "I:check simultaneous inactivation and publishing of dnskeys removes inactive signature ($n)" +ret=0 +cnt=0 +while : +do +$DIG $DIGOPTS publish-inactive.example @10.53.0.3 dnskey > dig.out.ns3.test$n +keys=`awk '$5 == 257 { print; }' dig.out.ns3.test$n | wc -l` +test $keys -gt 2 && break +cnt=`expr $cnt + 1` +test $cnt -gt 120 && break +sleep 1 +done +test $keys -gt 2 || ret=1 +sigs=`grep RRSIG dig.out.ns3.test$n | wc -l` +sigs=`expr $sigs + 0` +n=`expr $n + 1` +test $sigs -eq 2 || ret=1 +if test $ret != 0 ; then echo "I:failed"; fi +status=`expr $status + $ret` + echo "I:exit status: $status" exit $status diff --git a/lib/dns/dnssec.c b/lib/dns/dnssec.c index d00c99b412..602be1847d 100644 --- a/lib/dns/dnssec.c +++ b/lib/dns/dnssec.c @@ -764,6 +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)) { + dst_key_setinactive(pubkey, ISC_TRUE); dst_key_free(&keys[count]); keys[count] = pubkey; pubkey = NULL; diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c index 79c8240078..c310be5a11 100644 --- a/lib/dns/dst_api.c +++ b/lib/dns/dst_api.c @@ -1354,10 +1354,27 @@ get_key_struct(dns_name_t *name, unsigned int alg, key->times[i] = 0; key->timeset[i] = ISC_FALSE; } + key->inactive = ISC_FALSE; key->magic = KEY_MAGIC; return (key); } +isc_boolean_t +dst_key_inactive(const dst_key_t *key) { + + REQUIRE(VALID_KEY(key)); + + return (key->inactive); +} + +void +dst_key_setinactive(dst_key_t *key, isc_boolean_t inactive) { + + REQUIRE(VALID_KEY(key)); + + key->inactive = inactive; +} + /*% * Reads a public key from disk */ diff --git a/lib/dns/dst_internal.h b/lib/dns/dst_internal.h index c3e8e29a46..9b897d113b 100644 --- a/lib/dns/dst_internal.h +++ b/lib/dns/dst_internal.h @@ -126,6 +126,8 @@ struct dst_key { isc_boolean_t timeset[DST_MAX_TIMES + 1]; /*%< data set? */ isc_stdtime_t nums[DST_MAX_NUMERIC + 1]; /*%< numeric metadata */ isc_boolean_t numset[DST_MAX_NUMERIC + 1]; /*%< data set? */ + isc_boolean_t inactive; /*%< private key not present as it is + inactive */ int fmt_major; /*%< private key format, major version */ int fmt_minor; /*%< private key format, minor version */ diff --git a/lib/dns/include/dst/dst.h b/lib/dns/include/dst/dst.h index 0cb6ec220f..49e048b13a 100644 --- a/lib/dns/include/dst/dst.h +++ b/lib/dns/include/dst/dst.h @@ -935,6 +935,23 @@ dst_key_restore(dns_name_t *name, unsigned int alg, unsigned int flags, unsigned int protocol, dns_rdataclass_t rdclass, isc_mem_t *mctx, const char *keystr, dst_key_t **keyp); +isc_boolean_t +dst_key_inactive(const dst_key_t *key); +/*%< + * Determines if the private key is missing due the key being deemed inactive. + * + * Requires: + * 'key' to be valid. + */ + +void +dst_key_setinactive(dst_key_t *key, isc_boolean_t inactive); +/*%< + * Set key inactive state. + * + * Requires: + * 'key' to be valid. + */ ISC_LANG_ENDDECLS diff --git a/lib/dns/update.c b/lib/dns/update.c index 14ffcc2234..0c4db04641 100644 --- a/lib/dns/update.c +++ b/lib/dns/update.c @@ -1211,7 +1211,9 @@ del_keysigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, for (i = 0; i < nkeys; i++) { if (rrsig.keyid == dst_key_id(keys[i])) { found = ISC_TRUE; - if (!dst_key_isprivate(keys[i])) { + if (!dst_key_isprivate(keys[i]) && + !dst_key_inactive(keys[i])) + { /* * The re-signing code in zone.c * will mark this as offline. diff --git a/lib/dns/win32/libdns.def b/lib/dns/win32/libdns.def index 18b67709fa..8b75db78b7 100644 --- a/lib/dns/win32/libdns.def +++ b/lib/dns/win32/libdns.def @@ -1062,6 +1062,7 @@ dst_key_getprivateformat dst_key_gettime dst_key_getttl dst_key_id +dst_key_inactive dst_key_isnullkey dst_key_isprivate dst_key_iszonekey @@ -1074,6 +1075,7 @@ dst_key_rid dst_key_secretsize dst_key_setbits dst_key_setflags +dst_key_setinactive dst_key_setprivateformat dst_key_settime dst_key_setttl diff --git a/lib/dns/zone.c b/lib/dns/zone.c index eb82ce0b47..5525d18b57 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -5755,7 +5755,9 @@ del_sigs(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, * We want the earliest offline expire time * iff there is a new offline signature. */ - if (!dst_key_isprivate(keys[i])) { + if (!dst_key_inactive(keys[i]) && + !dst_key_isprivate(keys[i])) + { isc_int64_t timeexpire = dns_time64_from32(rrsig.timeexpire); if (warn != 0 && warn > timeexpire)