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