]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnscrypt.cc
rec: Update new b-root-server.net addresses in built-in hints.
[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
341d2553 402 const struct dnsheader * dh = reinterpret_cast<const struct dnsheader *>(packet.data());
11e1e08b 403 if (dh->qr || ntohs(dh->qdcount) != 1 || dh->ancount != 0 || dh->nscount != 0 || dh->opcode != Opcode::Query)
43234e76 404 return false;
11e1e08b 405
341d2553 406 unsigned int qnameWireLength;
11e1e08b 407 uint16_t qtype, qclass;
341d2553
RG
408 DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, &qclass, &qnameWireLength);
409 if ((packet.size() - sizeof(dnsheader)) < (qnameWireLength + sizeof(qtype) + sizeof(qclass))) {
43234e76 410 return false;
341d2553 411 }
11e1e08b 412
341d2553 413 if (qtype != QType::TXT || qclass != QClass::IN) {
43234e76 414 return false;
341d2553 415 }
11e1e08b 416
341d2553 417 if (qname != d_ctx->getProviderName()) {
43234e76 418 return false;
341d2553 419 }
43234e76
RG
420
421 d_qname = qname;
422 d_id = dh->id;
423 d_valid = true;
11e1e08b 424
43234e76 425 return true;
11e1e08b
RG
426}
427
32fbb2ab 428void DNSCryptContext::getCertificateResponse(time_t now, const DNSName& qname, uint16_t qid, PacketBuffer& response)
11e1e08b 429{
32fbb2ab 430 GenericDNSPacketWriter<PacketBuffer> pw(response, qname, QType::TXT, QClass::IN, Opcode::Query);
11e1e08b 431 struct dnsheader * dh = pw.getHeader();
43234e76 432 dh->id = qid;
11e1e08b
RG
433 dh->qr = true;
434 dh->rcode = RCode::NoError;
11e1e08b 435
6c1813a0
RG
436 auto certs = d_certs.read_lock();
437 for (const auto& pair : *certs) {
43234e76
RG
438 if (!pair->active || !pair->cert.isValid(now)) {
439 continue;
440 }
11e1e08b 441
43234e76
RG
442 pw.startRecord(qname, QType::TXT, (DNSCRYPT_CERTIFICATE_RESPONSE_TTL), QClass::IN, DNSResourceRecord::ANSWER, true);
443 std::string scert;
444 uint8_t certSize = sizeof(pair->cert);
445 scert.assign((const char*) &certSize, sizeof(certSize));
446 scert.append((const char*) &pair->cert, certSize);
11e1e08b 447
43234e76
RG
448 pw.xfrBlob(scert);
449 pw.commit();
11e1e08b 450 }
43234e76 451}
11e1e08b 452
43234e76
RG
453bool DNSCryptContext::magicMatchesAPublicKey(DNSCryptQuery& query, time_t now)
454{
455 const unsigned char* magic = query.getClientMagic();
456
6c1813a0
RG
457 auto certs = d_certs.read_lock();
458 for (const auto& pair : *certs) {
43234e76
RG
459 if (pair->cert.isValid(now) && memcmp(magic, pair->cert.signedData.clientMagic, DNSCRYPT_CLIENT_MAGIC_SIZE) == 0) {
460 query.setCertificatePair(pair);
461 return true;
462 }
11e1e08b
RG
463 }
464
465 return false;
466}
467
32fbb2ab 468bool DNSCryptQuery::isEncryptedQuery(const PacketBuffer& packet, bool tcp, time_t now)
11e1e08b 469{
43234e76 470 assert(d_ctx != nullptr);
11e1e08b 471
43234e76
RG
472 d_encrypted = false;
473
341d2553 474 if (packet.size() < sizeof(DNSCryptQueryHeader)) {
43234e76 475 return false;
11e1e08b
RG
476 }
477
341d2553 478 if (!tcp && packet.size() < DNSCryptQuery::s_minUDPLength) {
43234e76 479 return false;
11e1e08b
RG
480 }
481
341d2553 482 const struct DNSCryptQueryHeader* header = reinterpret_cast<const struct DNSCryptQueryHeader*>(packet.data());
11e1e08b 483
43234e76 484 d_header = *header;
11e1e08b 485
43234e76
RG
486 if (!d_ctx->magicMatchesAPublicKey(*this, now)) {
487 return false;
11e1e08b
RG
488 }
489
43234e76
RG
490 d_encrypted = true;
491
492 return true;
11e1e08b
RG
493}
494
32fbb2ab 495void DNSCryptQuery::getDecrypted(bool tcp, PacketBuffer& packet)
11e1e08b 496{
43234e76
RG
497 assert(d_encrypted);
498 assert(d_pair != nullptr);
499 assert(d_valid == false);
11e1e08b
RG
500
501#ifdef DNSCRYPT_STRICT_PADDING_LENGTH
341d2553
RG
502 if (tcp && ((packet.size() - sizeof(DNSCryptQueryHeader)) % DNSCRYPT_PADDED_BLOCK_SIZE) != 0) {
503 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
504 return;
505 }
506#endif
507
508 unsigned char nonce[DNSCRYPT_NONCE_SIZE];
43234e76 509 static_assert(sizeof(nonce) == (2* sizeof(d_header.clientNonce)), "Nonce should be larger than clientNonce (half)");
ef2ea4bf 510 static_assert(sizeof(d_header.clientPK) == DNSCRYPT_PUBLIC_KEY_SIZE, "Client Public key size is not right");
43234e76 511 static_assert(sizeof(d_pair->privateKey.key) == DNSCRYPT_PRIVATE_KEY_SIZE, "Private key size is not right");
11e1e08b 512
43234e76
RG
513 memcpy(nonce, &d_header.clientNonce, sizeof(d_header.clientNonce));
514 memset(nonce + sizeof(d_header.clientNonce), 0, sizeof(nonce) - sizeof(d_header.clientNonce));
11e1e08b 515
00ffb1c2 516#ifdef HAVE_CRYPTO_BOX_EASY_AFTERNM
43234e76 517 int res = computeSharedKey();
8089cbe5
RG
518 if (res != 0) {
519 vinfolog("Dropping encrypted query we can't compute the shared key for");
520 return;
332fdc5f
RG
521 }
522
43234e76
RG
523 const DNSCryptExchangeVersion version = getVersion();
524
525 if (version == DNSCryptExchangeVersion::VERSION1) {
341d2553
RG
526 res = crypto_box_open_easy_afternm(reinterpret_cast<unsigned char*>(packet.data()),
527 reinterpret_cast<unsigned char*>(&packet.at(sizeof(DNSCryptQueryHeader))),
528 packet.size() - sizeof(DNSCryptQueryHeader),
43234e76
RG
529 nonce,
530 d_sharedKey);
531 }
532 else if (version == DNSCryptExchangeVersion::VERSION2) {
533#ifdef HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY
341d2553
RG
534 res = crypto_box_curve25519xchacha20poly1305_open_easy_afternm(reinterpret_cast<unsigned char*>(packet.data()),
535 reinterpret_cast<unsigned char*>(&packet.at(sizeof(DNSCryptQueryHeader))),
536 packet.size() - sizeof(DNSCryptQueryHeader),
43234e76
RG
537 nonce,
538 d_sharedKey);
539#else /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */
540 res = -1;
541#endif /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */
542 } else {
543 res = -1;
544 }
545
546#else /* HAVE_CRYPTO_BOX_EASY_AFTERNM */
341d2553
RG
547 int res = crypto_box_open_easy(reinterpret_cast<unsigned char*>(packet.data()),
548 reinterpret_cast<unsigned char*>(&packet.at(sizeof(DNSCryptQueryHeader))),
549 packet.size() - sizeof(DNSCryptQueryHeader),
00ffb1c2 550 nonce,
43234e76
RG
551 d_header.clientPK,
552 d_pair->privateKey.key);
00ffb1c2 553#endif /* HAVE_CRYPTO_BOX_EASY_AFTERNM */
11e1e08b
RG
554
555 if (res != 0) {
556 vinfolog("Dropping encrypted query we can't decrypt");
557 return;
558 }
559
341d2553
RG
560 uint16_t decryptedQueryLen = packet.size() - sizeof(DNSCryptQueryHeader) - DNSCRYPT_MAC_SIZE;
561 uint16_t pos = decryptedQueryLen;
562 assert(pos < packet.size());
563 d_paddedLen = decryptedQueryLen;
11e1e08b 564
341d2553 565 while (pos > 0 && packet.at(pos - 1) == 0) pos--;
11e1e08b 566
341d2553 567 if (pos == 0 || packet.at(pos - 1) != 0x80) {
11e1e08b
RG
568 vinfolog("Dropping encrypted query with invalid padding value");
569 return;
570 }
571
572 pos--;
573
341d2553
RG
574 size_t paddingLen = decryptedQueryLen - pos;
575 packet.resize(pos);
11e1e08b
RG
576
577 if (tcp && paddingLen > DNSCRYPT_MAX_TCP_PADDING_SIZE) {
578 vinfolog("Dropping encrypted query with too long padding size");
579 return;
580 }
581
43234e76
RG
582 d_len = pos;
583 d_valid = true;
584}
11e1e08b 585
32fbb2ab 586void DNSCryptQuery::getCertificateResponse(time_t now, PacketBuffer& response) const
43234e76
RG
587{
588 assert(d_ctx != nullptr);
589 d_ctx->getCertificateResponse(now, d_qname, d_id, response);
11e1e08b
RG
590}
591
32fbb2ab 592void DNSCryptQuery::parsePacket(PacketBuffer& packet, bool tcp, time_t now)
11e1e08b 593{
43234e76 594 d_valid = false;
11e1e08b
RG
595
596 /* might be a plaintext certificate request or an authenticated request */
341d2553
RG
597 if (isEncryptedQuery(packet, tcp, now)) {
598 getDecrypted(tcp, packet);
11e1e08b
RG
599 }
600 else {
341d2553 601 parsePlaintextQuery(packet);
11e1e08b
RG
602 }
603}
604
43234e76 605void DNSCryptQuery::fillServerNonce(unsigned char* nonce) const
11e1e08b 606{
43234e76 607 uint32_t* dest = reinterpret_cast<uint32_t*>(nonce);
11e1e08b
RG
608 static const size_t nonceSize = DNSCRYPT_NONCE_SIZE / 2;
609
610 for (size_t pos = 0; pos < (nonceSize / sizeof(*dest)); pos++)
611 {
612 const uint32_t value = randombytes_random();
613 memcpy(dest + pos, &value, sizeof(value));
614 }
615}
616
617/*
618 "The length of <resolver-response-pad> must be between 0 and 256 bytes,
619 and must be constant for a given (<resolver-sk>, <client-nonce>) tuple."
620*/
43234e76 621uint16_t DNSCryptQuery::computePaddingSize(uint16_t unpaddedLen, size_t maxLen) const
11e1e08b 622{
43234e76 623 size_t paddedSize = 0;
11e1e08b
RG
624 uint16_t result = 0;
625 uint32_t rnd = 0;
43234e76
RG
626 assert(d_header.clientNonce);
627 assert(d_pair != nullptr);
628
11e1e08b 629 unsigned char nonce[DNSCRYPT_NONCE_SIZE];
43234e76
RG
630 memcpy(nonce, d_header.clientNonce, (DNSCRYPT_NONCE_SIZE / 2));
631 memcpy(&(nonce[DNSCRYPT_NONCE_SIZE / 2]), d_header.clientNonce, (DNSCRYPT_NONCE_SIZE / 2));
632 crypto_stream((unsigned char*) &rnd, sizeof(rnd), nonce, d_pair->privateKey.key);
11e1e08b 633
43234e76
RG
634 paddedSize = unpaddedLen + rnd % (maxLen - unpaddedLen + 1);
635 paddedSize += DNSCRYPT_PADDED_BLOCK_SIZE - (paddedSize % DNSCRYPT_PADDED_BLOCK_SIZE);
11e1e08b 636
43234e76
RG
637 if (paddedSize > maxLen)
638 paddedSize = maxLen;
11e1e08b 639
43234e76 640 result = paddedSize - unpaddedLen;
11e1e08b
RG
641
642 return result;
643}
644
32fbb2ab 645int DNSCryptQuery::encryptResponse(PacketBuffer& response, size_t maxResponseSize, bool tcp)
11e1e08b 646{
43234e76 647 struct DNSCryptResponseHeader responseHeader;
341d2553
RG
648 assert(response.size() > 0);
649 assert(maxResponseSize >= response.size());
43234e76
RG
650 assert(d_encrypted == true);
651 assert(d_pair != nullptr);
11e1e08b 652
341d2553
RG
653 /* a DNSCrypt UDP response can't be larger than the (padded) DNSCrypt query */
654 if (!tcp && d_paddedLen < response.size()) {
655 /* so we need to truncate it */
bd64cc44
RG
656 size_t questionSize = 0;
657
341d2553
RG
658 if (response.size() > sizeof(dnsheader)) {
659 unsigned int qnameWireLength = 0;
660 DNSName tempQName(reinterpret_cast<const char*>(response.data()), response.size(), sizeof(dnsheader), false, 0, 0, &qnameWireLength);
661 if (qnameWireLength > 0) {
662 questionSize = qnameWireLength + DNS_TYPE_SIZE + DNS_CLASS_SIZE;
bd64cc44
RG
663 }
664 }
665
341d2553 666 response.resize(sizeof(dnsheader) + questionSize);
bd64cc44 667
341d2553
RG
668 if (response.size() > d_paddedLen) {
669 /* that does not seem right but let's truncate even more */
670 response.resize(d_paddedLen);
bd64cc44 671 }
341d2553 672 struct dnsheader* dh = reinterpret_cast<struct dnsheader*>(response.data());
bd64cc44 673 dh->ancount = dh->arcount = dh->nscount = 0;
11e1e08b
RG
674 dh->tc = 1;
675 }
676
341d2553
RG
677 size_t requiredSize = sizeof(responseHeader) + DNSCRYPT_MAC_SIZE + response.size();
678 size_t maxSize = std::min(maxResponseSize, requiredSize + DNSCRYPT_MAX_RESPONSE_PADDING_SIZE);
43234e76 679 uint16_t paddingSize = computePaddingSize(requiredSize, maxSize);
11e1e08b
RG
680 requiredSize += paddingSize;
681
341d2553 682 if (requiredSize > maxResponseSize) {
11e1e08b 683 return ENOBUFS;
341d2553 684 }
11e1e08b 685
43234e76
RG
686 memcpy(&responseHeader.nonce, &d_header.clientNonce, sizeof d_header.clientNonce);
687 fillServerNonce(&(responseHeader.nonce[sizeof(d_header.clientNonce)]));
11e1e08b 688
341d2553 689 size_t responseLen = response.size();
11e1e08b 690 /* moving the existing response after the header + MAC */
341d2553
RG
691 response.resize(requiredSize);
692 std::copy_backward(response.begin(), response.begin() + responseLen, response.begin() + responseLen + sizeof(responseHeader) + DNSCRYPT_MAC_SIZE);
11e1e08b
RG
693
694 uint16_t pos = 0;
695 /* copying header */
341d2553 696 memcpy(&response.at(pos), &responseHeader, sizeof(responseHeader));
43234e76 697 pos += sizeof(responseHeader);
11e1e08b 698 /* setting MAC bytes to 0 */
341d2553 699 memset(&response.at(pos), 0, DNSCRYPT_MAC_SIZE);
11e1e08b
RG
700 pos += DNSCRYPT_MAC_SIZE;
701 uint16_t toEncryptPos = pos;
702 /* skipping response */
703 pos += responseLen;
704 /* padding */
341d2553 705 response.at(pos) = static_cast<uint8_t>(0x80);
11e1e08b 706 pos++;
341d2553 707 memset(&response.at(pos), 0, paddingSize - 1);
11e1e08b 708 pos += (paddingSize - 1);
332fdc5f 709
11e1e08b 710 /* encrypting */
00ffb1c2 711#ifdef HAVE_CRYPTO_BOX_EASY_AFTERNM
43234e76 712 int res = computeSharedKey();
8089cbe5
RG
713 if (res != 0) {
714 return res;
332fdc5f
RG
715 }
716
43234e76
RG
717 const DNSCryptExchangeVersion version = getVersion();
718
719 if (version == DNSCryptExchangeVersion::VERSION1) {
341d2553
RG
720 res = crypto_box_easy_afternm(reinterpret_cast<unsigned char*>(&response.at(sizeof(responseHeader))),
721 reinterpret_cast<unsigned char*>(&response.at(toEncryptPos)),
43234e76
RG
722 responseLen + paddingSize,
723 responseHeader.nonce,
724 d_sharedKey);
725 }
726 else if (version == DNSCryptExchangeVersion::VERSION2) {
727#ifdef HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY
341d2553
RG
728 res = crypto_box_curve25519xchacha20poly1305_easy_afternm(reinterpret_cast<unsigned char*>(&response.at(sizeof(responseHeader))),
729 reinterpret_cast<unsigned char*>(&response.at(toEncryptPos)),
43234e76
RG
730 responseLen + paddingSize,
731 responseHeader.nonce,
732 d_sharedKey);
733#else /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */
734 res = -1;
735#endif /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */
736 }
737 else {
738 res = -1;
739 }
00ffb1c2 740#else
341d2553
RG
741 int res = crypto_box_easy(reinterpret_cast<unsigned char*>(&response.at(sizeof(responseHeader))),
742 reinterpret_cast<unsigned char*>(&response.at(toEncryptPos)),
00ffb1c2 743 responseLen + paddingSize,
43234e76
RG
744 responseHeader.nonce,
745 d_header.clientPK,
746 d_pair->privateKey.key);
00ffb1c2 747#endif /* HAVE_CRYPTO_BOX_EASY_AFTERNM */
11e1e08b
RG
748
749 if (res == 0) {
750 assert(pos == requiredSize);
11e1e08b
RG
751 }
752
753 return res;
754}
755
32fbb2ab 756int 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 757{
341d2553 758 assert(packet.size() > 0);
43234e76
RG
759 assert(cert != nullptr);
760
341d2553 761 size_t queryLen = packet.size();
11e1e08b 762 unsigned char nonce[DNSCRYPT_NONCE_SIZE];
43234e76 763 size_t requiredSize = sizeof(DNSCryptQueryHeader) + DNSCRYPT_MAC_SIZE + queryLen;
11e1e08b
RG
764 /* this is not optimal, we should compute a random padding size, multiple of DNSCRYPT_PADDED_BLOCK_SIZE,
765 DNSCRYPT_PADDED_BLOCK_SIZE <= padding size <= 4096? */
766 uint16_t paddingSize = DNSCRYPT_PADDED_BLOCK_SIZE - (queryLen % DNSCRYPT_PADDED_BLOCK_SIZE);
767 requiredSize += paddingSize;
768
43234e76
RG
769 if (!tcp && requiredSize < DNSCryptQuery::s_minUDPLength) {
770 paddingSize += (DNSCryptQuery::s_minUDPLength - requiredSize);
771 requiredSize = DNSCryptQuery::s_minUDPLength;
11e1e08b
RG
772 }
773
341d2553 774 if (requiredSize > maximumSize) {
11e1e08b 775 return ENOBUFS;
341d2553 776 }
11e1e08b
RG
777
778 /* moving the existing query after the header + MAC */
341d2553
RG
779 packet.resize(requiredSize);
780 std::copy_backward(packet.begin(), packet.begin() + queryLen, packet.begin() + queryLen + sizeof(DNSCryptQueryHeader) + DNSCRYPT_MAC_SIZE);
11e1e08b
RG
781
782 size_t pos = 0;
783 /* client magic */
341d2553 784 memcpy(&packet.at(pos), cert->signedData.clientMagic, sizeof(cert->signedData.clientMagic));
43234e76 785 pos += sizeof(cert->signedData.clientMagic);
11e1e08b
RG
786
787 /* client PK */
341d2553 788 memcpy(&packet.at(pos), clientPublicKey, DNSCRYPT_PUBLIC_KEY_SIZE);
11e1e08b
RG
789 pos += DNSCRYPT_PUBLIC_KEY_SIZE;
790
791 /* client nonce */
341d2553 792 memcpy(&packet.at(pos), clientNonce, DNSCRYPT_NONCE_SIZE / 2);
11e1e08b
RG
793 pos += DNSCRYPT_NONCE_SIZE / 2;
794 size_t encryptedPos = pos;
795
796 /* clear the MAC bytes */
341d2553 797 memset(&packet.at(pos), 0, DNSCRYPT_MAC_SIZE);
11e1e08b
RG
798 pos += DNSCRYPT_MAC_SIZE;
799
800 /* skipping data */
801 pos += queryLen;
802
803 /* padding */
341d2553 804 packet.at(pos) = static_cast<uint8_t>(0x80);
11e1e08b 805 pos++;
341d2553 806 memset(&packet.at(pos), 0, paddingSize - 1);
11e1e08b
RG
807 pos += paddingSize - 1;
808
809 memcpy(nonce, clientNonce, DNSCRYPT_NONCE_SIZE / 2);
810 memset(nonce + (DNSCRYPT_NONCE_SIZE / 2), 0, DNSCRYPT_NONCE_SIZE / 2);
811
43234e76
RG
812 const DNSCryptExchangeVersion version = getExchangeVersion(*cert);
813 int res = -1;
814
815 if (version == DNSCryptExchangeVersion::VERSION1) {
341d2553
RG
816 res = crypto_box_easy(reinterpret_cast<unsigned char*>(&packet.at(encryptedPos)),
817 reinterpret_cast<unsigned char*>(&packet.at(encryptedPos + DNSCRYPT_MAC_SIZE)),
43234e76
RG
818 queryLen + paddingSize,
819 nonce,
820 cert->signedData.resolverPK,
821 clientPrivateKey.key);
822 }
823 else if (version == DNSCryptExchangeVersion::VERSION2) {
824#ifdef HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY
341d2553
RG
825 res = crypto_box_curve25519xchacha20poly1305_easy(reinterpret_cast<unsigned char*>(&packet.at(encryptedPos)),
826 reinterpret_cast<unsigned char*>(&packet.at(encryptedPos + DNSCRYPT_MAC_SIZE)),
43234e76
RG
827 queryLen + paddingSize,
828 nonce,
829 cert->signedData.resolverPK,
830 clientPrivateKey.key);
831#endif /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */
832 }
833 else {
834 throw std::runtime_error("Unknown DNSCrypt exchange version");
835 }
11e1e08b
RG
836
837 if (res == 0) {
838 assert(pos == requiredSize);
11e1e08b
RG
839 }
840
841 return res;
842}
843
43234e76 844bool generateDNSCryptCertificate(const std::string& providerPrivateKeyFile, uint32_t serial, time_t begin, time_t end, DNSCryptExchangeVersion version, DNSCryptCert& certOut, DNSCryptPrivateKey& keyOut)
6bb38cd6
RG
845{
846 bool success = false;
847 unsigned char providerPrivateKey[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE];
848 sodium_mlock(providerPrivateKey, sizeof(providerPrivateKey));
849 sodium_memzero(providerPrivateKey, sizeof(providerPrivateKey));
850
851 try {
852 ifstream providerKStream(providerPrivateKeyFile);
853 providerKStream.read((char*) providerPrivateKey, sizeof(providerPrivateKey));
854 if (providerKStream.fail()) {
855 providerKStream.close();
856 throw std::runtime_error("Invalid DNSCrypt provider key file " + providerPrivateKeyFile);
857 }
858
43234e76 859 DNSCryptContext::generateCertificate(serial, begin, end, version, providerPrivateKey, keyOut, certOut);
6bb38cd6
RG
860 success = true;
861 }
862 catch(const std::exception& e) {
863 errlog(e.what());
864 }
865
866 sodium_memzero(providerPrivateKey, sizeof(providerPrivateKey));
867 sodium_munlock(providerPrivateKey, sizeof(providerPrivateKey));
868 return success;
869}
870
11e1e08b 871#endif