From d45ca45859e0a1b2c3c96ff7e64fb3c3badd1527 Mon Sep 17 00:00:00 2001 From: Yukang-Lian Date: Thu, 27 Aug 2026 20:00:36 +0800 Subject: [PATCH 1/2] [feature](brpc) support custom TLS verify callbacks --- ...rpc-zz-user-verify-callback-userdata.patch | 225 ++++++++++++++++++ .../patches/brpc-zzz-fix-ssl-verify-set.patch | 7 + 2 files changed, 232 insertions(+) create mode 100644 thirdparty/patches/brpc-zz-user-verify-callback-userdata.patch create mode 100644 thirdparty/patches/brpc-zzz-fix-ssl-verify-set.patch diff --git a/thirdparty/patches/brpc-zz-user-verify-callback-userdata.patch b/thirdparty/patches/brpc-zz-user-verify-callback-userdata.patch new file mode 100644 index 00000000000000..12ff0f3943944a --- /dev/null +++ b/thirdparty/patches/brpc-zz-user-verify-callback-userdata.patch @@ -0,0 +1,225 @@ +diff --git a/src/brpc/ssl_options.h b/src/brpc/ssl_options.h +--- a/src/brpc/ssl_options.h ++++ b/src/brpc/ssl_options.h +@@ -22,6 +22,12 @@ + #include + #include + ++struct x509_store_ctx_st; ++ + namespace brpc { + ++typedef int (*SSLVerifyCallback)(int preverify_ok, ++ x509_store_ctx_st* store_ctx, ++ void* userdata); ++ + struct CertInfo { +@@ -62,2 +62,9 @@ + std::string ca_file_path; ++ ++ // Optional user verify callback invoked during handshake. ++ // Return 1 to continue, 0 to fail. ++ SSLVerifyCallback verify_callback; ++ ++ // Opaque pointer passed to verify_callback. ++ void* verify_userdata; + }; +diff --git a/src/brpc/ssl_options.cpp b/src/brpc/ssl_options.cpp +--- a/src/brpc/ssl_options.cpp ++++ b/src/brpc/ssl_options.cpp +@@ -23,1 +23,4 @@ +-VerifyOptions::VerifyOptions() : verify_depth(0) {} ++VerifyOptions::VerifyOptions() ++ : verify_depth(0) ++ , verify_callback(NULL) ++ , verify_userdata(NULL) {} +diff --git a/src/brpc/details/ssl_helper.cpp b/src/brpc/details/ssl_helper.cpp +--- a/src/brpc/details/ssl_helper.cpp ++++ b/src/brpc/details/ssl_helper.cpp +@@ -51,4 +51,70 @@ static bool IsPemString(const std::string& input) { + return false; + } + ++struct VerifyCallbackWrapper { ++ SSLVerifyCallback callback; ++ void* userdata; ++}; ++ ++static void FreeVerifyCallbackWrapper(void* parent, void* ptr, ++ CRYPTO_EX_DATA* ad, int idx, ++ long argl, void* argp) { ++ delete static_cast(ptr); ++} ++ ++static int GetVerifyCallbackWrapperIndex() { ++ static int index = SSL_CTX_get_ex_new_index( ++ 0, const_cast("brpc_ssl_verify_cb"), ++ NULL, NULL, FreeVerifyCallbackWrapper); ++ return index; ++} ++ ++static VerifyCallbackWrapper* GetVerifyCallbackWrapper(SSL_CTX* ctx) { ++ const int index = GetVerifyCallbackWrapperIndex(); ++ if (index < 0) { ++ return NULL; ++ } ++ return static_cast(SSL_CTX_get_ex_data(ctx, index)); ++} ++ ++static int SetVerifyCallbackWrapper(SSL_CTX* ctx, ++ SSLVerifyCallback callback, ++ void* userdata) { ++ const int index = GetVerifyCallbackWrapperIndex(); ++ if (index < 0) { ++ LOG(ERROR) << "Fail to get SSL_CTX ex data index for verify callback"; ++ return -1; ++ } ++ VerifyCallbackWrapper* wrapper = new (std::nothrow) VerifyCallbackWrapper(); ++ if (wrapper == NULL) { ++ LOG(ERROR) << "Fail to allocate verify callback wrapper"; ++ return -1; ++ } ++ wrapper->callback = callback; ++ wrapper->userdata = userdata; ++ if (SSL_CTX_set_ex_data(ctx, index, wrapper) != 1) { ++ delete wrapper; ++ LOG(ERROR) << "Fail to set SSL_CTX ex data for verify callback"; ++ return -1; ++ } ++ return 0; ++} ++ ++static int SSLVerifyCallbackProxy(int preverify_ok, X509_STORE_CTX* store_ctx) { ++ SSL* ssl = static_cast(X509_STORE_CTX_get_ex_data( ++ store_ctx, SSL_get_ex_data_X509_STORE_CTX_idx())); ++ if (ssl == NULL) { ++ return preverify_ok; ++ } ++ SSL_CTX* ctx = SSL_get_SSL_CTX(ssl); ++ if (ctx == NULL) { ++ return preverify_ok; ++ } ++ VerifyCallbackWrapper* wrapper = GetVerifyCallbackWrapper(ctx); ++ if (wrapper == NULL || wrapper->callback == NULL) { ++ return preverify_ok; ++ } ++ return wrapper->callback(preverify_ok, store_ctx, wrapper->userdata); ++} ++ + const char* SSLStateToString(SSLState s) { +@@ -413,4 +479,11 @@ static int SetSSLOptions(SSL_CTX* ctx, const std::string& ciphers, + // TODO: Verify the CNAME in certificate matches the requesting host + if (verify.verify_depth > 0) { +- SSL_CTX_set_verify(ctx, (SSL_VERIFY_PEER +- | SSL_VERIFY_FAIL_IF_NO_PEER_CERT), NULL); ++ const int verify_mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT; ++ int (*verify_cb)(int, X509_STORE_CTX*) = NULL; ++ if (verify.verify_callback != NULL) { ++ if (SetVerifyCallbackWrapper(ctx, verify.verify_callback, ++ verify.verify_userdata) != 0) { ++ return -1; ++ } ++ verify_cb = SSLVerifyCallbackProxy; ++ } ++ SSL_CTX_set_verify(ctx, verify_mode, verify_cb); ++ SSL_CTX_set_verify_depth(ctx, verify.verify_depth); + + diff --git a/src/brpc/details/mesalink_ssl_helper.cpp b/src/brpc/details/mesalink_ssl_helper.cpp +--- a/src/brpc/details/mesalink_ssl_helper.cpp ++++ b/src/brpc/details/mesalink_ssl_helper.cpp +@@ -45,4 +45,70 @@ static bool IsPemString(const std::string& input) { + return false; + } + ++struct VerifyCallbackWrapper { ++ SSLVerifyCallback callback; ++ void* userdata; ++}; ++ ++static void FreeVerifyCallbackWrapper(void* parent, void* ptr, ++ CRYPTO_EX_DATA* ad, int idx, ++ long argl, void* argp) { ++ delete static_cast(ptr); ++} ++ ++static int GetVerifyCallbackWrapperIndex() { ++ static int index = SSL_CTX_get_ex_new_index( ++ 0, const_cast("brpc_ssl_verify_cb"), ++ NULL, NULL, FreeVerifyCallbackWrapper); ++ return index; ++} ++ ++static VerifyCallbackWrapper* GetVerifyCallbackWrapper(SSL_CTX* ctx) { ++ const int index = GetVerifyCallbackWrapperIndex(); ++ if (index < 0) { ++ return NULL; ++ } ++ return static_cast(SSL_CTX_get_ex_data(ctx, index)); ++} ++ ++static int SetVerifyCallbackWrapper(SSL_CTX* ctx, ++ SSLVerifyCallback callback, ++ void* userdata) { ++ const int index = GetVerifyCallbackWrapperIndex(); ++ if (index < 0) { ++ LOG(ERROR) << "Fail to get SSL_CTX ex data index for verify callback"; ++ return -1; ++ } ++ VerifyCallbackWrapper* wrapper = new (std::nothrow) VerifyCallbackWrapper(); ++ if (wrapper == NULL) { ++ LOG(ERROR) << "Fail to allocate verify callback wrapper"; ++ return -1; ++ } ++ wrapper->callback = callback; ++ wrapper->userdata = userdata; ++ if (SSL_CTX_set_ex_data(ctx, index, wrapper) != 1) { ++ delete wrapper; ++ LOG(ERROR) << "Fail to set SSL_CTX ex data for verify callback"; ++ return -1; ++ } ++ return 0; ++} ++ ++static int SSLVerifyCallbackProxy(int preverify_ok, X509_STORE_CTX* store_ctx) { ++ SSL* ssl = static_cast(X509_STORE_CTX_get_ex_data( ++ store_ctx, SSL_get_ex_data_X509_STORE_CTX_idx())); ++ if (ssl == NULL) { ++ return preverify_ok; ++ } ++ SSL_CTX* ctx = SSL_get_SSL_CTX(ssl); ++ if (ctx == NULL) { ++ return preverify_ok; ++ } ++ VerifyCallbackWrapper* wrapper = GetVerifyCallbackWrapper(ctx); ++ if (wrapper == NULL || wrapper->callback == NULL) { ++ return preverify_ok; ++ } ++ return wrapper->callback(preverify_ok, store_ctx, wrapper->userdata); ++} ++ + const char* SSLStateToString(SSLState s) { +@@ -243,3 +309,10 @@ static int SetSSLOptions(SSL_CTX* ctx, const std::string& ciphers, + if (verify.verify_depth > 0) { +- SSL_CTX_set_verify(ctx, (SSL_VERIFY_PEER +- | SSL_VERIFY_FAIL_IF_NO_PEER_CERT), NULL); ++ const int verify_mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT; ++ if (verify.verify_callback != NULL) { ++ if (SetVerifyCallbackWrapper(ctx, verify.verify_callback, ++ verify.verify_userdata) != 0) { ++ return -1; ++ } ++ SSL_CTX_set_verify(ctx, verify_mode, SSLVerifyCallbackProxy); ++ } else { ++ SSL_CTX_set_verify(ctx, verify_mode, NULL); ++ } + } else { + SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); + } + +diff --git a/src/brpc/details/ssl_helper.h b/src/brpc/details/ssl_helper.h +--- a/src/brpc/details/ssl_helper.h ++++ b/src/brpc/details/ssl_helper.h +@@ -22,1 +22,2 @@ +-#include ++#include ++#include diff --git a/thirdparty/patches/brpc-zzz-fix-ssl-verify-set.patch b/thirdparty/patches/brpc-zzz-fix-ssl-verify-set.patch new file mode 100644 index 00000000000000..a82f578c5baab2 --- /dev/null +++ b/thirdparty/patches/brpc-zzz-fix-ssl-verify-set.patch @@ -0,0 +1,7 @@ +diff --git a/src/brpc/details/ssl_helper.cpp b/src/brpc/details/ssl_helper.cpp +--- a/src/brpc/details/ssl_helper.cpp ++++ b/src/brpc/details/ssl_helper.cpp +@@ -617,1 +617,2 @@ static int SetSSLOptions(SSL_CTX* ctx, const std::string& ciphers, +- SSL_CTX_set_verify_depth(ctx, verify.verify_depth); ++ SSL_CTX_set_verify(ctx, verify_mode, verify_cb); ++ SSL_CTX_set_verify_depth(ctx, verify.verify_depth); From b8fb0e5889ef2432a80a8997ca9a0d6e4459dc75 Mon Sep 17 00:00:00 2001 From: Yukang-Lian Date: Thu, 27 Aug 2026 21:08:40 +0800 Subject: [PATCH 2/2] [fix](thirdparty) make BRPC TLS callback patch portable --- ...rpc-zz-user-verify-callback-userdata.patch | 152 +++++++++++------- .../patches/brpc-zzz-fix-ssl-verify-set.patch | 7 - 2 files changed, 90 insertions(+), 69 deletions(-) delete mode 100644 thirdparty/patches/brpc-zzz-fix-ssl-verify-set.patch diff --git a/thirdparty/patches/brpc-zz-user-verify-callback-userdata.patch b/thirdparty/patches/brpc-zz-user-verify-callback-userdata.patch index 12ff0f3943944a..79775b12e25837 100644 --- a/thirdparty/patches/brpc-zz-user-verify-callback-userdata.patch +++ b/thirdparty/patches/brpc-zz-user-verify-callback-userdata.patch @@ -1,42 +1,8 @@ -diff --git a/src/brpc/ssl_options.h b/src/brpc/ssl_options.h ---- a/src/brpc/ssl_options.h -+++ b/src/brpc/ssl_options.h -@@ -22,6 +22,12 @@ - #include - #include - -+struct x509_store_ctx_st; -+ - namespace brpc { - -+typedef int (*SSLVerifyCallback)(int preverify_ok, -+ x509_store_ctx_st* store_ctx, -+ void* userdata); -+ - struct CertInfo { -@@ -62,2 +62,9 @@ - std::string ca_file_path; -+ -+ // Optional user verify callback invoked during handshake. -+ // Return 1 to continue, 0 to fail. -+ SSLVerifyCallback verify_callback; -+ -+ // Opaque pointer passed to verify_callback. -+ void* verify_userdata; - }; -diff --git a/src/brpc/ssl_options.cpp b/src/brpc/ssl_options.cpp ---- a/src/brpc/ssl_options.cpp -+++ b/src/brpc/ssl_options.cpp -@@ -23,1 +23,4 @@ --VerifyOptions::VerifyOptions() : verify_depth(0) {} -+VerifyOptions::VerifyOptions() -+ : verify_depth(0) -+ , verify_callback(NULL) -+ , verify_userdata(NULL) {} -diff --git a/src/brpc/details/ssl_helper.cpp b/src/brpc/details/ssl_helper.cpp ---- a/src/brpc/details/ssl_helper.cpp -+++ b/src/brpc/details/ssl_helper.cpp -@@ -51,4 +51,70 @@ static bool IsPemString(const std::string& input) { +diff --git a/src/brpc/details/mesalink_ssl_helper.cpp b/src/brpc/details/mesalink_ssl_helper.cpp +index afc3861359b13ec173c6d39257f3b0bc1ec27334..c2ce824ce7bbaf2c0c1d39767c5950c5555f58d3 100644 +--- a/src/brpc/details/mesalink_ssl_helper.cpp ++++ b/src/brpc/details/mesalink_ssl_helper.cpp +@@ -45,6 +45,72 @@ static bool IsPemString(const std::string& input) { return false; } @@ -107,27 +73,32 @@ diff --git a/src/brpc/details/ssl_helper.cpp b/src/brpc/details/ssl_helper.cpp +} + const char* SSLStateToString(SSLState s) { -@@ -413,4 +479,11 @@ static int SetSSLOptions(SSL_CTX* ctx, const std::string& ciphers, - // TODO: Verify the CNAME in certificate matches the requesting host - if (verify.verify_depth > 0) { + switch (s) { + case SSL_UNKNOWN: +@@ -249,8 +315,16 @@ static int SetSSLOptions(SSL_CTX* ctx, const std::string& ciphers, + return -1; + } + } - SSL_CTX_set_verify(ctx, (SSL_VERIFY_PEER - | SSL_VERIFY_FAIL_IF_NO_PEER_CERT), NULL); + const int verify_mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT; -+ int (*verify_cb)(int, X509_STORE_CTX*) = NULL; + if (verify.verify_callback != NULL) { + if (SetVerifyCallbackWrapper(ctx, verify.verify_callback, + verify.verify_userdata) != 0) { + return -1; + } -+ verify_cb = SSLVerifyCallbackProxy; ++ SSL_CTX_set_verify(ctx, verify_mode, SSLVerifyCallbackProxy); ++ } else { ++ SSL_CTX_set_verify(ctx, verify_mode, NULL); + } -+ SSL_CTX_set_verify(ctx, verify_mode, verify_cb); -+ SSL_CTX_set_verify_depth(ctx, verify.verify_depth); - - diff --git a/src/brpc/details/mesalink_ssl_helper.cpp b/src/brpc/details/mesalink_ssl_helper.cpp ---- a/src/brpc/details/mesalink_ssl_helper.cpp -+++ b/src/brpc/details/mesalink_ssl_helper.cpp -@@ -45,4 +45,70 @@ static bool IsPemString(const std::string& input) { + } else { + SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); + } +diff --git a/src/brpc/details/ssl_helper.cpp b/src/brpc/details/ssl_helper.cpp +index 81460aa99c4fb9b3bcd28be462d3b1b399a951e5..77e3cba731df97b134faf58d2c4a3b8eb6fdf036 100644 +--- a/src/brpc/details/ssl_helper.cpp ++++ b/src/brpc/details/ssl_helper.cpp +@@ -51,6 +51,72 @@ static bool IsPemString(const std::string& input) { return false; } @@ -198,28 +169,85 @@ diff --git a/src/brpc/details/ssl_helper.cpp b/src/brpc/details/ssl_helper.cpp +} + const char* SSLStateToString(SSLState s) { -@@ -243,3 +309,10 @@ static int SetSSLOptions(SSL_CTX* ctx, const std::string& ciphers, + switch (s) { + case SSL_UNKNOWN: +@@ -411,8 +477,16 @@ static int SetSSLOptions(SSL_CTX* ctx, const std::string& ciphers, + + // TODO: Verify the CNAME in certificate matches the requesting host if (verify.verify_depth > 0) { - SSL_CTX_set_verify(ctx, (SSL_VERIFY_PEER - | SSL_VERIFY_FAIL_IF_NO_PEER_CERT), NULL); + const int verify_mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT; ++ int (*verify_cb)(int, X509_STORE_CTX*) = NULL; + if (verify.verify_callback != NULL) { + if (SetVerifyCallbackWrapper(ctx, verify.verify_callback, + verify.verify_userdata) != 0) { + return -1; + } -+ SSL_CTX_set_verify(ctx, verify_mode, SSLVerifyCallbackProxy); -+ } else { -+ SSL_CTX_set_verify(ctx, verify_mode, NULL); ++ verify_cb = SSLVerifyCallbackProxy; + } - } else { - SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL); - } - ++ SSL_CTX_set_verify(ctx, verify_mode, verify_cb); + SSL_CTX_set_verify_depth(ctx, verify.verify_depth); + std::string cafile = verify.ca_file_path; + if (cafile.empty()) { diff --git a/src/brpc/details/ssl_helper.h b/src/brpc/details/ssl_helper.h +index 4f1e55b253b034e8a0d8a49b95cd456dd16bb4fc..23412cceb81427e4b46a175f3a8b5bf252ff4524 100644 --- a/src/brpc/details/ssl_helper.h +++ b/src/brpc/details/ssl_helper.h -@@ -22,1 +22,2 @@ --#include +@@ -19,6 +19,7 @@ + #ifndef BRPC_SSL_HELPER_H + #define BRPC_SSL_HELPER_H + +#include -+#include + #include + #ifndef USE_MESALINK + #include +diff --git a/src/brpc/ssl_options.cpp b/src/brpc/ssl_options.cpp +index e3b8f5b184fb83f1d036b44d6a0c1365490373a7..0c952a7b68f249a914bc55084b9771a0737538f3 100644 +--- a/src/brpc/ssl_options.cpp ++++ b/src/brpc/ssl_options.cpp +@@ -20,7 +20,10 @@ + + namespace brpc { + +-VerifyOptions::VerifyOptions() : verify_depth(0) {} ++VerifyOptions::VerifyOptions() ++ : verify_depth(0) ++ , verify_callback(NULL) ++ , verify_userdata(NULL) {} + + ChannelSSLOptions::ChannelSSLOptions() + : ciphers("DEFAULT") +diff --git a/src/brpc/ssl_options.h b/src/brpc/ssl_options.h +index 4e5d19c0c0fa2c3ddabbb7c987f7d60673090894..ce43ad2e1d68f162e819cb30ebfb2406eaae95b8 100644 +--- a/src/brpc/ssl_options.h ++++ b/src/brpc/ssl_options.h +@@ -22,8 +22,14 @@ + #include + #include + ++struct x509_store_ctx_st; ++ + namespace brpc { + ++typedef int (*SSLVerifyCallback)(int preverify_ok, ++ x509_store_ctx_st* store_ctx, ++ void* userdata); ++ + struct CertInfo { + // Certificate in PEM format. + // Note that CN and alt subjects will be extracted from the certificate, +@@ -54,6 +60,13 @@ struct VerifyOptions { + // If empty, use the system default CA files + // Default: "" + std::string ca_file_path; ++ ++ // Optional user verify callback invoked during handshake. ++ // Return 1 to continue, 0 to fail. ++ SSLVerifyCallback verify_callback; ++ ++ // Opaque pointer passed to verify_callback. ++ void* verify_userdata; + }; + + // SSL options at client side diff --git a/thirdparty/patches/brpc-zzz-fix-ssl-verify-set.patch b/thirdparty/patches/brpc-zzz-fix-ssl-verify-set.patch deleted file mode 100644 index a82f578c5baab2..00000000000000 --- a/thirdparty/patches/brpc-zzz-fix-ssl-verify-set.patch +++ /dev/null @@ -1,7 +0,0 @@ -diff --git a/src/brpc/details/ssl_helper.cpp b/src/brpc/details/ssl_helper.cpp ---- a/src/brpc/details/ssl_helper.cpp -+++ b/src/brpc/details/ssl_helper.cpp -@@ -617,1 +617,2 @@ static int SetSSLOptions(SSL_CTX* ctx, const std::string& ciphers, -- SSL_CTX_set_verify_depth(ctx, verify.verify_depth); -+ SSL_CTX_set_verify(ctx, verify_mode, verify_cb); -+ SSL_CTX_set_verify_depth(ctx, verify.verify_depth);