]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dbdnsseckeeper.cc
Merge pull request #8096 from mind04/pdns-notify-db-queries
[thirdparty/pdns.git] / pdns / dbdnsseckeeper.cc
CommitLineData
882358c8 1/*
12471842
PL
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
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.
8 *
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.
12 *
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.
17 *
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.
21 */
870a0fe4
AT
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
c0273500
BH
25#include "dnsseckeeper.hh"
26#include "dnssecinfra.hh"
27#include "ueberbackend.hh"
28#include "statbag.hh"
29#include <iostream>
fa8fd4d2 30
c0273500
BH
31#include <sys/stat.h>
32#include <sys/types.h>
33#include <fstream>
34#include <boost/algorithm/string.hpp>
35#include <boost/format.hpp>
36#include <boost/assign/std/vector.hpp> // for 'operator+=()'
37#include <boost/assign/list_inserter.hpp>
25b1ce13 38#include "base32.hh"
78bcb858 39#include "base64.hh"
157f806e
PD
40#include "cachecleaner.hh"
41#include "arguments.hh"
d473cb9a
BH
42
43
c0273500 44using namespace boost::assign;
9cb28241 45#include "namespaces.hh"
de43ec0f 46
c0273500 47
40fe813d 48DNSSECKeeper::keycache_t DNSSECKeeper::s_keycache;
d6f3dcdc 49DNSSECKeeper::metacache_t DNSSECKeeper::s_metacache;
18a144ef
BH
50pthread_rwlock_t DNSSECKeeper::s_metacachelock = PTHREAD_RWLOCK_INITIALIZER;
51pthread_rwlock_t DNSSECKeeper::s_keycachelock = PTHREAD_RWLOCK_INITIALIZER;
16f7d28d 52AtomicCounter DNSSECKeeper::s_ops;
157f806e 53time_t DNSSECKeeper::s_last_prune;
307994e7 54size_t DNSSECKeeper::s_maxEntries = 0;
d473cb9a 55
7fa35c07
KM
56bool DNSSECKeeper::doesDNSSEC()
57{
58 return d_keymetadb->doesDNSSEC();
59}
60
675fa24c 61bool DNSSECKeeper::isSecuredZone(const DNSName& zone)
c0273500 62{
d3e7090c 63 if(isPresigned(zone))
d6f3dcdc 64 return true;
157f806e 65
8a95b04c
KM
66 keyset_t keys = getKeys(zone); // does the cache
67
ef7cd021 68 for(keyset_t::value_type& val : keys) {
ade1b1e9
BH
69 if(val.second.active) {
70 return true;
71 }
c0273500 72 }
ade1b1e9 73 return false;
c0273500
BH
74}
75
675fa24c 76bool DNSSECKeeper::isPresigned(const DNSName& name)
d3e7090c 77{
9cb28241
BH
78 string meta;
79 getFromMeta(name, "PRESIGNED", meta);
80 return meta=="1";
d3e7090c 81}
c0273500 82
33918299 83bool DNSSECKeeper::addKey(const DNSName& name, bool setSEPBit, int algorithm, int64_t& id, int bits, bool active, bool published)
c0273500 84{
022e5e0b
BH
85 if(!bits) {
86 if(algorithm <= 10)
685a70c2 87 throw runtime_error("Creating an algorithm " +std::to_string(algorithm)+" ("+algorithm2name(algorithm)+") key requires the size (in bits) to be passed.");
022e5e0b 88 else {
902c4e9c 89 if(algorithm == DNSSECKeeper::ECCGOST || algorithm == DNSSECKeeper::ECDSA256 || algorithm == DNSSECKeeper::ED25519)
022e5e0b 90 bits = 256;
902c4e9c 91 else if(algorithm == DNSSECKeeper::ECDSA384)
022e5e0b 92 bits = 384;
902c4e9c 93 else if(algorithm == DNSSECKeeper::ED448)
21a8834a 94 bits = 456;
022e5e0b 95 else {
685a70c2 96 throw runtime_error("Can not guess key size for algorithm "+std::to_string(algorithm));
022e5e0b
BH
97 }
98 }
99 }
699e6e37 100 DNSSECPrivateKey dspk;
b6bd795c 101 shared_ptr<DNSCryptoKeyEngine> dpk(DNSCryptoKeyEngine::make(algorithm));
34aa40ce
BZ
102 try{
103 dpk->create(bits);
d38e2ba9 104 } catch (const std::runtime_error& error){
685a70c2 105 throw runtime_error("The algorithm does not support the given bit size.");
34aa40ce 106 }
699e6e37
BH
107 dspk.setKey(dpk);
108 dspk.d_algorithm = algorithm;
b6bd795c 109 dspk.d_flags = setSEPBit ? 257 : 256;
33918299 110 return addKey(name, dspk, id, active, published);
f7bcc763
BH
111}
112
627d2ca2
PD
113void DNSSECKeeper::clearAllCaches() {
114 {
18a144ef 115 WriteLock l(&s_keycachelock);
627d2ca2
PD
116 s_keycache.clear();
117 }
18a144ef 118 WriteLock l(&s_metacachelock);
627d2ca2
PD
119 s_metacache.clear();
120}
121
675fa24c 122void DNSSECKeeper::clearCaches(const DNSName& name)
5e91adff 123{
40fe813d 124 {
18a144ef 125 WriteLock l(&s_keycachelock);
40fe813d
BH
126 s_keycache.erase(name);
127 }
18a144ef 128 WriteLock l(&s_metacachelock);
0b7d7191 129 pair<metacache_t::iterator, metacache_t::iterator> range = s_metacache.equal_range(tie(name));
d6f3dcdc
BH
130 while(range.first != range.second)
131 s_metacache.erase(range.first++);
5e91adff
BH
132}
133
134
33918299 135bool DNSSECKeeper::addKey(const DNSName& name, const DNSSECPrivateKey& dpk, int64_t& id, bool active, bool published)
f7bcc763 136{
5e91adff 137 clearCaches(name);
c0273500 138 DNSBackend::KeyData kd;
7ddd79a7 139 kd.flags = dpk.d_flags; // the dpk doesn't get stored, only they key part
c0273500 140 kd.active = active;
33918299 141 kd.published = published;
189bb9d2 142 kd.content = dpk.getKey()->convertToISC();
c0273500 143 // now store it
82cc0761 144 return d_keymetadb->addDomainKey(name, kd, id);
c0273500
BH
145}
146
147
148static bool keyCompareByKindAndID(const DNSSECKeeper::keyset_t::value_type& a, const DNSSECKeeper::keyset_t::value_type& b)
149{
b6bd795c
PL
150 return make_pair(!a.second.keyType, a.second.id) <
151 make_pair(!b.second.keyType, b.second.id);
c0273500
BH
152}
153
675fa24c 154DNSSECPrivateKey DNSSECKeeper::getKeyById(const DNSName& zname, unsigned int id)
c0273500 155{
c0273500 156 vector<DNSBackend::KeyData> keys;
9c1c5d49 157 d_keymetadb->getDomainKeys(zname, keys);
ef7cd021 158 for(const DNSBackend::KeyData& kd : keys) {
c0273500
BH
159 if(kd.id != id)
160 continue;
161
162 DNSSECPrivateKey dpk;
699e6e37 163 DNSKEYRecordContent dkrc;
8d9f38f2 164 dpk.setKey(shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::makeFromISCString(dkrc, kd.content)));
c0273500 165 dpk.d_flags = kd.flags;
a254438f 166 dpk.d_algorithm = dkrc.d_algorithm;
c0273500 167
c0273500
BH
168 return dpk;
169 }
86f1af1c 170 throw runtime_error("Can't find a key with id "+std::to_string(id)+" for zone '"+zname.toLogString()+"'");
c0273500
BH
171}
172
173
675fa24c 174bool DNSSECKeeper::removeKey(const DNSName& zname, unsigned int id)
c0273500 175{
5e91adff 176 clearCaches(zname);
a84a8203 177 return d_keymetadb->removeDomainKey(zname, id);
c0273500
BH
178}
179
675fa24c 180bool DNSSECKeeper::deactivateKey(const DNSName& zname, unsigned int id)
c0273500 181{
5e91adff 182 clearCaches(zname);
a84a8203 183 return d_keymetadb->deactivateDomainKey(zname, id);
c0273500
BH
184}
185
675fa24c 186bool DNSSECKeeper::activateKey(const DNSName& zname, unsigned int id)
c0273500 187{
5e91adff 188 clearCaches(zname);
a84a8203 189 return d_keymetadb->activateDomainKey(zname, id);
c0273500
BH
190}
191
33918299
RG
192bool DNSSECKeeper::unpublishKey(const DNSName& zname, unsigned int id)
193{
194 clearCaches(zname);
195 return d_keymetadb->unpublishDomainKey(zname, id);
196}
197
198bool DNSSECKeeper::publishKey(const DNSName& zname, unsigned int id)
199{
200 clearCaches(zname);
201 return d_keymetadb->publishDomainKey(zname, id);
202}
203
2fb19458
PD
204void DNSSECKeeper::getFromMetaOrDefault(const DNSName& zname, const std::string& key, std::string& value, const std::string& defaultvalue)
205{
206 if (getFromMeta(zname, key, value))
207 return;
208 else
209 value = defaultvalue;
210}
d6f3dcdc 211
2fb19458 212bool DNSSECKeeper::getFromMeta(const DNSName& zname, const std::string& key, std::string& value)
c0273500 213{
030850a9 214 static int ttl = ::arg().asNum("domain-metadata-cache-ttl");
2fb19458 215 bool isset = false;
d6f3dcdc 216 value.clear();
5e91adff 217 unsigned int now = time(0);
157f806e 218
16f7d28d 219 if(!((++s_ops) % 100000)) {
157f806e
PD
220 cleanup();
221 }
222
030850a9 223 if (ttl > 0) {
18a144ef 224 ReadLock l(&s_metacachelock);
d473cb9a 225
d6f3dcdc
BH
226 metacache_t::const_iterator iter = s_metacache.find(tie(zname, key));
227 if(iter != s_metacache.end() && iter->d_ttd > now) {
228 value = iter->d_value;
2fb19458 229 return iter->d_isset;
d473cb9a 230 }
22c5aa60 231 }
d473cb9a 232 vector<string> meta;
936eb34a 233 d_keymetadb->getDomainMetadata(zname, key, meta);
2fb19458 234 if(!meta.empty()) {
d6f3dcdc 235 value=*meta.begin();
2fb19458
PD
236 isset = true;
237 }
030850a9
RG
238
239 if (ttl > 0) {
240 METACacheEntry nce;
241 nce.d_domain=zname;
242 nce.d_ttd = now + ttl;
243 nce.d_key= key;
244 nce.d_value = value;
2fb19458 245 nce.d_isset = isset;
030850a9
RG
246 {
247 WriteLock l(&s_metacachelock);
94306029 248 lruReplacingInsert<SequencedTag>(s_metacache, nce);
030850a9 249 }
d473cb9a 250 }
2fb19458 251 return isset;
d6f3dcdc
BH
252}
253
4192773a
KM
254void DNSSECKeeper::getSoaEdit(const DNSName& zname, std::string& value)
255{
256 static const string soaEdit(::arg()["default-soa-edit"]);
257 static const string soaEditSigned(::arg()["default-soa-edit-signed"]);
258
3ba10656
PD
259 if (isPresigned(zname)) {
260 // SOA editing on a presigned zone never makes sense
261 return;
262 }
263
4192773a
KM
264 getFromMeta(zname, "SOA-EDIT", value);
265
3ba10656 266 if ((!soaEdit.empty() || !soaEditSigned.empty()) && value.empty()) {
4192773a
KM
267 if (!soaEditSigned.empty() && isSecuredZone(zname))
268 value=soaEditSigned;
269 if (value.empty())
270 value=soaEdit;
271 }
272
273 return;
274}
275
e903706d 276uint64_t DNSSECKeeper::dbdnssecCacheSizes(const std::string& str)
277{
278 if(str=="meta-cache-size") {
279 ReadLock l(&s_metacachelock);
280 return s_metacache.size();
281 }
282 else if(str=="key-cache-size") {
283 ReadLock l(&s_keycachelock);
284 return s_keycache.size();
285 }
286 return (uint64_t)-1;
287}
288
675fa24c 289bool DNSSECKeeper::getNSEC3PARAM(const DNSName& zname, NSEC3PARAMRecordContent* ns3p, bool* narrow)
d6f3dcdc
BH
290{
291 string value;
292 getFromMeta(zname, "NSEC3PARAM", value);
5935cede 293 if(value.empty()) { // "no NSEC3"
d6f3dcdc 294 return false;
5935cede 295 }
28b66a94
KM
296
297 static int maxNSEC3Iterations=::arg().asNum("max-nsec3-iterations");
c0273500 298 if(ns3p) {
f6a81077 299 *ns3p = NSEC3PARAMRecordContent(value);
28b66a94
KM
300 if (ns3p->d_iterations > maxNSEC3Iterations) {
301 ns3p->d_iterations = maxNSEC3Iterations;
e6a9dde5 302 g_log<<Logger::Error<<"Number of NSEC3 iterations for zone '"<<zname<<"' is above 'max-nsec3-iterations'. Value adjusted to: "<<maxNSEC3Iterations<<endl;
28b66a94 303 }
c7fbe6c9 304 if (ns3p->d_algorithm != 1) {
e6a9dde5 305 g_log<<Logger::Error<<"Invalid hash algorithm for NSEC3: '"<<std::to_string(ns3p->d_algorithm)<<"', setting to 1 for zone '"<<zname<<"'."<<endl;
c7fbe6c9
PL
306 ns3p->d_algorithm = 1;
307 }
c0273500 308 }
d6f3dcdc
BH
309 if(narrow) {
310 getFromMeta(zname, "NSEC3NARROW", value);
311 *narrow = (value=="1");
312 }
c0273500
BH
313 return true;
314}
315
68fd1167
PL
316/*
317 * Check is the provided NSEC3PARAM record is something we can work with
318 *
319 * \param ns3p NSEC3PARAMRecordContent to check
320 * \param msg string to fill with an error message
321 * \return true on valid, false otherwise
322 */
323bool DNSSECKeeper::checkNSEC3PARAM(const NSEC3PARAMRecordContent& ns3p, string& msg)
c0273500 324{
28b66a94 325 static int maxNSEC3Iterations=::arg().asNum("max-nsec3-iterations");
68fd1167
PL
326 bool ret = true;
327 if (ns3p.d_iterations > maxNSEC3Iterations) {
328 msg += "Number of NSEC3 iterations is above 'max-nsec3-iterations'.";
329 ret = false;
330 }
28b66a94 331
68fd1167
PL
332 if (ns3p.d_algorithm != 1) {
333 if (!ret)
334 msg += ' ';
335 msg += "Invalid hash algorithm for NSEC3: '"+std::to_string(ns3p.d_algorithm)+"', the only valid value is '1'.";
336 ret = false;
337 }
338
339 return ret;
340}
341
342bool DNSSECKeeper::setNSEC3PARAM(const DNSName& zname, const NSEC3PARAMRecordContent& ns3p, const bool& narrow)
343{
344 string error_msg = "";
345 if (!checkNSEC3PARAM(ns3p, error_msg))
86f1af1c 346 throw runtime_error("NSEC3PARAMs provided for zone '"+zname.toLogString()+"' are invalid: " + error_msg);
c7fbe6c9 347
5e91adff 348 clearCaches(zname);
c0273500
BH
349 string descr = ns3p.getZoneRepresentation();
350 vector<string> meta;
351 meta.push_back(descr);
a84a8203
PD
352 if (d_keymetadb->setDomainMetadata(zname, "NSEC3PARAM", meta)) {
353 meta.clear();
354
355 if(narrow)
356 meta.push_back("1");
357
358 return d_keymetadb->setDomainMetadata(zname, "NSEC3NARROW", meta);
359 }
360 return false;
c0273500
BH
361}
362
675fa24c 363bool DNSSECKeeper::unsetNSEC3PARAM(const DNSName& zname)
c0273500 364{
5e91adff 365 clearCaches(zname);
a84a8203 366 return (d_keymetadb->setDomainMetadata(zname, "NSEC3PARAM", vector<string>()) && d_keymetadb->setDomainMetadata(zname, "NSEC3NARROW", vector<string>()));
c0273500
BH
367}
368
369
675fa24c 370bool DNSSECKeeper::setPresigned(const DNSName& zname)
d3e7090c
BH
371{
372 clearCaches(zname);
373 vector<string> meta;
374 meta.push_back("1");
a84a8203 375 return d_keymetadb->setDomainMetadata(zname, "PRESIGNED", meta);
d3e7090c
BH
376}
377
675fa24c 378bool DNSSECKeeper::unsetPresigned(const DNSName& zname)
d3e7090c
BH
379{
380 clearCaches(zname);
a84a8203 381 return d_keymetadb->setDomainMetadata(zname, "PRESIGNED", vector<string>());
d3e7090c
BH
382}
383
ef542223
PL
384/**
385 * Add domainmetadata to allow publishing CDS records for zone zname
386 *
387 * @param zname DNSName of the zone
388 * @param digestAlgos string with comma-separated numbers that describe the
389 * used digest algorithms. This is copied to the database
390 * verbatim
391 * @return true if the data was inserted, false otherwise
392 */
393bool DNSSECKeeper::setPublishCDS(const DNSName& zname, const string& digestAlgos)
394{
395 clearCaches(zname);
396 vector<string> meta;
397 meta.push_back(digestAlgos);
0900d2d3 398 return d_keymetadb->setDomainMetadata(zname, "PUBLISH-CDS", meta);
ef542223
PL
399}
400
c7094551
PD
401void DNSSECKeeper::getPublishCDS(const DNSName& zname, std::string& value)
402{
403 getFromMetaOrDefault(zname, "PUBLISH-CDS", value, ::arg()["default-publish-cds"]);
404}
405
ef542223
PL
406/**
407 * Remove domainmetadata to stop publishing CDS records for zone zname
408 *
409 * @param zname DNSName of the zone
410 * @return true if the operation was successful, false otherwise
411 */
412bool DNSSECKeeper::unsetPublishCDS(const DNSName& zname)
413{
414 clearCaches(zname);
0900d2d3 415 return d_keymetadb->setDomainMetadata(zname, "PUBLISH-CDS", vector<string>());
ef542223
PL
416}
417
088370cd
PL
418/**
419 * Add domainmetadata to allow publishing CDNSKEY records.for zone zname
420 *
421 * @param zname DNSName of the zone
422 * @return true if the data was inserted, false otherwise
423 */
424bool DNSSECKeeper::setPublishCDNSKEY(const DNSName& zname)
425{
426 clearCaches(zname);
427 vector<string> meta;
428 meta.push_back("1");
0900d2d3 429 return d_keymetadb->setDomainMetadata(zname, "PUBLISH-CDNSKEY", meta);
088370cd
PL
430}
431
c7094551
PD
432void DNSSECKeeper::getPublishCDNSKEY(const DNSName& zname, std::string& value)
433{
434 getFromMetaOrDefault(zname, "PUBLISH-CDNSKEY", value, ::arg()["default-publish-cdnskey"]);
435}
436
088370cd
PL
437/**
438 * Remove domainmetadata to stop publishing CDNSKEY records for zone zname
439 *
440 * @param zname DNSName of the zone
441 * @return true if the operation was successful, false otherwise
442 */
443bool DNSSECKeeper::unsetPublishCDNSKEY(const DNSName& zname)
444{
445 clearCaches(zname);
0900d2d3 446 return d_keymetadb->setDomainMetadata(zname, "PUBLISH-CDNSKEY", vector<string>());
088370cd 447}
d3e7090c 448
f889ab99
PL
449/**
450 * Returns all keys that are used to sign the DNSKEY RRSet in a zone
451 *
9091cf89 452 * @param zname DNSName of the zone
f889ab99
PL
453 * @return a keyset_t with all keys that are used to sign the DNSKEY
454 * RRSet (these are the entrypoint(s) to the zone)
455 */
9091cf89 456DNSSECKeeper::keyset_t DNSSECKeeper::getEntryPoints(const DNSName& zname)
f889ab99
PL
457{
458 DNSSECKeeper::keyset_t ret;
9091cf89 459 DNSSECKeeper::keyset_t keys = getKeys(zname);
f889ab99 460
b6bd795c 461 for(auto const &keymeta : keys)
c74f51e2 462 if(keymeta.second.keyType == KSK || keymeta.second.keyType == CSK)
f889ab99 463 ret.push_back(keymeta);
f889ab99
PL
464 return ret;
465}
466
b6bd795c 467DNSSECKeeper::keyset_t DNSSECKeeper::getKeys(const DNSName& zone, bool useCache)
c0273500 468{
030850a9 469 static int ttl = ::arg().asNum("dnssec-key-cache-ttl");
5e91adff 470 unsigned int now = time(0);
157f806e 471
16f7d28d 472 if(!((++s_ops) % 100000)) {
157f806e
PD
473 cleanup();
474 }
475
030850a9 476 if (useCache && ttl > 0) {
18a144ef 477 ReadLock l(&s_keycachelock);
40fe813d 478 keycache_t::const_iterator iter = s_keycache.find(zone);
b6bd795c
PL
479
480 if(iter != s_keycache.end() && iter->d_ttd > now) {
40fe813d 481 keyset_t ret;
b6bd795c
PL
482 for(const keyset_t::value_type& value : iter->d_keys)
483 ret.push_back(value);
40fe813d 484 return ret;
7aff7ead 485 }
b6bd795c
PL
486 }
487
488 keyset_t retkeyset;
3971cf53 489 vector<DNSBackend::KeyData> dbkeyset;
b6bd795c 490
9c1c5d49 491 d_keymetadb->getDomainKeys(zone, dbkeyset);
b6bd795c
PL
492
493 // Determine the algorithms that have a KSK/ZSK split
494 set<uint8_t> algoSEP, algoNoSEP;
495 vector<uint8_t> algoHasSeparateKSK;
496 for(const DNSBackend::KeyData &keydata : dbkeyset) {
c0273500 497 DNSSECPrivateKey dpk;
b6bd795c
PL
498 DNSKEYRecordContent dkrc;
499
500 dpk.setKey(shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::makeFromISCString(dkrc, keydata.content)));
c0273500 501
b6bd795c
PL
502 if(keydata.active) {
503 if(keydata.flags == 257)
504 algoSEP.insert(dkrc.d_algorithm);
505 else
506 algoNoSEP.insert(dkrc.d_algorithm);
507 }
508 }
509 set_intersection(algoSEP.begin(), algoSEP.end(), algoNoSEP.begin(), algoNoSEP.end(), std::back_inserter(algoHasSeparateKSK));
510
511 for(DNSBackend::KeyData& kd : dbkeyset)
512 {
513 DNSSECPrivateKey dpk;
699e6e37 514 DNSKEYRecordContent dkrc;
b6bd795c 515
8d9f38f2 516 dpk.setKey(shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::makeFromISCString(dkrc, kd.content)));
b6bd795c 517
c0273500 518 dpk.d_flags = kd.flags;
a254438f 519 dpk.d_algorithm = dkrc.d_algorithm;
b6bd795c 520
c0273500
BH
521 KeyMetaData kmd;
522
523 kmd.active = kd.active;
33918299 524 kmd.published = kd.published;
b6bd795c 525 kmd.hasSEPBit = (kd.flags == 257);
c0273500 526 kmd.id = kd.id;
b6bd795c
PL
527
528 if (find(algoHasSeparateKSK.begin(), algoHasSeparateKSK.end(), dpk.d_algorithm) == algoHasSeparateKSK.end())
529 kmd.keyType = CSK;
530 else if(kmd.hasSEPBit)
531 kmd.keyType = KSK;
532 else
533 kmd.keyType = ZSK;
534
535 retkeyset.push_back(make_pair(dpk, kmd));
c0273500 536 }
7aff7ead 537 sort(retkeyset.begin(), retkeyset.end(), keyCompareByKindAndID);
b6bd795c 538
030850a9
RG
539 if (ttl > 0) {
540 KeyCacheEntry kce;
541 kce.d_domain=zone;
542 kce.d_keys = retkeyset;
543 kce.d_ttd = now + ttl;
544 {
545 WriteLock l(&s_keycachelock);
94306029 546 lruReplacingInsert<SequencedTag>(s_keycache, kce);
030850a9 547 }
40fe813d 548 }
030850a9 549
7aff7ead 550 return retkeyset;
c0273500
BH
551}
552
ac3f3893 553bool DNSSECKeeper::checkKeys(const DNSName& zone, vector<string>* errorMessages)
8ca3ea33
RG
554{
555 vector<DNSBackend::KeyData> dbkeyset;
9c1c5d49 556 d_keymetadb->getDomainKeys(zone, dbkeyset);
ac3f3893 557 bool retval = true;
8ca3ea33
RG
558
559 for(const DNSBackend::KeyData &keydata : dbkeyset) {
560 DNSKEYRecordContent dkrc;
561 shared_ptr<DNSCryptoKeyEngine> dke(DNSCryptoKeyEngine::makeFromISCString(dkrc, keydata.content));
ac3f3893 562 retval = dke->checkKey(errorMessages) && retval;
8ca3ea33
RG
563 }
564
ac3f3893 565 return retval;
8ca3ea33
RG
566}
567
675fa24c
PD
568bool DNSSECKeeper::getPreRRSIGs(UeberBackend& db, const DNSName& signer, const DNSName& qname,
569 const DNSName& wildcardname, const QType& qtype,
90ba52e0 570 DNSResourceRecord::Place signPlace, vector<DNSZoneRecord>& rrsigs, uint32_t signTTL)
d3e7090c 571{
f1485b68 572 // cerr<<"Doing DB lookup for precomputed RRSIGs for '"<<(wildcardname.empty() ? qname : wildcardname)<<"'"<<endl;
232f0877 573 SOAData sd;
79ba7763 574 if(!db.getSOAUncached(signer, sd)) {
e6a9dde5 575 DLOG(g_log<<"Could not get SOA for domain"<<endl);
232f0877
CH
576 return false;
577 }
acb61e0a 578 db.lookup(QType(QType::RRSIG), wildcardname.countLabels() ? wildcardname : qname, sd.domain_id);
90ba52e0 579 DNSZoneRecord rr;
580 while(db.get(rr)) {
581 auto rrsig = getRR<RRSIGRecordContent>(rr.dr);
582 if(rrsig->d_type == qtype.getCode() && rrsig->d_signer==signer) {
583 if (wildcardname.countLabels())
584 rr.dr.d_name = qname;
585 rr.dr.d_place = signPlace;
586 rr.dr.d_ttl = signTTL;
587 rrsigs.push_back(rr);
588 }
232f0877
CH
589 }
590 return true;
d3e7090c 591}
78bcb858 592
675fa24c 593bool DNSSECKeeper::TSIGGrantsAccess(const DNSName& zone, const DNSName& keyname)
78bcb858
BH
594{
595 vector<string> allowed;
596
936eb34a 597 d_keymetadb->getDomainMetadata(zone, "TSIG-ALLOW-AXFR", allowed);
78bcb858 598
ef7cd021 599 for(const string& dbkey : allowed) {
675fa24c 600 if(DNSName(dbkey)==keyname)
78bcb858
BH
601 return true;
602 }
603 return false;
604}
29b92d6f 605
d622042f 606bool DNSSECKeeper::getTSIGForAccess(const DNSName& zone, const ComboAddress& master, DNSName* keyname)
29b92d6f
BH
607{
608 vector<string> keynames;
936eb34a 609 d_keymetadb->getDomainMetadata(zone, "AXFR-MASTER-TSIG", keynames);
675fa24c 610 keyname->trimToLabels(0);
29b92d6f
BH
611
612 // XXX FIXME this should check for a specific master!
ef7cd021 613 for(const string& dbkey : keynames) {
675fa24c 614 *keyname=DNSName(dbkey);
29b92d6f
BH
615 return true;
616 }
617 return false;
618}
157f806e 619
cbe8b186
PL
620bool DNSSECKeeper::unSecureZone(const DNSName& zone, string& error, string& info) {
621 // Not calling isSecuredZone(), as it will return false for zones with zero
622 // active keys.
623 DNSSECKeeper::keyset_t keyset=getKeys(zone);
624
625 if(keyset.empty()) {
626 error = "No keys for zone '" + zone.toLogString() + "'.";
627 return false;
628 }
629
630 for(auto& key : keyset) {
631 deactivateKey(zone, key.second.id);
632 removeKey(zone, key.second.id);
633 }
634
635 unsetNSEC3PARAM(zone);
636 unsetPresigned(zone);
637 return true;
638}
639
8d0f207b
PL
640/* Rectifies the zone
641 *
642 * \param zone The zone to rectify
643 * \param error& A string where error messages are added
59102608 644 * \param info& A string where informational messages are added
8d0f207b
PL
645 * \param doTransaction Whether or not to wrap the rectify in a transaction
646 */
59102608 647bool DNSSECKeeper::rectifyZone(const DNSName& zone, string& error, string& info, bool doTransaction) {
25b1ce13
PL
648 if (isPresigned(zone)) {
649 error = "Rectify presigned zone '"+zone.toLogString()+"' is not allowed/necessary.";
650 return false;
651 }
652
a2e700d4
PL
653 UeberBackend* B = d_keymetadb;
654 std::unique_ptr<UeberBackend> b;
655
656 if (d_ourDB) {
b0486ea5
PL
657 if (!doTransaction) {
658 error = "Can not rectify a zone with a new Ueberbackend inside a transaction.";
659 return false;
660 }
a2e700d4
PL
661 // We don't have a *full* Ueberbackend, just a key-only one.
662 // Let's create one and use it
663 b = std::unique_ptr<UeberBackend>(new UeberBackend());
664 B = b.get();
665 }
666
25b1ce13
PL
667 SOAData sd;
668
a2e700d4 669 if(!B->getSOAUncached(zone, sd)) {
25b1ce13
PL
670 error = "No SOA known for '" + zone.toLogString() + "', is such a zone in the database?";
671 return false;
672 }
673
674 sd.db->list(zone, sd.domain_id);
675
59102608 676 ostringstream infostream;
25b1ce13
PL
677 DNSResourceRecord rr;
678 set<DNSName> qnames, nsset, dsnames, insnonterm, delnonterm;
679 map<DNSName,bool> nonterm;
680 vector<DNSResourceRecord> rrs;
681
682 while(sd.db->get(rr)) {
683 rr.qname.makeUsLowerCase();
684 if (rr.qtype.getCode())
685 {
686 rrs.push_back(rr);
687 qnames.insert(rr.qname);
688 if(rr.qtype.getCode() == QType::NS && rr.qname != zone)
689 nsset.insert(rr.qname);
690 if(rr.qtype.getCode() == QType::DS)
691 dsnames.insert(rr.qname);
692 }
693 else
694 delnonterm.insert(rr.qname);
695 }
696
697 NSEC3PARAMRecordContent ns3pr;
2977b073
KM
698 bool securedZone = isSecuredZone(zone);
699 bool haveNSEC3 = false, isOptOut = false, narrow = false;
700
701 if(securedZone) {
702 haveNSEC3 = getNSEC3PARAM(zone, &ns3pr, &narrow);
703 isOptOut = (haveNSEC3 && ns3pr.d_flags);
25b1ce13 704
59102608
RG
705 if(!haveNSEC3) {
706 infostream<<"Adding NSEC ordering information ";
707 }
708 else if(!narrow) {
709 if(!isOptOut) {
42b6e1b7 710 infostream<<"Adding NSEC3 hashed ordering information for '"<<zone<<"'";
59102608
RG
711 }
712 else {
42b6e1b7 713 infostream<<"Adding NSEC3 opt-out hashed ordering information for '"<<zone<<"'";
59102608
RG
714 }
715 } else {
716 infostream<<"Erasing NSEC3 ordering since we are narrow, only setting 'auth' fields";
717 }
718 }
719 else {
720 infostream<<"Adding empty non-terminals for non-DNSSEC zone";
721 }
722
25b1ce13 723 set<DNSName> nsec3set;
2885750a 724 if (haveNSEC3 && (!narrow || !isOptOut)) {
2010ac95 725 for (auto &loopRR: rrs) {
25b1ce13 726 bool skip=false;
2010ac95 727 DNSName shorter = loopRR.qname;
25b1ce13
PL
728 if (shorter != zone && shorter.chopOff() && shorter != zone) {
729 do {
730 if(nsset.count(shorter)) {
731 skip=true;
732 break;
733 }
734 } while(shorter.chopOff() && shorter != zone);
735 }
2010ac95
RG
736 shorter = loopRR.qname;
737 if(!skip && (loopRR.qtype.getCode() != QType::NS || !isOptOut)) {
25b1ce13
PL
738
739 do {
740 if(!nsec3set.count(shorter)) {
741 nsec3set.insert(shorter);
742 }
743 } while(shorter != zone && shorter.chopOff());
744 }
745 }
746 }
747
8d0f207b
PL
748 if (doTransaction)
749 sd.db->startTransaction(zone, -1);
25b1ce13
PL
750
751 bool realrr=true;
752 bool doent=true;
753 uint32_t maxent = ::arg().asNum("max-ent-entries");
754
755 dononterm:;
756 for (const auto& qname: qnames)
757 {
758 bool auth=true;
759 DNSName ordername;
760 auto shorter(qname);
761
762 if(realrr) {
763 do {
764 if(nsset.count(shorter)) {
765 auth=false;
766 break;
767 }
768 } while(shorter.chopOff());
769 } else {
770 auth=nonterm.find(qname)->second;
771 }
772
773 if(haveNSEC3) // NSEC3
774 {
666c7211
KM
775 if(nsec3set.count(qname)) {
776 if(!narrow)
777 ordername=DNSName(toBase32Hex(hashQNameWithSalt(ns3pr, qname)));
778 if(!realrr && !isOptOut)
25b1ce13 779 auth=true;
666c7211 780 }
25b1ce13 781 }
2977b073 782 else if (realrr && securedZone) // NSEC
25b1ce13
PL
783 ordername=qname.makeRelative(zone);
784
25b1ce13
PL
785 sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, qname, ordername, auth);
786
787 if(realrr)
788 {
789 if (dsnames.count(qname))
790 sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, qname, ordername, true, QType::DS);
791 if (!auth || nsset.count(qname)) {
792 ordername.clear();
793 if(isOptOut && !dsnames.count(qname))
794 sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, qname, ordername, false, QType::NS);
795 sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, qname, ordername, false, QType::A);
796 sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, qname, ordername, false, QType::AAAA);
797 }
798
799 if(doent)
800 {
801 shorter=qname;
802 while(shorter!=zone && shorter.chopOff())
803 {
804 if(!qnames.count(shorter))
805 {
806 if(!(maxent))
807 {
e6a9dde5 808 g_log<<Logger::Warning<<"Zone '"<<zone<<"' has too many empty non terminals."<<endl;
25b1ce13
PL
809 insnonterm.clear();
810 delnonterm.clear();
811 doent=false;
812 break;
813 }
814
815 if (!delnonterm.count(shorter) && !nonterm.count(shorter))
816 insnonterm.insert(shorter);
817 else
818 delnonterm.erase(shorter);
819
820 if (!nonterm.count(shorter)) {
821 nonterm.insert(pair<DNSName, bool>(shorter, auth));
822 --maxent;
823 } else if (auth)
824 nonterm[shorter]=true;
825 }
826 }
827 }
828 }
829 }
830
831 if(realrr)
832 {
833 //cerr<<"Total: "<<nonterm.size()<<" Insert: "<<insnonterm.size()<<" Delete: "<<delnonterm.size()<<endl;
834 if(!insnonterm.empty() || !delnonterm.empty() || !doent)
835 {
836 sd.db->updateEmptyNonTerminals(sd.domain_id, insnonterm, delnonterm, !doent);
837 }
838 if(doent)
839 {
840 realrr=false;
841 qnames.clear();
842 for(const auto& nt : nonterm){
843 qnames.insert(nt.first);
844 }
845 goto dononterm;
846 }
847 }
848
8d0f207b
PL
849 if (doTransaction)
850 sd.db->commitTransaction();
25b1ce13 851
59102608 852 info = infostream.str();
25b1ce13
PL
853 return true;
854}
855
157f806e
PD
856void DNSSECKeeper::cleanup()
857{
858 struct timeval now;
859 Utility::gettimeofday(&now, 0);
860
861 if(now.tv_sec - s_last_prune > (time_t)(30)) {
862 {
18a144ef 863 WriteLock l(&s_metacachelock);
307994e7 864 pruneCollection<SequencedTag>(*this, s_metacache, s_maxEntries);
157f806e
PD
865 }
866 {
18a144ef 867 WriteLock l(&s_keycachelock);
307994e7 868 pruneCollection<SequencedTag>(*this, s_keycache, s_maxEntries);
157f806e 869 }
307994e7 870 s_last_prune = time(nullptr);
157f806e 871 }
627d2ca2 872}
307994e7
RG
873
874void DNSSECKeeper::setMaxEntries(size_t maxEntries)
875{
876 s_maxEntries = maxEntries;
877#if BOOST_VERSION >= 105600
878 WriteLock wl(&s_keycachelock);
879 s_keycache.get<KeyCacheTag>().reserve(s_maxEntries);
880#endif /* BOOST_VERSION >= 105600 */
881}