tlsConfig.d_ciphers = DOH_DEFAULT_CIPHERS;
}
- auto ctx = libssl_init_server_context(tlsConfig, acceptCtx.d_ocspResponses);
+ auto [ctx, warnings] = libssl_init_server_context(tlsConfig, acceptCtx.d_ocspResponses);
+ for (const auto& warning : warnings) {
+ warnlog("%s", warning);
+ }
if (tlsConfig.d_enableTickets && tlsConfig.d_numberOfTicketsKeys > 0) {
acceptCtx.d_ticketKeys = std::make_unique<OpenSSLTLSTicketKeysRing>(tlsConfig.d_numberOfTicketsKeys);
return true;
}
-std::map<int, std::string> libssl_load_ocsp_responses(const std::vector<std::string>& ocspFiles, std::vector<int> keyTypes)
+static std::map<int, std::string> libssl_load_ocsp_responses(const std::vector<std::string>& ocspFiles, std::vector<int> keyTypes, std::vector<std::string>& warnings)
{
std::map<int, std::string> ocspResponses;
for (const auto& filename : ocspFiles) {
std::ifstream file(filename, std::ios::binary);
std::string content;
- while(file) {
+ while (file) {
char buffer[4096];
file.read(buffer, sizeof(buffer));
if (file.bad()) {
file.close();
- throw std::runtime_error("Unable to load OCSP response from '" + filename + "'");
+ warnings.push_back("Unable to load OCSP response from " + filename);
+ continue;
}
content.append(buffer, file.gcount());
}
ocspResponses.insert({keyTypes.at(count), std::move(content)});
}
catch (const std::exception& e) {
- throw std::runtime_error("Error checking the validity of OCSP response from '" + filename + "': " + e.what());
+ warnings.push_back("Error checking the validity of OCSP response from '" + filename + "': " + e.what());
+ continue;
}
++count;
}
return true;
}
-std::unique_ptr<SSL_CTX, void(*)(SSL_CTX*)> libssl_init_server_context(const TLSConfig& config,
- std::map<int, std::string>& ocspResponses)
+std::pair<std::unique_ptr<SSL_CTX, void(*)(SSL_CTX*)>, std::vector<std::string>> libssl_init_server_context(const TLSConfig& config,
+ std::map<int, std::string>& ocspResponses)
{
+ std::vector<std::string> warnings;
auto ctx = std::unique_ptr<SSL_CTX, decltype(&SSL_CTX_free)>(SSL_CTX_new(SSLv23_server_method()), SSL_CTX_free);
if (!ctx) {
#ifdef SSL_MODE_ASYNC
mode |= SSL_MODE_ASYNC;
#else
- cerr<<"Warning: TLS async mode requested but not supported"<<endl;
+ warnings.push_back("Warning: TLS async mode requested but not supported");
#endif
}
#ifndef DISABLE_OCSP_STAPLING
if (!config.d_ocspFiles.empty()) {
try {
- ocspResponses = libssl_load_ocsp_responses(config.d_ocspFiles, keyTypes);
+ ocspResponses = libssl_load_ocsp_responses(config.d_ocspFiles, keyTypes, warnings);
}
catch(const std::exception& e) {
throw std::runtime_error("Unable to load OCSP responses: " + std::string(e.what()));
}
#endif /* HAVE_SSL_CTX_SET_CIPHERSUITES */
- return ctx;
+ return std::make_pair(std::move(ctx), std::move(warnings));
}
#ifdef HAVE_SSL_CTX_SET_KEYLOG_CALLBACK
#ifndef DISABLE_OCSP_STAPLING
int libssl_ocsp_stapling_callback(SSL* ssl, const std::map<int, std::string>& ocspMap);
-
-std::map<int, std::string> libssl_load_ocsp_responses(const std::vector<std::string>& ocspFiles, std::vector<int> keyTypes);
-
#ifdef HAVE_OCSP_BASIC_SIGN
bool libssl_generate_ocsp_response(const std::string& certFile, const std::string& caCert, const std::string& caKey, const std::string& outFile, int ndays, int nmin);
#endif
const std::string& libssl_tls_version_to_string(LibsslTLSVersion version);
bool libssl_set_min_tls_version(std::unique_ptr<SSL_CTX, void(*)(SSL_CTX*)>& ctx, LibsslTLSVersion version);
-std::unique_ptr<SSL_CTX, void(*)(SSL_CTX*)> libssl_init_server_context(const TLSConfig& config,
- std::map<int, std::string>& ocspResponses);
+/* return the created context, and a list of warning messages for issues not severe enough
+ to trigger raising an exception, like failing to load an OCSP response file */
+std::pair<std::unique_ptr<SSL_CTX, void(*)(SSL_CTX*)>, std::vector<std::string>> libssl_init_server_context(const TLSConfig& config,
+ std::map<int, std::string>& ocspResponses);
std::unique_ptr<FILE, int(*)(FILE*)> libssl_set_key_log_file(std::unique_ptr<SSL_CTX, void(*)(SSL_CTX*)>& ctx, const std::string& logFile);
{
registerOpenSSLUser();
- d_tlsCtx = libssl_init_server_context(tlsConfig, d_ocspResponses);
+ auto [ctx, warnings] = libssl_init_server_context(tlsConfig, d_ocspResponses);
+ for (const auto& warning : warnings) {
+ warnlog("%s", warning);
+ }
+ d_tlsCtx = std::move(ctx);
+
if (!d_tlsCtx) {
ERR_print_errors_fp(stderr);
throw std::runtime_error("Error creating TLS context on " + addr.toStringWithPort());
for (const auto& file : fe.d_tlsConfig.d_ocspFiles) {
rc = gnutls_certificate_set_ocsp_status_request_file(d_creds.get(), file.c_str(), count);
if (rc != GNUTLS_E_SUCCESS) {
- throw std::runtime_error("Error loading OCSP response from file '" + file + "' for certificate ('" + fe.d_tlsConfig.d_certKeyPairs.at(count).d_cert + "') and key ('" + fe.d_tlsConfig.d_certKeyPairs.at(count).d_key.value() + "') for TLS context on " + fe.d_addr.toStringWithPort() + ": " + gnutls_strerror(rc));
+ warnlog("Error loading OCSP response from file '%s' for certificate ('%s') and key ('%s') for TLS context on %s: %s", file, fe.d_tlsConfig.d_certKeyPairs.at(count).d_cert, fe.d_tlsConfig.d_certKeyPairs.at(count).d_key.value(), fe.d_addr.toStringWithPort(), gnutls_strerror(rc));
}
++count;
}
self.assertTrue(serialNumber2)
self.assertNotEqual(serialNumber, serialNumber2)
+class TestBrokenOCSPStaplingDoH(DNSDistOCSPStaplingTest):
+
+ _consoleKey = DNSDistTest.generateConsoleKey()
+ _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+ _serverKey = 'server.key'
+ _serverCert = 'server.chain'
+ _serverName = 'tls.tests.dnsdist.org'
+ _caCert = 'ca.pem'
+ # invalid OCSP file!
+ _ocspFile = '/dev/null'
+ _tlsServerPort = 8443
+ _config_template = """
+ newServer{address="127.0.0.1:%s"}
+ setKey("%s")
+ controlSocket("127.0.0.1:%s")
+
+ addDOHLocal("127.0.0.1:%s", "%s", "%s", { "/" }, { ocspResponses={"%s"}})
+ """
+ _config_params = ['_testServerPort', '_consoleKeyB64', '_consolePort', '_tlsServerPort', '_serverCert', '_serverKey', '_ocspFile']
+
+ def testBrokenOCSPStapling(self):
+ """
+ OCSP Stapling: Broken (DoH)
+ """
+ output = self.checkOCSPStaplingStatus('127.0.0.1', self._tlsServerPort, self._serverName, self._caCert)
+ self.assertNotIn('OCSP Response Status: successful (0x0)', output)
+
class TestOCSPStaplingTLSGnuTLS(DNSDistOCSPStaplingTest):
_consoleKey = DNSDistTest.generateConsoleKey()
self.assertTrue(serialNumber2)
self.assertNotEqual(serialNumber, serialNumber2)
+class TestBrokenOCSPStaplingTLSGnuTLS(DNSDistOCSPStaplingTest):
+
+ _consoleKey = DNSDistTest.generateConsoleKey()
+ _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+ _serverKey = 'server.key'
+ _serverCert = 'server.chain'
+ _serverName = 'tls.tests.dnsdist.org'
+ _caCert = 'ca.pem'
+ # invalid OCSP file!
+ _ocspFile = '/dev/null'
+ _tlsServerPort = 8443
+ _config_template = """
+ newServer{address="127.0.0.1:%s"}
+ setKey("%s")
+ controlSocket("127.0.0.1:%s")
+
+ addTLSLocal("127.0.0.1:%s", "%s", "%s", { provider="gnutls", ocspResponses={"%s"}})
+ """
+ _config_params = ['_testServerPort', '_consoleKeyB64', '_consolePort', '_tlsServerPort', '_serverCert', '_serverKey', '_ocspFile']
+
+ def testBrokenOCSPStapling(self):
+ """
+ OCSP Stapling: Broken (GnuTLS)
+ """
+ output = self.checkOCSPStaplingStatus('127.0.0.1', self._tlsServerPort, self._serverName, self._caCert)
+ self.assertNotIn('OCSP Response Status: successful (0x0)', output)
+ self.assertEquals(self.getTLSProvider(), "gnutls")
+
class TestOCSPStaplingTLSOpenSSL(DNSDistOCSPStaplingTest):
_consoleKey = DNSDistTest.generateConsoleKey()
serialNumber2 = self.getOCSPSerial(output)
self.assertTrue(serialNumber2)
self.assertNotEqual(serialNumber, serialNumber2)
+
+class TestBrokenOCSPStaplingTLSOpenSSL(DNSDistOCSPStaplingTest):
+
+ _consoleKey = DNSDistTest.generateConsoleKey()
+ _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
+ _serverKey = 'server.key'
+ _serverCert = 'server.chain'
+ _serverName = 'tls.tests.dnsdist.org'
+ _caCert = 'ca.pem'
+ # invalid OCSP file!
+ _ocspFile = '/dev/null'
+ _tlsServerPort = 8443
+ _config_template = """
+ newServer{address="127.0.0.1:%s"}
+ setKey("%s")
+ controlSocket("127.0.0.1:%s")
+
+ addTLSLocal("127.0.0.1:%s", "%s", "%s", { provider="openssl", ocspResponses={"%s"}})
+ """
+ _config_params = ['_testServerPort', '_consoleKeyB64', '_consolePort', '_tlsServerPort', '_serverCert', '_serverKey', '_ocspFile']
+
+ def testBrokenOCSPStapling(self):
+ """
+ OCSP Stapling: Broken (OpenSSL)
+ """
+ output = self.checkOCSPStaplingStatus('127.0.0.1', self._tlsServerPort, self._serverName, self._caCert)
+ self.assertNotIn('OCSP Response Status: successful (0x0)', output)
+ self.assertEquals(self.getTLSProvider(), "openssl")