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 auto fp
= std::unique_ptr
<FILE, int(*)(FILE*)>(fopen(fname
, "r"), fclose
);
57 throw runtime_error("Unable to read file '"+string(fname
)+"' for generating DNS Private Key");
60 while(stringfgets(fp
.get(), sline
)) {
65 shared_ptr
<DNSCryptoKeyEngine
> dke
= makeFromISCString(drc
, isc
);
66 vector
<string
> checkKeyErrors
;
68 if(!dke
->checkKey(&checkKeyErrors
)) {
70 if(checkKeyErrors
.size()) {
71 reason
= " ("+boost::algorithm::join(checkKeyErrors
, ", ")+")";
73 throw runtime_error("Invalid DNS Private Key in file '"+string(fname
)+"'"+reason
);
78 shared_ptr
<DNSCryptoKeyEngine
> DNSCryptoKeyEngine::makeFromISCString(DNSKEYRecordContent
& drc
, const std::string
& content
)
82 string sline
, key
, value
, raw
;
83 std::istringstream
str(content
);
84 map
<string
, string
> stormap
;
86 while(std::getline(str
, sline
)) {
87 tie(key
,value
)=splitField(sline
, ':');
89 if(pdns_iequals(key
,"algorithm")) {
90 algorithm
= pdns_stou(value
);
91 stormap
["algorithm"]=std::to_string(algorithm
);
93 } else if (pdns_iequals(key
,"pin")) {
96 } else if (pdns_iequals(key
,"engine")) {
97 stormap
["engine"]=value
;
100 } else if (pdns_iequals(key
,"slot")) {
101 stormap
["slot"]=value
;
103 } else if (pdns_iequals(key
,"label")) {
104 stormap
["label"]=value
;
106 } else if (pdns_iequals(key
,"publabel")) {
107 stormap
["publabel"]=value
;
110 else if(pdns_iequals(key
, "Private-key-format"))
113 B64Decode(value
, raw
);
114 stormap
[toLower(key
)]=raw
;
116 shared_ptr
<DNSCryptoKeyEngine
> dpk
;
120 if (stormap
.find("slot") == stormap
.end())
121 throw PDNSException("Cannot load PKCS#11 key, no Slot specified");
122 // we need PIN to be at least empty
123 if (stormap
.find("pin") == stormap
.end()) stormap
["pin"] = "";
124 dpk
= PKCS11DNSCryptoKeyEngine::maker(algorithm
);
126 throw PDNSException("Cannot load PKCS#11 key without support for it");
131 dpk
->fromISCMap(drc
, stormap
);
135 std::string
DNSCryptoKeyEngine::convertToISC() const
137 storvector_t storvector
= this->convertToISCVector();
139 ret
<<"Private-key-format: v1.2\n";
140 for(const storvector_t::value_type
& value
: storvector
) {
141 if(value
.first
!= "Algorithm" && value
.first
!= "PIN" &&
142 value
.first
!= "Slot" && value
.first
!= "Engine" &&
143 value
.first
!= "Label" && value
.first
!= "PubLabel")
144 ret
<<value
.first
<<": "<<Base64Encode(value
.second
)<<"\n";
146 ret
<<value
.first
<<": "<<value
.second
<<"\n";
151 shared_ptr
<DNSCryptoKeyEngine
> DNSCryptoKeyEngine::make(unsigned int algo
)
153 const makers_t
& makers
= getMakers();
154 makers_t::const_iterator iter
= makers
.find(algo
);
155 if(iter
!= makers
.cend())
156 return (iter
->second
)(algo
);
158 throw runtime_error("Request to create key object for unknown algorithm number "+std::to_string(algo
));
163 * Returns the supported DNSSEC algorithms with the name of the Crypto Backend used
165 * @return A vector with pairs of (algorithm-number (int), backend-name (string))
167 vector
<pair
<uint8_t, string
>> DNSCryptoKeyEngine::listAllAlgosWithBackend()
169 vector
<pair
<uint8_t, string
>> ret
;
170 for (auto const& value
: getMakers()) {
171 shared_ptr
<DNSCryptoKeyEngine
> dcke(value
.second(value
.first
));
172 ret
.push_back(make_pair(value
.first
, dcke
->getName()));
177 void DNSCryptoKeyEngine::report(unsigned int algo
, maker_t
* maker
, bool fallback
)
179 getAllMakers()[algo
].push_back(maker
);
180 if(getMakers().count(algo
) && fallback
) {
183 getMakers()[algo
]=maker
;
186 bool DNSCryptoKeyEngine::testAll()
190 for(const allmakers_t::value_type
& value
: getAllMakers())
192 for(maker_t
* creator
: value
.second
) {
194 for(maker_t
* signer
: value
.second
) {
195 // multi_map<unsigned int, maker_t*> bestSigner, bestVerifier;
197 for(maker_t
* verifier
: value
.second
) {
199 testMakers(value
.first
, creator
, signer
, verifier
);
201 catch(std::exception
& e
)
203 cerr
<<e
.what()<<endl
;
213 bool DNSCryptoKeyEngine::testOne(int algo
)
217 for(maker_t
* creator
: getAllMakers()[algo
]) {
219 for(maker_t
* signer
: getAllMakers()[algo
]) {
220 // multi_map<unsigned int, maker_t*> bestSigner, bestVerifier;
222 for(maker_t
* verifier
: getAllMakers()[algo
]) {
224 testMakers(algo
, creator
, signer
, verifier
);
226 catch(std::exception
& e
)
228 cerr
<<e
.what()<<endl
;
237 void DNSCryptoKeyEngine::testMakers(unsigned int algo
, maker_t
* creator
, maker_t
* signer
, maker_t
* verifier
)
239 shared_ptr
<DNSCryptoKeyEngine
> dckeCreate(creator(algo
));
240 shared_ptr
<DNSCryptoKeyEngine
> dckeSign(signer(algo
));
241 shared_ptr
<DNSCryptoKeyEngine
> dckeVerify(verifier(algo
));
243 cerr
<<"Testing algorithm "<<algo
<<": '"<<dckeCreate
->getName()<<"' ->'"<<dckeSign
->getName()<<"' -> '"<<dckeVerify
->getName()<<"' ";
247 else if(algo
== DNSSECKeeper::ECCGOST
|| algo
== DNSSECKeeper::ECDSA256
|| algo
== DNSSECKeeper::ED25519
)
249 else if(algo
== DNSSECKeeper::ECDSA384
)
251 else if(algo
== DNSSECKeeper::ED448
)
254 throw runtime_error("Can't guess key size for algorithm "+std::to_string(algo
));
257 for(unsigned int n
= 0; n
< 100; ++n
)
258 dckeCreate
->create(bits
);
259 cerr
<<"("<<dckeCreate
->getBits()<<" bits) ";
260 unsigned int udiffCreate
= dt
.udiff() / 100;
262 { // FIXME: this block copy/pasted from makeFromISCString
263 DNSKEYRecordContent dkrc
;
265 string sline
, key
, value
, raw
;
266 std::istringstream
str(dckeCreate
->convertToISC());
267 map
<string
, string
> stormap
;
269 while(std::getline(str
, sline
)) {
270 tie(key
,value
)=splitField(sline
, ':');
272 if(pdns_iequals(key
,"algorithm")) {
273 algorithm
= pdns_stou(value
);
274 stormap
["algorithm"]=std::to_string(algorithm
);
276 } else if (pdns_iequals(key
,"pin")) {
277 stormap
["pin"]=value
;
279 } else if (pdns_iequals(key
,"engine")) {
280 stormap
["engine"]=value
;
282 } else if (pdns_iequals(key
,"slot")) {
283 int slot
= std::stoi(value
);
284 stormap
["slot"]=std::to_string(slot
);
286 } else if (pdns_iequals(key
,"label")) {
287 stormap
["label"]=value
;
290 else if(pdns_iequals(key
, "Private-key-format"))
293 B64Decode(value
, raw
);
294 stormap
[toLower(key
)]=raw
;
296 dckeSign
->fromISCMap(dkrc
, stormap
);
297 if(!dckeSign
->checkKey()) {
298 throw runtime_error("Verification of key with creator "+dckeCreate
->getName()+" with signer "+dckeSign
->getName()+" and verifier "+dckeVerify
->getName()+" failed");
302 string
message("Hi! How is life?");
306 for(unsigned int n
= 0; n
< 100; ++n
)
307 signature
= dckeSign
->sign(message
);
308 unsigned int udiffSign
= dt
.udiff()/100, udiffVerify
;
310 dckeVerify
->fromPublicKeyString(dckeSign
->getPublicKeyString());
311 if (dckeVerify
->getPublicKeyString().compare(dckeSign
->getPublicKeyString())) {
312 throw runtime_error("Comparison of public key loaded into verifier produced by signer failed");
316 for(unsigned int n
= 0; n
< 100; ++n
)
317 verified
= dckeVerify
->verify(message
, signature
);
320 udiffVerify
= dt
.udiff() / 100;
321 cerr
<<"Signature & verify ok, create "<<udiffCreate
<<"usec, signature "<<udiffSign
<<"usec, verify "<<udiffVerify
<<"usec"<<endl
;
324 throw runtime_error("Verification of creator "+dckeCreate
->getName()+" with signer "+dckeSign
->getName()+" and verifier "+dckeVerify
->getName()+" failed");
328 shared_ptr
<DNSCryptoKeyEngine
> DNSCryptoKeyEngine::makeFromPublicKeyString(unsigned int algorithm
, const std::string
& content
)
330 shared_ptr
<DNSCryptoKeyEngine
> dpk
=make(algorithm
);
331 dpk
->fromPublicKeyString(content
);
336 shared_ptr
<DNSCryptoKeyEngine
> DNSCryptoKeyEngine::makeFromPEMString(DNSKEYRecordContent
& drc
, const std::string
& raw
)
339 for(const makers_t::value_type
& val
: getMakers())
341 shared_ptr
<DNSCryptoKeyEngine
> ret
=nullptr;
343 ret
= val
.second(val
.first
);
344 ret
->fromPEMString(drc
, raw
);
355 * Returns the string that should be hashed to create/verify the RRSIG content
357 * @param qname DNSName of the RRSIG's owner name.
358 * @param rrc The RRSIGRecordContent we take the Type Covered and
359 * original TTL fields from.
360 * @param signRecords A vector of DNSRecordContent shared_ptr's that are covered
361 * by the RRSIG, where we get the RDATA from.
362 * @param processRRSIGLabels A boolean to trigger processing the RRSIG's "Labels"
363 * field. This is usually only needed for validation
364 * purposes, as the authoritative server correctly
365 * sets qname to the wildcard.
367 string
getMessageForRRSET(const DNSName
& qname
, const RRSIGRecordContent
& rrc
, const sortedRecords_t
& signRecords
, bool processRRSIGLabels
)
370 toHash
.append(const_cast<RRSIGRecordContent
&>(rrc
).serialize(g_rootdnsname
, true, true));
371 toHash
.resize(toHash
.size() - rrc
.d_signature
.length()); // chop off the end, don't sign the signature!
373 string
nameToHash(qname
.toDNSStringLC());
375 if (processRRSIGLabels
) {
376 unsigned int rrsig_labels
= rrc
.d_labels
;
377 unsigned int fqdn_labels
= qname
.countLabels();
379 if (rrsig_labels
< fqdn_labels
) {
380 DNSName
choppedQname(qname
);
381 while (choppedQname
.countLabels() > rrsig_labels
)
382 choppedQname
.chopOff();
383 nameToHash
= "\x01*" + choppedQname
.toDNSStringLC();
384 } else if (rrsig_labels
> fqdn_labels
) {
385 // The RRSIG Labels field is a lie (or the qname is wrong) and the RRSIG
386 // can never be valid
391 for(const shared_ptr
<DNSRecordContent
>& add
: signRecords
) {
392 toHash
.append(nameToHash
);
393 uint16_t tmp
=htons(rrc
.d_type
);
394 toHash
.append((char*)&tmp
, 2);
395 tmp
=htons(1); // class
396 toHash
.append((char*)&tmp
, 2);
397 uint32_t ttl
=htonl(rrc
.d_originalttl
);
398 toHash
.append((char*)&ttl
, 4);
399 // for NSEC signatures, we should not lowercase the rdata section
400 string rdata
=add
->serialize(g_rootdnsname
, true, (add
->getType() == QType::NSEC
) ? false : true); // RFC 6840, 5.1
401 tmp
=htons(rdata
.length());
402 toHash
.append((char*)&tmp
, 2);
403 toHash
.append(rdata
);
409 bool DNSCryptoKeyEngine::isAlgorithmSupported(unsigned int algo
)
411 const makers_t
& makers
= getMakers();
412 makers_t::const_iterator iter
= makers
.find(algo
);
413 return iter
!= makers
.cend();
416 static unsigned int digestToAlgorithmNumber(uint8_t digest
)
419 case DNSSECKeeper::DIGEST_SHA1
:
420 return DNSSECKeeper::RSASHA1
;
421 case DNSSECKeeper::DIGEST_SHA256
:
422 return DNSSECKeeper::RSASHA256
;
423 case DNSSECKeeper::DIGEST_GOST
:
424 return DNSSECKeeper::ECCGOST
;
425 case DNSSECKeeper::DIGEST_SHA384
:
426 return DNSSECKeeper::ECDSA384
;
428 throw std::runtime_error("Unknown digest type " + std::to_string(digest
));
433 bool DNSCryptoKeyEngine::isDigestSupported(uint8_t digest
)
436 unsigned int algo
= digestToAlgorithmNumber(digest
);
437 return isAlgorithmSupported(algo
);
439 catch(const std::exception
& e
) {
444 DSRecordContent
makeDSFromDNSKey(const DNSName
& qname
, const DNSKEYRecordContent
& drc
, uint8_t digest
)
447 toHash
.assign(qname
.toDNSStringLC());
448 toHash
.append(const_cast<DNSKEYRecordContent
&>(drc
).serialize(DNSName(), true, true));
450 DSRecordContent dsrc
;
452 unsigned int algo
= digestToAlgorithmNumber(digest
);
453 shared_ptr
<DNSCryptoKeyEngine
> dpk(DNSCryptoKeyEngine::make(algo
));
454 dsrc
.d_digest
= dpk
->hash(toHash
);
456 catch(const std::exception
& e
) {
457 throw std::runtime_error("Asked to create (C)DS record of unknown digest type " + std::to_string(digest
));
460 dsrc
.d_algorithm
= drc
.d_algorithm
;
461 dsrc
.d_digesttype
= digest
;
462 dsrc
.d_tag
= const_cast<DNSKEYRecordContent
&>(drc
).getTag();
468 static DNSKEYRecordContent
makeDNSKEYFromDNSCryptoKeyEngine(const std::shared_ptr
<DNSCryptoKeyEngine
>& pk
, uint8_t algorithm
, uint16_t flags
)
470 DNSKEYRecordContent drc
;
473 drc
.d_algorithm
= algorithm
;
476 drc
.d_key
= pk
->getPublicKeyString();
481 uint32_t getStartOfWeek()
483 uint32_t now
= time(0);
484 now
-= (now
% (7*86400));
488 string
hashQNameWithSalt(const NSEC3PARAMRecordContent
& ns3prc
, const DNSName
& qname
)
490 return hashQNameWithSalt(ns3prc
.d_salt
, ns3prc
.d_iterations
, qname
);
493 string
hashQNameWithSalt(const std::string
& salt
, unsigned int iterations
, const DNSName
& qname
)
495 unsigned int times
= iterations
;
496 unsigned char hash
[20];
497 string
toHash(qname
.toDNSStringLC());
501 SHA1((unsigned char*)toHash
.c_str(), toHash
.length(), hash
);
502 toHash
.assign((char*)hash
, sizeof(hash
));
509 void incrementHash(std::string
& raw
) // I wonder if this is correct, cmouse? ;-)
514 for(string::size_type pos
=raw
.size(); pos
; ) {
516 unsigned char c
= (unsigned char)raw
[pos
];
524 void decrementHash(std::string
& raw
) // I wonder if this is correct, cmouse? ;-)
529 for(string::size_type pos
=raw
.size(); pos
; ) {
531 unsigned char c
= (unsigned char)raw
[pos
];
539 DNSKEYRecordContent
DNSSECPrivateKey::getDNSKEY() const
541 return makeDNSKEYFromDNSCryptoKeyEngine(getKey(), d_algorithm
, d_flags
);
547 DEREater(const std::string
& str
) : d_str(str
), d_pos(0)
554 if(d_pos
>= d_str
.length()) {
557 return (uint8_t) d_str
[d_pos
++];
562 uint8_t first
= getByte();
569 for(int n
=0; n
< first
; ++n
) {
576 std::string
getBytes(unsigned int len
)
579 for(unsigned int n
=0; n
< len
; ++n
)
580 ret
.append(1, (char)getByte());
584 std::string::size_type
getOffset()
589 const std::string
& d_str
;
590 std::string::size_type d_pos
;
593 static string
calculateHMAC(const std::string
& key
, const std::string
& text
, TSIGHashEnum hasher
) {
595 const EVP_MD
* md_type
;
597 unsigned char hash
[EVP_MAX_MD_SIZE
];
603 md_type
= EVP_sha1();
606 md_type
= EVP_sha224();
609 md_type
= EVP_sha256();
612 md_type
= EVP_sha384();
615 md_type
= EVP_sha512();
618 throw PDNSException("Unknown hash algorithm requested from calculateHMAC()");
621 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
);
622 if (out
== NULL
|| outlen
== 0) {
623 throw PDNSException("HMAC computation failed");
626 return string((char*) hash
, outlen
);
629 static bool constantTimeStringEquals(const std::string
& a
, const std::string
& b
)
631 if (a
.size() != b
.size()) {
634 const size_t size
= a
.size();
635 #ifdef HAVE_CRYPTO_MEMCMP
636 return CRYPTO_memcmp(a
.c_str(), b
.c_str(), size
) == 0;
638 const volatile unsigned char *_a
= (const volatile unsigned char *) a
.c_str();
639 const volatile unsigned char *_b
= (const volatile unsigned char *) b
.c_str();
640 unsigned char res
= 0;
642 for (size_t idx
= 0; idx
< size
; idx
++) {
643 res
|= _a
[idx
] ^ _b
[idx
];
650 static string
makeTSIGPayload(const string
& previous
, const char* packetBegin
, size_t packetSize
, const DNSName
& tsigKeyName
, const TSIGRecordContent
& trc
, bool timersonly
)
654 if(!previous
.empty()) {
655 uint16_t len
= htons(previous
.length());
656 message
.append(reinterpret_cast<const char*>(&len
), sizeof(len
));
657 message
.append(previous
);
660 message
.append(packetBegin
, packetSize
);
662 vector
<uint8_t> signVect
;
663 DNSPacketWriter
dw(signVect
, DNSName(), 0);
664 auto pos
=signVect
.size();
666 dw
.xfrName(tsigKeyName
, false);
667 dw
.xfr16BitInt(QClass::ANY
); // class
668 dw
.xfr32BitInt(0); // TTL
669 dw
.xfrName(trc
.d_algoName
.makeLowerCase(), false);
672 uint32_t now
= trc
.d_time
;
674 dw
.xfr16BitInt(trc
.d_fudge
); // fudge
676 dw
.xfr16BitInt(trc
.d_eRcode
); // extended rcode
677 dw
.xfr16BitInt(trc
.d_otherData
.length()); // length of 'other' data
678 // dw.xfrBlob(trc->d_otherData);
680 message
.append(signVect
.begin()+pos
, signVect
.end());
684 static string
makeTSIGMessageFromTSIGPacket(const string
& opacket
, unsigned int tsigOffset
, const DNSName
& keyname
, const TSIGRecordContent
& trc
, const string
& previous
, bool timersonly
, unsigned int dnsHeaderOffset
=0)
687 string
packet(opacket
);
689 packet
.resize(tsigOffset
); // remove the TSIG record at the end as per RFC2845 3.4.1
690 packet
[(dnsHeaderOffset
+ sizeof(struct dnsheader
))-1]--; // Decrease ARCOUNT because we removed the TSIG RR in the previous line.
693 // Replace the message ID with the original message ID from the TSIG record.
694 // 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
695 // signature was created with the original ID, so we replace it here to get the originally signed message.
696 // If the message is not forwarded, we simply override it with the same id.
697 uint16_t origID
= htons(trc
.d_origID
);
698 packet
.replace(0, 2, (char*)&origID
, 2);
700 return makeTSIGPayload(previous
, packet
.data(), packet
.size(), keyname
, trc
, timersonly
);
703 void addTSIG(DNSPacketWriter
& pw
, TSIGRecordContent
& trc
, const DNSName
& tsigkeyname
, const string
& tsigsecret
, const string
& tsigprevious
, bool timersonly
)
706 if (!getTSIGHashEnum(trc
.d_algoName
, algo
)) {
707 throw PDNSException(string("Unsupported TSIG HMAC algorithm ") + trc
.d_algoName
.toLogString());
710 string toSign
= makeTSIGPayload(tsigprevious
, reinterpret_cast<const char*>(pw
.getContent().data()), pw
.getContent().size(), tsigkeyname
, trc
, timersonly
);
712 if (algo
== TSIG_GSS
) {
713 if (!gss_add_signature(tsigkeyname
, toSign
, trc
.d_mac
)) {
714 throw PDNSException(string("Could not add TSIG signature with algorithm 'gss-tsig' and key name '")+tsigkeyname
.toLogString()+string("'"));
717 trc
.d_mac
= calculateHMAC(tsigsecret
, toSign
, algo
);
718 // trc.d_mac[0]++; // sabotage
720 pw
.startRecord(tsigkeyname
, QType::TSIG
, 0, QClass::ANY
, DNSResourceRecord::ADDITIONAL
, false);
725 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
)
727 uint64_t delta
= std::abs((int64_t)trc
.d_time
- (int64_t)time(nullptr));
728 if(delta
> trc
.d_fudge
) {
729 throw std::runtime_error("Invalid TSIG time delta " + std::to_string(delta
) + " > fudge " + std::to_string(trc
.d_fudge
));
733 if (!getTSIGHashEnum(trc
.d_algoName
, algo
)) {
734 throw std::runtime_error("Unsupported TSIG HMAC algorithm " + trc
.d_algoName
.toLogString());
737 TSIGHashEnum expectedAlgo
;
738 if (!getTSIGHashEnum(tt
.algo
, expectedAlgo
)) {
739 throw std::runtime_error("Unsupported TSIG HMAC algorithm expected " + tt
.algo
.toLogString());
742 if (algo
!= expectedAlgo
) {
743 throw std::runtime_error("Signature with TSIG key '"+tt
.name
.toLogString()+"' does not match the expected algorithm (" + tt
.algo
.toLogString() + " / " + trc
.d_algoName
.toLogString() + ")");
747 tsigMsg
= makeTSIGMessageFromTSIGPacket(packet
, sigPos
, tt
.name
, trc
, previousMAC
, timersOnly
, dnsHeaderOffset
);
749 if (algo
== TSIG_GSS
) {
750 GssContext
gssctx(tt
.name
);
751 if (!gss_verify_signature(tt
.name
, tsigMsg
, theirMAC
)) {
752 throw std::runtime_error("Signature with TSIG key '"+tt
.name
.toLogString()+"' failed to validate");
755 string ourMac
= calculateHMAC(tt
.secret
, tsigMsg
, algo
);
757 if(!constantTimeStringEquals(ourMac
, theirMAC
)) {
758 throw std::runtime_error("Signature with TSIG key '"+tt
.name
.toLogString()+"' failed to validate");