]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Send out CDNSKEY/CDS only for entrypoints
authorPieter Lexis <pieter.lexis@powerdns.com>
Sun, 27 Dec 2015 11:01:50 +0000 (12:01 +0100)
committerPieter Lexis <pieter.lexis@powerdns.com>
Mon, 18 Jan 2016 18:16:35 +0000 (19:16 +0100)
Closes #3098

15 files changed:
pdns/dbdnsseckeeper.cc
pdns/dnsseckeeper.hh
pdns/packethandler.cc
pdns/packethandler.hh
pdns/tcpreceiver.cc
regression-tests.nobackend/tinydns-data-check/expected_result
regression-tests/named.conf
regression-tests/start-test-stop
regression-tests/tests/00dnssec-grabkeys/expected_result.dnssec
regression-tests/tests/publishing-cds-cdnskey/command
regression-tests/tests/publishing-cds-cdnskey/expected_result
regression-tests/tests/verify-dnssec-zone/expected_result
regression-tests/tests/verify-dnssec-zone/expected_result.nsec3
regression-tests/tests/verify-dnssec-zone/expected_result.nsec3-optout
regression-tests/zones/cdnskey-cds-test.com [new file with mode: 0644]

index 7df4afc4f510167a436769a4ed48697701882dd6..65d9dab407dce594daadcc5689af4de7cb1fbb9f 100644 (file)
@@ -367,6 +367,38 @@ bool DNSSECKeeper::unsetPublishCDNSKEY(const DNSName& zname)
   return d_keymetadb->setDomainMetadata(zname, "PUBLISH_CDNSKEY", vector<string>());
 }
 
+/**
+ * Returns all keys that are used to sign the DNSKEY RRSet in a zone
+ *
+ * @param zone         DNSName of the zone
+ * @return             a keyset_t with all keys that are used to sign the DNSKEY
+ *                     RRSet (these are the entrypoint(s) to the zone)
+ */
+DNSSECKeeper::keyset_t DNSSECKeeper::getEntryPoints(const DNSName& zone)
+{
+  DNSSECKeeper::keyset_t ret;
+  DNSSECKeeper::keyset_t keys = getKeys(zone);
+
+  set<int> algoHasKSK;
+
+  for(DNSSECKeeper::keyset_t::value_type& keymeta : keys) {
+    if(keymeta.second.active && keymeta.second.keyOrZone) {
+      // KSKs should always be returned
+      ret.push_back(keymeta);
+      algoHasKSK.insert(keymeta.first.d_algorithm);
+    }
+  }
+
+  // Now add ZSK EntryPoints
+  for(auto const &keymeta : keys) {
+    // Skip inactive keys, KSKs and algos that have a KSK
+    if (!keymeta.second.active || keymeta.second.keyOrZone || algoHasKSK.count(keymeta.first.d_algorithm))
+      continue;
+    ret.push_back(keymeta);
+  }
+  return ret;
+}
+
 DNSSECKeeper::keyset_t DNSSECKeeper::getKeys(const DNSName& zone, boost::tribool allOrKeyOrZone, bool useCache)
 {
   unsigned int now = time(0);
index 4cdbd81b77fc471b2c3c7f9b94fca3ab9cb7dcce..aff52b99c655e19dc09582a14942dd51b9340690 100644 (file)
@@ -71,6 +71,7 @@ public:
   }
   bool isSecuredZone(const DNSName& zone);
   static uint64_t dbdnssecCacheSizes(const std::string& str);  
+  keyset_t getEntryPoints(const DNSName& zone);
   keyset_t getKeys(const DNSName& zone, boost::tribool allOrKeyOrZone = boost::indeterminate, bool useCache = true);
   DNSSECPrivateKey getKeyById(const DNSName& zone, unsigned int id);
   bool addKey(const DNSName& zname, bool keyOrZone, int algorithm=5, int bits=0, bool active=true);
