]>
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 | ||
341d2553 | 402 | const struct dnsheader * dh = reinterpret_cast<const struct dnsheader *>(packet.data()); |
11e1e08b | 403 | if (dh->qr || ntohs(dh->qdcount) != 1 || dh->ancount != 0 || dh->nscount != 0 || dh->opcode != Opcode::Query) |
43234e76 | 404 | return false; |
11e1e08b | 405 | |
341d2553 | 406 | unsigned int qnameWireLength; |
11e1e08b | 407 | uint16_t qtype, qclass; |
341d2553 RG |
408 | DNSName qname(reinterpret_cast<const char*>(packet.data()), packet.size(), sizeof(dnsheader), false, &qtype, &qclass, &qnameWireLength); |
409 | if ((packet.size() - sizeof(dnsheader)) < (qnameWireLength + sizeof(qtype) + sizeof(qclass))) { | |
43234e76 | 410 | return false; |
341d2553 | 411 | } |
11e1e08b | 412 | |
341d2553 | 413 | if (qtype != QType::TXT || qclass != QClass::IN) { |
43234e76 | 414 | return false; |
341d2553 | 415 | } |
11e1e08b | 416 | |
341d2553 | 417 | if (qname != d_ctx->getProviderName()) { |
43234e76 | 418 | return false; |
341d2553 | 419 | } |
43234e76 RG |
420 | |
421 | d_qname = qname; | |
422 | d_id = dh->id; | |
423 | d_valid = true; | |
11e1e08b | 424 | |
43234e76 | 425 | return true; |
11e1e08b RG |
426 | } |
427 | ||
32fbb2ab | 428 | void DNSCryptContext::getCertificateResponse(time_t now, const DNSName& qname, uint16_t qid, PacketBuffer& response) |
11e1e08b | 429 | { |
32fbb2ab | 430 | GenericDNSPacketWriter<PacketBuffer> pw(response, qname, QType::TXT, QClass::IN, Opcode::Query); |
11e1e08b | 431 | struct dnsheader * dh = pw.getHeader(); |
43234e76 | 432 | dh->id = qid; |
11e1e08b RG |
433 | dh->qr = true; |
434 | dh->rcode = RCode::NoError; | |
11e1e08b | 435 | |
6c1813a0 RG |
436 | auto certs = d_certs.read_lock(); |
437 | for (const auto& pair : *certs) { | |
43234e76 RG |
438 | if (!pair->active || !pair->cert.isValid(now)) { |
439 | continue; | |
440 | } | |
11e1e08b | 441 | |
43234e76 RG |
442 | pw.startRecord(qname, QType::TXT, (DNSCRYPT_CERTIFICATE_RESPONSE_TTL), QClass::IN, DNSResourceRecord::ANSWER, true); |
443 | std::string scert; | |
444 | uint8_t certSize = sizeof(pair->cert); | |
445 | scert.assign((const char*) &certSize, sizeof(certSize)); | |
446 | scert.append((const char*) &pair->cert, certSize); | |
11e1e08b | 447 | |
43234e76 RG |
448 | pw.xfrBlob(scert); |
449 | pw.commit(); | |
11e1e08b | 450 | } |
43234e76 | 451 | } |
11e1e08b | 452 | |
43234e76 RG |
453 | bool DNSCryptContext::magicMatchesAPublicKey(DNSCryptQuery& query, time_t now) |
454 | { | |
455 | const unsigned char* magic = query.getClientMagic(); | |
456 | ||
6c1813a0 RG |
457 | auto certs = d_certs.read_lock(); |
458 | for (const auto& pair : *certs) { | |
43234e76 RG |
459 | if (pair->cert.isValid(now) && memcmp(magic, pair->cert.signedData.clientMagic, DNSCRYPT_CLIENT_MAGIC_SIZE) == 0) { |
460 | query.setCertificatePair(pair); | |
461 | return true; | |
462 | } | |
11e1e08b RG |
463 | } |
464 | ||
465 | return false; | |
466 | } | |
467 | ||
32fbb2ab | 468 | bool DNSCryptQuery::isEncryptedQuery(const PacketBuffer& packet, bool tcp, time_t now) |
11e1e08b | 469 | { |
43234e76 | 470 | assert(d_ctx != nullptr); |
11e1e08b | 471 | |
43234e76 RG |
472 | d_encrypted = false; |
473 | ||
341d2553 | 474 | if (packet.size() < sizeof(DNSCryptQueryHeader)) { |
43234e76 | 475 | return false; |
11e1e08b RG |
476 | } |
477 | ||
341d2553 | 478 | if (!tcp && packet.size() < DNSCryptQuery::s_minUDPLength) { |
43234e76 | 479 | return false; |
11e1e08b RG |
480 | } |
481 | ||
341d2553 | 482 | const struct DNSCryptQueryHeader* header = reinterpret_cast<const struct DNSCryptQueryHeader*>(packet.data()); |
11e1e08b | 483 | |
43234e76 | 484 | d_header = *header; |
11e1e08b | 485 | |
43234e76 RG |
486 | if (!d_ctx->magicMatchesAPublicKey(*this, now)) { |
487 | return false; | |
11e1e08b RG |
488 | } |
489 | ||
43234e76 RG |
490 | d_encrypted = true; |
491 | ||
492 | return true; | |
11e1e08b RG |
493 | } |
494 | ||
32fbb2ab | 495 | void DNSCryptQuery::getDecrypted(bool tcp, PacketBuffer& packet) |
11e1e08b | 496 | { |
43234e76 RG |
497 | assert(d_encrypted); |
498 | assert(d_pair != nullptr); | |
499 | assert(d_valid == false); | |
11e1e08b RG |
500 | |
501 | #ifdef DNSCRYPT_STRICT_PADDING_LENGTH | |
341d2553 RG |
502 | if (tcp && ((packet.size() - sizeof(DNSCryptQueryHeader)) % DNSCRYPT_PADDED_BLOCK_SIZE) != 0) { |
503 | 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 |
504 | return; |
505 | } | |
506 | #endif | |
507 | ||
508 | unsigned char nonce[DNSCRYPT_NONCE_SIZE]; | |
43234e76 | 509 | static_assert(sizeof(nonce) == (2* sizeof(d_header.clientNonce)), "Nonce should be larger than clientNonce (half)"); |
ef2ea4bf | 510 | static_assert(sizeof(d_header.clientPK) == DNSCRYPT_PUBLIC_KEY_SIZE, "Client Public key size is not right"); |
43234e76 | 511 | static_assert(sizeof(d_pair->privateKey.key) == DNSCRYPT_PRIVATE_KEY_SIZE, "Private key size is not right"); |
11e1e08b | 512 | |
43234e76 RG |
513 | memcpy(nonce, &d_header.clientNonce, sizeof(d_header.clientNonce)); |
514 | memset(nonce + sizeof(d_header.clientNonce), 0, sizeof(nonce) - sizeof(d_header.clientNonce)); | |
11e1e08b | 515 | |
00ffb1c2 | 516 | #ifdef HAVE_CRYPTO_BOX_EASY_AFTERNM |
43234e76 | 517 | int res = computeSharedKey(); |
8089cbe5 RG |
518 | if (res != 0) { |
519 | vinfolog("Dropping encrypted query we can't compute the shared key for"); | |
520 | return; | |
332fdc5f RG |
521 | } |
522 | ||
43234e76 RG |
523 | const DNSCryptExchangeVersion version = getVersion(); |
524 | ||
525 | if (version == DNSCryptExchangeVersion::VERSION1) { | |
341d2553 RG |
526 | res = crypto_box_open_easy_afternm(reinterpret_cast<unsigned char*>(packet.data()), |
527 | reinterpret_cast<unsigned char*>(&packet.at(sizeof(DNSCryptQueryHeader))), | |
528 | packet.size() - sizeof(DNSCryptQueryHeader), | |
43234e76 RG |
529 | nonce, |
530 | d_sharedKey); | |
531 | } | |
532 | else if (version == DNSCryptExchangeVersion::VERSION2) { | |
533 | #ifdef HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY | |
341d2553 RG |
534 | res = crypto_box_curve25519xchacha20poly1305_open_easy_afternm(reinterpret_cast<unsigned char*>(packet.data()), |
535 | reinterpret_cast<unsigned char*>(&packet.at(sizeof(DNSCryptQueryHeader))), | |
536 | packet.size() - sizeof(DNSCryptQueryHeader), | |
43234e76 RG |
537 | nonce, |
538 | d_sharedKey); | |
539 | #else /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */ | |
540 | res = -1; | |
541 | #endif /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */ | |
542 | } else { | |
543 | res = -1; | |
544 | } | |
545 | ||
546 | #else /* HAVE_CRYPTO_BOX_EASY_AFTERNM */ | |
341d2553 RG |
547 | int res = crypto_box_open_easy(reinterpret_cast<unsigned char*>(packet.data()), |
548 | reinterpret_cast<unsigned char*>(&packet.at(sizeof(DNSCryptQueryHeader))), | |
549 | packet.size() - sizeof(DNSCryptQueryHeader), | |
00ffb1c2 | 550 | nonce, |
43234e76 RG |
551 | d_header.clientPK, |
552 | d_pair->privateKey.key); | |
00ffb1c2 | 553 | #endif /* HAVE_CRYPTO_BOX_EASY_AFTERNM */ |
11e1e08b RG |
554 | |
555 | if (res != 0) { | |
556 | vinfolog("Dropping encrypted query we can't decrypt"); | |
557 | return; | |
558 | } | |
559 | ||
341d2553 RG |
560 | uint16_t decryptedQueryLen = packet.size() - sizeof(DNSCryptQueryHeader) - DNSCRYPT_MAC_SIZE; |
561 | uint16_t pos = decryptedQueryLen; | |
562 | assert(pos < packet.size()); | |
563 | d_paddedLen = decryptedQueryLen; | |
11e1e08b | 564 | |
341d2553 | 565 | while (pos > 0 && packet.at(pos - 1) == 0) pos--; |
11e1e08b | 566 | |
341d2553 | 567 | if (pos == 0 || packet.at(pos - 1) != 0x80) { |
11e1e08b RG |
568 | vinfolog("Dropping encrypted query with invalid padding value"); |
569 | return; | |
570 | } | |
571 | ||
572 | pos--; | |
573 | ||
341d2553 RG |
574 | size_t paddingLen = decryptedQueryLen - pos; |
575 | packet.resize(pos); | |
11e1e08b RG |
576 | |
577 | if (tcp && paddingLen > DNSCRYPT_MAX_TCP_PADDING_SIZE) { | |
578 | vinfolog("Dropping encrypted query with too long padding size"); | |
579 | return; | |
580 | } | |
581 | ||
43234e76 RG |
582 | d_len = pos; |
583 | d_valid = true; | |
584 | } | |
11e1e08b | 585 | |
32fbb2ab | 586 | void DNSCryptQuery::getCertificateResponse(time_t now, PacketBuffer& response) const |
43234e76 RG |
587 | { |
588 | assert(d_ctx != nullptr); | |
589 | d_ctx->getCertificateResponse(now, d_qname, d_id, response); | |
11e1e08b RG |
590 | } |
591 | ||
32fbb2ab | 592 | void DNSCryptQuery::parsePacket(PacketBuffer& packet, bool tcp, time_t now) |
11e1e08b | 593 | { |
43234e76 | 594 | d_valid = false; |
11e1e08b RG |
595 | |
596 | /* might be a plaintext certificate request or an authenticated request */ | |
341d2553 RG |
597 | if (isEncryptedQuery(packet, tcp, now)) { |
598 | getDecrypted(tcp, packet); | |
11e1e08b RG |
599 | } |
600 | else { | |
341d2553 | 601 | parsePlaintextQuery(packet); |
11e1e08b RG |
602 | } |
603 | } | |
604 | ||
43234e76 | 605 | void DNSCryptQuery::fillServerNonce(unsigned char* nonce) const |
11e1e08b | 606 | { |
43234e76 | 607 | uint32_t* dest = reinterpret_cast<uint32_t*>(nonce); |
11e1e08b RG |
608 | static const size_t nonceSize = DNSCRYPT_NONCE_SIZE / 2; |
609 | ||
610 | for (size_t pos = 0; pos < (nonceSize / sizeof(*dest)); pos++) | |
611 | { | |
612 | const uint32_t value = randombytes_random(); | |
613 | memcpy(dest + pos, &value, sizeof(value)); | |
614 | } | |
615 | } | |
616 | ||
617 | /* | |
618 | "The length of <resolver-response-pad> must be between 0 and 256 bytes, | |
619 | and must be constant for a given (<resolver-sk>, <client-nonce>) tuple." | |
620 | */ | |
43234e76 | 621 | uint16_t DNSCryptQuery::computePaddingSize(uint16_t unpaddedLen, size_t maxLen) const |
11e1e08b | 622 | { |
43234e76 | 623 | size_t paddedSize = 0; |
11e1e08b RG |
624 | uint16_t result = 0; |
625 | uint32_t rnd = 0; | |
43234e76 RG |
626 | assert(d_header.clientNonce); |
627 | assert(d_pair != nullptr); | |
628 | ||
11e1e08b | 629 | unsigned char nonce[DNSCRYPT_NONCE_SIZE]; |
43234e76 RG |
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); | |
11e1e08b | 633 | |
43234e76 RG |
634 | paddedSize = unpaddedLen + rnd % (maxLen - unpaddedLen + 1); |
635 | paddedSize += DNSCRYPT_PADDED_BLOCK_SIZE - (paddedSize % DNSCRYPT_PADDED_BLOCK_SIZE); | |
11e1e08b | 636 | |
43234e76 RG |
637 | if (paddedSize > maxLen) |
638 | paddedSize = maxLen; | |
11e1e08b | 639 | |
43234e76 | 640 | result = paddedSize - unpaddedLen; |
11e1e08b RG |
641 | |
642 | return result; | |
643 | } | |
644 | ||
32fbb2ab | 645 | int DNSCryptQuery::encryptResponse(PacketBuffer& response, size_t maxResponseSize, bool tcp) |
11e1e08b | 646 | { |
43234e76 | 647 | struct DNSCryptResponseHeader responseHeader; |
341d2553 RG |
648 | assert(response.size() > 0); |
649 | assert(maxResponseSize >= response.size()); | |
43234e76 RG |
650 | assert(d_encrypted == true); |
651 | assert(d_pair != nullptr); | |
11e1e08b | 652 | |
341d2553 RG |
653 | /* a DNSCrypt UDP response can't be larger than the (padded) DNSCrypt query */ |
654 | if (!tcp && d_paddedLen < response.size()) { | |
655 | /* so we need to truncate it */ | |
bd64cc44 RG |
656 | size_t questionSize = 0; |
657 | ||
341d2553 RG |
658 | if (response.size() > sizeof(dnsheader)) { |
659 | unsigned int qnameWireLength = 0; | |
660 | DNSName tempQName(reinterpret_cast<const char*>(response.data()), response.size(), sizeof(dnsheader), false, 0, 0, &qnameWireLength); | |
661 | if (qnameWireLength > 0) { | |
662 | questionSize = qnameWireLength + DNS_TYPE_SIZE + DNS_CLASS_SIZE; | |
bd64cc44 RG |
663 | } |
664 | } | |
665 | ||
341d2553 | 666 | response.resize(sizeof(dnsheader) + questionSize); |
bd64cc44 | 667 | |
341d2553 RG |
668 | if (response.size() > d_paddedLen) { |
669 | /* that does not seem right but let's truncate even more */ | |
670 | response.resize(d_paddedLen); | |
bd64cc44 | 671 | } |
341d2553 | 672 | struct dnsheader* dh = reinterpret_cast<struct dnsheader*>(response.data()); |
bd64cc44 | 673 | dh->ancount = dh->arcount = dh->nscount = 0; |
11e1e08b RG |
674 | dh->tc = 1; |
675 | } | |
676 | ||
341d2553 RG |
677 | size_t requiredSize = sizeof(responseHeader) + DNSCRYPT_MAC_SIZE + response.size(); |
678 | size_t maxSize = std::min(maxResponseSize, requiredSize + DNSCRYPT_MAX_RESPONSE_PADDING_SIZE); | |
43234e76 | 679 | uint16_t paddingSize = computePaddingSize(requiredSize, maxSize); |
11e1e08b RG |
680 | requiredSize += paddingSize; |
681 | ||
341d2553 | 682 | if (requiredSize > maxResponseSize) { |
11e1e08b | 683 | return ENOBUFS; |
341d2553 | 684 | } |
11e1e08b | 685 | |
43234e76 RG |
686 | memcpy(&responseHeader.nonce, &d_header.clientNonce, sizeof d_header.clientNonce); |
687 | fillServerNonce(&(responseHeader.nonce[sizeof(d_header.clientNonce)])); | |
11e1e08b | 688 | |
341d2553 | 689 | size_t responseLen = response.size(); |
11e1e08b | 690 | /* moving the existing response after the header + MAC */ |
341d2553 RG |
691 | response.resize(requiredSize); |
692 | std::copy_backward(response.begin(), response.begin() + responseLen, response.begin() + responseLen + sizeof(responseHeader) + DNSCRYPT_MAC_SIZE); | |
11e1e08b RG |
693 | |
694 | uint16_t pos = 0; | |
695 | /* copying header */ | |
341d2553 | 696 | memcpy(&response.at(pos), &responseHeader, sizeof(responseHeader)); |
43234e76 | 697 | pos += sizeof(responseHeader); |
11e1e08b | 698 | /* setting MAC bytes to 0 */ |
341d2553 | 699 | memset(&response.at(pos), 0, DNSCRYPT_MAC_SIZE); |
11e1e08b RG |
700 | pos += DNSCRYPT_MAC_SIZE; |
701 | uint16_t toEncryptPos = pos; | |
702 | /* skipping response */ | |
703 | pos += responseLen; | |
704 | /* padding */ | |
341d2553 | 705 | response.at(pos) = static_cast<uint8_t>(0x80); |
11e1e08b | 706 | pos++; |
341d2553 | 707 | memset(&response.at(pos), 0, paddingSize - 1); |
11e1e08b | 708 | pos += (paddingSize - 1); |
332fdc5f | 709 | |
11e1e08b | 710 | /* encrypting */ |
00ffb1c2 | 711 | #ifdef HAVE_CRYPTO_BOX_EASY_AFTERNM |
43234e76 | 712 | int res = computeSharedKey(); |
8089cbe5 RG |
713 | if (res != 0) { |
714 | return res; | |
332fdc5f RG |
715 | } |
716 | ||
43234e76 RG |
717 | const DNSCryptExchangeVersion version = getVersion(); |
718 | ||
719 | if (version == DNSCryptExchangeVersion::VERSION1) { | |
341d2553 RG |
720 | res = crypto_box_easy_afternm(reinterpret_cast<unsigned char*>(&response.at(sizeof(responseHeader))), |
721 | reinterpret_cast<unsigned char*>(&response.at(toEncryptPos)), | |
43234e76 RG |
722 | responseLen + paddingSize, |
723 | responseHeader.nonce, | |
724 | d_sharedKey); | |
725 | } | |
726 | else if (version == DNSCryptExchangeVersion::VERSION2) { | |
727 | #ifdef HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY | |
341d2553 RG |
728 | res = crypto_box_curve25519xchacha20poly1305_easy_afternm(reinterpret_cast<unsigned char*>(&response.at(sizeof(responseHeader))), |
729 | reinterpret_cast<unsigned char*>(&response.at(toEncryptPos)), | |
43234e76 RG |
730 | responseLen + paddingSize, |
731 | responseHeader.nonce, | |
732 | d_sharedKey); | |
733 | #else /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */ | |
734 | res = -1; | |
735 | #endif /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */ | |
736 | } | |
737 | else { | |
738 | res = -1; | |
739 | } | |
00ffb1c2 | 740 | #else |
341d2553 RG |
741 | int res = crypto_box_easy(reinterpret_cast<unsigned char*>(&response.at(sizeof(responseHeader))), |
742 | reinterpret_cast<unsigned char*>(&response.at(toEncryptPos)), | |
00ffb1c2 | 743 | responseLen + paddingSize, |
43234e76 RG |
744 | responseHeader.nonce, |
745 | d_header.clientPK, | |
746 | d_pair->privateKey.key); | |
00ffb1c2 | 747 | #endif /* HAVE_CRYPTO_BOX_EASY_AFTERNM */ |
11e1e08b RG |
748 | |
749 | if (res == 0) { | |
750 | assert(pos == requiredSize); | |
11e1e08b RG |
751 | } |
752 | ||
753 | return res; | |
754 | } | |
755 | ||
32fbb2ab | 756 | 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 | 757 | { |
341d2553 | 758 | assert(packet.size() > 0); |
43234e76 RG |
759 | assert(cert != nullptr); |
760 | ||
341d2553 | 761 | size_t queryLen = packet.size(); |
11e1e08b | 762 | unsigned char nonce[DNSCRYPT_NONCE_SIZE]; |
43234e76 | 763 | size_t requiredSize = sizeof(DNSCryptQueryHeader) + DNSCRYPT_MAC_SIZE + queryLen; |
11e1e08b RG |
764 | /* this is not optimal, we should compute a random padding size, multiple of DNSCRYPT_PADDED_BLOCK_SIZE, |
765 | DNSCRYPT_PADDED_BLOCK_SIZE <= padding size <= 4096? */ | |
766 | uint16_t paddingSize = DNSCRYPT_PADDED_BLOCK_SIZE - (queryLen % DNSCRYPT_PADDED_BLOCK_SIZE); | |
767 | requiredSize += paddingSize; | |
768 | ||
43234e76 RG |
769 | if (!tcp && requiredSize < DNSCryptQuery::s_minUDPLength) { |
770 | paddingSize += (DNSCryptQuery::s_minUDPLength - requiredSize); | |
771 | requiredSize = DNSCryptQuery::s_minUDPLength; | |
11e1e08b RG |
772 | } |
773 | ||
341d2553 | 774 | if (requiredSize > maximumSize) { |
11e1e08b | 775 | return ENOBUFS; |
341d2553 | 776 | } |
11e1e08b RG |
777 | |
778 | /* moving the existing query after the header + MAC */ | |
341d2553 RG |
779 | packet.resize(requiredSize); |
780 | std::copy_backward(packet.begin(), packet.begin() + queryLen, packet.begin() + queryLen + sizeof(DNSCryptQueryHeader) + DNSCRYPT_MAC_SIZE); | |
11e1e08b RG |
781 | |
782 | size_t pos = 0; | |
783 | /* client magic */ | |
341d2553 | 784 | memcpy(&packet.at(pos), cert->signedData.clientMagic, sizeof(cert->signedData.clientMagic)); |
43234e76 | 785 | pos += sizeof(cert->signedData.clientMagic); |
11e1e08b RG |
786 | |
787 | /* client PK */ | |
341d2553 | 788 | memcpy(&packet.at(pos), clientPublicKey, DNSCRYPT_PUBLIC_KEY_SIZE); |
11e1e08b RG |
789 | pos += DNSCRYPT_PUBLIC_KEY_SIZE; |
790 | ||
791 | /* client nonce */ | |
341d2553 | 792 | memcpy(&packet.at(pos), clientNonce, DNSCRYPT_NONCE_SIZE / 2); |
11e1e08b RG |
793 | pos += DNSCRYPT_NONCE_SIZE / 2; |
794 | size_t encryptedPos = pos; | |
795 | ||
796 | /* clear the MAC bytes */ | |
341d2553 | 797 | memset(&packet.at(pos), 0, DNSCRYPT_MAC_SIZE); |
11e1e08b RG |
798 | pos += DNSCRYPT_MAC_SIZE; |
799 | ||
800 | /* skipping data */ | |
801 | pos += queryLen; | |
802 | ||
803 | /* padding */ | |
341d2553 | 804 | packet.at(pos) = static_cast<uint8_t>(0x80); |
11e1e08b | 805 | pos++; |
341d2553 | 806 | memset(&packet.at(pos), 0, paddingSize - 1); |
11e1e08b RG |
807 | pos += paddingSize - 1; |
808 | ||
809 | memcpy(nonce, clientNonce, DNSCRYPT_NONCE_SIZE / 2); | |
810 | memset(nonce + (DNSCRYPT_NONCE_SIZE / 2), 0, DNSCRYPT_NONCE_SIZE / 2); | |
811 | ||
43234e76 RG |
812 | const DNSCryptExchangeVersion version = getExchangeVersion(*cert); |
813 | int res = -1; | |
814 | ||
815 | if (version == DNSCryptExchangeVersion::VERSION1) { | |
341d2553 RG |
816 | res = crypto_box_easy(reinterpret_cast<unsigned char*>(&packet.at(encryptedPos)), |
817 | reinterpret_cast<unsigned char*>(&packet.at(encryptedPos + DNSCRYPT_MAC_SIZE)), | |
43234e76 RG |
818 | queryLen + paddingSize, |
819 | nonce, | |
820 | cert->signedData.resolverPK, | |
821 | clientPrivateKey.key); | |
822 | } | |
823 | else if (version == DNSCryptExchangeVersion::VERSION2) { | |
824 | #ifdef HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY | |
341d2553 RG |
825 | res = crypto_box_curve25519xchacha20poly1305_easy(reinterpret_cast<unsigned char*>(&packet.at(encryptedPos)), |
826 | reinterpret_cast<unsigned char*>(&packet.at(encryptedPos + DNSCRYPT_MAC_SIZE)), | |
43234e76 RG |
827 | queryLen + paddingSize, |
828 | nonce, | |
829 | cert->signedData.resolverPK, | |
830 | clientPrivateKey.key); | |
831 | #endif /* HAVE_CRYPTO_BOX_CURVE25519XCHACHA20POLY1305_EASY */ | |
832 | } | |
833 | else { | |
834 | throw std::runtime_error("Unknown DNSCrypt exchange version"); | |
835 | } | |
11e1e08b RG |
836 | |
837 | if (res == 0) { | |
838 | assert(pos == requiredSize); | |
11e1e08b RG |
839 | } |
840 | ||
841 | return res; | |
842 | } | |
843 | ||
43234e76 | 844 | bool generateDNSCryptCertificate(const std::string& providerPrivateKeyFile, uint32_t serial, time_t begin, time_t end, DNSCryptExchangeVersion version, DNSCryptCert& certOut, DNSCryptPrivateKey& keyOut) |
6bb38cd6 RG |
845 | { |
846 | bool success = false; | |
847 | unsigned char providerPrivateKey[DNSCRYPT_PROVIDER_PRIVATE_KEY_SIZE]; | |
848 | sodium_mlock(providerPrivateKey, sizeof(providerPrivateKey)); | |
849 | sodium_memzero(providerPrivateKey, sizeof(providerPrivateKey)); | |
850 | ||
851 | try { | |
852 | ifstream providerKStream(providerPrivateKeyFile); | |
853 | providerKStream.read((char*) providerPrivateKey, sizeof(providerPrivateKey)); | |
854 | if (providerKStream.fail()) { | |
855 | providerKStream.close(); | |
856 | throw std::runtime_error("Invalid DNSCrypt provider key file " + providerPrivateKeyFile); | |
857 | } | |
858 | ||
43234e76 | 859 | DNSCryptContext::generateCertificate(serial, begin, end, version, providerPrivateKey, keyOut, certOut); |
6bb38cd6 RG |
860 | success = true; |
861 | } | |
862 | catch(const std::exception& e) { | |
863 | errlog(e.what()); | |
864 | } | |
865 | ||
866 | sodium_memzero(providerPrivateKey, sizeof(providerPrivateKey)); | |
867 | sodium_munlock(providerPrivateKey, sizeof(providerPrivateKey)); | |
868 | return success; | |
869 | } | |
870 | ||
11e1e08b | 871 | #endif |