You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pulsar.apache.org by pe...@apache.org on 2022/04/21 03:09:11 UTC

[pulsar] branch branch-2.9 updated: [branch-2.9][broker] Full-support set ssl provider, ciphers and protocols (#15226)

This is an automated email from the ASF dual-hosted git repository.

penghui pushed a commit to branch branch-2.9
in repository https://gitbox.apache.org/repos/asf/pulsar.git


The following commit(s) were added to refs/heads/branch-2.9 by this push:
     new 6b6a32d6cb1 [branch-2.9][broker] Full-support set ssl provider, ciphers and protocols (#15226)
6b6a32d6cb1 is described below

commit 6b6a32d6cb1f6f11d5c7e82cffd30a64ee11492e
Author: Zixuan Liu <no...@gmail.com>
AuthorDate: Thu Apr 21 11:09:05 2022 +0800

    [branch-2.9][broker] Full-support set ssl provider, ciphers and protocols (#15226)
---
 conf/broker.conf                                   |   8 +-
 conf/standalone.conf                               |   8 +-
 .../apache/pulsar/broker/ServiceConfiguration.java |   4 +-
 .../broker/service/PulsarChannelInitializer.java   |  15 ++-
 .../admin/internal/http/AsyncHttpConnector.java    |  26 ++--
 .../org/apache/pulsar/client/impl/HttpClient.java  |  38 +++---
 .../client/impl/PulsarChannelInitializer.java      |  47 +++++---
 .../util/NettyClientSslContextRefresher.java       |  43 +++++--
 .../common/util/NettyServerSslContextBuilder.java  |  16 ++-
 .../apache/pulsar/common/util/SecurityUtility.java |  71 +++++++----
 .../pulsar/common/util/netty/SslContextTest.java   | 132 +++++++++++++++++++++
 .../src/test/resources/ssl/jetty_client_key.jks    | Bin 0 -> 2679 bytes
 .../src/test/resources/ssl/jetty_client_trust.jks  | Bin 0 -> 1207 bytes
 .../src/test/resources/ssl/jetty_server_key.jks    | Bin 0 -> 2679 bytes
 .../src/test/resources/ssl/jetty_server_trust.jks  | Bin 0 -> 1207 bytes
 pulsar-common/src/test/resources/ssl/my-ca/ca.pem  |  18 +++
 .../src/test/resources/ssl/my-ca/client-ca.pem     |  19 +++
 .../src/test/resources/ssl/my-ca/client-key.pem    |  28 +++++
 .../src/test/resources/ssl/my-ca/server-ca.pem     |  19 +++
 .../src/test/resources/ssl/my-ca/server-key.pem    |  28 +++++
 .../pulsar/proxy/server/ProxyConfiguration.java    |   4 +-
 .../proxy/server/ServiceChannelInitializer.java    |  19 ++-
 22 files changed, 452 insertions(+), 91 deletions(-)

diff --git a/conf/broker.conf b/conf/broker.conf
index e36892e3584..849121f9fe8 100644
--- a/conf/broker.conf
+++ b/conf/broker.conf
@@ -594,13 +594,15 @@ tlsCiphers=
 # authentication.
 tlsRequireTrustedClientCertOnConnect=false
 
+# Specify the TLS provider for the broker service:
+# When using TLS authentication with CACert, the valid value is either OPENSSL or JDK.
+# When using TLS authentication with KeyStore, available values can be SunJSSE, Conscrypt and etc.
+tlsProvider=
+
 ### --- KeyStore TLS config variables --- ###
 # Enable TLS with KeyStore type configuration in broker.
 tlsEnabledWithKeyStore=false
 
-# TLS Provider for KeyStore type
-tlsProvider=
-
 # TLS KeyStore type configuration in broker: JKS, PKCS12
 tlsKeyStoreType=JKS
 
diff --git a/conf/standalone.conf b/conf/standalone.conf
index 577a6ffad42..16312125a02 100644
--- a/conf/standalone.conf
+++ b/conf/standalone.conf
@@ -357,13 +357,15 @@ tlsCiphers=
 # authentication.
 tlsRequireTrustedClientCertOnConnect=false
 
+# Specify the TLS provider for the broker service:
+# When using TLS authentication with CACert, the valid value is either OPENSSL or JDK.
+# When using TLS authentication with KeyStore, available values can be SunJSSE, Conscrypt and etc.
+tlsProvider=
+
 ### --- KeyStore TLS config variables --- ###
 # Enable TLS with KeyStore type configuration in broker.
 tlsEnabledWithKeyStore=false
 
-# TLS Provider for KeyStore type
-tlsProvider=
-
 # TLS KeyStore type configuration in broker: JKS, PKCS12
 tlsKeyStoreType=JKS
 
diff --git a/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/ServiceConfiguration.java b/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/ServiceConfiguration.java
index fa8464376fc..1e7eac5ef9a 100644
--- a/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/ServiceConfiguration.java
+++ b/pulsar-broker-common/src/main/java/org/apache/pulsar/broker/ServiceConfiguration.java
@@ -2237,7 +2237,9 @@ public class ServiceConfiguration implements PulsarConfiguration {
 
     @FieldContext(
             category = CATEGORY_KEYSTORE_TLS,
-            doc = "TLS Provider for KeyStore type"
+            doc = "TLS Provider for Specify the SSL provider for the broker service: \n"
+                    + "When using TLS authentication with CACert, the valid value is either OPENSSL or JDK.\n"
+                    + "When using TLS authentication with KeyStore, available values can be SunJSSE, Conscrypt and etc."
     )
     private String tlsProvider = null;
 
diff --git a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/PulsarChannelInitializer.java b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/PulsarChannelInitializer.java
index 831e56f4f5d..e75c518a50f 100644
--- a/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/PulsarChannelInitializer.java
+++ b/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/PulsarChannelInitializer.java
@@ -28,6 +28,7 @@ import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
 import io.netty.handler.flow.FlowControlHandler;
 import io.netty.handler.ssl.SslContext;
 import io.netty.handler.ssl.SslHandler;
+import io.netty.handler.ssl.SslProvider;
 import java.net.SocketAddress;
 import java.util.concurrent.TimeUnit;
 import lombok.Builder;
@@ -92,10 +93,18 @@ public class PulsarChannelInitializer extends ChannelInitializer<SocketChannel>
                         serviceConfig.getTlsProtocols(),
                         serviceConfig.getTlsCertRefreshCheckDurationSec());
             } else {
-                sslCtxRefresher = new NettyServerSslContextBuilder(serviceConfig.isTlsAllowInsecureConnection(),
-                        serviceConfig.getTlsTrustCertsFilePath(), serviceConfig.getTlsCertificateFilePath(),
+                SslProvider sslProvider = null;
+                if (serviceConfig.getTlsProvider() != null) {
+                    sslProvider = SslProvider.valueOf(serviceConfig.getTlsProvider());
+                }
+                sslCtxRefresher = new NettyServerSslContextBuilder(
+                        sslProvider,
+                        serviceConfig.isTlsAllowInsecureConnection(),
+                        serviceConfig.getTlsTrustCertsFilePath(),
+                        serviceConfig.getTlsCertificateFilePath(),
                         serviceConfig.getTlsKeyFilePath(),
-                        serviceConfig.getTlsCiphers(), serviceConfig.getTlsProtocols(),
+                        serviceConfig.getTlsCiphers(),
+                        serviceConfig.getTlsProtocols(),
                         serviceConfig.isTlsRequireTrustedClientCertOnConnect(),
                         serviceConfig.getTlsCertRefreshCheckDurationSec());
             }
diff --git a/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/http/AsyncHttpConnector.java b/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/http/AsyncHttpConnector.java
index 3e17a38da2b..1f302f6586c 100644
--- a/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/http/AsyncHttpConnector.java
+++ b/pulsar-client-admin/src/main/java/org/apache/pulsar/client/admin/internal/http/AsyncHttpConnector.java
@@ -21,6 +21,7 @@ package org.apache.pulsar.client.admin.internal.http;
 import io.netty.handler.codec.http.HttpRequest;
 import io.netty.handler.codec.http.HttpResponse;
 import io.netty.handler.ssl.SslContext;
+import io.netty.handler.ssl.SslProvider;
 import io.netty.util.concurrent.DefaultThreadFactory;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -137,21 +138,32 @@ public class AsyncHttpConnector implements Connector {
                     JsseSslEngineFactory sslEngineFactory = new JsseSslEngineFactory(sslCtx);
                     confBuilder.setSslEngineFactory(sslEngineFactory);
                 } else {
+                    SslProvider sslProvider = null;
+                    if (conf.getSslProvider() != null) {
+                        sslProvider = SslProvider.valueOf(conf.getSslProvider());
+                    }
                     SslContext sslCtx = null;
                     if (authData.hasDataForTls()) {
                         sslCtx = authData.getTlsTrustStoreStream() == null
                                 ? SecurityUtility.createAutoRefreshSslContextForClient(
-                                        conf.isTlsAllowInsecureConnection() || !conf.isTlsHostnameVerificationEnable(),
-                                        conf.getTlsTrustCertsFilePath(), authData.getTlsCerificateFilePath(),
-                                        authData.getTlsPrivateKeyFilePath(), null, autoCertRefreshTimeSeconds, delayer)
+                                sslProvider,
+                                conf.isTlsAllowInsecureConnection() || !conf.isTlsHostnameVerificationEnable(),
+                                conf.getTlsTrustCertsFilePath(), authData.getTlsCerificateFilePath(),
+                                authData.getTlsPrivateKeyFilePath(), null, autoCertRefreshTimeSeconds, delayer)
                                 : SecurityUtility.createNettySslContextForClient(
-                                        conf.isTlsAllowInsecureConnection() || !conf.isTlsHostnameVerificationEnable(),
-                                        authData.getTlsTrustStoreStream(), authData.getTlsCertificates(),
-                                        authData.getTlsPrivateKey());
+                                sslProvider,
+                                conf.isTlsAllowInsecureConnection() || !conf.isTlsHostnameVerificationEnable(),
+                                authData.getTlsTrustStoreStream(), authData.getTlsCertificates(),
+                                authData.getTlsPrivateKey(),
+                                conf.getTlsCiphers(),
+                                conf.getTlsProtocols());
                     } else {
                         sslCtx = SecurityUtility.createNettySslContextForClient(
+                                sslProvider,
                                 conf.isTlsAllowInsecureConnection() || !conf.isTlsHostnameVerificationEnable(),
-                                conf.getTlsTrustCertsFilePath());
+                                conf.getTlsTrustCertsFilePath(),
+                                conf.getTlsCiphers(),
+                                conf.getTlsProtocols());
                     }
                     confBuilder.setSslContext(sslCtx);
                 }
diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/HttpClient.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/HttpClient.java
index c295975ecd3..2a7e434cd38 100644
--- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/HttpClient.java
+++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/HttpClient.java
@@ -18,24 +18,24 @@
  */
 package org.apache.pulsar.client.impl;
 
+import io.netty.channel.EventLoopGroup;
+import io.netty.handler.codec.http.HttpRequest;
+import io.netty.handler.codec.http.HttpResponse;
+import io.netty.handler.ssl.SslContext;
+import io.netty.handler.ssl.SslProvider;
 import java.io.Closeable;
 import java.io.IOException;
 import java.net.HttpURLConnection;
 import java.net.InetSocketAddress;
 import java.net.URI;
 import java.net.URL;
+import java.security.GeneralSecurityException;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 import java.util.concurrent.CompletableFuture;
-
-import io.netty.channel.EventLoopGroup;
-import io.netty.handler.codec.http.HttpRequest;
-import io.netty.handler.codec.http.HttpResponse;
-import io.netty.handler.ssl.SslContext;
 import javax.net.ssl.SSLContext;
 import lombok.extern.slf4j.Slf4j;
-
 import org.apache.pulsar.PulsarVersion;
 import org.apache.pulsar.client.api.Authentication;
 import org.apache.pulsar.client.api.AuthenticationDataProvider;
@@ -111,25 +111,33 @@ public class HttpClient implements Closeable {
                     JsseSslEngineFactory sslEngineFactory = new JsseSslEngineFactory(sslCtx);
                     confBuilder.setSslEngineFactory(sslEngineFactory);
                 } else {
+                    SslProvider sslProvider = null;
+                    if (conf.getSslProvider() != null) {
+                        sslProvider = SslProvider.valueOf(conf.getSslProvider());
+                    }
                     SslContext sslCtx = null;
                     if (authData.hasDataForTls()) {
                         sslCtx = authData.getTlsTrustStoreStream() == null
-                                ? SecurityUtility.createNettySslContextForClient(conf.isTlsAllowInsecureConnection(),
-                                        conf.getTlsTrustCertsFilePath(), authData.getTlsCertificates(),
-                                        authData.getTlsPrivateKey())
-                                : SecurityUtility.createNettySslContextForClient(conf.isTlsAllowInsecureConnection(),
-                                        authData.getTlsTrustStoreStream(), authData.getTlsCertificates(),
-                                        authData.getTlsPrivateKey());
-                    }
-                    else {
+                                ? SecurityUtility.createNettySslContextForClient(sslProvider,
+                                conf.isTlsAllowInsecureConnection(),
+                                conf.getTlsTrustCertsFilePath(), authData.getTlsCertificates(),
+                                authData.getTlsPrivateKey(), conf.getTlsCiphers(), conf.getTlsProtocols())
+                                : SecurityUtility.createNettySslContextForClient(sslProvider,
+                                conf.isTlsAllowInsecureConnection(),
+                                authData.getTlsTrustStoreStream(), authData.getTlsCertificates(),
+                                authData.getTlsPrivateKey(), conf.getTlsCiphers(), conf.getTlsProtocols());
+                    } else {
                         sslCtx = SecurityUtility.createNettySslContextForClient(
+                                sslProvider,
                                 conf.isTlsAllowInsecureConnection(),
-                                conf.getTlsTrustCertsFilePath());
+                                conf.getTlsTrustCertsFilePath(), conf.getTlsCiphers(), conf.getTlsProtocols());
                     }
                     confBuilder.setSslContext(sslCtx);
                 }
 
                 confBuilder.setUseInsecureTrustManager(conf.isTlsAllowInsecureConnection());
+            } catch (GeneralSecurityException e) {
+                throw new PulsarClientException.InvalidConfigurationException(e);
             } catch (Exception e) {
                 throw new PulsarClientException.InvalidConfigurationException(e);
             }
diff --git a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/PulsarChannelInitializer.java b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/PulsarChannelInitializer.java
index b7a5fbadb42..497793d792d 100644
--- a/pulsar-client/src/main/java/org/apache/pulsar/client/impl/PulsarChannelInitializer.java
+++ b/pulsar-client/src/main/java/org/apache/pulsar/client/impl/PulsarChannelInitializer.java
@@ -18,6 +18,13 @@
  */
 package org.apache.pulsar.client.impl;
 
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
+import io.netty.handler.ssl.SslContext;
+import io.netty.handler.ssl.SslHandler;
+import io.netty.handler.ssl.SslProvider;
 import java.net.InetSocketAddress;
 import java.util.Objects;
 import java.util.concurrent.CompletableFuture;
