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