return true;
}
+
+static void parseTLSConfig(TLSConfig& config, const std::string& context, boost::optional<localbind_t> vars)
+{
+ if (vars->count("ciphers")) {
+ config.d_ciphers = boost::get<const string>((*vars)["ciphers"]);
+ }
+
+ if (vars->count("ciphersTLS13")) {
+ config.d_ciphers13 = boost::get<const string>((*vars)["ciphersTLS13"]);
+ }
+
+#ifdef HAVE_LIBSSL
+ if (vars->count("minTLSVersion")) {
+ config.d_minTLSVersion = libssl_tls_version_from_string(boost::get<const string>((*vars)["minTLSVersion"]));
+ }
+#endif /* HAVE_LIBSSL */
+
+ if (vars->count("ticketKeyFile")) {
+ config.d_ticketKeyFile = boost::get<const string>((*vars)["ticketKeyFile"]);
+ }
+
+ if (vars->count("ticketsKeysRotationDelay")) {
+ config.d_ticketsKeyRotationDelay = boost::get<int>((*vars)["ticketsKeysRotationDelay"]);
+ }
+
+ if (vars->count("numberOfTicketsKeys")) {
+ config.d_numberOfTicketsKeys = boost::get<int>((*vars)["numberOfTicketsKeys"]);
+ }
+
+ if (vars->count("preferServerCiphers")) {
+ config.d_preferServerCiphers = boost::get<bool>((*vars)["preferServerCiphers"]);
+ }
+
+ if (vars->count("sessionTickets")) {
+ config.d_enableTickets = boost::get<bool>((*vars)["sessionTickets"]);
+ }
+
+ if (vars->count("numberOfStoredSessions")) {
+ auto value = boost::get<int>((*vars)["numberOfStoredSessions"]);
+ if (value < 0) {
+ errlog("Invalid value '%d' for %s() parameter 'numberOfStoredSessions', should be >= 0, dismissing", value, context);
+ g_outputBuffer="Invalid value '" + std::to_string(value) + "' for " + context + "() parameter 'numberOfStoredSessions', should be >= 0, dimissing";
+ }
+ config.d_maxStoredSessions = value;
+ }
+
+ if (vars->count("ocspResponses")) {
+ auto files = boost::get<std::vector<std::pair<int, std::string>>>((*vars)["ocspResponses"]);
+ for (const auto& file : files) {
+ config.d_ocspFiles.push_back(file.second);
+ }
+ }
+}
+
#endif // defined(HAVE_DNS_OVER_TLS) || defined(HAVE_DNS_OVER_HTTPS)
void setupLuaConfig(bool client)
auto frontend = std::make_shared<DOHFrontend>();
if (certFiles && !certFiles->empty() && keyFiles && !keyFiles->empty()) {
- if (!loadTLSCertificateAndKeys("addDOHLocal", frontend->d_certKeyPairs, *certFiles, *keyFiles)) {
+ if (!loadTLSCertificateAndKeys("addDOHLocal", frontend->d_tlsConfig.d_certKeyPairs, *certFiles, *keyFiles)) {
return;
}
if (vars->count("idleTimeout")) {
frontend->d_idleTimeout = boost::get<int>((*vars)["idleTimeout"]);
}
- if (vars->count("ciphers")) {
- frontend->d_ciphers = boost::get<const string>((*vars)["ciphers"]);
- }
- if (vars->count("ciphersTLS13")) {
- frontend->d_ciphers13 = boost::get<const string>((*vars)["ciphersTLS13"]);
- }
- if (vars->count("minTLSVersion")) {
- frontend->d_minTLSVersion = libssl_tls_version_from_string(boost::get<const string>((*vars)["minTLSVersion"]));
- }
+
if (vars->count("serverTokens")) {
frontend->d_serverTokens = boost::get<const string>((*vars)["serverTokens"]);
}
+
if (vars->count("customResponseHeaders")) {
for (auto const& headerMap : boost::get<std::map<std::string,std::string>>((*vars)["customResponseHeaders"])) {
std::pair<std::string,std::string> headerResponse = std::make_pair(boost::to_lower_copy(headerMap.first), headerMap.second);
}
}
- if (vars->count("ticketKeyFile")) {
- frontend->d_ticketKeyFile = boost::get<const string>((*vars)["ticketKeyFile"]);
- }
-
- if (vars->count("ticketsKeysRotationDelay")) {
- frontend->d_ticketsKeyRotationDelay = boost::get<int>((*vars)["ticketsKeysRotationDelay"]);
- }
-
- if (vars->count("numberOfTicketsKeys")) {
- frontend->d_numberOfTicketsKeys = boost::get<int>((*vars)["numberOfTicketsKeys"]);
- }
-
- if (vars->count("sessionTickets")) {
- frontend->d_enableTickets = boost::get<bool>((*vars)["sessionTickets"]);
- }
-
- if (vars->count("preferServerCiphers")) {
- frontend->d_preferServerCiphers = boost::get<bool>((*vars)["preferServerCiphers"]);
- }
-
- if (vars->count("numberOfStoredSessions")) {
- auto value = boost::get<int>((*vars)["numberOfStoredSessions"]);
- if (value < 0) {
- errlog("Invalid value '%d' for addDOHLocal() parameter 'numberOfStoredSessions', should be >= 0, dismissing", value);
- g_outputBuffer="Invalid value '" + std::to_string(value) + "' for addDOHLocal() parameter 'numberOfStoredSessions', should be >= 0, dimissing";
- return;
- }
- frontend->d_maxStoredSessions = value;
- }
-
- if (vars->count("ocspResponses")) {
- auto files = boost::get<std::vector<std::pair<int, std::string>>>((*vars)["ocspResponses"]);
- for (const auto& file : files) {
- frontend->d_ocspFiles.push_back(file.second);
- }
- }
+ parseTLSConfig(frontend->d_tlsConfig, "addDOHLocal", vars);
}
g_dohlocals.push_back(frontend);
auto cs = std::unique_ptr<ClientState>(new ClientState(frontend->d_local, true, reusePort, tcpFastOpenQueueSize, interface, cpus));
}
shared_ptr<TLSFrontend> frontend = std::make_shared<TLSFrontend>();
- if (!loadTLSCertificateAndKeys("addTLSLocal", frontend->d_certKeyPairs, certFiles, keyFiles)) {
+ if (!loadTLSCertificateAndKeys("addTLSLocal", frontend->d_tlsConfig.d_certKeyPairs, certFiles, keyFiles)) {
return;
}
frontend->d_provider = boost::get<const string>((*vars)["provider"]);
}
- if (vars->count("ciphers")) {
- frontend->d_ciphers = boost::get<const string>((*vars)["ciphers"]);
- }
-
- if (vars->count("ciphersTLS13")) {
- frontend->d_ciphers13 = boost::get<const string>((*vars)["ciphersTLS13"]);
- }
-
-#ifdef HAVE_LIBSSL
- if (vars->count("minTLSVersion")) {
- frontend->d_minTLSVersion = libssl_tls_version_from_string(boost::get<const string>((*vars)["minTLSVersion"]));
- }
-#endif /* HAVE_LIBSSL */
-
- if (vars->count("ticketKeyFile")) {
- frontend->d_ticketKeyFile = boost::get<const string>((*vars)["ticketKeyFile"]);
- }
-
- if (vars->count("ticketsKeysRotationDelay")) {
- frontend->d_ticketsKeyRotationDelay = boost::get<int>((*vars)["ticketsKeysRotationDelay"]);
- }
-
- if (vars->count("numberOfTicketsKeys")) {
- frontend->d_numberOfTicketsKeys = boost::get<int>((*vars)["numberOfTicketsKeys"]);
- }
-
- if (vars->count("sessionTickets")) {
- frontend->d_enableTickets = boost::get<bool>((*vars)["sessionTickets"]);
- }
-
- if (vars->count("preferServerCiphers")) {
- frontend->d_preferServerCiphers = boost::get<bool>((*vars)["preferServerCiphers"]);
- }
-
- if (vars->count("numberOfStoredSessions")) {
- auto value = boost::get<int>((*vars)["numberOfStoredSessions"]);
- if (value < 0) {
- errlog("Invalid value '%d' for addTLSLocal() parameter 'numberOfStoredSessions', should be >= 0, dismissing", value);
- g_outputBuffer="Invalid value '" + std::to_string(value) + "' for addTLSLocal() parameter 'numberOfStoredSessions', should be >= 0, dimissing";
- return;
- }
- frontend->d_maxStoredSessions = value;
- }
-
- if (vars->count("ocspResponses")) {
- auto files = boost::get<std::vector<std::pair<int, std::string>>>((*vars)["ocspResponses"]);
- for (const auto& file : files) {
- frontend->d_ocspFiles.push_back(file.second);
- }
- }
+ parseTLSConfig(frontend->d_tlsConfig, "addTLSLocal", vars);
}
try {
g_lua.registerFunction<void(std::shared_ptr<TLSFrontend>::*)(boost::variant<std::string, std::vector<std::pair<int,std::string>>> certFiles, boost::variant<std::string, std::vector<std::pair<int,std::string>>> keyFiles)>("loadNewCertificatesAndKeys", [](std::shared_ptr<TLSFrontend>& frontend, boost::variant<std::string, std::vector<std::pair<int,std::string>>> certFiles, boost::variant<std::string, std::vector<std::pair<int,std::string>>> keyFiles) {
#ifdef HAVE_DNS_OVER_TLS
- if (loadTLSCertificateAndKeys("loadNewCertificatesAndKeys", frontend->d_certKeyPairs, certFiles, keyFiles)) {
+ if (loadTLSCertificateAndKeys("loadNewCertificatesAndKeys", frontend->d_tlsConfig.d_certKeyPairs, certFiles, keyFiles)) {
frontend->setupTLS();
}
#endif
static std::unique_ptr<SSL_CTX, void(*)(SSL_CTX*)> getTLSContext(DOHFrontend& df,
std::map<int, std::string>& ocspResponses)
{
- auto ctx = std::unique_ptr<SSL_CTX, void(*)(SSL_CTX*)>(SSL_CTX_new(SSLv23_server_method()), SSL_CTX_free);
-
- int sslOptions =
- SSL_OP_NO_SSLv2 |
- SSL_OP_NO_SSLv3 |
- SSL_OP_NO_COMPRESSION |
- SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
- SSL_OP_SINGLE_DH_USE |
- SSL_OP_SINGLE_ECDH_USE;
-
- if (!df.d_enableTickets || df.d_numberOfTicketsKeys == 0) {
- /* for TLS 1.3 this means no stateless tickets, but stateful tickets might still be issued,
- which is something we don't want. */
- sslOptions |= SSL_OP_NO_TICKET;
- /* really disable all tickets */
-#ifdef HAVE_SSL_CTX_SET_NUM_TICKETS
- SSL_CTX_set_num_tickets(ctx.get(), 0);
-#endif /* HAVE_SSL_CTX_SET_NUM_TICKETS */
- }
- else {
- df.d_ticketKeys = std::unique_ptr<OpenSSLTLSTicketKeysRing>(new OpenSSLTLSTicketKeysRing(df.d_numberOfTicketsKeys));
- SSL_CTX_set_tlsext_ticket_key_cb(ctx.get(), &ticket_key_callback);
- libssl_set_ticket_key_callback_data(ctx.get(), &df);
- }
-
- if (df.d_preferServerCiphers) {
- sslOptions |= SSL_OP_CIPHER_SERVER_PREFERENCE;
- }
-
- SSL_CTX_set_options(ctx.get(), sslOptions);
- if (!libssl_set_min_tls_version(ctx, df.d_minTLSVersion)) {
- throw std::runtime_error("Failed to set the minimum version to '" + libssl_tls_version_to_string(df.d_minTLSVersion) + "' for DoH listener");
- }
-
-#ifdef SSL_CTX_set_ecdh_auto
- SSL_CTX_set_ecdh_auto(ctx.get(), 1);
-#endif
+ try {
+ if (df.d_tlsConfig.d_ciphers.empty()) {
+ df.d_tlsConfig.d_ciphers = DOH_DEFAULT_CIPHERS;
+ }
- if (df.d_maxStoredSessions == 0) {
- /* disable stored sessions entirely */
- SSL_CTX_set_session_cache_mode(ctx.get(), SSL_SESS_CACHE_OFF);
- }
- else {
- /* use the internal built-in cache to store sessions */
- SSL_CTX_set_session_cache_mode(ctx.get(), SSL_SESS_CACHE_SERVER);
- SSL_CTX_sess_set_cache_size(ctx.get(), df.d_maxStoredSessions);
- }
+ auto ctx = libssl_init_server_context(df.d_tlsConfig, ocspResponses);
- std::vector<int> keyTypes;
- /* load certificate and private key */
- for (const auto& pair : df.d_certKeyPairs) {
- if (SSL_CTX_use_certificate_chain_file(ctx.get(), pair.first.c_str()) != 1) {
- ERR_print_errors_fp(stderr);
- throw std::runtime_error("Failed to setup SSL/TLS for DoH listener, an error occurred while trying to load the DOH server certificate file: " + pair.first);
- }
- if (SSL_CTX_use_PrivateKey_file(ctx.get(), pair.second.c_str(), SSL_FILETYPE_PEM) != 1) {
- ERR_print_errors_fp(stderr);
- throw std::runtime_error("Failed to setup SSL/TLS for DoH listener, an error occurred while trying to load the DOH server private key file: " + pair.second);
- }
- if (SSL_CTX_check_private_key(ctx.get()) != 1) {
- ERR_print_errors_fp(stderr);
- throw std::runtime_error("Failed to setup SSL/TLS for DoH listener, the key from '" + pair.second + "' does not match the certificate from '" + pair.first + "'");
+ if (df.d_tlsConfig.d_enableTickets && df.d_tlsConfig.d_numberOfTicketsKeys > 0) {
+ df.d_ticketKeys = std::unique_ptr<OpenSSLTLSTicketKeysRing>(new OpenSSLTLSTicketKeysRing(df.d_tlsConfig.d_numberOfTicketsKeys));
+ SSL_CTX_set_tlsext_ticket_key_cb(ctx.get(), &ticket_key_callback);
+ libssl_set_ticket_key_callback_data(ctx.get(), &df);
}
- /* store the type of the new key, we might need it later to select the right OCSP stapling response */
- auto keyType = libssl_get_last_key_type(ctx);
- if (keyType < 0) {
- throw std::runtime_error("Failed to setup SSL/TLS for DoH listener, the key from '" + pair.second + "' has an unknown type");
- }
- keyTypes.push_back(keyType);
- }
-
- if (!df.d_ocspFiles.empty()) {
- try {
- ocspResponses = libssl_load_ocsp_responses(df.d_ocspFiles, keyTypes);
+ if (!ocspResponses.empty()) {
SSL_CTX_set_tlsext_status_cb(ctx.get(), &ocsp_stapling_callback);
SSL_CTX_set_tlsext_status_arg(ctx.get(), &ocspResponses);
}
- catch(const std::exception& e) {
- throw std::runtime_error("Unable to load OCSP responses for the SSL/TLS DoH listener: " + std::string(e.what()));
- }
- }
- if (SSL_CTX_set_cipher_list(ctx.get(), df.d_ciphers.empty() == false ? df.d_ciphers.c_str() : DOH_DEFAULT_CIPHERS) != 1) {
- throw std::runtime_error("Failed to setup SSL/TLS for DoH listener, DOH ciphers could not be set: " + df.d_ciphers);
- }
-
-#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
- if (!df.d_ciphers13.empty() && SSL_CTX_set_ciphersuites(ctx.get(), df.d_ciphers13.c_str()) != 1) {
- throw std::runtime_error("Failed to setup SSL/TLS for DoH listener, DOH TLS 1.3 ciphers could not be set: " + df.d_ciphers13);
- }
-#endif /* HAVE_SSL_CTX_SET_CIPHERSUITES */
-
- h2o_ssl_register_alpn_protocols(ctx.get(), h2o_http2_alpn_protocols);
+ h2o_ssl_register_alpn_protocols(ctx.get(), h2o_http2_alpn_protocols);
- try {
- if (df.d_ticketKeyFile.empty()) {
+ if (df.d_tlsConfig.d_ticketKeyFile.empty()) {
df.handleTicketsKeyRotation();
}
else {
- df.loadTicketsKeys(df.d_ticketKeyFile);
+ df.loadTicketsKeys(df.d_tlsConfig.d_ticketKeyFile);
}
+
+ return ctx;
}
- catch (const std::exception& e) {
- throw;
+ catch (const std::runtime_error& e) {
+ throw std::runtime_error("Error setting up TLS context for DoH listener on '" + df.d_local.toStringWithPort() + "': " + e.what());
}
-
- return ctx;
}
static void setupAcceptContext(DOHAcceptContext& ctx, DOHServerConfig& dsc, bool setupTLS)
auto nativeCtx = ctx.get();
nativeCtx->ctx = &dsc.h2o_ctx;
nativeCtx->hosts = dsc.h2o_config.hosts;
- if (setupTLS && !dsc.df->d_certKeyPairs.empty()) {
+ if (setupTLS && !dsc.df->d_tlsConfig.d_certKeyPairs.empty()) {
auto tlsCtx = getTLSContext(*dsc.df,
ctx.d_ocspResponses);
d_ticketKeys->rotateTicketsKey(now);
- if (d_ticketsKeyRotationDelay > 0) {
- d_ticketsKeyNextRotation = now + d_ticketsKeyRotationDelay;
+ if (d_tlsConfig.d_ticketsKeyRotationDelay > 0) {
+ d_ticketsKeyNextRotation = now + d_tlsConfig.d_ticketsKeyRotationDelay;
}
}
}
d_ticketKeys->loadTicketsKeys(keyFile);
- if (d_ticketsKeyRotationDelay > 0) {
- d_ticketsKeyNextRotation = time(nullptr) + d_ticketsKeyRotationDelay;
+ if (d_tlsConfig.d_ticketsKeyRotationDelay > 0) {
+ d_ticketsKeyNextRotation = time(nullptr) + d_tlsConfig.d_ticketsKeyRotationDelay;
}
}
void DOHFrontend::handleTicketsKeyRotation()
{
- if (d_ticketsKeyRotationDelay == 0) {
+ if (d_tlsConfig.d_ticketsKeyRotationDelay == 0) {
return;
}
d_dsc = std::make_shared<DOHServerConfig>(d_idleTimeout);
- if (!d_certKeyPairs.empty()) {
+ if (!d_tlsConfig.d_certKeyPairs.empty()) {
auto tlsCtx = getTLSContext(*this,
d_dsc->accept_ctx->d_ocspResponses);
return true;
}
+std::unique_ptr<SSL_CTX, void(*)(SSL_CTX*)> libssl_init_server_context(const TLSConfig& config,
+ std::map<int, std::string>& ocspResponses)
+{
+ auto ctx = std::unique_ptr<SSL_CTX, void(*)(SSL_CTX*)>(SSL_CTX_new(SSLv23_server_method()), SSL_CTX_free);
+
+ int sslOptions =
+ SSL_OP_NO_SSLv2 |
+ SSL_OP_NO_SSLv3 |
+ SSL_OP_NO_COMPRESSION |
+ SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
+ SSL_OP_SINGLE_DH_USE |
+ SSL_OP_SINGLE_ECDH_USE;
+
+ if (!config.d_enableTickets || config.d_numberOfTicketsKeys == 0) {
+ /* for TLS 1.3 this means no stateless tickets, but stateful tickets might still be issued,
+ which is something we don't want. */
+ sslOptions |= SSL_OP_NO_TICKET;
+ /* really disable all tickets */
+#ifdef HAVE_SSL_CTX_SET_NUM_TICKETS
+ SSL_CTX_set_num_tickets(ctx.get(), 0);
+#endif /* HAVE_SSL_CTX_SET_NUM_TICKETS */
+ }
+
+ if (config.d_preferServerCiphers) {
+ sslOptions |= SSL_OP_CIPHER_SERVER_PREFERENCE;
+ }
+
+ SSL_CTX_set_options(ctx.get(), sslOptions);
+ if (!libssl_set_min_tls_version(ctx, config.d_minTLSVersion)) {
+ throw std::runtime_error("Failed to set the minimum version to '" + libssl_tls_version_to_string(config.d_minTLSVersion));
+ }
+
+#ifdef SSL_CTX_set_ecdh_auto
+ SSL_CTX_set_ecdh_auto(ctx.get(), 1);
+#endif
+
+ if (config.d_maxStoredSessions == 0) {
+ /* disable stored sessions entirely */
+ SSL_CTX_set_session_cache_mode(ctx.get(), SSL_SESS_CACHE_OFF);
+ }
+ else {
+ /* use the internal built-in cache to store sessions */
+ SSL_CTX_set_session_cache_mode(ctx.get(), SSL_SESS_CACHE_SERVER);
+ SSL_CTX_sess_set_cache_size(ctx.get(), config.d_maxStoredSessions);
+ }
+
+ std::vector<int> keyTypes;
+ /* load certificate and private key */
+ for (const auto& pair : config.d_certKeyPairs) {
+ if (SSL_CTX_use_certificate_chain_file(ctx.get(), pair.first.c_str()) != 1) {
+ ERR_print_errors_fp(stderr);
+ throw std::runtime_error("An error occurred while trying to load the TLS server certificate file: " + pair.first);
+ }
+ if (SSL_CTX_use_PrivateKey_file(ctx.get(), pair.second.c_str(), SSL_FILETYPE_PEM) != 1) {
+ ERR_print_errors_fp(stderr);
+ throw std::runtime_error("An error occurred while trying to load the TLS server private key file: " + pair.second);
+ }
+ if (SSL_CTX_check_private_key(ctx.get()) != 1) {
+ ERR_print_errors_fp(stderr);
+ throw std::runtime_error("The key from '" + pair.second + "' does not match the certificate from '" + pair.first + "'");
+ }
+ /* store the type of the new key, we might need it later to select the right OCSP stapling response */
+ auto keyType = libssl_get_last_key_type(ctx);
+ if (keyType < 0) {
+ throw std::runtime_error("The key from '" + pair.second + "' has an unknown type");
+ }
+ keyTypes.push_back(keyType);
+ }
+
+ if (!config.d_ocspFiles.empty()) {
+ try {
+ ocspResponses = libssl_load_ocsp_responses(config.d_ocspFiles, keyTypes);
+ }
+ catch(const std::exception& e) {
+ throw std::runtime_error("Unable to load OCSP responses: " + std::string(e.what()));
+ }
+ }
+
+ if (!config.d_ciphers.empty() && SSL_CTX_set_cipher_list(ctx.get(), config.d_ciphers.c_str()) != 1) {
+ throw std::runtime_error("The TLS ciphers could not be set: " + config.d_ciphers);
+ }
+
+#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
+ if (!config.d_ciphers13.empty() && SSL_CTX_set_ciphersuites(ctx.get(), config.d_ciphers13.c_str()) != 1) {
+ throw std::runtime_error("The TLS 1.3 ciphers could not be set: " + config.d_ciphers13);
+ }
+#endif /* HAVE_SSL_CTX_SET_CIPHERSUITES */
+
+ return ctx;
+}
+
#endif /* HAVE_LIBSSL */
class OpenSSLTLSIOCtx: public TLSCtx
{
public:
- OpenSSLTLSIOCtx(const TLSFrontend& fe): d_ticketKeys(fe.d_numberOfTicketsKeys), d_tlsCtx(std::unique_ptr<SSL_CTX, void(*)(SSL_CTX*)>(nullptr, SSL_CTX_free))
+ OpenSSLTLSIOCtx(const TLSFrontend& fe): d_ticketKeys(fe.d_tlsConfig.d_numberOfTicketsKeys)
{
- d_ticketsKeyRotationDelay = fe.d_ticketsKeyRotationDelay;
-
- int sslOptions =
- SSL_OP_NO_SSLv2 |
- SSL_OP_NO_SSLv3 |
- SSL_OP_NO_COMPRESSION |
- SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
- SSL_OP_SINGLE_DH_USE |
- SSL_OP_SINGLE_ECDH_USE;
-
registerOpenSSLUser();
+ d_ticketsKeyRotationDelay = fe.d_tlsConfig.d_ticketsKeyRotationDelay;
- d_tlsCtx = std::unique_ptr<SSL_CTX, void(*)(SSL_CTX*)>(SSL_CTX_new(SSLv23_server_method()), SSL_CTX_free);
+ d_tlsCtx = libssl_init_server_context(fe.d_tlsConfig, d_ocspResponses);
if (!d_tlsCtx) {
ERR_print_errors_fp(stderr);
throw std::runtime_error("Error creating TLS context on " + fe.d_addr.toStringWithPort());
}
- if (!fe.d_enableTickets || fe.d_numberOfTicketsKeys == 0) {
- /* for TLS 1.3 this means no stateless tickets, but stateful tickets might still be issued,
- which is something we don't want. */
- sslOptions |= SSL_OP_NO_TICKET;
- /* really disable all tickets */
-#ifdef HAVE_SSL_CTX_SET_NUM_TICKETS
- SSL_CTX_set_num_tickets(d_tlsCtx.get(), 0);
-#endif /* HAVE_SSL_CTX_SET_NUM_TICKETS */
- }
- else {
+ if (fe.d_tlsConfig.d_enableTickets && fe.d_tlsConfig.d_numberOfTicketsKeys > 0) {
/* use our own ticket keys handler so we can rotate them */
SSL_CTX_set_tlsext_ticket_key_cb(d_tlsCtx.get(), &OpenSSLTLSIOCtx::ticketKeyCb);
libssl_set_ticket_key_callback_data(d_tlsCtx.get(), this);
}
- if (fe.d_preferServerCiphers) {
- sslOptions |= SSL_OP_CIPHER_SERVER_PREFERENCE;
- }
-
- SSL_CTX_set_options(d_tlsCtx.get(), sslOptions);
- if (!libssl_set_min_tls_version(d_tlsCtx, fe.d_minTLSVersion)) {
- throw std::runtime_error("Failed to set the minimum version to '" + libssl_tls_version_to_string(fe.d_minTLSVersion) + "' for ths TLS context on " + fe.d_addr.toStringWithPort());
- }
-
-#if defined(SSL_CTX_set_ecdh_auto)
- SSL_CTX_set_ecdh_auto(d_tlsCtx.get(), 1);
-#endif
- if (fe.d_maxStoredSessions == 0) {
- /* disable stored sessions entirely */
- SSL_CTX_set_session_cache_mode(d_tlsCtx.get(), SSL_SESS_CACHE_OFF);
- }
- else {
- /* use the internal built-in cache to store sessions */
- SSL_CTX_set_session_cache_mode(d_tlsCtx.get(), SSL_SESS_CACHE_SERVER);
- SSL_CTX_sess_set_cache_size(d_tlsCtx.get(), fe.d_maxStoredSessions);
- }
-
- std::vector<int> keyTypes;
- for (const auto& pair : fe.d_certKeyPairs) {
- if (SSL_CTX_use_certificate_chain_file(d_tlsCtx.get(), pair.first.c_str()) != 1) {
- ERR_print_errors_fp(stderr);
- throw std::runtime_error("Error loading certificate from " + pair.first + " for the TLS context on " + fe.d_addr.toStringWithPort());
- }
- if (SSL_CTX_use_PrivateKey_file(d_tlsCtx.get(), pair.second.c_str(), SSL_FILETYPE_PEM) != 1) {
- ERR_print_errors_fp(stderr);
- throw std::runtime_error("Error loading key from " + pair.second + " for the TLS context on " + fe.d_addr.toStringWithPort());
- }
- if (SSL_CTX_check_private_key(d_tlsCtx.get()) != 1) {
- ERR_print_errors_fp(stderr);
- throw std::runtime_error("Key from '" + pair.second + "' does not match the certificate from '" + pair.first + "' for the TLS context on " + fe.d_addr.toStringWithPort());
- }
-
- /* store the type of the new key, we might need it later to select the right OCSP stapling response */
- auto keyType = libssl_get_last_key_type(d_tlsCtx);
- if (keyType < 0) {
- throw std::runtime_error("Key from '" + pair.second + "' has an unknown type");
- }
- keyTypes.push_back(keyType);
- }
-
- if (!fe.d_ocspFiles.empty()) {
- try {
- d_ocspResponses = libssl_load_ocsp_responses(fe.d_ocspFiles, keyTypes);
- }
- catch(const std::exception& e) {
- throw std::runtime_error("Error loading responses for the TLS context on " + fe.d_addr.toStringWithPort() + ": " + e.what());
- }
-
+ if (!d_ocspResponses.empty()) {
SSL_CTX_set_tlsext_status_cb(d_tlsCtx.get(), &OpenSSLTLSIOCtx::ocspStaplingCb);
SSL_CTX_set_tlsext_status_arg(d_tlsCtx.get(), &d_ocspResponses);
}
- if (!fe.d_ciphers.empty()) {
- if (SSL_CTX_set_cipher_list(d_tlsCtx.get(), fe.d_ciphers.c_str()) != 1) {
- ERR_print_errors_fp(stderr);
- throw std::runtime_error("Error setting the cipher list to '" + fe.d_ciphers + "' for the TLS context on " + fe.d_addr.toStringWithPort());
- }
- }
-
-#ifdef HAVE_SSL_CTX_SET_CIPHERSUITES
- if (!fe.d_ciphers13.empty()) {
- if (SSL_CTX_set_ciphersuites(d_tlsCtx.get(), fe.d_ciphers13.c_str()) != 1) {
- ERR_print_errors_fp(stderr);
- throw std::runtime_error("Error setting the TLS 1.3 cipher list to '" + fe.d_ciphers13 + "' for the TLS context on " + fe.d_addr.toStringWithPort());
- }
- }
-#endif /* HAVE_SSL_CTX_SET_CIPHERSUITES */
-
try {
- if (fe.d_ticketKeyFile.empty()) {
+ if (fe.d_tlsConfig.d_ticketKeyFile.empty()) {
handleTicketsKeyRotation(time(nullptr));
}
else {
- loadTicketsKeys(fe.d_ticketKeyFile);
+ loadTicketsKeys(fe.d_tlsConfig.d_ticketKeyFile);
}
}
catch (const std::exception& e) {
private:
OpenSSLTLSTicketKeysRing d_ticketKeys;
std::map<int, std::string> d_ocspResponses;
- std::unique_ptr<SSL_CTX, void(*)(SSL_CTX*)> d_tlsCtx;
+ std::unique_ptr<SSL_CTX, void(*)(SSL_CTX*)> d_tlsCtx{nullptr, SSL_CTX_free};
};
#endif /* HAVE_LIBSSL */
class GnuTLSIOCtx: public TLSCtx
{
public:
- GnuTLSIOCtx(const TLSFrontend& fe): d_creds(std::unique_ptr<gnutls_certificate_credentials_st, void(*)(gnutls_certificate_credentials_t)>(nullptr, gnutls_certificate_free_credentials)), d_enableTickets(fe.d_enableTickets)
+ GnuTLSIOCtx(const TLSFrontend& fe): d_creds(std::unique_ptr<gnutls_certificate_credentials_st, void(*)(gnutls_certificate_credentials_t)>(nullptr, gnutls_certificate_free_credentials)), d_enableTickets(fe.d_tlsConfig.d_enableTickets)
{
int rc = 0;
- d_ticketsKeyRotationDelay = fe.d_ticketsKeyRotationDelay;
+ d_ticketsKeyRotationDelay = fe.d_tlsConfig.d_ticketsKeyRotationDelay;
gnutls_certificate_credentials_t creds;
rc = gnutls_certificate_allocate_credentials(&creds);
d_creds = std::unique_ptr<gnutls_certificate_credentials_st, void(*)(gnutls_certificate_credentials_t)>(creds, gnutls_certificate_free_credentials);
creds = nullptr;
- for (const auto& pair : fe.d_certKeyPairs) {
+ for (const auto& pair : fe.d_tlsConfig.d_certKeyPairs) {
rc = gnutls_certificate_set_x509_key_file(d_creds.get(), pair.first.c_str(), pair.second.c_str(), GNUTLS_X509_FMT_PEM);
if (rc != GNUTLS_E_SUCCESS) {
throw std::runtime_error("Error loading certificate ('" + pair.first + "') and key ('" + pair.second + "') for TLS context on " + fe.d_addr.toStringWithPort() + ": " + gnutls_strerror(rc));
}
size_t count = 0;
- for (const auto& file : fe.d_ocspFiles) {
+ 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_certKeyPairs.at(count).first + "') and key ('" + fe.d_certKeyPairs.at(count).second + "') for TLS context on " + fe.d_addr.toStringWithPort() + ": " + gnutls_strerror(rc));
+ throw std::runtime_error("Error loading OCSP response from file '" + file + "' for certificate ('" + fe.d_tlsConfig.d_certKeyPairs.at(count).first + "') and key ('" + fe.d_tlsConfig.d_certKeyPairs.at(count).second + "') for TLS context on " + fe.d_addr.toStringWithPort() + ": " + gnutls_strerror(rc));
}
++count;
}
}
#endif
- rc = gnutls_priority_init(&d_priorityCache, fe.d_ciphers.empty() ? "NORMAL" : fe.d_ciphers.c_str(), nullptr);
+ rc = gnutls_priority_init(&d_priorityCache, fe.d_tlsConfig.d_ciphers.empty() ? "NORMAL" : fe.d_tlsConfig.d_ciphers.c_str(), nullptr);
if (rc != GNUTLS_E_SUCCESS) {
- throw std::runtime_error("Error setting up TLS cipher preferences to '" + fe.d_ciphers + "' (" + gnutls_strerror(rc) + ") on " + fe.d_addr.toStringWithPort());
+ throw std::runtime_error("Error setting up TLS cipher preferences to '" + fe.d_tlsConfig.d_ciphers + "' (" + gnutls_strerror(rc) + ") on " + fe.d_addr.toStringWithPort());
}
pthread_rwlock_init(&d_lock, nullptr);
try {
- if (fe.d_ticketKeyFile.empty()) {
+ if (fe.d_tlsConfig.d_ticketKeyFile.empty()) {
handleTicketsKeyRotation(time(nullptr));
}
else {
- loadTicketsKeys(fe.d_ticketKeyFile);
+ loadTicketsKeys(fe.d_tlsConfig.d_ticketKeyFile);
}
}
catch(const std::runtime_error& e) {
}
std::shared_ptr<DOHServerConfig> d_dsc{nullptr};
- std::vector<std::pair<std::string, std::string>> d_certKeyPairs;
- std::vector<std::string> d_ocspFiles;
std::vector<std::shared_ptr<DOHResponseMapEntry>> d_responsesMap;
- std::string d_ciphers;
- std::string d_ciphers13;
+ TLSConfig d_tlsConfig;
std::string d_serverTokens{"h2o/dnsdist"};
- LibsslTLSVersion d_minTLSVersion{LibsslTLSVersion::TLS10};
#ifdef HAVE_DNS_OVER_HTTPS
std::unique_ptr<OpenSSLTLSTicketKeysRing> d_ticketKeys{nullptr};
#endif
uint32_t d_idleTimeout{30}; // HTTP idle timeout in seconds
std::vector<std::string> d_urls;
- std::string d_ticketKeyFile;
-
- time_t d_ticketsKeyRotationDelay{43200};
- size_t d_maxStoredSessions{20480};
- uint8_t d_numberOfTicketsKeys{5};
- bool d_enableTickets{true};
- bool d_preferServerCiphers{false};
std::atomic<uint64_t> d_httpconnects{0}; // number of TCP/IP connections established
std::atomic<uint64_t> d_getqueries{0}; // valid DNS queries received via GET
enum class LibsslTLSVersion { Unknown, TLS10, TLS11, TLS12, TLS13 };
+class TLSConfig
+{
+public:
+ std::vector<std::pair<std::string, std::string>> d_certKeyPairs;
+ std::vector<std::string> d_ocspFiles;
+
+ std::string d_ciphers;
+ std::string d_ciphers13;
+ std::string d_ticketKeyFile;
+
+ size_t d_maxStoredSessions{20480};
+ time_t d_ticketsKeyRotationDelay{43200};
+ uint8_t d_numberOfTicketsKeys{5};
+ LibsslTLSVersion d_minTLSVersion{LibsslTLSVersion::TLS10};
+
+ bool d_preferServerCiphers{false};
+ bool d_enableTickets{true};
+};
+
#ifdef HAVE_LIBSSL
#include <openssl/ssl.h>
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);
+
#endif /* HAVE_LIBSSL */
time_t getTicketsKeyRotationDelay() const
{
- return d_ticketsKeyRotationDelay;
+ return d_tlsConfig.d_ticketsKeyRotationDelay;
}
std::string getNextTicketsKeyRotation() const
return res;
}
- std::vector<std::pair<std::string, std::string>> d_certKeyPairs;
- std::vector<std::string> d_ocspFiles;
+ TLSConfig d_tlsConfig;
ComboAddress d_addr;
- std::string d_ciphers;
- std::string d_ciphers13;
std::string d_provider;
- std::string d_ticketKeyFile;
-
- size_t d_maxStoredSessions{20480};
- time_t d_ticketsKeyRotationDelay{43200};
- uint8_t d_numberOfTicketsKeys{5};
- LibsslTLSVersion d_minTLSVersion{LibsslTLSVersion::TLS10};
-
- bool d_enableTickets{true};
- bool d_preferServerCiphers{false};
private:
std::shared_ptr<TLSCtx> d_ctx{nullptr};