From: Remi Gacogne Date: Wed, 11 Oct 2017 09:25:04 +0000 (+0200) Subject: rec: Check that the NSEC covers an ENT when looking for NODATA X-Git-Tag: rec-4.1.0-rc2~40^2~1 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=00e3fef4defb7ca4090992e9cedc69d2ea8ca3b9;p=pdns rec: Check that the NSEC covers an ENT when looking for NODATA Otherwise we might consider that a NSEC record covers a name when it does not. --- diff --git a/pdns/recursordist/test-syncres_cc.cc b/pdns/recursordist/test-syncres_cc.cc index 5c82bb41d..3ce10cf89 100644 --- a/pdns/recursordist/test-syncres_cc.cc +++ b/pdns/recursordist/test-syncres_cc.cc @@ -6987,10 +6987,10 @@ BOOST_AUTO_TEST_CASE(test_nsec_denial_nowrap) { cspmap_t denialMap; denialMap[std::make_pair(DNSName("a.example.org."), QType::NSEC)] = pair; - dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false); + dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, false); BOOST_CHECK_EQUAL(denialState, NXDOMAIN); - denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false); + denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false); /* let's check that d.example.org. is not denied by this proof */ BOOST_CHECK_EQUAL(denialState, NODATA); } @@ -7022,10 +7022,10 @@ BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_1) { cspmap_t denialMap; denialMap[std::make_pair(DNSName("z.example.org."), QType::NSEC)] = pair; - dState denialState = getDenial(denialMap, DNSName("a.example.org."), QType::A, false); + dState denialState = getDenial(denialMap, DNSName("a.example.org."), QType::A, false, false); BOOST_CHECK_EQUAL(denialState, NXDOMAIN); - denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false); + denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false); /* let's check that d.example.org. is not denied by this proof */ BOOST_CHECK_EQUAL(denialState, NODATA); } @@ -7057,10 +7057,10 @@ BOOST_AUTO_TEST_CASE(test_nsec_denial_wrap_case_2) { cspmap_t denialMap; denialMap[std::make_pair(DNSName("y.example.org."), QType::NSEC)] = pair; - dState denialState = getDenial(denialMap, DNSName("z.example.org."), QType::A, false); + dState denialState = getDenial(denialMap, DNSName("z.example.org."), QType::A, false, false); BOOST_CHECK_EQUAL(denialState, NXDOMAIN); - denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false); + denialState = getDenial(denialMap, DNSName("d.example.org."), QType::A, false, false); /* let's check that d.example.org. is not denied by this proof */ BOOST_CHECK_EQUAL(denialState, NODATA); } @@ -7092,10 +7092,10 @@ BOOST_AUTO_TEST_CASE(test_nsec_denial_only_one_nsec) { cspmap_t denialMap; denialMap[std::make_pair(DNSName("a.example.org."), QType::NSEC)] = pair; - dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false); + dState denialState = getDenial(denialMap, DNSName("b.example.org."), QType::A, false, false); BOOST_CHECK_EQUAL(denialState, NXDOMAIN); - denialState = getDenial(denialMap, DNSName("a.example.org."), QType::A, false); + denialState = getDenial(denialMap, DNSName("a.example.org."), QType::A, false, false); /* let's check that d.example.org. is not denied by this proof */ BOOST_CHECK_EQUAL(denialState, NODATA); } @@ -7127,7 +7127,7 @@ BOOST_AUTO_TEST_CASE(test_nsec_root_nxd_denial) { cspmap_t denialMap; denialMap[std::make_pair(DNSName("a."), QType::NSEC)] = pair; - dState denialState = getDenial(denialMap, DNSName("b."), QType::A, false); + dState denialState = getDenial(denialMap, DNSName("b."), QType::A, false, false); BOOST_CHECK_EQUAL(denialState, NXDOMAIN); } @@ -7167,12 +7167,12 @@ BOOST_AUTO_TEST_CASE(test_nsec_ancestor_nxqtype_denial) { owner name regardless of type. */ - dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false); + dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, false); /* no data means the qname/qtype is not denied, because an ancestor delegation NSEC can only deny the DS */ BOOST_CHECK_EQUAL(denialState, NODATA); - denialState = getDenial(denialMap, DNSName("a."), QType::DS, true); + denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true); BOOST_CHECK_EQUAL(denialState, NXQTYPE); } @@ -7213,10 +7213,43 @@ BOOST_AUTO_TEST_CASE(test_nsec_insecure_delegation_denial) { /* Insecure because the NS is not set, so while it does denies the DS, it can't prove an insecure delegation */ - dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true); + dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true); BOOST_CHECK_EQUAL(denialState, INSECURE); } +BOOST_AUTO_TEST_CASE(test_nsec_ent_denial) { + init(); + + testkeysset_t keys; + generateKeyMaterial(DNSName("powerdns.com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + + vector records; + + vector> recordContents; + vector> signatureContents; + + addNSECRecordToLW(DNSName("a.powerdns.com."), DNSName("a.c.powerdns.com."), { QType::A }, 600, records); + recordContents.push_back(records.at(0).d_content); + addRRSIG(keys, records, DNSName("powerdns.com."), 300); + signatureContents.push_back(getRR(records.at(1))); + records.clear(); + + ContentSigPair pair; + pair.records = recordContents; + pair.signatures = signatureContents; + cspmap_t denialMap; + denialMap[std::make_pair(DNSName("a.powerdns.com."), QType::NSEC)] = pair; + + /* this NSEC is not valid to prove a NXQTYPE at b.powerdns.com */ + dState denialState = getDenial(denialMap, DNSName("b.powerdns.com."), QType::AAAA, true, true); + BOOST_CHECK_EQUAL(denialState, NXDOMAIN); + + /* it is valid to prove a NXQTYPE at c.powerdns.com because it proves that + it is an ENT */ + denialState = getDenial(denialMap, DNSName("c.powerdns.com."), QType::AAAA, true, true); + BOOST_CHECK_EQUAL(denialState, NXQTYPE); +} + BOOST_AUTO_TEST_CASE(test_nsec3_ancestor_nxqtype_denial) { init(); @@ -7253,12 +7286,12 @@ BOOST_AUTO_TEST_CASE(test_nsec3_ancestor_nxqtype_denial) { owner name regardless of type. */ - dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false); + dState denialState = getDenial(denialMap, DNSName("a."), QType::A, false, true); /* no data means the qname/qtype is not denied, because an ancestor delegation NSEC3 can only deny the DS */ BOOST_CHECK_EQUAL(denialState, NODATA); - denialState = getDenial(denialMap, DNSName("a."), QType::DS, true); + denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true); BOOST_CHECK_EQUAL(denialState, NXQTYPE); } @@ -7299,7 +7332,7 @@ BOOST_AUTO_TEST_CASE(test_nsec3_insecure_delegation_denial) { /* Insecure because the NS is not set, so while it does denies the DS, it can't prove an insecure delegation */ - dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true); + dState denialState = getDenial(denialMap, DNSName("a."), QType::DS, true, true); BOOST_CHECK_EQUAL(denialState, INSECURE); } diff --git a/pdns/syncres.cc b/pdns/syncres.cc index e964ffc83..8caede3ac 100644 --- a/pdns/syncres.cc +++ b/pdns/syncres.cc @@ -1929,7 +1929,7 @@ void SyncRes::getDenialValidationState(NegCache::NegCacheEntry& ne, vState& stat if (state == Secure) { cspmap_t csp = harvestCSPFromNE(ne); - dState res = getDenial(csp, ne.d_name, ne.d_qtype.getCode(), referralToUnsigned); + dState res = getDenial(csp, ne.d_name, ne.d_qtype.getCode(), referralToUnsigned, expectedState == NXQTYPE); if (res != expectedState) { if (res == OPTOUT && allowOptOut) { LOG(d_prefix<<"OPT-out denial found for "< nsec3) { std::string result; @@ -95,10 +104,7 @@ bool denialProvesNoDelegation(const DNSName& zone, const std::vector& return false; } -// FIXME: needs a zone argument, to avoid things like 6840 4.1 -// FIXME: Add ENT support -// FIXME: Make usable for non-DS records and hook up to validateRecords (or another place) -dState getDenial(const cspmap_t &validrrsets, const DNSName& qname, const uint16_t qtype, bool referralToUnsigned) +dState getDenial(const cspmap_t &validrrsets, const DNSName& qname, const uint16_t qtype, bool referralToUnsigned, bool wantsNoDataProof) { for(const auto& v : validrrsets) { LOG("Do have: "<d_next)) { + + if (wantsNoDataProof && nsecProvesENT(qname, v.first.first, nsec->d_next)) { + LOG("Denies existence of type "<& anchors, const DNSName& zone, dsmap_t &res); bool haveNegativeTrustAnchor(const map& negAnchors, const DNSName& zone, std::string& reason); void validateDNSKeysAgainstDS(time_t now, const DNSName& zone, const dsmap_t& dsmap, const skeyset_t& tkeys, vector >& toSign, const vector >& sigs, skeyset_t& validkeys); -dState getDenial(const cspmap_t &validrrsets, const DNSName& qname, const uint16_t qtype, bool referralToUnsigned); +dState getDenial(const cspmap_t &validrrsets, const DNSName& qname, const uint16_t qtype, bool referralToUnsigned, bool wantsNoDataProof); bool isSupportedDS(const DSRecordContent& ds); DNSName getSigner(const std::vector >& signatures); bool denialProvesNoDelegation(const DNSName& zone, const std::vector& dsrecords);