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