File pdns-3.4.10-tsig-165253_port.patch of Package pdns.6226
Index: pdns-3.4.9/pdns/dnspacket.cc
===================================================================
--- pdns-3.4.9.orig/pdns/dnspacket.cc
+++ pdns-3.4.9/pdns/dnspacket.cc
@@ -466,7 +466,7 @@ bool DNSPacket::getTSIGDetails(TSIGRecor
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 == QType::ANY) {
// cast can fail, f.e. if d_content is an UnknownRecordContent.
shared_ptr<TSIGRecordContent> content = boost::dynamic_pointer_cast<TSIGRecordContent>(i->first.d_content);
if (!content) {
@@ -643,7 +643,10 @@ bool checkForCorrectTSIG(const DNSPacket
{
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;
@@ -669,7 +672,7 @@ bool checkForCorrectTSIG(const DNSPacket
}
B64Decode(secret64, *secret);
- bool result=calculateHMAC(*secret, message, algo) == trc->d_mac;
+ bool result=constantTimeStringEquals(calculateHMAC(*secret, message, algo), 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;
}
Index: pdns-3.4.9/pdns/dnsparser.cc
===================================================================
--- pdns-3.4.9.orig/pdns/dnsparser.cc
+++ pdns-3.4.9/pdns/dnsparser.cc
@@ -287,8 +287,12 @@ void MOADNSParser::init(bool query, cons
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 == QClass::ANY) {
+ 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
Index: pdns-3.4.9/pdns/dnsparser.hh
===================================================================
--- pdns-3.4.9.orig/pdns/dnsparser.hh
+++ pdns-3.4.9/pdns/dnsparser.hh
@@ -335,7 +335,7 @@ public:
return pr;
}
- uint16_t getTSIGPos()
+ uint16_t getTSIGPos() const
{
return d_tsigPos;
}
Index: pdns-3.4.9/pdns/dnssecinfra.cc
===================================================================
--- pdns-3.4.9.orig/pdns/dnssecinfra.cc
+++ pdns-3.4.9/pdns/dnssecinfra.cc
@@ -516,7 +516,7 @@ string calculateSHAHMAC(const std::strin
break;
};
default:
- throw new PDNSException("Unknown hash algorithm requested for SHA");
+ throw PDNSException("Unknown hash algorithm requested for SHA");
};
return res;
@@ -530,6 +530,23 @@ string calculateHMAC(const std::string&
return calculateSHAHMAC(key, text, hash);
}
+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;
Index: pdns-3.4.9/pdns/dnssecinfra.hh
===================================================================
--- pdns-3.4.9.orig/pdns/dnssecinfra.hh
+++ pdns-3.4.9/pdns/dnssecinfra.hh
@@ -134,6 +134,7 @@ typedef enum { TSIG_MD5, TSIG_SHA1, TSIG
string calculateMD5HMAC(const std::string& key, const std::string& text);
string calculateSHAHMAC(const std::string& key, const std::string& text, TSIGHashEnum hash);
string calculateHMAC(const std::string& key, const std::string& text, TSIGHashEnum hash);
+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);
bool getTSIGHashEnum(const string &algoName, TSIGHashEnum& algoEnum);
Index: pdns-3.4.9/pdns/resolver.cc
===================================================================
--- pdns-3.4.9.orig/pdns/resolver.cc
+++ pdns-3.4.9/pdns/resolver.cc
@@ -493,6 +493,7 @@ int AXFRRetriever::getChunk(Resolver::re
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;
}
}
@@ -505,6 +506,11 @@ int AXFRRetriever::getChunk(Resolver::re
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);
@@ -520,7 +526,7 @@ int AXFRRetriever::getChunk(Resolver::re
string ourMac=calculateHMAC(d_tsigsecret, message, algo);
// 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+"'");
}
Index: pdns-3.4.9/pdns/tcpreceiver.cc
===================================================================
--- pdns-3.4.9.orig/pdns/tcpreceiver.cc
+++ pdns-3.4.9/pdns/tcpreceiver.cc
@@ -590,9 +590,9 @@ int TCPNameserver::doAXFR(const string &
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;
string algorithm=toLowerCanonic(trc.d_algoName);
if (algorithm == "hmac-md5.sig-alg.reg.int")
@@ -616,7 +616,7 @@ int TCPNameserver::doAXFR(const string &
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);
@@ -799,7 +799,7 @@ int TCPNameserver::doAXFR(const string &
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;
@@ -850,7 +850,7 @@ int TCPNameserver::doAXFR(const string &
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;
@@ -885,7 +885,7 @@ int TCPNameserver::doAXFR(const string &
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;
@@ -906,7 +906,7 @@ int TCPNameserver::doAXFR(const string &
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;
@@ -925,7 +925,7 @@ int TCPNameserver::doAXFR(const string &
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);
@@ -1027,9 +1027,9 @@ int TCPNameserver::doIXFR(shared_ptr<DNS
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;
string algorithm=toLowerCanonic(trc.d_algoName);
if (algorithm == "hmac-md5.sig-alg.reg.int")
@@ -1052,7 +1052,7 @@ int TCPNameserver::doIXFR(shared_ptr<DNS
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);