]> granicus.if.org Git - pdns/commitdiff
Hook GSS-TSIG feature to code
authorAki Tuomi <cmouse@cmouse.fi>
Thu, 21 May 2015 19:30:53 +0000 (22:30 +0300)
committerAki Tuomi <cmouse@cmouse.fi>
Thu, 28 May 2015 14:42:20 +0000 (17:42 +0300)
pdns/dnspacket.cc
pdns/dnspacket.hh
pdns/dnssecinfra.cc
pdns/packethandler.cc
pdns/packethandler.hh
pdns/resolver.cc
pdns/tcpreceiver.cc

index e202004edd528d3c5a680636e3b529464eef6775..73151cee2a50e1bd62f77517efa47b5445fc03e4 100644 (file)
@@ -47,6 +47,7 @@
 #include "dnssecinfra.hh" 
 #include "base64.hh"
 #include "ednssubnet.hh"
+#include "gss_context.hh"
 
 bool DNSPacket::s_doEDNSSubnetProcessing;
 uint16_t DNSPacket::s_udpTruncationThreshold;
@@ -636,6 +637,14 @@ bool checkForCorrectTSIG(const DNSPacket* q, UeberBackend* B, string* keyname, s
   if (algoName == "hmac-md5.sig-alg.reg.int")
     algoName = "hmac-md5";
 
+  if (algoName == "gss-tsig") {
+    if (!gss_verify_signature(*keyname, message, trc->d_mac)) {
+      L<<Logger::Error<<"Packet for domain '"<<q->qdomain<<"' denied: TSIG signature mismatch using '"<<*keyname<<"' and algorithm '"<<trc->d_algoName<<"'"<<endl;
+      return false;
+    }
+    return true;
+  }
+
   string secret64;
   if(!B->getTSIGKey(*keyname, &algoName, &secret64)) {
     L<<Logger::Error<<"Packet for domain '"<<q->qdomain<<"' denied: can't find TSIG key with name '"<<*keyname<<"' and algorithm '"<<algoName<<"'"<<endl;
index 84574be3dd2fdab98fb101c9b2e7a263a4e696ef..db1181b1e65953124fb1408b89dd8645720c9816 100644 (file)
@@ -146,6 +146,9 @@ public:
   bool d_dnssecOk;
   bool d_havetsig;
 
+  string d_peer_principal;
+  TSIGHashEnum d_tsig_algo;
+
   bool getTSIGDetails(TSIGRecordContent* tr, string* keyname, string* message) const;
   void setTSIGDetails(const TSIGRecordContent& tr, const string& keyname, const string& secret, const string& previous, bool timersonly=false);
   bool getTKEYRecord(TKEYRecordContent* tr, string* keyname) const;
index 3dcfb71b6eaba7ba24c5c4d9c581ea0e7682a9a5..d5ae99e6641a91d30d16efa8750e233908917a8a 100644 (file)
@@ -22,6 +22,7 @@
 #ifdef HAVE_P11KIT1
 #include "pkcs11signers.hh"
 #endif
+#include "gss_context.hh"
 
 using namespace boost::assign;
 
@@ -612,8 +613,7 @@ void addTSIG(DNSPacketWriter& pw, TSIGRecordContent* trc, const string& tsigkeyn
 {
   TSIGHashEnum algo;
   if (!getTSIGHashEnum(trc->d_algoName, algo)) {
-     L<<Logger::Error<<"Unsupported TSIG HMAC algorithm " << trc->d_algoName << endl;
-     return;
+    throw PDNSException(string("Unsupported TSIG HMAC algorithm ") + trc->d_algoName);
   }
 
   string toSign;
@@ -647,8 +647,14 @@ void addTSIG(DNSPacketWriter& pw, TSIGRecordContent* trc, const string& tsigkeyn
   const vector<uint8_t>& signRecord=dw.getRecordBeingWritten();
   toSign.append(&*signRecord.begin(), &*signRecord.end());
 
-  trc->d_mac = calculateHMAC(tsigsecret, toSign, algo);
-  //  d_trc->d_mac[0]++; // sabotage
+  if (algo == TSIG_GSS) {
+    if (!gss_add_signature(tsigkeyname, toSign, trc->d_mac)) {
+      throw PDNSException(string("Could not add TSIG signature with algorithm 'gss-tsig' and key name '")+tsigkeyname+string("'"));
+    }
+  } else {
+    trc->d_mac = calculateHMAC(tsigsecret, toSign, algo);
+    //  d_trc->d_mac[0]++; // sabotage
+  }
   pw.startRecord(tsigkeyname, QType::TSIG, 0, QClass::ANY, DNSPacketWriter::ADDITIONAL, false);
   trc->toPacket(pw);
   pw.commit();
index af58d62756342632a2498b660b12043175bb5aed..d35e543c92dd88bb50663976471db1342a71db66 100644 (file)
@@ -1058,6 +1058,14 @@ DNSPacket *PacketHandler::questionOrRecurse(DNSPacket *p, bool *shouldRecurse)
       else
         r->setRcode(RCode::NotAuth);
       return r;
+    } else {
+      getTSIGHashEnum(trc.d_algoName, p->d_tsig_algo);
+      if (p->d_tsig_algo == TSIG_GSS) {
+        GssContext gssctx(keyname);
+        if (!gssctx.getPeerPrincipal(p->d_peer_principal)) {
+          L<<Logger::Warning<<"Failed to extract peer principal from GSS context with keyname '"<<keyname<<"'"<<endl;
+        }
+      }
     }
     p->setTSIGDetails(trc, keyname, secret, trc.d_mac); // this will get copied by replyPacket()
     noCache=true;
@@ -1420,7 +1428,8 @@ DNSPacket *PacketHandler::questionOrRecurse(DNSPacket *p, bool *shouldRecurse)
 void PacketHandler::tkeyHandler(DNSPacket *p, DNSPacket *r) {
   TKEYRecordContent tkey_in;
   std::shared_ptr<TKEYRecordContent> tkey_out(new TKEYRecordContent());
-  string label, lcLabel;
+  string label;
+  bool sign = false;
 
   if (!p->getTKEYRecord(&tkey_in, &label)) {
     L<<Logger::Error<<"TKEY request but no TKEY RR found"<<endl;
@@ -1429,17 +1438,38 @@ void PacketHandler::tkeyHandler(DNSPacket *p, DNSPacket *r) {
   }
 
   // retain original label for response
-  lcLabel = toLowerCanonic(label);
-
   tkey_out->d_error = 0;
   tkey_out->d_mode = tkey_in.d_mode;
   tkey_out->d_algo = tkey_in.d_algo;
   tkey_out->d_inception = time((time_t*)NULL);
   tkey_out->d_expiration = tkey_out->d_inception+15;
 
-  if (tkey_in.d_mode == 3) {
-    tkey_out->d_error = 19; // BADMODE
-  } else if (tkey_in.d_mode == 5) {
+  GssContext ctx(label);
+
+  if (tkey_in.d_mode == 3) { // establish context
+    if (tkey_in.d_algo == "gss-tsig.") {
+      std::vector<std::string> meta;
+      string tmpLabel = toLowerCanonic(label);
+      bool ok = true;
+      while(ok) {
+        if (B.getDomainMetadata(tmpLabel, "GSS-ACCEPTOR-PRINCIPAL", meta) && meta.size()>0) {
+          break;
+        }
+        ok = chopOff(tmpLabel);
+      }
+
+      if (meta.size()>0) {
+        ctx.setLocalPrincipal(meta[0]);
+      }
+      // try to get a context
+      if (!ctx.accept(tkey_in.d_key, tkey_out->d_key))
+        tkey_out->d_error = 19;
+      else
+        sign = true;
+    } else {
+      tkey_out->d_error = 21; // BADALGO
+    }
+  } else if (tkey_in.d_mode == 5) { // destroy context
     if (p->d_havetsig == false) { // unauthenticated
       if (p->d.opcode == Opcode::Update)
         r->setRcode(RCode::Refused);
@@ -1447,7 +1477,10 @@ void PacketHandler::tkeyHandler(DNSPacket *p, DNSPacket *r) {
         r->setRcode(RCode::NotAuth);
       return;
     }
-    tkey_out->d_error = 20; // BADNAME (because we have no support for anything here)
+    if (ctx.valid())
+      ctx.destroy();
+    else
+      tkey_out->d_error = 20; // BADNAME (because we have no support for anything here)
   } else {
     if (p->d_havetsig == false && tkey_in.d_mode != 2) { // unauthenticated
       if (p->d.opcode == Opcode::Update)
@@ -1474,5 +1507,20 @@ void PacketHandler::tkeyHandler(DNSPacket *p, DNSPacket *r) {
   rr.qtype = QType::TKEY;
   rr.d_place = DNSResourceRecord::ANSWER;
   r->addRecord(rr);
+
+  if (sign)
+  {
+    TSIGRecordContent trc;
+    trc.d_algoName = "gss-tsig";
+    trc.d_time = tkey_out->d_inception;
+    trc.d_fudge = 300;
+    trc.d_mac = "";
+    trc.d_origID = p->d.id;
+    trc.d_eRcode = 0;
+    trc.d_otherData = "";
+    // this should cause it to lookup label context
+    r->setTSIGDetails(trc, label, label, "", false);
+  }
+
   r->commitD();
 }
index 645e8fca5fe826c4fe0c9308235fe075c8ac9ac0..352ecf60b685326c92938f77d8df2f75b31f9511 100644 (file)
@@ -30,6 +30,7 @@
 #include "packetcache.hh"
 #include "dnsseckeeper.hh"
 #include "lua-auth.hh"
+#include "gss_context.hh"
 
 #include "namespaces.hh"
 
index a4e847565868a0c39e034bc54c792798bfc11745..6f8778d17160130edfdd1b71d2fc04ff374e0afd 100644 (file)
@@ -505,11 +505,18 @@ int AXFRRetriever::getChunk(Resolver::res_t &res) // Implementation is making su
         throw ResolverException("Unsupported TSIG HMAC algorithm " + d_trc.d_algoName);
       }
 
-      string ourMac=calculateHMAC(d_tsigsecret, message, algo);
+      if (algo == TSIG_GSS) {
+        GssContext gssctx(d_tsigkeyname);
+        if (!gss_verify_signature(d_tsigkeyname, message, theirMac)) {
+          throw ResolverException("Signature failed to validate on AXFR response from "+d_remote.toStringWithPort()+" signed with TSIG key '"+d_tsigkeyname+"'");
+        }
+      } else {
+        string ourMac=calculateHMAC(d_tsigsecret, message, algo);
 
-      // ourMac[0]++; // sabotage == for testing :-)
-      if(ourMac != theirMac) {
-        throw ResolverException("Signature failed to validate on AXFR response from "+d_remote.toStringWithPort()+" signed with TSIG key '"+d_tsigkeyname+"'");
+        // ourMac[0]++; // sabotage == for testing :-)
+        if(ourMac != theirMac) {
+          throw ResolverException("Signature failed to validate on AXFR response from "+d_remote.toStringWithPort()+" signed with TSIG key '"+d_tsigkeyname+"'");
+        }
       }
 
       // Reset and store some values for the next chunks. 
index 36b346883164f925bca0464af9601b8c5f5a66be..e6710b797df5568f2127c8c83437e7b1ea7ee76d 100644 (file)
@@ -420,7 +420,16 @@ bool TCPNameserver::canDoAXFR(shared_ptr<DNSPacket> q)
     string keyname, secret;
     if(!checkForCorrectTSIG(q.get(), s_P->getBackend(), &keyname, &secret, &trc))
       return false;
-    
+    } else {
+      getTSIGHashEnum(trc.d_algoName, q->d_tsig_algo);
+      if (q->d_tsig_algo == TSIG_GSS) {
+        GssContext gssctx(keyname);
+        if (!gssctx.getPeerPrincipal(q->d_peer_principal)) {
+          L<<Logger::Warning<<"Failed to extract peer principal from GSS context with keyname '"<<keyname<<"'"<<endl;
+        }
+      }
+    }
+
     DNSSECKeeper dk;
 
     string algorithm=toLowerCanonic(trc.d_algoName);