]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
rec: Validate cached DNSKEYs against the DSs, not the RRSIGs only
authorRemi Gacogne <remi.gacogne@powerdns.com>
Mon, 6 Jul 2020 13:00:44 +0000 (15:00 +0200)
committerOtto Moerbeek <otto.moerbeek@open-xchange.com>
Mon, 13 Jul 2020 14:17:08 +0000 (16:17 +0200)
DNSKEYs might be cached in a non-validated state ("Indeterminate")
when the DNSSEC mode is set to "Process" and the initial query did
not ask for validation.
We would then validate the DNSKEY records against the RRSIGs, like
for regular records, but not against the DSs.

(cherry picked from commit 453f37736a4d372e16755a903f5b5d5ac52b0c17)

pdns/recursordist/test-syncres_cc4.cc
pdns/syncres.cc

index f879409d4ab56668f5e7d2b0b35478a718c99d37..7c72748fdda751312e563af8fe15d98cba4e20c1 100644 (file)
@@ -689,7 +689,7 @@ BOOST_AUTO_TEST_CASE(test_dnssec_bogus_dnskey_doesnt_match_ds)
   std::unique_ptr<SyncRes> sr;
   initSR(sr, true);
 
-  setDNSSECValidation(sr, DNSSECMode::ValidateAll);
+  setDNSSECValidation(sr, DNSSECMode::Process);
 
   primeHints();
   const DNSName target(".");
@@ -754,6 +754,8 @@ BOOST_AUTO_TEST_CASE(test_dnssec_bogus_dnskey_doesnt_match_ds)
     return 0;
   });
 
+  /* === with validation enabled === */
+  sr->setDNSSECValidationRequested(true);
   vector<DNSRecord> ret;
   int res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
   BOOST_CHECK_EQUAL(res, RCode::NoError);
@@ -769,6 +771,39 @@ BOOST_AUTO_TEST_CASE(test_dnssec_bogus_dnskey_doesnt_match_ds)
   BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
   BOOST_REQUIRE_EQUAL(ret.size(), 14U);
   BOOST_CHECK_EQUAL(queriesCount, 2U);
+
+  /* === first without validation, then with (just-in-time validation) === */
+  /* clear the caches */
+  s_RC = std::unique_ptr<MemRecursorCache>(new MemRecursorCache());
+  SyncRes::clearNegCache();
+  sr->setDNSSECValidationRequested(false);
+  primeHints();
+
+  ret.clear();
+  res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
+  BOOST_CHECK_EQUAL(res, RCode::NoError);
+  BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
+  /* 13 NS + 1 RRSIG */
+  BOOST_REQUIRE_EQUAL(ret.size(), 14U);
+  BOOST_CHECK_EQUAL(queriesCount, 3U);
+
+  /* now we ask for the DNSKEYs (still without validation) */
+  ret.clear();
+  res = sr->beginResolve(target, QType(QType::DNSKEY), QClass::IN, ret);
+  BOOST_CHECK_EQUAL(res, RCode::NoError);
+  BOOST_CHECK_EQUAL(sr->getValidationState(), Indeterminate);
+  /* 1 SOA + 1 RRSIG */
+  BOOST_REQUIRE_EQUAL(ret.size(), 2U);
+  BOOST_CHECK_EQUAL(queriesCount, 4U);
+
+  /* again, to test the cache WITH validation */
+  sr->setDNSSECValidationRequested(true);
+  ret.clear();
+  res = sr->beginResolve(target, QType(QType::NS), QClass::IN, ret);
+  BOOST_CHECK_EQUAL(res, RCode::NoError);
+  BOOST_CHECK_EQUAL(sr->getValidationState(), Bogus);
+  BOOST_REQUIRE_EQUAL(ret.size(), 14U);
+  BOOST_CHECK_EQUAL(queriesCount, 4U);
 }
 
 BOOST_AUTO_TEST_CASE(test_dnssec_bogus_rrsig_signed_with_unknown_dnskey)
index cd86a67f9fdc14f6a398acb7bdeeb17d0a327f34..20a2811d830e116579c93ab0d6493756e296d030 100644 (file)
@@ -1594,7 +1594,12 @@ bool SyncRes::doCacheCheck(const DNSName &qname, const DNSName& authname, bool w
       vState recordState = getValidationStatus(qname, false);
       if (recordState == Secure) {
         LOG(prefix<<sqname<<": got Indeterminate state from the cache, validating.."<<endl);
-        cachedState = SyncRes::validateRecordsWithSigs(depth, sqname, sqt, sqname, cset, signatures);
+        if (sqt == QType::DNSKEY) {
+          cachedState = validateDNSKeys(sqname, cset, signatures, depth);
+        }
+        else {
+          cachedState = SyncRes::validateRecordsWithSigs(depth, sqname, sqt, sqname, cset, signatures);
+        }
       }
       else {
         cachedState = recordState;