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..79775b12e25837 --- /dev/null +++ b/thirdparty/patches/brpc-zz-user-verify-callback-userdata.patch @@ -0,0 +1,253 @@ +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; + } + ++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) { + 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; ++ 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.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; + } + ++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) { + 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; ++ } ++ verify_cb = SSLVerifyCallbackProxy; ++ } ++ 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 +@@ -19,6 +19,7 @@ + #ifndef BRPC_SSL_HELPER_H + #define BRPC_SSL_HELPER_H + ++#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