Coverage Report

Created: 2024-11-12 06:21

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