index d6217e412dd210b1cfb90613ae5a15457f6b918a..ae50e3ec19bd178641f8a6cc06406226376f3464 100644 (file)
@@ -133,34 +133,64 @@ void PacketHandler::addRootReferral(DNSPacket* r)
 }
 
 /**
- * This adds DNSKEY records to the answer packet. Returns true if one was added.
- * The optional doCDNSKEY parameter signifies that we need to add a CDNSKEY (RFC 7344)
- * instead of DNSKEY.
+ * This adds CDNSKEY records to the answer packet. Returns true if one was added.
  *
  * @param p          Pointer to the DNSPacket containing the original question
  * @param r          Pointer to the DNSPacket where the records should be inserted into
- * @param sd         SOAData of the zone for which DNSKEY records sets should be added
- * @param doCDNSKEY  When set to true, add CDNSKEYs instead of DNSKEYs
+ * @param sd         SOAData of the zone for which CDNSKEY records sets should be added
  * @return           bool that shows if any records were added
 **/
-bool PacketHandler::addDNSKEY(DNSPacket *p, DNSPacket *r, const SOAData& sd, bool doCDNSKEY=false)
+bool PacketHandler::addCDNSKEY(DNSPacket *p, DNSPacket *r, const SOAData& sd)
 {
   string publishCDNSKEY;
   d_dk.getFromMeta(p->qdomain, "PUBLISH_CDNSKEY", publishCDNSKEY);
-  if (doCDNSKEY && publishCDNSKEY != "1")
+  if (publishCDNSKEY != "1")
     return false;
 
   DNSResourceRecord rr;
   bool haveOne=false;
   DNSSECPrivateKey dpk;
 
+  DNSSECKeeper::keyset_t entryPoints = d_dk.getEntryPoints(p->qdomain);
+  for(const auto& value: entryPoints) {
+    rr.qtype=QType::CDNSKEY;
+    rr.ttl=sd.default_ttl;
+    rr.qname=p->qdomain;
+    rr.content=value.first.getDNSKEY().getZoneRepresentation();
+    rr.auth=true;
+    r->addRecord(rr);
+    haveOne=true;
+  }
+
+  if(::arg().mustDo("direct-dnskey")) {
+    B.lookup(QType(QType::CDNSKEY), p->qdomain, p, sd.domain_id);
+
+    while(B.get(rr)) {
+      rr.ttl=sd.default_ttl;
+      r->addRecord(rr);
+      haveOne=true;
+    }
+  }
+  return haveOne;
+}
+
+/**
+ * This adds DNSKEY records to the answer packet. Returns true if one was added.
+ *
+ * @param p          Pointer to the DNSPacket containing the original question
+ * @param r          Pointer to the DNSPacket where the records should be inserted into
+ * @param sd         SOAData of the zone for which DNSKEY records sets should be added
+ * @return           bool that shows if any records were added
+**/
+bool PacketHandler::addDNSKEY(DNSPacket *p, DNSPacket *r, const SOAData& sd)
+{
+  DNSResourceRecord rr;
+  bool haveOne=false;
+  DNSSECPrivateKey dpk;
+
   DNSSECKeeper::keyset_t keyset = d_dk.getKeys(p->qdomain);
   for(const auto& value: keyset) {
-    if (doCDNSKEY && !value.second.keyOrZone) {
-      // Don't send out CDNSKEY records for ZSKs
-      continue;
-    }
-    rr.qtype=doCDNSKEY ? QType::CDNSKEY : QType::DNSKEY;
+    rr.qtype=QType::DNSKEY;
     rr.ttl=sd.default_ttl;
     rr.qname=p->qdomain;
     rr.content=value.first.getDNSKEY().getZoneRepresentation();
@@ -170,10 +200,7 @@ bool PacketHandler::addDNSKEY(DNSPacket *p, DNSPacket *r, const SOAData& sd, boo
   }
 
   if(::arg().mustDo("direct-dnskey")) {
-    if(doCDNSKEY)
-      B.lookup(QType(QType::CDNSKEY), p->qdomain, p, sd.domain_id);
-    else
-      B.lookup(QType(QType::DNSKEY), p->qdomain, p, sd.domain_id);
+    B.lookup(QType(QType::DNSKEY), p->qdomain, p, sd.domain_id);
 
     while(B.get(rr)) {
       rr.ttl=sd.default_ttl;
@@ -213,13 +240,9 @@ bool PacketHandler::addCDS(DNSPacket *p, DNSPacket *r, const SOAData& sd)
   bool haveOne=false;
   DNSSECPrivateKey dpk;
 
-  DNSSECKeeper::keyset_t keyset = d_dk.getKeys(p->qdomain);
+  DNSSECKeeper::keyset_t keyset = d_dk.getEntryPoints(p->qdomain);
 
   for(auto const &value : keyset) {
-    if (!value.second.keyOrZone) {
-      // Don't send out CDS records for ZSKs
-      continue;
-    }
     for(auto const &digestAlgo : digestAlgos){
       rr.content=makeDSFromDNSKey(p->qdomain, value.first.getDNSKEY(), std::stoi(digestAlgo)).getZoneRepresentation();
       r->addRecord(rr);
@@ -1024,11 +1047,11 @@ void PacketHandler::completeANYRecords(DNSPacket *p, DNSPacket*r, SOAData& sd, c
 
   if(!d_dk.isSecuredZone(sd.qname))
     return;
-    
+
   addNSECX(p, r, target, DNSName(), sd.qname, 5);
   if(sd.qname == p->qdomain) {
     addDNSKEY(p, r, sd);
-    addDNSKEY(p, r, sd, true);
+    addCDNSKEY(p, r, sd);
     addCDS(p, r, sd);
     addNSEC3PARAM(p, r, sd);
   }
@@ -1283,7 +1306,7 @@ DNSPacket *PacketHandler::questionOrRecurse(DNSPacket *p, bool *shouldRecurse)
       }
       else if(p->qtype.getCode() == QType::CDNSKEY)
       {
-        if(addDNSKEY(p,r, sd, true))
+        if(addCDNSKEY(p,r, sd))
           goto sendit;
       }
       else if(p->qtype.getCode() == QType::CDS)
index 550358465aecb3f2f6e0e6ece8ce89cfe774fd93..24f9d243d6128df67e0b655f204c8613b389ada9 100644 (file)
@@ -71,7 +71,8 @@ private:
   int processNotify(DNSPacket *);
   void addRootReferral(DNSPacket *r);
   int doChaosRequest(DNSPacket *p, DNSPacket *r, DNSName &target);
-  bool addDNSKEY(DNSPacket *p, DNSPacket *r, const SOAData& sd, bool doCDNSKEY);
+  bool addDNSKEY(DNSPacket *p, DNSPacket *r, const SOAData& sd);
+  bool addCDNSKEY(DNSPacket *p, DNSPacket *r, const SOAData& sd);
   bool addCDS(DNSPacket *p, DNSPacket *r, const SOAData& sd);
   bool addNSEC3PARAM(DNSPacket *p, DNSPacket *r, const SOAData& sd);
   int doAdditionalProcessingAndDropAA(DNSPacket *p, DNSPacket *r, const SOAData& sd, bool retargeted);
index 9920f51603f09eac67a4017fd1e28238a8c9271b..09de4f65655d9ae3faf8a6ab3ca472b611c0fb62 100644 (file)
@@ -664,6 +664,10 @@ int TCPNameserver::doAXFR(const DNSName &target, shared_ptr<DNSPacket> q, int ou
   dk.getFromMeta(q->qdomain, "PUBLISH_CDNSKEY", publishCDNSKEY);
   dk.getFromMeta(q->qdomain, "PUBLISH_CDS", publishCDS);
   vector<DNSResourceRecord> cds, cdnskey;
+  DNSSECKeeper::keyset_t entryPoints = dk.getEntryPoints(q->qdomain);
+  set<uint32_t> entryPointIds;
+  for (auto const& value : entryPoints)
+    entryPointIds.insert(value.second.id);
 
   for(const DNSSECKeeper::keyset_t::value_type& value :  keys) {
     rr.qtype = QType(QType::DNSKEY);
@@ -676,7 +680,7 @@ int TCPNameserver::doAXFR(const DNSName &target, shared_ptr<DNSPacket> q, int ou
     csp.submit(rr);
 
     // generate CDS and CDNSKEY records
-    if(value.second.keyOrZone){
+    if(entryPointIds.count(value.second.id) > 0){
       if(publishCDNSKEY == "1") {
         rr.qtype=QType(QType::CDNSKEY);
         rr.content = value.first.getDNSKEY().getZoneRepresentation();
index 71e330d340803cd5d3cf8464e3b25779b70d66cf..36553b1404d7cb6a5911ec16ad548d434ef77128 100644 (file)
@@ -9,4 +9,5 @@ a63dc120391d9df0003f2ec4f461a6af  ../regression-tests/zones/secure-delegated.dns
 24514dc104b22206daeb973ff9303545  ../regression-tests/zones/minimal.com
 0b20d7a0250576451135483b863750bf  ../regression-tests/zones/tsig.com
 b1f775045fa2cf0a3b91aa834af06e49  ../regression-tests/zones/stest.com
+a98864b315f16bcf49ce577426063c42  ../regression-tests/zones/cdnskey-cds-test.com
 2d30ff6855f531368c72e2195a76eabb  ../modules/tinydnsbackend/data.cdb
index c1ca0849012255729ae786072c5791fdc7738b2f..ce6483cb609d06a92d77603562dcf278eeda8a05 100644 (file)
@@ -64,3 +64,8 @@ zone "stest.com"{
        type master;
        file "stest.com";
 };
+
+zone "cdnskey-cds-test.com"{
+       type master;
+       file "cdnskey-cds-test.com";
+};
index 6bca98904c95658208045da1df2a78e1baf09772..231f16546191c00519de401dd22a7038984f3ced 100755 (executable)
@@ -92,6 +92,10 @@ securezone ()
                   $PDNSUTIL --config-dir=. $configname hsm create-key $zone $kid
                 else
                   $PDNSUTIL --config-dir=. $configname secure-zone $zone 2>&1
+                  if [ "${zone: 0:20}" = "cdnskey-cds-test.com" ]; then
+                    $PDNSUTIL --config-dir=. $configname set-publish-cds $zone 2>&1
+                    $PDNSUTIL --config-dir=. $configname set-publish-cdnskey $zone 2>&1
+                  fi
                 fi
        fi
 }
index 2cf7d9c20553e8f2c71edcc864436aa3a3325ca5..b019335fcf5ec05607e46695ffb8503f4d9b6fb8 100755 (executable)
@@ -3,3 +3,9 @@
 cleandig secure-delegated.dnssec-parent.com CDS dnssec
 cleandig secure-delegated.dnssec-parent.com CDNSKEY dnssec
 cleandig secure-delegated.dnssec-parent.com ANY dnssec tcp | grep 'CDS\|CDNSKEY' | grep -v 'NSEC'
+
+# We only want to know if we get these records when the default secure-zone is use
+# This means a single ZSK, we don't care about the conents
+cleandig cdnskey-cds-test.com CDS dnssec | perl -pe 's!86400.*!86400!g'
+cleandig cdnskey-cds-test.com CDNSKEY dnssec | perl -pe 's!86400.*!86400!g'
+cleandig cdnskey-cds-test.com ANY dnssec tcp | grep 'CDS\|CDNSKEY' | grep -v 'NSEC' | perl -pe 's!86400.*!86400!g'
index d07af16d8d2de6ac793cb2cc93a1d8a8f67ed4fe..cc03f2d9a0b4d3ecd58cfb68718d4639d91f9f69 100644 (file)
@@ -14,3 +14,19 @@ Reply to question for qname='secure-delegated.dnssec-parent.com.', qtype=CDNSKEY
 0      secure-delegated.dnssec-parent.com.     IN      CDS     86400   54319 8 2 a0b9c38cd324182af0ef66830d0a0e85a1d58979c9834e18c871779e040857b7
 0      secure-delegated.dnssec-parent.com.     IN      RRSIG   86400   CDNSKEY 8 3 86400 [expiry] [inception] [keytag] secure-delegated.dnssec-parent.com. ...
 0      secure-delegated.dnssec-parent.com.     IN      RRSIG   86400   CDS 8 3 86400 [expiry] [inception] [keytag] secure-delegated.dnssec-parent.com. ...
+0      cdnskey-cds-test.com.   IN      CDS     86400
+0      cdnskey-cds-test.com.   IN      CDS     86400
+0      cdnskey-cds-test.com.   IN      RRSIG   86400
+2      .       IN      OPT     32768   
+Rcode: 0 (No Error), RD: 0, QR: 1, TC: 0, AA: 1, opcode: 0
+Reply to question for qname='cdnskey-cds-test.com.', qtype=CDS
+0      cdnskey-cds-test.com.   IN      CDNSKEY 86400
+0      cdnskey-cds-test.com.   IN      RRSIG   86400
+2      .       IN      OPT     32768   
+Rcode: 0 (No Error), RD: 0, QR: 1, TC: 0, AA: 1, opcode: 0
+Reply to question for qname='cdnskey-cds-test.com.', qtype=CDNSKEY
+0      cdnskey-cds-test.com.   IN      CDNSKEY 86400
+0      cdnskey-cds-test.com.   IN      CDS     86400
+0      cdnskey-cds-test.com.   IN      CDS     86400
+0      cdnskey-cds-test.com.   IN      RRSIG   86400
+0      cdnskey-cds-test.com.   IN      RRSIG   86400
index a116ca02b2e445ab9984e1c3abb29f4f9998078b..074ec83493908b09947a9bc85a384ee2a1b6b5a4 100644 (file)
@@ -73,3 +73,11 @@ zone stest.com/IN: loaded serial 2000081501 (DNSSEC signed)
 OK
 RETVAL: 0
 
+--- ldns-verify-zone -V2 cdnskey-cds-test.com
+RETVAL: 0
+
+--- named-checkzone cdnskey-cds-test.com
+zone cdnskey-cds-test.com/IN: loaded serial 2005092501 (DNSSEC signed)
+OK
+RETVAL: 0
+
index a116ca02b2e445ab9984e1c3abb29f4f9998078b..074ec83493908b09947a9bc85a384ee2a1b6b5a4 100644 (file)
@@ -73,3 +73,11 @@ zone stest.com/IN: loaded serial 2000081501 (DNSSEC signed)
 OK
 RETVAL: 0
 
+--- ldns-verify-zone -V2 cdnskey-cds-test.com
+RETVAL: 0
+
+--- named-checkzone cdnskey-cds-test.com
+zone cdnskey-cds-test.com/IN: loaded serial 2005092501 (DNSSEC signed)
+OK
+RETVAL: 0
+
index b8d3184a98d31cd195651bca7573b7984322db0f..8f41144cf960370ae5dc08ac08c99b37ab048c2c 100644 (file)
@@ -76,3 +76,11 @@ zone stest.com/IN: loaded serial 2000081501 (DNSSEC signed)
 OK
 RETVAL: 0
 
+--- ldns-verify-zone -V2 cdnskey-cds-test.com
+RETVAL: 0
+
+--- named-checkzone cdnskey-cds-test.com
+zone cdnskey-cds-test.com/IN: loaded serial 2005092501 (DNSSEC signed)
+OK
+RETVAL: 0
+
diff --git a/regression-tests/zones/cdnskey-cds-test.com b/regression-tests/zones/cdnskey-cds-test.com
new file mode 100644 (file)
index 0000000..7fb64fa
--- /dev/null
@@ -0,0 +1,14 @@
+$TTL 3600
+$ORIGIN cdnskey-cds-test.com.
+@              IN      SOA     ns1.cdnskey-cds-test.   ahu.example.com. (  2005092501
+                       8H ; refresh
+                       2H ; retry
+                       1W ; expire
+                       1D ; default_ttl
+                       )
+
+@                      IN      NS      ns1
+@                      IN      NS      ns2
+@                      IN      A       127.0.0.1
+ns1                    IN      A       1.1.1.1
+ns2                    IN      A       2.2.2.2