2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
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.
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.
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.
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.
26 #include "dnscrypt.hh"
27 #include "dnswriter.hh"
30 DNSCryptPrivateKey::DNSCryptPrivateKey()
32 sodium_memzero(key
, sizeof(key
));
33 sodium_mlock(key
, sizeof(key
));
36 void DNSCryptPrivateKey::loadFromFile(const std::string
& keyFile
)
38 ifstream
file(keyFile
);
39 sodium_memzero(key
, sizeof(key
));
40 file
.read((char*) key
, sizeof(key
));
43 sodium_memzero(key
, sizeof(key
));
45 throw std::runtime_error("Invalid DNSCrypt key file " + keyFile
);
51 void DNSCryptPrivateKey::saveToFile(const std::string
& keyFile
) const
53 ofstream
file(keyFile
);
54 file
.write((char*) key
, sizeof(key
));
58 DNSCryptPrivateKey::~DNSCryptPrivateKey()
60 sodium_munlock(key
, sizeof(key
));
63 DNSCryptExchangeVersion
DNSCryptQuery::getVersion() const
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");
69 return DNSCryptContext::getExchangeVersion(d_pair
->cert
);
72 #ifdef HAVE_CRYPTO_BOX_EASY_AFTERNM
73 DNSCryptQuery::~DNSCryptQuery()
75 if (d_sharedKeyComputed
) {
76 sodium_munlock(d_sharedKey
, sizeof(d_sharedKey
));
80 int DNSCryptQuery::computeSharedKey()
82 assert(d_pair
!= nullptr);
86 if (d_sharedKeyComputed
) {
90 const DNSCryptExchangeVersion version
= DNSCryptContext::getExchangeVersion(d_pair
->cert
);
92 sodium_mlock(d_sharedKey
, sizeof(d_sharedKey
));
94 if (version
== DNSCryptExchangeVersion::VERSION1
) {
95 res
= crypto_box_beforenm(d_sharedKey
,
97 d_pair
->privateKey
.key
);
99 else if (version
== DNSCryptExchangeVersion::VERSION2
) {
100 #ifdef HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY
101 res
= crypto_box_curve25519xchacha20poly1305_beforenm(d_sharedKey
,
103 d_pair
->privateKey
.key
);
104 #else /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */
106 #endif /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */
113 sodium_munlock(d_sharedKey
, sizeof(d_sharedKey
));
117 d_sharedKeyComputed
= true;
121 DNSCryptQuery::~DNSCryptQuery()
124 #endif /* HAVE_CRYPTO_BOX_EASY_AFTERNM */
127 DNSCryptContext::~DNSCryptContext() {
128 pthread_rwlock_destroy(&d_lock
);
131 DNSCryptContext::DNSCryptContext(const std::string
& pName
, const std::vector
<CertKeyPaths
>& certKeys
): d_certKeyPaths(certKeys
), providerName(pName
)
133 pthread_rwlock_init(&d_lock
, 0);
135 reloadCertificates();
138 DNSCryptContext::DNSCryptContext(const std::string
& pName
, const DNSCryptCert
& certificate
, const DNSCryptPrivateKey
& pKey
): providerName(pName
)
140 pthread_rwlock_init(&d_lock
, 0);
142 addNewCertificate(certificate
, pKey
);
145 void DNSCryptContext::generateProviderKeys(unsigned char publicKey
[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE
], unsigned char privateKey
[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE
])
147 int res
= crypto_sign_ed25519_keypair(publicKey
, privateKey
);
150 throw std::runtime_error("Error generating DNSCrypt provider keys");
154 std::string
DNSCryptContext::getProviderFingerprint(unsigned char publicKey
[DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE
])
156 boost::format
fmt("%02X%02X");
159 for (size_t idx
= 0; idx
< DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE
; idx
+= 2)
161 ret
<< (fmt
% static_cast<int>(publicKey
[idx
]) % static_cast<int>(publicKey
[idx
+1]));
162 if (idx
< (DNSCRYPT_PROVIDER_PUBLIC_KEY_SIZE
- 2)) {
170 void DNSCryptContext::setExchangeVersion(const DNSCryptExchangeVersion
& version
, unsigned char esVersion
[sizeof(DNSCryptCert::esVersion
)])
174 if (version
== DNSCryptExchangeVersion::VERSION1
) {
175 esVersion
[1] = { 0x01 };
177 else if (version
== DNSCryptExchangeVersion::VERSION2
) {
178 esVersion
[1] = { 0x02 };
181 throw std::runtime_error("Unknown DNSCrypt exchange version");
185 DNSCryptExchangeVersion
DNSCryptContext::getExchangeVersion(const unsigned char esVersion
[sizeof(DNSCryptCert::esVersion
)])
187 if (esVersion
[0] != 0x00) {
188 throw std::runtime_error("Unknown DNSCrypt exchange version");
191 if (esVersion
[1] == 0x01) {
192 return DNSCryptExchangeVersion::VERSION1
;
194 else if (esVersion
[1] == 0x02) {
195 return DNSCryptExchangeVersion::VERSION2
;
198 throw std::runtime_error("Unknown DNSCrypt exchange version");
201 DNSCryptExchangeVersion
DNSCryptContext::getExchangeVersion(const DNSCryptCert
& cert
)
203 return getExchangeVersion(cert
.esVersion
);
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
)
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
);
215 generateResolverKeyPair(privateKey
, pubK
);
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
);
226 unsigned long long signatureSize
= 0;
228 int res
= crypto_sign_ed25519(cert
.signature
,
230 (unsigned char*) &cert
.signedData
,
231 sizeof(cert
.signedData
),
235 assert(signatureSize
== sizeof(DNSCryptCertSignedData
) + DNSCRYPT_SIGNATURE_SIZE
);
238 throw std::runtime_error("Error generating DNSCrypt certificate");
242 void DNSCryptContext::loadCertFromFile(const std::string
&filename
, DNSCryptCert
& dest
)
244 ifstream
file(filename
);
245 file
.read((char *) &dest
, sizeof(dest
));
248 throw std::runtime_error("Invalid dnscrypt certificate file " + filename
);
253 void DNSCryptContext::saveCertFromFile(const DNSCryptCert
& cert
, const std::string
&filename
)
255 ofstream
file(filename
);
256 file
.write((char *) &cert
, sizeof(cert
));
260 void DNSCryptContext::generateResolverKeyPair(DNSCryptPrivateKey
& privK
, unsigned char pubK
[DNSCRYPT_PUBLIC_KEY_SIZE
])
262 int res
= crypto_box_keypair(pubK
, privK
.key
);
265 throw std::runtime_error("Error generating DNSCrypt resolver keys");
269 void DNSCryptContext::computePublicKeyFromPrivate(const DNSCryptPrivateKey
& privK
, unsigned char* pubK
)
271 int res
= crypto_scalarmult_base(pubK
,
275 throw std::runtime_error("Error computing dnscrypt public key from the private one");
279 std::string
DNSCryptContext::certificateDateToStr(uint32_t date
)
282 time_t tdate
= static_cast<time_t>(ntohl(date
));
285 localtime_r(&tdate
, &date_tm
);
286 strftime(buf
, sizeof(buf
), "%Y-%m-%d %H:%M:%S", &date_tm
);
291 void DNSCryptContext::addNewCertificate(std::shared_ptr
<DNSCryptCertificatePair
>& newCert
, bool reload
)
293 WriteLock
w(&d_lock
);
295 for (auto pair
: d_certs
) {
296 if (pair
->cert
.getSerial() == newCert
->cert
.getSerial()) {
298 /* on reload we just assume that this is the same certificate */
302 throw std::runtime_error("Error adding a new certificate: we already have a certificate with the same serial");
307 d_certs
.push_back(newCert
);
310 void DNSCryptContext::addNewCertificate(const DNSCryptCert
& newCert
, const DNSCryptPrivateKey
& newKey
, bool active
, bool reload
)
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
;
318 addNewCertificate(pair
, reload
);
321 std::shared_ptr
<DNSCryptCertificatePair
> DNSCryptContext::loadCertificatePair(const std::string
& certFile
, const std::string
& keyFile
)
323 auto pair
= std::make_shared
<DNSCryptCertificatePair
>();
324 loadCertFromFile(certFile
, pair
->cert
);
325 pair
->privateKey
.loadFromFile(keyFile
);
327 computePublicKeyFromPrivate(pair
->privateKey
, pair
->publicKey
);
331 void DNSCryptContext::loadNewCertificate(const std::string
& certFile
, const std::string
& keyFile
, bool active
, bool reload
)
333 auto newPair
= DNSCryptContext::loadCertificatePair(certFile
, keyFile
);
334 newPair
->active
= active
;
335 addNewCertificate(newPair
, reload
);
336 d_certKeyPaths
.push_back({certFile
, keyFile
});
339 void DNSCryptContext::reloadCertificates()
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
));
347 WriteLock
w(&d_lock
);
348 d_certs
= std::move(newCerts
);
352 void DNSCryptContext::markActive(uint32_t serial
)
354 WriteLock
w(&d_lock
);
356 for (auto pair
: d_certs
) {
357 if (pair
->active
== false && pair
->cert
.getSerial() == serial
) {
362 throw std::runtime_error("No inactive certificate found with this serial");
365 void DNSCryptContext::markInactive(uint32_t serial
)
367 WriteLock
w(&d_lock
);
369 for (auto pair
: d_certs
) {
370 if (pair
->active
== true && pair
->cert
.getSerial() == serial
) {
371 pair
->active
= false;
375 throw std::runtime_error("No active certificate found with this serial");
378 void DNSCryptContext::removeInactiveCertificate(uint32_t serial
)
380 WriteLock
w(&d_lock
);
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
);
390 throw std::runtime_error("No inactive certificate found with this serial");
393 bool DNSCryptQuery::parsePlaintextQuery(const char * packet
, uint16_t packetSize
)
395 assert(d_ctx
!= nullptr);
397 if (packetSize
< sizeof(dnsheader
)) {
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
)
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
)))
411 if (qtype
!= QType::TXT
|| qclass
!= QClass::IN
)
414 if (qname
!= d_ctx
->getProviderName())
424 void DNSCryptContext::getCertificateResponse(time_t now
, const DNSName
& qname
, uint16_t qid
, std::vector
<uint8_t>& response
)
426 DNSPacketWriter
pw(response
, qname
, QType::TXT
, QClass::IN
, Opcode::Query
);
427 struct dnsheader
* dh
= pw
.getHeader();
430 dh
->rcode
= RCode::NoError
;
433 for (const auto pair
: d_certs
) {
434 if (!pair
->active
|| !pair
->cert
.isValid(now
)) {
438 pw
.startRecord(qname
, QType::TXT
, (DNSCRYPT_CERTIFICATE_RESPONSE_TTL
), QClass::IN
, DNSResourceRecord::ANSWER
, true);
440 uint8_t certSize
= sizeof(pair
->cert
);
441 scert
.assign((const char*) &certSize
, sizeof(certSize
));
442 scert
.append((const char*) &pair
->cert
, certSize
);
449 bool DNSCryptContext::magicMatchesAPublicKey(DNSCryptQuery
& query
, time_t now
)
451 const unsigned char* magic
= query
.getClientMagic();
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
);
464 bool DNSCryptQuery::isEncryptedQuery(const char * packet
, uint16_t packetSize
, bool tcp
, time_t now
)
466 assert(d_ctx
!= nullptr);
470 if (packetSize
< sizeof(DNSCryptQueryHeader
)) {
474 if (!tcp
&& packetSize
< DNSCryptQuery::s_minUDPLength
) {
478 const struct DNSCryptQueryHeader
* header
= reinterpret_cast<const struct DNSCryptQueryHeader
*>(packet
);
482 if (!d_ctx
->magicMatchesAPublicKey(*this, now
)) {
491 void DNSCryptQuery::getDecrypted(bool tcp
, char* packet
, uint16_t packetSize
, uint16_t* decryptedQueryLen
)
493 assert(decryptedQueryLen
!= nullptr);
495 assert(d_pair
!= nullptr);
496 assert(d_valid
== false);
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
);
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");
510 memcpy(nonce
, &d_header
.clientNonce
, sizeof(d_header
.clientNonce
));
511 memset(nonce
+ sizeof(d_header
.clientNonce
), 0, sizeof(nonce
) - sizeof(d_header
.clientNonce
));
513 #ifdef HAVE_CRYPTO_BOX_EASY_AFTERNM
514 int res
= computeSharedKey();
516 vinfolog("Dropping encrypted query we can't compute the shared key for");
520 const DNSCryptExchangeVersion version
= getVersion();
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
),
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
),
536 #else /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */
538 #endif /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */
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
),
549 d_pair
->privateKey
.key
);
550 #endif /* HAVE_CRYPTO_BOX_EASY_AFTERNM */
553 vinfolog("Dropping encrypted query we can't decrypt");
557 *decryptedQueryLen
= packetSize
- sizeof(DNSCryptQueryHeader
) - DNSCRYPT_MAC_SIZE
;
558 uint16_t pos
= *decryptedQueryLen
;
559 assert(pos
< packetSize
);
560 d_paddedLen
= *decryptedQueryLen
;
562 while(pos
> 0 && packet
[pos
- 1] == 0) pos
--;
564 if (pos
== 0 || static_cast<uint8_t>(packet
[pos
- 1]) != 0x80) {
565 vinfolog("Dropping encrypted query with invalid padding value");
571 size_t paddingLen
= *decryptedQueryLen
- pos
;
572 *decryptedQueryLen
= pos
;
574 if (tcp
&& paddingLen
> DNSCRYPT_MAX_TCP_PADDING_SIZE
) {
575 vinfolog("Dropping encrypted query with too long padding size");
583 void DNSCryptQuery::getCertificateResponse(time_t now
, std::vector
<uint8_t>& response
) const
585 assert(d_ctx
!= nullptr);
586 d_ctx
->getCertificateResponse(now
, d_qname
, d_id
, response
);
589 void DNSCryptQuery::parsePacket(char* packet
, uint16_t packetSize
, bool tcp
, uint16_t* decryptedQueryLen
, time_t now
)
591 assert(packet
!= nullptr);
592 assert(decryptedQueryLen
!= nullptr);
596 /* might be a plaintext certificate request or an authenticated request */
597 if (isEncryptedQuery(packet
, packetSize
, tcp
, now
)) {
598 getDecrypted(tcp
, packet
, packetSize
, decryptedQueryLen
);
601 parsePlaintextQuery(packet
, packetSize
);
605 void DNSCryptQuery::fillServerNonce(unsigned char* nonce
) const
607 uint32_t* dest
= reinterpret_cast<uint32_t*>(nonce
);
608 static const size_t nonceSize
= DNSCRYPT_NONCE_SIZE
/ 2;
610 for (size_t pos
= 0; pos
< (nonceSize
/ sizeof(*dest
)); pos
++)
612 const uint32_t value
= randombytes_random();
613 memcpy(dest
+ pos
, &value
, sizeof(value
));
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."
621 uint16_t DNSCryptQuery::computePaddingSize(uint16_t unpaddedLen
, size_t maxLen
) const
623 size_t paddedSize
= 0;
626 assert(d_header
.clientNonce
);
627 assert(d_pair
!= nullptr);
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
);
634 paddedSize
= unpaddedLen
+ rnd
% (maxLen
- unpaddedLen
+ 1);
635 paddedSize
+= DNSCRYPT_PADDED_BLOCK_SIZE
- (paddedSize
% DNSCRYPT_PADDED_BLOCK_SIZE
);
637 if (paddedSize
> maxLen
)
640 result
= paddedSize
- unpaddedLen
;
645 int DNSCryptQuery::encryptResponse(char* response
, uint16_t responseLen
, uint16_t responseSize
, bool tcp
, uint16_t* encryptedResponseLen
)
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);
655 if (!tcp
&& d_paddedLen
< responseLen
) {
656 struct dnsheader
* dh
= reinterpret_cast<struct dnsheader
*>(response
);
657 size_t questionSize
= 0;
659 if (responseLen
> sizeof(dnsheader
)) {
660 unsigned int consumed
= 0;
661 DNSName
tempQName(response
, responseLen
, sizeof(dnsheader
), false, 0, 0, &consumed
);
663 questionSize
= consumed
+ DNS_TYPE_SIZE
+ DNS_CLASS_SIZE
;
667 responseLen
= sizeof(dnsheader
) + questionSize
;
669 if (responseLen
> d_paddedLen
) {
670 responseLen
= d_paddedLen
;
672 dh
->ancount
= dh
->arcount
= dh
->nscount
= 0;
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
;
681 if (requiredSize
> responseSize
)
684 memcpy(&responseHeader
.nonce
, &d_header
.clientNonce
, sizeof d_header
.clientNonce
);
685 fillServerNonce(&(responseHeader
.nonce
[sizeof(d_header
.clientNonce
)]));
687 /* moving the existing response after the header + MAC */
688 memmove(response
+ sizeof(responseHeader
) + DNSCRYPT_MAC_SIZE
, response
, responseLen
);
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 */
701 response
[pos
] = static_cast<uint8_t>(0x80);
703 memset(response
+ pos
, 0, paddingSize
- 1);
704 pos
+= (paddingSize
- 1);
707 #ifdef HAVE_CRYPTO_BOX_EASY_AFTERNM
708 int res
= computeSharedKey();
713 const DNSCryptExchangeVersion version
= getVersion();
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
,
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
,
729 #else /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */
731 #endif /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */
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
,
742 d_pair
->privateKey
.key
);
743 #endif /* HAVE_CRYPTO_BOX_EASY_AFTERNM */
746 assert(pos
== requiredSize
);
747 *encryptedResponseLen
= requiredSize
;
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
755 assert(query
!= nullptr);
756 assert(queryLen
> 0);
757 assert(querySize
>= queryLen
);
758 assert(encryptedResponseLen
!= nullptr);
759 assert(cert
!= nullptr);
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
;
768 if (!tcp
&& requiredSize
< DNSCryptQuery::s_minUDPLength
) {
769 paddingSize
+= (DNSCryptQuery::s_minUDPLength
- requiredSize
);
770 requiredSize
= DNSCryptQuery::s_minUDPLength
;
773 if (requiredSize
> querySize
)
776 /* moving the existing query after the header + MAC */
777 memmove(query
+ sizeof(DNSCryptQueryHeader
) + DNSCRYPT_MAC_SIZE
, query
, queryLen
);
781 memcpy(query
+ pos
, cert
->signedData
.clientMagic
, sizeof(cert
->signedData
.clientMagic
));
782 pos
+= sizeof(cert
->signedData
.clientMagic
);
785 memcpy(query
+ pos
, clientPublicKey
, DNSCRYPT_PUBLIC_KEY_SIZE
);
786 pos
+= DNSCRYPT_PUBLIC_KEY_SIZE
;
789 memcpy(query
+ pos
, clientNonce
, DNSCRYPT_NONCE_SIZE
/ 2);
790 pos
+= DNSCRYPT_NONCE_SIZE
/ 2;
791 size_t encryptedPos
= pos
;
793 /* clear the MAC bytes */
794 memset(query
+ pos
, 0, DNSCRYPT_MAC_SIZE
);
795 pos
+= DNSCRYPT_MAC_SIZE
;
801 query
[pos
] = static_cast<uint8_t>(0x80);
803 memset(query
+ pos
, 0, paddingSize
- 1);
804 pos
+= paddingSize
- 1;
806 memcpy(nonce
, clientNonce
, DNSCRYPT_NONCE_SIZE
/ 2);
807 memset(nonce
+ (DNSCRYPT_NONCE_SIZE
/ 2), 0, DNSCRYPT_NONCE_SIZE
/ 2);
809 const DNSCryptExchangeVersion version
= getExchangeVersion(*cert
);
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
,
817 cert
->signedData
.resolverPK
,
818 clientPrivateKey
.key
);
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
,
826 cert
->signedData
.resolverPK
,
827 clientPrivateKey
.key
);
828 #endif /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */
831 throw std::runtime_error("Unknown DNSCrypt exchange version");
835 assert(pos
== requiredSize
);
836 *encryptedResponseLen
= requiredSize
;
842 bool generateDNSCryptCertificate(const std::string
& providerPrivateKeyFile
, uint32_t serial
, time_t begin
, time_t end
, DNSCryptExchangeVersion version
, DNSCryptCert
& certOut
, DNSCryptPrivateKey
& keyOut
)
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
));
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
);
857 DNSCryptContext::generateCertificate(serial
, begin
, end
, version
, providerPrivateKey
, keyOut
, certOut
);
860 catch(const std::exception
& e
) {
864 sodium_memzero(providerPrivateKey
, sizeof(providerPrivateKey
));
865 sodium_munlock(providerPrivateKey
, sizeof(providerPrivateKey
));