]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnscrypt.hh
Merge pull request #6019 from mind04/schema
[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 <sodium.h>
31
32 #include "dnsname.hh"
33
34 #define DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE (crypto_sign_ed25519_PUBLICKEYBYTES)
35 #define DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE (crypto_sign_ed25519_SECRETKEYBYTES)
36 #define DNSCRYPT_PUBLIC_KEY_SIZE (crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES)
37 #define DNSCRYPT_PRIVATE_KEY_SIZE (crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES)
38 #define DNSCRYPT_NONCE_SIZE (crypto_box_curve25519xsalsa20poly1305_NONCEBYTES)
39 #define DNSCRYPT_BEFORENM_SIZE (crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES)
40 #define DNSCRYPT_SIGNATURE_SIZE (crypto_sign_ed25519_BYTES)
41 #define DNSCRYPT_MAC_SIZE (crypto_box_curve25519xsalsa20poly1305_MACBYTES)
42 #define DNSCRYPT_CERT_MAGIC_SIZE (4)
43 #define DNSCRYPT_CERT_MAGIC_VALUE { 0x44, 0x4e, 0x53, 0x43 }
44 #define DNSCRYPT_CERT_ES_VERSION_VALUE { 0x00, 0x01 }
45 #define DNSCRYPT_CERT_PROTOCOL_MINOR_VERSION_VALUE { 0x00, 0x00 }
46 #define DNSCRYPT_CLIENT_MAGIC_SIZE (8)
47 #define DNSCRYPT_RESOLVER_MAGIC { 0x72, 0x36, 0x66, 0x6e, 0x76, 0x57, 0x6a, 0x38 }
48 #define DNSCRYPT_RESOLVER_MAGIC_SIZE (8)
49 #define DNSCRYPT_PADDED_BLOCK_SIZE (64)
50 #define DNSCRYPT_MAX_TCP_PADDING_SIZE (256)
51 #define DNSCRYPT_MAX_RESPONSE_PADDING_SIZE (256)
52 #define DNSCRYPT_MAX_RESPONSE_PADDING_AND_MAC_SIZE (DNSCRYPT_MAX_RESPONSE_PADDING_SIZE + DNSCRYPT_MAC_SIZE)
53
54 /* "The client must check for new certificates every hour", so let's use one hour TTL */
55 #define DNSCRYPT_CERTIFICATE_RESPONSE_TTL (3600)
56
57 static_assert(DNSCRYPT_CLIENT_MAGIC_SIZE <= DNSCRYPT_PUBLIC_KEY_SIZE, "Dnscrypt Client Nonce size should be smaller or equal to public key size.");
58
59 class DnsCryptContext;
60
61 struct DnsCryptCertSignedData
62 {
63 unsigned char resolverPK[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE];
64 unsigned char clientMagic[DNSCRYPT_CLIENT_MAGIC_SIZE];
65 uint32_t serial;
66 uint32_t tsStart;
67 uint32_t tsEnd;
68 };
69
70 struct DnsCryptCert
71 {
72 unsigned char magic[DNSCRYPT_CERT_MAGIC_SIZE];
73 unsigned char esVersion[2];
74 unsigned char protocolMinorVersion[2];
75 unsigned char signature[DNSCRYPT_SIGNATURE_SIZE];
76 struct DnsCryptCertSignedData signedData;
77 };
78
79 static_assert((sizeof(DnsCryptCertSignedData) + DNSCRYPT_SIGNATURE_SIZE) == 116, "Dnscrypt cert signed data size + signature size should be 116!");
80 static_assert(sizeof(DnsCryptCert) == 124, "Dnscrypt cert size should be 124!");
81
82 struct DnsCryptQueryHeader
83 {
84 unsigned char clientMagic[DNSCRYPT_CLIENT_MAGIC_SIZE];
85 unsigned char clientPK[DNSCRYPT_PUBLIC_KEY_SIZE];
86 unsigned char clientNonce[DNSCRYPT_NONCE_SIZE / 2];
87 };
88
89 static_assert(sizeof(DnsCryptQueryHeader) == 52, "Dnscrypt query header size should be 52!");
90
91 struct DnsCryptResponseHeader
92 {
93 const unsigned char resolverMagic[DNSCRYPT_RESOLVER_MAGIC_SIZE] = DNSCRYPT_RESOLVER_MAGIC;
94 unsigned char nonce[DNSCRYPT_NONCE_SIZE];
95 };
96
97 class DnsCryptPrivateKey
98 {
99 public:
100 DnsCryptPrivateKey();
101 ~DnsCryptPrivateKey();
102 void loadFromFile(const std::string& keyFile);
103 void saveToFile(const std::string& keyFile) const;
104
105 unsigned char key[DNSCRYPT_PRIVATE_KEY_SIZE];
106 };
107
108 class DnsCryptQuery
109 {
110 public:
111 DnsCryptQuery()
112 {
113 }
114 ~DnsCryptQuery();
115 #ifdef HAVE_CRYPTO_BOX_EASY_AFTERNM
116 int computeSharedKey(const DnsCryptPrivateKey& privateKey);
117 #endif /* HAVE_CRYPTO_BOX_EASY_AFTERNM */
118
119 static const size_t minUDPLength = 256;
120
121 DnsCryptQueryHeader header;
122 #ifdef HAVE_CRYPTO_BOX_EASY_AFTERNM
123 unsigned char sharedKey[crypto_box_BEFORENMBYTES];
124 #endif /* HAVE_CRYPTO_BOX_EASY_AFTERNM */
125 DNSName qname;
126 DnsCryptContext* ctx;
127 uint16_t id{0};
128 uint16_t len{0};
129 uint16_t paddedLen;
130 bool useOldCert{false};
131 bool encrypted{false};
132 bool valid{false};
133 #ifdef HAVE_CRYPTO_BOX_EASY_AFTERNM
134 bool sharedKeyComputed{false};
135 #endif /* HAVE_CRYPTO_BOX_EASY_AFTERNM */
136 };
137
138 class DnsCryptContext
139 {
140 public:
141 static void generateProviderKeys(unsigned char publicKey[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE], unsigned char privateKey[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE]);
142 static std::string getProviderFingerprint(unsigned char publicKey[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE]);
143 static void generateCertificate(uint32_t serial, time_t begin, time_t end, const unsigned char providerPrivateKey[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE], DnsCryptPrivateKey& privateKey, DnsCryptCert& cert);
144 static void saveCertFromFile(const DnsCryptCert& cert, const std::string&filename);
145 static std::string certificateDateToStr(uint32_t date);
146 static void generateResolverKeyPair(DnsCryptPrivateKey& privK, unsigned char pubK[DNSCRYPT_PUBLIC_KEY_SIZE]);
147
148 DnsCryptContext(const std::string& pName, const std::string& certFile, const std::string& keyFile): providerName(pName)
149 {
150 loadCertFromFile(certFile, cert);
151 privateKey.loadFromFile(keyFile);
152 computePublicKeyFromPrivate(privateKey, publicKey);
153 }
154
155 DnsCryptContext(const std::string& pName, const DnsCryptCert& certificate, const DnsCryptPrivateKey& pKey): providerName(pName), cert(certificate), privateKey(pKey)
156 {
157 computePublicKeyFromPrivate(privateKey, publicKey);
158 }
159
160 void parsePacket(char* packet, uint16_t packetSize, std::shared_ptr<DnsCryptQuery> query, bool tcp, uint16_t* decryptedQueryLen) const;
161 int encryptResponse(char* response, uint16_t responseLen, uint16_t responseSize, const std::shared_ptr<DnsCryptQuery> query, bool tcp, uint16_t* encryptedResponseLen) const;
162 void getCertificateResponse(const std::shared_ptr<DnsCryptQuery> query, std::vector<uint8_t>& response) const;
163 void loadNewCertificate(const std::string& certFile, const std::string& keyFile);
164 void setNewCertificate(const DnsCryptCert& newCert, const DnsCryptPrivateKey& newKey);
165 const DnsCryptCert& getCurrentCertificate() const { return cert; };
166 const DnsCryptCert& getOldCertificate() const { return oldCert; };
167 bool hasOldCertificate() const { return hasOldCert; };
168 const std::string& getProviderName() const { return providerName; }
169 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;
170
171
172 private:
173 static void computePublicKeyFromPrivate(const DnsCryptPrivateKey& privK, unsigned char pubK[DNSCRYPT_PUBLIC_KEY_SIZE]);
174 static void loadCertFromFile(const std::string&filename, DnsCryptCert& dest);
175
176 void parsePlaintextQuery(const char * packet, uint16_t packetSize, std::shared_ptr<DnsCryptQuery> query) const;
177 bool magicMatchesPublicKey(std::shared_ptr<DnsCryptQuery> query) const;
178 void isQueryEncrypted(const char * packet, uint16_t packetSize, std::shared_ptr<DnsCryptQuery> query, bool tcp) const;
179 void getDecryptedQuery(std::shared_ptr<DnsCryptQuery> query, bool tcp, char* packet, uint16_t packetSize, uint16_t* decryptedQueryLen) const;
180 void fillServerNonce(unsigned char* dest) const;
181 uint16_t computePaddingSize(uint16_t unpaddedLen, size_t maxLen, const unsigned char* clientNonce) const;
182
183 std::string providerName;
184 DnsCryptCert cert;
185 DnsCryptCert oldCert;
186 DnsCryptPrivateKey privateKey;
187 unsigned char publicKey[DNSCRYPT_PUBLIC_KEY_SIZE];
188 DnsCryptPrivateKey oldPrivateKey;
189 bool hasOldCert{false};
190 };
191
192 bool generateDNSCryptCertificate(const std::string& providerPrivateKeyFile, uint32_t serial, time_t begin, time_t end, DnsCryptCert& certOut, DnsCryptPrivateKey& keyOut);
193
194 #endif