@@ -56,11 +56,10 @@ namespace DB
5656namespace ErrorCodes
5757{
5858 extern const int RAFT_ERROR;
59- extern const int NO_ELEMENTS_IN_CONFIG;
6059 extern const int SUPPORT_IS_DISABLED;
6160 extern const int LOGICAL_ERROR;
6261 extern const int INVALID_CONFIG_PARAMETER;
63- extern const int BAD_ARGUMENTS ;
62+ extern const int OPENSSL_ERROR ;
6463}
6564
6665using namespace std ::chrono_literals;
@@ -70,47 +69,38 @@ namespace
7069
7170#if USE_SSL
7271
73- int callSetCertificate (SSL * ssl, void * arg )
72+ auto getSslContextProvider ( const Poco::Util::AbstractConfiguration & config, std::string_view key )
7473{
75- if (!arg)
76- return -1 ;
77-
78- const CertificateReloader::Data * data = reinterpret_cast <CertificateReloader::Data *>(arg);
79- return setCertificateCallback (ssl, data, getLogger (" SSLContext" ));
80- }
81-
82- void setSSLParams (nuraft::asio_service::options & asio_opts)
83- {
84- const Poco::Util::LayeredConfiguration & config = Poco::Util::Application::instance ().config ();
85- String certificate_file_property = " openSSL.server.certificateFile" ;
86- String private_key_file_property = " openSSL.server.privateKeyFile" ;
87- String root_ca_file_property = " openSSL.server.caConfig" ;
88-
89- if (!config.has (certificate_file_property))
90- throw Exception (ErrorCodes::NO_ELEMENTS_IN_CONFIG, " Server certificate file is not set." );
91-
92- if (!config.has (private_key_file_property))
93- throw Exception (ErrorCodes::NO_ELEMENTS_IN_CONFIG, " Server private key file is not set." );
74+ String load_default_ca_file_property = fmt::format (" openSSL.{}.loadDefaultCAFile" , key);
75+ String verification_mode_property = fmt::format (" openSSL.{}.verificationMode" , key);
76+ String root_ca_file_property = fmt::format (" openSSL.{}.caConfig" , key);
77+ String private_key_passphrase_property = fmt::format (" openSSL.{}.privateKeyPassphraseHandler.options.password" , key);
9478
9579 Poco::Net::Context::Params params;
96- params.certificateFile = config.getString (certificate_file_property);
97- if (params.certificateFile .empty ())
98- throw Exception (ErrorCodes::BAD_ARGUMENTS, " Server certificate file in config '{}' is empty" , certificate_file_property);
80+ String certificate_file_property = fmt::format (" openSSL.{}.certificateFile" , key);
81+ String private_key_file_property = fmt::format (" openSSL.{}.privateKeyFile" , key);
82+ if (config.has (certificate_file_property))
83+ params.certificateFile = config.getString (certificate_file_property);
9984
100- params.privateKeyFile = config.getString (private_key_file_property);
101- if (params.privateKeyFile .empty ())
102- throw Exception (ErrorCodes::BAD_ARGUMENTS, " Server key file in config '{}' is empty" , private_key_file_property);
85+ if (config.has (private_key_file_property))
86+ params.privateKeyFile = config.getString (private_key_file_property);
10387
104- auto pass_phrase = config.getString (" openSSL.server.privateKeyPassphraseHandler.options.password" , " " );
105- auto certificate_data = std::make_shared<CertificateReloader::Data>(params.certificateFile , params.privateKeyFile , pass_phrase);
88+ std::shared_ptr<CertificateReloader::Data> certificate_data;
89+ if (config.has (private_key_passphrase_property))
90+ {
91+ certificate_data = std::make_shared<CertificateReloader::Data>(
92+ params.certificateFile , params.privateKeyFile , config.getString (private_key_passphrase_property));
93+ params.certificateFile .clear ();
94+ params.privateKeyFile .clear ();
95+ }
10696
10797 if (config.has (root_ca_file_property))
10898 params.caLocation = config.getString (root_ca_file_property);
10999
110- params.loadDefaultCAs = config.getBool (" openSSL.server.loadDefaultCAFile " , false );
111- params.verificationMode = Poco::Net::Utility::convertVerificationMode (config.getString (" openSSL.server.verificationMode " , " none" ));
100+ params.loadDefaultCAs = config.getBool (load_default_ca_file_property , false );
101+ params.verificationMode = Poco::Net::Utility::convertVerificationMode (config.getString (verification_mode_property , " none" ));
112102
113- std::string disabled_protocols_list = config.getString (" openSSL.server .disableProtocols" , " " );
103+ std::string disabled_protocols_list = config.getString (fmt::format ( " openSSL.{} .disableProtocols" , key) , " " );
114104 Poco::StringTokenizer dp_tok (disabled_protocols_list, " ;," , Poco::StringTokenizer::TOK_TRIM | Poco::StringTokenizer::TOK_IGNORE_EMPTY);
115105 int disabled_protocols = 0 ;
116106 for (const auto & token : dp_tok)
@@ -127,21 +117,54 @@ void setSSLParams(nuraft::asio_service::options & asio_opts)
127117 disabled_protocols |= Poco::Net::Context::PROTO_TLSV1_2;
128118 }
129119
130- asio_opts.ssl_context_provider_server_ = [params, certificate_data, disabled_protocols]
120+ auto prefer_server_cypher = config.getBool (fmt::format (" openSSL.{}.preferServerCiphers" , key), false );
121+ auto cache_sessions = config.getBool (fmt::format (" openSSL.{}.cache_sessions" , key), false );
122+ return [params, disabled_protocols, prefer_server_cypher, cache_sessions, is_server = key == " server" , certificate_data]
131123 {
132- Poco::Net::Context context (Poco::Net::Context::Usage::TLSV1_2_SERVER_USE , params);
124+ Poco::Net::Context context (is_server ? Poco::Net::Context::Usage::SERVER_USE : Poco::Net::Context::Usage::CLIENT_USE , params);
133125 context.disableProtocols (disabled_protocols);
134- SSL_CTX * ssl_ctx = context.takeSslContext ();
135- SSL_CTX_set_cert_cb (ssl_ctx, callSetCertificate, reinterpret_cast <void *>(certificate_data.get ()));
136- return ssl_ctx;
137- };
138126
139- asio_opts.ssl_context_provider_client_ = [ctx_params = std::move (params)]
140- {
141- Poco::Net::Context context (Poco::Net::Context::Usage::TLSV1_2_CLIENT_USE, ctx_params);
127+ if (prefer_server_cypher)
128+ context.preferServerCiphers ();
129+
130+ if (cache_sessions)
131+ context.enableSessionCache ();
132+
133+ auto * ssl_ctx = context.sslContext ();
134+ if (certificate_data)
135+ {
136+ if (auto err = SSL_CTX_clear_chain_certs (ssl_ctx); err != 1 )
137+ throw Exception (ErrorCodes::OPENSSL_ERROR, " Clear certificates {}" , Poco::Net::Utility::getLastError ());
138+
139+ if (auto err = SSL_CTX_use_certificate (ssl_ctx, const_cast <X509 *>(certificate_data->certs_chain [0 ].certificate ())); err != 1 )
140+ throw Exception (ErrorCodes::OPENSSL_ERROR, " Use certificate {}" , Poco::Net::Utility::getLastError ());
141+
142+ for (auto cert = certificate_data->certs_chain .begin () + 1 ; cert != certificate_data->certs_chain .end (); cert++)
143+ {
144+ if (auto err = SSL_CTX_add1_chain_cert (ssl_ctx, const_cast <X509 *>(cert->certificate ())); err != 1 )
145+ throw Exception (ErrorCodes::OPENSSL_ERROR, " Add certificate to chain {}" , Poco::Net::Utility::getLastError ());
146+ }
147+
148+ if (auto err = SSL_CTX_use_PrivateKey (ssl_ctx, const_cast <EVP_PKEY *>(static_cast <const EVP_PKEY *>(certificate_data->key ))); err != 1 )
149+ throw Exception (ErrorCodes::OPENSSL_ERROR, " Use private key {}" , Poco::Net::Utility::getLastError ());
150+
151+ if (auto err = SSL_CTX_check_private_key (ssl_ctx); err != 1 )
152+ throw Exception (ErrorCodes::OPENSSL_ERROR, " Unusable key-pair {}" , Poco::Net::Utility::getLastError ());
153+ }
154+
155+
142156 return context.takeSslContext ();
143157 };
144158}
159+
160+ void setSSLParams (nuraft::asio_service::options & asio_opts)
161+ {
162+ asio_opts.enable_ssl_ = true ;
163+
164+ const Poco::Util::LayeredConfiguration & config = Poco::Util::Application::instance ().config ();
165+ asio_opts.ssl_context_provider_server_ = getSslContextProvider (config, " server" );
166+ asio_opts.ssl_context_provider_client_ = getSslContextProvider (config, " client" );
167+ }
145168#endif
146169
147170std::string checkAndGetSuperdigest (const String & user_and_digest)
@@ -229,7 +252,7 @@ struct KeeperServer::KeeperRaftServer : public nuraft::raft_server
229252 }
230253
231254 const size_t voting_members = get_num_voting_members ();
232- const auto not_responding_peers = get_not_responding_peers ();
255+ const auto not_responding_peers = get_not_responding_peers_count ();
233256 const auto quorum_size = voting_members / 2 + 1 ;
234257 const auto max_not_responding_peers = voting_members - quorum_size;
235258
@@ -266,6 +289,11 @@ struct KeeperServer::KeeperRaftServer : public nuraft::raft_server
266289 return std::unique_lock (lock_);
267290 }
268291
292+ std::unique_lock<std::mutex> lockCommit ()
293+ {
294+ return std::unique_lock (commit_lock_);
295+ }
296+
269297 bool isCommitInProgress () const
270298 {
271299 return sm_commit_exec_in_progress_;
@@ -441,7 +469,6 @@ void KeeperServer::launchRaftServer(const Poco::Util::AbstractConfiguration & co
441469 throw Exception (ErrorCodes::SUPPORT_IS_DISABLED, " SSL support for NuRaft is disabled because ClickHouse was built without SSL support." );
442470#endif
443471 }
444-
445472 if (is_recovering)
446473 enterRecoveryMode (params);
447474
@@ -1200,6 +1227,7 @@ Keeper4LWInfo KeeperServer::getPartiallyFilled4LWInfo() const
12001227
12011228uint64_t KeeperServer::createSnapshot ()
12021229{
1230+ auto commit_lock = raft_instance->lockCommit ();
12031231 uint64_t log_idx = raft_instance->create_snapshot ();
12041232 if (log_idx != 0 )
12051233 LOG_INFO (log, " Snapshot creation scheduled with last committed log index {}." , log_idx);
0 commit comments