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) {
{
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;
}
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;
}
break;
};
default:
- throw new PDNSException("Unknown hash algorithm requested for SHA");
+ throw PDNSException("Unknown hash algorithm requested for SHA");
};
return res;
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;
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;
}
}
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);
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+"'");
}
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")
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);
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;
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;
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;
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;
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);
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")
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);