]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnscrypt.cc
Merge pull request #7973 from yantarou/do_pdsn_control_current_config
[thirdparty/pdns.git] / pdns / dnscrypt.cc
1 /*
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22 #include "config.h"
23 #ifdef HAVE_DNSCRYPT
24 #include <fstream>
25 #include "dolog.hh"
26 #include "dnscrypt.hh"
27 #include "dnswriter.hh"
28 #include "lock.hh"
29
30 DNSCryptPrivateKey::DNSCryptPrivateKey()
31 {
32 sodium_memzero(key, sizeof(key));
33 sodium_mlock(key, sizeof(key));
34 }
35
36 void DNSCryptPrivateKey::loadFromFile(const std::string& keyFile)
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
51 void DNSCryptPrivateKey::saveToFile(const std::string& keyFile) const
52 {
53 ofstream file(keyFile);
54 file.write((char*) key, sizeof(key));
55 file.close();
56 }
57
58 DNSCryptPrivateKey::~DNSCryptPrivateKey()
59 {
60 sodium_munlock(key, sizeof(key));
61 }
62
63 DNSCryptExchangeVersion 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
72 #ifdef HAVE_CRYPTO_BOX_EASY_AFTERNM
73 DNSCryptQuery::~DNSCryptQuery()
74 {
75 if (d_sharedKeyComputed) {
76 sodium_munlock(d_sharedKey, sizeof(d_sharedKey));
77 }
78 }
79
80 int DNSCryptQuery::computeSharedKey()
81 {
82 assert(d_pair != nullptr);
83
84 int res = 0;
85
86 if (d_sharedKeyComputed) {
87 return res;
88 }
89
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 }
111
112 if (res != 0) {
113 sodium_munlock(d_sharedKey, sizeof(d_sharedKey));
114 return res;
115 }
116
117 d_sharedKeyComputed = true;
118 return res;
119 }
120 #else
121 DNSCryptQuery::~DNSCryptQuery()
122 {
123 }
124 #endif /* HAVE_CRYPTO_BOX_EASY_AFTERNM */
125
126 DNSCryptContext::DNSCryptContext(const std::string& pName, const std::vector<CertKeyPaths>& certKeys): d_certKeyPaths(certKeys), providerName(pName)
127 {
128 pthread_rwlock_init(&d_lock, 0);
129
130 reloadCertificates();
131 }
132
133 DNSCryptContext::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
140 void DNSCryptContext::generateProviderKeys(unsigned char publicKey[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE], unsigned char privateKey[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE])
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
149 std::string DNSCryptContext::getProviderFingerprint(unsigned char publicKey[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE])
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
165 void 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
180 DNSCryptExchangeVersion 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
196 DNSCryptExchangeVersion DNSCryptContext::getExchangeVersion(const DNSCryptCert& cert)
197 {
198 return getExchangeVersion(cert.esVersion);
199 }
200
201
202 void 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)
203 {
204 unsigned char magic[DNSCRYPT_CERT_MAGIC_SIZE] = DNSCRYPT_CERT_MAGIC_VALUE;
205 unsigned char protocolMinorVersion[] = DNSCRYPT_CERT_PROTOCOL_MINOR_VERSION_VALUE;
206 unsigned char pubK[DNSCRYPT_PUBLIC_KEY_SIZE];
207 unsigned char esVersion[sizeof(DNSCryptCert::esVersion)];
208 setExchangeVersion(version, esVersion);
209
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));
217 cert.signedData.serial = htonl(serial);
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) {
230 assert(signatureSize == sizeof(DNSCryptCertSignedData) + DNSCRYPT_SIGNATURE_SIZE);
231 }
232 else {
233 throw std::runtime_error("Error generating DNSCrypt certificate");
234 }
235 }
236
237 void DNSCryptContext::loadCertFromFile(const std::string&filename, DNSCryptCert& dest)
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
248 void DNSCryptContext::saveCertFromFile(const DNSCryptCert& cert, const std::string&filename)
249 {
250 ofstream file(filename);
251 file.write((char *) &cert, sizeof(cert));
252 file.close();
253 }
254
255 void DNSCryptContext::generateResolverKeyPair(DNSCryptPrivateKey& privK, unsigned char pubK[DNSCRYPT_PUBLIC_KEY_SIZE])
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
264 void DNSCryptContext::computePublicKeyFromPrivate(const DNSCryptPrivateKey& privK, unsigned char* pubK)
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
274 std::string DNSCryptContext::certificateDateToStr(uint32_t date)
275 {
276 char buf[20];
277 time_t tdate = static_cast<time_t>(ntohl(date));
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
286 void DNSCryptContext::addNewCertificate(std::shared_ptr<DNSCryptCertificatePair>& newCert, bool reload)
287 {
288 WriteLock w(&d_lock);
289
290 for (auto pair : d_certs) {
291 if (pair->cert.getSerial() == newCert->cert.getSerial()) {
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 }
299 }
300 }
301
302 d_certs.push_back(newCert);
303 }
304
305 void DNSCryptContext::addNewCertificate(const DNSCryptCert& newCert, const DNSCryptPrivateKey& newKey, bool active, bool reload)
306 {
307 auto pair = std::make_shared<DNSCryptCertificatePair>();
308 pair->cert = newCert;
309 pair->privateKey = newKey;
310 computePublicKeyFromPrivate(pair->privateKey, pair->publicKey);
311 pair->active = active;
312
313 addNewCertificate(pair, reload);
314 }
315
316 std::shared_ptr<DNSCryptCertificatePair> DNSCryptContext::loadCertificatePair(const std::string& certFile, const std::string& keyFile)
317 {
318 auto pair = std::make_shared<DNSCryptCertificatePair>();
319 loadCertFromFile(certFile, pair->cert);
320 pair->privateKey.loadFromFile(keyFile);
321 pair->active = true;
322 computePublicKeyFromPrivate(pair->privateKey, pair->publicKey);
323 return pair;
324 }
325
326 void DNSCryptContext::loadNewCertificate(const std::string& certFile, const std::string& keyFile, bool active, bool reload)
327 {
328 auto newPair = DNSCryptContext::loadCertificatePair(certFile, keyFile);
329 newPair->active = active;
330 addNewCertificate(newPair, reload);
331 d_certKeyPaths.push_back({certFile, keyFile});
332 }
333
334 void DNSCryptContext::reloadCertificates()
335 {
336 std::vector<std::shared_ptr<DNSCryptCertificatePair>> newCerts;
337 for (const auto& pair : d_certKeyPaths) {
338 newCerts.push_back(DNSCryptContext::loadCertificatePair(pair.cert, pair.key));
339 }
340
341 {
342 WriteLock w(&d_lock);
343 d_certs = std::move(newCerts);
344 }
345 }
346
347 void DNSCryptContext::markActive(uint32_t serial)
348 {
349 WriteLock w(&d_lock);
350
351 for (auto pair : d_certs) {
352 if (pair->active == false && pair->cert.getSerial() == serial) {
353 pair->active = true;
354 return;
355 }
356 }
357 throw std::runtime_error("No inactive certificate found with this serial");
358 }
359
360 void DNSCryptContext::markInactive(uint32_t serial)
361 {
362 WriteLock w(&d_lock);
363
364 for (auto pair : d_certs) {
365 if (pair->active == true && pair->cert.getSerial() == serial) {
366 pair->active = false;
367 return;
368 }
369 }
370 throw std::runtime_error("No active certificate found with this serial");
371 }
372
373 void DNSCryptContext::removeInactiveCertificate(uint32_t serial)
374 {
375 WriteLock w(&d_lock);
376
377 for (auto it = d_certs.begin(); it != d_certs.end(); ) {
378 if ((*it)->active == false && (*it)->cert.getSerial() == serial) {
379 it = d_certs.erase(it);
380 return;
381 } else {
382 it++;
383 }
384 }
385 throw std::runtime_error("No inactive certificate found with this serial");
386 }
387
388 bool DNSCryptQuery::parsePlaintextQuery(const char * packet, uint16_t packetSize)
389 {
390 assert(d_ctx != nullptr);
391
392 if (packetSize < sizeof(dnsheader)) {
393 return false;
394 }
395
396 const struct dnsheader * dh = reinterpret_cast<const struct dnsheader *>(packet);
397 if (dh->qr || ntohs(dh->qdcount) != 1 || dh->ancount != 0 || dh->nscount != 0 || dh->opcode != Opcode::Query)
398 return false;
399
400 unsigned int consumed;
401 uint16_t qtype, qclass;
402 DNSName qname(packet, packetSize, sizeof(dnsheader), false, &qtype, &qclass, &consumed);
403 if ((packetSize - sizeof(dnsheader)) < (consumed + sizeof(qtype) + sizeof(qclass)))
404 return false;
405
406 if (qtype != QType::TXT || qclass != QClass::IN)
407 return false;
408
409 if (qname != d_ctx->getProviderName())
410 return false;
411
412 d_qname = qname;
413 d_id = dh->id;
414 d_valid = true;
415
416 return true;
417 }
418
419 void DNSCryptContext::getCertificateResponse(time_t now, const DNSName& qname, uint16_t qid, std::vector<uint8_t>& response)
420 {
421 DNSPacketWriter pw(response, qname, QType::TXT, QClass::IN, Opcode::Query);
422 struct dnsheader * dh = pw.getHeader();
423 dh->id = qid;
424 dh->qr = true;
425 dh->rcode = RCode::NoError;
426
427 ReadLock r(&d_lock);
428 for (const auto pair : d_certs) {
429 if (!pair->active || !pair->cert.isValid(now)) {
430 continue;
431 }
432
433 pw.startRecord(qname, QType::TXT, (DNSCRYPT_CERTIFICATE_RESPONSE_TTL), QClass::IN, DNSResourceRecord::ANSWER, true);
434 std::string scert;
435 uint8_t certSize = sizeof(pair->cert);
436 scert.assign((const char*) &certSize, sizeof(certSize));
437 scert.append((const char*) &pair->cert, certSize);
438
439 pw.xfrBlob(scert);
440 pw.commit();
441 }
442 }
443
444 bool DNSCryptContext::magicMatchesAPublicKey(DNSCryptQuery& query, time_t now)
445 {
446 const unsigned char* magic = query.getClientMagic();
447
448 ReadLock r(&d_lock);
449 for (const auto& pair : d_certs) {
450 if (pair->cert.isValid(now) && memcmp(magic, pair->cert.signedData.clientMagic, DNSCRYPT_CLIENT_MAGIC_SIZE) == 0) {
451 query.setCertificatePair(pair);
452 return true;
453 }
454 }
455
456 return false;
457 }
458
459 bool DNSCryptQuery::isEncryptedQuery(const char * packet, uint16_t packetSize, bool tcp, time_t now)
460 {
461 assert(d_ctx != nullptr);
462
463 d_encrypted = false;
464
465 if (packetSize < sizeof(DNSCryptQueryHeader)) {
466 return false;
467 }
468
469 if (!tcp && packetSize < DNSCryptQuery::s_minUDPLength) {
470 return false;
471 }
472
473 const struct DNSCryptQueryHeader* header = reinterpret_cast<const struct DNSCryptQueryHeader*>(packet);
474
475 d_header = *header;
476
477 if (!d_ctx->magicMatchesAPublicKey(*this, now)) {
478 return false;
479 }
480
481 d_encrypted = true;
482
483 return true;
484 }
485
486 void DNSCryptQuery::getDecrypted(bool tcp, char* packet, uint16_t packetSize, uint16_t* decryptedQueryLen)
487 {
488 assert(decryptedQueryLen != nullptr);
489 assert(d_encrypted);
490 assert(d_pair != nullptr);
491 assert(d_valid == false);
492
493 #ifdef DNSCRYPT_STRICT_PADDING_LENGTH
494 if (tcp && ((packetSize - sizeof(DNSCryptQueryHeader)) % DNSCRYPT_PADDED_BLOCK_SIZE) != 0) {
495 vinfolog("Dropping encrypted query with invalid size of %d (should be a multiple of %d)", (packetSize - sizeof(DNSCryptQueryHeader)), DNSCRYPT_PADDED_BLOCK_SIZE);
496 return;
497 }
498 #endif
499
500 unsigned char nonce[DNSCRYPT_NONCE_SIZE];
501 static_assert(sizeof(nonce) == (2* sizeof(d_header.clientNonce)), "Nonce should be larger than clientNonce (half)");
502 static_assert(sizeof(d_header.clientPK) == DNSCRYPT_PUBLIC_KEY_SIZE, "Client Publick key size is not right");
503 static_assert(sizeof(d_pair->privateKey.key) == DNSCRYPT_PRIVATE_KEY_SIZE, "Private key size is not right");
504
505 memcpy(nonce, &d_header.clientNonce, sizeof(d_header.clientNonce));
506 memset(nonce + sizeof(d_header.clientNonce), 0, sizeof(nonce) - sizeof(d_header.clientNonce));
507
508 #ifdef HAVE_CRYPTO_BOX_EASY_AFTERNM
509 int res = computeSharedKey();
510 if (res != 0) {
511 vinfolog("Dropping encrypted query we can't compute the shared key for");
512 return;
513 }
514
515 const DNSCryptExchangeVersion version = getVersion();
516
517 if (version == DNSCryptExchangeVersion::VERSION1) {
518 res = crypto_box_open_easy_afternm(reinterpret_cast<unsigned char*>(packet),
519 reinterpret_cast<unsigned char*>(packet + sizeof(DNSCryptQueryHeader)),
520 packetSize - sizeof(DNSCryptQueryHeader),
521 nonce,
522 d_sharedKey);
523 }
524 else if (version == DNSCryptExchangeVersion::VERSION2) {
525 #ifdef HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY
526 res = crypto_box_curve25519xchacha20poly1305_open_easy_afternm(reinterpret_cast<unsigned char*>(packet),
527 reinterpret_cast<unsigned char*>(packet + sizeof(DNSCryptQueryHeader)),
528 packetSize - sizeof(DNSCryptQueryHeader),
529 nonce,
530 d_sharedKey);
531 #else /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */
532 res = -1;
533 #endif /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */
534 } else {
535 res = -1;
536 }
537
538 #else /* HAVE_CRYPTO_BOX_EASY_AFTERNM */
539 int res = crypto_box_open_easy(reinterpret_cast<unsigned char*>(packet),
540 reinterpret_cast<unsigned char*>(packet + sizeof(DNSCryptQueryHeader)),
541 packetSize - sizeof(DNSCryptQueryHeader),
542 nonce,
543 d_header.clientPK,
544 d_pair->privateKey.key);
545 #endif /* HAVE_CRYPTO_BOX_EASY_AFTERNM */
546
547 if (res != 0) {
548 vinfolog("Dropping encrypted query we can't decrypt");
549 return;
550 }
551
552 *decryptedQueryLen = packetSize - sizeof(DNSCryptQueryHeader) - DNSCRYPT_MAC_SIZE;
553 uint16_t pos = *decryptedQueryLen;
554 assert(pos < packetSize);
555 d_paddedLen = *decryptedQueryLen;
556
557 while(pos > 0 && packet[pos - 1] == 0) pos--;
558
559 if (pos == 0 || static_cast<uint8_t>(packet[pos - 1]) != 0x80) {
560 vinfolog("Dropping encrypted query with invalid padding value");
561 return;
562 }
563
564 pos--;
565
566 size_t paddingLen = *decryptedQueryLen - pos;
567 *decryptedQueryLen = pos;
568
569 if (tcp && paddingLen > DNSCRYPT_MAX_TCP_PADDING_SIZE) {
570 vinfolog("Dropping encrypted query with too long padding size");
571 return;
572 }
573
574 d_len = pos;
575 d_valid = true;
576 }
577
578 void DNSCryptQuery::getCertificateResponse(time_t now, std::vector<uint8_t>& response) const
579 {
580 assert(d_ctx != nullptr);
581 d_ctx->getCertificateResponse(now, d_qname, d_id, response);
582 }
583
584 void DNSCryptQuery::parsePacket(char* packet, uint16_t packetSize, bool tcp, uint16_t* decryptedQueryLen, time_t now)
585 {
586 assert(packet != nullptr);
587 assert(decryptedQueryLen != nullptr);
588
589 d_valid = false;
590
591 /* might be a plaintext certificate request or an authenticated request */
592 if (isEncryptedQuery(packet, packetSize, tcp, now)) {
593 getDecrypted(tcp, packet, packetSize, decryptedQueryLen);
594 }
595 else {
596 parsePlaintextQuery(packet, packetSize);
597 }
598 }
599
600 void DNSCryptQuery::fillServerNonce(unsigned char* nonce) const
601 {
602 uint32_t* dest = reinterpret_cast<uint32_t*>(nonce);
603 static const size_t nonceSize = DNSCRYPT_NONCE_SIZE / 2;
604
605 for (size_t pos = 0; pos < (nonceSize / sizeof(*dest)); pos++)
606 {
607 const uint32_t value = randombytes_random();
608 memcpy(dest + pos, &value, sizeof(value));
609 }
610 }
611
612 /*
613 "The length of <resolver-response-pad> must be between 0 and 256 bytes,
614 and must be constant for a given (<resolver-sk>, <client-nonce>) tuple."
615 */
616 uint16_t DNSCryptQuery::computePaddingSize(uint16_t unpaddedLen, size_t maxLen) const
617 {
618 size_t paddedSize = 0;
619 uint16_t result = 0;
620 uint32_t rnd = 0;
621 assert(d_header.clientNonce);
622 assert(d_pair != nullptr);
623
624 unsigned char nonce[DNSCRYPT_NONCE_SIZE];
625 memcpy(nonce, d_header.clientNonce, (DNSCRYPT_NONCE_SIZE / 2));
626 memcpy(&(nonce[DNSCRYPT_NONCE_SIZE / 2]), d_header.clientNonce, (DNSCRYPT_NONCE_SIZE / 2));
627 crypto_stream((unsigned char*) &rnd, sizeof(rnd), nonce, d_pair->privateKey.key);
628
629 paddedSize = unpaddedLen + rnd % (maxLen - unpaddedLen + 1);
630 paddedSize += DNSCRYPT_PADDED_BLOCK_SIZE - (paddedSize % DNSCRYPT_PADDED_BLOCK_SIZE);
631
632 if (paddedSize > maxLen)
633 paddedSize = maxLen;
634
635 result = paddedSize - unpaddedLen;
636
637 return result;
638 }
639
640 int DNSCryptQuery::encryptResponse(char* response, uint16_t responseLen, uint16_t responseSize, bool tcp, uint16_t* encryptedResponseLen)
641 {
642 struct DNSCryptResponseHeader responseHeader;
643 assert(response != nullptr);
644 assert(responseLen > 0);
645 assert(responseSize >= responseLen);
646 assert(encryptedResponseLen != nullptr);
647 assert(d_encrypted == true);
648 assert(d_pair != nullptr);
649
650 if (!tcp && d_paddedLen < responseLen) {
651 struct dnsheader* dh = reinterpret_cast<struct dnsheader*>(response);
652 size_t questionSize = 0;
653
654 if (responseLen > sizeof(dnsheader)) {
655 unsigned int consumed = 0;
656 DNSName tempQName(response, responseLen, sizeof(dnsheader), false, 0, 0, &consumed);
657 if (consumed > 0) {
658 questionSize = consumed + DNS_TYPE_SIZE + DNS_CLASS_SIZE;
659 }
660 }
661
662 responseLen = sizeof(dnsheader) + questionSize;
663
664 if (responseLen > d_paddedLen) {
665 responseLen = d_paddedLen;
666 }
667 dh->ancount = dh->arcount = dh->nscount = 0;
668 dh->tc = 1;
669 }
670
671 size_t requiredSize = sizeof(responseHeader) + DNSCRYPT_MAC_SIZE + responseLen;
672 size_t maxSize = (responseSize > (requiredSize + DNSCRYPT_MAX_RESPONSE_PADDING_SIZE)) ? (requiredSize + DNSCRYPT_MAX_RESPONSE_PADDING_SIZE) : responseSize;
673 uint16_t paddingSize = computePaddingSize(requiredSize, maxSize);
674 requiredSize += paddingSize;
675
676 if (requiredSize > responseSize)
677 return ENOBUFS;
678
679 memcpy(&responseHeader.nonce, &d_header.clientNonce, sizeof d_header.clientNonce);
680 fillServerNonce(&(responseHeader.nonce[sizeof(d_header.clientNonce)]));
681
682 /* moving the existing response after the header + MAC */
683 memmove(response + sizeof(responseHeader) + DNSCRYPT_MAC_SIZE, response, responseLen);
684
685 uint16_t pos = 0;
686 /* copying header */
687 memcpy(response + pos, &responseHeader, sizeof(responseHeader));
688 pos += sizeof(responseHeader);
689 /* setting MAC bytes to 0 */
690 memset(response + pos, 0, DNSCRYPT_MAC_SIZE);
691 pos += DNSCRYPT_MAC_SIZE;
692 uint16_t toEncryptPos = pos;
693 /* skipping response */
694 pos += responseLen;
695 /* padding */
696 response[pos] = static_cast<uint8_t>(0x80);
697 pos++;
698 memset(response + pos, 0, paddingSize - 1);
699 pos += (paddingSize - 1);
700
701 /* encrypting */
702 #ifdef HAVE_CRYPTO_BOX_EASY_AFTERNM
703 int res = computeSharedKey();
704 if (res != 0) {
705 return res;
706 }
707
708 const DNSCryptExchangeVersion version = getVersion();
709
710 if (version == DNSCryptExchangeVersion::VERSION1) {
711 res = crypto_box_easy_afternm(reinterpret_cast<unsigned char*>(response + sizeof(responseHeader)),
712 reinterpret_cast<unsigned char*>(response + toEncryptPos),
713 responseLen + paddingSize,
714 responseHeader.nonce,
715 d_sharedKey);
716 }
717 else if (version == DNSCryptExchangeVersion::VERSION2) {
718 #ifdef HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY
719 res = crypto_box_curve25519xchacha20poly1305_easy_afternm(reinterpret_cast<unsigned char*>(response + sizeof(responseHeader)),
720 reinterpret_cast<unsigned char*>(response + toEncryptPos),
721 responseLen + paddingSize,
722 responseHeader.nonce,
723 d_sharedKey);
724 #else /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */
725 res = -1;
726 #endif /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */
727 }
728 else {
729 res = -1;
730 }
731 #else
732 int res = crypto_box_easy(reinterpret_cast<unsigned char*>(response + sizeof(responseHeader)),
733 reinterpret_cast<unsigned char*>(response + toEncryptPos),
734 responseLen + paddingSize,
735 responseHeader.nonce,
736 d_header.clientPK,
737 d_pair->privateKey.key);
738 #endif /* HAVE_CRYPTO_BOX_EASY_AFTERNM */
739
740 if (res == 0) {
741 assert(pos == requiredSize);
742 *encryptedResponseLen = requiredSize;
743 }
744
745 return res;
746 }
747
748 int 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
749 {
750 assert(query != nullptr);
751 assert(queryLen > 0);
752 assert(querySize >= queryLen);
753 assert(encryptedResponseLen != nullptr);
754 assert(cert != nullptr);
755
756 unsigned char nonce[DNSCRYPT_NONCE_SIZE];
757 size_t requiredSize = sizeof(DNSCryptQueryHeader) + DNSCRYPT_MAC_SIZE + queryLen;
758 /* this is not optimal, we should compute a random padding size, multiple of DNSCRYPT_PADDED_BLOCK_SIZE,
759 DNSCRYPT_PADDED_BLOCK_SIZE <= padding size <= 4096? */
760 uint16_t paddingSize = DNSCRYPT_PADDED_BLOCK_SIZE - (queryLen % DNSCRYPT_PADDED_BLOCK_SIZE);
761 requiredSize += paddingSize;
762
763 if (!tcp && requiredSize < DNSCryptQuery::s_minUDPLength) {
764 paddingSize += (DNSCryptQuery::s_minUDPLength - requiredSize);
765 requiredSize = DNSCryptQuery::s_minUDPLength;
766 }
767
768 if (requiredSize > querySize)
769 return ENOBUFS;
770
771 /* moving the existing query after the header + MAC */
772 memmove(query + sizeof(DNSCryptQueryHeader) + DNSCRYPT_MAC_SIZE, query, queryLen);
773
774 size_t pos = 0;
775 /* client magic */
776 memcpy(query + pos, cert->signedData.clientMagic, sizeof(cert->signedData.clientMagic));
777 pos += sizeof(cert->signedData.clientMagic);
778
779 /* client PK */
780 memcpy(query + pos, clientPublicKey, DNSCRYPT_PUBLIC_KEY_SIZE);
781 pos += DNSCRYPT_PUBLIC_KEY_SIZE;
782
783 /* client nonce */
784 memcpy(query + pos, clientNonce, DNSCRYPT_NONCE_SIZE / 2);
785 pos += DNSCRYPT_NONCE_SIZE / 2;
786 size_t encryptedPos = pos;
787
788 /* clear the MAC bytes */
789 memset(query + pos, 0, DNSCRYPT_MAC_SIZE);
790 pos += DNSCRYPT_MAC_SIZE;
791
792 /* skipping data */
793 pos += queryLen;
794
795 /* padding */
796 query[pos] = static_cast<uint8_t>(0x80);
797 pos++;
798 memset(query + pos, 0, paddingSize - 1);
799 pos += paddingSize - 1;
800
801 memcpy(nonce, clientNonce, DNSCRYPT_NONCE_SIZE / 2);
802 memset(nonce + (DNSCRYPT_NONCE_SIZE / 2), 0, DNSCRYPT_NONCE_SIZE / 2);
803
804 const DNSCryptExchangeVersion version = getExchangeVersion(*cert);
805 int res = -1;
806
807 if (version == DNSCryptExchangeVersion::VERSION1) {
808 res = crypto_box_easy(reinterpret_cast<unsigned char*>(query + encryptedPos),
809 reinterpret_cast<unsigned char*>(query + encryptedPos + DNSCRYPT_MAC_SIZE),
810 queryLen + paddingSize,
811 nonce,
812 cert->signedData.resolverPK,
813 clientPrivateKey.key);
814 }
815 else if (version == DNSCryptExchangeVersion::VERSION2) {
816 #ifdef HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY
817 res = crypto_box_curve25519xchacha20poly1305_easy(reinterpret_cast<unsigned char*>(query + encryptedPos),
818 reinterpret_cast<unsigned char*>(query + encryptedPos + DNSCRYPT_MAC_SIZE),
819 queryLen + paddingSize,
820 nonce,
821 cert->signedData.resolverPK,
822 clientPrivateKey.key);
823 #endif /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */
824 }
825 else {
826 throw std::runtime_error("Unknown DNSCrypt exchange version");
827 }
828
829 if (res == 0) {
830 assert(pos == requiredSize);
831 *encryptedResponseLen = requiredSize;
832 }
833
834 return res;
835 }
836
837 bool generateDNSCryptCertificate(const std::string& providerPrivateKeyFile, uint32_t serial, time_t begin, time_t end, DNSCryptExchangeVersion version, DNSCryptCert& certOut, DNSCryptPrivateKey& keyOut)
838 {
839 bool success = false;
840 unsigned char providerPrivateKey[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE];
841 sodium_mlock(providerPrivateKey, sizeof(providerPrivateKey));
842 sodium_memzero(providerPrivateKey, sizeof(providerPrivateKey));
843
844 try {
845 ifstream providerKStream(providerPrivateKeyFile);
846 providerKStream.read((char*) providerPrivateKey, sizeof(providerPrivateKey));
847 if (providerKStream.fail()) {
848 providerKStream.close();
849 throw std::runtime_error("Invalid DNSCrypt provider key file " + providerPrivateKeyFile);
850 }
851
852 DNSCryptContext::generateCertificate(serial, begin, end, version, providerPrivateKey, keyOut, certOut);
853 success = true;
854 }
855 catch(const std::exception& e) {
856 errlog(e.what());
857 }
858
859 sodium_memzero(providerPrivateKey, sizeof(providerPrivateKey));
860 sodium_munlock(providerPrivateKey, sizeof(providerPrivateKey));
861 return success;
862 }
863
864 #endif