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