]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnssecinfra.cc
addcab456734ec62f7c66f86b6a7efebeb0974d0
[thirdparty/pdns.git] / pdns / dnssecinfra.cc
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4 #include "dnsparser.hh"
5 #include "sstuff.hh"
6 #include "misc.hh"
7 #include "dnswriter.hh"
8 #include "dnsrecords.hh"
9 #ifndef RECURSOR
10 #include "statbag.hh"
11 #endif
12 #include "iputils.hh"
13
14 #include <boost/algorithm/string.hpp>
15 #include "dnssecinfra.hh"
16 #include "dnsseckeeper.hh"
17 #include <openssl/hmac.h>
18 #include <openssl/sha.h>
19 #include <boost/assign/std/vector.hpp> // for 'operator+=()'
20 #include <boost/assign/list_inserter.hpp>
21 #include "base64.hh"
22 #include "namespaces.hh"
23 #ifdef HAVE_P11KIT1
24 #include "pkcs11signers.hh"
25 #endif
26 #include "gss_context.hh"
27 #include "misc.hh"
28
29 using namespace boost::assign;
30
31 DNSCryptoKeyEngine* DNSCryptoKeyEngine::makeFromISCFile(DNSKEYRecordContent& drc, const char* fname)
32 {
33 string sline, isc;
34 FILE *fp=fopen(fname, "r");
35 if(!fp) {
36 throw runtime_error("Unable to read file '"+string(fname)+"' for generating DNS Private Key");
37 }
38
39 while(stringfgets(fp, sline)) {
40 isc += sline;
41 }
42 fclose(fp);
43 DNSCryptoKeyEngine* dke = makeFromISCString(drc, isc);
44 if(!dke->checkKey()) {
45 delete dke;
46 throw runtime_error("Invalid DNS Private Key in file '"+string(fname));
47 }
48 return dke;
49 }
50
51 DNSCryptoKeyEngine* DNSCryptoKeyEngine::makeFromISCString(DNSKEYRecordContent& drc, const std::string& content)
52 {
53 bool pkcs11=false;
54 int algorithm = 0;
55 string sline, key, value, raw;
56 std::istringstream str(content);
57 map<string, string> stormap;
58
59 while(std::getline(str, sline)) {
60 tie(key,value)=splitField(sline, ':');
61 trim(value);
62 if(pdns_iequals(key,"algorithm")) {
63 algorithm = pdns_stou(value);
64 stormap["algorithm"]=std::to_string(algorithm);
65 continue;
66 } else if (pdns_iequals(key,"pin")) {
67 stormap["pin"]=value;
68 continue;
69 } else if (pdns_iequals(key,"engine")) {
70 stormap["engine"]=value;
71 pkcs11=true;
72 continue;
73 } else if (pdns_iequals(key,"slot")) {
74 stormap["slot"]=value;
75 continue;
76 } else if (pdns_iequals(key,"label")) {
77 stormap["label"]=value;
78 continue;
79 }
80 else if(pdns_iequals(key, "Private-key-format"))
81 continue;
82 raw.clear();
83 B64Decode(value, raw);
84 stormap[toLower(key)]=raw;
85 }
86 DNSCryptoKeyEngine* dpk;
87
88 if (pkcs11) {
89 #ifdef HAVE_P11KIT1
90 if (stormap.find("slot") == stormap.end())
91 throw PDNSException("Cannot load PKCS#11 key, no Slot specified");
92 // we need PIN to be at least empty
93 if (stormap.find("pin") == stormap.end()) stormap["pin"] = "";
94 dpk = PKCS11DNSCryptoKeyEngine::maker(algorithm);
95 #else
96 throw PDNSException("Cannot load PKCS#11 key without support for it");
97 #endif
98 } else {
99 dpk=make(algorithm);
100 }
101 dpk->fromISCMap(drc, stormap);
102 return dpk;
103 }
104
105 std::string DNSCryptoKeyEngine::convertToISC() const
106 {
107 typedef map<string, string> stormap_t;
108 storvector_t stormap = this->convertToISCVector();
109 ostringstream ret;
110 ret<<"Private-key-format: v1.2\n";
111 for(const stormap_t::value_type& value : stormap) {
112 if(value.first != "Algorithm" && value.first != "PIN" &&
113 value.first != "Slot" && value.first != "Engine" &&
114 value.first != "Label")
115 ret<<value.first<<": "<<Base64Encode(value.second)<<"\n";
116 else
117 ret<<value.first<<": "<<value.second<<"\n";
118 }
119 return ret.str();
120 }
121
122 DNSCryptoKeyEngine* DNSCryptoKeyEngine::make(unsigned int algo)
123 {
124 makers_t& makers = getMakers();
125 makers_t::const_iterator iter = makers.find(algo);
126 if(iter != makers.end())
127 return (iter->second)(algo);
128 else {
129 throw runtime_error("Request to create key object for unknown algorithm number "+std::to_string(algo));
130 }
131 }
132
133 /**
134 * Returns the supported DNSSEC algorithms with the name of the Crypto Backend used
135 *
136 * @return A vector with pairs of (algorithm-number (int), backend-name (string))
137 */
138 vector<pair<uint8_t, string>> DNSCryptoKeyEngine::listAllAlgosWithBackend()
139 {
140 vector<pair<uint8_t, string>> ret;
141 for (auto const& value : getMakers()) {
142 shared_ptr<DNSCryptoKeyEngine> dcke(value.second(value.first));
143 ret.push_back(make_pair(value.first, dcke->getName()));
144 }
145 return ret;
146 }
147
148 void DNSCryptoKeyEngine::report(unsigned int algo, maker_t* maker, bool fallback)
149 {
150 getAllMakers()[algo].push_back(maker);
151 if(getMakers().count(algo) && fallback) {
152 return;
153 }
154 getMakers()[algo]=maker;
155 }
156
157 bool DNSCryptoKeyEngine::testAll()
158 {
159 bool ret=true;
160
161 for(const allmakers_t::value_type& value : getAllMakers())
162 {
163 for(maker_t* creator : value.second) {
164
165 for(maker_t* signer : value.second) {
166 // multi_map<unsigned int, maker_t*> bestSigner, bestVerifier;
167
168 for(maker_t* verifier : value.second) {
169 try {
170 /* pair<unsigned int, unsigned int> res=*/ testMakers(value.first, creator, signer, verifier);
171 }
172 catch(std::exception& e)
173 {
174 cerr<<e.what()<<endl;
175 ret=false;
176 }
177 }
178 }
179 }
180 }
181 return ret;
182 }
183
184 bool DNSCryptoKeyEngine::testOne(int algo)
185 {
186 bool ret=true;
187
188 for(maker_t* creator : getAllMakers()[algo]) {
189
190 for(maker_t* signer : getAllMakers()[algo]) {
191 // multi_map<unsigned int, maker_t*> bestSigner, bestVerifier;
192
193 for(maker_t* verifier : getAllMakers()[algo]) {
194 try {
195 /* pair<unsigned int, unsigned int> res=*/testMakers(algo, creator, signer, verifier);
196 }
197 catch(std::exception& e)
198 {
199 cerr<<e.what()<<endl;
200 ret=false;
201 }
202 }
203 }
204 }
205 return ret;
206 }
207 // returns times it took to sign and verify
208 pair<unsigned int, unsigned int> DNSCryptoKeyEngine::testMakers(unsigned int algo, maker_t* creator, maker_t* signer, maker_t* verifier)
209 {
210 shared_ptr<DNSCryptoKeyEngine> dckeCreate(creator(algo));
211 shared_ptr<DNSCryptoKeyEngine> dckeSign(signer(algo));
212 shared_ptr<DNSCryptoKeyEngine> dckeVerify(verifier(algo));
213
214 cerr<<"Testing algorithm "<<algo<<": '"<<dckeCreate->getName()<<"' ->'"<<dckeSign->getName()<<"' -> '"<<dckeVerify->getName()<<"' ";
215 unsigned int bits;
216 if(algo <= 10)
217 bits=1024;
218 else if(algo == 12 || algo == 13 || algo == 250) // ECC-GOST or ECDSAP256SHA256 or ED25519SHA512
219 bits=256;
220 else if(algo == 14) // ECDSAP384SHA384
221 bits = 384;
222 else
223 throw runtime_error("Can't guess key size for algorithm "+std::to_string(algo));
224
225 dckeCreate->create(bits);
226
227 { // FIXME: this block copy/pasted from makeFromISCString
228 DNSKEYRecordContent dkrc;
229 int algorithm = 0;
230 string sline, key, value, raw;
231 std::istringstream str(dckeCreate->convertToISC());
232 map<string, string> stormap;
233
234 while(std::getline(str, sline)) {
235 tie(key,value)=splitField(sline, ':');
236 trim(value);
237 if(pdns_iequals(key,"algorithm")) {
238 algorithm = pdns_stou(value);
239 stormap["algorithm"]=std::to_string(algorithm);
240 continue;
241 } else if (pdns_iequals(key,"pin")) {
242 stormap["pin"]=value;
243 continue;
244 } else if (pdns_iequals(key,"engine")) {
245 stormap["engine"]=value;
246 continue;
247 } else if (pdns_iequals(key,"slot")) {
248 int slot = std::stoi(value);
249 stormap["slot"]=std::to_string(slot);
250 continue;
251 } else if (pdns_iequals(key,"label")) {
252 stormap["label"]=value;
253 continue;
254 }
255 else if(pdns_iequals(key, "Private-key-format"))
256 continue;
257 raw.clear();
258 B64Decode(value, raw);
259 stormap[toLower(key)]=raw;
260 }
261 dckeSign->fromISCMap(dkrc, stormap);
262 if(!dckeSign->checkKey()) {
263 throw runtime_error("Verification of key with creator "+dckeCreate->getName()+" with signer "+dckeSign->getName()+" and verifier "+dckeVerify->getName()+" failed");
264 }
265 }
266
267 string message("Hi! How is life?");
268
269 string signature;
270 DTime dt; dt.set();
271 for(unsigned int n = 0; n < 100; ++n)
272 signature = dckeSign->sign(message);
273 unsigned int udiffSign= dt.udiff()/100, udiffVerify;
274
275 dckeVerify->fromPublicKeyString(dckeSign->getPublicKeyString());
276 if (dckeVerify->getPublicKeyString().compare(dckeSign->getPublicKeyString())) {
277 throw runtime_error("Comparison of public key loaded into verifier produced by signer failed");
278 }
279 dt.set();
280 if(dckeVerify->verify(message, signature)) {
281 udiffVerify = dt.udiff();
282 cerr<<"Signature & verify ok, signature "<<udiffSign<<"usec, verify "<<udiffVerify<<"usec"<<endl;
283 }
284 else {
285 throw runtime_error("Verification of creator "+dckeCreate->getName()+" with signer "+dckeSign->getName()+" and verifier "+dckeVerify->getName()+" failed");
286 }
287 return make_pair(udiffSign, udiffVerify);
288 }
289
290 DNSCryptoKeyEngine* DNSCryptoKeyEngine::makeFromPublicKeyString(unsigned int algorithm, const std::string& content)
291 {
292 DNSCryptoKeyEngine* dpk=make(algorithm);
293 dpk->fromPublicKeyString(content);
294 return dpk;
295 }
296
297
298 DNSCryptoKeyEngine* DNSCryptoKeyEngine::makeFromPEMString(DNSKEYRecordContent& drc, const std::string& raw)
299 {
300
301 for(makers_t::value_type& val : getMakers())
302 {
303 DNSCryptoKeyEngine* ret=0;
304 try {
305 ret = val.second(val.first);
306 ret->fromPEMString(drc, raw);
307 return ret;
308 }
309 catch(...)
310 {
311 delete ret; // fine if 0
312 }
313 }
314 return 0;
315 }
316
317
318 bool sharedDNSSECCompare(const shared_ptr<DNSRecordContent>& a, const shared_ptr<DNSRecordContent>& b)
319 {
320 return a->serialize(DNSName("."), true, true) < b->serialize(DNSName("."), true, true);
321 }
322
323 /**
324 * Returns the string that should be hashed to create/verify the RRSIG content
325 *
326 * @param qname DNSName of the RRSIG's owner name.
327 * @param rrc The RRSIGRecordContent we take the Type Covered and
328 * original TTL fields from.
329 * @param signRecords A vector of DNSRecordContent shared_ptr's that are covered
330 * by the RRSIG, where we get the RDATA from.
331 * @param processRRSIGLabels A boolean to trigger processing the RRSIG's "Labels"
332 * field. This is usually only needed for validation
333 * purposes, as the authoritative server correctly
334 * sets qname to the wildcard.
335 */
336 string getMessageForRRSET(const DNSName& qname, const RRSIGRecordContent& rrc, vector<shared_ptr<DNSRecordContent> >& signRecords, bool processRRSIGLabels)
337 {
338 sort(signRecords.begin(), signRecords.end(), sharedDNSSECCompare);
339
340 string toHash;
341 toHash.append(const_cast<RRSIGRecordContent&>(rrc).serialize(DNSName("."), true, true));
342 toHash.resize(toHash.size() - rrc.d_signature.length()); // chop off the end, don't sign the signature!
343
344 string nameToHash(qname.toDNSStringLC());
345
346 if (processRRSIGLabels) {
347 unsigned int rrsig_labels = rrc.d_labels;
348 unsigned int fqdn_labels = qname.countLabels();
349
350 if (rrsig_labels < fqdn_labels) {
351 DNSName choppedQname(qname);
352 while (choppedQname.countLabels() > rrsig_labels)
353 choppedQname.chopOff();
354 nameToHash = "\x01*" + choppedQname.toDNSStringLC();
355 } else if (rrsig_labels > fqdn_labels) {
356 // The RRSIG Labels field is a lie (or the qname is wrong) and the RRSIG
357 // can never be valid
358 return "";
359 }
360 }
361
362 for(shared_ptr<DNSRecordContent>& add : signRecords) {
363 toHash.append(nameToHash);
364 uint16_t tmp=htons(rrc.d_type);
365 toHash.append((char*)&tmp, 2);
366 tmp=htons(1); // class
367 toHash.append((char*)&tmp, 2);
368 uint32_t ttl=htonl(rrc.d_originalttl);
369 toHash.append((char*)&ttl, 4);
370 // for NSEC signatures, we should not lowercase the rdata section
371 string rdata=add->serialize(DNSName("."), true, (add->getType() == QType::NSEC) ? false : true); // RFC 6840, 5.1
372 tmp=htons(rdata.length());
373 toHash.append((char*)&tmp, 2);
374 toHash.append(rdata);
375 }
376
377 return toHash;
378 }
379
380 DSRecordContent makeDSFromDNSKey(const DNSName& qname, const DNSKEYRecordContent& drc, int digest)
381 {
382 string toHash;
383 toHash.assign(qname.toDNSStringLC());
384 toHash.append(const_cast<DNSKEYRecordContent&>(drc).serialize(DNSName(), true, true));
385
386 DSRecordContent dsrc;
387 if(digest==1) {
388 shared_ptr<DNSCryptoKeyEngine> dpk(DNSCryptoKeyEngine::make(5)); // gives us SHA1
389 dsrc.d_digest = dpk->hash(toHash);
390 }
391 else if(digest == 2) {
392 shared_ptr<DNSCryptoKeyEngine> dpk(DNSCryptoKeyEngine::make(8)); // gives us SHA256
393 dsrc.d_digest = dpk->hash(toHash);
394 }
395 else if(digest == 3) {
396 shared_ptr<DNSCryptoKeyEngine> dpk(DNSCryptoKeyEngine::make(12)); // gives us GOST
397 dsrc.d_digest = dpk->hash(toHash);
398 }
399 else if(digest == 4) {
400 shared_ptr<DNSCryptoKeyEngine> dpk(DNSCryptoKeyEngine::make(14)); // gives us ECDSAP384
401 dsrc.d_digest = dpk->hash(toHash);
402 }
403 else
404 throw std::runtime_error("Asked to a DS of unknown digest type " + std::to_string(digest)+"\n");
405
406 dsrc.d_algorithm= drc.d_algorithm;
407 dsrc.d_digesttype=digest;
408 dsrc.d_tag=const_cast<DNSKEYRecordContent&>(drc).getTag();
409
410 return dsrc;
411 }
412
413
414 DNSKEYRecordContent makeDNSKEYFromDNSCryptoKeyEngine(const DNSCryptoKeyEngine* pk, uint8_t algorithm, uint16_t flags)
415 {
416 DNSKEYRecordContent drc;
417
418 drc.d_protocol=3;
419 drc.d_algorithm = algorithm;
420
421 drc.d_flags=flags;
422 drc.d_key = pk->getPublicKeyString();
423
424 return drc;
425 }
426
427 int countLabels(const std::string& signQName)
428 {
429 if(!signQName.empty()) {
430 int count=1;
431 for(string::const_iterator pos = signQName.begin(); pos != signQName.end() ; ++pos)
432 if(*pos == '.' && pos+1 != signQName.end())
433 count++;
434
435 if(boost::starts_with(signQName, "*."))
436 count--;
437 return count;
438 }
439 return 0;
440 }
441
442 uint32_t getStartOfWeek()
443 {
444 uint32_t now = time(0);
445 now -= (now % (7*86400));
446 return now;
447 }
448
449 string hashQNameWithSalt(const NSEC3PARAMRecordContent& ns3prc, const DNSName& qname)
450 {
451 return hashQNameWithSalt(ns3prc.d_salt, ns3prc.d_iterations, qname);
452 }
453
454 string hashQNameWithSalt(const std::string& salt, unsigned int iterations, const DNSName& qname)
455 {
456 unsigned int times = iterations;
457 unsigned char hash[20];
458 string toHash(qname.toDNSStringLC());
459
460 for(;;) {
461 toHash.append(salt);
462 SHA1((unsigned char*)toHash.c_str(), toHash.length(), hash);
463 toHash.assign((char*)hash, sizeof(hash));
464 if(!times--)
465 break;
466 }
467 return toHash;
468 }
469
470 DNSKEYRecordContent DNSSECPrivateKey::getDNSKEY() const
471 {
472 return makeDNSKEYFromDNSCryptoKeyEngine(getKey(), d_algorithm, d_flags);
473 }
474
475 class DEREater
476 {
477 public:
478 DEREater(const std::string& str) : d_str(str), d_pos(0)
479 {}
480
481 struct eof{};
482
483 uint8_t getByte()
484 {
485 if(d_pos >= d_str.length()) {
486 throw eof();
487 }
488 return (uint8_t) d_str[d_pos++];
489 }
490
491 uint32_t getLength()
492 {
493 uint8_t first = getByte();
494 if(first < 0x80) {
495 return first;
496 }
497 first &= ~0x80;
498
499 uint32_t len=0;
500 for(int n=0; n < first; ++n) {
501 len *= 0x100;
502 len += getByte();
503 }
504 return len;
505 }
506
507 std::string getBytes(unsigned int len)
508 {
509 std::string ret;
510 for(unsigned int n=0; n < len; ++n)
511 ret.append(1, (char)getByte());
512 return ret;
513 }
514
515 std::string::size_type getOffset()
516 {
517 return d_pos;
518 }
519 private:
520 const std::string& d_str;
521 std::string::size_type d_pos;
522 };
523
524 void decodeDERIntegerSequence(const std::string& input, vector<string>& output)
525 {
526 output.clear();
527 DEREater de(input);
528 if(de.getByte() != 0x30)
529 throw runtime_error("Not a DER sequence");
530
531 unsigned int seqlen=de.getLength();
532 unsigned int startseq=de.getOffset();
533 unsigned int len;
534 string ret;
535 try {
536 for(;;) {
537 uint8_t kind = de.getByte();
538 if(kind != 0x02)
539 throw runtime_error("DER Sequence contained non-INTEGER component: "+std::to_string(static_cast<unsigned int>(kind)) );
540 len = de.getLength();
541 ret = de.getBytes(len);
542 output.push_back(ret);
543 }
544 }
545 catch(DEREater::eof& eof)
546 {
547 if(de.getOffset() - startseq != seqlen)
548 throw runtime_error("DER Sequence ended before end of data");
549 }
550 }
551
552 string calculateHMAC(const std::string& key, const std::string& text, TSIGHashEnum hasher) {
553
554 const EVP_MD* md_type;
555 unsigned int outlen;
556 unsigned char hash[EVP_MAX_MD_SIZE];
557 switch(hasher) {
558 case TSIG_MD5:
559 md_type = EVP_md5();
560 break;
561 case TSIG_SHA1:
562 md_type = EVP_sha1();
563 break;
564 case TSIG_SHA224:
565 md_type = EVP_sha224();
566 break;
567 case TSIG_SHA256:
568 md_type = EVP_sha256();
569 break;
570 case TSIG_SHA384:
571 md_type = EVP_sha384();
572 break;
573 case TSIG_SHA512:
574 md_type = EVP_sha512();
575 break;
576 default:
577 throw new PDNSException("Unknown hash algorithm requested from calculateHMAC()");
578 }
579
580 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);
581 if (out != NULL && outlen > 0) {
582 return string((char*) hash, outlen);
583 }
584
585 return "";
586 }
587
588 string makeTSIGMessageFromTSIGPacket(const string& opacket, unsigned int tsigOffset, const DNSName& keyname, const TSIGRecordContent& trc, const string& previous, bool timersonly, unsigned int dnsHeaderOffset)
589 {
590 string message;
591 string packet(opacket);
592
593 packet.resize(tsigOffset); // remove the TSIG record at the end as per RFC2845 3.4.1
594 packet[(dnsHeaderOffset + sizeof(struct dnsheader))-1]--; // Decrease ARCOUNT because we removed the TSIG RR in the previous line.
595
596
597 // Replace the message ID with the original message ID from the TSIG record.
598 // 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
599 // signature was created with the original ID, so we replace it here to get the originally signed message.
600 // If the message is not forwarded, we simply override it with the same id.
601 uint16_t origID = htons(trc.d_origID);
602 packet.replace(0, 2, (char*)&origID, 2);
603
604 if(!previous.empty()) {
605 uint16_t len = htons(previous.length());
606 message.append((char*)&len, 2);
607 message.append(previous);
608 }
609
610 message.append(packet);
611
612 vector<uint8_t> signVect;
613 DNSPacketWriter dw(signVect, DNSName(), 0);
614 if(!timersonly) {
615 dw.xfrName(keyname, false);
616 dw.xfr16BitInt(QClass::ANY); // class
617 dw.xfr32BitInt(0); // TTL
618 // dw.xfrName(toLower(trc.d_algoName), false); //FIXME400
619 dw.xfrName(trc.d_algoName, false);
620 }
621
622 uint32_t now = trc.d_time;
623 dw.xfr48BitInt(now);
624 dw.xfr16BitInt(trc.d_fudge); // fudge
625 if(!timersonly) {
626 dw.xfr16BitInt(trc.d_eRcode); // extended rcode
627 dw.xfr16BitInt(trc.d_otherData.length()); // length of 'other' data
628 // dw.xfrBlob(trc->d_otherData);
629 }
630 const vector<uint8_t>& signRecord=dw.getRecordBeingWritten();
631 message.append(signRecord.begin(), signRecord.end());
632 return message;
633 }
634
635 void addTSIG(DNSPacketWriter& pw, TSIGRecordContent* trc, const DNSName& tsigkeyname, const string& tsigsecret, const string& tsigprevious, bool timersonly)
636 {
637 TSIGHashEnum algo;
638 if (!getTSIGHashEnum(trc->d_algoName, algo)) {
639 throw PDNSException(string("Unsupported TSIG HMAC algorithm ") + trc->d_algoName.toString());
640 }
641
642 string toSign;
643 if(!tsigprevious.empty()) {
644 uint16_t len = htons(tsigprevious.length());
645 toSign.append((char*)&len, 2);
646
647 toSign.append(tsigprevious);
648 }
649 toSign.append(pw.getContent().begin(), pw.getContent().end());
650
651 // now add something that looks a lot like a TSIG record, but isn't
652 vector<uint8_t> signVect;
653 DNSPacketWriter dw(signVect, DNSName(), 0);
654 if(!timersonly) {
655 dw.xfrName(tsigkeyname, false);
656 dw.xfr16BitInt(QClass::ANY); // class
657 dw.xfr32BitInt(0); // TTL
658 dw.xfrName(trc->d_algoName, false);
659 }
660 uint32_t now = trc->d_time;
661 dw.xfr48BitInt(now);
662 dw.xfr16BitInt(trc->d_fudge); // fudge
663
664 if(!timersonly) {
665 dw.xfr16BitInt(trc->d_eRcode); // extended rcode
666 dw.xfr16BitInt(trc->d_otherData.length()); // length of 'other' data
667 // dw.xfrBlob(trc->d_otherData);
668 }
669
670 const vector<uint8_t>& signRecord=dw.getRecordBeingWritten();
671 toSign.append(signRecord.begin(), signRecord.end());
672
673 if (algo == TSIG_GSS) {
674 if (!gss_add_signature(tsigkeyname, toSign, trc->d_mac)) {
675 throw PDNSException(string("Could not add TSIG signature with algorithm 'gss-tsig' and key name '")+tsigkeyname.toString()+string("'"));
676 }
677 } else {
678 trc->d_mac = calculateHMAC(tsigsecret, toSign, algo);
679 // d_trc->d_mac[0]++; // sabotage
680 }
681 pw.startRecord(tsigkeyname, QType::TSIG, 0, QClass::ANY, DNSResourceRecord::ADDITIONAL, false);
682 trc->toPacket(pw);
683 pw.commit();
684 }
685