2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include "dnsparser.hh"
28 #include "dnswriter.hh"
29 #include "dnsrecords.hh"
35 #include <boost/algorithm/string.hpp>
36 #include "dnssecinfra.hh"
37 #include "dnsseckeeper.hh"
38 #include <openssl/hmac.h>
39 #include <openssl/sha.h>
40 #include <boost/assign/std/vector.hpp> // for 'operator+=()'
41 #include <boost/assign/list_inserter.hpp>
43 #include "namespaces.hh"
45 #include "pkcs11signers.hh"
47 #include "gss_context.hh"
50 using namespace boost::assign
;
52 shared_ptr
<DNSCryptoKeyEngine
> DNSCryptoKeyEngine::makeFromISCFile(DNSKEYRecordContent
& drc
, const char* fname
)
55 FILE *fp
=fopen(fname
, "r");
57 throw runtime_error("Unable to read file '"+string(fname
)+"' for generating DNS Private Key");
60 while(stringfgets(fp
, sline
)) {
64 shared_ptr
<DNSCryptoKeyEngine
> dke
= makeFromISCString(drc
, isc
);
65 if(!dke
->checkKey()) {
66 throw runtime_error("Invalid DNS Private Key in file '"+string(fname
));
71 shared_ptr
<DNSCryptoKeyEngine
> DNSCryptoKeyEngine::makeFromISCString(DNSKEYRecordContent
& drc
, const std::string
& content
)
75 string sline
, key
, value
, raw
;
76 std::istringstream
str(content
);
77 map
<string
, string
> stormap
;
79 while(std::getline(str
, sline
)) {
80 tie(key
,value
)=splitField(sline
, ':');
82 if(pdns_iequals(key
,"algorithm")) {
83 algorithm
= pdns_stou(value
);
84 stormap
["algorithm"]=std::to_string(algorithm
);
86 } else if (pdns_iequals(key
,"pin")) {
89 } else if (pdns_iequals(key
,"engine")) {
90 stormap
["engine"]=value
;
93 } else if (pdns_iequals(key
,"slot")) {
94 stormap
["slot"]=value
;
96 } else if (pdns_iequals(key
,"label")) {
97 stormap
["label"]=value
;
99 } else if (pdns_iequals(key
,"publabel")) {
100 stormap
["publabel"]=value
;
103 else if(pdns_iequals(key
, "Private-key-format"))
106 B64Decode(value
, raw
);
107 stormap
[toLower(key
)]=raw
;
109 shared_ptr
<DNSCryptoKeyEngine
> dpk
;
113 if (stormap
.find("slot") == stormap
.end())
114 throw PDNSException("Cannot load PKCS#11 key, no Slot specified");
115 // we need PIN to be at least empty
116 if (stormap
.find("pin") == stormap
.end()) stormap
["pin"] = "";
117 dpk
= PKCS11DNSCryptoKeyEngine::maker(algorithm
);
119 throw PDNSException("Cannot load PKCS#11 key without support for it");
124 dpk
->fromISCMap(drc
, stormap
);
128 std::string
DNSCryptoKeyEngine::convertToISC() const
130 storvector_t stormap
= this->convertToISCVector();
132 ret
<<"Private-key-format: v1.2\n";
133 for(const stormap_t::value_type
& value
: stormap
) {
134 if(value
.first
!= "Algorithm" && value
.first
!= "PIN" &&
135 value
.first
!= "Slot" && value
.first
!= "Engine" &&
136 value
.first
!= "Label" && value
.first
!= "PubLabel")
137 ret
<<value
.first
<<": "<<Base64Encode(value
.second
)<<"\n";
139 ret
<<value
.first
<<": "<<value
.second
<<"\n";
144 shared_ptr
<DNSCryptoKeyEngine
> DNSCryptoKeyEngine::make(unsigned int algo
)
146 const makers_t
& makers
= getMakers();
147 makers_t::const_iterator iter
= makers
.find(algo
);
148 if(iter
!= makers
.cend())
149 return (iter
->second
)(algo
);
151 throw runtime_error("Request to create key object for unknown algorithm number "+std::to_string(algo
));
156 * Returns the supported DNSSEC algorithms with the name of the Crypto Backend used
158 * @return A vector with pairs of (algorithm-number (int), backend-name (string))
160 vector
<pair
<uint8_t, string
>> DNSCryptoKeyEngine::listAllAlgosWithBackend()
162 vector
<pair
<uint8_t, string
>> ret
;
163 for (auto const& value
: getMakers()) {
164 shared_ptr
<DNSCryptoKeyEngine
> dcke(value
.second(value
.first
));
165 ret
.push_back(make_pair(value
.first
, dcke
->getName()));
170 void DNSCryptoKeyEngine::report(unsigned int algo
, maker_t
* maker
, bool fallback
)
172 getAllMakers()[algo
].push_back(maker
);
173 if(getMakers().count(algo
) && fallback
) {
176 getMakers()[algo
]=maker
;
179 bool DNSCryptoKeyEngine::testAll()
183 for(const allmakers_t::value_type
& value
: getAllMakers())
185 for(maker_t
* creator
: value
.second
) {
187 for(maker_t
* signer
: value
.second
) {
188 // multi_map<unsigned int, maker_t*> bestSigner, bestVerifier;
190 for(maker_t
* verifier
: value
.second
) {
192 /* pair<unsigned int, unsigned int> res=*/ testMakers(value
.first
, creator
, signer
, verifier
);
194 catch(std::exception
& e
)
196 cerr
<<e
.what()<<endl
;
206 bool DNSCryptoKeyEngine::testOne(int algo
)
210 for(maker_t
* creator
: getAllMakers()[algo
]) {
212 for(maker_t
* signer
: getAllMakers()[algo
]) {
213 // multi_map<unsigned int, maker_t*> bestSigner, bestVerifier;
215 for(maker_t
* verifier
: getAllMakers()[algo
]) {
217 /* pair<unsigned int, unsigned int> res=*/testMakers(algo
, creator
, signer
, verifier
);
219 catch(std::exception
& e
)
221 cerr
<<e
.what()<<endl
;
229 // returns times it took to sign and verify
230 pair
<unsigned int, unsigned int> DNSCryptoKeyEngine::testMakers(unsigned int algo
, maker_t
* creator
, maker_t
* signer
, maker_t
* verifier
)
232 shared_ptr
<DNSCryptoKeyEngine
> dckeCreate(creator(algo
));
233 shared_ptr
<DNSCryptoKeyEngine
> dckeSign(signer(algo
));
234 shared_ptr
<DNSCryptoKeyEngine
> dckeVerify(verifier(algo
));
236 cerr
<<"Testing algorithm "<<algo
<<": '"<<dckeCreate
->getName()<<"' ->'"<<dckeSign
->getName()<<"' -> '"<<dckeVerify
->getName()<<"' ";
240 else if(algo
== DNSSECKeeper::ECCGOST
|| algo
== DNSSECKeeper::ECDSA256
|| algo
== DNSSECKeeper::ED25519
)
242 else if(algo
== DNSSECKeeper::ECDSA384
)
244 else if(algo
== DNSSECKeeper::ED448
)
247 throw runtime_error("Can't guess key size for algorithm "+std::to_string(algo
));
249 dckeCreate
->create(bits
);
251 { // FIXME: this block copy/pasted from makeFromISCString
252 DNSKEYRecordContent dkrc
;
254 string sline
, key
, value
, raw
;
255 std::istringstream
str(dckeCreate
->convertToISC());
256 map
<string
, string
> stormap
;
258 while(std::getline(str
, sline
)) {
259 tie(key
,value
)=splitField(sline
, ':');
261 if(pdns_iequals(key
,"algorithm")) {
262 algorithm
= pdns_stou(value
);
263 stormap
["algorithm"]=std::to_string(algorithm
);
265 } else if (pdns_iequals(key
,"pin")) {
266 stormap
["pin"]=value
;
268 } else if (pdns_iequals(key
,"engine")) {
269 stormap
["engine"]=value
;
271 } else if (pdns_iequals(key
,"slot")) {
272 int slot
= std::stoi(value
);
273 stormap
["slot"]=std::to_string(slot
);
275 } else if (pdns_iequals(key
,"label")) {
276 stormap
["label"]=value
;
279 else if(pdns_iequals(key
, "Private-key-format"))
282 B64Decode(value
, raw
);
283 stormap
[toLower(key
)]=raw
;
285 dckeSign
->fromISCMap(dkrc
, stormap
);
286 if(!dckeSign
->checkKey()) {
287 throw runtime_error("Verification of key with creator "+dckeCreate
->getName()+" with signer "+dckeSign
->getName()+" and verifier "+dckeVerify
->getName()+" failed");
291 string
message("Hi! How is life?");
295 for(unsigned int n
= 0; n
< 100; ++n
)
296 signature
= dckeSign
->sign(message
);
297 unsigned int udiffSign
= dt
.udiff()/100, udiffVerify
;
299 dckeVerify
->fromPublicKeyString(dckeSign
->getPublicKeyString());
300 if (dckeVerify
->getPublicKeyString().compare(dckeSign
->getPublicKeyString())) {
301 throw runtime_error("Comparison of public key loaded into verifier produced by signer failed");
304 if(dckeVerify
->verify(message
, signature
)) {
305 udiffVerify
= dt
.udiff();
306 cerr
<<"Signature & verify ok, signature "<<udiffSign
<<"usec, verify "<<udiffVerify
<<"usec"<<endl
;
309 throw runtime_error("Verification of creator "+dckeCreate
->getName()+" with signer "+dckeSign
->getName()+" and verifier "+dckeVerify
->getName()+" failed");
311 return make_pair(udiffSign
, udiffVerify
);
314 shared_ptr
<DNSCryptoKeyEngine
> DNSCryptoKeyEngine::makeFromPublicKeyString(unsigned int algorithm
, const std::string
& content
)
316 shared_ptr
<DNSCryptoKeyEngine
> dpk
=make(algorithm
);
317 dpk
->fromPublicKeyString(content
);
322 shared_ptr
<DNSCryptoKeyEngine
> DNSCryptoKeyEngine::makeFromPEMString(DNSKEYRecordContent
& drc
, const std::string
& raw
)
325 for(const makers_t::value_type
& val
: getMakers())
327 shared_ptr
<DNSCryptoKeyEngine
> ret
=nullptr;
329 ret
= val
.second(val
.first
);
330 ret
->fromPEMString(drc
, raw
);
341 static bool sharedDNSSECCompare(const shared_ptr
<DNSRecordContent
>& a
, const shared_ptr
<DNSRecordContent
>& b
)
343 return a
->serialize(g_rootdnsname
, true, true) < b
->serialize(g_rootdnsname
, true, true);
347 * Returns the string that should be hashed to create/verify the RRSIG content
349 * @param qname DNSName of the RRSIG's owner name.
350 * @param rrc The RRSIGRecordContent we take the Type Covered and
351 * original TTL fields from.
352 * @param signRecords A vector of DNSRecordContent shared_ptr's that are covered
353 * by the RRSIG, where we get the RDATA from.
354 * @param processRRSIGLabels A boolean to trigger processing the RRSIG's "Labels"
355 * field. This is usually only needed for validation
356 * purposes, as the authoritative server correctly
357 * sets qname to the wildcard.
359 string
getMessageForRRSET(const DNSName
& qname
, const RRSIGRecordContent
& rrc
, vector
<shared_ptr
<DNSRecordContent
> >& signRecords
, bool processRRSIGLabels
)
361 sort(signRecords
.begin(), signRecords
.end(), sharedDNSSECCompare
);
364 toHash
.append(const_cast<RRSIGRecordContent
&>(rrc
).serialize(g_rootdnsname
, true, true));
365 toHash
.resize(toHash
.size() - rrc
.d_signature
.length()); // chop off the end, don't sign the signature!
367 string
nameToHash(qname
.toDNSStringLC());
369 if (processRRSIGLabels
) {
370 unsigned int rrsig_labels
= rrc
.d_labels
;
371 unsigned int fqdn_labels
= qname
.countLabels();
373 if (rrsig_labels
< fqdn_labels
) {
374 DNSName
choppedQname(qname
);
375 while (choppedQname
.countLabels() > rrsig_labels
)
376 choppedQname
.chopOff();
377 nameToHash
= "\x01*" + choppedQname
.toDNSStringLC();
378 } else if (rrsig_labels
> fqdn_labels
) {
379 // The RRSIG Labels field is a lie (or the qname is wrong) and the RRSIG
380 // can never be valid
385 for(shared_ptr
<DNSRecordContent
>& add
: signRecords
) {
386 toHash
.append(nameToHash
);
387 uint16_t tmp
=htons(rrc
.d_type
);
388 toHash
.append((char*)&tmp
, 2);
389 tmp
=htons(1); // class
390 toHash
.append((char*)&tmp
, 2);
391 uint32_t ttl
=htonl(rrc
.d_originalttl
);
392 toHash
.append((char*)&ttl
, 4);
393 // for NSEC signatures, we should not lowercase the rdata section
394 string rdata
=add
->serialize(g_rootdnsname
, true, (add
->getType() == QType::NSEC
) ? false : true); // RFC 6840, 5.1
395 tmp
=htons(rdata
.length());
396 toHash
.append((char*)&tmp
, 2);
397 toHash
.append(rdata
);
403 bool DNSCryptoKeyEngine::isAlgorithmSupported(unsigned int algo
)
405 const makers_t
& makers
= getMakers();
406 makers_t::const_iterator iter
= makers
.find(algo
);
407 return iter
!= makers
.cend();
410 static unsigned int digestToAlgorithmNumber(uint8_t digest
)
413 case DNSSECKeeper::SHA1
:
414 return DNSSECKeeper::RSASHA1
;
415 case DNSSECKeeper::SHA256
:
416 return DNSSECKeeper::RSASHA256
;
417 case DNSSECKeeper::GOST
:
418 return DNSSECKeeper::ECCGOST
;
419 case DNSSECKeeper::SHA384
:
420 return DNSSECKeeper::ECDSA384
;
422 throw std::runtime_error("Unknown digest type " + std::to_string(digest
));
427 bool DNSCryptoKeyEngine::isDigestSupported(uint8_t digest
)
430 unsigned int algo
= digestToAlgorithmNumber(digest
);
431 return isAlgorithmSupported(algo
);
433 catch(const std::exception
& e
) {
438 DSRecordContent
makeDSFromDNSKey(const DNSName
& qname
, const DNSKEYRecordContent
& drc
, uint8_t digest
)
441 toHash
.assign(qname
.toDNSStringLC());
442 toHash
.append(const_cast<DNSKEYRecordContent
&>(drc
).serialize(DNSName(), true, true));
444 DSRecordContent dsrc
;
446 unsigned int algo
= digestToAlgorithmNumber(digest
);
447 shared_ptr
<DNSCryptoKeyEngine
> dpk(DNSCryptoKeyEngine::make(algo
));
448 dsrc
.d_digest
= dpk
->hash(toHash
);
450 catch(const std::exception
& e
) {
451 throw std::runtime_error("Asked to create (C)DS record of unknown digest type " + std::to_string(digest
));
454 dsrc
.d_algorithm
= drc
.d_algorithm
;
455 dsrc
.d_digesttype
= digest
;
456 dsrc
.d_tag
= const_cast<DNSKEYRecordContent
&>(drc
).getTag();
462 static DNSKEYRecordContent
makeDNSKEYFromDNSCryptoKeyEngine(const std::shared_ptr
<DNSCryptoKeyEngine
>& pk
, uint8_t algorithm
, uint16_t flags
)
464 DNSKEYRecordContent drc
;
467 drc
.d_algorithm
= algorithm
;
470 drc
.d_key
= pk
->getPublicKeyString();
475 uint32_t getStartOfWeek()
477 uint32_t now
= time(0);
478 now
-= (now
% (7*86400));
482 string
hashQNameWithSalt(const NSEC3PARAMRecordContent
& ns3prc
, const DNSName
& qname
)
484 return hashQNameWithSalt(ns3prc
.d_salt
, ns3prc
.d_iterations
, qname
);
487 string
hashQNameWithSalt(const std::string
& salt
, unsigned int iterations
, const DNSName
& qname
)
489 unsigned int times
= iterations
;
490 unsigned char hash
[20];
491 string
toHash(qname
.toDNSStringLC());
495 SHA1((unsigned char*)toHash
.c_str(), toHash
.length(), hash
);
496 toHash
.assign((char*)hash
, sizeof(hash
));
503 void incrementHash(std::string
& raw
) // I wonder if this is correct, cmouse? ;-)
508 for(string::size_type pos
=raw
.size(); pos
; ) {
510 unsigned char c
= (unsigned char)raw
[pos
];
518 void decrementHash(std::string
& raw
) // I wonder if this is correct, cmouse? ;-)
523 for(string::size_type pos
=raw
.size(); pos
; ) {
525 unsigned char c
= (unsigned char)raw
[pos
];
533 DNSKEYRecordContent
DNSSECPrivateKey::getDNSKEY() const
535 return makeDNSKEYFromDNSCryptoKeyEngine(getKey(), d_algorithm
, d_flags
);
541 DEREater(const std::string
& str
) : d_str(str
), d_pos(0)
548 if(d_pos
>= d_str
.length()) {
551 return (uint8_t) d_str
[d_pos
++];
556 uint8_t first
= getByte();
563 for(int n
=0; n
< first
; ++n
) {
570 std::string
getBytes(unsigned int len
)
573 for(unsigned int n
=0; n
< len
; ++n
)
574 ret
.append(1, (char)getByte());
578 std::string::size_type
getOffset()
583 const std::string
& d_str
;
584 std::string::size_type d_pos
;
587 static string
calculateHMAC(const std::string
& key
, const std::string
& text
, TSIGHashEnum hasher
) {
589 const EVP_MD
* md_type
;
591 unsigned char hash
[EVP_MAX_MD_SIZE
];
597 md_type
= EVP_sha1();
600 md_type
= EVP_sha224();
603 md_type
= EVP_sha256();
606 md_type
= EVP_sha384();
609 md_type
= EVP_sha512();
612 throw PDNSException("Unknown hash algorithm requested from calculateHMAC()");
615 unsigned char* out
= HMAC(md_type
, reinterpret_cast<const unsigned char*>(key
.c_str()), key
.size(), reinterpret_cast<const unsigned char*>(text
.c_str()), text
.size(), hash
, &outlen
);
616 if (out
== NULL
|| outlen
== 0) {
617 throw PDNSException("HMAC computation failed");
620 return string((char*) hash
, outlen
);
623 static bool constantTimeStringEquals(const std::string
& a
, const std::string
& b
)
625 if (a
.size() != b
.size()) {
628 const size_t size
= a
.size();
629 #if OPENSSL_VERSION_NUMBER >= 0x0090819fL
630 return CRYPTO_memcmp(a
.c_str(), b
.c_str(), size
) == 0;
632 const volatile unsigned char *_a
= (const volatile unsigned char *) a
.c_str();
633 const volatile unsigned char *_b
= (const volatile unsigned char *) b
.c_str();
634 unsigned char res
= 0;
636 for (size_t idx
= 0; idx
< size
; idx
++) {
637 res
|= _a
[idx
] ^ _b
[idx
];
644 static string
makeTSIGPayload(const string
& previous
, const char* packetBegin
, size_t packetSize
, const DNSName
& tsigKeyName
, const TSIGRecordContent
& trc
, bool timersonly
)
648 if(!previous
.empty()) {
649 uint16_t len
= htons(previous
.length());
650 message
.append(reinterpret_cast<const char*>(&len
), sizeof(len
));
651 message
.append(previous
);
654 message
.append(packetBegin
, packetSize
);
656 vector
<uint8_t> signVect
;
657 DNSPacketWriter
dw(signVect
, DNSName(), 0);
658 auto pos
=signVect
.size();
660 dw
.xfrName(tsigKeyName
, false);
661 dw
.xfr16BitInt(QClass::ANY
); // class
662 dw
.xfr32BitInt(0); // TTL
663 dw
.xfrName(trc
.d_algoName
.makeLowerCase(), false);
666 uint32_t now
= trc
.d_time
;
668 dw
.xfr16BitInt(trc
.d_fudge
); // fudge
670 dw
.xfr16BitInt(trc
.d_eRcode
); // extended rcode
671 dw
.xfr16BitInt(trc
.d_otherData
.length()); // length of 'other' data
672 // dw.xfrBlob(trc->d_otherData);
674 message
.append(signVect
.begin()+pos
, signVect
.end());
678 static string
makeTSIGMessageFromTSIGPacket(const string
& opacket
, unsigned int tsigOffset
, const DNSName
& keyname
, const TSIGRecordContent
& trc
, const string
& previous
, bool timersonly
, unsigned int dnsHeaderOffset
=0)
681 string
packet(opacket
);
683 packet
.resize(tsigOffset
); // remove the TSIG record at the end as per RFC2845 3.4.1
684 packet
[(dnsHeaderOffset
+ sizeof(struct dnsheader
))-1]--; // Decrease ARCOUNT because we removed the TSIG RR in the previous line.
687 // Replace the message ID with the original message ID from the TSIG record.
688 // This is needed for forwarded DNS Update as they get a new ID when forwarding (section 6.1 of RFC2136). The TSIG record stores the original ID and the
689 // signature was created with the original ID, so we replace it here to get the originally signed message.
690 // If the message is not forwarded, we simply override it with the same id.
691 uint16_t origID
= htons(trc
.d_origID
);
692 packet
.replace(0, 2, (char*)&origID
, 2);
694 return makeTSIGPayload(previous
, packet
.data(), packet
.size(), keyname
, trc
, timersonly
);
697 void addTSIG(DNSPacketWriter
& pw
, TSIGRecordContent
& trc
, const DNSName
& tsigkeyname
, const string
& tsigsecret
, const string
& tsigprevious
, bool timersonly
)
700 if (!getTSIGHashEnum(trc
.d_algoName
, algo
)) {
701 throw PDNSException(string("Unsupported TSIG HMAC algorithm ") + trc
.d_algoName
.toLogString());
704 string toSign
= makeTSIGPayload(tsigprevious
, reinterpret_cast<const char*>(pw
.getContent().data()), pw
.getContent().size(), tsigkeyname
, trc
, timersonly
);
706 if (algo
== TSIG_GSS
) {
707 if (!gss_add_signature(tsigkeyname
, toSign
, trc
.d_mac
)) {
708 throw PDNSException(string("Could not add TSIG signature with algorithm 'gss-tsig' and key name '")+tsigkeyname
.toLogString()+string("'"));
711 trc
.d_mac
= calculateHMAC(tsigsecret
, toSign
, algo
);
712 // trc.d_mac[0]++; // sabotage
714 pw
.startRecord(tsigkeyname
, QType::TSIG
, 0, QClass::ANY
, DNSResourceRecord::ADDITIONAL
, false);
719 bool validateTSIG(const std::string
& packet
, size_t sigPos
, const TSIGTriplet
& tt
, const TSIGRecordContent
& trc
, const std::string
& previousMAC
, const std::string
& theirMAC
, bool timersOnly
, unsigned int dnsHeaderOffset
)
721 uint64_t delta
= std::abs((int64_t)trc
.d_time
- (int64_t)time(nullptr));
722 if(delta
> trc
.d_fudge
) {
723 throw std::runtime_error("Invalid TSIG time delta " + std::to_string(delta
) + " > fudge " + std::to_string(trc
.d_fudge
));
727 if (!getTSIGHashEnum(trc
.d_algoName
, algo
)) {
728 throw std::runtime_error("Unsupported TSIG HMAC algorithm " + trc
.d_algoName
.toLogString());
731 TSIGHashEnum expectedAlgo
;
732 if (!getTSIGHashEnum(tt
.algo
, expectedAlgo
)) {
733 throw std::runtime_error("Unsupported TSIG HMAC algorithm expected " + tt
.algo
.toLogString());
736 if (algo
!= expectedAlgo
) {
737 throw std::runtime_error("Signature with TSIG key '"+tt
.name
.toLogString()+"' does not match the expected algorithm (" + tt
.algo
.toLogString() + " / " + trc
.d_algoName
.toLogString() + ")");
741 tsigMsg
= makeTSIGMessageFromTSIGPacket(packet
, sigPos
, tt
.name
, trc
, previousMAC
, timersOnly
, dnsHeaderOffset
);
743 if (algo
== TSIG_GSS
) {
744 GssContext
gssctx(tt
.name
);
745 if (!gss_verify_signature(tt
.name
, tsigMsg
, theirMAC
)) {
746 throw std::runtime_error("Signature with TSIG key '"+tt
.name
.toLogString()+"' failed to validate");
749 string ourMac
= calculateHMAC(tt
.secret
, tsigMsg
, algo
);
751 if(!constantTimeStringEquals(ourMac
, theirMAC
)) {
752 throw std::runtime_error("Signature with TSIG key '"+tt
.name
.toLogString()+"' failed to validate");