in src/server/tls_util.cc [118:224]
UniqueSSLContext CreateSSLContext(const Config *config, const SSL_METHOD *method) {
if (config->tls_cert_file.empty() || config->tls_key_file.empty()) {
error("Both tls-cert-file and tls-key-file must be specified while TLS is enabled");
return nullptr;
}
auto ssl_ctx = UniqueSSLContext(method);
if (!ssl_ctx) {
error("Failed to construct SSL context: {}", fmt::streamed(SSLErrors{}));
return nullptr;
}
auto proto_status = ParseSSLProtocols(config->tls_protocols);
if (!proto_status) {
error("{}", proto_status.Msg());
return nullptr;
}
auto ctx_options = *proto_status;
#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
ctx_options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
#endif
#ifdef SSL_OP_NO_COMPRESSION
ctx_options |= SSL_OP_NO_COMPRESSION;
#endif
#ifdef SSL_OP_NO_CLIENT_RENEGOTIATION
ctx_options |= SSL_OP_NO_CLIENT_RENEGOTIATION;
#endif
if (config->tls_prefer_server_ciphers) {
ctx_options |= SSL_OP_CIPHER_SERVER_PREFERENCE;
}
SSL_CTX_set_options(ssl_ctx.get(), ctx_options);
SSL_CTX_set_mode(ssl_ctx.get(), SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
if (config->tls_session_caching) {
SSL_CTX_set_session_cache_mode(ssl_ctx.get(), SSL_SESS_CACHE_SERVER);
SSL_CTX_set_timeout(ssl_ctx.get(), config->tls_session_cache_timeout);
SSL_CTX_sess_set_cache_size(ssl_ctx.get(), config->tls_session_cache_size);
const char *session_id = "kvrocks";
SSL_CTX_set_session_id_context(ssl_ctx.get(), (const unsigned char *)session_id, strlen(session_id));
} else {
SSL_CTX_set_session_cache_mode(ssl_ctx.get(), SSL_SESS_CACHE_OFF);
}
if (config->tls_auth_clients == TLS_AUTH_CLIENTS_NO) {
SSL_CTX_set_verify(ssl_ctx.get(), SSL_VERIFY_NONE, nullptr);
} else if (config->tls_auth_clients == TLS_AUTH_CLIENTS_OPTIONAL) {
SSL_CTX_set_verify(ssl_ctx.get(), SSL_VERIFY_PEER, nullptr);
} else {
SSL_CTX_set_verify(ssl_ctx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
}
auto ca_file = config->tls_ca_cert_file.empty() ? nullptr : config->tls_ca_cert_file.c_str();
auto ca_dir = config->tls_ca_cert_dir.empty() ? nullptr : config->tls_ca_cert_dir.c_str();
if (ca_file || ca_dir) {
if (SSL_CTX_load_verify_locations(ssl_ctx.get(), ca_file, ca_dir) != 1) {
error("Failed to load CA certificates: {}", fmt::streamed(SSLErrors{}));
return nullptr;
}
} else if (config->tls_auth_clients != TLS_AUTH_CLIENTS_NO) {
error("Either tls-ca-cert-file or tls-ca-cert-dir must be specified while tls-auth-clients is enabled");
return nullptr;
}
if (SSL_CTX_use_certificate_chain_file(ssl_ctx.get(), config->tls_cert_file.c_str()) != 1) {
error("Failed to load SSL certificate file: {}", fmt::streamed(SSLErrors{}));
return nullptr;
}
if (!config->tls_key_file_pass.empty()) {
SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx.get(), static_cast<void *>(const_cast<Config *>(config)));
SSL_CTX_set_default_passwd_cb(ssl_ctx.get(), [](char *buf, int size, int, void *cfg) -> int {
strncpy(buf, static_cast<const Config *>(cfg)->tls_key_file_pass.c_str(), size);
buf[size - 1] = '\0';
return static_cast<int>(strlen(buf));
});
}
if (SSL_CTX_use_PrivateKey_file(ssl_ctx.get(), config->tls_key_file.c_str(), SSL_FILETYPE_PEM) != 1) {
error("Failed to load SSL private key file: {}", fmt::streamed(SSLErrors{}));
return nullptr;
}
if (SSL_CTX_check_private_key(ssl_ctx.get()) != 1) {
error("Failed to check the loaded private key: {}", fmt::streamed(SSLErrors{}));
return nullptr;
}
if (!config->tls_ciphers.empty() && !SSL_CTX_set_cipher_list(ssl_ctx.get(), config->tls_ciphers.c_str())) {
error("Failed to set SSL ciphers: {}", fmt::streamed(SSLErrors{}));
return nullptr;
}
#ifdef SSL_OP_NO_TLSv1_3
if (!config->tls_ciphersuites.empty() && !SSL_CTX_set_ciphersuites(ssl_ctx.get(), config->tls_ciphersuites.c_str())) {
error("Failed to set SSL ciphersuites: {}", fmt::streamed(SSLErrors{}));
return nullptr;
}
#endif
return ssl_ctx;
}