]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnscrypt.cc
dnsdist: Add 'reloadAllCertificates()'
[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>
25#include "dolog.hh"
26#include "dnscrypt.hh"
27#include "dnswriter.hh"
43234e76 28#include "lock.hh"
11e1e08b 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);
54 file.write((char*) key, sizeof(key));
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
43234e76
RG
126DNSCryptContext::DNSCryptContext(const std::string& pName, const std::string& certFile, const std::string& keyFile): providerName(pName)
127{
128 pthread_rwlock_init(&d_lock, 0);
129
130 loadNewCertificate(certFile, keyFile);
131}
132
133DNSCryptContext::DNSCryptContext(const std::string& pName, const DNSCryptCert& certificate, const DNSCryptPrivateKey& pKey): providerName(pName)
134{
135 pthread_rwlock_init(&d_lock, 0);
136
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);
11e1e08b
RG
218 cert.signedData.tsStart = htonl((uint32_t) begin);
219 cert.signedData.tsEnd = htonl((uint32_t) end);
220
221 unsigned long long signatureSize = 0;
222
223 int res = crypto_sign_ed25519(cert.signature,
224 &signatureSize,
225 (unsigned char*) &cert.signedData,
226 sizeof(cert.signedData),
227 providerPrivateKey);
228
229 if (res == 0) {
43234e76 230 assert(signatureSize == sizeof(DNSCryptCertSignedData) + DNSCRYPT_SIGNATURE_SIZE);
11e1e08b
RG
231 }
232 else {
233 throw std::runtime_error("Error generating DNSCrypt certificate");
234 }
235}
236
43234e76 237void DNSCryptContext::loadCertFromFile(const std::string&filename, DNSCryptCert& dest)
11e1e08b
RG
238{
239 ifstream file(filename);
240 file.read((char *) &dest, sizeof(dest));
241
242 if (file.fail())
243 throw std::runtime_error("Invalid dnscrypt certificate file " + filename);
244
245 file.close();
246}
247
43234e76 248void DNSCryptContext::saveCertFromFile(const DNSCryptCert& cert, const std::string&filename)
11e1e08b
RG
249{
250 ofstream file(filename);
251 file.write((char *) &cert, sizeof(cert));
252 file.close();
253}
254
43234e76 255void DNSCryptContext::generateResolverKeyPair(DNSCryptPrivateKey& privK, unsigned char pubK[DNSCRYPT_PUBLIC_KEY_SIZE])
11e1e08b
RG
256{
257 int res = crypto_box_keypair(pubK, privK.key);
258
259 if (res != 0) {
260 throw std::runtime_error("Error generating DNSCrypt resolver keys");
261 }
262}
263
43234e76 264void DNSCryptContext::computePublicKeyFromPrivate(const DNSCryptPrivateKey& privK, unsigned char* pubK)
11e1e08b
RG
265{
266 int res = crypto_scalarmult_base(pubK,
267 privK.key);
268
269 if (res != 0) {
270 throw std::runtime_error("Error computing dnscrypt public key from the private one");
271 }
272}
273
43234e76 274std::string DNSCryptContext::certificateDateToStr(uint32_t date)
11e1e08b
RG
275{
276 char buf[20];
43234e76 277 time_t tdate = static_cast<time_t>(ntohl(date));
11e1e08b
RG
278 struct tm date_tm;
279
280 localtime_r(&tdate, &date_tm);
281 strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &date_tm);
282
283 return string(buf);
284}
285
bcc62bfb 286void DNSCryptContext::addNewCertificate(const DNSCryptCert& newCert, const DNSCryptPrivateKey& newKey, bool active, bool reload)
11e1e08b 287{
43234e76
RG
288 WriteLock w(&d_lock);
289
290 for (auto pair : certs) {
291 if (pair->cert.getSerial() == newCert.getSerial()) {
bcc62bfb
RG
292 if (reload) {
293 /* on reload we just assume that this is the same certificate */
294 return;
295 }
296 else {
297 throw std::runtime_error("Error adding a new certificate: we already have a certificate with the same serial");
298 }
43234e76
RG
299 }
300 }
301
302 auto pair = std::make_shared<DNSCryptCertificatePair>();
303 pair->cert = newCert;
304 pair->privateKey = newKey;
305 computePublicKeyFromPrivate(pair->privateKey, pair->publicKey);
306 pair->active = active;
307 certs.push_back(pair);
11e1e08b
RG
308}
309
bcc62bfb 310void DNSCryptContext::loadNewCertificate(const std::string& certFile, const std::string& keyFile, bool active, bool reload)
11e1e08b 311{
43234e76
RG
312 DNSCryptCert newCert;
313 DNSCryptPrivateKey newPrivateKey;
11e1e08b
RG
314
315 loadCertFromFile(certFile, newCert);
316 newPrivateKey.loadFromFile(keyFile);
43234e76 317
bcc62bfb
RG
318 addNewCertificate(newCert, newPrivateKey, active, reload);
319 certificatePath = certFile;
320 keyPath = keyFile;
321}
322
323void DNSCryptContext::reloadCertificate()
324{
325 loadNewCertificate(certificatePath, keyPath, true, true);
43234e76
RG
326}
327
328void DNSCryptContext::markActive(uint32_t serial)
329{
330 WriteLock w(&d_lock);
331
332 for (auto pair : certs) {
333 if (pair->active == false && pair->cert.getSerial() == serial) {
334 pair->active = true;
335 return;
336 }
337 }
338 throw std::runtime_error("No inactive certificate found with this serial");
339}
340
341void DNSCryptContext::markInactive(uint32_t serial)
342{
343 WriteLock w(&d_lock);
344
345 for (auto pair : certs) {
346 if (pair->active == true && pair->cert.getSerial() == serial) {
347 pair->active = false;
348 return;
349 }
350 }
351 throw std::runtime_error("No active certificate found with this serial");
11e1e08b
RG
352}
353
43234e76 354void DNSCryptContext::removeInactiveCertificate(uint32_t serial)
11e1e08b 355{
43234e76
RG
356 WriteLock w(&d_lock);
357
358 for (auto it = certs.begin(); it != certs.end(); ) {
359 if ((*it)->active == false && (*it)->cert.getSerial() == serial) {
360 it = certs.erase(it);
361 return;
362 } else {
363 it++;
364 }
365 }
366 throw std::runtime_error("No inactive certificate found with this serial");
367}
368
369bool DNSCryptQuery::parsePlaintextQuery(const char * packet, uint16_t packetSize)
370{
371 assert(d_ctx != nullptr);
372
11e1e08b 373 if (packetSize < sizeof(dnsheader)) {
43234e76 374 return false;
11e1e08b
RG
375 }
376
43234e76 377 const struct dnsheader * dh = reinterpret_cast<const struct dnsheader *>(packet);
11e1e08b 378 if (dh->qr || ntohs(dh->qdcount) != 1 || dh->ancount != 0 || dh->nscount != 0 || dh->opcode != Opcode::Query)
43234e76 379 return false;
11e1e08b
RG
380
381 unsigned int consumed;
382 uint16_t qtype, qclass;
383 DNSName qname(packet, packetSize, sizeof(dnsheader), false, &qtype, &qclass, &consumed);
bd910269 384 if ((packetSize - sizeof(dnsheader)) < (consumed + sizeof(qtype) + sizeof(qclass)))
43234e76 385 return false;
11e1e08b
RG
386
387 if (qtype != QType::TXT || qclass != QClass::IN)
43234e76 388 return false;
11e1e08b 389
43234e76
RG
390 if (qname != d_ctx->getProviderName())
391 return false;
392
393 d_qname = qname;
394 d_id = dh->id;
395 d_valid = true;
11e1e08b 396
43234e76 397 return true;
11e1e08b
RG
398}
399
43234e76 400void DNSCryptContext::getCertificateResponse(time_t now, const DNSName& qname, uint16_t qid, std::vector<uint8_t>& response)
11e1e08b 401{
43234e76 402 DNSPacketWriter pw(response, qname, QType::TXT, QClass::IN, Opcode::Query);
11e1e08b 403 struct dnsheader * dh = pw.getHeader();
43234e76 404 dh->id = qid;
11e1e08b
RG
405 dh->qr = true;
406 dh->rcode = RCode::NoError;
11e1e08b 407
43234e76
RG
408 ReadLock r(&d_lock);
409 for (const auto pair : certs) {
410 if (!pair->active || !pair->cert.isValid(now)) {
411 continue;
412 }
11e1e08b 413
43234e76
RG
414 pw.startRecord(qname, QType::TXT, (DNSCRYPT_CERTIFICATE_RESPONSE_TTL), QClass::IN, DNSResourceRecord::ANSWER, true);
415 std::string scert;
416 uint8_t certSize = sizeof(pair->cert);
417 scert.assign((const char*) &certSize, sizeof(certSize));
418 scert.append((const char*) &pair->cert, certSize);
11e1e08b 419
43234e76
RG
420 pw.xfrBlob(scert);
421 pw.commit();
11e1e08b 422 }
43234e76 423}
11e1e08b 424
43234e76
RG
425bool DNSCryptContext::magicMatchesAPublicKey(DNSCryptQuery& query, time_t now)
426{
427 const unsigned char* magic = query.getClientMagic();
428
429 ReadLock r(&d_lock);
430 for (const auto& pair : certs) {
431 if (pair->cert.isValid(now) && memcmp(magic, pair->cert.signedData.clientMagic, DNSCRYPT_CLIENT_MAGIC_SIZE) == 0) {
432 query.setCertificatePair(pair);
433 return true;
434 }
11e1e08b
RG
435 }
436
437 return false;
438}
439
43234e76 440bool DNSCryptQuery::isEncryptedQuery(const char * packet, uint16_t packetSize, bool tcp, time_t now)
11e1e08b 441{
43234e76 442 assert(d_ctx != nullptr);
11e1e08b 443
43234e76
RG
444 d_encrypted = false;
445
446 if (packetSize < sizeof(DNSCryptQueryHeader)) {
447 return false;
11e1e08b
RG
448 }
449
43234e76
RG
450 if (!tcp && packetSize < DNSCryptQuery::s_minUDPLength) {
451 return false;
11e1e08b
RG
452 }
453
43234e76 454 const struct DNSCryptQueryHeader* header = reinterpret_cast<const struct DNSCryptQueryHeader*>(packet);
11e1e08b 455
43234e76 456 d_header = *header;
11e1e08b 457
43234e76
RG
458 if (!d_ctx->magicMatchesAPublicKey(*this, now)) {
459 return false;
11e1e08b
RG
460 }
461
43234e76
RG
462 d_encrypted = true;
463
464 return true;
11e1e08b
RG
465}
466
43234e76 467void DNSCryptQuery::getDecrypted(bool tcp, char* packet, uint16_t packetSize, uint16_t* decryptedQueryLen)
11e1e08b 468{
43234e76
RG
469 assert(decryptedQueryLen != nullptr);
470 assert(d_encrypted);
471 assert(d_pair != nullptr);
472 assert(d_valid == false);
11e1e08b
RG
473
474#ifdef DNSCRYPT_STRICT_PADDING_LENGTH
43234e76
RG
475 if (tcp && ((packetSize - sizeof(DNSCryptQueryHeader)) % DNSCRYPT_PADDED_BLOCK_SIZE) != 0) {
476 vinfolog("Dropping encrypted query with invalid size of %d (should be a multiple of %d)", (packetSize - sizeof(DNSCryptQueryHeader)), DNSCRYPT_PADDED_BLOCK_SIZE);
11e1e08b
RG
477 return;
478 }
479#endif
480
481 unsigned char nonce[DNSCRYPT_NONCE_SIZE];
43234e76
RG
482 static_assert(sizeof(nonce) == (2* sizeof(d_header.clientNonce)), "Nonce should be larger than clientNonce (half)");
483 static_assert(sizeof(d_header.clientPK) == DNSCRYPT_PUBLIC_KEY_SIZE, "Client Publick key size is not right");
484 static_assert(sizeof(d_pair->privateKey.key) == DNSCRYPT_PRIVATE_KEY_SIZE, "Private key size is not right");
11e1e08b 485
43234e76
RG
486 memcpy(nonce, &d_header.clientNonce, sizeof(d_header.clientNonce));
487 memset(nonce + sizeof(d_header.clientNonce), 0, sizeof(nonce) - sizeof(d_header.clientNonce));
11e1e08b 488
00ffb1c2 489#ifdef HAVE_CRYPTO_BOX_EASY_AFTERNM
43234e76 490 int res = computeSharedKey();
8089cbe5
RG
491 if (res != 0) {
492 vinfolog("Dropping encrypted query we can't compute the shared key for");
493 return;
332fdc5f
RG
494 }
495
43234e76
RG
496 const DNSCryptExchangeVersion version = getVersion();
497
498 if (version == DNSCryptExchangeVersion::VERSION1) {
499 res = crypto_box_open_easy_afternm(reinterpret_cast<unsigned char*>(packet),
500 reinterpret_cast<unsigned char*>(packet + sizeof(DNSCryptQueryHeader)),
501 packetSize - sizeof(DNSCryptQueryHeader),
502 nonce,
503 d_sharedKey);
504 }
505 else if (version == DNSCryptExchangeVersion::VERSION2) {
506#ifdef HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY
507 res = crypto_box_curve25519xchacha20poly1305_open_easy_afternm(reinterpret_cast<unsigned char*>(packet),
508 reinterpret_cast<unsigned char*>(packet + sizeof(DNSCryptQueryHeader)),
509 packetSize - sizeof(DNSCryptQueryHeader),
510 nonce,
511 d_sharedKey);
512#else /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */
513 res = -1;
514#endif /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */
515 } else {
516 res = -1;
517 }
518
519#else /* HAVE_CRYPTO_BOX_EASY_AFTERNM */
520 int res = crypto_box_open_easy(reinterpret_cast<unsigned char*>(packet),
521 reinterpret_cast<unsigned char*>(packet + sizeof(DNSCryptQueryHeader)),
522 packetSize - sizeof(DNSCryptQueryHeader),
00ffb1c2 523 nonce,
43234e76
RG
524 d_header.clientPK,
525 d_pair->privateKey.key);
00ffb1c2 526#endif /* HAVE_CRYPTO_BOX_EASY_AFTERNM */
11e1e08b
RG
527
528 if (res != 0) {
529 vinfolog("Dropping encrypted query we can't decrypt");
530 return;
531 }
532
43234e76 533 *decryptedQueryLen = packetSize - sizeof(DNSCryptQueryHeader) - DNSCRYPT_MAC_SIZE;
11e1e08b
RG
534 uint16_t pos = *decryptedQueryLen;
535 assert(pos < packetSize);
43234e76 536 d_paddedLen = *decryptedQueryLen;
11e1e08b
RG
537
538 while(pos > 0 && packet[pos - 1] == 0) pos--;
539
43234e76 540 if (pos == 0 || static_cast<uint8_t>(packet[pos - 1]) != 0x80) {
11e1e08b
RG
541 vinfolog("Dropping encrypted query with invalid padding value");
542 return;
543 }
544
545 pos--;
546
547 size_t paddingLen = *decryptedQueryLen - pos;
548 *decryptedQueryLen = pos;
549
550 if (tcp && paddingLen > DNSCRYPT_MAX_TCP_PADDING_SIZE) {
551 vinfolog("Dropping encrypted query with too long padding size");
552 return;
553 }
554
43234e76
RG
555 d_len = pos;
556 d_valid = true;
557}
11e1e08b 558
43234e76
RG
559void DNSCryptQuery::getCertificateResponse(time_t now, std::vector<uint8_t>& response) const
560{
561 assert(d_ctx != nullptr);
562 d_ctx->getCertificateResponse(now, d_qname, d_id, response);
11e1e08b
RG
563}
564
43234e76 565void DNSCryptQuery::parsePacket(char* packet, uint16_t packetSize, bool tcp, uint16_t* decryptedQueryLen, time_t now)
11e1e08b 566{
43234e76
RG
567 assert(packet != nullptr);
568 assert(decryptedQueryLen != nullptr);
11e1e08b 569
43234e76 570 d_valid = false;
11e1e08b
RG
571
572 /* might be a plaintext certificate request or an authenticated request */
43234e76
RG
573 if (isEncryptedQuery(packet, packetSize, tcp, now)) {
574 getDecrypted(tcp, packet, packetSize, decryptedQueryLen);
11e1e08b
RG
575 }
576 else {
43234e76 577 parsePlaintextQuery(packet, packetSize);
11e1e08b
RG
578 }
579}
580
43234e76 581void DNSCryptQuery::fillServerNonce(unsigned char* nonce) const
11e1e08b 582{
43234e76 583 uint32_t* dest = reinterpret_cast<uint32_t*>(nonce);
11e1e08b
RG
584 static const size_t nonceSize = DNSCRYPT_NONCE_SIZE / 2;
585
586 for (size_t pos = 0; pos < (nonceSize / sizeof(*dest)); pos++)
587 {
588 const uint32_t value = randombytes_random();
589 memcpy(dest + pos, &value, sizeof(value));
590 }
591}
592
593/*
594 "The length of <resolver-response-pad> must be between 0 and 256 bytes,
595 and must be constant for a given (<resolver-sk>, <client-nonce>) tuple."
596*/
43234e76 597uint16_t DNSCryptQuery::computePaddingSize(uint16_t unpaddedLen, size_t maxLen) const
11e1e08b 598{
43234e76 599 size_t paddedSize = 0;
11e1e08b
RG
600 uint16_t result = 0;
601 uint32_t rnd = 0;
43234e76
RG
602 assert(d_header.clientNonce);
603 assert(d_pair != nullptr);
604
11e1e08b 605 unsigned char nonce[DNSCRYPT_NONCE_SIZE];
43234e76
RG
606 memcpy(nonce, d_header.clientNonce, (DNSCRYPT_NONCE_SIZE / 2));
607 memcpy(&(nonce[DNSCRYPT_NONCE_SIZE / 2]), d_header.clientNonce, (DNSCRYPT_NONCE_SIZE / 2));
608 crypto_stream((unsigned char*) &rnd, sizeof(rnd), nonce, d_pair->privateKey.key);
11e1e08b 609
43234e76
RG
610 paddedSize = unpaddedLen + rnd % (maxLen - unpaddedLen + 1);
611 paddedSize += DNSCRYPT_PADDED_BLOCK_SIZE - (paddedSize % DNSCRYPT_PADDED_BLOCK_SIZE);
11e1e08b 612
43234e76
RG
613 if (paddedSize > maxLen)
614 paddedSize = maxLen;
11e1e08b 615
43234e76 616 result = paddedSize - unpaddedLen;
11e1e08b
RG
617
618 return result;
619}
620
43234e76 621int DNSCryptQuery::encryptResponse(char* response, uint16_t responseLen, uint16_t responseSize, bool tcp, uint16_t* encryptedResponseLen)
11e1e08b 622{
43234e76
RG
623 struct DNSCryptResponseHeader responseHeader;
624 assert(response != nullptr);
11e1e08b
RG
625 assert(responseLen > 0);
626 assert(responseSize >= responseLen);
43234e76
RG
627 assert(encryptedResponseLen != nullptr);
628 assert(d_encrypted == true);
629 assert(d_pair != nullptr);
11e1e08b 630
43234e76
RG
631 if (!tcp && d_paddedLen < responseLen) {
632 struct dnsheader* dh = reinterpret_cast<struct dnsheader*>(response);
bd64cc44
RG
633 size_t questionSize = 0;
634
635 if (responseLen > sizeof(dnsheader)) {
636 unsigned int consumed = 0;
43234e76 637 DNSName tempQName(response, responseLen, sizeof(dnsheader), false, 0, 0, &consumed);
bd64cc44
RG
638 if (consumed > 0) {
639 questionSize = consumed + DNS_TYPE_SIZE + DNS_CLASS_SIZE;
640 }
641 }
642
643 responseLen = sizeof(dnsheader) + questionSize;
644
43234e76
RG
645 if (responseLen > d_paddedLen) {
646 responseLen = d_paddedLen;
bd64cc44
RG
647 }
648 dh->ancount = dh->arcount = dh->nscount = 0;
11e1e08b
RG
649 dh->tc = 1;
650 }
651
43234e76 652 size_t requiredSize = sizeof(responseHeader) + DNSCRYPT_MAC_SIZE + responseLen;
11e1e08b 653 size_t maxSize = (responseSize > (requiredSize + DNSCRYPT_MAX_RESPONSE_PADDING_SIZE)) ? (requiredSize + DNSCRYPT_MAX_RESPONSE_PADDING_SIZE) : responseSize;
43234e76 654 uint16_t paddingSize = computePaddingSize(requiredSize, maxSize);
11e1e08b
RG
655 requiredSize += paddingSize;
656
657 if (requiredSize > responseSize)
658 return ENOBUFS;
659
43234e76
RG
660 memcpy(&responseHeader.nonce, &d_header.clientNonce, sizeof d_header.clientNonce);
661 fillServerNonce(&(responseHeader.nonce[sizeof(d_header.clientNonce)]));
11e1e08b
RG
662
663 /* moving the existing response after the header + MAC */
43234e76 664 memmove(response + sizeof(responseHeader) + DNSCRYPT_MAC_SIZE, response, responseLen);
11e1e08b
RG
665
666 uint16_t pos = 0;
667 /* copying header */
43234e76
RG
668 memcpy(response + pos, &responseHeader, sizeof(responseHeader));
669 pos += sizeof(responseHeader);
11e1e08b
RG
670 /* setting MAC bytes to 0 */
671 memset(response + pos, 0, DNSCRYPT_MAC_SIZE);
672 pos += DNSCRYPT_MAC_SIZE;
673 uint16_t toEncryptPos = pos;
674 /* skipping response */
675 pos += responseLen;
676 /* padding */
43234e76 677 response[pos] = static_cast<uint8_t>(0x80);
11e1e08b
RG
678 pos++;
679 memset(response + pos, 0, paddingSize - 1);
680 pos += (paddingSize - 1);
332fdc5f 681
11e1e08b 682 /* encrypting */
00ffb1c2 683#ifdef HAVE_CRYPTO_BOX_EASY_AFTERNM
43234e76 684 int res = computeSharedKey();
8089cbe5
RG
685 if (res != 0) {
686 return res;
332fdc5f
RG
687 }
688
43234e76
RG
689 const DNSCryptExchangeVersion version = getVersion();
690
691 if (version == DNSCryptExchangeVersion::VERSION1) {
692 res = crypto_box_easy_afternm(reinterpret_cast<unsigned char*>(response + sizeof(responseHeader)),
693 reinterpret_cast<unsigned char*>(response + toEncryptPos),
694 responseLen + paddingSize,
695 responseHeader.nonce,
696 d_sharedKey);
697 }
698 else if (version == DNSCryptExchangeVersion::VERSION2) {
699#ifdef HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY
700 res = crypto_box_curve25519xchacha20poly1305_easy_afternm(reinterpret_cast<unsigned char*>(response + sizeof(responseHeader)),
701 reinterpret_cast<unsigned char*>(response + toEncryptPos),
702 responseLen + paddingSize,
703 responseHeader.nonce,
704 d_sharedKey);
705#else /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */
706 res = -1;
707#endif /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */
708 }
709 else {
710 res = -1;
711 }
00ffb1c2 712#else
43234e76
RG
713 int res = crypto_box_easy(reinterpret_cast<unsigned char*>(response + sizeof(responseHeader)),
714 reinterpret_cast<unsigned char*>(response + toEncryptPos),
00ffb1c2 715 responseLen + paddingSize,
43234e76
RG
716 responseHeader.nonce,
717 d_header.clientPK,
718 d_pair->privateKey.key);
00ffb1c2 719#endif /* HAVE_CRYPTO_BOX_EASY_AFTERNM */
11e1e08b
RG
720
721 if (res == 0) {
722 assert(pos == requiredSize);
723 *encryptedResponseLen = requiredSize;
724 }
725
726 return res;
727}
728
f3b1a1ef 729int DNSCryptContext::encryptQuery(char* query, uint16_t queryLen, uint16_t querySize, const unsigned char clientPublicKey[DNSCRYPT_PUBLIC_KEY_SIZE], const DNSCryptPrivateKey& clientPrivateKey, const unsigned char clientNonce[DNSCRYPT_NONCE_SIZE / 2], bool tcp, uint16_t* encryptedResponseLen, const std::shared_ptr<DNSCryptCert>& cert) const
11e1e08b 730{
43234e76 731 assert(query != nullptr);
11e1e08b
RG
732 assert(queryLen > 0);
733 assert(querySize >= queryLen);
43234e76
RG
734 assert(encryptedResponseLen != nullptr);
735 assert(cert != nullptr);
736
11e1e08b 737 unsigned char nonce[DNSCRYPT_NONCE_SIZE];
43234e76 738 size_t requiredSize = sizeof(DNSCryptQueryHeader) + DNSCRYPT_MAC_SIZE + queryLen;
11e1e08b
RG
739 /* this is not optimal, we should compute a random padding size, multiple of DNSCRYPT_PADDED_BLOCK_SIZE,
740 DNSCRYPT_PADDED_BLOCK_SIZE <= padding size <= 4096? */
741 uint16_t paddingSize = DNSCRYPT_PADDED_BLOCK_SIZE - (queryLen % DNSCRYPT_PADDED_BLOCK_SIZE);
742 requiredSize += paddingSize;
743
43234e76
RG
744 if (!tcp && requiredSize < DNSCryptQuery::s_minUDPLength) {
745 paddingSize += (DNSCryptQuery::s_minUDPLength - requiredSize);
746 requiredSize = DNSCryptQuery::s_minUDPLength;
11e1e08b
RG
747 }
748
749 if (requiredSize > querySize)
750 return ENOBUFS;
751
752 /* moving the existing query after the header + MAC */
43234e76 753 memmove(query + sizeof(DNSCryptQueryHeader) + DNSCRYPT_MAC_SIZE, query, queryLen);
11e1e08b
RG
754
755 size_t pos = 0;
756 /* client magic */
43234e76
RG
757 memcpy(query + pos, cert->signedData.clientMagic, sizeof(cert->signedData.clientMagic));
758 pos += sizeof(cert->signedData.clientMagic);
11e1e08b
RG
759
760 /* client PK */
761 memcpy(query + pos, clientPublicKey, DNSCRYPT_PUBLIC_KEY_SIZE);
762 pos += DNSCRYPT_PUBLIC_KEY_SIZE;
763
764 /* client nonce */
765 memcpy(query + pos, clientNonce, DNSCRYPT_NONCE_SIZE / 2);
766 pos += DNSCRYPT_NONCE_SIZE / 2;
767 size_t encryptedPos = pos;
768
769 /* clear the MAC bytes */
770 memset(query + pos, 0, DNSCRYPT_MAC_SIZE);
771 pos += DNSCRYPT_MAC_SIZE;
772
773 /* skipping data */
774 pos += queryLen;
775
776 /* padding */
43234e76 777 query[pos] = static_cast<uint8_t>(0x80);
11e1e08b
RG
778 pos++;
779 memset(query + pos, 0, paddingSize - 1);
780 pos += paddingSize - 1;
781
782 memcpy(nonce, clientNonce, DNSCRYPT_NONCE_SIZE / 2);
783 memset(nonce + (DNSCRYPT_NONCE_SIZE / 2), 0, DNSCRYPT_NONCE_SIZE / 2);
784
43234e76
RG
785 const DNSCryptExchangeVersion version = getExchangeVersion(*cert);
786 int res = -1;
787
788 if (version == DNSCryptExchangeVersion::VERSION1) {
789 res = crypto_box_easy(reinterpret_cast<unsigned char*>(query + encryptedPos),
790 reinterpret_cast<unsigned char*>(query + encryptedPos + DNSCRYPT_MAC_SIZE),
791 queryLen + paddingSize,
792 nonce,
793 cert->signedData.resolverPK,
794 clientPrivateKey.key);
795 }
796 else if (version == DNSCryptExchangeVersion::VERSION2) {
797#ifdef HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY
798 res = crypto_box_curve25519xchacha20poly1305_easy(reinterpret_cast<unsigned char*>(query + encryptedPos),
799 reinterpret_cast<unsigned char*>(query + encryptedPos + DNSCRYPT_MAC_SIZE),
800 queryLen + paddingSize,
801 nonce,
802 cert->signedData.resolverPK,
803 clientPrivateKey.key);
804#endif /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */
805 }
806 else {
807 throw std::runtime_error("Unknown DNSCrypt exchange version");
808 }
11e1e08b
RG
809
810 if (res == 0) {
811 assert(pos == requiredSize);
812 *encryptedResponseLen = requiredSize;
813 }
814
815 return res;
816}
817
43234e76 818bool generateDNSCryptCertificate(const std::string& providerPrivateKeyFile, uint32_t serial, time_t begin, time_t end, DNSCryptExchangeVersion version, DNSCryptCert& certOut, DNSCryptPrivateKey& keyOut)
6bb38cd6
RG
819{
820 bool success = false;
821 unsigned char providerPrivateKey[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE];
822 sodium_mlock(providerPrivateKey, sizeof(providerPrivateKey));
823 sodium_memzero(providerPrivateKey, sizeof(providerPrivateKey));
824
825 try {
826 ifstream providerKStream(providerPrivateKeyFile);
827 providerKStream.read((char*) providerPrivateKey, sizeof(providerPrivateKey));
828 if (providerKStream.fail()) {
829 providerKStream.close();
830 throw std::runtime_error("Invalid DNSCrypt provider key file " + providerPrivateKeyFile);
831 }
832
43234e76 833 DNSCryptContext::generateCertificate(serial, begin, end, version, providerPrivateKey, keyOut, certOut);
6bb38cd6
RG
834 success = true;
835 }
836 catch(const std::exception& e) {
837 errlog(e.what());
838 }
839
840 sodium_memzero(providerPrivateKey, sizeof(providerPrivateKey));
841 sodium_munlock(providerPrivateKey, sizeof(providerPrivateKey));
842 return success;
843}
844
11e1e08b 845#endif