From: Mark Andrews Date: Thu, 3 May 2018 06:43:15 +0000 (+1000) Subject: only sign with other keys when deleting a key if there are not already existing signa... X-Git-Tag: v9.10.8rc1~8^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5686e3bb6a85b358b44d66a083aa0d51cf160379;p=thirdparty%2Fbind9.git only sign with other keys when deleting a key if there are not already existing signature for the deleted algorithm (cherry picked from commit 0667bf7ae71e4ae5203c85901fdfe3ec0e070038) (cherry picked from commit c1e342cedbd48b19aff9522722d7990e7c590228) (cherry picked from commit 298372d8d2efa2f338c091b11d2b5d7f977d3f85) --- diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 9dcba212ca8..4c0219403f7 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -796,7 +796,8 @@ static void zone_maintenance(dns_zone_t *zone); static void zone_notify(dns_zone_t *zone, isc_time_t *now); static void dump_done(void *arg, isc_result_t result); static isc_result_t zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, - isc_uint16_t keyid, isc_boolean_t deleteit); + isc_uint16_t keyid, + isc_boolean_t deleteit); static isc_result_t delete_nsec(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node, dns_name_t *name, dns_diff_t *diff); @@ -8102,15 +8103,26 @@ zone_nsec3chain(dns_zone_t *zone) { INSIST(version == NULL); } +/*% + * Delete all RRSIG records with the given algorithm and keyid. + * Remove the NSEC record and RRSIGs if nkeys is zero. + * If all remaining RRsets are signed with the given algorithm + * set *has_algp to ISC_TRUE. + */ static isc_result_t del_sig(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, dns_dbnode_t *node, unsigned int nkeys, dns_secalg_t algorithm, - isc_uint16_t keyid, dns_diff_t *diff) + isc_uint16_t keyid, isc_boolean_t *has_algp, dns_diff_t *diff) { dns_rdata_rrsig_t rrsig; dns_rdataset_t rdataset; dns_rdatasetiter_t *iterator = NULL; isc_result_t result; + isc_boolean_t alg_missed = ISC_FALSE; + isc_boolean_t alg_found = ISC_FALSE; + + char namebuf[DNS_NAME_FORMATSIZE]; + dns_name_format(name, namebuf, sizeof(namebuf)); result = dns_db_allrdatasets(db, node, version, 0, &iterator); if (result != ISC_R_SUCCESS) { @@ -8123,6 +8135,7 @@ del_sig(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, for (result = dns_rdatasetiter_first(iterator); result == ISC_R_SUCCESS; result = dns_rdatasetiter_next(iterator)) { + isc_boolean_t has_alg = ISC_FALSE; dns_rdatasetiter_current(iterator, &rdataset); if (nkeys == 0 && rdataset.type == dns_rdatatype_nsec) { for (result = dns_rdataset_first(&rdataset); @@ -8145,13 +8158,20 @@ del_sig(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, } for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS; - result = dns_rdataset_next(&rdataset)) { + result = dns_rdataset_next(&rdataset)) + { dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdataset_current(&rdataset, &rdata); CHECK(dns_rdata_tostruct(&rdata, &rrsig, NULL)); - if (rrsig.algorithm != algorithm || - rrsig.keyid != keyid) + if (nkeys != 0 && + (rrsig.algorithm != algorithm || + rrsig.keyid != keyid)) + { + if (rrsig.algorithm == algorithm) { + has_alg = ISC_TRUE; + } continue; + } CHECK(update_one_rr(db, version, diff, DNS_DIFFOP_DELRESIGN, name, rdataset.ttl, &rdata)); @@ -8159,9 +8179,25 @@ del_sig(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name, dns_rdataset_disassociate(&rdataset); if (result != ISC_R_NOMORE) break; + + /* + * After deleting, if there's still a signature for + * 'algorithm', set alg_found; if not, set alg_missed. + */ + if (has_alg) { + alg_found = ISC_TRUE; + } else { + alg_missed = ISC_TRUE; + } } if (result == ISC_R_NOMORE) result = ISC_R_SUCCESS; + + /* + * Set `has_algp` if the algorithm was found in every RRset: + * i.e., found in at least one, and not missing from any. + */ + *has_algp = ISC_TF(alg_found && !alg_missed); failure: if (dns_rdataset_isassociated(&rdataset)) dns_rdataset_disassociate(&rdataset); @@ -8191,6 +8227,7 @@ zone_sign(dns_zone_t *zone) { dst_key_t *zone_keys[DNS_MAXZONEKEYS]; isc_int32_t signatures; isc_boolean_t check_ksk, keyset_kskonly, is_ksk; + isc_boolean_t with_ksk, with_zsk; isc_boolean_t commit = ISC_FALSE; isc_boolean_t delegation; isc_boolean_t build_nsec = ISC_FALSE; @@ -8283,6 +8320,7 @@ zone_sign(dns_zone_t *zone) { build_nsec = ISC_TRUE; while (signing != NULL && nodes-- > 0 && signatures > 0) { + isc_boolean_t has_alg = ISC_FALSE; nextsigning = ISC_LIST_NEXT(signing, link); ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read); @@ -8322,6 +8360,9 @@ zone_sign(dns_zone_t *zone) { zone_keys[j] = zone_keys[i]; j++; } + for (i = j; i < nkeys; i++) { + zone_keys[i] = NULL; + } nkeys = j; } @@ -8331,7 +8372,7 @@ zone_sign(dns_zone_t *zone) { dns_dbiterator_pause(signing->dbiterator); CHECK(del_sig(db, version, name, node, nkeys, signing->algorithm, signing->keyid, - zonediff.diff)); + &has_alg, zonediff.diff)); } /* @@ -8363,8 +8404,10 @@ zone_sign(dns_zone_t *zone) { /* * Process one node. */ + with_ksk = ISC_FALSE; + with_zsk = ISC_FALSE; dns_dbiterator_pause(signing->dbiterator); - for (i = 0; i < nkeys; i++) { + for (i = 0; !has_alg && i < nkeys; i++) { isc_boolean_t both = ISC_FALSE; /* @@ -8434,6 +8477,19 @@ zone_sign(dns_zone_t *zone) { else is_ksk = ISC_FALSE; + /* + * If deleting signatures, we need to ensure that + * the RRset is still signed at least once by a + * KSK and a ZSK. + */ + if (signing->deleteit && !is_ksk && with_zsk) { + continue; + } + + if (signing->deleteit && is_ksk && with_ksk) { + continue; + } + CHECK(sign_a_node(db, name, node, version, build_nsec3, build_nsec, zone_keys[i], inception, expire, zone->minimum, is_ksk, @@ -8444,8 +8500,15 @@ zone_sign(dns_zone_t *zone) { * If we are adding we are done. Look for other keys * of the same algorithm if deleting. */ - if (!signing->deleteit) + if (!signing->deleteit) { break; + } + if (!is_ksk) { + with_zsk = ISC_TRUE; + } + if (KSK(zone_keys[i])) { + with_ksk = ISC_TRUE; + } } /*