1 /*
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  */
22 #pragma once
23 #include <string>
24 #include <string.h>
25 #include <vector>
26 #include <boost/logic/tribool.hpp>
27 #include <boost/multi_index_container.hpp>
28 #include <boost/multi_index/hashed_index.hpp>
29 #include <boost/multi_index/ordered_index.hpp>
30 #include <boost/tuple/tuple_comparison.hpp>
31 #include <boost/multi_index/key_extractors.hpp>
32 #include <boost/multi_index/sequenced_index.hpp>
33 #include "dnssecinfra.hh"
34 #include "dnsrecords.hh"
35 #include "ueberbackend.hh"
36 #include "lock.hh"
37 
38 using namespace ::boost::multi_index;
39 
40 class DNSSECKeeper : public boost::noncopyable
41 {
42 public:
43   enum keytype_t { KSK, ZSK, CSK };
44   enum keyalgorithm_t : uint8_t {
45     RSAMD5=1,
46     DH=2,
47     DSA=3,
48     RSASHA1=5,
49     DSANSEC3SHA1=6,
50     RSASHA1NSEC3SHA1=7,
51     RSASHA256=8,
52     RSASHA512=10,
53     ECCGOST=12,
54     ECDSA256=13,
55     ECDSA384=14,
56     ED25519=15,
57     ED448=16
58   };
59 
60   enum dsdigestalgorithm_t : uint8_t {
61     DIGEST_SHA1=1,
62     DIGEST_SHA256=2,
63     DIGEST_GOST=3,
64     DIGEST_SHA384=4
65   };
66 
67   struct KeyMetaData
68   {
69     string fname;
70     unsigned int id;
71     bool active;
72     keytype_t keyType;
73     bool hasSEPBit;
74     bool published;
75   };
76   typedef std::pair<DNSSECPrivateKey, KeyMetaData> keymeta_t;
77   typedef std::vector<keymeta_t > keyset_t;
78 
keyTypeToString(const keytype_t & keyType)79   static string keyTypeToString(const keytype_t &keyType)
80   {
81     switch(keyType) {
82       case DNSSECKeeper::KSK:
83         return("KSK");
84       case DNSSECKeeper::ZSK:
85         return("ZSK");
86       case DNSSECKeeper::CSK:
87         return("CSK");
88       default:
89         return("UNKNOWN");
90     }
91   }
92 
93   /*
94    * Returns the algorithm number based on the mnemonic (or old PowerDNS value of) a string.
95    * See https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml for the mapping
96    */
shorthand2algorithm(const string & algorithm)97   static int shorthand2algorithm(const string &algorithm)
98   {
99     if (pdns_iequals(algorithm, "rsamd5")) return RSAMD5;
100     if (pdns_iequals(algorithm, "dh")) return DH;
101     if (pdns_iequals(algorithm, "dsa")) return DSA;
102     if (pdns_iequals(algorithm, "rsasha1")) return RSASHA1;
103     if (pdns_iequals(algorithm, "dsa-nsec3-sha1")) return DSANSEC3SHA1;
104     if (pdns_iequals(algorithm, "rsasha1-nsec3-sha1")) return RSASHA1NSEC3SHA1;
105     if (pdns_iequals(algorithm, "rsasha256")) return RSASHA256;
106     if (pdns_iequals(algorithm, "rsasha512")) return RSASHA512;
107     if (pdns_iequals(algorithm, "ecc-gost")) return ECCGOST;
108     if (pdns_iequals(algorithm, "gost")) return ECCGOST;
109     if (pdns_iequals(algorithm, "ecdsa256")) return ECDSA256;
110     if (pdns_iequals(algorithm, "ecdsap256sha256")) return ECDSA256;
111     if (pdns_iequals(algorithm, "ecdsa384")) return ECDSA384;
112     if (pdns_iequals(algorithm, "ecdsap384sha384")) return ECDSA384;
113     if (pdns_iequals(algorithm, "ed25519")) return ED25519;
114     if (pdns_iequals(algorithm, "ed448")) return ED448;
115     if (pdns_iequals(algorithm, "indirect")) return 252;
116     if (pdns_iequals(algorithm, "privatedns")) return 253;
117     if (pdns_iequals(algorithm, "privateoid")) return 254;
118     return -1;
119   }
120 
121   /*
122    * Returns the mnemonic from https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml
123    */
algorithm2name(uint8_t algo)124   static string algorithm2name(uint8_t algo) {
125     switch(algo) {
126       case 0:
127       case 4:
128       case 9:
129       case 11:
130         return "Reserved";
131       case RSAMD5:
132         return "RSAMD5";
133       case DH:
134         return "DH";
135       case DSA:
136         return "DSA";
137       case RSASHA1:
138         return "RSASHA1";
139       case DSANSEC3SHA1:
140         return "DSA-NSEC3-SHA1";
141       case RSASHA1NSEC3SHA1:
142         return "RSASHA1-NSEC3-SHA1";
143       case RSASHA256:
144         return "RSASHA256";
145       case RSASHA512:
146         return "RSASHA512";
147       case ECCGOST:
148         return "ECC-GOST";
149       case ECDSA256:
150         return "ECDSAP256SHA256";
151       case ECDSA384:
152         return "ECDSAP384SHA384";
153       case ED25519:
154         return "ED25519";
155       case ED448:
156         return "ED448";
157       case 252:
158         return "INDIRECT";
159       case 253:
160         return "PRIVATEDNS";
161       case 254:
162         return "PRIVATEOID";
163       default:
164         return "Unallocated/Reserved";
165     }
166   }
167 
168 private:
169   UeberBackend* d_keymetadb;
170   bool d_ourDB;
171 
172 public:
DNSSECKeeper()173   DNSSECKeeper() : d_keymetadb( new UeberBackend("key-only")), d_ourDB(true)
174   {
175 
176   }
177 
DNSSECKeeper(UeberBackend * db)178   DNSSECKeeper(UeberBackend* db) : d_keymetadb(db), d_ourDB(false)
179   {
180   }
181 
~DNSSECKeeper()182   ~DNSSECKeeper()
183   {
184     if(d_ourDB)
185       delete d_keymetadb;
186   }
187 
188   static uint64_t dbdnssecCacheSizes(const std::string& str);
189   static void clearAllCaches();
190   static bool clearKeyCache(const DNSName& name);
191   static bool clearMetaCache(const DNSName& name);
192   static void clearCaches(const DNSName& name);
193 
194   bool doesDNSSEC();
195   bool isSecuredZone(const DNSName& zone, bool useCache=true);
196   keyset_t getEntryPoints(const DNSName& zname);
197   keyset_t getKeys(const DNSName& zone, bool useCache = true);
198   DNSSECPrivateKey getKeyById(const DNSName& zone, unsigned int id);
199   bool addKey(const DNSName& zname, bool setSEPBit, int algorithm, int64_t& id, int bits=0, bool active=true, bool published=true);
200   bool addKey(const DNSName& zname, const DNSSECPrivateKey& dpk, int64_t& id, bool active=true, bool published=true);
201   bool removeKey(const DNSName& zname, unsigned int id);
202   bool activateKey(const DNSName& zname, unsigned int id);
203   bool deactivateKey(const DNSName& zname, unsigned int id);
204   bool publishKey(const DNSName& zname, unsigned int id);
205   bool unpublishKey(const DNSName& zname, unsigned int id);
206   bool checkKeys(const DNSName& zname, vector<string>* errorMessages = nullptr);
207 
208   bool getNSEC3PARAM(const DNSName& zname, NSEC3PARAMRecordContent* n3p=0, bool* narrow=0, bool useCache=true);
209   bool checkNSEC3PARAM(const NSEC3PARAMRecordContent& ns3p, string& msg);
210   bool setNSEC3PARAM(const DNSName& zname, const NSEC3PARAMRecordContent& n3p, const bool& narrow=false);
211   bool unsetNSEC3PARAM(const DNSName& zname);
212   void getPreRRSIGs(UeberBackend& db, vector<DNSZoneRecord>& rrs, uint32_t signTTL);
213   bool isPresigned(const DNSName& zname, bool useCache=true);
214   bool setPresigned(const DNSName& zname);
215   bool unsetPresigned(const DNSName& zname);
216   bool setPublishCDNSKEY(const DNSName& zname, bool deleteAlg);
217   void getPublishCDNSKEY(const DNSName& zname, std::string& value);
218   bool unsetPublishCDNSKEY(const DNSName& zname);
219   bool setPublishCDS(const DNSName& zname, const string& digestAlgos);
220   void getPublishCDS(const DNSName& zname, std::string& value);
221   bool unsetPublishCDS(const DNSName& zname);
222 
223   bool TSIGGrantsAccess(const DNSName& zone, const DNSName& keyname);
224   bool getTSIGForAccess(const DNSName& zone, const ComboAddress& master, DNSName* keyname);
225 
startTransaction(const DNSName & zone,int zone_id)226   void startTransaction(const DNSName& zone, int zone_id)
227   {
228     (*d_keymetadb->backends.begin())->startTransaction(zone, zone_id);
229   }
230 
commitTransaction()231   void commitTransaction()
232   {
233     (*d_keymetadb->backends.begin())->commitTransaction();
234   }
235 
236   void getFromMetaOrDefault(const DNSName& zname, const std::string& key, std::string& value, const std::string& defaultvalue);
237   bool getFromMeta(const DNSName& zname, const std::string& key, std::string& value);
238   void getSoaEdit(const DNSName& zname, std::string& value, bool useCache=true);
239   bool unSecureZone(const DNSName& zone, std::string& error, std::string& info);
240   bool rectifyZone(const DNSName& zone, std::string& error, std::string& info, bool doTransaction);
241 
242   static void setMaxEntries(size_t maxEntries);
243 
244   typedef std::map<std::string, std::vector<std::string> > METAValues;
245 private:
246   bool getFromMetaNoCache(const DNSName& name, const std::string& kind, std::string& value);
247 
248   int64_t d_metaCacheCleanAction{0};
249   bool d_metaUpdate{false};
250 
251   struct KeyCacheEntry
252   {
253     typedef vector<DNSSECKeeper::keymeta_t> keys_t;
254 
getTTDDNSSECKeeper::KeyCacheEntry255     uint32_t getTTD() const
256     {
257       return d_ttd;
258     }
259 
260     DNSName d_domain;
261     mutable keys_t d_keys;
262     unsigned int d_ttd;
263   };
264 
265   struct METACacheEntry
266   {
getTTDDNSSECKeeper::METACacheEntry267     time_t getTTD() const
268     {
269       return d_ttd;
270     }
271 
272     DNSName d_domain;
273     mutable METAValues d_value;
274     time_t d_ttd;
275   };
276 
277   struct KeyCacheTag{};
278   struct CompositeTag{};
279   struct SequencedTag{};
280 
281   typedef multi_index_container<
282     KeyCacheEntry,
283     indexed_by<
284       hashed_unique<tag<KeyCacheTag>,member<KeyCacheEntry, DNSName, &KeyCacheEntry::d_domain> >,
285       sequenced<tag<SequencedTag>>
286     >
287   > keycache_t;
288 
289   typedef multi_index_container<
290     METACacheEntry,
291     indexed_by<
292       ordered_unique<member<METACacheEntry, DNSName, &METACacheEntry::d_domain> >,
293       sequenced<tag<SequencedTag>>
294     >
295   > metacache_t;
296 
297   void cleanup();
298 
299   static keycache_t s_keycache;
300   static metacache_t s_metacache;
301   static int64_t s_metaCacheCleanActions;
302   static ReadWriteLock s_metacachelock;
303   static ReadWriteLock s_keycachelock;
304   static AtomicCounter s_ops;
305   static time_t s_last_prune;
306   static size_t s_maxEntries;
307 
308 public:
preRemoval(const KeyCacheEntry &)309   void preRemoval(const KeyCacheEntry&)
310   {
311   }
preRemoval(const METACacheEntry &)312   void preRemoval(const METACacheEntry&)
313   {
314   }
315 };
316 
317 class DNSPacket;
318 uint32_t localtime_format_YYYYMMDDSS(time_t t, uint32_t seq);
319 // for SOA-EDIT
320 uint32_t calculateEditSOA(uint32_t old_serial, DNSSECKeeper& dk, const DNSName& zonename);
321 uint32_t calculateEditSOA(uint32_t old_serial, const string& kind, const DNSName& zonename);
322 // for SOA-EDIT-DNSUPDATE/API
323 bool increaseSOARecord(DNSResourceRecord& dr, const string& increaseKind, const string& editKind);
324 bool makeIncreasedSOARecord(SOAData& sd, const string& increaseKind, const string& editKind, DNSResourceRecord& rrout);
325 DNSZoneRecord makeEditedDNSZRFromSOAData(DNSSECKeeper& dk, const SOAData& sd, DNSResourceRecord::Place place=DNSResourceRecord::ANSWER);
326