]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnscrypt.hh
dnsdist: Fix DNS over plain HTTP broken by `reloadAllCertificates()`
[thirdparty/pdns.git] / pdns / dnscrypt.hh
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 "config.h"
24 #include <memory>
25
26 #ifndef HAVE_DNSCRYPT
27
28 /* let's just define a few types and values so that the rest of
29 the code can ignore whether DNSCrypt support is available */
30 #define DNSCRYPT_MAX_RESPONSE_PADDING_AND_MAC_SIZE (0)
31
32 class DNSCryptContext
33 {
34 };
35
36 class DNSCryptQuery
37 {
38 DNSCryptQuery(const std::shared_ptr<DNSCryptContext>& ctx): d_ctx(ctx)
39 {
40 }
41 private:
42 std::shared_ptr<DNSCryptContext> d_ctx{nullptr};
43 };
44
45 #else /* HAVE_DNSCRYPT */
46
47 #include <string>
48 #include <vector>
49 #include <arpa/inet.h>
50
51 #include <sodium.h>
52
53 #include "dnsname.hh"
54 #include "lock.hh"
55 #include "noinitvector.hh"
56
57 #define DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE (crypto_sign_ed25519_PUBLICKEYBYTES)
58 #define DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE (crypto_sign_ed25519_SECRETKEYBYTES)
59 #define DNSCRYPT_SIGNATURE_SIZE (crypto_sign_ed25519_BYTES)
60
61 #define DNSCRYPT_PUBLIC_KEY_SIZE (crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES)
62 #define DNSCRYPT_PRIVATE_KEY_SIZE (crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES)
63 #define DNSCRYPT_NONCE_SIZE (crypto_box_curve25519xsalsa20poly1305_NONCEBYTES)
64 #define DNSCRYPT_BEFORENM_SIZE (crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES)
65 #define DNSCRYPT_MAC_SIZE (crypto_box_curve25519xsalsa20poly1305_MACBYTES)
66
67 #ifdef HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY
68 static_assert(crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES == crypto_box_curve25519xchacha20poly1305_PUBLICKEYBYTES, "DNSCrypt public key size should be the same for all exchange versions");
69 static_assert(crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES == crypto_box_curve25519xchacha20poly1305_SECRETKEYBYTES, "DNSCrypt private key size should be the same for all exchange versions");
70 static_assert(crypto_box_curve25519xchacha20poly1305_NONCEBYTES == crypto_box_curve25519xsalsa20poly1305_NONCEBYTES, "DNSCrypt nonce size should be the same for all exchange versions");
71 static_assert(crypto_box_curve25519xsalsa20poly1305_MACBYTES == crypto_box_curve25519xchacha20poly1305_MACBYTES, "DNSCrypt MAC size should be the same for all exchange versions");
72 static_assert(crypto_box_curve25519xchacha20poly1305_BEFORENMBYTES == crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES, "DNSCrypt BEFORENM size should be the same for all exchange versions");
73 #endif /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */
74
75 #define DNSCRYPT_CERT_MAGIC_SIZE (4)
76 #define DNSCRYPT_CERT_MAGIC_VALUE { 0x44, 0x4e, 0x53, 0x43 }
77 #define DNSCRYPT_CERT_PROTOCOL_MINOR_VERSION_VALUE { 0x00, 0x00 }
78 #define DNSCRYPT_CLIENT_MAGIC_SIZE (8)
79 #define DNSCRYPT_RESOLVER_MAGIC { 0x72, 0x36, 0x66, 0x6e, 0x76, 0x57, 0x6a, 0x38 }
80 #define DNSCRYPT_RESOLVER_MAGIC_SIZE (8)
81 #define DNSCRYPT_PADDED_BLOCK_SIZE (64)
82 #define DNSCRYPT_MAX_TCP_PADDING_SIZE (256)
83 #define DNSCRYPT_MAX_RESPONSE_PADDING_SIZE (256)
84 #define DNSCRYPT_MAX_RESPONSE_PADDING_AND_MAC_SIZE (DNSCRYPT_MAX_RESPONSE_PADDING_SIZE + DNSCRYPT_MAC_SIZE)
85
86 /* "The client must check for new certificates every hour", so let's use one hour TTL */
87 #define DNSCRYPT_CERTIFICATE_RESPONSE_TTL (3600)
88
89 static_assert(DNSCRYPT_CLIENT_MAGIC_SIZE <= DNSCRYPT_PUBLIC_KEY_SIZE, "DNSCrypt Client Nonce size should be smaller or equal to public key size.");
90
91 #define DNSCRYPT_CERT_ES_VERSION1_VALUE { 0x00, 0x01 }
92 #define DNSCRYPT_CERT_ES_VERSION2_VALUE { 0x00, 0x02 }
93
94 class DNSCryptContext;
95
96 struct DNSCryptCertSignedData
97 {
98 unsigned char resolverPK[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE];
99 unsigned char clientMagic[DNSCRYPT_CLIENT_MAGIC_SIZE];
100 uint32_t serial;
101 uint32_t tsStart;
102 uint32_t tsEnd;
103 };
104
105 class DNSCryptCert
106 {
107 public:
108 uint32_t getSerial() const
109 {
110 return ntohl(signedData.serial);
111 }
112 uint32_t getTSStart() const
113 {
114 return signedData.tsStart;
115 }
116 uint32_t getTSEnd() const
117 {
118 return signedData.tsEnd;
119 }
120 bool isValid(time_t now) const
121 {
122 // coverity[store_truncates_time_t]
123 return ntohl(getTSStart()) <= static_cast<uint32_t>(now) && static_cast<uint32_t>(now) <= ntohl(getTSEnd());
124 }
125 unsigned char magic[DNSCRYPT_CERT_MAGIC_SIZE];
126 unsigned char esVersion[2];
127 unsigned char protocolMinorVersion[2];
128 unsigned char signature[DNSCRYPT_SIGNATURE_SIZE];
129 struct DNSCryptCertSignedData signedData;
130 };
131
132 static_assert((sizeof(DNSCryptCertSignedData) + DNSCRYPT_SIGNATURE_SIZE) == 116, "Dnscrypt cert signed data size + signature size should be 116!");
133 static_assert(sizeof(DNSCryptCert) == 124, "Dnscrypt cert size should be 124!");
134
135 struct DNSCryptQueryHeader
136 {
137 unsigned char clientMagic[DNSCRYPT_CLIENT_MAGIC_SIZE];
138 unsigned char clientPK[DNSCRYPT_PUBLIC_KEY_SIZE];
139 unsigned char clientNonce[DNSCRYPT_NONCE_SIZE / 2];
140 };
141
142 static_assert(sizeof(DNSCryptQueryHeader) == 52, "Dnscrypt query header size should be 52!");
143
144 struct DNSCryptResponseHeader
145 {
146 const unsigned char resolverMagic[DNSCRYPT_RESOLVER_MAGIC_SIZE] = DNSCRYPT_RESOLVER_MAGIC;
147 unsigned char nonce[DNSCRYPT_NONCE_SIZE];
148 };
149
150 typedef enum {
151 VERSION1,
152 VERSION2
153 } DNSCryptExchangeVersion;
154
155 class DNSCryptPrivateKey
156 {
157 public:
158 DNSCryptPrivateKey();
159 ~DNSCryptPrivateKey();
160 void loadFromFile(const std::string& keyFile);
161 void saveToFile(const std::string& keyFile) const;
162
163 unsigned char key[DNSCRYPT_PRIVATE_KEY_SIZE];
164 };
165
166 struct DNSCryptCertificatePair
167 {
168 unsigned char publicKey[DNSCRYPT_PUBLIC_KEY_SIZE];
169 DNSCryptCert cert;
170 DNSCryptPrivateKey privateKey;
171 bool active;
172 };
173
174 class DNSCryptQuery
175 {
176 public:
177 DNSCryptQuery(const std::shared_ptr<DNSCryptContext>& ctx): d_ctx(ctx)
178 {
179 memset(&d_header, 0, sizeof(d_header));
180 #ifdef HAVE_CRYPTO_BOX_EASY_AFTERNM
181 memset(&d_sharedKey, 0, sizeof(d_sharedKey));
182 #endif /* HAVE_CRYPTO_BOX_EASY_AFTERNM */
183 }
184
185 ~DNSCryptQuery();
186
187 bool isValid() const
188 {
189 return d_valid;
190 }
191
192 const DNSName& getQName() const
193 {
194 return d_qname;
195 }
196
197 uint16_t getID() const
198 {
199 return d_id;
200 }
201
202 const unsigned char* getClientMagic() const
203 {
204 return d_header.clientMagic;
205 }
206
207 bool isEncrypted() const
208 {
209 return d_encrypted;
210 }
211
212 void setCertificatePair(const std::shared_ptr<DNSCryptCertificatePair>& pair)
213 {
214 d_pair = pair;
215 }
216
217 void parsePacket(PacketBuffer& packet, bool tcp, time_t now);
218 void getDecrypted(bool tcp, PacketBuffer& packet);
219 void getCertificateResponse(time_t now, PacketBuffer& response) const;
220 int encryptResponse(PacketBuffer& response, size_t maxResponseSize, bool tcp);
221
222 static const size_t s_minUDPLength = 256;
223
224 private:
225 DNSCryptExchangeVersion getVersion() const;
226 #ifdef HAVE_CRYPTO_BOX_EASY_AFTERNM
227 int computeSharedKey();
228 #endif /* HAVE_CRYPTO_BOX_EASY_AFTERNM */
229 void fillServerNonce(unsigned char* dest) const;
230 uint16_t computePaddingSize(uint16_t unpaddedLen, size_t maxLen) const;
231 bool parsePlaintextQuery(const PacketBuffer& packet);
232 bool isEncryptedQuery(const PacketBuffer& packet, bool tcp, time_t now);
233
234 DNSCryptQueryHeader d_header;
235 #ifdef HAVE_CRYPTO_BOX_EASY_AFTERNM
236 unsigned char d_sharedKey[crypto_box_BEFORENMBYTES];
237 #endif /* HAVE_CRYPTO_BOX_EASY_AFTERNM */
238 DNSName d_qname;
239 std::shared_ptr<DNSCryptContext> d_ctx{nullptr};
240 std::shared_ptr<DNSCryptCertificatePair> d_pair{nullptr};
241 uint16_t d_id{0};
242 uint16_t d_len{0};
243 uint16_t d_paddedLen{0};
244 bool d_encrypted{false};
245 bool d_valid{false};
246
247 #ifdef HAVE_CRYPTO_BOX_EASY_AFTERNM
248 bool d_sharedKeyComputed{false};
249 #endif /* HAVE_CRYPTO_BOX_EASY_AFTERNM */
250 };
251
252 class DNSCryptContext
253 {
254 public:
255 static void generateProviderKeys(unsigned char publicKey[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE], unsigned char privateKey[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE]);
256 static std::string getProviderFingerprint(unsigned char publicKey[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE]);
257 static void generateCertificate(uint32_t serial, time_t begin, time_t end, const DNSCryptExchangeVersion& version, const unsigned char providerPrivateKey[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE], DNSCryptPrivateKey& privateKey, DNSCryptCert& cert);
258 static void saveCertFromFile(const DNSCryptCert& cert, const std::string&filename);
259 static std::string certificateDateToStr(uint32_t date);
260 static void generateResolverKeyPair(DNSCryptPrivateKey& privK, unsigned char pubK[DNSCRYPT_PUBLIC_KEY_SIZE]);
261 static void setExchangeVersion(const DNSCryptExchangeVersion& version, unsigned char esVersion[sizeof(DNSCryptCert::esVersion)]);
262 static DNSCryptExchangeVersion getExchangeVersion(const unsigned char esVersion[sizeof(DNSCryptCert::esVersion)]);
263 static DNSCryptExchangeVersion getExchangeVersion(const DNSCryptCert& cert);
264
265 struct CertKeyPaths
266 {
267 std::string cert;
268 std::string key;
269 };
270
271 DNSCryptContext(const std::string& pName, const std::vector<CertKeyPaths>& certKeys);
272 DNSCryptContext(const std::string& pName, const DNSCryptCert& certificate, const DNSCryptPrivateKey& pKey);
273 ~DNSCryptContext();
274
275 void reloadCertificates();
276 void loadNewCertificate(const std::string& certFile, const std::string& keyFile, bool active=true, bool reload=false);
277 void addNewCertificate(const DNSCryptCert& newCert, const DNSCryptPrivateKey& newKey, bool active=true, bool reload=false);
278
279 void markActive(uint32_t serial);
280 void markInactive(uint32_t serial);
281 void removeInactiveCertificate(uint32_t serial);
282 std::vector<std::shared_ptr<DNSCryptCertificatePair>> getCertificates();
283 const DNSName& getProviderName() const { return providerName; }
284
285 int encryptQuery(PacketBuffer& query, size_t maximumSize, const unsigned char clientPublicKey[DNSCRYPT_PUBLIC_KEY_SIZE], const DNSCryptPrivateKey& clientPrivateKey, const unsigned char clientNonce[DNSCRYPT_NONCE_SIZE / 2], bool tcp, const std::shared_ptr<DNSCryptCert>& cert) const;
286 bool magicMatchesAPublicKey(DNSCryptQuery& query, time_t now);
287 void getCertificateResponse(time_t now, const DNSName& qname, uint16_t qid, PacketBuffer& response);
288
289 private:
290 static void computePublicKeyFromPrivate(const DNSCryptPrivateKey& privK, unsigned char pubK[DNSCRYPT_PUBLIC_KEY_SIZE]);
291 static void loadCertFromFile(const std::string&filename, DNSCryptCert& dest);
292 static std::shared_ptr<DNSCryptCertificatePair> loadCertificatePair(const std::string& certFile, const std::string& keyFile);
293
294 void addNewCertificate(std::shared_ptr<DNSCryptCertificatePair>& newCert, bool reload=false);
295
296 SharedLockGuarded<std::vector<std::shared_ptr<DNSCryptCertificatePair>>> d_certs;
297 SharedLockGuarded<std::vector<CertKeyPaths>> d_certKeyPaths;
298 DNSName providerName;
299 };
300
301 bool generateDNSCryptCertificate(const std::string& providerPrivateKeyFile, uint32_t serial, time_t begin, time_t end, DNSCryptExchangeVersion version, DNSCryptCert& certOut, DNSCryptPrivateKey& keyOut);
302
303 #endif