From: Michał Kępień Date: Wed, 13 Jun 2018 10:19:54 +0000 (+0200) Subject: Treat records below a DNAME as out-of-zone data X-Git-Tag: v9.10.8rc2~12^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9a4145168ce80abd218d4ea46a380555d16d6de9;p=thirdparty%2Fbind9.git Treat records below a DNAME as out-of-zone data DNAME records indicate bottom of zone and thus no records below a DNAME should be DNSSEC-signed or included in NSEC(3) chains. Add a helper function, has_dname(), for detecting DNAME records at a given node. Prevent signing DNAME-obscured records. Check that DNAME-obscured records are not signed. (cherry picked from commit 6d8a514ecbd72d1f8b2b12fbbbca5c5f87085abd) --- diff --git a/bin/dnssec/dnssec-signzone.c b/bin/dnssec/dnssec-signzone.c index fed91a4b58e..06f0dfeeccc 100644 --- a/bin/dnssec/dnssec-signzone.c +++ b/bin/dnssec/dnssec-signzone.c @@ -1501,8 +1501,14 @@ assignwork(isc_task_t *task, isc_task_t *worker) { if (!OPTOUT(nsec3flags) || secure(name, node)) found = ISC_TRUE; - } else + } else if (has_dname(gdb, gversion, node)) { + dns_fixedname_init(&fzonecut); + zonecut = dns_fixedname_name(&fzonecut); + dns_name_copy(name, zonecut, NULL); found = ISC_TRUE; + } else { + found = ISC_TRUE; + } } } @@ -1810,6 +1816,9 @@ nsecify(void) { remove_sigs(node, ISC_TRUE, 0); if (generateds) add_ds(name, node, nsttl); + } else if (has_dname(gdb, gversion, node)) { + zonecut = dns_fixedname_name(&fzonecut); + dns_name_copy(name, zonecut, NULL); } result = dns_dbiterator_next(dbiter); @@ -2253,6 +2262,11 @@ nsec3ify(unsigned int hashalg, dns_iterations_t iterations, (void)active_node(node); } + if (has_dname(gdb, gversion, node)) { + zonecut = dns_fixedname_name(&fzonecut); + dns_name_copy(name, zonecut, NULL); + } + result = dns_dbiterator_next(dbiter); nextnode = NULL; while (result == ISC_R_SUCCESS) { @@ -2287,6 +2301,9 @@ nsec3ify(unsigned int hashalg, dns_iterations_t iterations, result = dns_dbiterator_next(dbiter); continue; } + } else if (has_dname(gdb, gversion, nextnode)) { + zonecut = dns_fixedname_name(&fzonecut); + dns_name_copy(nextname, zonecut, NULL); } dns_db_detachnode(gdb, &nextnode); break; @@ -2385,6 +2402,12 @@ nsec3ify(unsigned int hashalg, dns_iterations_t iterations, dns_db_detachnode(gdb, &node); continue; } + + if (has_dname(gdb, gversion, node)) { + zonecut = dns_fixedname_name(&fzonecut); + dns_name_copy(name, zonecut, NULL); + } + result = dns_dbiterator_next(dbiter); nextnode = NULL; while (result == ISC_R_SUCCESS) { @@ -2415,6 +2438,9 @@ nsec3ify(unsigned int hashalg, dns_iterations_t iterations, result = dns_dbiterator_next(dbiter); continue; } + } else if (has_dname(gdb, gversion, nextnode)) { + zonecut = dns_fixedname_name(&fzonecut); + dns_name_copy(nextname, zonecut, NULL); } dns_db_detachnode(gdb, &nextnode); break; diff --git a/bin/dnssec/dnssectool.c b/bin/dnssec/dnssectool.c index 77f2f219de7..1758d94be19 100644 --- a/bin/dnssec/dnssectool.c +++ b/bin/dnssec/dnssectool.c @@ -576,6 +576,21 @@ is_delegation(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin, return (ISC_TF(result == ISC_R_SUCCESS)); } +isc_boolean_t +has_dname(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node) { + dns_rdataset_t dnameset; + isc_result_t result; + + dns_rdataset_init(&dnameset); + result = dns_db_findrdataset(db, node, ver, dns_rdatatype_dname, 0, 0, + &dnameset, NULL); + if (dns_rdataset_isassociated(&dnameset)) { + dns_rdataset_disassociate(&dnameset); + } + + return (ISC_TF(result == ISC_R_SUCCESS)); +} + static isc_boolean_t goodsig(dns_name_t *origin, dns_rdata_t *sigrdata, dns_name_t *name, dns_rdataset_t *keyrdataset, dns_rdataset_t *rdataset, isc_mem_t *mctx) @@ -1730,6 +1745,9 @@ verifyzone(dns_db_t *db, dns_dbversion_t *ver, zonecut = dns_fixedname_name(&fzonecut); dns_name_copy(name, zonecut, NULL); isdelegation = ISC_TRUE; + } else if (has_dname(db, ver, node)) { + zonecut = dns_fixedname_name(&fzonecut); + dns_name_copy(name, zonecut, NULL); } nextnode = NULL; result = dns_dbiterator_next(dbiter); diff --git a/bin/dnssec/dnssectool.h b/bin/dnssec/dnssectool.h index 21274359f7e..d9ecd7f3da2 100644 --- a/bin/dnssec/dnssectool.h +++ b/bin/dnssec/dnssectool.h @@ -93,6 +93,13 @@ isc_boolean_t is_delegation(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin, dns_name_t *name, dns_dbnode_t *node, isc_uint32_t *ttlp); +/*% + * Return ISC_TRUE if version 'ver' of database 'db' contains a DNAME RRset at + * 'node'; return ISC_FALSE otherwise. + */ +isc_boolean_t +has_dname(dns_db_t *db, dns_dbversion_t *ver, dns_dbnode_t *node); + void verifyzone(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *origin, isc_mem_t *mctx, diff --git a/bin/tests/system/verify/tests.sh b/bin/tests/system/verify/tests.sh index 450b49a60b3..da8a23ad436 100644 --- a/bin/tests/system/verify/tests.sh +++ b/bin/tests/system/verify/tests.sh @@ -63,7 +63,7 @@ do expect1="signature has expired" expect2="No self-signed .*DNSKEY found" ;; - *.out-of-zone-nsec|*.below-bottom-of-zone-nsec) + *.out-of-zone-nsec|*.below-bottom-of-zone-nsec|*.below-dname-nsec) expect1="unexpected NSEC RRset at" ;; *.nsec.broken-chain) diff --git a/bin/tests/system/verify/zones/genzones.sh b/bin/tests/system/verify/zones/genzones.sh index a7ce8fb3663..26cfc25b72c 100644 --- a/bin/tests/system/verify/zones/genzones.sh +++ b/bin/tests/system/verify/zones/genzones.sh @@ -47,6 +47,13 @@ $KEYGEN -r $RANDFILE ${zone} > kg1.out$n 2>&1 || dumpit kg1.out$n $KEYGEN -r $RANDFILE -fK ${zone} > kg2.out$n 2>&1 || dumpit kg2.out$n $SIGNER -SPx -o ${zone} -f ${file} unsigned.db > s.out$n 2>&1 || dumpit s.out$n +setup ksk+zsk.nsec.apex-dname good +zsk=`$KEYGEN -r $RANDFILE ${zone} 2> kg1.out$n` || dumpit kg1.out$n +ksk=`$KEYGEN -r $RANDFILE -fK ${zone} 2> kg2.out$n` || dumpit kg2.out$n +cp unsigned.db ${file}.tmp +echo "@ DNAME data" >> ${file}.tmp +$SIGNER -SP -o ${zone} -f ${file} ${file}.tmp > s.out$n 2>&1 || dumpit s.out$n + # A set of nsec3 zones. setup zsk-only.nsec3 good $KEYGEN -3 -r $RANDFILE ${zone}> kg.out$n 2>&1 || dumpit kg.out$n @@ -61,11 +68,18 @@ $KEYGEN -3 -r $RANDFILE ${zone} > kg1.out$n 2>&1 || dumpit kg1.out$n $KEYGEN -3 -r $RANDFILE -fK ${zone} > kg2.out$n 2>&1 || dumpit kg2.out$n $SIGNER -3 - -SPx -o ${zone} -f ${file} unsigned.db > s.out$n 2>&1 || dumpit s.out$n -setup ksk+zsk.outout good +setup ksk+zsk.optout good $KEYGEN -3 -r $RANDFILE ${zone} > kg1.out$n 2>&1 || dumpit kg1.out$n $KEYGEN -3 -r $RANDFILE -fK ${zone} > kg2.out$n 2>&1 || dumpit kg2.out$n $SIGNER -3 - -A -SPx -o ${zone} -f ${file} unsigned.db > s.out$n 2>&1 || dumpit s.out$n +setup ksk+zsk.nsec3.apex-dname good +zsk=`$KEYGEN -3 -r $RANDFILE ${zone} 2> kg1.out$n` || dumpit kg1.out$n +ksk=`$KEYGEN -3 -r $RANDFILE -fK ${zone} 2> kg2.out$n` || dumpit kg2.out$n +cp unsigned.db ${file}.tmp +echo "@ DNAME data" >> ${file}.tmp +$SIGNER -3 - -SP -o ${zone} -f ${file} ${file}.tmp > s.out$n 2>&1 || dumpit s.out$n + # A set of zones with only DNSKEY records. setup zsk-only.dnskeyonly bad key1=`$KEYGEN -r $RANDFILE ${zone} 2>kg.out` || dumpit kg.out$n @@ -156,7 +170,7 @@ $SIGNER -P -O full -o ${zone} -f ${file} ${file} $ksk > s.out$n 2>&1 || dumpit s echo "out-of-zone. 3600 IN NSEC ${zone}. A" >> ${file} $SIGNER -Px -Z nonsecify -O full -o ${zone} -f ${file} ${file} $zsk > s.out$n 2>&1 || dumpit s.out$n -# extra NSEC record below bottom of one +# extra NSEC record below bottom of zone setup ksk+zsk.nsec.below-bottom-of-zone-nsec bad zsk=`$KEYGEN -r $RANDFILE ${zone} 2> kg1.out$n` || dumpit kg1.out$n ksk=`$KEYGEN -r $RANDFILE -fK ${zone} 2> kg2.out$n` || dumpit kg2.out$n @@ -167,6 +181,15 @@ $SIGNER -Px -Z nonsecify -O full -o ${zone} -f ${file}.tmp ${file} $zsk > s.out$ # dnssec-signzone signs any node with a NSEC record. awk '$1 ~ /^ns.sub/ && $4 == "RRSIG" && $5 != "NSEC" { next; } { print; }' ${file}.tmp > ${file} +# extra NSEC record below DNAME +setup ksk+zsk.nsec.below-dname-nsec bad +zsk=`$KEYGEN -r $RANDFILE ${zone} 2> kg1.out$n` || dumpit kg1.out$n +ksk=`$KEYGEN -r $RANDFILE -fK ${zone} 2> kg2.out$n` || dumpit kg2.out$n +cat unsigned.db $ksk.key $zsk.key > $file +$SIGNER -P -O full -o ${zone} -f ${file} ${file} $ksk > s.out$n 2>&1 || dumpit s.out$n +echo "sub.dname.${zone}. 3600 IN NSEC ${zone}. TXT" >> ${file} +$SIGNER -Px -Z nonsecify -O full -o ${zone} -f ${file} ${file} $zsk > s.out$n 2>&1 || dumpit s.out$n + # missing NSEC3 record at empty node # extract the hash fields from the empty node's NSEC 3 record then fix up # the NSEC3 chain to remove it