From 98b75b74fd8e9970892828461aa530a2db6e846b Mon Sep 17 00:00:00 2001 From: lairongzeng Date: Mon, 1 Jun 2026 17:56:03 +0800 Subject: [PATCH 1/2] feat:Support for TLSv1.3 --- src/brpc/details/ssl_helper.cpp | 10 ++++- src/brpc/details/ssl_helper.h | 1 + src/brpc/ssl_options.cpp | 2 +- src/brpc/ssl_options.h | 4 +- test/brpc_ssl_unittest.cpp | 65 +++++++++++++++++++++++++++++++++ 5 files changed, 78 insertions(+), 4 deletions(-) diff --git a/src/brpc/details/ssl_helper.cpp b/src/brpc/details/ssl_helper.cpp index 322b9cc3ff..0e31f14b30 100644 --- a/src/brpc/details/ssl_helper.cpp +++ b/src/brpc/details/ssl_helper.cpp @@ -86,6 +86,8 @@ static int ParseSSLProtocols(const std::string& str_protocol) { protocol_flag |= TLSv1_1; } else if (strncasecmp(protocol.data(), "TLSv1.2", protocol.size()) == 0) { protocol_flag |= TLSv1_2; + } else if (strncasecmp(protocol.data(), "TLSv1.3", protocol.size()) == 0) { + protocol_flag |= TLSv1_3; } else { LOG(ERROR) << "Unknown SSL protocol=" << protocol; return -1; @@ -443,6 +445,12 @@ static int SetSSLOptions(SSL_CTX* ctx, const std::string& ciphers, ssloptions |= SSL_OP_NO_TLSv1_2; } #endif // SSL_OP_NO_TLSv1_2 + +#ifdef SSL_OP_NO_TLSv1_3 + if (!(protocols & TLSv1_3)) { + ssloptions |= SSL_OP_NO_TLSv1_3; + } +#endif // SSL_OP_NO_TLSv1_3 SSL_CTX_set_options(ctx, ssloptions); long sslmode = SSL_MODE_ENABLE_PARTIAL_WRITE @@ -585,7 +593,7 @@ SSL_CTX* CreateServerSSLContext(const std::string& certificate, return NULL; } - int protocols = TLSv1 | TLSv1_1 | TLSv1_2; + int protocols = TLSv1 | TLSv1_1 | TLSv1_2 | TLSv1_3; if (!options.disable_ssl3) { protocols |= SSLv3; } diff --git a/src/brpc/details/ssl_helper.h b/src/brpc/details/ssl_helper.h index da126b3943..a9b8736bfa 100644 --- a/src/brpc/details/ssl_helper.h +++ b/src/brpc/details/ssl_helper.h @@ -53,6 +53,7 @@ enum SSLProtocol { TLSv1 = 1 << 1, TLSv1_1 = 1 << 2, TLSv1_2 = 1 << 3, + TLSv1_3 = 1 << 4, }; struct FreeSSLCTX { diff --git a/src/brpc/ssl_options.cpp b/src/brpc/ssl_options.cpp index 748749ae82..efeab5c43a 100644 --- a/src/brpc/ssl_options.cpp +++ b/src/brpc/ssl_options.cpp @@ -27,7 +27,7 @@ VerifyOptions::VerifyOptions() ChannelSSLOptions::ChannelSSLOptions() : ciphers("DEFAULT") - , protocols("TLSv1, TLSv1.1, TLSv1.2") + , protocols("TLSv1, TLSv1.1, TLSv1.2, TLSv1.3") {} ServerSSLOptions::ServerSSLOptions() diff --git a/src/brpc/ssl_options.h b/src/brpc/ssl_options.h index 8ddda248a6..3fdb1e85bb 100644 --- a/src/brpc/ssl_options.h +++ b/src/brpc/ssl_options.h @@ -79,8 +79,8 @@ struct ChannelSSLOptions { std::string ciphers; // SSL protocols used for SSL handshake, separated by comma. - // Available protocols: SSLv3, TLSv1, TLSv1.1, TLSv1.2 - // Default: TLSv1, TLSv1.1, TLSv1.2 + // Available protocols: SSLv3, TLSv1, TLSv1.1, TLSv1.2, TLSv1.3 + // Default: TLSv1, TLSv1.1, TLSv1.2, TLSv1.3 std::string protocols; // When set, fill this into the SNI extension field during handshake, diff --git a/test/brpc_ssl_unittest.cpp b/test/brpc_ssl_unittest.cpp index a469a62386..f0202e1ee6 100644 --- a/test/brpc_ssl_unittest.cpp +++ b/test/brpc_ssl_unittest.cpp @@ -35,6 +35,7 @@ #include "brpc/channel.h" #include "brpc/socket_map.h" #include "brpc/controller.h" +#include "brpc/details/ssl_helper.h" #include "echo.pb.h" namespace brpc { @@ -497,3 +498,67 @@ TEST_F(SSLTest, ssl_perf) { close(clifd); close(servfd); } + + +#ifdef TLS1_3_VERSION + +TEST_F(SSLTest, tls13_protocol_string) { + brpc::Server server; + brpc::ServerOptions options; + brpc::CertInfo cert; + cert.certificate = "cert1.crt"; + cert.private_key = "cert1.key"; + options.mutable_ssl_options()->default_cert = cert; + + EchoServiceImpl echo_svc; + ASSERT_EQ(0, server.AddService( + &echo_svc, brpc::SERVER_DOESNT_OWN_SERVICE)); + brpc::PortRange pr(8613, 8623); + ASSERT_EQ(0, server.Start(pr, &options)); + const int port = server.listen_address().port; + + brpc::Channel channel; + brpc::ChannelOptions coptions; + coptions.mutable_ssl_options()->protocols = "TLSv1.3"; + ASSERT_EQ(0, channel.Init("127.0.0.1", port, &coptions)); + + brpc::Controller cntl; + test::EchoRequest req; + test::EchoResponse res; + req.set_message(EXP_REQUEST); + test::EchoService_Stub stub(&channel); + stub.Echo(&cntl, &req, &res, NULL); + ASSERT_FALSE(cntl.Failed()) << cntl.ErrorText(); + EXPECT_EQ(EXP_RESPONSE, res.message()); + // Client Controller::is_ssl() checks sending_sock which is cleared after + // RPC finishes, so verify SSL on the underlying socket instead. + + std::vector ids; + brpc::SocketMap2List(&ids); + ASSERT_EQ(1u, ids.size()); + brpc::SocketUniquePtr sock; + ASSERT_EQ(0, brpc::Socket::Address(ids[0], &sock)); + ASSERT_EQ(brpc::SSL_CONNECTED, sock->ssl_state()); + { + BAIDU_SCOPED_LOCK(sock->_ssl_session_mutex); + ASSERT_TRUE(sock->_ssl_session != NULL); + const char* version = SSL_get_version(sock->_ssl_session); + ASSERT_TRUE(version != NULL); + EXPECT_STREQ("TLSv1.3", version) << "negotiated protocol=" << version; + } + + ASSERT_EQ(0, server.Stop(0)); + ASSERT_EQ(0, server.Join()); +} + +#else // TLS1_3_VERSION + +TEST_F(SSLTest, tls13_protocol_string) { + brpc::ChannelSSLOptions opt; + opt.protocols = "TLSv1.3"; + SSL_CTX* ctx = brpc::CreateClientSSLContext(opt); + ASSERT_TRUE(ctx != NULL); + SSL_CTX_free(ctx); +} + +#endif // TLS1_3_VERSION From e8f2750893d32d837ded899488d9b156426169f2 Mon Sep 17 00:00:00 2001 From: lairongzeng Date: Tue, 2 Jun 2026 17:24:30 +0800 Subject: [PATCH 2/2] Align other UTs in this file --- test/brpc_ssl_unittest.cpp | 87 +++++++++++++++++++------------------- 1 file changed, 44 insertions(+), 43 deletions(-) diff --git a/test/brpc_ssl_unittest.cpp b/test/brpc_ssl_unittest.cpp index f0202e1ee6..00fe705edb 100644 --- a/test/brpc_ssl_unittest.cpp +++ b/test/brpc_ssl_unittest.cpp @@ -502,53 +502,54 @@ TEST_F(SSLTest, ssl_perf) { #ifdef TLS1_3_VERSION -TEST_F(SSLTest, tls13_protocol_string) { - brpc::Server server; - brpc::ServerOptions options; - brpc::CertInfo cert; - cert.certificate = "cert1.crt"; - cert.private_key = "cert1.key"; - options.mutable_ssl_options()->default_cert = cert; - - EchoServiceImpl echo_svc; - ASSERT_EQ(0, server.AddService( - &echo_svc, brpc::SERVER_DOESNT_OWN_SERVICE)); - brpc::PortRange pr(8613, 8623); - ASSERT_EQ(0, server.Start(pr, &options)); - const int port = server.listen_address().port; +void* tls13_do_handshake(void* arg) { + SSL* ssl = (SSL*)arg; + EXPECT_EQ(1, SSL_do_handshake(ssl)); + return NULL; +} - brpc::Channel channel; - brpc::ChannelOptions coptions; - coptions.mutable_ssl_options()->protocols = "TLSv1.3"; - ASSERT_EQ(0, channel.Init("127.0.0.1", port, &coptions)); +TEST_F(SSLTest, tls13_protocol_string) { + // Same style as ssl_perf: direct SSL handshake, no SocketMap / socket internals. + const butil::EndPoint ep(butil::IP_ANY, 8613); + butil::fd_guard listenfd(butil::tcp_listen(ep)); + ASSERT_GT(listenfd, 0); + int clifd = tcp_connect(ep, NULL); + ASSERT_GT(clifd, 0); + int servfd = accept(listenfd, NULL, NULL); + ASSERT_GT(servfd, 0); - brpc::Controller cntl; - test::EchoRequest req; - test::EchoResponse res; - req.set_message(EXP_REQUEST); - test::EchoService_Stub stub(&channel); - stub.Echo(&cntl, &req, &res, NULL); - ASSERT_FALSE(cntl.Failed()) << cntl.ErrorText(); - EXPECT_EQ(EXP_RESPONSE, res.message()); - // Client Controller::is_ssl() checks sending_sock which is cleared after - // RPC finishes, so verify SSL on the underlying socket instead. + brpc::ChannelSSLOptions opt; + opt.protocols = "TLSv1.3"; + SSL_CTX* cli_ctx = brpc::CreateClientSSLContext(opt); + ASSERT_NE(nullptr, cli_ctx); + SSL_CTX* serv_ctx = + brpc::CreateServerSSLContext("cert1.crt", "cert1.key", + brpc::SSLOptions(), NULL, NULL); + ASSERT_NE(nullptr, serv_ctx); + SSL* cli_ssl = brpc::CreateSSLSession(cli_ctx, 0, clifd, false); +#if defined(SSL_CTRL_SET_TLSEXT_HOSTNAME) || defined(USE_MESALINK) + SSL_set_tlsext_host_name(cli_ssl, "localhost"); +#endif + SSL* serv_ssl = brpc::CreateSSLSession(serv_ctx, 0, servfd, true); + ASSERT_NE(nullptr, cli_ssl); + ASSERT_NE(nullptr, serv_ssl); + pthread_t cpid; + pthread_t spid; + ASSERT_EQ(0, pthread_create(&cpid, NULL, tls13_do_handshake, cli_ssl)); + ASSERT_EQ(0, pthread_create(&spid, NULL, tls13_do_handshake, serv_ssl)); + ASSERT_EQ(0, pthread_join(cpid, NULL)); + ASSERT_EQ(0, pthread_join(spid, NULL)); - std::vector ids; - brpc::SocketMap2List(&ids); - ASSERT_EQ(1u, ids.size()); - brpc::SocketUniquePtr sock; - ASSERT_EQ(0, brpc::Socket::Address(ids[0], &sock)); - ASSERT_EQ(brpc::SSL_CONNECTED, sock->ssl_state()); - { - BAIDU_SCOPED_LOCK(sock->_ssl_session_mutex); - ASSERT_TRUE(sock->_ssl_session != NULL); - const char* version = SSL_get_version(sock->_ssl_session); - ASSERT_TRUE(version != NULL); - EXPECT_STREQ("TLSv1.3", version) << "negotiated protocol=" << version; - } + const char* version = SSL_get_version(cli_ssl); + ASSERT_TRUE(version != NULL); + EXPECT_STREQ("TLSv1.3", version) << "negotiated protocol=" << version; - ASSERT_EQ(0, server.Stop(0)); - ASSERT_EQ(0, server.Join()); + SSL_free(cli_ssl); + SSL_free(serv_ssl); + SSL_CTX_free(cli_ctx); + SSL_CTX_free(serv_ctx); + close(clifd); + close(servfd); } #else // TLS1_3_VERSION