Coverage Report

Created: 2024-04-25 06:27

/src/pdns/pdns/dnsdistdist/dnscrypt.hh
Line
Count
Source (jump to first uncovered line)
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
0
  {
40
0
  }
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