diff -ru pdns-3.3.3/pdns/dnspacket.cc pdns-3.3.3-tsig-165253.good/pdns/dnspacket.cc
--- pdns-3.3.3/pdns/dnspacket.cc	2015-06-08 13:59:02.000000000 +0200
+++ pdns-3.3.3-tsig-165253.good/pdns/dnspacket.cc	2016-12-09 10:56:33.903270155 +0100
@@ -448,7 +448,7 @@
   
   bool gotit=false;
   for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {          
-    if(i->first.d_type == QType::TSIG) {
+    if(i->first.d_type == QType::TSIG && i->first.d_class == 0xff) {
       *trc = *boost::dynamic_pointer_cast<TSIGRecordContent>(i->first.d_content);
       
       gotit=true;
@@ -591,7 +591,10 @@
 {
   string message;
   
-  q->getTSIGDetails(trc, keyname, &message);
+  if (!q->getTSIGDetails(trc, keyname, &message)) {
+    return false;
+  }
+
   uint64_t now = time(0);
   if(abs(trc->d_time - now) > trc->d_fudge) {
     L<<Logger::Error<<"Packet for '"<<q->qdomain<<"' denied: TSIG (key '"<<*keyname<<"') time delta "<< abs(trc->d_time - now)<<" > 'fudge' "<<trc->d_fudge<<endl;
@@ -617,7 +620,7 @@
   }
 
   B64Decode(secret64, *secret);
-  bool result=calculateMD5HMAC(*secret, message) == trc->d_mac;
+  bool result=constantTimeStringEquals(calculateMD5HMAC(*secret, message), trc->d_mac);
   if(!result) {
     L<<Logger::Error<<"Packet for domain '"<<q->qdomain<<"' denied: TSIG signature mismatch using '"<<*keyname<<"' and algorithm '"<<trc->d_algoName<<"'"<<endl;
   }
diff -ru pdns-3.3.3/pdns/dnsparser.cc pdns-3.3.3-tsig-165253.good/pdns/dnsparser.cc
--- pdns-3.3.3/pdns/dnsparser.cc	2015-06-08 13:59:02.000000000 +0200
+++ pdns-3.3.3-tsig-165253.good/pdns/dnsparser.cc	2016-12-09 10:56:00.704326701 +0100
@@ -256,8 +256,12 @@
       dr.d_content=boost::shared_ptr<DNSRecordContent>(DNSRecordContent::mastermake(dr, pr));
       d_answers.push_back(make_pair(dr, pr.d_pos));
 
-      if(dr.d_type == QType::TSIG && dr.d_class == 0xff) 
+      if(dr.d_type == QType::TSIG && dr.d_class == 0xff) {
+        if(dr.d_place != DNSRecord::Additional || n != (unsigned int)(d_header.ancount + d_header.nscount + d_header.arcount) - 1) {
+          throw MOADNSException("Packet ("+d_qname+"|#"+lexical_cast<string>(d_qtype)+") has a TSIG record in an invalid position.");
+        }
         d_tsigPos = recordStartPos + sizeof(struct dnsheader);
+      }
     }
 
 #if 0    
diff -ru pdns-3.3.3/pdns/dnsparser.hh pdns-3.3.3-tsig-165253.good/pdns/dnsparser.hh
--- pdns-3.3.3/pdns/dnsparser.hh	2015-06-08 13:59:02.000000000 +0200
+++ pdns-3.3.3-tsig-165253.good/pdns/dnsparser.hh	2016-12-09 10:56:00.984317614 +0100
@@ -327,7 +327,7 @@
     return pr;
   }
 
-  uint16_t getTSIGPos()
+  uint16_t getTSIGPos() const
   {
     return d_tsigPos;
   }
diff -ru pdns-3.3.3/pdns/dnssecinfra.cc pdns-3.3.3-tsig-165253.good/pdns/dnssecinfra.cc
--- pdns-3.3.3/pdns/dnssecinfra.cc	2015-06-08 13:59:02.000000000 +0200
+++ pdns-3.3.3-tsig-165253.good/pdns/dnssecinfra.cc	2016-12-09 10:56:01.330973043 +0100
@@ -454,6 +454,23 @@
   return md5_2.get();
 }
 
+bool constantTimeStringEquals(const std::string& a, const std::string& b)
+{
+  if (a.size() != b.size()) {
+    return false;
+  }
+  const size_t size = a.size();
+  const volatile unsigned char *_a = (const volatile unsigned char *) a.c_str();
+  const volatile unsigned char *_b = (const volatile unsigned char *) b.c_str();
+  unsigned char res = 0;
+
+  for (size_t idx = 0; idx < size; idx++) {
+    res |= _a[idx] ^ _b[idx];
+  }
+
+  return res == 0;
+}
+
 string makeTSIGMessageFromTSIGPacket(const string& opacket, unsigned int tsigOffset, const string& keyname, const TSIGRecordContent& trc, const string& previous, bool timersonly, unsigned int dnsHeaderOffset)
 {
   string message;
diff -ru pdns-3.3.3/pdns/dnssecinfra.hh pdns-3.3.3-tsig-165253.good/pdns/dnssecinfra.hh
--- pdns-3.3.3/pdns/dnssecinfra.hh	2015-06-08 13:59:02.000000000 +0200
+++ pdns-3.3.3-tsig-165253.good/pdns/dnssecinfra.hh	2016-12-09 10:56:01.730960079 +0100
@@ -129,6 +129,7 @@
 void addRRSigs(DNSSECKeeper& dk, DNSBackend& db, const std::set<string, CIStringCompare>& authMap, vector<DNSResourceRecord>& rrs);
 
 string calculateMD5HMAC(const std::string& key_, const std::string& text);
+bool constantTimeStringEquals(const std::string& a, const std::string& b);
 string makeTSIGMessageFromTSIGPacket(const string& opacket, unsigned int tsigoffset, const string& keyname, const TSIGRecordContent& trc, const string& previous, bool timersonly, unsigned int dnsHeaderOffset=0);
 void addTSIG(DNSPacketWriter& pw, TSIGRecordContent* trc, const string& tsigkeyname, const string& tsigsecret, const string& tsigprevious, bool timersonly);
 
diff -ru pdns-3.3.3/pdns/resolver.cc pdns-3.3.3-tsig-165253.good/pdns/resolver.cc
--- pdns-3.3.3/pdns/resolver.cc	2015-06-08 13:59:04.000000000 +0200
+++ pdns-3.3.3-tsig-165253.good/pdns/resolver.cc	2016-12-09 10:56:02.090948414 +0100
@@ -416,6 +416,7 @@
         shared_ptr<TSIGRecordContent> trc = boost::dynamic_pointer_cast<TSIGRecordContent>(answer.first.d_content);
         theirMac = trc->d_mac;
         d_trc.d_time = trc->d_time;
+        d_trc.d_fudge = trc->d_fudge;
         checkTSIG = true;
       }
     }
