]>
Commit | Line | Data |
---|---|---|
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> | |
78bcb858 | 38 | #include "base64.hh" |
157f806e PD |
39 | #include "cachecleaner.hh" |
40 | #include "arguments.hh" | |
d473cb9a BH |
41 | |
42 | ||
c0273500 | 43 | using namespace boost::assign; |
9cb28241 | 44 | #include "namespaces.hh" |
de43ec0f | 45 | |
c0273500 | 46 | |
40fe813d | 47 | DNSSECKeeper::keycache_t DNSSECKeeper::s_keycache; |
d6f3dcdc | 48 | DNSSECKeeper::metacache_t DNSSECKeeper::s_metacache; |
18a144ef BH |
49 | pthread_rwlock_t DNSSECKeeper::s_metacachelock = PTHREAD_RWLOCK_INITIALIZER; |
50 | pthread_rwlock_t DNSSECKeeper::s_keycachelock = PTHREAD_RWLOCK_INITIALIZER; | |
16f7d28d | 51 | AtomicCounter DNSSECKeeper::s_ops; |
157f806e | 52 | time_t DNSSECKeeper::s_last_prune; |
d473cb9a | 53 | |
675fa24c | 54 | bool DNSSECKeeper::isSecuredZone(const DNSName& zone) |
c0273500 | 55 | { |
d3e7090c | 56 | if(isPresigned(zone)) |
d6f3dcdc | 57 | return true; |
157f806e | 58 | |
8a95b04c KM |
59 | keyset_t keys = getKeys(zone); // does the cache |
60 | ||
ef7cd021 | 61 | for(keyset_t::value_type& val : keys) { |
ade1b1e9 BH |
62 | if(val.second.active) { |
63 | return true; | |
64 | } | |
c0273500 | 65 | } |
ade1b1e9 | 66 | return false; |
c0273500 BH |
67 | } |
68 | ||
675fa24c | 69 | bool DNSSECKeeper::isPresigned(const DNSName& name) |
d3e7090c | 70 | { |
9cb28241 BH |
71 | string meta; |
72 | getFromMeta(name, "PRESIGNED", meta); | |
73 | return meta=="1"; | |
d3e7090c | 74 | } |
c0273500 | 75 | |
b6bd795c | 76 | bool DNSSECKeeper::addKey(const DNSName& name, bool setSEPBit, int algorithm, int bits, bool active) |
c0273500 | 77 | { |
022e5e0b BH |
78 | if(!bits) { |
79 | if(algorithm <= 10) | |
b6bd795c | 80 | throw runtime_error("Creating an algorithm " +std::to_string(algorithm)+" ("+algorithm2name(algorithm)+") key requires the size (in bits) to be passed"); |
022e5e0b | 81 | else { |
45826dd7 | 82 | if(algorithm == 12 || algorithm == 13 || algorithm == 250) // GOST, ECDSAP256SHA256, ED25519SHA512 |
022e5e0b | 83 | bits = 256; |
45826dd7 | 84 | else if(algorithm == 14) // ECDSAP384SHA384 |
022e5e0b BH |
85 | bits = 384; |
86 | else { | |
335da0ba | 87 | throw runtime_error("Can't guess key size for algorithm "+std::to_string(algorithm)); |
022e5e0b BH |
88 | } |
89 | } | |
90 | } | |
699e6e37 | 91 | DNSSECPrivateKey dspk; |
b6bd795c | 92 | shared_ptr<DNSCryptoKeyEngine> dpk(DNSCryptoKeyEngine::make(algorithm)); |
699e6e37 BH |
93 | dpk->create(bits); |
94 | dspk.setKey(dpk); | |
95 | dspk.d_algorithm = algorithm; | |
b6bd795c | 96 | dspk.d_flags = setSEPBit ? 257 : 256; |
40fe813d | 97 | return addKey(name, dspk, active); |
f7bcc763 BH |
98 | } |
99 | ||
627d2ca2 PD |
100 | void DNSSECKeeper::clearAllCaches() { |
101 | { | |
18a144ef | 102 | WriteLock l(&s_keycachelock); |
627d2ca2 PD |
103 | s_keycache.clear(); |
104 | } | |
18a144ef | 105 | WriteLock l(&s_metacachelock); |
627d2ca2 PD |
106 | s_metacache.clear(); |
107 | } | |
108 | ||
675fa24c | 109 | void DNSSECKeeper::clearCaches(const DNSName& name) |
5e91adff | 110 | { |
40fe813d | 111 | { |
18a144ef | 112 | WriteLock l(&s_keycachelock); |
40fe813d BH |
113 | s_keycache.erase(name); |
114 | } | |
18a144ef | 115 | WriteLock l(&s_metacachelock); |
0b7d7191 | 116 | pair<metacache_t::iterator, metacache_t::iterator> range = s_metacache.equal_range(tie(name)); |
d6f3dcdc BH |
117 | while(range.first != range.second) |
118 | s_metacache.erase(range.first++); | |
5e91adff BH |
119 | } |
120 | ||
121 | ||
675fa24c | 122 | bool DNSSECKeeper::addKey(const DNSName& name, const DNSSECPrivateKey& dpk, bool active) |
f7bcc763 | 123 | { |
5e91adff | 124 | clearCaches(name); |
c0273500 | 125 | DNSBackend::KeyData kd; |
7ddd79a7 | 126 | kd.flags = dpk.d_flags; // the dpk doesn't get stored, only they key part |
c0273500 | 127 | kd.active = active; |
189bb9d2 | 128 | kd.content = dpk.getKey()->convertToISC(); |
c0273500 | 129 | // now store it |
936eb34a | 130 | return d_keymetadb->addDomainKey(name, kd) >= 0; // >= 0 == s |
c0273500 BH |
131 | } |
132 | ||
133 | ||
134 | static bool keyCompareByKindAndID(const DNSSECKeeper::keyset_t::value_type& a, const DNSSECKeeper::keyset_t::value_type& b) | |
135 | { | |
b6bd795c PL |
136 | return make_pair(!a.second.keyType, a.second.id) < |
137 | make_pair(!b.second.keyType, b.second.id); | |
c0273500 BH |
138 | } |
139 | ||
675fa24c | 140 | DNSSECPrivateKey DNSSECKeeper::getKeyById(const DNSName& zname, unsigned int id) |
c0273500 | 141 | { |
c0273500 | 142 | vector<DNSBackend::KeyData> keys; |
936eb34a | 143 | d_keymetadb->getDomainKeys(zname, 0, keys); |
ef7cd021 | 144 | for(const DNSBackend::KeyData& kd : keys) { |
c0273500 BH |
145 | if(kd.id != id) |
146 | continue; | |
147 | ||
148 | DNSSECPrivateKey dpk; | |
699e6e37 | 149 | DNSKEYRecordContent dkrc; |
8d9f38f2 | 150 | dpk.setKey(shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::makeFromISCString(dkrc, kd.content))); |
c0273500 | 151 | dpk.d_flags = kd.flags; |
a254438f | 152 | dpk.d_algorithm = dkrc.d_algorithm; |
c0273500 | 153 | |
a254438f BH |
154 | if(dpk.d_algorithm == 5 && getNSEC3PARAM(zname)) { |
155 | dpk.d_algorithm += 2; | |
156 | } | |
c0273500 BH |
157 | |
158 | return dpk; | |
159 | } | |
335da0ba | 160 | throw runtime_error("Can't find a key with id "+std::to_string(id)+" for zone '"+zname.toString()+"'"); |
c0273500 BH |
161 | } |
162 | ||
163 | ||
675fa24c | 164 | bool DNSSECKeeper::removeKey(const DNSName& zname, unsigned int id) |
c0273500 | 165 | { |
5e91adff | 166 | clearCaches(zname); |
a84a8203 | 167 | return d_keymetadb->removeDomainKey(zname, id); |
c0273500 BH |
168 | } |
169 | ||
675fa24c | 170 | bool DNSSECKeeper::deactivateKey(const DNSName& zname, unsigned int id) |
c0273500 | 171 | { |
5e91adff | 172 | clearCaches(zname); |
a84a8203 | 173 | return d_keymetadb->deactivateDomainKey(zname, id); |
c0273500 BH |
174 | } |
175 | ||
675fa24c | 176 | bool DNSSECKeeper::activateKey(const DNSName& zname, unsigned int id) |
c0273500 | 177 | { |
5e91adff | 178 | clearCaches(zname); |
a84a8203 | 179 | return d_keymetadb->activateDomainKey(zname, id); |
c0273500 BH |
180 | } |
181 | ||
d6f3dcdc | 182 | |
675fa24c | 183 | void DNSSECKeeper::getFromMeta(const DNSName& zname, const std::string& key, std::string& value) |
c0273500 | 184 | { |
030850a9 | 185 | static int ttl = ::arg().asNum("domain-metadata-cache-ttl"); |
d6f3dcdc | 186 | value.clear(); |
5e91adff | 187 | unsigned int now = time(0); |
157f806e | 188 | |
16f7d28d | 189 | if(!((++s_ops) % 100000)) { |
157f806e PD |
190 | cleanup(); |
191 | } | |
192 | ||
030850a9 | 193 | if (ttl > 0) { |
18a144ef | 194 | ReadLock l(&s_metacachelock); |
d473cb9a | 195 | |
d6f3dcdc BH |
196 | metacache_t::const_iterator iter = s_metacache.find(tie(zname, key)); |
197 | if(iter != s_metacache.end() && iter->d_ttd > now) { | |
198 | value = iter->d_value; | |
199 | return; | |
d473cb9a | 200 | } |
22c5aa60 | 201 | } |
d473cb9a | 202 | vector<string> meta; |
936eb34a | 203 | d_keymetadb->getDomainMetadata(zname, key, meta); |
d6f3dcdc BH |
204 | if(!meta.empty()) |
205 | value=*meta.begin(); | |
030850a9 RG |
206 | |
207 | if (ttl > 0) { | |
208 | METACacheEntry nce; | |
209 | nce.d_domain=zname; | |
210 | nce.d_ttd = now + ttl; | |
211 | nce.d_key= key; | |
212 | nce.d_value = value; | |
213 | { | |
214 | WriteLock l(&s_metacachelock); | |
215 | replacing_insert(s_metacache, nce); | |
216 | } | |
d473cb9a | 217 | } |
d6f3dcdc BH |
218 | } |
219 | ||
4192773a KM |
220 | void DNSSECKeeper::getSoaEdit(const DNSName& zname, std::string& value) |
221 | { | |
222 | static const string soaEdit(::arg()["default-soa-edit"]); | |
223 | static const string soaEditSigned(::arg()["default-soa-edit-signed"]); | |
224 | ||
225 | getFromMeta(zname, "SOA-EDIT", value); | |
226 | ||
227 | if ((!soaEdit.empty() || !soaEditSigned.empty()) && value.empty() && !isPresigned(zname)) { | |
228 | if (!soaEditSigned.empty() && isSecuredZone(zname)) | |
229 | value=soaEditSigned; | |
230 | if (value.empty()) | |
231 | value=soaEdit; | |
232 | } | |
233 | ||
234 | return; | |
235 | } | |
236 | ||
e903706d | 237 | uint64_t DNSSECKeeper::dbdnssecCacheSizes(const std::string& str) |
238 | { | |
239 | if(str=="meta-cache-size") { | |
240 | ReadLock l(&s_metacachelock); | |
241 | return s_metacache.size(); | |
242 | } | |
243 | else if(str=="key-cache-size") { | |
244 | ReadLock l(&s_keycachelock); | |
245 | return s_keycache.size(); | |
246 | } | |
247 | return (uint64_t)-1; | |
248 | } | |
249 | ||
675fa24c | 250 | bool DNSSECKeeper::getNSEC3PARAM(const DNSName& zname, NSEC3PARAMRecordContent* ns3p, bool* narrow) |
d6f3dcdc BH |
251 | { |
252 | string value; | |
253 | getFromMeta(zname, "NSEC3PARAM", value); | |
5935cede | 254 | if(value.empty()) { // "no NSEC3" |
d6f3dcdc | 255 | return false; |
5935cede | 256 | } |
28b66a94 KM |
257 | |
258 | static int maxNSEC3Iterations=::arg().asNum("max-nsec3-iterations"); | |
c0273500 | 259 | if(ns3p) { |
d6f3dcdc | 260 | NSEC3PARAMRecordContent* tmp=dynamic_cast<NSEC3PARAMRecordContent*>(DNSRecordContent::mastermake(QType::NSEC3PARAM, 1, value)); |
c0273500 BH |
261 | *ns3p = *tmp; |
262 | delete tmp; | |
28b66a94 KM |
263 | if (ns3p->d_iterations > maxNSEC3Iterations) { |
264 | ns3p->d_iterations = maxNSEC3Iterations; | |
f43c4448 | 265 | L<<Logger::Error<<"Number of NSEC3 iterations for zone '"<<zname<<"' is above 'max-nsec3-iterations'. Value adjusted to: "<<maxNSEC3Iterations<<endl; |
28b66a94 | 266 | } |
c7fbe6c9 PL |
267 | if (ns3p->d_algorithm != 1) { |
268 | L<<Logger::Error<<"Invalid hash algorithm for NSEC3: '"<<std::to_string(ns3p->d_algorithm)<<"', setting to 1 for zone '"<<zname<<"'."<<endl; | |
269 | ns3p->d_algorithm = 1; | |
270 | } | |
c0273500 | 271 | } |
d6f3dcdc BH |
272 | if(narrow) { |
273 | getFromMeta(zname, "NSEC3NARROW", value); | |
274 | *narrow = (value=="1"); | |
275 | } | |
c0273500 BH |
276 | return true; |
277 | } | |
278 | ||
675fa24c | 279 | bool DNSSECKeeper::setNSEC3PARAM(const DNSName& zname, const NSEC3PARAMRecordContent& ns3p, const bool& narrow) |
c0273500 | 280 | { |
28b66a94 KM |
281 | static int maxNSEC3Iterations=::arg().asNum("max-nsec3-iterations"); |
282 | if (ns3p.d_iterations > maxNSEC3Iterations) | |
675fa24c | 283 | throw runtime_error("Can't set NSEC3PARAM for zone '"+zname.toString()+"': number of NSEC3 iterations is above 'max-nsec3-iterations'"); |
28b66a94 | 284 | |
c7fbe6c9 PL |
285 | if (ns3p.d_algorithm != 1) |
286 | throw runtime_error("Invalid hash algorithm for NSEC3: '"+std::to_string(ns3p.d_algorithm)+"' for zone '"+zname.toString()+"'. The only valid value is '1'"); | |
287 | ||
5e91adff | 288 | clearCaches(zname); |
c0273500 BH |
289 | string descr = ns3p.getZoneRepresentation(); |
290 | vector<string> meta; | |
291 | meta.push_back(descr); | |
a84a8203 PD |
292 | if (d_keymetadb->setDomainMetadata(zname, "NSEC3PARAM", meta)) { |
293 | meta.clear(); | |
294 | ||
295 | if(narrow) | |
296 | meta.push_back("1"); | |
297 | ||
298 | return d_keymetadb->setDomainMetadata(zname, "NSEC3NARROW", meta); | |
299 | } | |
300 | return false; | |
c0273500 BH |
301 | } |
302 | ||
675fa24c | 303 | bool DNSSECKeeper::unsetNSEC3PARAM(const DNSName& zname) |
c0273500 | 304 | { |
5e91adff | 305 | clearCaches(zname); |
a84a8203 | 306 | return (d_keymetadb->setDomainMetadata(zname, "NSEC3PARAM", vector<string>()) && d_keymetadb->setDomainMetadata(zname, "NSEC3NARROW", vector<string>())); |
c0273500 BH |
307 | } |
308 | ||
309 | ||
675fa24c | 310 | bool DNSSECKeeper::setPresigned(const DNSName& zname) |
d3e7090c BH |
311 | { |
312 | clearCaches(zname); | |
313 | vector<string> meta; | |
314 | meta.push_back("1"); | |
a84a8203 | 315 | return d_keymetadb->setDomainMetadata(zname, "PRESIGNED", meta); |
d3e7090c BH |
316 | } |
317 | ||
675fa24c | 318 | bool DNSSECKeeper::unsetPresigned(const DNSName& zname) |
d3e7090c BH |
319 | { |
320 | clearCaches(zname); | |
a84a8203 | 321 | return d_keymetadb->setDomainMetadata(zname, "PRESIGNED", vector<string>()); |
d3e7090c BH |
322 | } |
323 | ||
ef542223 PL |
324 | /** |
325 | * Add domainmetadata to allow publishing CDS records for zone zname | |
326 | * | |
327 | * @param zname DNSName of the zone | |
328 | * @param digestAlgos string with comma-separated numbers that describe the | |
329 | * used digest algorithms. This is copied to the database | |
330 | * verbatim | |
331 | * @return true if the data was inserted, false otherwise | |
332 | */ | |
333 | bool DNSSECKeeper::setPublishCDS(const DNSName& zname, const string& digestAlgos) | |
334 | { | |
335 | clearCaches(zname); | |
336 | vector<string> meta; | |
337 | meta.push_back(digestAlgos); | |
0900d2d3 | 338 | return d_keymetadb->setDomainMetadata(zname, "PUBLISH-CDS", meta); |
ef542223 PL |
339 | } |
340 | ||
341 | /** | |
342 | * Remove domainmetadata to stop publishing CDS records for zone zname | |
343 | * | |
344 | * @param zname DNSName of the zone | |
345 | * @return true if the operation was successful, false otherwise | |
346 | */ | |
347 | bool DNSSECKeeper::unsetPublishCDS(const DNSName& zname) | |
348 | { | |
349 | clearCaches(zname); | |
0900d2d3 | 350 | return d_keymetadb->setDomainMetadata(zname, "PUBLISH-CDS", vector<string>()); |
ef542223 PL |
351 | } |
352 | ||
088370cd PL |
353 | /** |
354 | * Add domainmetadata to allow publishing CDNSKEY records.for zone zname | |
355 | * | |
356 | * @param zname DNSName of the zone | |
357 | * @return true if the data was inserted, false otherwise | |
358 | */ | |
359 | bool DNSSECKeeper::setPublishCDNSKEY(const DNSName& zname) | |
360 | { | |
361 | clearCaches(zname); | |
362 | vector<string> meta; | |
363 | meta.push_back("1"); | |
0900d2d3 | 364 | return d_keymetadb->setDomainMetadata(zname, "PUBLISH-CDNSKEY", meta); |
088370cd PL |
365 | } |
366 | ||
367 | /** | |
368 | * Remove domainmetadata to stop publishing CDNSKEY records for zone zname | |
369 | * | |
370 | * @param zname DNSName of the zone | |
371 | * @return true if the operation was successful, false otherwise | |
372 | */ | |
373 | bool DNSSECKeeper::unsetPublishCDNSKEY(const DNSName& zname) | |
374 | { | |
375 | clearCaches(zname); | |
0900d2d3 | 376 | return d_keymetadb->setDomainMetadata(zname, "PUBLISH-CDNSKEY", vector<string>()); |
088370cd | 377 | } |
d3e7090c | 378 | |
f889ab99 PL |
379 | /** |
380 | * Returns all keys that are used to sign the DNSKEY RRSet in a zone | |
381 | * | |
9091cf89 | 382 | * @param zname DNSName of the zone |
f889ab99 PL |
383 | * @return a keyset_t with all keys that are used to sign the DNSKEY |
384 | * RRSet (these are the entrypoint(s) to the zone) | |
385 | */ | |
9091cf89 | 386 | DNSSECKeeper::keyset_t DNSSECKeeper::getEntryPoints(const DNSName& zname) |
f889ab99 PL |
387 | { |
388 | DNSSECKeeper::keyset_t ret; | |
9091cf89 | 389 | DNSSECKeeper::keyset_t keys = getKeys(zname); |
f889ab99 | 390 | |
b6bd795c PL |
391 | for(auto const &keymeta : keys) |
392 | if(keymeta.second.active && (keymeta.second.keyType == KSK || keymeta.second.keyType == CSK)) | |
f889ab99 | 393 | ret.push_back(keymeta); |
f889ab99 PL |
394 | return ret; |
395 | } | |
396 | ||
b6bd795c | 397 | DNSSECKeeper::keyset_t DNSSECKeeper::getKeys(const DNSName& zone, bool useCache) |
c0273500 | 398 | { |
030850a9 | 399 | static int ttl = ::arg().asNum("dnssec-key-cache-ttl"); |
5e91adff | 400 | unsigned int now = time(0); |
157f806e | 401 | |
16f7d28d | 402 | if(!((++s_ops) % 100000)) { |
157f806e PD |
403 | cleanup(); |
404 | } | |
405 | ||
030850a9 | 406 | if (useCache && ttl > 0) { |
18a144ef | 407 | ReadLock l(&s_keycachelock); |
40fe813d | 408 | keycache_t::const_iterator iter = s_keycache.find(zone); |
b6bd795c PL |
409 | |
410 | if(iter != s_keycache.end() && iter->d_ttd > now) { | |
40fe813d | 411 | keyset_t ret; |
b6bd795c PL |
412 | for(const keyset_t::value_type& value : iter->d_keys) |
413 | ret.push_back(value); | |
40fe813d | 414 | return ret; |
7aff7ead | 415 | } |
b6bd795c PL |
416 | } |
417 | ||
418 | keyset_t retkeyset; | |
3971cf53 | 419 | vector<DNSBackend::KeyData> dbkeyset; |
b6bd795c | 420 | |
936eb34a | 421 | d_keymetadb->getDomainKeys(zone, 0, dbkeyset); |
b6bd795c PL |
422 | |
423 | // Determine the algorithms that have a KSK/ZSK split | |
424 | set<uint8_t> algoSEP, algoNoSEP; | |
425 | vector<uint8_t> algoHasSeparateKSK; | |
426 | for(const DNSBackend::KeyData &keydata : dbkeyset) { | |
c0273500 | 427 | DNSSECPrivateKey dpk; |
b6bd795c PL |
428 | DNSKEYRecordContent dkrc; |
429 | ||
430 | dpk.setKey(shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::makeFromISCString(dkrc, keydata.content))); | |
c0273500 | 431 | |
b6bd795c PL |
432 | if(keydata.active) { |
433 | if(keydata.flags == 257) | |
434 | algoSEP.insert(dkrc.d_algorithm); | |
435 | else | |
436 | algoNoSEP.insert(dkrc.d_algorithm); | |
437 | } | |
438 | } | |
439 | set_intersection(algoSEP.begin(), algoSEP.end(), algoNoSEP.begin(), algoNoSEP.end(), std::back_inserter(algoHasSeparateKSK)); | |
440 | ||
441 | for(DNSBackend::KeyData& kd : dbkeyset) | |
442 | { | |
443 | DNSSECPrivateKey dpk; | |
699e6e37 | 444 | DNSKEYRecordContent dkrc; |
b6bd795c | 445 | |
8d9f38f2 | 446 | dpk.setKey(shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::makeFromISCString(dkrc, kd.content))); |
b6bd795c | 447 | |
c0273500 | 448 | dpk.d_flags = kd.flags; |
a254438f | 449 | dpk.d_algorithm = dkrc.d_algorithm; |
89c8b2ce | 450 | if(dpk.d_algorithm == 5 && getNSEC3PARAM(zone)) |
a254438f | 451 | dpk.d_algorithm+=2; |
b6bd795c | 452 | |
c0273500 BH |
453 | KeyMetaData kmd; |
454 | ||
455 | kmd.active = kd.active; | |
b6bd795c | 456 | kmd.hasSEPBit = (kd.flags == 257); |
c0273500 | 457 | kmd.id = kd.id; |
b6bd795c PL |
458 | |
459 | if (find(algoHasSeparateKSK.begin(), algoHasSeparateKSK.end(), dpk.d_algorithm) == algoHasSeparateKSK.end()) | |
460 | kmd.keyType = CSK; | |
461 | else if(kmd.hasSEPBit) | |
462 | kmd.keyType = KSK; | |
463 | else | |
464 | kmd.keyType = ZSK; | |
465 | ||
466 | retkeyset.push_back(make_pair(dpk, kmd)); | |
c0273500 | 467 | } |
7aff7ead | 468 | sort(retkeyset.begin(), retkeyset.end(), keyCompareByKindAndID); |
b6bd795c | 469 | |
030850a9 RG |
470 | if (ttl > 0) { |
471 | KeyCacheEntry kce; | |
472 | kce.d_domain=zone; | |
473 | kce.d_keys = retkeyset; | |
474 | kce.d_ttd = now + ttl; | |
475 | { | |
476 | WriteLock l(&s_keycachelock); | |
477 | replacing_insert(s_keycache, kce); | |
478 | } | |
40fe813d | 479 | } |
030850a9 | 480 | |
7aff7ead | 481 | return retkeyset; |
c0273500 BH |
482 | } |
483 | ||
8ca3ea33 RG |
484 | bool DNSSECKeeper::checkKeys(const DNSName& zone) |
485 | { | |
486 | vector<DNSBackend::KeyData> dbkeyset; | |
487 | d_keymetadb->getDomainKeys(zone, 0, dbkeyset); | |
488 | ||
489 | for(const DNSBackend::KeyData &keydata : dbkeyset) { | |
490 | DNSKEYRecordContent dkrc; | |
491 | shared_ptr<DNSCryptoKeyEngine> dke(DNSCryptoKeyEngine::makeFromISCString(dkrc, keydata.content)); | |
45c2bc60 | 492 | if (!dke->checkKey()) { |
8ca3ea33 RG |
493 | return false; |
494 | } | |
495 | } | |
496 | ||
497 | return true; | |
498 | } | |
499 | ||
675fa24c PD |
500 | bool DNSSECKeeper::getPreRRSIGs(UeberBackend& db, const DNSName& signer, const DNSName& qname, |
501 | const DNSName& wildcardname, const QType& qtype, | |
e693ff5a | 502 | DNSResourceRecord::Place signPlace, vector<DNSResourceRecord>& rrsigs, uint32_t signTTL) |
d3e7090c | 503 | { |
f1485b68 | 504 | // cerr<<"Doing DB lookup for precomputed RRSIGs for '"<<(wildcardname.empty() ? qname : wildcardname)<<"'"<<endl; |
232f0877 | 505 | SOAData sd; |
79ba7763 | 506 | if(!db.getSOAUncached(signer, sd)) { |
232f0877 CH |
507 | DLOG(L<<"Could not get SOA for domain"<<endl); |
508 | return false; | |
509 | } | |
675fa24c | 510 | db.lookup(QType(QType::RRSIG), wildcardname.countLabels() ? wildcardname : qname, NULL, sd.domain_id); |
232f0877 CH |
511 | DNSResourceRecord rr; |
512 | while(db.get(rr)) { | |
513 | // cerr<<"Considering for '"<<qtype.getName()<<"' RRSIG '"<<rr.content<<"'\n"; | |
514 | vector<string> parts; | |
515 | stringtok(parts, rr.content); | |
675fa24c | 516 | if(parts[0] == qtype.getName() && DNSName(parts[7])==signer) { |
232f0877 | 517 | // cerr<<"Got it"<<endl; |
675fa24c | 518 | if (wildcardname.countLabels()) |
232f0877 | 519 | rr.qname = qname; |
e693ff5a | 520 | rr.d_place = signPlace; |
232f0877 CH |
521 | rr.ttl = signTTL; |
522 | rrsigs.push_back(rr); | |
523 | } | |
e125fc69 | 524 | // else cerr<<"Skipping!"<<endl; |
232f0877 CH |
525 | } |
526 | return true; | |
d3e7090c | 527 | } |
78bcb858 | 528 | |
675fa24c | 529 | bool DNSSECKeeper::TSIGGrantsAccess(const DNSName& zone, const DNSName& keyname) |
78bcb858 BH |
530 | { |
531 | vector<string> allowed; | |
532 | ||
936eb34a | 533 | d_keymetadb->getDomainMetadata(zone, "TSIG-ALLOW-AXFR", allowed); |
78bcb858 | 534 | |
ef7cd021 | 535 | for(const string& dbkey : allowed) { |
675fa24c | 536 | if(DNSName(dbkey)==keyname) |
78bcb858 BH |
537 | return true; |
538 | } | |
539 | return false; | |
540 | } | |
29b92d6f | 541 | |
675fa24c | 542 | bool DNSSECKeeper::getTSIGForAccess(const DNSName& zone, const string& master, DNSName* keyname) |
29b92d6f BH |
543 | { |
544 | vector<string> keynames; | |
936eb34a | 545 | d_keymetadb->getDomainMetadata(zone, "AXFR-MASTER-TSIG", keynames); |
675fa24c | 546 | keyname->trimToLabels(0); |
29b92d6f BH |
547 | |
548 | // XXX FIXME this should check for a specific master! | |
ef7cd021 | 549 | for(const string& dbkey : keynames) { |
675fa24c | 550 | *keyname=DNSName(dbkey); |
29b92d6f BH |
551 | return true; |
552 | } | |
553 | return false; | |
554 | } | |
157f806e PD |
555 | |
556 | void DNSSECKeeper::cleanup() | |
557 | { | |
558 | struct timeval now; | |
559 | Utility::gettimeofday(&now, 0); | |
560 | ||
561 | if(now.tv_sec - s_last_prune > (time_t)(30)) { | |
562 | { | |
18a144ef | 563 | WriteLock l(&s_metacachelock); |
157f806e PD |
564 | pruneCollection(s_metacache, ::arg().asNum("max-cache-entries")); |
565 | } | |
566 | { | |
18a144ef | 567 | WriteLock l(&s_keycachelock); |
157f806e PD |
568 | pruneCollection(s_keycache, ::arg().asNum("max-cache-entries")); |
569 | } | |
570 | s_last_prune=time(0); | |
571 | } | |
627d2ca2 | 572 | } |