]> granicus.if.org Git - pdns/commitdiff
Add tests for DS downgrade protection
authorPieter Lexis <pieter.lexis@powerdns.com>
Tue, 31 Oct 2017 21:59:54 +0000 (22:59 +0100)
committerPieter Lexis <pieter.lexis@powerdns.com>
Thu, 2 Nov 2017 15:24:51 +0000 (16:24 +0100)
Adds an ugly hack to be able to test private functions in the syncres as
well.

pdns/recursordist/test-syncres_cc.cc

index c29cff5fd89f58e430ec646a5aeffab05fd95e5e..cc8af34b67bafe15b6228a114214169648b3768d 100644 (file)
@@ -8138,6 +8138,292 @@ BOOST_AUTO_TEST_CASE(test_lowercase_outgoing) {
   g_lowercaseOutgoing = false;
 }
 
+BOOST_AUTO_TEST_CASE(test_getDSRecords_multialgo) {
+  std::unique_ptr<SyncRes> 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<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> 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<SyncRes> 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<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> 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<SyncRes> 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<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> 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<SyncRes> 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<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> 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<SyncRes> 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<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> 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<SyncRes> 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<Netmask>& srcmask, boost::optional<const ResolveContext&> context, std::shared_ptr<RemoteLogger> 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 "<<ip.toStringWithPort()<<" about "<<domain.toString()<<" / "<<QType(type).getName()<<" over "<<(doTCP ? "TCP" : "UDP")<<" (rd: "<<sendRDQuery<<", EDNS0 level: "<<EDNS0Level<<")"<<endl;