@@ -428,6 +429,11 @@
       if (theirMac.empty())
         throw ResolverException("No TSIG on AXFR response from "+d_remote.toStringWithPort()+" , should be signed with TSIG key '"+d_tsigkeyname+"'");
 
+      uint64_t delta = std::abs((int64_t)d_trc.d_time - (int64_t)time(0));
+      if(delta > d_trc.d_fudge) {
+        throw ResolverException("Invalid TSIG time delta " + lexical_cast<string>(delta) + " >  fudge " + lexical_cast<string>(d_trc.d_fudge));
+      }
+
       string message;
       if (!d_prevMac.empty()) {
         message = makeTSIGMessageFromTSIGPacket(d_signData, d_tsigPos, d_tsigkeyname, d_trc, d_prevMac, true, d_signData.size()-len);
@@ -437,7 +443,7 @@
       string ourMac=calculateMD5HMAC(d_tsigsecret, message);
 
       // ourMac[0]++; // sabotage == for testing :-)
-      if(ourMac != theirMac) {
+      if(!constantTimeStringEquals(ourMac, theirMac)) {
         throw ResolverException("Signature failed to validate on AXFR response from "+d_remote.toStringWithPort()+" signed with TSIG key '"+d_tsigkeyname+"'");
       }
 
diff -ru pdns-3.3.3/pdns/tcpreceiver.cc pdns-3.3.3-tsig-165253.good/pdns/tcpreceiver.cc
--- pdns-3.3.3/pdns/tcpreceiver.cc	2015-06-08 13:59:04.000000000 +0200
+++ pdns-3.3.3-tsig-165253.good/pdns/tcpreceiver.cc	2016-12-09 10:56:02.617598028 +0100
@@ -553,9 +553,9 @@
   TSIGRecordContent trc;
   string tsigkeyname, tsigsecret;
 
-  q->getTSIGDetails(&trc, &tsigkeyname, 0);
+  bool haveTSIGDetails = q->getTSIGDetails(&trc, &tsigkeyname, 0);
 
-  if(!tsigkeyname.empty()) {
+  if(haveTSIGDetails && !tsigkeyname.empty()) {
     string tsig64, algorithm;
     Lock l(&s_plock);
     s_P->getBackend()->getTSIGKey(tsigkeyname, &algorithm, &tsig64);
@@ -576,7 +576,7 @@
     addRRSigs(dk, signatureDB, authSet, outpacket->getRRS());
   }
   
-  if(!tsigkeyname.empty())
+  if(haveTSIGDetails && !tsigkeyname.empty())
     outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac); // first answer is 'normal'
   
   sendPacket(outpacket, outsock);
@@ -684,7 +684,7 @@
       for(;;) {
         outpacket->getRRS() = csp.getChunk();
         if(!outpacket->getRRS().empty()) {
-          if(!tsigkeyname.empty()) 
+          if(haveTSIGDetails && !tsigkeyname.empty()) 
             outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
           sendPacket(outpacket, outsock);
           trc.d_mac=outpacket->d_trc.d_mac;
@@ -735,7 +735,7 @@
             for(;;) {
               outpacket->getRRS() = csp.getChunk();
               if(!outpacket->getRRS().empty()) {
-                if(!tsigkeyname.empty())
+                if(haveTSIGDetails && !tsigkeyname.empty())
                   outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
                 sendPacket(outpacket, outsock);
                 trc.d_mac=outpacket->d_trc.d_mac;
@@ -770,7 +770,7 @@
         for(;;) {
           outpacket->getRRS() = csp.getChunk();
           if(!outpacket->getRRS().empty()) {
-            if(!tsigkeyname.empty())
+            if(haveTSIGDetails && !tsigkeyname.empty())
               outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true); 
             sendPacket(outpacket, outsock);
             trc.d_mac=outpacket->d_trc.d_mac;
@@ -791,7 +791,7 @@
   for(;;) { 
     outpacket->getRRS() = csp.getChunk(true); // flush the pipe
     if(!outpacket->getRRS().empty()) {
-      if(!tsigkeyname.empty())
+      if(haveTSIGDetails && !tsigkeyname.empty())
         outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true); // first answer is 'normal'
       sendPacket(outpacket, outsock);
       trc.d_mac=outpacket->d_trc.d_mac;
@@ -810,7 +810,7 @@
   outpacket=getFreshAXFRPacket(q);
   outpacket->addRecord(soa);
   editSOA(dk, sd.qname, outpacket.get());
-  if(!tsigkeyname.empty())
+  if(haveTSIGDetails && !tsigkeyname.empty())
     outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true); 
   
   sendPacket(outpacket, outsock);
