From: Remi Gacogne Date: Thu, 29 Oct 2020 15:00:14 +0000 (+0100) Subject: rec: Add more Bogus states to better match rfc8914 extended codes X-Git-Tag: auth-4.4.0-alpha3~2^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=refs%2Fpull%2F9597%2Fhead;p=thirdparty%2Fpdns.git rec: Add more Bogus states to better match rfc8914 extended codes --- diff --git a/pdns/lua-recursor4.cc b/pdns/lua-recursor4.cc index f240f0c550..f16e020257 100644 --- a/pdns/lua-recursor4.cc +++ b/pdns/lua-recursor4.cc @@ -355,6 +355,13 @@ void RecursorLua4::postPrepareContext() {"BogusNoRRSIG", static_cast(vState::BogusNoRRSIG) }, {"BogusNoValidRRSIG", static_cast(vState::BogusNoValidRRSIG) }, {"BogusMissingNegativeIndication", static_cast(vState::BogusMissingNegativeIndication) }, + {"BogusSignatureNotYetValid", static_cast(vState::BogusSignatureNotYetValid)}, + {"BogusSignatureExpired", static_cast(vState::BogusSignatureExpired)}, + {"BogusUnsupportedDNSKEYAlgo", static_cast(vState::BogusUnsupportedDNSKEYAlgo)}, + {"BogusUnsupportedDSDigestType", static_cast(vState::BogusUnsupportedDSDigestType)}, + {"BogusNoZoneKeyBitSet", static_cast(vState::BogusNoZoneKeyBitSet)}, + {"BogusRevokedDNSKEY", static_cast(vState::BogusRevokedDNSKEY)}, + {"BogusInvalidDNSKEYProtocol", static_cast(vState::BogusInvalidDNSKEYProtocol)}, {"Insecure", static_cast(vState::Insecure) }, {"Secure", static_cast(vState::Secure) }, }}); diff --git a/pdns/rec_channel_rec.cc b/pdns/rec_channel_rec.cc index 468f130999..ec48ffb02f 100644 --- a/pdns/rec_channel_rec.cc +++ b/pdns/rec_channel_rec.cc @@ -1177,6 +1177,13 @@ void registerAllStats() addGetStat("dnssec-result-bogus-no-rrsig", &g_stats.dnssecResults[vState::BogusNoRRSIG]); addGetStat("dnssec-result-bogus-no-valid-rrsig", &g_stats.dnssecResults[vState::BogusNoValidRRSIG]); addGetStat("dnssec-result-bogus-missing-negative-indication", &g_stats.dnssecResults[vState::BogusMissingNegativeIndication]); + addGetStat("dnssec-result-bogus-signature-not-yet-valid", &g_stats.dnssecResults[vState::BogusSignatureNotYetValid]); + addGetStat("dnssec-result-bogus-signature-expired", &g_stats.dnssecResults[vState::BogusSignatureExpired]); + addGetStat("dnssec-result-bogus-unsupported-dnskey-algo", &g_stats.dnssecResults[vState::BogusUnsupportedDNSKEYAlgo]); + addGetStat("dnssec-result-bogus-unsupported-ds-digest-type", &g_stats.dnssecResults[vState::BogusUnsupportedDSDigestType]); + addGetStat("dnssec-result-bogus-no-zone-key-bit-set", &g_stats.dnssecResults[vState::BogusNoZoneKeyBitSet]); + addGetStat("dnssec-result-bogus-revoked-dnskey", &g_stats.dnssecResults[vState::BogusRevokedDNSKEY]); + addGetStat("dnssec-result-bogus-invalid-dnskey-protocol", &g_stats.dnssecResults[vState::BogusInvalidDNSKEYProtocol]); addGetStat("dnssec-result-indeterminate", &g_stats.dnssecResults[vState::Indeterminate]); addGetStat("dnssec-result-nta", &g_stats.dnssecResults[vState::NTA]); diff --git a/pdns/recursordist/test-syncres_cc4.cc b/pdns/recursordist/test-syncres_cc4.cc index 761d84cc31..c7b9bf52f3 100644 --- a/pdns/recursordist/test-syncres_cc4.cc +++ b/pdns/recursordist/test-syncres_cc4.cc @@ -460,7 +460,7 @@ BOOST_AUTO_TEST_CASE(test_dnssec_rrsig) std::vector> sigs; sigs.push_back(std::make_shared(rrc)); - BOOST_CHECK(validateWithKeySet(now, qname, recordcontents, sigs, keyset)); + BOOST_CHECK(validateWithKeySet(now, qname, recordcontents, sigs, keyset) == vState::Secure); } BOOST_AUTO_TEST_CASE(test_dnssec_root_validation_csk) @@ -747,7 +747,7 @@ BOOST_AUTO_TEST_CASE(test_dnssec_bogus_dnskey_without_zone_flag) vector ret; int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret); BOOST_CHECK_EQUAL(res, RCode::NoError); - BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusNoValidDNSKEY); + BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusNoZoneKeyBitSet); /* 13 NS + 1 RRSIG */ BOOST_REQUIRE_EQUAL(ret.size(), 14U); BOOST_CHECK_EQUAL(queriesCount, 2U); @@ -756,7 +756,7 @@ BOOST_AUTO_TEST_CASE(test_dnssec_bogus_dnskey_without_zone_flag) ret.clear(); res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret); BOOST_CHECK_EQUAL(res, RCode::NoError); - BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusNoValidDNSKEY); + BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusNoZoneKeyBitSet); BOOST_REQUIRE_EQUAL(ret.size(), 14U); BOOST_CHECK_EQUAL(queriesCount, 2U); } @@ -824,7 +824,7 @@ BOOST_AUTO_TEST_CASE(test_dnssec_bogus_dnskey_revoked) vector ret; int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret); BOOST_CHECK_EQUAL(res, RCode::NoError); - BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusNoValidDNSKEY); + BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusRevokedDNSKEY); /* 13 NS + 1 RRSIG */ BOOST_REQUIRE_EQUAL(ret.size(), 14U); BOOST_CHECK_EQUAL(queriesCount, 2U); @@ -833,7 +833,7 @@ BOOST_AUTO_TEST_CASE(test_dnssec_bogus_dnskey_revoked) ret.clear(); res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret); BOOST_CHECK_EQUAL(res, RCode::NoError); - BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusNoValidDNSKEY); + BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusRevokedDNSKEY); BOOST_REQUIRE_EQUAL(ret.size(), 14U); BOOST_CHECK_EQUAL(queriesCount, 2U); } diff --git a/pdns/recursordist/test-syncres_cc6.cc b/pdns/recursordist/test-syncres_cc6.cc index dc056974af..152a144712 100644 --- a/pdns/recursordist/test-syncres_cc6.cc +++ b/pdns/recursordist/test-syncres_cc6.cc @@ -385,7 +385,7 @@ BOOST_AUTO_TEST_CASE(test_dnssec_dnskey_signed_child) vector ret; int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); BOOST_CHECK_EQUAL(res, RCode::NoError); - BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusNoValidDNSKEY); + BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusNoValidRRSIG); BOOST_REQUIRE_EQUAL(ret.size(), 2U); BOOST_CHECK_EQUAL(queriesCount, 10U); @@ -393,7 +393,7 @@ BOOST_AUTO_TEST_CASE(test_dnssec_dnskey_signed_child) ret.clear(); res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret); BOOST_CHECK_EQUAL(res, RCode::NoError); - BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusNoValidDNSKEY); + BOOST_CHECK_EQUAL(sr->getValidationState(), vState::BogusNoValidRRSIG); BOOST_REQUIRE_EQUAL(ret.size(), 2U); BOOST_CHECK_EQUAL(queriesCount, 10U); } diff --git a/pdns/syncres.cc b/pdns/syncres.cc index 5b021d0148..522acd04d2 100644 --- a/pdns/syncres.cc +++ b/pdns/syncres.cc @@ -2594,6 +2594,14 @@ vState SyncRes::validateDNSKeys(const DNSName& zone, const std::vector& allowedAdditionals, const DNSRecord& rec) diff --git a/pdns/validate.cc b/pdns/validate.cc index 4b09dd2c4d..dc1e4c4dce 100644 --- a/pdns/validate.cc +++ b/pdns/validate.cc @@ -745,9 +745,14 @@ static const vector getZoneCuts(const DNSName& begin, const DNSName& en return ret; } -bool isRRSIGNotExpired(const time_t now, const shared_ptr sig) +bool isRRSIGNotExpired(const time_t now, const shared_ptr& sig) { - return sig->d_siginception - g_signatureInceptionSkew <= now && sig->d_sigexpire >= now; + return sig->d_sigexpire >= now; +} + +bool isRRSIGIncepted(const time_t now, const shared_ptr& sig) +{ + return sig->d_siginception - g_signatureInceptionSkew <= now; } static bool checkSignatureWithKey(time_t now, const shared_ptr sig, const shared_ptr key, const std::string& msg) @@ -758,7 +763,7 @@ static bool checkSignatureWithKey(time_t now, const shared_ptr dke = shared_ptr(DNSCryptoKeyEngine::makeFromPublicKeyString(key->d_algorithm, key->d_key)); result = dke->verify(msg, sig->d_signature); LOG("signature by key with tag "<d_tag<<" and algorithm "<d_algorithm)<<" was " << (result ? "" : "NOT ")<<"valid"<d_siginception - g_signatureInceptionSkew > now) ? "not yet valid" : "expired")<<" (inception: "<d_siginception<<", inception skew: "<d_sigexpire<<", now: "< >& signatures, const skeyset_t& keys, bool validateAllSigs) +vState validateWithKeySet(time_t now, const DNSName& name, const sortedRecords_t& toSign, const vector >& signatures, const skeyset_t& keys, bool validateAllSigs) { + bool foundKey = false; bool isValid = false; + bool allExpired = true; + bool noneIncepted = true; for(const auto& signature : signatures) { unsigned int labelCount = name.countLabels(); @@ -791,8 +799,10 @@ bool validateWithKeySet(time_t now, const DNSName& name, const sortedRecords_t& } string msg = getMessageForRRSET(name, *signature, toSign, true); - for(const auto& key : keysMatchingTag) { + for (const auto& key : keysMatchingTag) { bool signIsValid = checkSignatureWithKey(now, signature, key, msg); + foundKey = true; + if (signIsValid) { isValid = true; LOG("Validated "<d_type)<first.first)<<"/"<first.second)<<" with "<second.signatures.size()<<" sigs"<first.first, i->second.records, i->second.signatures, keys, true)) { + if (validateWithKeySet(now, i->first.first, i->second.records, i->second.signatures, keys, true) == vState::Secure) { validated[i->first] = i->second; } } @@ -878,18 +908,18 @@ bool haveNegativeTrustAnchor(const map& negAnchors, const D return true; } -void validateDNSKeysAgainstDS(time_t now, const DNSName& zone, const dsmap_t& dsmap, const skeyset_t& tkeys, const sortedRecords_t& toSign, const vector >& sigs, skeyset_t& validkeys) +vState validateDNSKeysAgainstDS(time_t now, const DNSName& zone, const dsmap_t& dsmap, const skeyset_t& tkeys, const sortedRecords_t& toSign, const vector >& sigs, skeyset_t& validkeys) { /* * Check all DNSKEY records against all DS records and place all DNSKEY records * that have DS records (that we support the algo for) in the tentative key storage */ - for(auto const& dsrc : dsmap) + for (const auto& dsrc : dsmap) { auto r = getByTag(tkeys, dsrc.d_tag, dsrc.d_algorithm); // cerr<<"looking at DS with tag "<d_tag<<" matching "<d_tag).size()<<" keys of which "<d_tag).size()<<" valid"<d_tag, sig->d_algorithm); @@ -935,11 +965,11 @@ void validateDNSKeysAgainstDS(time_t now, const DNSName& zone, const dsmap_t& ds } string msg = getMessageForRRSET(zone, *sig, toSign); - for(const auto& key : bytag) { + for (const auto& key : bytag) { // cerr<<"validating : "; bool signIsValid = checkSignatureWithKey(now, sig, key, msg); - if(signIsValid) + if (signIsValid) { LOG("validation succeeded - whole DNSKEY set is valid"<d_protocol != 3) { + continue; + } + validProtocol = true; + } + + if (!zoneKey) { + return vState::BogusNoZoneKeyBitSet; + } + if (!notRevoked) { + return vState::BogusRevokedDNSKEY; + } + if (!validProtocol) { + return vState::BogusInvalidDNSKEYProtocol; + } + + return vState::BogusNoValidDNSKEY; + } + + return vState::Secure; } vState getKeysFor(DNSRecordOracle& dro, const DNSName& zone, skeyset_t& keyset) @@ -1050,19 +1138,19 @@ vState getKeysFor(DNSRecordOracle& dro, const DNSName& zone, skeyset_t& keyset) * Check all DNSKEY records against all DS records and place all DNSKEY records * that have DS records (that we support the algo for) in the tentative key storage */ - validateDNSKeysAgainstDS(time(nullptr), *zoneCutIter, dsmap, tkeys, toSign, sigs, validkeys); + auto state = validateDNSKeysAgainstDS(time(nullptr), *zoneCutIter, dsmap, tkeys, toSign, sigs, validkeys); - if(validkeys.empty()) + if (validkeys.empty()) { LOG("ended up with zero valid DNSKEYs, going Bogus"< >& signa const std::string& vStateToString(vState state) { - static const std::vector vStates = {"Indeterminate", "Insecure", "Secure", "NTA", "TA", "Bogus - No valid DNSKEY", "Bogus - Invalid denial", "Bogus - Unable to get DSs", "Bogus - Unable to get DNSKEYs", "Bogus - Self Signed DS", "Bogus - No RRSIG", "Bogus - No valid RRSIG", "Bogus - Missing negative indication" }; + static const std::vector vStates = {"Indeterminate", "Insecure", "Secure", "NTA", "TA", "Bogus - No valid DNSKEY", "Bogus - Invalid denial", "Bogus - Unable to get DSs", "Bogus - Unable to get DNSKEYs", "Bogus - Self Signed DS", "Bogus - No RRSIG", "Bogus - No valid RRSIG", "Bogus - Missing negative indication", "Bogus - Signature not yet valid", "Bogus - Signature expired", "Bogus - Unsupported DNSKEY algorithm", "Bogus - Unsuuported DS digest type", "Bogus - No zone key bit set", "Bogus - Revoked DNSKEY", "Bogus - Invalid DNSKEY Protocol" }; return vStates.at(static_cast(state)); } diff --git a/pdns/validate.hh b/pdns/validate.hh index 99229d0e91..4819eb026e 100644 --- a/pdns/validate.hh +++ b/pdns/validate.hh @@ -33,7 +33,7 @@ extern time_t g_signatureInceptionSkew; extern uint16_t g_maxNSEC3Iterations; // 4033 5 -enum class vState : uint8_t { Indeterminate, Insecure, Secure, NTA, TA, BogusNoValidDNSKEY, BogusInvalidDenial, BogusUnableToGetDSs, BogusUnableToGetDNSKEYs, BogusSelfSignedDS, BogusNoRRSIG, BogusNoValidRRSIG, BogusMissingNegativeIndication }; +enum class vState : uint8_t { Indeterminate, Insecure, Secure, NTA, TA, BogusNoValidDNSKEY, BogusInvalidDenial, BogusUnableToGetDSs, BogusUnableToGetDNSKEYs, BogusSelfSignedDS, BogusNoRRSIG, BogusNoValidRRSIG, BogusMissingNegativeIndication, BogusSignatureNotYetValid, BogusSignatureExpired, BogusUnsupportedDNSKEYAlgo, BogusUnsupportedDSDigestType, BogusNoZoneKeyBitSet, BogusRevokedDNSKEY, BogusInvalidDNSKEYProtocol }; const std::string& vStateToString(vState state); inline bool vStateIsBogus(vState state) { @@ -72,18 +72,19 @@ struct sharedDNSKeyRecordContentCompare typedef set, sharedDNSKeyRecordContentCompare > skeyset_t; -bool validateWithKeySet(time_t now, const DNSName& name, const sortedRecords_t& records, const vector >& signatures, const skeyset_t& keys, bool validateAllSigs=true); +vState validateWithKeySet(time_t now, const DNSName& name, const sortedRecords_t& records, const vector >& signatures, const skeyset_t& keys, bool validateAllSigs=true); void validateWithKeySet(const cspmap_t& rrsets, cspmap_t& validated, const skeyset_t& keys); cspmap_t harvestCSPFromRecs(const vector& recs); vState getKeysFor(DNSRecordOracle& dro, const DNSName& zone, skeyset_t& keyset); bool getTrustAnchor(const map& 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, const sortedRecords_t& toSign, const vector >& sigs, skeyset_t& validkeys); +vState validateDNSKeysAgainstDS(time_t now, const DNSName& zone, const dsmap_t& dsmap, const skeyset_t& tkeys, const sortedRecords_t& toSign, const vector >& sigs, skeyset_t& validkeys); dState getDenial(const cspmap_t &validrrsets, const DNSName& qname, const uint16_t qtype, bool referralToUnsigned, bool wantsNoDataProof, bool needsWildcardProof=true, unsigned int wildcardLabelsCount=0); bool isSupportedDS(const DSRecordContent& ds); DNSName getSigner(const std::vector >& signatures); bool denialProvesNoDelegation(const DNSName& zone, const std::vector& dsrecords); -bool isRRSIGNotExpired(const time_t now, const shared_ptr sig); +bool isRRSIGNotExpired(const time_t now, const std::shared_ptr& sig); +bool isRRSIGIncepted(const time_t now, const shared_ptr& sig); bool isWildcardExpanded(unsigned int labelCount, const std::shared_ptr& sign); bool isWildcardExpandedOntoItself(const DNSName& owner, unsigned int labelCount, const std::shared_ptr& sign); void updateDNSSECValidationState(vState& state, const vState stateUpdate);