@@ -36,13 +43,6 @@ import org.apache.pulsar.common.protocol.Commands;
 import org.apache.pulsar.common.util.SecurityUtility;
 import org.apache.pulsar.common.util.keystoretls.NettySSLContextAutoRefreshBuilder;
 
-import io.netty.channel.Channel;
-import io.netty.channel.ChannelInitializer;
-import io.netty.channel.socket.SocketChannel;
-import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
-import io.netty.handler.ssl.SslContext;
-import io.netty.handler.ssl.SslHandler;
-
 @Slf4j
 public class PulsarChannelInitializer extends ChannelInitializer<SocketChannel> {
 
@@ -93,19 +93,36 @@ public class PulsarChannelInitializer extends ChannelInitializer<SocketChannel>
 
             sslContextSupplier = new ObjectCache<SslContext>(() -> {
                 try {
+                    SslProvider sslProvider = null;
+                    if (conf.getSslProvider() != null) {
+                        sslProvider = SslProvider.valueOf(conf.getSslProvider());
+                    }
+
                     // Set client certificate if available
                     AuthenticationDataProvider authData = conf.getAuthentication().getAuthData();
                     if (authData.hasDataForTls()) {
                         return authData.getTlsTrustStoreStream() == null
-                                ? SecurityUtility.createNettySslContextForClient(conf.isTlsAllowInsecureConnection(),
-                                        conf.getTlsTrustCertsFilePath(),
-                                        authData.getTlsCertificates(), authData.getTlsPrivateKey())
-                                : SecurityUtility.createNettySslContextForClient(conf.isTlsAllowInsecureConnection(),
-                                        authData.getTlsTrustStoreStream(),
-                                        authData.getTlsCertificates(), authData.getTlsPrivateKey());
+                                ? SecurityUtility.createNettySslContextForClient(
+                                sslProvider,
+                                conf.isTlsAllowInsecureConnection(),
+                                conf.getTlsTrustCertsFilePath(),
+                                authData.getTlsCertificates(),
+                                authData.getTlsPrivateKey(),
+                                conf.getTlsCiphers(),
+                                conf.getTlsProtocols())
+                                : SecurityUtility.createNettySslContextForClient(sslProvider,
+                                conf.isTlsAllowInsecureConnection(),
+                                authData.getTlsTrustStoreStream(),
+                                authData.getTlsCertificates(), authData.getTlsPrivateKey(),
+                                conf.getTlsCiphers(),
+                                conf.getTlsProtocols());
                     } else {
-                        return SecurityUtility.createNettySslContextForClient(conf.isTlsAllowInsecureConnection(),
-                                conf.getTlsTrustCertsFilePath());
+                        return SecurityUtility.createNettySslContextForClient(
+                                sslProvider,
+                                conf.isTlsAllowInsecureConnection(),
+                                conf.getTlsTrustCertsFilePath(),
+                                conf.getTlsCiphers(),
+                                conf.getTlsProtocols());
                     }
                 } catch (Exception e) {
                     throw new RuntimeException("Failed to create TLS context", e);
diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/util/NettyClientSslContextRefresher.java b/pulsar-common/src/main/java/org/apache/pulsar/common/util/NettyClientSslContextRefresher.java
index 560746df7f6..e1fef9aaa9b 100644
--- a/pulsar-common/src/main/java/org/apache/pulsar/common/util/NettyClientSslContextRefresher.java
+++ b/pulsar-common/src/main/java/org/apache/pulsar/common/util/NettyClientSslContextRefresher.java
@@ -19,10 +19,12 @@
 package org.apache.pulsar.common.util;
 
 import io.netty.handler.ssl.SslContext;
+import io.netty.handler.ssl.SslProvider;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.security.GeneralSecurityException;
 import java.security.cert.X509Certificate;
+import java.util.Set;
 import javax.net.ssl.SSLException;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.pulsar.client.api.AuthenticationDataProvider;
@@ -33,19 +35,33 @@ import org.apache.pulsar.client.api.AuthenticationDataProvider;
 @Slf4j
 public class NettyClientSslContextRefresher extends SslContextAutoRefreshBuilder<SslContext> {
     private volatile SslContext sslNettyContext;
-    private boolean tlsAllowInsecureConnection;
+    private final boolean tlsAllowInsecureConnection;
     protected final FileModifiedTimeUpdater tlsTrustCertsFilePath;
-    private AuthenticationDataProvider authData;
+    protected final FileModifiedTimeUpdater tlsCertsFilePath;
+    protected final FileModifiedTimeUpdater tlsPrivateKeyFilePath;
+    private final AuthenticationDataProvider authData;
+    private final SslProvider sslProvider;
+    private final Set<String> ciphers;
+    private final Set<String> protocols;
 
-    public NettyClientSslContextRefresher(boolean allowInsecure,
+    public NettyClientSslContextRefresher(SslProvider sslProvider, boolean allowInsecure,
                                           String trustCertsFilePath,
                                           AuthenticationDataProvider authData,
+                                          Set<String> ciphers,
+                                          Set<String> protocols,
                                           long delayInSeconds)
             throws IOException, GeneralSecurityException {
         super(delayInSeconds);
         this.tlsAllowInsecureConnection = allowInsecure;
         this.tlsTrustCertsFilePath = new FileModifiedTimeUpdater(trustCertsFilePath);
         this.authData = authData;
+        this.tlsCertsFilePath = new FileModifiedTimeUpdater(
+                authData != null ? authData.getTlsCerificateFilePath() : null);
+        this.tlsPrivateKeyFilePath = new FileModifiedTimeUpdater(
+                authData != null ? authData.getTlsPrivateKeyFilePath() : null);
+        this.sslProvider = sslProvider;
+        this.ciphers = ciphers;
+        this.protocols = protocols;
     }
 
     @Override
@@ -53,15 +69,16 @@ public class NettyClientSslContextRefresher extends SslContextAutoRefreshBuilder
             throws SSLException, FileNotFoundException, GeneralSecurityException, IOException {
         if (authData != null && authData.hasDataForTls()) {
             this.sslNettyContext = authData.getTlsTrustStoreStream() == null
-                    ? SecurityUtility.createNettySslContextForClient(this.tlsAllowInsecureConnection,
-                            tlsTrustCertsFilePath.getFileName(), (X509Certificate[]) authData.getTlsCertificates(),
-                            authData.getTlsPrivateKey())
-                    : SecurityUtility.createNettySslContextForClient(this.tlsAllowInsecureConnection,
-                            authData.getTlsTrustStoreStream(), (X509Certificate[]) authData.getTlsCertificates(),
-                            authData.getTlsPrivateKey());
+                    ? SecurityUtility.createNettySslContextForClient(this.sslProvider, this.tlsAllowInsecureConnection,
+                    tlsTrustCertsFilePath.getFileName(), (X509Certificate[]) authData.getTlsCertificates(),
+                    authData.getTlsPrivateKey(), this.ciphers, this.protocols)
+                    : SecurityUtility.createNettySslContextForClient(this.sslProvider, this.tlsAllowInsecureConnection,
+                    authData.getTlsTrustStoreStream(), (X509Certificate[]) authData.getTlsCertificates(),
+                    authData.getTlsPrivateKey(), this.ciphers, this.protocols);
         } else {
-            this.sslNettyContext = SecurityUtility.createNettySslContextForClient(this.tlsAllowInsecureConnection,
-                    this.tlsTrustCertsFilePath.getFileName());
+            this.sslNettyContext =
+                    SecurityUtility.createNettySslContextForClient(this.sslProvider, this.tlsAllowInsecureConnection,
+                            this.tlsTrustCertsFilePath.getFileName(), this.ciphers, this.protocols);
         }
         return this.sslNettyContext;
     }
@@ -73,6 +90,8 @@ public class NettyClientSslContextRefresher extends SslContextAutoRefreshBuilder
 
     @Override
     public boolean needUpdate() {
-        return  tlsTrustCertsFilePath.checkAndRefresh();
+        return tlsTrustCertsFilePath.checkAndRefresh() || tlsCertsFilePath.checkAndRefresh()
+                || tlsPrivateKeyFilePath.checkAndRefresh();
+
     }
 }
diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/util/NettyServerSslContextBuilder.java b/pulsar-common/src/main/java/org/apache/pulsar/common/util/NettyServerSslContextBuilder.java
index 250e628f0de..e9fbb1f5e3e 100644
--- a/pulsar-common/src/main/java/org/apache/pulsar/common/util/NettyServerSslContextBuilder.java
+++ b/pulsar-common/src/main/java/org/apache/pulsar/common/util/NettyServerSslContextBuilder.java
@@ -19,6 +19,7 @@
 package org.apache.pulsar.common.util;
 
 import io.netty.handler.ssl.SslContext;
+import io.netty.handler.ssl.SslProvider;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.security.GeneralSecurityException;
@@ -36,8 +37,10 @@ public class NettyServerSslContextBuilder extends SslContextAutoRefreshBuilder<S
     protected final Set<String> tlsCiphers;
     protected final Set<String> tlsProtocols;
     protected final boolean tlsRequireTrustedClientCertOnConnect;
+    protected final SslProvider sslProvider;
 
-    public NettyServerSslContextBuilder(boolean allowInsecure, String trustCertsFilePath, String certificateFilePath,
+    public NettyServerSslContextBuilder(SslProvider sslProvider, boolean allowInsecure, String trustCertsFilePath,
+                                        String certificateFilePath,
                                         String keyFilePath, Set<String> ciphers, Set<String> protocols,
                                         boolean requireTrustedClientCertOnConnect,
                                         long delayInSeconds) {
@@ -49,14 +52,17 @@ public class NettyServerSslContextBuilder extends SslContextAutoRefreshBuilder<S
         this.tlsCiphers = ciphers;
         this.tlsProtocols = protocols;
         this.tlsRequireTrustedClientCertOnConnect = requireTrustedClientCertOnConnect;
+        this.sslProvider = sslProvider;
     }
 
     @Override
     public synchronized SslContext update()
-        throws SSLException, FileNotFoundException, GeneralSecurityException, IOException {
-        this.sslNettyContext = SecurityUtility.createNettySslContextForServer(tlsAllowInsecureConnection,
-                tlsTrustCertsFilePath.getFileName(), tlsCertificateFilePath.getFileName(), tlsKeyFilePath.getFileName(),
-                tlsCiphers, tlsProtocols, tlsRequireTrustedClientCertOnConnect);
+            throws SSLException, FileNotFoundException, GeneralSecurityException, IOException {
+        this.sslNettyContext =
+                SecurityUtility.createNettySslContextForServer(this.sslProvider, tlsAllowInsecureConnection,
+                        tlsTrustCertsFilePath.getFileName(), tlsCertificateFilePath.getFileName(),
+                        tlsKeyFilePath.getFileName(),
+                        tlsCiphers, tlsProtocols, tlsRequireTrustedClientCertOnConnect);
         return this.sslNettyContext;
     }
 
diff --git a/pulsar-common/src/main/java/org/apache/pulsar/common/util/SecurityUtility.java b/pulsar-common/src/main/java/org/apache/pulsar/common/util/SecurityUtility.java
index db8f861c789..d5a0c5a5767 100644
--- a/pulsar-common/src/main/java/org/apache/pulsar/common/util/SecurityUtility.java
+++ b/pulsar-common/src/main/java/org/apache/pulsar/common/util/SecurityUtility.java
@@ -21,6 +21,7 @@ package org.apache.pulsar.common.util;
 import io.netty.handler.ssl.ClientAuth;
 import io.netty.handler.ssl.SslContext;
 import io.netty.handler.ssl.SslContextBuilder;
+import io.netty.handler.ssl.SslProvider;
 import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
 import java.io.BufferedReader;
 import java.io.File;
@@ -111,7 +112,7 @@ public class SecurityUtility {
             return getBCProviderFromClassPath();
         } catch (Exception e) {
             log.warn("Not able to get Bouncy Castle provider for both FIPS and Non-FIPS from class path:", e);
-            throw new RuntimeException(e);
+            return null;
         }
     }
 
@@ -201,10 +202,13 @@ public class SecurityUtility {
         return createSslContext(allowInsecureConnection, trustCertificates, (Certificate[]) null, (PrivateKey) null);
     }
 
-    public static SslContext createNettySslContextForClient(boolean allowInsecureConnection, String trustCertsFilePath)
+    public static SslContext createNettySslContextForClient(SslProvider sslProvider, boolean allowInsecureConnection,
+                                                            String trustCertsFilePath, Set<String> ciphers,
+                                                            Set<String> protocols)
             throws GeneralSecurityException, SSLException, FileNotFoundException, IOException {
-        return createNettySslContextForClient(allowInsecureConnection, trustCertsFilePath, (Certificate[]) null,
-                (PrivateKey) null);
+        return createNettySslContextForClient(sslProvider, allowInsecureConnection, trustCertsFilePath,
+                (Certificate[]) null,
+                (PrivateKey) null, ciphers, protocols);
     }
 
     public static SSLContext createSslContext(boolean allowInsecureConnection, String trustCertsFilePath,
@@ -230,12 +234,15 @@ public class SecurityUtility {
      * @throws FileNotFoundException
      * @throws IOException
      */
-    public static SslContext createAutoRefreshSslContextForClient(boolean allowInsecureConnection,
-            String trustCertsFilePath, String certFilePath, String keyFilePath, String sslContextAlgorithm,
-            int refreshDurationSec, ScheduledExecutorService executor)
+    public static SslContext createAutoRefreshSslContextForClient(SslProvider sslProvider,
+                                                                  boolean allowInsecureConnection,
+                                                                  String trustCertsFilePath, String certFilePath,
+                                                                  String keyFilePath, String sslContextAlgorithm,
+                                                                  int refreshDurationSec,
+                                                                  ScheduledExecutorService executor)
             throws GeneralSecurityException, SSLException, FileNotFoundException, IOException {
         KeyManagerProxy keyManager = new KeyManagerProxy(certFilePath, keyFilePath, refreshDurationSec, executor);
-        SslContextBuilder sslContexBuilder = SslContextBuilder.forClient();
+        SslContextBuilder sslContexBuilder = SslContextBuilder.forClient().sslProvider(sslProvider);
         sslContexBuilder.keyManager(keyManager);
         if (allowInsecureConnection) {
             sslContexBuilder.trustManager(InsecureTrustManagerFactory.INSTANCE);
@@ -246,46 +253,62 @@ public class SecurityUtility {
         return sslContexBuilder.build();
     }
 
-    public static SslContext createNettySslContextForClient(boolean allowInsecureConnection, String trustCertsFilePath,
-            String certFilePath, String keyFilePath)
+    public static SslContext createNettySslContextForClient(SslProvider sslProvider, boolean allowInsecureConnection,
+                                                            String trustCertsFilePath,
+                                                            String certFilePath, String keyFilePath,
+                                                            Set<String> ciphers,
+                                                            Set<String> protocols)
             throws GeneralSecurityException, SSLException, FileNotFoundException, IOException {
         X509Certificate[] certificates = loadCertificatesFromPemFile(certFilePath);
         PrivateKey privateKey = loadPrivateKeyFromPemFile(keyFilePath);
-        return createNettySslContextForClient(allowInsecureConnection, trustCertsFilePath, certificates, privateKey);
+        return createNettySslContextForClient(sslProvider, allowInsecureConnection, trustCertsFilePath, certificates,
+                privateKey, ciphers, protocols);
     }
 
-    public static SslContext createNettySslContextForClient(boolean allowInsecureConnection, String trustCertsFilePath,
-            Certificate[] certificates, PrivateKey privateKey)
+    public static SslContext createNettySslContextForClient(SslProvider sslProvider, boolean allowInsecureConnection,
+                                                            String trustCertsFilePath,
+                                                            Certificate[] certificates, PrivateKey privateKey,
+                                                            Set<String> ciphers,
+                                                            Set<String> protocols)
             throws GeneralSecurityException, SSLException, FileNotFoundException, IOException {
 
         if (StringUtils.isNotBlank(trustCertsFilePath)) {
             try (FileInputStream trustCertsStream = new FileInputStream(trustCertsFilePath)) {
-                return createNettySslContextForClient(allowInsecureConnection, trustCertsStream, certificates,
-                        privateKey);
+                return createNettySslContextForClient(sslProvider, allowInsecureConnection, trustCertsStream,
+                        certificates,
+                        privateKey, ciphers, protocols);
             }
         } else {
-            return createNettySslContextForClient(allowInsecureConnection, (InputStream) null, certificates,
-                    privateKey);
+            return createNettySslContextForClient(sslProvider, allowInsecureConnection, (InputStream) null,
+                    certificates,
+                    privateKey, ciphers, protocols);
         }
     }
 
-    public static SslContext createNettySslContextForClient(boolean allowInsecureConnection,
-            InputStream trustCertsStream, Certificate[] certificates, PrivateKey privateKey)
+    public static SslContext createNettySslContextForClient(SslProvider sslProvider, boolean allowInsecureConnection,
+                                                            InputStream trustCertsStream, Certificate[] certificates,
+                                                            PrivateKey privateKey, Set<String> ciphers,
+                                                            Set<String> protocols)
             throws GeneralSecurityException, SSLException, FileNotFoundException, IOException {
-        SslContextBuilder builder = SslContextBuilder.forClient();
+        SslContextBuilder builder = SslContextBuilder.forClient().sslProvider(sslProvider);
         setupTrustCerts(builder, allowInsecureConnection, trustCertsStream);
         setupKeyManager(builder, privateKey, (X509Certificate[]) certificates);
+        setupCiphers(builder, ciphers);
+        setupProtocols(builder, protocols);
         return builder.build();
     }
 
-    public static SslContext createNettySslContextForServer(boolean allowInsecureConnection, String trustCertsFilePath,
-            String certFilePath, String keyFilePath, Set<String> ciphers, Set<String> protocols,
-            boolean requireTrustedClientCertOnConnect)
+    public static SslContext createNettySslContextForServer(SslProvider sslProvider, boolean allowInsecureConnection,
+                                                            String trustCertsFilePath,
+                                                            String certFilePath, String keyFilePath,
+                                                            Set<String> ciphers, Set<String> protocols,
+                                                            boolean requireTrustedClientCertOnConnect)
             throws GeneralSecurityException, SSLException, FileNotFoundException, IOException {
         X509Certificate[] certificates = loadCertificatesFromPemFile(certFilePath);
         PrivateKey privateKey = loadPrivateKeyFromPemFile(keyFilePath);
 
-        SslContextBuilder builder = SslContextBuilder.forServer(privateKey, (X509Certificate[]) certificates);
+        SslContextBuilder builder =
+                SslContextBuilder.forServer(privateKey, (X509Certificate[]) certificates).sslProvider(sslProvider);
         setupCiphers(builder, ciphers);
         setupProtocols(builder, protocols);
         if (StringUtils.isNotBlank(trustCertsFilePath)) {
diff --git a/pulsar-common/src/test/java/org/apache/pulsar/common/util/netty/SslContextTest.java b/pulsar-common/src/test/java/org/apache/pulsar/common/util/netty/SslContextTest.java
new file mode 100644
index 00000000000..0fbd2521ae0
--- /dev/null
+++ b/pulsar-common/src/test/java/org/apache/pulsar/common/util/netty/SslContextTest.java
@@ -0,0 +1,132 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.pulsar.common.util.netty;
+
+import static org.testng.Assert.assertThrows;
+import com.google.common.io.Resources;
+import io.netty.handler.ssl.SslProvider;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.util.HashSet;
+import java.util.Set;
+import javax.net.ssl.SSLException;
+import org.apache.pulsar.client.api.AuthenticationDataProvider;
+import org.apache.pulsar.client.api.KeyStoreParams;
+import org.apache.pulsar.common.util.NettyClientSslContextRefresher;
+import org.apache.pulsar.common.util.NettyServerSslContextBuilder;
+import org.apache.pulsar.common.util.keystoretls.NettySSLContextAutoRefreshBuilder;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+public class SslContextTest {
+    @DataProvider(name = "caCertSslContextDataProvider")
+    public static Object[][] getSslContextDataProvider() {
+        Set<String> ciphers = new HashSet<>();
+        ciphers.add("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384");
+        ciphers.add("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256");
+        ciphers.add("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256");
+        ciphers.add("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384");
+        ciphers.add("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384");
+
+        // Note: OPENSSL doesn't support these ciphers.
+        return new Object[][]{
+                new Object[]{SslProvider.JDK, ciphers},
+                new Object[]{SslProvider.JDK, null},
+
+                new Object[]{SslProvider.OPENSSL, ciphers},
+                new Object[]{SslProvider.OPENSSL, null},
+
+                new Object[]{null, ciphers},
+                new Object[]{null, null},
+        };
+    }
+
+    @DataProvider(name = "cipherDataProvider")
+    public static Object[] getCipher() {
+        Set<String> cipher = new HashSet<>();
+        cipher.add("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384");
+        cipher.add("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256");
+        cipher.add("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256");
+        cipher.add("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384");
+        cipher.add("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384");
+
+        return new Object[]{null, cipher};
+    }
+
+    @Test(dataProvider = "cipherDataProvider")
+    public void testServerKeyStoreSSLContext(Set<String> cipher) throws Exception {
+        NettySSLContextAutoRefreshBuilder contextAutoRefreshBuilder = new NettySSLContextAutoRefreshBuilder(null,
+                "JKS", Resources.getResource("ssl/jetty_server_key.jks").getPath(),
+                "jetty_server_pwd", false, "JKS",
+                Resources.getResource("ssl/jetty_server_trust.jks").getPath(),
+                "jetty_server_pwd", true, cipher,
+                null, 600);
+        contextAutoRefreshBuilder.update();
+    }
+
+    private static class ClientAuthenticationData implements AuthenticationDataProvider {
+        @Override
+        public KeyStoreParams getTlsKeyStoreParams() {
+            return null;
+        }
+    }
+
+    @Test(dataProvider = "cipherDataProvider")
+    public void testClientKeyStoreSSLContext(Set<String> cipher) throws Exception {
+        NettySSLContextAutoRefreshBuilder contextAutoRefreshBuilder = new NettySSLContextAutoRefreshBuilder(null,
+                false, "JKS", Resources.getResource("ssl/jetty_server_trust.jks").getPath(),
+                "jetty_server_pwd", cipher, null, 0, new ClientAuthenticationData());
+        contextAutoRefreshBuilder.update();
+    }
+
+    @Test(dataProvider = "caCertSslContextDataProvider")
+    public void testServerCaCertSslContextWithSslProvider(SslProvider sslProvider, Set<String> ciphers)
+            throws GeneralSecurityException, IOException {
+        NettyServerSslContextBuilder sslContext = new NettyServerSslContextBuilder(sslProvider,
+                true, Resources.getResource("ssl/my-ca/ca.pem").getPath(),
+                Resources.getResource("ssl/my-ca/server-ca.pem").getPath(),
+                Resources.getResource("ssl/my-ca/server-key.pem").getPath(),
+                ciphers,
+                null,
+                true, 60);
+        if (ciphers != null) {
+            if (sslProvider == null || sslProvider == SslProvider.OPENSSL) {
+                assertThrows(SSLException.class, sslContext::update);
+                return;
+            }
+        }
+        sslContext.update();
+    }
+
+    @Test(dataProvider = "caCertSslContextDataProvider")
+    public void testClientCaCertSslContextWithSslProvider(SslProvider sslProvider, Set<String> ciphers)
+            throws GeneralSecurityException, IOException {
+        NettyClientSslContextRefresher sslContext = new NettyClientSslContextRefresher(sslProvider,
+                true, Resources.getResource("ssl/my-ca/ca.pem").getPath(),
+                null, ciphers, null, 0);
+        if (ciphers != null) {
+            if (sslProvider == null || sslProvider == SslProvider.OPENSSL) {
+                assertThrows(SSLException.class, sslContext::update);
+                return;
+            }
+        }
+        sslContext.update();
+    }
+}
diff --git a/pulsar-common/src/test/resources/ssl/jetty_client_key.jks b/pulsar-common/src/test/resources/ssl/jetty_client_key.jks
new file mode 100644
index 00000000000..2b8ea64347d
Binary files /dev/null and b/pulsar-common/src/test/resources/ssl/jetty_client_key.jks differ
diff --git a/pulsar-common/src/test/resources/ssl/jetty_client_trust.jks b/pulsar-common/src/test/resources/ssl/jetty_client_trust.jks
new file mode 100644
index 00000000000..166a2e00fb3
Binary files /dev/null and b/pulsar-common/src/test/resources/ssl/jetty_client_trust.jks differ
diff --git a/pulsar-common/src/test/resources/ssl/jetty_server_key.jks b/pulsar-common/src/test/resources/ssl/jetty_server_key.jks
new file mode 100644
index 00000000000..b6189b75c8a
Binary files /dev/null and b/pulsar-common/src/test/resources/ssl/jetty_server_key.jks differ
diff --git a/pulsar-common/src/test/resources/ssl/jetty_server_trust.jks b/pulsar-common/src/test/resources/ssl/jetty_server_trust.jks
new file mode 100644
index 00000000000..b09cc030a71
Binary files /dev/null and b/pulsar-common/src/test/resources/ssl/jetty_server_trust.jks differ
diff --git a/pulsar-common/src/test/resources/ssl/my-ca/ca.pem b/pulsar-common/src/test/resources/ssl/my-ca/ca.pem
new file mode 100644
index 00000000000..3d5a80e2347
--- /dev/null
+++ b/pulsar-common/src/test/resources/ssl/my-ca/ca.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC9DCCAdygAwIBAgIUNbNkV2+K2Hf4Q1V5gdAENZQiLokwDQYJKoZIhvcNAQEL
+BQAwETEPMA0GA1UEAxMGUHVsc2FyMCAXDTIyMDExNDA0MjgwMFoYDzIxMjIwMTE2
+MDQyODAwWjARMQ8wDQYDVQQDEwZQdWxzYXIwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQDBR2K5EKVziLqdsz78efEW4lOwKiJ32e97uxn1Z6oKgkgImpVP
+Z9aoJB4EwSnDg+6FV2YULdWPm7C6W33tDmWRaU/Hlo/cOejnK8UmiMu/EyDpE2Wj
+n0RimGmwOkBi2IWIcIzWMmPDZ9kZc65OUeEmwZedKRy62PQyfCeNU4OOHQn3PXjI
+NbXJZD5TvBmn4SJn2RP9EgmIPaBAh/Mng045ZeHHLhwMKC8EOyHc2aB7AL6brymR
+xzsiYWdcJn4mqqMvT82mVvhkgAMOcR4CXYF8eYnsG6ZbDHb13CawcvLVREJZk7AB
+XZi9Rd5xczxHILM8rdkIZfunaG1X5hbih5wJAgMBAAGjQjBAMA4GA1UdDwEB/wQE
+AwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTCC1lYG+62cUPjNk9q4jCm
+Ps65njANBgkqhkiG9w0BAQsFAAOCAQEAKV2Lpu5cH5EsG53EWsYxEKvuQZ0LTxCE
+wCDf/NxJaQbzfv0tsbZatMge0vcZ/5r8tZZoOC+pGTwk6MaRbEFH8PmvlH1LIQvu
+Y34/YQZOy8wBTWwaIfFMnYWc0iAFoFt2Lzuq+GOI+svTFp729Ae8r7UxY/f9Lioc
+ttdGr7vA6PpcIMoEIPjVp+m41uL9IDfX8eOxg4gVlwtqpbHdTzMrOz0YY+3qH/WK
+6Qffw4pwitzAEj2zCn2lvGC5cbpd13SAaqtB3xL/Aet0SS2r3g9qDo1RruQhXUng
+06U/Hqtn5K1fNQv3pivi3Jg5z1DfJWHkH37luAoIlOZHRmPK6rhp/g==
+-----END CERTIFICATE-----
diff --git a/pulsar-common/src/test/resources/ssl/my-ca/client-ca.pem b/pulsar-common/src/test/resources/ssl/my-ca/client-ca.pem
new file mode 100644
index 00000000000..adcae3393ad
--- /dev/null
+++ b/pulsar-common/src/test/resources/ssl/my-ca/client-ca.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDHDCCAgSgAwIBAgIUJJpmKX3DnbUwJ7tUhCt8MTiwz0owDQYJKoZIhvcNAQEL
+BQAwETEPMA0GA1UEAxMGUHVsc2FyMCAXDTIyMDExNDA0MjgwMFoYDzIxMjExMjIx
+MDQyODAwWjARMQ8wDQYDVQQDEwZQdWxzYXIwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQDZN+CNZ1i1WaXulbwSASOfXErWXhGV9DHqavPp3DohgQdundfS
+648T/X80uWQlyxu4L4j0oc97jtzc1AyZFXj5nocVsveEO9aDjnYCc5NdBNJLQHgl
+IO59fEpTd55NO24g9a8/sxgn0ADCenMlngk1Ou+2QJBONw7W12/WUSUg6ICe+b+x
+qPzgApue16oGw9HxhPwa3oEvVZrEnFIWLjsSWtezhgFHMCH9/ngk0KlRyes/EZCz
+ZgkO5mgii2fmNDg+yuWUfw7Q0x6BJskGIrxisJiJBRR1+DIvJqgqxJsNmeeEQrZK
+YHBukj5RWDFOpOHgqFbPsv45sVKoLrGFrMnNAgMBAAGjajBoMA4GA1UdDwEB/wQE
+AwIFoDATBgNVHSUEDDAKBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQW
+BBSwkx93xjYP4I+dcFF3xS9NLesmFjAUBgNVHREEDTALgglsb2NhbGhvc3QwDQYJ
+KoZIhvcNAQELBQADggEBAAK3ZF63w46pT76QIOeSM3ocUm6izvW/IrxLUESfgRC4
+gg0/5VfPiHHUe6orn15KuPXHe7xCUFqc2oFn5aIU1B/6iOPeNItvMJidU0a3UAiw
+hFK9MSFgESNBiEnu1dE5tPcIIxTyCFQ/8loeY3dsdcNVoguH/2J9v/XcMMga46A1
+wudaaa1nb+ZYnXkRuyObKVJQN7EqC+4edinMOTPBbF9wtRMAMBRHXXENXb9zFthi
+Dbdn4YvadYsNHxh5ar+hQn/HSPMuCUPY/uUqxtBagb6aS0YnSoUscSLs1Jizg5NX
+d+QV8X/5E6W4xWnptUZwVxOemkdnr6A8MH1eQKKFZTM=
+-----END CERTIFICATE-----
diff --git a/pulsar-common/src/test/resources/ssl/my-ca/client-key.pem b/pulsar-common/src/test/resources/ssl/my-ca/client-key.pem
new file mode 100644
index 00000000000..5b08b151c80
--- /dev/null
+++ b/pulsar-common/src/test/resources/ssl/my-ca/client-key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDZN+CNZ1i1WaXu
+lbwSASOfXErWXhGV9DHqavPp3DohgQdundfS648T/X80uWQlyxu4L4j0oc97jtzc
+1AyZFXj5nocVsveEO9aDjnYCc5NdBNJLQHglIO59fEpTd55NO24g9a8/sxgn0ADC
+enMlngk1Ou+2QJBONw7W12/WUSUg6ICe+b+xqPzgApue16oGw9HxhPwa3oEvVZrE
+nFIWLjsSWtezhgFHMCH9/ngk0KlRyes/EZCzZgkO5mgii2fmNDg+yuWUfw7Q0x6B
+JskGIrxisJiJBRR1+DIvJqgqxJsNmeeEQrZKYHBukj5RWDFOpOHgqFbPsv45sVKo
+LrGFrMnNAgMBAAECggEATeVZ45uiFja16J9NuG8sJSPluoY1bD8L/3KnUcAmIImy
+7powIXVT8+k+StwI6/ywThbN2FyGmVqcHZz1f5hRr8KH0uJBHOyQetEFxM9Jk1v9
+Rfsymq36mImP5erJnAyp66vvUrqY+P4Ap71duam4x5wBBqyUk1fvPGA5vPOQiwHs
+TN9JHizGobY25fpigWKIMamyE7HWXEUzVdOo83ZiNx53ths+WcF/kqto2v5LtyfJ
+HgoPocfZI8tRz9tfgc8zOkvyjsvgdd6rLhd0r2oExnyQBJdktGFpQZMGambU328u
+NqcdJscjP/HWAHRzuSdOvCMOEn8E5GIjcWEnQqOmSQKBgQDcpb655/UdcVxrv2Ou
+8juucDJMpf6i/UcmlXVXx+3zGSuQZcCC2fupe3JcxPdK7bo65YlC3OoRihggh2sS
+cnFMNHMfyoE3G/doXIr3QyL9UAQt4yb+7Nz7jRXYcg4Ytv+FVS6BSzIDEK17v+es
+GuWDM3JwtigtzYS4tRh7lgmuBwKBgQD8BXp7yIyVv657B8OJJSoeGataziFPhZux
+WKoS3gq24169ZWXwLc+nwrdgvBNrRaHuX+cYh93RF9+2WZrRcRL41XqN938adasY
+zPsfOJa9IOgUzQtGUMSe1/WqvHfcvqZCqYq4u/LSdf+I67woP4tCqqn4E928aIZb
+6PjLH+dUiwKBgH1ntn7y1t1lEKIspPtJsaHzIqNttMvuKAJF7+t0Nkl0hM4NBt1Y
+BzDMeLNBP0vW0YGn89uMs3xEgHH8hV52rO4i4UuwTMCFpJgsAM+H2NsgHz/1WrSI
+6xANn9zk9h4V5CRjxYq2sjYLxI4RBBtNLiTjmKd24F8n78cLJl8XZ2kBAoGAGoHF
+ATH1v2ZaxqvpYApdpK7UfAeEL2YBGyUVNkjOXbAKbec1Uo6u8ZkkSnNdo4G+Z2EE
+4Gqh5PUa3YYNJ4w6D5v8eOQYJUNNDJ26p+z+xcOpRU7PqcSi+YYDW8LY5InU2NwW
+MBnsj0BD8TXCI4WTcx6aI/KK9t8TiqU1Tb/8R8MCgYANVinOLz2enB+Qzu4o88W/
+witKHI3D9+z/uWjp0Q4rwmr3OL4FD9vZWvL4qwbDgpfLirJ4e3UVfN1/FoytAKlk
+Kykf8oDWciCIdxStt/yUpgQv78IL3vM5d9B8Qb7KCRtJ0BIXGJ7Gle3xJeuduZLe
++F+hwI3Dpv5HPqa9o6ttJw==
+-----END PRIVATE KEY-----
diff --git a/pulsar-common/src/test/resources/ssl/my-ca/server-ca.pem b/pulsar-common/src/test/resources/ssl/my-ca/server-ca.pem
new file mode 100644
index 00000000000..df5f69298e2
--- /dev/null
+++ b/pulsar-common/src/test/resources/ssl/my-ca/server-ca.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDHDCCAgSgAwIBAgIUVQHD0/oi9Ca50HA7DFLYOO2wEzYwDQYJKoZIhvcNAQEL
+BQAwETEPMA0GA1UEAxMGUHVsc2FyMCAXDTIyMDExNDA0MjgwMFoYDzIxMjExMjIx
+MDQyODAwWjARMQ8wDQYDVQQDEwZQdWxzYXIwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQDBcqDkMhjLd9ik//UQijqbajQP5t6dvVZNn9gODQrS9oB/URur
+NzCcPWYPJZfEJlTkV8mlmgq4dBjwghpy5ALOGiERk55JPIN4cy01hQ6j7YSPFvMv
+BjqZvm5dpGDNTr7GY7THegMM1wpk9EaUOm7tBOHtf6ZnANjSMcQM74RCSBt0Koqw
+06CKVDCbgJ5NNE1LgwYeVQAwtQAhY8rqqQKJvCorFbq7OiisFBnz5pRBT6N4kMo1
+9LZo3Oe2F2w9eH9vacQ0NjSOCNXqal9Xl/Pwy9JgKKppwZ/3nCgRc+yfjrnkRz0f
+b+llb2NpR5Ge+tNMakqelE8bDSw/5BPjRPftAgMBAAGjajBoMA4GA1UdDwEB/wQE
+AwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMB0GA1UdDgQW
+BBRXws5mmLbW+xOLflUyUZ0I0uN96zAUBgNVHREEDTALgglsb2NhbGhvc3QwDQYJ
+KoZIhvcNAQELBQADggEBAKMklpYJIkp4icz9Ea5wWQiRXWb94lGdyCA833VHeGB2
+fKvNXj1d6lEiy26pOjhDmycroKelj70WqOsqVgi4xh4Y9sj6pwb8Q423Tu3qNO1k
+qaScTar2DANSigNzqlSbLshPWQ2ZyDwkvZPuqPgHzOXekzbUGwxgCiySaQkl2mCS
+mBaG3XnESwiMIKkLphEv0MAvTVaImbSRWYEQ4OECwcHXxx+14wK8NLcdDIHcSzki
+8Eq24CxDOeL5QxciGMi5tylsdCpT+D/BXTKiu46yoRjXUsTLYL53yUZZIqQ3A4CV
+enZ/vHhP0Ev9RcRigFTqrBm7EC3b2AUpvqgRMnPwQZo=
+-----END CERTIFICATE-----
diff --git a/pulsar-common/src/test/resources/ssl/my-ca/server-key.pem b/pulsar-common/src/test/resources/ssl/my-ca/server-key.pem
new file mode 100644
index 00000000000..a3f3a36b73c
--- /dev/null
+++ b/pulsar-common/src/test/resources/ssl/my-ca/server-key.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDBcqDkMhjLd9ik
+//UQijqbajQP5t6dvVZNn9gODQrS9oB/URurNzCcPWYPJZfEJlTkV8mlmgq4dBjw
+ghpy5ALOGiERk55JPIN4cy01hQ6j7YSPFvMvBjqZvm5dpGDNTr7GY7THegMM1wpk
+9EaUOm7tBOHtf6ZnANjSMcQM74RCSBt0Koqw06CKVDCbgJ5NNE1LgwYeVQAwtQAh
+Y8rqqQKJvCorFbq7OiisFBnz5pRBT6N4kMo19LZo3Oe2F2w9eH9vacQ0NjSOCNXq
+al9Xl/Pwy9JgKKppwZ/3nCgRc+yfjrnkRz0fb+llb2NpR5Ge+tNMakqelE8bDSw/
+5BPjRPftAgMBAAECggEBAJm2JsgMUo1ihn/dbnIdFCKoCgRUs7FtYCVADOJlVKN7
+AXGpFi4/JV4Qn4cLnQNcXfovE2iF9VzJy4NYLgH60YvJUVtxC8Yv0lukUVkEiDST
+p9A3MTa9YVUG7xVzZwPcPVTQpzYV6lSKjpTXUTm5EKk/RvJ7itKv5plmt9x7eYFb
+/JwqXo1Z6C4gfIFR85LWmrCsNUK5T9oooLz88D6+ZH3+fWlr75RDff2kqdLshMTs
+N0Ov7NXcRFeruFs/IPrgTxjBMeNa2LFdYVPeeQ41L4uOI49uVBAmSn1be+THvDoj
+Do+6wTEF/h6/VLoOaIFZZdHlqd4is+xcEg8gwVkCn2ECgYEAxqVvGKc9qaqEVwBx
+U5Ru9OFx0NqEBvkYZRbCg1REcMFd3lqFTHvHiF3pmCp0XgLJKYuy42618IJXhj6D
+Y15/p9jX0025MpnH/AdwpO6x5pv6gb/JOMnHOnq8sI3R+V6TVsv1WZj0sOj94mF0
++Od++bQkUnSlfE4X7v+cJfo/Q8UCgYEA+Uz1yOyI9Dv1dEdBMdBA8MTriYU0uJCV
+dVKzL/uC9XyguVBWu1HX0MvEKyjPRycvLB7TuQqAFLgCtC8EEuPGBpWtyXOm9Jxw
+ToCfUZFuBQeMuf4vZcFgJjiEKTdKBxrvjkhyIhPR6JAy0WUr8Ry+ZtqvmG5NOEz5
+ptm1tznYngkCgYEAlckeyV8p/uqF2biKu3QcamgoU0zB6yQfAfK0fySmasNTzZtC
+EhbvsOLnhgbVMiI1ny8ol5fedtlBuAchOWeDKIQ40as0r3QHuQG/LY6S9Im+zeFY
+kIqNwInWB+cYYkmvHe6zNXlBYLh+4BmOgzTDqPPtw4MTWXTlVSDGlFhrJeUCgYBX
+7rlS4Xt9ChkNpoRsWZROWGbr3rw1zWmqND1X01Lh28+lDZ1J/RguYXET+BUEd+G/
+oi/zuKxsomrxuxOoxgZ3FBx0TgK5jORgDCYl0zIHPB57DBkTvx123cBf+Ux3LR0K
+BqubMXp8mUATc6gIJ6dRCBmfnmhGT4BPRcM+mXy6YQKBgGEGH37VABus+Oi3g1bk
+qEAaUI1asRLJIfbY2ImxEroLIQAbTFuIQUsZTKpT7jJZubjYvy1Fev0LU/n7Kv2w
+7ym41z70ro5uxwUBfJjnF3RtgncNcftn4b3siNzvBfKEBuhegMeS5YAbBIwABUpR
+4mVpm9BLOiX4yENIT6JdUQFc
+-----END PRIVATE KEY-----
diff --git a/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/ProxyConfiguration.java b/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/ProxyConfiguration.java
index 0231251e3f7..a29158f3902 100644
--- a/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/ProxyConfiguration.java
+++ b/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/ProxyConfiguration.java
@@ -410,7 +410,9 @@ public class ProxyConfiguration implements PulsarConfiguration {
 
     @FieldContext(
             category = CATEGORY_KEYSTORE_TLS,
-            doc = "TLS Provider"
+            doc = "Specify the TLS provider for the broker service: \n"
+                    + "When using TLS authentication with CACert, the valid value is either OPENSSL or JDK.\n"
+                    + "When using TLS authentication with KeyStore, available values can be SunJSSE, Conscrypt and etc."
     )
     private String tlsProvider = null;
 
diff --git a/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/ServiceChannelInitializer.java b/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/ServiceChannelInitializer.java
index a033a87912d..12abf871b50 100644
--- a/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/ServiceChannelInitializer.java
+++ b/pulsar-proxy/src/main/java/org/apache/pulsar/proxy/server/ServiceChannelInitializer.java
@@ -21,6 +21,7 @@ package org.apache.pulsar.proxy.server;
 import static org.apache.commons.lang3.StringUtils.isEmpty;
 
 import io.netty.handler.ssl.SslHandler;
+import io.netty.handler.ssl.SslProvider;
 import io.netty.handler.timeout.ReadTimeoutHandler;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Supplier;
@@ -79,7 +80,13 @@ public class ServiceChannelInitializer extends ChannelInitializer<SocketChannel>
                         serviceConfig.getTlsProtocols(),
                         serviceConfig.getTlsCertRefreshCheckDurationSec());
             } else {
-                serverSslCtxRefresher = new NettyServerSslContextBuilder(serviceConfig.isTlsAllowInsecureConnection(),
+                SslProvider sslProvider = null;
+                if (serviceConfig.getTlsProvider() != null) {
+                    sslProvider = SslProvider.valueOf(serviceConfig.getTlsProvider());
+                }
+                serverSslCtxRefresher = new NettyServerSslContextBuilder(
+                        sslProvider,
+                        serviceConfig.isTlsAllowInsecureConnection(),
                         serviceConfig.getTlsTrustCertsFilePath(), serviceConfig.getTlsCertificateFilePath(),
                         serviceConfig.getTlsKeyFilePath(), serviceConfig.getTlsCiphers(), serviceConfig.getTlsProtocols(),
                         serviceConfig.isTlsRequireTrustedClientCertOnConnect(),
@@ -109,11 +116,19 @@ public class ServiceChannelInitializer extends ChannelInitializer<SocketChannel>
                         serviceConfig.getTlsCertRefreshCheckDurationSec(),
                         authData);
             } else {
+                SslProvider sslProvider = null;
+                if (serviceConfig.getBrokerClientSslProvider() != null) {
+                    sslProvider = SslProvider.valueOf(serviceConfig.getBrokerClientSslProvider());
+                }
                 clientSslCtxRefresher = new NettyClientSslContextRefresher(
+                        sslProvider,
                         serviceConfig.isTlsAllowInsecureConnection(),
                         serviceConfig.getBrokerClientTrustCertsFilePath(),
                         authData,
-                        serviceConfig.getTlsCertRefreshCheckDurationSec());
+                        serviceConfig.getBrokerClientTlsCiphers(),
+                        serviceConfig.getBrokerClientTlsProtocols(),
+                        serviceConfig.getTlsCertRefreshCheckDurationSec()
+                );
             }
         } else {
             this.clientSslCtxRefresher = null;