]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnssecinfra.hh
Merge pull request #14032 from rgacogne/ddist-192-changelog-secpoll
[thirdparty/pdns.git] / pdns / dnssecinfra.hh
CommitLineData
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
31class 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 35class 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
204struct 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 246private:
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 257struct 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 272struct 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 278typedef std::set<std::shared_ptr<const DNSRecordContent>, sharedDNSSECRecordCompare> sortedRecords_t;
c1e7b833 279
e7ea7d4e 280string getMessageForRRSET(const DNSName& qname, const RRSIGRecordContent& rrc, const sortedRecords_t& signRecords, bool processRRSIGLabels = false, bool includeRRSIG_RDATA = true);
022e5e0b 281
8455425c 282DSRecordContent makeDSFromDNSKey(const DNSName& qname, const DNSKEYRecordContent& drc, uint8_t digest);
4691b2df 283
1a3b143f 284class DNSSECKeeper;
4691b2df 285
b61e407d 286uint32_t getStartOfWeek();
4691b2df 287
28e2e78e 288string hashQNameWithSalt(const NSEC3PARAMRecordContent& ns3prc, const DNSName& qname);
e4805005 289string hashQNameWithSalt(const std::string& salt, unsigned int iterations, const DNSName& qname);
8455425c 290
95823c07
RG
291void incrementHash(std::string& raw);
292void decrementHash(std::string& raw);
293
90ba52e0 294void addRRSigs(DNSSECKeeper& dk, UeberBackend& db, const std::set<DNSName>& authMap, vector<DNSZoneRecord>& rrs);
431a3cbc 295
ea3816cf
RG
296void addTSIG(DNSPacketWriter& pw, TSIGRecordContent& trc, const DNSName& tsigkeyname, const string& tsigsecret, const string& tsigprevious, bool timersonly);
297bool 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 299uint64_t signatureCacheSize(const std::string& str);