}
#endif /* HAVE_CRYPTO_BOX_EASY_AFTERNM */
-DNSCryptContext::DNSCryptContext(const std::string& pName, const std::string& certFile, const std::string& keyFile): providerName(pName)
+DNSCryptContext::DNSCryptContext(const std::string& pName, const std::vector<CertKeyPaths>& certKeys): d_certKeyPaths(certKeys), providerName(pName)
{
pthread_rwlock_init(&d_lock, 0);
- loadNewCertificate(certFile, keyFile);
+ reloadCertificates();
}
DNSCryptContext::DNSCryptContext(const std::string& pName, const DNSCryptCert& certificate, const DNSCryptPrivateKey& pKey): providerName(pName)
return string(buf);
}
-void DNSCryptContext::addNewCertificate(const DNSCryptCert& newCert, const DNSCryptPrivateKey& newKey, bool active, bool reload)
+void DNSCryptContext::addNewCertificate(std::shared_ptr<DNSCryptCertificatePair>& newCert, bool reload)
{
WriteLock w(&d_lock);
- for (auto pair : certs) {
- if (pair->cert.getSerial() == newCert.getSerial()) {
+ for (auto pair : d_certs) {
+ if (pair->cert.getSerial() == newCert->cert.getSerial()) {
if (reload) {
/* on reload we just assume that this is the same certificate */
return;
}
}
+ d_certs.push_back(newCert);
+}
+
+void DNSCryptContext::addNewCertificate(const DNSCryptCert& newCert, const DNSCryptPrivateKey& newKey, bool active, bool reload)
+{
auto pair = std::make_shared<DNSCryptCertificatePair>();
pair->cert = newCert;
pair->privateKey = newKey;
computePublicKeyFromPrivate(pair->privateKey, pair->publicKey);
pair->active = active;
- certs.push_back(pair);
+
+ addNewCertificate(pair, reload);
}
-void DNSCryptContext::loadNewCertificate(const std::string& certFile, const std::string& keyFile, bool active, bool reload)
+std::shared_ptr<DNSCryptCertificatePair> DNSCryptContext::loadCertificatePair(const std::string& certFile, const std::string& keyFile)
{
- DNSCryptCert newCert;
- DNSCryptPrivateKey newPrivateKey;
-
- loadCertFromFile(certFile, newCert);
- newPrivateKey.loadFromFile(keyFile);
+ auto pair = std::make_shared<DNSCryptCertificatePair>();
+ loadCertFromFile(certFile, pair->cert);
+ pair->privateKey.loadFromFile(keyFile);
+ pair->active = true;
+ computePublicKeyFromPrivate(pair->privateKey, pair->publicKey);
+ return pair;
+}
- addNewCertificate(newCert, newPrivateKey, active, reload);
- certificatePath = certFile;
- keyPath = keyFile;
+void DNSCryptContext::loadNewCertificate(const std::string& certFile, const std::string& keyFile, bool active, bool reload)
+{
+ auto newPair = DNSCryptContext::loadCertificatePair(certFile, keyFile);
+ newPair->active = active;
+ addNewCertificate(newPair, reload);
+ d_certKeyPaths.push_back({certFile, keyFile});
}
-void DNSCryptContext::reloadCertificate()
+void DNSCryptContext::reloadCertificates()
{
- loadNewCertificate(certificatePath, keyPath, true, true);
+ std::vector<std::shared_ptr<DNSCryptCertificatePair>> newCerts;
+ for (const auto& pair : d_certKeyPaths) {
+ newCerts.push_back(DNSCryptContext::loadCertificatePair(pair.cert, pair.key));
+ }
+
+ {
+ WriteLock w(&d_lock);
+ d_certs = std::move(newCerts);
+ }
}
void DNSCryptContext::markActive(uint32_t serial)
{
WriteLock w(&d_lock);
- for (auto pair : certs) {
+ for (auto pair : d_certs) {
if (pair->active == false && pair->cert.getSerial() == serial) {
pair->active = true;
return;
{
WriteLock w(&d_lock);
- for (auto pair : certs) {
+ for (auto pair : d_certs) {
if (pair->active == true && pair->cert.getSerial() == serial) {
pair->active = false;
return;
{
WriteLock w(&d_lock);
- for (auto it = certs.begin(); it != certs.end(); ) {
+ for (auto it = d_certs.begin(); it != d_certs.end(); ) {
if ((*it)->active == false && (*it)->cert.getSerial() == serial) {
- it = certs.erase(it);
+ it = d_certs.erase(it);
return;
} else {
it++;
dh->rcode = RCode::NoError;
ReadLock r(&d_lock);
- for (const auto pair : certs) {
+ for (const auto pair : d_certs) {
if (!pair->active || !pair->cert.isValid(now)) {
continue;
}
const unsigned char* magic = query.getClientMagic();
ReadLock r(&d_lock);
- for (const auto& pair : certs) {
+ for (const auto& pair : d_certs) {
if (pair->cert.isValid(now) && memcmp(magic, pair->cert.signedData.clientMagic, DNSCRYPT_CLIENT_MAGIC_SIZE) == 0) {
query.setCertificatePair(pair);
return true;
static DNSCryptExchangeVersion getExchangeVersion(const unsigned char esVersion[sizeof(DNSCryptCert::esVersion)]);
static DNSCryptExchangeVersion getExchangeVersion(const DNSCryptCert& cert);
- DNSCryptContext(const std::string& pName, const std::string& certFile, const std::string& keyFile);
+ struct CertKeyPaths
+ {
+ std::string cert;
+ std::string key;
+ };
+
+ DNSCryptContext(const std::string& pName, const std::vector<CertKeyPaths>& certKeys);
DNSCryptContext(const std::string& pName, const DNSCryptCert& certificate, const DNSCryptPrivateKey& pKey);
- void reloadCertificate();
+ void reloadCertificates();
void loadNewCertificate(const std::string& certFile, const std::string& keyFile, bool active=true, bool reload=false);
void addNewCertificate(const DNSCryptCert& newCert, const DNSCryptPrivateKey& newKey, bool active=true, bool reload=false);
+
void markActive(uint32_t serial);
void markInactive(uint32_t serial);
void removeInactiveCertificate(uint32_t serial);
- std::vector<std::shared_ptr<DNSCryptCertificatePair>> getCertificates() { return certs; };
+ std::vector<std::shared_ptr<DNSCryptCertificatePair>> getCertificates() { return d_certs; };
const DNSName& getProviderName() const { return providerName; }
int 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;
private:
static void computePublicKeyFromPrivate(const DNSCryptPrivateKey& privK, unsigned char pubK[DNSCRYPT_PUBLIC_KEY_SIZE]);
static void loadCertFromFile(const std::string&filename, DNSCryptCert& dest);
+ static std::shared_ptr<DNSCryptCertificatePair> loadCertificatePair(const std::string& certFile, const std::string& keyFile);
+
+ void addNewCertificate(std::shared_ptr<DNSCryptCertificatePair>& newCert, bool reload=false);
pthread_rwlock_t d_lock;
- std::vector<std::shared_ptr<DNSCryptCertificatePair>> certs;
+ std::vector<std::shared_ptr<DNSCryptCertificatePair>> d_certs;
+ std::vector<CertKeyPaths> d_certKeyPaths;
DNSName providerName;
- std::string certificatePath;
- std::string keyPath;
};
bool generateDNSCryptCertificate(const std::string& providerPrivateKeyFile, uint32_t serial, time_t begin, time_t end, DNSCryptExchangeVersion version, DNSCryptCert& certOut, DNSCryptPrivateKey& keyOut);
if (ctx != nullptr) {
size_t idx = 1;
- boost::format fmt("%1$-3d %|5t|%2$-8d %|10t|%3$-2d %|20t|%4$-21.21s %|41t|%5$-21.21s");
+ boost::format fmt("%1$-3d %|5t|%2$-8d %|10t|%3$-7d %|20t|%4$-21.21s %|41t|%5$-21.21s");
ret << (fmt % "#" % "Serial" % "Version" % "From" % "To" ) << endl;
for (auto pair : ctx->getCertificates()) {
}
});
- g_lua.writeFunction("addDNSCryptBind", [](const std::string& addr, const std::string& providerName, const std::string& certFile, const std::string keyFile, boost::optional<localbind_t> vars) {
+ g_lua.writeFunction("addDNSCryptBind", [](const std::string& addr, const std::string& providerName, boost::variant<std::string, std::vector<std::pair<int, std::string>>> certFiles, boost::variant<std::string, std::vector<std::pair<int, std::string>>> keyFiles, boost::optional<localbind_t> vars) {
if (g_configurationDone) {
g_outputBuffer="addDNSCryptBind cannot be used at runtime!\n";
return;
int tcpFastOpenQueueSize = 0;
std::string interface;
std::set<int> cpus;
+ std::vector<DNSCryptContext::CertKeyPaths> certKeys;
parseLocalBindVars(vars, reusePort, tcpFastOpenQueueSize, interface, cpus);
+ if (certFiles.type() == typeid(std::string) && keyFiles.type() == typeid(std::string)) {
+ auto certFile = boost::get<std::string>(certFiles);
+ auto keyFile = boost::get<std::string>(keyFiles);
+ certKeys.push_back({certFile, keyFile});
+ }
+ else if (certFiles.type() == typeid(std::vector<std::pair<int,std::string>>) && keyFiles.type() == typeid(std::vector<std::pair<int,std::string>>)) {
+ auto certFilesVect = boost::get<std::vector<std::pair<int,std::string>>>(certFiles);
+ auto keyFilesVect = boost::get<std::vector<std::pair<int,std::string>>>(keyFiles);
+ if (certFilesVect.size() == keyFilesVect.size()) {
+ for (size_t idx = 0; idx < certFilesVect.size(); idx++) {
+ certKeys.push_back({certFilesVect.at(idx).second, keyFilesVect.at(idx).second});
+ }
+ }
+ else {
+ errlog("Error, mismatching number of certificates and keys in call to addDNSCryptBind!");
+ g_outputBuffer="Error, mismatching number of certificates and keys in call to addDNSCryptBind()!";
+ return;
+ }
+ }
+ else {
+ errlog("Error, mismatching number of certificates and keys in call to addDNSCryptBind()!");
+ g_outputBuffer="Error, mismatching number of certificates and keys in call to addDNSCryptBind()!";
+ return;
+ }
+
try {
- auto ctx = std::make_shared<DNSCryptContext>(providerName, certFile, keyFile);
+ auto ctx = std::make_shared<DNSCryptContext>(providerName, certKeys);
/* UDP */
auto cs = std::unique_ptr<ClientState>(new ClientState(ComboAddress(addr, 443), false, reusePort, tcpFastOpenQueueSize, interface, cpus));
try {
#ifdef HAVE_DNSCRYPT
if (frontend->dnscryptCtx) {
- frontend->dnscryptCtx->reloadCertificate();
+ frontend->dnscryptCtx->reloadCertificates();
}
#endif /* HAVE_DNSCRYPT */
#ifdef HAVE_DNS_OVER_TLS
DNSCrypt objects and functions
==============================
-.. function:: addDNSCryptBind(address, provider, certificate, keyfile[, options])
+.. function:: addDNSCryptBind(address, provider, certFile(s), keyFile(s) [, options])
.. versionchanged:: 1.3.0
``cpus`` option added.
.. versionchanged:: 1.4.0
Removed ``doTCP`` from the options. A listen socket on TCP is always created.
+ ``certFile(s)`` and ``keyFile(s)`` now accept a list of files.
Adds a DNSCrypt listen socket on ``address``.
:param string address: The address and port to listen on
:param string provider: The provider name for this bind
- :param string certificate: Path to the certificate file
- :param string keyfile: Path to the key file of the certificate
+ :param str certFile(s): The path to a X.509 certificate file in PEM format, or a list of paths to such files.
+ :param str keyFile(s): The path to the private key file corresponding to the certificate, or a list of paths to such files, whose order should match the certFile(s) ones.
:param table options: A table with key: value pairs with options (see below)
Options: