From 4d787d305e2edc4b5737e77c643717ca8c6c226e Mon Sep 17 00:00:00 2001 From: Pieter Lexis Date: Tue, 31 Oct 2017 22:59:54 +0100 Subject: [PATCH] Add tests for DS downgrade protection Adds an ugly hack to be able to test private functions in the syncres as well. --- pdns/recursordist/test-syncres_cc.cc | 286 +++++++++++++++++++++++++++ 1 file changed, 286 insertions(+) diff --git a/pdns/recursordist/test-syncres_cc.cc b/pdns/recursordist/test-syncres_cc.cc index c29cff5fd..cc8af34b6 100644 --- a/pdns/recursordist/test-syncres_cc.cc +++ b/pdns/recursordist/test-syncres_cc.cc @@ -8138,6 +8138,292 @@ BOOST_AUTO_TEST_CASE(test_lowercase_outgoing) { g_lowercaseOutgoing = false; } +BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("com."); + testkeysset_t keys, keys2; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + g_luaconfs.setState(luaconfsCopy); + + // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo + generateKeyMaterial(DNSName("com."), DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys2); + // But add the existing root key otherwise no RRSIG can be created + auto rootkey = keys.find(g_rootdnsname); + keys2.insert(*rootkey); + + sr->setAsyncCallback([target, keys, keys2](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res) { + DNSName auth = domain; + auth.chopOff(); + if (type == QType::DS || type == QType::DNSKEY) { + if (domain == target) { + if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) { + return 0; + } + } + return genericDSAndDNSKEYHandler(res, domain, auth, type, keys); + } + return 0; + }); + + dsmap_t ds; + auto state = sr->getDSRecords(target, ds, false, 0, false); + BOOST_CHECK_EQUAL(state, Secure); + BOOST_REQUIRE_EQUAL(ds.size(), 1); + for (const auto& i : ds) { + BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256); + } +} + +BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_all_sha) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("com."); + testkeysset_t keys, keys2, keys3; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + g_luaconfs.setState(luaconfsCopy); + + // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo + generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys2); + // But add the existing root key otherwise no RRSIG can be created + auto rootkey = keys.find(g_rootdnsname); + keys2.insert(*rootkey); + + generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA384, keys3); + // But add the existing root key otherwise no RRSIG can be created + keys3.insert(*rootkey); + + sr->setAsyncCallback([target, keys, keys2, keys3](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res) { + DNSName auth = domain; + auth.chopOff(); + if (type == QType::DS || type == QType::DNSKEY) { + if (domain == target) { + if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) { + return 0; + } + if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys3) != 1) { + return 0; + } + } + return genericDSAndDNSKEYHandler(res, domain, auth, type, keys); + } + return 0; + }); + + dsmap_t ds; + auto state = sr->getDSRecords(target, ds, false, 0, false); + BOOST_CHECK_EQUAL(state, Secure); + BOOST_REQUIRE_EQUAL(ds.size(), 1); + for (const auto& i : ds) { + BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA384); + } +} + +BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_two_highest) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("com."); + testkeysset_t keys, keys2, keys3; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + g_luaconfs.setState(luaconfsCopy); + + // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo + generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys2); + // But add the existing root key otherwise no RRSIG can be created + auto rootkey = keys.find(g_rootdnsname); + keys2.insert(*rootkey); + + generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys3); + // But add the existing root key otherwise no RRSIG can be created + keys3.insert(*rootkey); + + sr->setAsyncCallback([target, keys, keys2, keys3](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res) { + DNSName auth = domain; + auth.chopOff(); + if (type == QType::DS || type == QType::DNSKEY) { + if (domain == target) { + if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) { + return 0; + } + if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys3) != 1) { + return 0; + } + } + return genericDSAndDNSKEYHandler(res, domain, auth, type, keys); + } + return 0; + }); + + dsmap_t ds; + auto state = sr->getDSRecords(target, ds, false, 0, false); + BOOST_CHECK_EQUAL(state, Secure); + BOOST_REQUIRE_EQUAL(ds.size(), 2); + for (const auto& i : ds) { + BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256); + } +} + +#ifdef HAVE_BOTAN110 +BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_prefer_sha384_over_gost) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("com."); + testkeysset_t keys, keys2; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA384, keys); + g_luaconfs.setState(luaconfsCopy); + + // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo + generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::GOST, keys2); + // But add the existing root key otherwise no RRSIG can be created + auto rootkey = keys.find(g_rootdnsname); + keys2.insert(*rootkey); + + sr->setAsyncCallback([target, keys, keys2](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res) { + DNSName auth = domain; + auth.chopOff(); + if (type == QType::DS || type == QType::DNSKEY) { + if (domain == target) { + if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) { + return 0; + } + } + return genericDSAndDNSKEYHandler(res, domain, auth, type, keys); + } + return 0; + }); + + dsmap_t ds; + auto state = sr->getDSRecords(target, ds, false, 0, false); + BOOST_CHECK_EQUAL(state, Secure); + BOOST_REQUIRE_EQUAL(ds.size(), 1); + for (const auto& i : ds) { + BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA384); + } +} + +BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_prefer_sha256_over_gost) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("com."); + testkeysset_t keys, keys2; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys); + g_luaconfs.setState(luaconfsCopy); + + // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo + generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::GOST, keys2); + // But add the existing root key otherwise no RRSIG can be created + auto rootkey = keys.find(g_rootdnsname); + keys2.insert(*rootkey); + + sr->setAsyncCallback([target, keys, keys2](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res) { + DNSName auth = domain; + auth.chopOff(); + if (type == QType::DS || type == QType::DNSKEY) { + if (domain == target) { + if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) { + return 0; + } + } + return genericDSAndDNSKEYHandler(res, domain, auth, type, keys); + } + return 0; + }); + + dsmap_t ds; + auto state = sr->getDSRecords(target, ds, false, 0, false); + BOOST_CHECK_EQUAL(state, Secure); + BOOST_REQUIRE_EQUAL(ds.size(), 1); + for (const auto& i : ds) { + BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::SHA256); + } +} + +BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo_prefer_gost_over_sha1) { + std::unique_ptr sr; + initSR(sr, true); + + setDNSSECValidation(sr, DNSSECMode::ValidateAll); + + primeHints(); + const DNSName target("com."); + testkeysset_t keys, keys2; + + auto luaconfsCopy = g_luaconfs.getCopy(); + luaconfsCopy.dsAnchors.clear(); + generateKeyMaterial(g_rootdnsname, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA256, keys, luaconfsCopy.dsAnchors); + generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::SHA1, keys); + g_luaconfs.setState(luaconfsCopy); + + // As testkeysset_t only contains one DSRecordContent, create another one with a different hash algo + generateKeyMaterial(target, DNSSECKeeper::ECDSA256, DNSSECKeeper::GOST, keys2); + // But add the existing root key otherwise no RRSIG can be created + auto rootkey = keys.find(g_rootdnsname); + keys2.insert(*rootkey); + + sr->setAsyncCallback([target, keys, keys2](const ComboAddress& ip, const DNSName& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional& srcmask, boost::optional context, std::shared_ptr outgoingLogger, LWResult* res) { + DNSName auth = domain; + auth.chopOff(); + if (type == QType::DS || type == QType::DNSKEY) { + if (domain == target) { + if (genericDSAndDNSKEYHandler(res, domain, auth, type, keys2) != 1) { + return 0; + } + } + return genericDSAndDNSKEYHandler(res, domain, auth, type, keys); + } + return 0; + }); + + dsmap_t ds; + auto state = sr->getDSRecords(target, ds, false, 0, false); + BOOST_CHECK_EQUAL(state, Secure); + BOOST_REQUIRE_EQUAL(ds.size(), 1); + for (const auto& i : ds) { + BOOST_CHECK_EQUAL(i.d_digesttype, DNSSECKeeper::GOST); + } +} +#endif // HAVE_BOTAN110 + /* // cerr<<"asyncresolve called to ask "<