Skip to content

Commit 897ea9c

Browse files
Denis Razinkinapolukhin
authored andcommitted
feat core: reuse ssl ctx for TLS server
Resolves #968 Tests: протестировано CI Pull Request resolved: #973 commit_hash:5e72ba8e59f34422c8efce70fa8c0542760b55da
1 parent 582368a commit 897ea9c

File tree

14 files changed

+499
-321
lines changed

14 files changed

+499
-321
lines changed

.mapping.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4712,6 +4712,7 @@
47124712
"universal/include/userver/crypto/public_key.hpp":"taxi/uservices/userver/universal/include/userver/crypto/public_key.hpp",
47134713
"universal/include/userver/crypto/random.hpp":"taxi/uservices/userver/universal/include/userver/crypto/random.hpp",
47144714
"universal/include/userver/crypto/signers.hpp":"taxi/uservices/userver/universal/include/userver/crypto/signers.hpp",
4715+
"universal/include/userver/crypto/ssl_ctx.hpp":"taxi/uservices/userver/universal/include/userver/crypto/ssl_ctx.hpp",
47154716
"universal/include/userver/crypto/verifiers.hpp":"taxi/uservices/userver/universal/include/userver/crypto/verifiers.hpp",
47164717
"universal/include/userver/decimal64/decimal64.hpp":"taxi/uservices/userver/universal/include/userver/decimal64/decimal64.hpp",
47174718
"universal/include/userver/decimal64/format_options.hpp":"taxi/uservices/userver/universal/include/userver/decimal64/format_options.hpp",
@@ -4957,6 +4958,7 @@
49574958
"universal/src/crypto/random.cpp":"taxi/uservices/userver/universal/src/crypto/random.cpp",
49584959
"universal/src/crypto/signature_test.cpp":"taxi/uservices/userver/universal/src/crypto/signature_test.cpp",
49594960
"universal/src/crypto/signers.cpp":"taxi/uservices/userver/universal/src/crypto/signers.cpp",
4961+
"universal/src/crypto/ssl_ctx.cpp":"taxi/uservices/userver/universal/src/crypto/ssl_ctx.cpp",
49604962
"universal/src/crypto/verifiers.cpp":"taxi/uservices/userver/universal/src/crypto/verifiers.cpp",
49614963
"universal/src/decimal64/decimal64.cpp":"taxi/uservices/userver/universal/src/decimal64/decimal64.cpp",
49624964
"universal/src/decimal64/decimal64_errors_test.cpp":"taxi/uservices/userver/universal/src/decimal64/decimal64_errors_test.cpp",

core/include/userver/engine/io/tls_wrapper.hpp

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include <userver/crypto/certificate.hpp>
1010
#include <userver/crypto/private_key.hpp>
11+
#include <userver/crypto/ssl_ctx.hpp>
1112
#include <userver/engine/deadline.hpp>
1213
#include <userver/engine/io/common.hpp>
1314
#include <userver/engine/io/socket.hpp>
@@ -40,13 +41,7 @@ class [[nodiscard]] TlsWrapper final : public RwBase {
4041
);
4142

4243
/// Starts a TLS server on an opened socket
43-
static TlsWrapper StartTlsServer(
44-
Socket&& socket,
45-
const crypto::CertificatesChain& cert_chain,
46-
const crypto::PrivateKey& key,
47-
Deadline deadline,
48-
const std::vector<crypto::Certificate>& extra_cert_authorities = {}
49-
);
44+
static TlsWrapper StartTlsServer(Socket&& socket, const crypto::SslCtx& ctx, Deadline deadline);
5045

5146
~TlsWrapper() override;
5247

