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