]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnscrypt.cc
Merge pull request #14020 from omoerbeek/rec-compiling-rust-dcos
[thirdparty/pdns.git] / pdns / dnscrypt.cc
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#include "config.h"
23#ifdef HAVE_DNSCRYPT
24#include <fstream>
a48e03da 25#include <boost/format.hpp>
11e1e08b
RG
26#include "dolog.hh"
27#include "dnscrypt.hh"
28#include "dnswriter.hh"
29
43234e76 30DNSCryptPrivateKey::DNSCryptPrivateKey()
11e1e08b
RG
31{
32 sodium_memzero(key, sizeof(key));
33 sodium_mlock(key, sizeof(key));
34}
35
43234e76 36void DNSCryptPrivateKey::loadFromFile(const std::string& keyFile)
11e1e08b
RG
37{
38 ifstream file(keyFile);
39 sodium_memzero(key, sizeof(key));
40 file.read((char*) key, sizeof(key));
41
42 if (file.fail()) {
43 sodium_memzero(key, sizeof(key));
44 file.close();
45 throw std::runtime_error("Invalid DNSCrypt key file " + keyFile);
46 }
47
48 file.close();
49}
50
43234e76 51void DNSCryptPrivateKey::saveToFile(const std::string& keyFile) const
11e1e08b
RG
52{
53 ofstream file(keyFile);
f1b2ae9b 54 file.write(reinterpret_cast<const char*>(key), sizeof(key));
11e1e08b
RG
55 file.close();
56}
57
43234e76 58DNSCryptPrivateKey::~DNSCryptPrivateKey()
11e1e08b 59{
11e1e08b
RG
60 sodium_munlock(key, sizeof(key));
61}
62
43234e76
RG
63DNSCryptExchangeVersion DNSCryptQuery::getVersion() const
64{
65 if (d_pair == nullptr) {
66 throw std::runtime_error("Unable to determine the version of a DNSCrypt query if there is not associated cert");
67 }
68
69 return DNSCryptContext::getExchangeVersion(d_pair->cert);
70}
71
00ffb1c2 72#ifdef HAVE_CRYPTO_BOX_EASY_AFTERNM
43234e76 73DNSCryptQuery::~DNSCryptQuery()
332fdc5f 74{
43234e76
RG
75 if (d_sharedKeyComputed) {
76 sodium_munlock(d_sharedKey, sizeof(d_sharedKey));
8089cbe5 77 }
332fdc5f
RG
78}
79
43234e76 80int DNSCryptQuery::computeSharedKey()
332fdc5f 81{
43234e76
RG
82 assert(d_pair != nullptr);
83
8089cbe5
RG
84 int res = 0;
85
43234e76 86 if (d_sharedKeyComputed) {
8089cbe5
RG
87 return res;
88 }
89
43234e76
RG
90 const DNSCryptExchangeVersion version = DNSCryptContext::getExchangeVersion(d_pair->cert);
91
92 sodium_mlock(d_sharedKey, sizeof(d_sharedKey));
93
94 if (version == DNSCryptExchangeVersion::VERSION1) {
95 res = crypto_box_beforenm(d_sharedKey,
96 d_header.clientPK,
97 d_pair->privateKey.key);
98 }
99 else if (version == DNSCryptExchangeVersion::VERSION2) {
100#ifdef HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY
101 res = crypto_box_curve25519xchacha20poly1305_beforenm(d_sharedKey,
102 d_header.clientPK,
103 d_pair->privateKey.key);
104#else /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */
105 res = -1;
106#endif /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */
107 }
108 else {
109 res = -1;
110 }
8089cbe5
RG
111
112 if (res != 0) {
43234e76 113 sodium_munlock(d_sharedKey, sizeof(d_sharedKey));
8089cbe5
RG
114 return res;
115 }
116
43234e76 117 d_sharedKeyComputed = true;
8089cbe5 118 return res;
332fdc5f 119}
00ffb1c2 120#else
43234e76 121DNSCryptQuery::~DNSCryptQuery()
00ffb1c2
RG
122{
123}
124#endif /* HAVE_CRYPTO_BOX_EASY_AFTERNM */
8089cbe5 125
040793d4
OM
126
127DNSCryptContext::~DNSCryptContext() {
040793d4
OM
128}
129
37b6d73d 130DNSCryptContext::DNSCryptContext(const std::string& pName, const std::vector<CertKeyPaths>& certKeys): d_certKeyPaths(certKeys), providerName(pName)
43234e76 131{
37b6d73d 132 reloadCertificates();
43234e76
RG
133}
134
135DNSCryptContext::DNSCryptContext(const std::string& pName, const DNSCryptCert& certificate, const DNSCryptPrivateKey& pKey): providerName(pName)
136{
43234e76
RG
137 addNewCertificate(certificate, pKey);
138}
139
140void DNSCryptContext::generateProviderKeys(unsigned char publicKey[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE], unsigned char privateKey[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE])
11e1e08b
RG
141{
142 int res = crypto_sign_ed25519_keypair(publicKey, privateKey);
143
144 if (res != 0) {
145 throw std::runtime_error("Error generating DNSCrypt provider keys");
146 }
147}
148
43234e76 149std::string DNSCryptContext::getProviderFingerprint(unsigned char publicKey[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE])
11e1e08b
RG
150{
151 boost::format fmt("%02X%02X");
152 ostringstream ret;
153
154 for (size_t idx = 0; idx < DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE; idx += 2)
155 {
156 ret << (fmt % static_cast<int>(publicKey[idx]) % static_cast<int>(publicKey[idx+1]));
157 if (idx < (DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE - 2)) {
158 ret << ":";
159 }
160 }
161
162 return ret.str();
163}
164
43234e76
RG
165void DNSCryptContext::setExchangeVersion(const DNSCryptExchangeVersion& version, unsigned char esVersion[sizeof(DNSCryptCert::esVersion)])
166{
167 esVersion[0] = 0x00;
168
169 if (version == DNSCryptExchangeVersion::VERSION1) {
170 esVersion[1] = { 0x01 };
171 }
172 else if (version == DNSCryptExchangeVersion::VERSION2) {
173 esVersion[1] = { 0x02 };
174 }
175 else {
176 throw std::runtime_error("Unknown DNSCrypt exchange version");
177 }
178}
179
180DNSCryptExchangeVersion DNSCryptContext::getExchangeVersion(const unsigned char esVersion[sizeof(DNSCryptCert::esVersion)])
181{
182 if (esVersion[0] != 0x00) {
183 throw std::runtime_error("Unknown DNSCrypt exchange version");
184 }
185
186 if (esVersion[1] == 0x01) {
187 return DNSCryptExchangeVersion::VERSION1;
188 }
189 else if (esVersion[1] == 0x02) {
190 return DNSCryptExchangeVersion::VERSION2;
191 }
192
193 throw std::runtime_error("Unknown DNSCrypt exchange version");
194}
195
196DNSCryptExchangeVersion DNSCryptContext::getExchangeVersion(const DNSCryptCert& cert)
197{
198 return getExchangeVersion(cert.esVersion);
199}
200
201
202void DNSCryptContext::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)
11e1e08b
RG
203{
204 unsigned char magic[DNSCRYPT_CERT_MAGIC_SIZE] = DNSCRYPT_CERT_MAGIC_VALUE;
11e1e08b
RG
205 unsigned char protocolMinorVersion[] = DNSCRYPT_CERT_PROTOCOL_MINOR_VERSION_VALUE;
206 unsigned char pubK[DNSCRYPT_PUBLIC_KEY_SIZE];
43234e76
RG
207 unsigned char esVersion[sizeof(DNSCryptCert::esVersion)];
208 setExchangeVersion(version, esVersion);
209
11e1e08b
RG
210 generateResolverKeyPair(privateKey, pubK);
211
212 memcpy(cert.magic, magic, sizeof(magic));
213 memcpy(cert.esVersion, esVersion, sizeof(esVersion));
214 memcpy(cert.protocolMinorVersion, protocolMinorVersion, sizeof(protocolMinorVersion));
215 memcpy(cert.signedData.resolverPK, pubK, sizeof(cert.signedData.resolverPK));
216 memcpy(cert.signedData.clientMagic, pubK, sizeof(cert.signedData.clientMagic));
b7bd0317 217 cert.signedData.serial = htonl(serial);
56b827c5 218 // coverity[store_truncates_time_t]
11e1e08b 219 cert.signedData.tsStart = htonl((uint32_t) begin);
56b827c5 220 // coverity[store_truncates_time_t]
11e1e08b
RG
221 cert.signedData.tsEnd = htonl((uint32_t) end);
222
223 unsigned long long signatureSize = 0;
224
225 int res = crypto_sign_ed25519(cert.signature,
226 &signatureSize,
227 (unsigned char*) &cert.signedData,
228 sizeof(cert.signedData),
229 providerPrivateKey);
230
231 if (res == 0) {
43234e76 232 assert(signatureSize == sizeof(DNSCryptCertSignedData) + DNSCRYPT_SIGNATURE_SIZE);
11e1e08b
RG
233 }
234 else {
235 throw std::runtime_error("Error generating DNSCrypt certificate");
236 }
237}
238
43234e76 239void DNSCryptContext::loadCertFromFile(const std::string&filename, DNSCryptCert& dest)
11e1e08b
RG
240{
241 ifstream file(filename);
242 file.read((char *) &dest, sizeof(dest));
243
244 if (file.fail())
245 throw std::runtime_error("Invalid dnscrypt certificate file " + filename);
246
247 file.close();
248}
249
43234e76 250void DNSCryptContext::saveCertFromFile(const DNSCryptCert& cert, const std::string&filename)
11e1e08b
RG
251{
252 ofstream file(filename);
f1b2ae9b 253 file.write(reinterpret_cast<const char *>(&cert), sizeof(cert));
11e1e08b
RG
254 file.close();
255}
256
43234e76 257void DNSCryptContext::generateResolverKeyPair(DNSCryptPrivateKey& privK, unsigned char pubK[DNSCRYPT_PUBLIC_KEY_SIZE])
11e1e08b
RG
258{
259 int res = crypto_box_keypair(pubK, privK.key);
260
261 if (res != 0) {
262 throw std::runtime_error("Error generating DNSCrypt resolver keys");
263 }
264}
265
43234e76 266void DNSCryptContext::computePublicKeyFromPrivate(const DNSCryptPrivateKey& privK, unsigned char* pubK)
11e1e08b
RG
267{
268 int res = crypto_scalarmult_base(pubK,
269 privK.key);
270
271 if (res != 0) {
272 throw std::runtime_error("Error computing dnscrypt public key from the private one");
273 }
274}
275
43234e76 276std::string DNSCryptContext::certificateDateToStr(uint32_t date)
11e1e08b
RG
277{
278 char buf[20];
43234e76 279 time_t tdate = static_cast<time_t>(ntohl(date));
11e1e08b
RG
280 struct tm date_tm;
281
282 localtime_r(&tdate, &date_tm);
283 strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &date_tm);
284
285 return string(buf);
286}
287
37b6d73d 288void DNSCryptContext::addNewCertificate(std::shared_ptr<DNSCryptCertificatePair>& newCert, bool reload)
11e1e08b 289{
6e41eb90 290 auto certs = d_certs.write_lock();
43234e76 291
160a19ad 292 for (const auto& pair : *certs) {
37b6d73d 293 if (pair->cert.getSerial() == newCert->cert.getSerial()) {
bcc62bfb
RG
294 if (reload) {
295 /* on reload we just assume that this is the same certificate */
296 return;
297 }
298 else {
299 throw std::runtime_error("Error adding a new certificate: we already have a certificate with the same serial");
300 }
43234e76
RG
301 }
302 }
303
6c1813a0 304 certs->push_back(newCert);
37b6d73d
RG
305}
306
307void DNSCryptContext::addNewCertificate(const DNSCryptCert& newCert, const DNSCryptPrivateKey& newKey, bool active, bool reload)
308{
43234e76
RG
309 auto pair = std::make_shared<DNSCryptCertificatePair>();
310 pair->cert = newCert;
311 pair->privateKey = newKey;
312 computePublicKeyFromPrivate(pair->privateKey, pair->publicKey);
313 pair->active = active;
37b6d73d
RG
314
315 addNewCertificate(pair, reload);
11e1e08b
RG
316}
317
37b6d73d 318std::shared_ptr<DNSCryptCertificatePair> DNSCryptContext::loadCertificatePair(const std::string& certFile, const std::string& keyFile)
11e1e08b 319{
37b6d73d
RG
320 auto pair = std::make_shared<DNSCryptCertificatePair>();
321 loadCertFromFile(certFile, pair->cert);
322 pair->privateKey.loadFromFile(keyFile);
323 pair->active = true;
324 computePublicKeyFromPrivate(pair->privateKey, pair->publicKey);
325 return pair;
326}
43234e76 327
37b6d73d
RG
328void DNSCryptContext::loadNewCertificate(const std::string& certFile, const std::string& keyFile, bool active, bool reload)
329{
330 auto newPair = DNSCryptContext::loadCertificatePair(certFile, keyFile);
331 newPair->active = active;
332 addNewCertificate(newPair, reload);
6e41eb90 333 d_certKeyPaths.write_lock()->push_back({certFile, keyFile});
bcc62bfb
RG
334}
335
37b6d73d 336void DNSCryptContext::reloadCertificates()
bcc62bfb 337{
37b6d73d 338 std::vector<std::shared_ptr<DNSCryptCertificatePair>> newCerts;
5a9cff11 339 {
6c1813a0
RG
340 auto paths = d_certKeyPaths.read_lock();
341 newCerts.reserve(paths->size());
342 for (const auto& pair : *paths) {
5a9cff11
RG
343 newCerts.push_back(DNSCryptContext::loadCertificatePair(pair.cert, pair.key));
344 }
37b6d73d 345 }
6c1813a0 346
37b6d73d 347 {
6e41eb90 348 *(d_certs.write_lock()) = std::move(newCerts);
37b6d73d 349 }
43234e76
RG
350}
351
5a9cff11 352std::vector<std::shared_ptr<DNSCryptCertificatePair>> DNSCryptContext::getCertificates() {
6c1813a0 353 std::vector<std::shared_ptr<DNSCryptCertificatePair>> ret = *(d_certs.read_lock());
5a9cff11
RG
354 return ret;
355};
356
43234e76
RG
357void DNSCryptContext::markActive(uint32_t serial)
358{
160a19ad 359 for (const auto& pair : *d_certs.write_lock()) {
43234e76
RG
360 if (pair->active == false && pair->cert.getSerial() == serial) {
361 pair->active = true;
362 return;
363 }
364 }
365 throw std::runtime_error("No inactive certificate found with this serial");
366}
367
368void DNSCryptContext::markInactive(uint32_t serial)
369{
160a19ad 370 for (const auto& pair : *d_certs.write_lock()) {
43234e76
RG
371 if (pair->active == true && pair->cert.getSerial() == serial) {
372 pair->active = false;
373 return;
374 }
375 }
376 throw std::runtime_error("No active certificate found with this serial");
11e1e08b
RG
377}
378
43234e76 379void DNSCryptContext::removeInactiveCertificate(uint32_t serial)
11e1e08b 380{
6e41eb90 381 auto certs = d_certs.write_lock();
43234e76 382
6c1813a0 383 for (auto it = certs->begin(); it != certs->end(); ) {
43234e76 384 if ((*it)->active == false && (*it)->cert.getSerial() == serial) {
6c1813a0 385 it = certs->erase(it);
43234e76
RG
386 return;
387 } else {
388 it++;
389 }
390 }
391 throw std::runtime_error("No inactive certificate found with this serial");
392}
393
32fbb2ab 394bool DNSCryptQuery::parsePlaintextQuery(const PacketBuffer& packet)
43234e76
RG
395{
396 assert(d_ctx != nullptr);
397
341d2553 398 if (packet.size() < sizeof(dnsheader)) {
43234e76 399 return false;
11e1e08b
RG
400 }
401
90686725 402 const dnsheader_aligned dh(packet.data());
3f5e00d8 403 if (dh->qr || ntohs(dh->qdcount) != 1 || dh->ancount != 0 || dh->nscount != 0 || static_cast<uint8_t>(dh->opcode) != Opcode::Query) {
43234e76 404 return false;
90686725 405 }
11e1e08b 406
341d2553 407 unsigned int qnameWireLength;
11e1e08b 408 uint16_t qtype, qclass;
341d2553
RG
409 DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, &qclass, &qnameWireLength);
410 if ((packet.size() - sizeof(dnsheader)) < (qnameWireLength + sizeof(qtype) + sizeof(qclass))) {
43234e76 411 return false;
341d2553 412 }
11e1e08b 413
341d2553 414 if (qtype != QType::TXT || qclass != QClass::IN) {
43234e76 415 return false;
341d2553 416 }
11e1e08b 417
341d2553 418 if (qname != d_ctx->getProviderName()) {
43234e76 419 return false;
341d2553 420 }
43234e76 421
c43570b6 422 d_qname = std::move(qname);
43234e76
RG
423 d_id = dh->id;
424 d_valid = true;
11e1e08b 425
43234e76 426 return true;
11e1e08b
RG
427}
428
32fbb2ab 429void DNSCryptContext::getCertificateResponse(time_t now, const DNSName& qname, uint16_t qid, PacketBuffer& response)
11e1e08b 430{
32fbb2ab 431 GenericDNSPacketWriter<PacketBuffer> pw(response, qname, QType::TXT, QClass::IN, Opcode::Query);
11e1e08b 432 struct dnsheader * dh = pw.getHeader();
43234e76 433 dh->id = qid;
11e1e08b
RG
434 dh->qr = true;
435 dh->rcode = RCode::NoError;
11e1e08b 436
6c1813a0
RG
437 auto certs = d_certs.read_lock();
438 for (const auto& pair : *certs) {
43234e76
RG
439 if (!pair->active || !pair->cert.isValid(now)) {
440 continue;
441 }
11e1e08b 442
43234e76
RG
443 pw.startRecord(qname, QType::TXT, (DNSCRYPT_CERTIFICATE_RESPONSE_TTL), QClass::IN, DNSResourceRecord::ANSWER, true);
444 std::string scert;
445 uint8_t certSize = sizeof(pair->cert);
446 scert.assign((const char*) &certSize, sizeof(certSize));
447 scert.append((const char*) &pair->cert, certSize);
11e1e08b 448
43234e76
RG
449 pw.xfrBlob(scert);
450 pw.commit();
11e1e08b 451 }
43234e76 452}
11e1e08b 453
43234e76
RG
454bool DNSCryptContext::magicMatchesAPublicKey(DNSCryptQuery& query, time_t now)
455{
456 const unsigned char* magic = query.getClientMagic();
457
6c1813a0
RG
458 auto certs = d_certs.read_lock();
459 for (const auto& pair : *certs) {
43234e76
RG
460 if (pair->cert.isValid(now) && memcmp(magic, pair->cert.signedData.clientMagic, DNSCRYPT_CLIENT_MAGIC_SIZE) == 0) {
461 query.setCertificatePair(pair);
462 return true;
463 }
11e1e08b
RG
464 }
465
466 return false;
467}
468
32fbb2ab 469bool DNSCryptQuery::isEncryptedQuery(const PacketBuffer& packet, bool tcp, time_t now)
11e1e08b 470{
43234e76 471 assert(d_ctx != nullptr);
11e1e08b 472
43234e76
RG
473 d_encrypted = false;
474
341d2553 475 if (packet.size() < sizeof(DNSCryptQueryHeader)) {
43234e76 476 return false;
11e1e08b
RG
477 }
478
341d2553 479 if (!tcp && packet.size() < DNSCryptQuery::s_minUDPLength) {
43234e76 480 return false;
11e1e08b
RG
481 }
482
341d2553 483 const struct DNSCryptQueryHeader* header = reinterpret_cast<const struct DNSCryptQueryHeader*>(packet.data());
11e1e08b 484
43234e76 485 d_header = *header;
11e1e08b 486
43234e76
RG
487 if (!d_ctx->magicMatchesAPublicKey(*this, now)) {
488 return false;
11e1e08b
RG
489 }
490
43234e76
RG
491 d_encrypted = true;
492
493 return true;
11e1e08b
RG
494}
495
32fbb2ab 496void DNSCryptQuery::getDecrypted(bool tcp, PacketBuffer& packet)
11e1e08b 497{
43234e76
RG
498 assert(d_encrypted);
499 assert(d_pair != nullptr);
500 assert(d_valid == false);
11e1e08b
RG
501
502#ifdef DNSCRYPT_STRICT_PADDING_LENGTH
341d2553
RG
503 if (tcp && ((packet.size() - sizeof(DNSCryptQueryHeader)) % DNSCRYPT_PADDED_BLOCK_SIZE) != 0) {
504 vinfolog("Dropping encrypted query with invalid size of %d (should be a multiple of %d)", (packet.size() - sizeof(DNSCryptQueryHeader)), DNSCRYPT_PADDED_BLOCK_SIZE);
11e1e08b
RG
505 return;
506 }
507#endif
508
509 unsigned char nonce[DNSCRYPT_NONCE_SIZE];
43234e76 510 static_assert(sizeof(nonce) == (2* sizeof(d_header.clientNonce)), "Nonce should be larger than clientNonce (half)");
ef2ea4bf 511 static_assert(sizeof(d_header.clientPK) == DNSCRYPT_PUBLIC_KEY_SIZE, "Client Public key size is not right");
43234e76 512 static_assert(sizeof(d_pair->privateKey.key) == DNSCRYPT_PRIVATE_KEY_SIZE, "Private key size is not right");
11e1e08b 513
43234e76
RG
514 memcpy(nonce, &d_header.clientNonce, sizeof(d_header.clientNonce));
515 memset(nonce + sizeof(d_header.clientNonce), 0, sizeof(nonce) - sizeof(d_header.clientNonce));
11e1e08b 516
00ffb1c2 517#ifdef HAVE_CRYPTO_BOX_EASY_AFTERNM
43234e76 518 int res = computeSharedKey();
8089cbe5
RG
519 if (res != 0) {
520 vinfolog("Dropping encrypted query we can't compute the shared key for");
521 return;
332fdc5f
RG
522 }
523
43234e76
RG
524 const DNSCryptExchangeVersion version = getVersion();
525
526 if (version == DNSCryptExchangeVersion::VERSION1) {
341d2553
RG
527 res = crypto_box_open_easy_afternm(reinterpret_cast<unsigned char*>(packet.data()),
528 reinterpret_cast<unsigned char*>(&packet.at(sizeof(DNSCryptQueryHeader))),
529 packet.size() - sizeof(DNSCryptQueryHeader),
43234e76
RG
530 nonce,
531 d_sharedKey);
532 }
533 else if (version == DNSCryptExchangeVersion::VERSION2) {
534#ifdef HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY
341d2553
RG
535 res = crypto_box_curve25519xchacha20poly1305_open_easy_afternm(reinterpret_cast<unsigned char*>(packet.data()),
536 reinterpret_cast<unsigned char*>(&packet.at(sizeof(DNSCryptQueryHeader))),
537 packet.size() - sizeof(DNSCryptQueryHeader),
43234e76
RG
538 nonce,
539 d_sharedKey);
540#else /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */
541 res = -1;
542#endif /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */
543 } else {
544 res = -1;
545 }
546
547#else /* HAVE_CRYPTO_BOX_EASY_AFTERNM */
341d2553
RG
548 int res = crypto_box_open_easy(reinterpret_cast<unsigned char*>(packet.data()),
549 reinterpret_cast<unsigned char*>(&packet.at(sizeof(DNSCryptQueryHeader))),
550 packet.size() - sizeof(DNSCryptQueryHeader),
00ffb1c2 551 nonce,
43234e76
RG
552 d_header.clientPK,
553 d_pair->privateKey.key);
00ffb1c2 554#endif /* HAVE_CRYPTO_BOX_EASY_AFTERNM */
11e1e08b
RG
555
556 if (res != 0) {
557 vinfolog("Dropping encrypted query we can't decrypt");
558 return;
559 }
560
341d2553
RG
561 uint16_t decryptedQueryLen = packet.size() - sizeof(DNSCryptQueryHeader) - DNSCRYPT_MAC_SIZE;
562 uint16_t pos = decryptedQueryLen;
563 assert(pos < packet.size());
564 d_paddedLen = decryptedQueryLen;
11e1e08b 565
341d2553 566 while (pos > 0 && packet.at(pos - 1) == 0) pos--;
11e1e08b 567
341d2553 568 if (pos == 0 || packet.at(pos - 1) != 0x80) {
11e1e08b
RG
569 vinfolog("Dropping encrypted query with invalid padding value");
570 return;
571 }
572
573 pos--;
574
341d2553
RG
575 size_t paddingLen = decryptedQueryLen - pos;
576 packet.resize(pos);
11e1e08b
RG
577
578 if (tcp && paddingLen > DNSCRYPT_MAX_TCP_PADDING_SIZE) {
579 vinfolog("Dropping encrypted query with too long padding size");
580 return;
581 }
582
43234e76
RG
583 d_len = pos;
584 d_valid = true;
585}
11e1e08b 586
32fbb2ab 587void DNSCryptQuery::getCertificateResponse(time_t now, PacketBuffer& response) const
43234e76
RG
588{
589 assert(d_ctx != nullptr);
590 d_ctx->getCertificateResponse(now, d_qname, d_id, response);
11e1e08b
RG
591}
592
32fbb2ab 593void DNSCryptQuery::parsePacket(PacketBuffer& packet, bool tcp, time_t now)
11e1e08b 594{
43234e76 595 d_valid = false;
11e1e08b
RG
596
597 /* might be a plaintext certificate request or an authenticated request */
341d2553
RG
598 if (isEncryptedQuery(packet, tcp, now)) {
599 getDecrypted(tcp, packet);
11e1e08b
RG
600 }
601 else {
341d2553 602 parsePlaintextQuery(packet);
11e1e08b
RG
603 }
604}
605
43234e76 606void DNSCryptQuery::fillServerNonce(unsigned char* nonce) const
11e1e08b 607{
43234e76 608 uint32_t* dest = reinterpret_cast<uint32_t*>(nonce);
11e1e08b
RG
609 static const size_t nonceSize = DNSCRYPT_NONCE_SIZE / 2;
610
611 for (size_t pos = 0; pos < (nonceSize / sizeof(*dest)); pos++)
612 {
613 const uint32_t value = randombytes_random();
614 memcpy(dest + pos, &value, sizeof(value));
615 }
616}
617
618/*
619 "The length of <resolver-response-pad> must be between 0 and 256 bytes,
620 and must be constant for a given (<resolver-sk>, <client-nonce>) tuple."
621*/
43234e76 622uint16_t DNSCryptQuery::computePaddingSize(uint16_t unpaddedLen, size_t maxLen) const
11e1e08b 623{
43234e76 624 size_t paddedSize = 0;
11e1e08b
RG
625 uint16_t result = 0;
626 uint32_t rnd = 0;
43234e76
RG
627 assert(d_header.clientNonce);
628 assert(d_pair != nullptr);
629
11e1e08b 630 unsigned char nonce[DNSCRYPT_NONCE_SIZE];
43234e76
RG
631 memcpy(nonce, d_header.clientNonce, (DNSCRYPT_NONCE_SIZE / 2));
632 memcpy(&(nonce[DNSCRYPT_NONCE_SIZE / 2]), d_header.clientNonce, (DNSCRYPT_NONCE_SIZE / 2));
633 crypto_stream((unsigned char*) &rnd, sizeof(rnd), nonce, d_pair->privateKey.key);
11e1e08b 634
43234e76
RG
635 paddedSize = unpaddedLen + rnd % (maxLen - unpaddedLen + 1);
636 paddedSize += DNSCRYPT_PADDED_BLOCK_SIZE - (paddedSize % DNSCRYPT_PADDED_BLOCK_SIZE);
11e1e08b 637
43234e76
RG
638 if (paddedSize > maxLen)
639 paddedSize = maxLen;
11e1e08b 640
43234e76 641 result = paddedSize - unpaddedLen;
11e1e08b
RG
642
643 return result;
644}
645
32fbb2ab 646int DNSCryptQuery::encryptResponse(PacketBuffer& response, size_t maxResponseSize, bool tcp)
11e1e08b 647{
43234e76 648 struct DNSCryptResponseHeader responseHeader;
341d2553
RG
649 assert(response.size() > 0);
650 assert(maxResponseSize >= response.size());
43234e76
RG
651 assert(d_encrypted == true);
652 assert(d_pair != nullptr);
11e1e08b 653
341d2553
RG
654 /* a DNSCrypt UDP response can't be larger than the (padded) DNSCrypt query */
655 if (!tcp && d_paddedLen < response.size()) {
656 /* so we need to truncate it */
bd64cc44
RG
657 size_t questionSize = 0;
658
341d2553
RG
659 if (response.size() > sizeof(dnsheader)) {
660 unsigned int qnameWireLength = 0;
661 DNSName tempQName(reinterpret_cast<const char*>(response.data()), response.size(), sizeof(dnsheader), false, 0, 0, &qnameWireLength);
662 if (qnameWireLength > 0) {
663 questionSize = qnameWireLength + DNS_TYPE_SIZE + DNS_CLASS_SIZE;
bd64cc44
RG
664 }
665 }
666
341d2553 667 response.resize(sizeof(dnsheader) + questionSize);
bd64cc44 668
341d2553
RG
669 if (response.size() > d_paddedLen) {
670 /* that does not seem right but let's truncate even more */
671 response.resize(d_paddedLen);
bd64cc44 672 }
341d2553 673 struct dnsheader* dh = reinterpret_cast<struct dnsheader*>(response.data());
bd64cc44 674 dh->ancount = dh->arcount = dh->nscount = 0;
11e1e08b
RG
675 dh->tc = 1;
676 }
677
341d2553
RG
678 size_t requiredSize = sizeof(responseHeader) + DNSCRYPT_MAC_SIZE + response.size();
679 size_t maxSize = std::min(maxResponseSize, requiredSize + DNSCRYPT_MAX_RESPONSE_PADDING_SIZE);
43234e76 680 uint16_t paddingSize = computePaddingSize(requiredSize, maxSize);
11e1e08b
RG
681 requiredSize += paddingSize;
682
341d2553 683 if (requiredSize > maxResponseSize) {
11e1e08b 684 return ENOBUFS;
341d2553 685 }
11e1e08b 686
43234e76
RG
687 memcpy(&responseHeader.nonce, &d_header.clientNonce, sizeof d_header.clientNonce);
688 fillServerNonce(&(responseHeader.nonce[sizeof(d_header.clientNonce)]));
11e1e08b 689
341d2553 690 size_t responseLen = response.size();
11e1e08b 691 /* moving the existing response after the header + MAC */
341d2553
RG
692 response.resize(requiredSize);
693 std::copy_backward(response.begin(), response.begin() + responseLen, response.begin() + responseLen + sizeof(responseHeader) + DNSCRYPT_MAC_SIZE);
11e1e08b
RG
694
695 uint16_t pos = 0;
696 /* copying header */
341d2553 697 memcpy(&response.at(pos), &responseHeader, sizeof(responseHeader));
43234e76 698 pos += sizeof(responseHeader);
11e1e08b 699 /* setting MAC bytes to 0 */
341d2553 700 memset(&response.at(pos), 0, DNSCRYPT_MAC_SIZE);
11e1e08b
RG
701 pos += DNSCRYPT_MAC_SIZE;
702 uint16_t toEncryptPos = pos;
703 /* skipping response */
704 pos += responseLen;
705 /* padding */
341d2553 706 response.at(pos) = static_cast<uint8_t>(0x80);
11e1e08b 707 pos++;
341d2553 708 memset(&response.at(pos), 0, paddingSize - 1);
11e1e08b 709 pos += (paddingSize - 1);
332fdc5f 710
11e1e08b 711 /* encrypting */
00ffb1c2 712#ifdef HAVE_CRYPTO_BOX_EASY_AFTERNM
43234e76 713 int res = computeSharedKey();
8089cbe5
RG
714 if (res != 0) {
715 return res;
332fdc5f
RG
716 }
717
43234e76
RG
718 const DNSCryptExchangeVersion version = getVersion();
719
720 if (version == DNSCryptExchangeVersion::VERSION1) {
341d2553
RG
721 res = crypto_box_easy_afternm(reinterpret_cast<unsigned char*>(&response.at(sizeof(responseHeader))),
722 reinterpret_cast<unsigned char*>(&response.at(toEncryptPos)),
43234e76
RG
723 responseLen + paddingSize,
724 responseHeader.nonce,
725 d_sharedKey);
726 }
727 else if (version == DNSCryptExchangeVersion::VERSION2) {
728#ifdef HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY
341d2553
RG
729 res = crypto_box_curve25519xchacha20poly1305_easy_afternm(reinterpret_cast<unsigned char*>(&response.at(sizeof(responseHeader))),
730 reinterpret_cast<unsigned char*>(&response.at(toEncryptPos)),
43234e76
RG
731 responseLen + paddingSize,
732 responseHeader.nonce,
733 d_sharedKey);
734#else /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */
735 res = -1;
736#endif /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */
737 }
738 else {
739 res = -1;
740 }
00ffb1c2 741#else
341d2553
RG
742 int res = crypto_box_easy(reinterpret_cast<unsigned char*>(&response.at(sizeof(responseHeader))),
743 reinterpret_cast<unsigned char*>(&response.at(toEncryptPos)),
00ffb1c2 744 responseLen + paddingSize,
43234e76
RG
745 responseHeader.nonce,
746 d_header.clientPK,
747 d_pair->privateKey.key);
00ffb1c2 748#endif /* HAVE_CRYPTO_BOX_EASY_AFTERNM */
11e1e08b
RG
749
750 if (res == 0) {
751 assert(pos == requiredSize);
11e1e08b
RG
752 }
753
754 return res;
755}
756
32fbb2ab 757int DNSCryptContext::encryptQuery(PacketBuffer& packet, 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
11e1e08b 758{
341d2553 759 assert(packet.size() > 0);
43234e76
RG
760 assert(cert != nullptr);
761
341d2553 762 size_t queryLen = packet.size();
11e1e08b 763 unsigned char nonce[DNSCRYPT_NONCE_SIZE];
43234e76 764 size_t requiredSize = sizeof(DNSCryptQueryHeader) + DNSCRYPT_MAC_SIZE + queryLen;
11e1e08b
RG
765 /* this is not optimal, we should compute a random padding size, multiple of DNSCRYPT_PADDED_BLOCK_SIZE,
766 DNSCRYPT_PADDED_BLOCK_SIZE <= padding size <= 4096? */
767 uint16_t paddingSize = DNSCRYPT_PADDED_BLOCK_SIZE - (queryLen % DNSCRYPT_PADDED_BLOCK_SIZE);
768 requiredSize += paddingSize;
769
43234e76
RG
770 if (!tcp && requiredSize < DNSCryptQuery::s_minUDPLength) {
771 paddingSize += (DNSCryptQuery::s_minUDPLength - requiredSize);
772 requiredSize = DNSCryptQuery::s_minUDPLength;
11e1e08b
RG
773 }
774
341d2553 775 if (requiredSize > maximumSize) {
11e1e08b 776 return ENOBUFS;
341d2553 777 }
11e1e08b
RG
778
779 /* moving the existing query after the header + MAC */
341d2553
RG
780 packet.resize(requiredSize);
781 std::copy_backward(packet.begin(), packet.begin() + queryLen, packet.begin() + queryLen + sizeof(DNSCryptQueryHeader) + DNSCRYPT_MAC_SIZE);
11e1e08b
RG
782
783 size_t pos = 0;
784 /* client magic */
341d2553 785 memcpy(&packet.at(pos), cert->signedData.clientMagic, sizeof(cert->signedData.clientMagic));
43234e76 786 pos += sizeof(cert->signedData.clientMagic);
11e1e08b
RG
787
788 /* client PK */
341d2553 789 memcpy(&packet.at(pos), clientPublicKey, DNSCRYPT_PUBLIC_KEY_SIZE);
11e1e08b
RG
790 pos += DNSCRYPT_PUBLIC_KEY_SIZE;
791
792 /* client nonce */
341d2553 793 memcpy(&packet.at(pos), clientNonce, DNSCRYPT_NONCE_SIZE / 2);
11e1e08b
RG
794 pos += DNSCRYPT_NONCE_SIZE / 2;
795 size_t encryptedPos = pos;
796
797 /* clear the MAC bytes */
341d2553 798 memset(&packet.at(pos), 0, DNSCRYPT_MAC_SIZE);
11e1e08b
RG
799 pos += DNSCRYPT_MAC_SIZE;
800
801 /* skipping data */
802 pos += queryLen;
803
804 /* padding */
341d2553 805 packet.at(pos) = static_cast<uint8_t>(0x80);
11e1e08b 806 pos++;
341d2553 807 memset(&packet.at(pos), 0, paddingSize - 1);
11e1e08b
RG
808 pos += paddingSize - 1;
809
810 memcpy(nonce, clientNonce, DNSCRYPT_NONCE_SIZE / 2);
811 memset(nonce + (DNSCRYPT_NONCE_SIZE / 2), 0, DNSCRYPT_NONCE_SIZE / 2);
812
43234e76
RG
813 const DNSCryptExchangeVersion version = getExchangeVersion(*cert);
814 int res = -1;
815
816 if (version == DNSCryptExchangeVersion::VERSION1) {
341d2553
RG
817 res = crypto_box_easy(reinterpret_cast<unsigned char*>(&packet.at(encryptedPos)),
818 reinterpret_cast<unsigned char*>(&packet.at(encryptedPos + DNSCRYPT_MAC_SIZE)),
43234e76
RG
819 queryLen + paddingSize,
820 nonce,
821 cert->signedData.resolverPK,
822 clientPrivateKey.key);
823 }
824 else if (version == DNSCryptExchangeVersion::VERSION2) {
825#ifdef HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY
341d2553
RG
826 res = crypto_box_curve25519xchacha20poly1305_easy(reinterpret_cast<unsigned char*>(&packet.at(encryptedPos)),
827 reinterpret_cast<unsigned char*>(&packet.at(encryptedPos + DNSCRYPT_MAC_SIZE)),
43234e76
RG
828 queryLen + paddingSize,
829 nonce,
830 cert->signedData.resolverPK,
831 clientPrivateKey.key);
832#endif /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */
833 }
834 else {
835 throw std::runtime_error("Unknown DNSCrypt exchange version");
836 }
11e1e08b
RG
837
838 if (res == 0) {
839 assert(pos == requiredSize);
11e1e08b
RG
840 }
841
842 return res;
843}
844
43234e76 845bool generateDNSCryptCertificate(const std::string& providerPrivateKeyFile, uint32_t serial, time_t begin, time_t end, DNSCryptExchangeVersion version, DNSCryptCert& certOut, DNSCryptPrivateKey& keyOut)
6bb38cd6
RG
846{
847 bool success = false;
848 unsigned char providerPrivateKey[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE];
849 sodium_mlock(providerPrivateKey, sizeof(providerPrivateKey));
850 sodium_memzero(providerPrivateKey, sizeof(providerPrivateKey));
851
852 try {
853 ifstream providerKStream(providerPrivateKeyFile);
854 providerKStream.read((char*) providerPrivateKey, sizeof(providerPrivateKey));
855 if (providerKStream.fail()) {
856 providerKStream.close();
857 throw std::runtime_error("Invalid DNSCrypt provider key file " + providerPrivateKeyFile);
858 }
859
43234e76 860 DNSCryptContext::generateCertificate(serial, begin, end, version, providerPrivateKey, keyOut, certOut);
6bb38cd6
RG
861 success = true;
862 }
863 catch(const std::exception& e) {
864 errlog(e.what());
865 }
866
867 sodium_memzero(providerPrivateKey, sizeof(providerPrivateKey));
868 sodium_munlock(providerPrivateKey, sizeof(providerPrivateKey));
869 return success;
870}
871
11e1e08b 872#endif