core/src/clients/http/client_crl_test.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -315,13 +315,12 @@ struct TlsServer {
315315
auto deadline = engine::Deadline::FromDuration(utest::kMaxTestWaitTime);
316316
auto socket = tcp_listener.socket.Accept(deadline);
317317

318-
auto tls_server = engine::io::TlsWrapper::StartTlsServer(
319-
std::move(socket),
318+
crypto::SslCtx ssl_ctx = crypto::SslCtx::CreateServerTlsContext(
320319
crypto::LoadCertificatesChainFromString(kServerCertificate),
321320
crypto::PrivateKey::LoadFromString(kRevokedServerPrivateKey),
322-
deadline,
323321
cas
324322
);
323+
auto tls_server = engine::io::TlsWrapper::StartTlsServer(std::move(socket), ssl_ctx, deadline);
325324

326325
std::array<char, 2048> data{};
327326
const auto size = tls_server.RecvSome(data.data(), data.size(), deadline);

core/src/engine/io/tls_wrapper.cpp

Lines changed: 6 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,6 @@ USERVER_NAMESPACE_BEGIN
2121
namespace engine::io {
2222
namespace {
2323

24-
struct SslCtxDeleter {
25-
void operator()(SSL_CTX* ctx) const noexcept { SSL_CTX_free(ctx); }
26-
};
27-
using SslCtx = std::unique_ptr<SSL_CTX, SslCtxDeleter>;
28-
2924
struct SslDeleter {
3025
void operator()(SSL* ssl) const noexcept { SSL_free(ssl); }
3126
};
@@ -190,65 +185,11 @@ int SSL_write_ex(SSL* ssl, const void* data, size_t len, size_t* bytes_written)
190185
}
191186
#endif
192187

193-
SslCtx MakeSslCtx() {
194-
crypto::Openssl::Init();
195-
196-
SslCtx ssl_ctx{SSL_CTX_new(SSLv23_method())};
197-
if (!ssl_ctx) {
198-
throw TlsException(crypto::FormatSslError("Failed create an SSL context: SSL_CTX_new"));
199-
}
200-
#if OPENSSL_VERSION_NUMBER >= 0x010100000L
201-
if (1 != SSL_CTX_set_min_proto_version(ssl_ctx.get(), TLS1_VERSION)) {
202-
throw TlsException(crypto::FormatSslError("Failed create an SSL context: SSL_CTX_set_min_proto_version"));
203-
}
204-
#endif
205-
206-
constexpr auto options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION
207-
#if OPENSSL_VERSION_NUMBER >= 0x010100000L
208-
| SSL_OP_NO_RENEGOTIATION
209-
#endif
210-
;
211-
SSL_CTX_set_options(ssl_ctx.get(), options);
212-
SSL_CTX_set_mode(ssl_ctx.get(), SSL_MODE_ENABLE_PARTIAL_WRITE);
213-
SSL_CTX_clear_mode(ssl_ctx.get(), SSL_MODE_AUTO_RETRY);
214-
if (1 != SSL_CTX_set_default_verify_paths(ssl_ctx.get())) {
215-
LOG_LIMITED_WARNING() << crypto::FormatSslError("Failed create an SSL context: SSL_CTX_set_default_verify_paths"
216-
);
217-
}
218-
return ssl_ctx;
219-
}
220-
221188
enum InterruptAction {
222189
kPass,
223190
kFail,
224191
};
225192

226-
void SetServerName(SslCtx& ctx, std::string_view server_name) {
227-
if (server_name.empty()) {
228-
return;
229-
}
230-
231-
X509_VERIFY_PARAM* verify_param = SSL_CTX_get0_param(ctx.get());
232-
if (!verify_param) {
233-
throw TlsException("Failed to set up client TLS wrapper: SSL_CTX_get0_param");
234-
}
235-
if (1 != X509_VERIFY_PARAM_set1_host(verify_param, server_name.data(), server_name.size())) {
236-
throw TlsException(crypto::FormatSslError("Failed to set up client TLS wrapper: X509_VERIFY_PARAM_set1_host"));
237-
}
238-
SSL_CTX_set_verify(ctx.get(), SSL_VERIFY_PEER, nullptr);
239-
}
240-
241-
void AddCertAuthorities(SslCtx& ctx, const std::vector<crypto::Certificate>& cert_authorities) {
242-
UASSERT(!cert_authorities.empty());
243-
auto* store = SSL_CTX_get_cert_store(ctx.get());
244-
UASSERT(store);
245-
for (const auto& ca : cert_authorities) {
246-
if (1 != X509_STORE_add_cert(store, ca.GetNative())) {
247-
throw TlsException(crypto::FormatSslError("Failed to set up client TLS wrapper: X509_STORE_add_cert"));
248-
}
249-
}
250-
}
251-
252193
} // namespace
253194

254195
class TlsWrapper::ReadContextAccessor final : public engine::impl::ContextAccessor {
@@ -284,7 +225,7 @@ class TlsWrapper::Impl {
284225
SyncBioData(SSL_get_rbio(ssl.get()), &other.bio_data);
285226
}
286227

287-
void SetUp(SslCtx&& ssl_ctx) {
228+
void SetUp(const crypto::SslCtx& ssl_ctx) {
288229
Bio socket_bio{BIO_new(GetSocketBioMethod())};
289230
if (!socket_bio) {
290231
throw TlsException(crypto::FormatSslError("Failed to set up TLS wrapper: BIO_new"));
@@ -293,7 +234,7 @@ class TlsWrapper::Impl {
293234
SyncBioData(socket_bio.get(), nullptr);
294235
BIO_set_init(socket_bio.get(), 1);
295236

296-
ssl.reset(SSL_new(ssl_ctx.get()));
237+
ssl.reset(SSL_new(static_cast<SSL_CTX*>(ssl_ctx.GetRawSslCtx())));
297238
if (!ssl) {
298239
throw TlsException(crypto::FormatSslError("Failed to set up TLS wrapper: SSL_new"));
299240
}
@@ -489,11 +430,8 @@ engine::impl::ContextAccessor& TlsWrapper::ReadContextAccessor::GetSocketContext
489430
TlsWrapper::TlsWrapper(Socket&& socket) : impl_(std::move(socket)) { SetupContextAccessors(); }
490431

491432
TlsWrapper TlsWrapper::StartTlsClient(Socket&& socket, const std::string& server_name, Deadline deadline) {
492-
auto ssl_ctx = MakeSslCtx();
493-
SetServerName(ssl_ctx, server_name);
494-
495433
TlsWrapper wrapper{std::move(socket)};
496-
wrapper.impl_->SetUp(std::move(ssl_ctx));
434+
wrapper.impl_->SetUp(crypto::SslCtx::CreateClientTlsContext(server_name));
497435
wrapper.impl_->ClientConnect(server_name, deadline);
498436
return wrapper;
499437
}
@@ -506,79 +444,15 @@ TlsWrapper TlsWrapper::StartTlsClient(
506444
Deadline deadline,
507445
const std::vector<crypto::Certificate>& extra_cert_authorities
508446
) {
509-
auto ssl_ctx = MakeSslCtx();
510-
SetServerName(ssl_ctx, server_name);
511-
512-
if (!extra_cert_authorities.empty()) {
513-
AddCertAuthorities(ssl_ctx, extra_cert_authorities);
514-
}
515-
516-
if (cert) {
517-
if (1 != SSL_CTX_use_certificate(ssl_ctx.get(), cert.GetNative())) {
518-
throw TlsException(crypto::FormatSslError("Failed to set up client TLS wrapper: SSL_CTX_use_certificate"));
519-
}
520-
}
521-
522-
if (key) {
523-
if (1 != SSL_CTX_use_PrivateKey(ssl_ctx.get(), key.GetNative())) {
524-
throw TlsException(crypto::FormatSslError("Failed to set up client TLS wrapper: SSL_CTX_use_PrivateKey"));
525-
}
526-
}
527-
528447
TlsWrapper wrapper{std::move(socket)};
529-
wrapper.impl_->SetUp(std::move(ssl_ctx));
448+
wrapper.impl_->SetUp(crypto::SslCtx::CreateClientTlsContext(server_name, cert, key, extra_cert_authorities));
530449
wrapper.impl_->ClientConnect(server_name, deadline);
531450
return wrapper;
532451
}
533452

534-
TlsWrapper TlsWrapper::StartTlsServer(
535-
Socket&& socket,
536-
const crypto::CertificatesChain& cert_chain,
537-
const crypto::PrivateKey& key,
538-
Deadline deadline,
539-
const std::vector<crypto::Certificate>& extra_cert_authorities
540-
) {
541-
auto ssl_ctx = MakeSslCtx();
542-
543-
if (!extra_cert_authorities.empty()) {
544-
AddCertAuthorities(ssl_ctx, extra_cert_authorities);
545-
SSL_CTX_set_verify(ssl_ctx.get(), SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr);
546-
LOG_INFO() << "Client SSL cert will be verified";
547-
} else {
548-
LOG_INFO() << "Client SSL cert will not be verified";
549-
}
550-
551-
if (cert_chain.empty()) {
552-
throw TlsException(crypto::FormatSslError("Empty certificate chain provided"));
553-
}
554-
555-
if (1 != SSL_CTX_use_certificate(ssl_ctx.get(), cert_chain.begin()->GetNative())) {
556-
throw TlsException(crypto::FormatSslError("Failed to set up server TLS wrapper: SSL_CTX_use_certificate"));
557-
}
558-
559-
if (cert_chain.size() > 1) {
560-
auto cert_it = std::next(cert_chain.begin());
561-
for (; cert_it != cert_chain.end(); ++cert_it) {
562-
// cast in openssl1.0 macro expansion
563-
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
564-
if (SSL_CTX_add_extra_chain_cert(ssl_ctx.get(), cert_it->GetNative()) <= 0) {
565-
throw TlsException(
566-
crypto::FormatSslError("Failed to set up server TLS wrapper: SSL_CTX_add_extra_chain_cert")
567-
);
568-
}
569-
570-
// After SSL_CTX_add_extra_chain_cert we should not free the cert
571-
const auto ret = X509_up_ref(cert_it->GetNative());
572-
UASSERT(ret == 1);
573-
}
574-
}
575-
576-
if (1 != SSL_CTX_use_PrivateKey(ssl_ctx.get(), key.GetNative())) {
577-
throw TlsException(crypto::FormatSslError("Failed to set up server TLS wrapper: SSL_CTX_use_PrivateKey"));
578-
}
579-
453+
TlsWrapper TlsWrapper::StartTlsServer(Socket&& socket, const crypto::SslCtx& ctx, Deadline deadline) {
580454
TlsWrapper wrapper{std::move(socket)};
581-
wrapper.impl_->SetUp(std::move(ssl_ctx));
455+
wrapper.impl_->SetUp(ctx);
582456
wrapper.impl_->bio_data.current_deadline = deadline;
583457

584458
auto ret = SSL_accept(wrapper.impl_->ssl.get());

core/src/engine/io/tls_wrapper_benchmark.cpp

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,13 @@ constexpr auto kDeadlineMaxTime = std::chrono::seconds{60};
9393
auto [server, client] = tcp_listener.MakeSocketPair(deadline);
9494

9595
std::atomic<bool> reading{true};
96+
crypto::SslCtx ssl_ctx = crypto::SslCtx::CreateServerTlsContext(
97+
crypto::LoadCertificatesChainFromString(cert), crypto::PrivateKey::LoadFromString(key)
98+
);
9699
auto server_task = engine::AsyncNoSpan(
97-
[&reading, deadline](auto&& server) {
98-
auto tls_server = io::TlsWrapper::StartTlsServer(
99-
std::forward<decltype(server)>(server),
100-
crypto::LoadCertificatesChainFromString(cert),
101-
crypto::PrivateKey::LoadFromString(key),
102-
deadline
103-
);
100+
[&reading, deadline, &ssl_ctx](auto&& server) {
101+
auto tls_server =
102+
io::TlsWrapper::StartTlsServer(std::forward<decltype(server)>(server), ssl_ctx, deadline);
104103

105104
std::array<std::byte, 16'384> buf{};
106105
while (tls_server.RecvSome(buf.data(), buf.size(), deadline) > 0 && reading) {
@@ -137,14 +136,13 @@ BENCHMARK(tls_write_all_buffered)->RangeMultiplier(2)->Range(1 << 6, 1 << 12)->U
137136
auto [server, client] = tcp_listener.MakeSocketPair(deadline);
138137

139138
std::atomic<bool> reading{true};
139+
crypto::SslCtx ssl_ctx = crypto::SslCtx::CreateServerTlsContext(
140+
crypto::LoadCertificatesChainFromString(cert), crypto::PrivateKey::LoadFromString(key)
141+
);
140142
auto server_task = engine::AsyncNoSpan(
141-
[&reading, deadline](auto&& server) {
142-
auto tls_server = io::TlsWrapper::StartTlsServer(
143-
std::forward<decltype(server)>(server),
144-
crypto::LoadCertificatesChainFromString(cert),
145-
crypto::PrivateKey::LoadFromString(key),
146-
deadline
147-
);
143+
[&reading, deadline, &ssl_ctx](auto&& server) {
144+
auto tls_server =
145+
io::TlsWrapper::StartTlsServer(std::forward<decltype(server)>(server), ssl_ctx, deadline);
148146

149147
std::array<std::byte, 16'384> buf{};
150148
while (tls_server.RecvSome(buf.data(), buf.size(), deadline) > 0 && reading) {

0 commit comments

Comments
 (0)