Skip to content

Commit b03ca1b

Browse files
authored
Merge pull request #768 from Altinity/backports/24.3/72730
24.3 Backport of ClickHouse#72730 - Fix advanced SSL configuration for Keeper's internal communication
2 parents e79dfb9 + 7c0e0bf commit b03ca1b

File tree

17 files changed

+232
-160
lines changed

17 files changed

+232
-160
lines changed

contrib/NuRaft

Submodule NuRaft updated 51 files

contrib/nuraft-cmake/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ set(SRCS
3232
"${LIBRARY_DIR}/src/handle_custom_notification.cxx"
3333
"${LIBRARY_DIR}/src/handle_vote.cxx"
3434
"${LIBRARY_DIR}/src/launcher.cxx"
35+
"${LIBRARY_DIR}/src/log_entry.cxx"
3536
"${LIBRARY_DIR}/src/srv_config.cxx"
3637
"${LIBRARY_DIR}/src/snapshot_sync_req.cxx"
3738
"${LIBRARY_DIR}/src/snapshot_sync_ctx.cxx"
@@ -50,6 +51,12 @@ else()
5051
target_compile_definitions(_nuraft PRIVATE USE_BOOST_ASIO=1 BOOST_ASIO_STANDALONE=1)
5152
endif()
5253

54+
target_link_libraries (_nuraft PRIVATE clickhouse_common_io)
55+
# We must have it PUBLIC here because some headers which depend on it directly
56+
# included in clickhouse
57+
target_compile_definitions(_nuraft PUBLIC USE_CLICKHOUSE_THREADS=1)
58+
MESSAGE(STATUS "Will use clickhouse threads for NuRaft")
59+
5360
target_include_directories (_nuraft SYSTEM PRIVATE "${LIBRARY_DIR}/include/libnuraft")
5461
# for some reason include "asio.h" directly without "boost/" prefix.
5562
target_include_directories (_nuraft SYSTEM PRIVATE "${ClickHouse_SOURCE_DIR}/contrib/boost/boost")

src/Coordination/Changelog.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2244,7 +2244,7 @@ uint64_t Changelog::getStartIndex() const
22442244
LogEntryPtr Changelog::getLastEntry() const
22452245
{
22462246
/// This entry treaded in special way by NuRaft
2247-
static LogEntryPtr fake_entry = nuraft::cs_new<nuraft::log_entry>(0, nuraft::buffer::alloc(sizeof(uint64_t)));
2247+
static LogEntryPtr fake_entry = nuraft::cs_new<nuraft::log_entry>(0, nuraft::buffer::alloc(0));
22482248

22492249
auto entry = entry_storage.getEntry(max_log_id);
22502250
if (entry == nullptr)

src/Coordination/InMemoryLogStore.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ ptr<log_entry> makeClone(const ptr<log_entry> & entry)
1616
InMemoryLogStore::InMemoryLogStore()
1717
: start_idx(1)
1818
{
19-
nuraft::ptr<nuraft::buffer> buf = nuraft::buffer::alloc(sizeof(uint64_t));
19+
nuraft::ptr<nuraft::buffer> buf = nuraft::buffer::alloc(0);
2020
logs[0] = nuraft::cs_new<nuraft::log_entry>(0, buf);
2121
}
2222

src/Coordination/KeeperServer.cpp

Lines changed: 72 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,10 @@ namespace DB
5656
namespace 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

6665
using 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

147170
std::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

12011228
uint64_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);

tests/config/config.d/database_replicated.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,19 @@
4444
<election_timeout_upper_bound_ms>5000</election_timeout_upper_bound_ms>
4545
<raft_logs_level>information</raft_logs_level>
4646
<force_sync>false</force_sync>
47+
<async_replication>1</async_replication>
4748
<!-- we want all logs for complex problems investigation -->
4849
<reserved_log_items>1000000000000000</reserved_log_items>
4950
</coordination_settings>
5051

52+
<feature_flags>
53+
<filtered_list>1</filtered_list>
54+
<multi_read>1</multi_read>
55+
<check_not_exists>1</check_not_exists>
56+
<create_if_not_exists>1</create_if_not_exists>
57+
<remove_recursive>1</remove_recursive>
58+
</feature_flags>
59+
5160
<raft_configuration>
5261
<server>
5362
<id>1</id>
Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
11
-----BEGIN CERTIFICATE-----
2-
MIIDPDCCAiQCFBXNOvsLA+dqmX/TkYG9JXdD5m72MA0GCSqGSIb3DQEBCwUAMFox
3-
CzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRl
4-
cm5ldCBXaWRnaXRzIFB0eSBMdGQxEzARBgNVBAMMCmNsaWNraG91c2UwIBcNMjIw
5-
NDIxMTAzNDU1WhgPMjEyMjAzMjgxMDM0NTVaMFkxCzAJBgNVBAYTAkFVMRMwEQYD
6-
VQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBM
7-
dGQxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
8-
AQoCggEBAKaXz596N4NC2zZdIqdwZbSYAtNdBCsBVPt5YT9F640aF5zOogPZyxGP
9-
ENyOZwABi/7HhwFbH657xyRvi8lTau8dZL+0tbakyoIn1Tw6j+/3GXTjLduJSy6C
10-
mOf4OzsrFC8mYgU+7p5ijvWVlO9h5NMbLdAPSIB5WSHhmSORH5LgjoK6oMOYdRod
11-
GmfHqSbwPVwy3Li5SXlniCQmJsM0zl64LFbJ/NU+13qETmhBiDgmh0Svi+wzSzqZ
12-
q1PIX92T3k44IXNZbvF7lKbUOS9Xb3BoxA4cDqRcTx4x73xRDwodSmqiuQOC99HI
13-
A0C/tZJ25VNAGjLKukPSHqYscq2PAsUCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEA
14-
IDQwjf/ja3TfOXrz+Gn1eErSKnWS3asjRT9rYWQsy3tzVUkMIcszrG+FqTR16g5H
15-
ZWyuEOi6KIRmda3SYKdLKmtQLrgx6/d/jvH5TQ0LTFZrp6vh0lo3pV+L6fLo1ZRD
16-
V1i8jW/7HHNyqJamUXOjwA0DpPOMkdtwuyV+rJ+2bTG1ZSK33O4Ae2CY5+dad6zy
17-
YI6b1c9flWfDznuNEMH7jDDjKgXwjZGeU53FiuuhHiNyRchsr/B9eIBsom8oykiD
18-
kch4cnAxx2E+m3hLYzupkXHOVQ5CNpVk8PGUCIGcyqDxPt+fOj1WbDQ9laEcfhmV
19-
kR+vHmzOqWZnHU4QeMqDig==
2+
MIIDtjCCAp6gAwIBAgIUdOfco+b8/fQZQOafHgghkEYL3YkwDQYJKoZIhvcNAQEL
3+
BQAwazELMAkGA1UEBhMCREUxDjAMBgNVBAgMBVN0YXRlMQ0wCwYDVQQHDARDaXR5
4+
MRAwDgYDVQQKDAdDb21wYW55MQ0wCwYDVQQLDARVbml0MRwwGgYDVQQDDBNUZXN0
5+
Y2x1c3RlciBSb290IENBMB4XDTI0MTIwMjE0MjkyNloXDTM0MTEzMDE0MjkyNlow
6+
ajELMAkGA1UEBhMCREUxDjAMBgNVBAgMBVN0YXRlMQ0wCwYDVQQHDARDaXR5MRAw
7+
DgYDVQQKDAdDb21wYW55MQ0wCwYDVQQLDARVbml0MRswGQYDVQQDDBJjbGlja2hv
8+
dXNlLWtlZXBlcjEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDUXmnn
9+
Cv7sY9lbrS1Q3c5q7ok9R4XEPq/jWBFkIEnJR7vSjCEnOjLxg+1MdUItjbqODf9N
10+
5vFbHiiqWQVkGrmg8/CTSme0qyNr7FcmG1hO4bzK/dvIyK1R7YISqZpXoCTVzEnU
11+
IjU7f+PkX2uAiSypxM4zpNyC7++j6ah8xYNRfR9AS5c7e1dvNKBNMmNipYxVgaEo
12+
pIke40m12ezIzLOtkL/rGlsnM2Tv/0Wv1xQE+OjHByyQE08vuliatFfweTXLF48m
13+
4S4NdOq5dh2WX8xLPr8BxRLjXzs08wgKVFpWkIOR2uEInjuVQAGMuZeOqUuQGdar
14+
GMH4M/3tDl0eJ7mbAgMBAAGjUzBRMB0GA1UdDgQWBBTr9ldBtTB0vatq2yhQgYtt
15+
zMNhJDAfBgNVHSMEGDAWgBTGSqv6LHbQlKrpPWtYEVoX+/c5cTAPBgNVHRMBAf8E
16+
BTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBYc03AV8n0D43xm07MxpgqDvNEZC9u
17+
Q2LnP89UBnBmXD5FwMz4XhA/iupyAeYItZ8R17caIpLHgwOUrh3oHxVW5V144Q0p
18+
hBBp/im8WQ8NnS3z52CusxE1Zu5AMjoZtxY8FTvgs6vuJZYds/dgtUg5bBawR2LX
19+
A5FsPLyYpwCjoPTM622uXkuPfRMc5SC5edwHa1RyoG8Poz8B6Y63iKQydOXin9Q1
20+
9rQ7mqM7D2dCURx4gVoN9y+fLkXgQEzTMBT4wuVJl+CXnxcmKsoROAy7g2mL0RMw
21+
P3cl+Bod3NrabhjAqG01nHsQzy0uJ/aJHbqoR3OtYo8DdsoKrBRramiG
2022
-----END CERTIFICATE-----
Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,28 @@
1-
-----BEGIN RSA PRIVATE KEY-----
2-
Proc-Type: 4,ENCRYPTED
3-
DEK-Info: AES-256-CBC,4E14FF586022476CD22AAFB662BB0E40
4-
5-
dpJZKq5k+fMuC7XECfTSRjPeOEl9wNuVtZkcjEWaHN8ky4umND7ARyRyuU1Nk7cy
6-
fpCFlFKOqDfCkT5zVK/fB6pF32wqAI7sqeSuYPfQY0+L77yRdwM6L46WslzVKZYE
7-
lXD1AmqKT/LgF3+eBY5slkAAJo10zYDgKEwnoQVBp31YW2/+6oAGaY/O6x3p7aTG
8-
dw9CP+SFc0o8lPl1lsSovdNXDUiVCftvClog7hwyDv8AhHyGgynw3UJXX8UlyWu+
9-
Zz5zpgrvB2gvDLeoZZ6qjMGvtpEwlYBh4de9ZOsvQUpXEEfkQFtJV0j613OCQune
10-
LoTxKpYV1V/mZX4HPaJ1oC0OJ7XcliAOSS9K49YobTuz7Kg5Wg3bVGo9xRfYDjch
11-
rVeMP4u5RXSGuHL23FPMfK6EqcldrFyRwLaY/IV1Yl6UNUMKAphn/WMtWVuT3TiT
12-
QMCI2VRt7ItwZwwFn5RgyDweWdFf5v3AmN/lOhATDBqosahkPxDZ1VZ6OBPoJLPM
13-
UrDWH/lqrByeEjtAOwr5UsWKwLuJ8qUxQ4TchHwFKOwy6VsrRwMQ3ZWi2govPF9I
14-
W0sfLj5Ulfjx6zHdqnF48a1Elit4JH6inBEWFuj7bmlOotq+PHoeT61zAwW+gnrG
15-
3JTo3XnaE2WwRDpqvKYHWLv/J218rq8PtIaq9gjr55odPfIt8lkJ1XzF4WQ21rIJ
16-
GNWZ3xz4fxpvrKnQyAKGu0ZcdjA1nqs16oiVr+UnJoXmkM5yBCic4fZYwPTSQHYS
17-
ZxwaTzEjfeGxrSeLrN9CgoweucvogOvUjJOBcW/py80du8vWz0YyzMhg3o0YeGME
18-
C+Kts/YWxmyfw4DaWt8RtWCKl85hEmz8RODvkMLGtLzvVoSyLQWqp1NhGIlFtzXs
19-
7sPLulUeyD2avTC/RB/Pu9Nk80c0368BxCoeYbiFWZpaN70SJmCUE5H59J2d0olw
20-
5v2RVjLBi8wqnzoa0+2L8wnG7IQGadS97dj0eBR+JXNtoJhVrurS80RJ6B0bNxdu
21-
gX8otfnJYsZyK5hbEhcQqLdnyGhDEE8YHe7Hv9stWwLAFOfOMzyzC06lFS1eNiw4
22-
FJyXJUhDieb8EqetouAC8dNVXz4Q1zOTlGuAbGoKm5v0U5IhCQap9GUSW5QiUgOQ
23-
AEMs9aGfd91R+IcDf19mZptsQLYA6MGBN6fm+3O2iZImKIbF+ZZo0S6liFFmn6lm
24-
M+diTzaoiqgEkiXOuRhdQUMaiGV8BMZxv8qUH6/vyC3gSueoTio0f9PfASDYfvXD
25-
A3GuI87P6LF1it2UlN6ssFoXTZdfQQZwRmNuqOqw+BJOJHrR6trcXOCZOQ77Qnvd
26-
M5a348gIzluVUkExAPGCsySQWMx4Of5NBF28jEC3+TAwkRqBV2ZHmfGLWnvwaB+A
27-
YUeKtpWblfG1lsrDAdwL2dilU95oby+35sExX7M2dCrL9Y2P5oTCW3u12//ZSLeL
28-
Yhi1Rzol6LAuesZCVF0Zv/YYDhzAckJfT/qXK5B5pz9saswxCUBEpiKlLpVsjOFJ
29-
2bHm8NgOMD5b3cdh1kvts4wZe+giry7LHsn46f+9VqN+gA6XxeVsPyb4uO1KW3SN
30-
-----END RSA PRIVATE KEY-----
1+
-----BEGIN PRIVATE KEY-----
2+
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDUXmnnCv7sY9lb
3+
rS1Q3c5q7ok9R4XEPq/jWBFkIEnJR7vSjCEnOjLxg+1MdUItjbqODf9N5vFbHiiq
4+
WQVkGrmg8/CTSme0qyNr7FcmG1hO4bzK/dvIyK1R7YISqZpXoCTVzEnUIjU7f+Pk
5+
X2uAiSypxM4zpNyC7++j6ah8xYNRfR9AS5c7e1dvNKBNMmNipYxVgaEopIke40m1
6+
2ezIzLOtkL/rGlsnM2Tv/0Wv1xQE+OjHByyQE08vuliatFfweTXLF48m4S4NdOq5
7+
dh2WX8xLPr8BxRLjXzs08wgKVFpWkIOR2uEInjuVQAGMuZeOqUuQGdarGMH4M/3t
8+
Dl0eJ7mbAgMBAAECggEAJwzxZlXESI2Xw17VzV/r/Ae+3rDPLSXly+U+1W2Gg+eX
9+
5wBzfDYcdgKvWPba42uDWWnDf3yu9vVVvvU9o4myhqE0pLDy3ur1SXwdDlnK5D5o
10+
K9+AUaxtCnqlB29+fQxqmZHGJabgqP88VZsiNnGC7/jLff2buswKAdcOb1sWaZ5F
11+
p5YBL6TmUzpg3Pdbs2N/OVsZGh5Y+d6m6hJgjsbdcWC4LrFurj9UyQoCGIRruelN
12+
Ra3ft4QAC3biD0/hEc4WyjzZdlMvvEqaeQUmqK2TJLELwyH33W1Ek2FsLm6LTP9i
13+
7kW2+9684GWBXo5ge87BXASVwAXnFE+pnXV5QGLMqQKBgQDpo2ZM/R/lWLR8Hpww
14+
WKZZFfWPpsv0d6DbwVWowdRoojPue62nIby6+LBk08j9UwqkC0TK8pWCjL4hhSfU
15+
JjLuGuzl+RFfstpt42qh2zgi8aedLtGHjFyjHp1jE3rb9l95YXUpNm7syEMbLR8V
16+
NR09na41ftFCBPBNYFsdxrzKPwKBgQDosd6qwhrTL+ndtiJIeonRvunjo4yXn22/
17+
qWqRy3WJmZpDKWpsGWOmlJ4G7+10Q3zOMpb+nUOEjJNI3EdnLrVTeJo8WNuNXHyl
18+
axgWV3TR8JT6GIG+zavGEI51JjTH3X1eGzm9T4Di8mj34FzyK1af6atiiRj5sIuk
19+
NG71CUjhpQKBgQCDJ90n3vjm0LMQ8kYPxdQsMm2VZLcd14IPmyqw/45z5opsmDVV
20+
m1TNSQoMr+8mdlWE3WaS3zcbAFNDkfJX39G7ZJYUS4t7Q3XnNkEH934975Z+YGfz
21+
RdJDJ86GbcsMa/QQuasBpbMDbTBusxe92gE+M6Q2F6j0/LzBUxQTVRtqFQKBgBFZ
22+
IXatnf5cthzXdVrd9+RxTVKxYMv1EOOXJ+DSwGKP1xZmwg5pHirPLbDqtlNSrL1a
23+
vDMjWmNJb7mg4pnou5ALj8QsA8JYQNq8T0FrJ8R3IUQ8C4BEKShNF7HYNVspQi1/
24+
7iAVC1DgLb89NPDBFmY5r5NbEUecR+zoE9Wk6ZAZAoGBAIHTifNzf7/qDtHI2+Cc
25+
YGiudMlWWwNqTUr1BjPQx1au1VImpDAB6eaz3DV0oIS0fpREte6SRrcwvtrRqp4M
26+
AT4uCjiVOaXW/MwybfS6BIivTvuTkyPuNCBIWTH1JBQ3CEcEIIV5YcpFDQs5FQ0M
27+
GPtHFxbKMUmLmJVW5nbKUUhr
28+
-----END PRIVATE KEY-----

0 commit comments

Comments
 (0)