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