]>
Commit | Line | Data |
---|---|---|
12471842 PL |
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 | */ | |
e8c59f2d | 22 | #pragma once |
4691b2df | 23 | #include "dnsrecords.hh" |
dd7da6cd | 24 | |
4691b2df BH |
25 | #include <string> |
26 | #include <vector> | |
f7b9d3b7 | 27 | #include <optional> |
022e5e0b | 28 | #include <map> |
4691b2df | 29 | #include "misc.hh" |
39ec5d29 | 30 | |
31 | class UeberBackend; | |
4691b2df | 32 | |
189bb9d2 BH |
33 | // rules of the road: Algorithm must be set in 'make' for each KeyEngine, and will NEVER change! |
34 | ||
8d9f38f2 | 35 | class DNSCryptoKeyEngine |
699e6e37 BH |
36 | { |
37 | public: | |
189bb9d2 | 38 | explicit DNSCryptoKeyEngine(unsigned int algorithm) : d_algorithm(algorithm) {} |
abb11ca4 | 39 | virtual ~DNSCryptoKeyEngine() = default; |
c2173c78 | 40 | [[nodiscard]] virtual string getName() const = 0; |
1a3b143f | 41 | |
c2173c78 FM |
42 | using stormap_t = std::map<std::string, std::string>; |
43 | using storvector_t = std::vector<std::pair<std::string, std::string>>; | |
699e6e37 | 44 | virtual void create(unsigned int bits)=0; |
c2173c78 | 45 | |
c97af739 | 46 | virtual void createFromPEMFile(DNSKEYRecordContent& /* drc */, std::FILE& /* inputFile */, const std::optional<std::reference_wrapper<const std::string>> filename = std::nullopt) |
87066241 | 47 | { |
c97af739 FM |
48 | if (filename.has_value()) { |
49 | throw std::runtime_error("Can't create key from PEM file `" + filename->get() + "`"); | |
50 | } | |
51 | ||
52 | throw std::runtime_error("Can't create key from PEM contents"); | |
87066241 | 53 | } |
c2173c78 | 54 | |
3de36d82 FM |
55 | /** |
56 | * \brief Creates a key engine from a PEM string. | |
57 | * | |
58 | * Receives PEM contents and creates a key engine. | |
59 | * | |
60 | * \param[in] drc Key record contents to be populated. | |
61 | * | |
62 | * \param[in] contents The PEM string contents. | |
63 | * | |
64 | * \return A key engine populated with the contents of the PEM string. | |
65 | */ | |
66 | void createFromPEMString(DNSKEYRecordContent& drc, const std::string& contents) | |
67 | { | |
68 | // NOLINTNEXTLINE(*-cast): POSIX APIs. | |
46c4985c | 69 | pdns::UniqueFilePtr inputFile{fmemopen(const_cast<char*>(contents.data()), contents.length(), "r")}; |
3de36d82 FM |
70 | createFromPEMFile(drc, *inputFile); |
71 | } | |
72 | ||
c2173c78 FM |
73 | [[nodiscard]] virtual storvector_t convertToISCVector() const =0; |
74 | [[nodiscard]] std::string convertToISC() const ; | |
75 | ||
a8b5e8ba | 76 | virtual void convertToPEMFile(std::FILE& /* outputFile */) const |
18567bc6 FM |
77 | { |
78 | throw std::runtime_error(getName() + ": Conversion to PEM not supported"); | |
79 | }; | |
c2173c78 | 80 | |
d0fa1838 FM |
81 | /** |
82 | * \brief Converts the key into a PEM string. | |
83 | * | |
84 | * \return A string containing the key's PEM contents. | |
85 | */ | |
86 | [[nodiscard]] auto convertToPEMString() const -> std::string | |
87 | { | |
88 | const size_t buflen = 4096; | |
89 | ||
90 | std::string output{}; | |
91 | output.resize(buflen); | |
46c4985c | 92 | pdns::UniqueFilePtr outputFile{fmemopen(output.data(), output.length() - 1, "w")}; |
d0fa1838 FM |
93 | convertToPEMFile(*outputFile); |
94 | std::fflush(outputFile.get()); | |
95 | output.resize(std::ftell(outputFile.get())); | |
96 | ||
97 | return output; | |
98 | }; | |
99 | ||
c2173c78 FM |
100 | [[nodiscard]] virtual std::string sign(const std::string& msg) const =0; |
101 | ||
102 | [[nodiscard]] virtual std::string hash(const std::string& msg) const | |
7c9c554a KM |
103 | { |
104 | throw std::runtime_error("hash() function not implemented"); | |
105 | return msg; | |
106 | } | |
1a3b143f | 107 | |
c2173c78 FM |
108 | [[nodiscard]] virtual bool verify(const std::string& msg, const std::string& signature) const =0; |
109 | ||
c2173c78 FM |
110 | [[nodiscard]] virtual std::string getPublicKeyString()const =0; |
111 | [[nodiscard]] virtual int getBits() const =0; | |
112 | [[nodiscard]] virtual unsigned int getAlgorithm() const | |
8455425c RG |
113 | { |
114 | return d_algorithm; | |
115 | } | |
1a3b143f | 116 | |
0eadf4db | 117 | virtual void fromISCMap(DNSKEYRecordContent& drc, stormap_t& stormap) = 0; |
189bb9d2 | 118 | virtual void fromPublicKeyString(const std::string& content) = 0; |
c2173c78 | 119 | |
f7b9d3b7 | 120 | [[nodiscard]] virtual bool checkKey(std::optional<std::reference_wrapper<std::vector<std::string>>> /* errorMessages */ = std::nullopt) const |
8ca3ea33 RG |
121 | { |
122 | return true; | |
123 | } | |
c2173c78 | 124 | |
a2c6e554 | 125 | static std::unique_ptr<DNSCryptoKeyEngine> makeFromISCFile(DNSKEYRecordContent& drc, const char* fname); |
87066241 FM |
126 | |
127 | /** | |
128 | * \brief Creates a key engine from a PEM file. | |
129 | * | |
e959b65f FM |
130 | * Receives an open file handle with PEM contents and creates a key engine |
131 | * corresponding to the algorithm requested. | |
87066241 FM |
132 | * |
133 | * \param[in] drc Key record contents to be populated. | |
134 | * | |
87066241 FM |
135 | * \param[in] algorithm Which algorithm to use. See |
136 | * https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml | |
137 | * | |
e959b65f FM |
138 | * \param[in] fp An open file handle to a file containing PEM contents. |
139 | * | |
140 | * \param[in] filename Only used for providing filename information in error messages. | |
141 | * | |
142 | * \return A key engine corresponding to the requested algorithm and populated with | |
143 | * the contents of the PEM file. | |
87066241 | 144 | */ |
e959b65f | 145 | static std::unique_ptr<DNSCryptoKeyEngine> makeFromPEMFile(DNSKEYRecordContent& drc, uint8_t algorithm, std::FILE& inputFile, const std::string& filename); |
87066241 | 146 | |
3de36d82 FM |
147 | /** |
148 | * \brief Creates a key engine from a PEM string. | |
149 | * | |
150 | * Receives PEM contents and creates a key engine corresponding to the algorithm | |
151 | * requested. | |
152 | * | |
153 | * \param[in] drc Key record contents to be populated. | |
154 | * | |
155 | * \param[in] algorithm Which algorithm to use. See | |
156 | * https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml | |
157 | * | |
158 | * \param[in] contents The PEM contents. | |
159 | * | |
160 | * \return A key engine corresponding to the requested algorithm and populated with | |
161 | * the contents of the PEM string. | |
162 | */ | |
163 | static std::unique_ptr<DNSCryptoKeyEngine> makeFromPEMString(DNSKEYRecordContent& drc, uint8_t algorithm, const std::string& contents); | |
164 | ||
a2c6e554 | 165 | static std::unique_ptr<DNSCryptoKeyEngine> makeFromISCString(DNSKEYRecordContent& drc, const std::string& content); |
a2c6e554 RG |
166 | static std::unique_ptr<DNSCryptoKeyEngine> makeFromPublicKeyString(unsigned int algorithm, const std::string& raw); |
167 | static std::unique_ptr<DNSCryptoKeyEngine> make(unsigned int algorithm); | |
8455425c | 168 | static bool isAlgorithmSupported(unsigned int algo); |
04cee981 OM |
169 | static bool isAlgorithmSwitchedOff(unsigned int algo); |
170 | static void switchOffAlgorithm(unsigned int algo); | |
8455425c | 171 | static bool isDigestSupported(uint8_t digest); |
1a3b143f | 172 | |
c2173c78 | 173 | using maker_t = std::unique_ptr<DNSCryptoKeyEngine> (unsigned int); |
1a3b143f | 174 | |
f309dacd | 175 | static void report(unsigned int algorithm, maker_t* maker, bool fallback=false); |
f558c987 | 176 | static void testMakers(unsigned int algorithm, maker_t* creator, maker_t* signer, maker_t* verifier); |
98d13a90 | 177 | static vector<pair<uint8_t, string>> listAllAlgosWithBackend(); |
166d8647 KM |
178 | static bool testAll(); |
179 | static bool testOne(int algo); | |
81a94207 | 180 | static bool verifyOne(unsigned int algo); |
a2458070 | 181 | static bool testVerify(unsigned int algo, maker_t* verifier); |
a47ea8ec | 182 | static string listSupportedAlgoNames(); |
1a3b143f | 183 | |
c2173c78 FM |
184 | private: |
185 | using makers_t = std::map<unsigned int, maker_t *>; | |
186 | using allmakers_t = std::map<unsigned int, vector<maker_t *>>; | |
022e5e0b BH |
187 | static makers_t& getMakers() |
188 | { | |
189 | static makers_t s_makers; | |
190 | return s_makers; | |
191 | } | |
189bb9d2 BH |
192 | static allmakers_t& getAllMakers() |
193 | { | |
194 | static allmakers_t s_allmakers; | |
195 | return s_allmakers; | |
196 | } | |
a2458070 | 197 | // Must be set before going multi-threaded and not changed after that |
04cee981 | 198 | static std::unordered_set<unsigned int> s_switchedOff; |
c2173c78 | 199 | |
189bb9d2 BH |
200 | protected: |
201 | const unsigned int d_algorithm; | |
431a3cbc BH |
202 | }; |
203 | ||
431a3cbc BH |
204 | struct DNSSECPrivateKey |
205 | { | |
620d4801 RG |
206 | uint16_t getTag() const |
207 | { | |
208 | return getDNSKEY().getTag(); | |
209 | } | |
1a3b143f | 210 | |
a2c6e554 | 211 | const std::shared_ptr<DNSCryptoKeyEngine>& getKey() const |
699e6e37 | 212 | { |
e69c2dac | 213 | return d_key; |
699e6e37 | 214 | } |
1a3b143f | 215 | |
a456662f | 216 | // be aware that calling setKey() will also set the algorithm |
c5153ca0 | 217 | void setKey(std::shared_ptr<DNSCryptoKeyEngine>& key, uint16_t flags, std::optional<uint8_t> algorithm = std::nullopt) |
699e6e37 BH |
218 | { |
219 | d_key = key; | |
a456662f | 220 | d_flags = flags; |
c5153ca0 | 221 | d_algorithm = algorithm ? *algorithm : d_key->getAlgorithm(); |
a3260095 | 222 | computeDNSKEY(); |
699e6e37 | 223 | } |
a2c6e554 | 224 | |
a456662f | 225 | // be aware that calling setKey() will also set the algorithm |
c5153ca0 | 226 | void setKey(std::unique_ptr<DNSCryptoKeyEngine>&& key, uint16_t flags, std::optional<uint8_t> algorithm = std::nullopt) |
a2c6e554 RG |
227 | { |
228 | d_key = std::move(key); | |
a456662f | 229 | d_flags = flags; |
c5153ca0 | 230 | d_algorithm = algorithm ? *algorithm : d_key->getAlgorithm(); |
a3260095 | 231 | computeDNSKEY(); |
a2c6e554 RG |
232 | } |
233 | ||
a3260095 | 234 | const DNSKEYRecordContent& getDNSKEY() const; |
d5aac6e6 | 235 | |
a456662f RG |
236 | uint16_t getFlags() const |
237 | { | |
238 | return d_flags; | |
239 | } | |
240 | ||
241 | uint8_t getAlgorithm() const | |
242 | { | |
243 | return d_algorithm; | |
244 | } | |
245 | ||
699e6e37 | 246 | private: |
a3260095 RG |
247 | void computeDNSKEY(); |
248 | ||
249 | DNSKEYRecordContent d_dnskey; | |
a2c6e554 | 250 | std::shared_ptr<DNSCryptoKeyEngine> d_key; |
ed5dfdee RG |
251 | uint16_t d_flags{0}; |
252 | uint8_t d_algorithm{0}; | |
431a3cbc BH |
253 | }; |
254 | ||
255 | ||
256 | ||
7587bcbe | 257 | struct CanonicalCompare |
4691b2df BH |
258 | { |
259 | bool operator()(const std::string& a, const std::string& b) { | |
260 | std::vector<std::string> avect, bvect; | |
261 | ||
262 | stringtok(avect, a, "."); | |
263 | stringtok(bvect, b, "."); | |
1a3b143f | 264 | |
4691b2df BH |
265 | reverse(avect.begin(), avect.end()); |
266 | reverse(bvect.begin(), bvect.end()); | |
1a3b143f | 267 | |
4691b2df BH |
268 | return avect < bvect; |
269 | } | |
270 | }; | |
271 | ||
c1e7b833 | 272 | struct sharedDNSSECRecordCompare { |
d06dcda4 | 273 | bool operator() (const shared_ptr<const DNSRecordContent>& a, const shared_ptr<const DNSRecordContent>& b) const { |
c1e7b833 RG |
274 | return a->serialize(g_rootdnsname, true, true) < b->serialize(g_rootdnsname, true, true); |
275 | } | |
276 | }; | |
277 | ||
d06dcda4 | 278 | typedef std::set<std::shared_ptr<const DNSRecordContent>, sharedDNSSECRecordCompare> sortedRecords_t; |
c1e7b833 | 279 | |
e7ea7d4e | 280 | string getMessageForRRSET(const DNSName& qname, const RRSIGRecordContent& rrc, const sortedRecords_t& signRecords, bool processRRSIGLabels = false, bool includeRRSIG_RDATA = true); |
022e5e0b | 281 | |
8455425c | 282 | DSRecordContent makeDSFromDNSKey(const DNSName& qname, const DNSKEYRecordContent& drc, uint8_t digest); |
4691b2df | 283 | |
1a3b143f | 284 | class DNSSECKeeper; |
4691b2df | 285 | |
b61e407d | 286 | uint32_t getStartOfWeek(); |
4691b2df | 287 | |
28e2e78e | 288 | string hashQNameWithSalt(const NSEC3PARAMRecordContent& ns3prc, const DNSName& qname); |
e4805005 | 289 | string hashQNameWithSalt(const std::string& salt, unsigned int iterations, const DNSName& qname); |
8455425c | 290 | |
95823c07 RG |
291 | void incrementHash(std::string& raw); |
292 | void decrementHash(std::string& raw); | |
293 | ||
90ba52e0 | 294 | void addRRSigs(DNSSECKeeper& dk, UeberBackend& db, const std::set<DNSName>& authMap, vector<DNSZoneRecord>& rrs); |
431a3cbc | 295 | |
ea3816cf RG |
296 | void addTSIG(DNSPacketWriter& pw, TSIGRecordContent& trc, const DNSName& tsigkeyname, const string& tsigsecret, const string& tsigprevious, bool timersonly); |
297 | 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=0); | |
3213be1e | 298 | |
e903706d | 299 | uint64_t signatureCacheSize(const std::string& str); |