You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by th...@apache.org on 2022/11/22 23:35:06 UTC

[nifi] branch main updated: NIFI-10755 Refactored SSLContext creation using nifi-security-ssl

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

thenatog pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git


The following commit(s) were added to refs/heads/main by this push:
     new 5bc8e49c7a NIFI-10755 Refactored SSLContext creation using nifi-security-ssl
5bc8e49c7a is described below

commit 5bc8e49c7ab85be8b1e4ec3ff950f463e84f8607
Author: exceptionfactory <ex...@apache.org>
AuthorDate: Thu Nov 3 11:36:08 2022 -0500

    NIFI-10755 Refactored SSLContext creation using nifi-security-ssl
    
    - Added TrustManagerBuilder to nifi-security-ssl
    - Removed SslContextFactory and CertificateUtils from nifi-registry
    - Refactored c2-client-http
    - Refactored minifi-bootstrap
    - Refactored nifi-site-to-site-client
    - Refactored nifi-registry-client
    - Refactored nifi-registry-framework
    - Refactored nifi-toolkit-admin
    - Refactored nifi-toolkit-cli
    
    Signed-off-by: Nathan Gough <th...@gmail.com>
    
    This closes #6618.
---
 c2/c2-client-bundle/c2-client-http/pom.xml         |   5 +
 .../apache/nifi/c2/client/http/C2HttpClient.java   |  61 +-
 minifi/minifi-bootstrap/pom.xml                    |   9 +
 .../ingestors/PullHttpChangeIngestor.java          |  62 +-
 .../ingestors/RestChangeIngestorSSLTest.java       |  90 ++-
 minifi/pom.xml                                     |   5 +
 .../security/ssl/StandardSslContextBuilder.java    |  23 +-
 .../security/ssl/StandardTrustManagerBuilder.java  |  91 +++
 .../nifi/security/ssl/TrustManagerBuilder.java     |  31 +
 nifi-commons/nifi-site-to-site-client/pom.xml      |  10 +
 .../nifi/remote/client/SiteToSiteClient.java       |  71 ++-
 .../nifi/remote/client/http/TestHttpClient.java    |   2 +-
 .../nifi-registry-client/pom.xml                   |   5 +
 .../registry/client/NiFiRegistryClientConfig.java  |  89 ++-
 .../nifi-registry-framework/pom.xml                |   5 +
 .../security/ldap/LdapIdentityProvider.java        |  63 +-
 .../ldap/tenants/LdapUserGroupProvider.java        |  78 ++-
 .../registry/security/util/CertificateUtils.java   | 671 ---------------------
 .../registry/security/util/SslContextFactory.java  | 249 --------
 nifi-toolkit/nifi-toolkit-admin/pom.xml            |   5 +
 .../toolkit/admin/client/NiFiClientFactory.groovy  |  82 ++-
 nifi-toolkit/nifi-toolkit-cli/pom.xml              |   5 +
 .../cli/impl/client/nifi/NiFiClientConfig.java     |  90 ++-
 23 files changed, 480 insertions(+), 1322 deletions(-)

diff --git a/c2/c2-client-bundle/c2-client-http/pom.xml b/c2/c2-client-bundle/c2-client-http/pom.xml
index e5bfd786e9..8d106670de 100644
--- a/c2/c2-client-bundle/c2-client-http/pom.xml
+++ b/c2/c2-client-bundle/c2-client-http/pom.xml
@@ -38,6 +38,11 @@ limitations under the License.
             <artifactId>c2-client-base</artifactId>
             <version>1.19.0-SNAPSHOT</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-security-ssl</artifactId>
+            <version>1.19.0-SNAPSHOT</version>
+        </dependency>
         <dependency>
             <groupId>com.squareup.okhttp3</groupId>
             <artifactId>okhttp</artifactId>
diff --git a/c2/c2-client-bundle/c2-client-http/src/main/java/org/apache/nifi/c2/client/http/C2HttpClient.java b/c2/c2-client-bundle/c2-client-http/src/main/java/org/apache/nifi/c2/client/http/C2HttpClient.java
index bf9c083a0a..293851c0f5 100644
--- a/c2/c2-client-bundle/c2-client-http/src/main/java/org/apache/nifi/c2/client/http/C2HttpClient.java
+++ b/c2/c2-client-bundle/c2-client-http/src/main/java/org/apache/nifi/c2/client/http/C2HttpClient.java
@@ -23,15 +23,11 @@ import static okhttp3.RequestBody.create;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.security.KeyStore;
-import java.security.NoSuchAlgorithmException;
 import java.util.Optional;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
-import javax.net.ssl.KeyManagerFactory;
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLSocketFactory;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
 import javax.net.ssl.X509TrustManager;
 import okhttp3.MediaType;
 import okhttp3.MultipartBody;
@@ -47,6 +43,9 @@ import org.apache.nifi.c2.protocol.api.C2Heartbeat;
 import org.apache.nifi.c2.protocol.api.C2HeartbeatResponse;
 import org.apache.nifi.c2.protocol.api.C2OperationAck;
 import org.apache.nifi.c2.serializer.C2Serializer;
+import org.apache.nifi.security.ssl.StandardKeyStoreBuilder;
+import org.apache.nifi.security.ssl.StandardSslContextBuilder;
+import org.apache.nifi.security.ssl.StandardTrustManagerBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -195,50 +194,40 @@ public class C2HttpClient implements C2Client {
         final String keystoreLocation = clientConfig.getKeystoreFilename();
         final String keystoreType = clientConfig.getKeystoreType();
         final String keystorePass = clientConfig.getKeystorePass();
-
         assertKeystorePropertiesSet(keystoreLocation, keystorePass, keystoreType);
 
-        // prepare the keystore
-        final KeyStore keyStore = KeyStore.getInstance(keystoreType);
-
-        try (FileInputStream keyStoreStream = new FileInputStream(keystoreLocation)) {
-            keyStore.load(keyStoreStream, keystorePass.toCharArray());
+        final KeyStore keyStore;
+        try (final FileInputStream keyStoreStream = new FileInputStream(keystoreLocation)) {
+            keyStore = new StandardKeyStoreBuilder()
+                    .type(keystoreType)
+                    .inputStream(keyStoreStream)
+                    .password(keystorePass.toCharArray())
+                    .build();
         }
 
-        final KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
-        keyManagerFactory.init(keyStore, keystorePass.toCharArray());
-
-        // load truststore
         final String truststoreLocation = clientConfig.getTruststoreFilename();
         final String truststorePass = clientConfig.getTruststorePass();
         final String truststoreType = clientConfig.getTruststoreType();
         assertTruststorePropertiesSet(truststoreLocation, truststorePass, truststoreType);
 
-        KeyStore truststore = KeyStore.getInstance(truststoreType);
-        final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("X509");
-        truststore.load(new FileInputStream(truststoreLocation), truststorePass.toCharArray());
-        trustManagerFactory.init(truststore);
-
-        final X509TrustManager x509TrustManager;
-        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
-        if (trustManagers[0] != null) {
-            x509TrustManager = (X509TrustManager) trustManagers[0];
-        } else {
-            throw new IllegalStateException("List of trust managers is null");
-        }
-
-        SSLContext tempSslContext;
-        try {
-            tempSslContext = SSLContext.getInstance("TLS");
-        } catch (NoSuchAlgorithmException e) {
-            throw new IllegalStateException("SSLContext creation failed", e);
+        final KeyStore truststore;
+        try (final FileInputStream trustStoreStream = new FileInputStream(truststoreLocation)) {
+            truststore = new StandardKeyStoreBuilder()
+                    .type(truststoreType)
+                    .inputStream(trustStoreStream)
+                    .password(truststorePass.toCharArray())
+                    .build();
         }
 
-        final SSLContext sslContext = tempSslContext;
-        sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
-
+        final X509TrustManager trustManager = new StandardTrustManagerBuilder().trustStore(truststore).build();
+        final SSLContext sslContext = new StandardSslContextBuilder()
+                .keyStore(keyStore)
+                .keyPassword(keystorePass.toCharArray())
+                .trustStore(truststore)
+                .build();
         final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
-        okHttpClientBuilder.sslSocketFactory(sslSocketFactory, x509TrustManager);
+
+        okHttpClientBuilder.sslSocketFactory(sslSocketFactory, trustManager);
     }
 
     private void assertKeystorePropertiesSet(String location, String password, String type) {
diff --git a/minifi/minifi-bootstrap/pom.xml b/minifi/minifi-bootstrap/pom.xml
index c125a2e160..bca0fe444c 100644
--- a/minifi/minifi-bootstrap/pom.xml
+++ b/minifi/minifi-bootstrap/pom.xml
@@ -69,6 +69,10 @@ limitations under the License.
             <groupId>org.apache.nifi</groupId>
             <artifactId>nifi-xml-processing</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-security-ssl</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.apache.nifi</groupId>
             <artifactId>nifi-properties</artifactId>
@@ -113,6 +117,11 @@ limitations under the License.
             <groupId>com.fasterxml.jackson.core</groupId>
             <artifactId>jackson-databind</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-security-utils</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
 
diff --git a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/PullHttpChangeIngestor.java b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/PullHttpChangeIngestor.java
index 02e4bac6eb..14000d9e6b 100644
--- a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/PullHttpChangeIngestor.java
+++ b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/PullHttpChangeIngestor.java
@@ -26,7 +26,6 @@ import java.net.InetSocketAddress;
 import java.net.Proxy;
 import java.nio.ByteBuffer;
 import java.security.KeyStore;
-import java.security.NoSuchAlgorithmException;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
@@ -34,11 +33,8 @@ import java.util.Properties;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Supplier;
-import javax.net.ssl.KeyManagerFactory;
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLSocketFactory;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
 import javax.net.ssl.X509TrustManager;
 import okhttp3.Credentials;
 import okhttp3.HttpUrl;
@@ -52,6 +48,9 @@ import org.apache.nifi.minifi.bootstrap.configuration.differentiators.Differenti
 import org.apache.nifi.minifi.bootstrap.configuration.differentiators.WholeConfigDifferentiator;
 import org.apache.nifi.minifi.bootstrap.util.ConfigTransformer;
 import org.apache.nifi.minifi.commons.schema.common.StringUtil;
+import org.apache.nifi.security.ssl.StandardKeyStoreBuilder;
+import org.apache.nifi.security.ssl.StandardSslContextBuilder;
+import org.apache.nifi.security.ssl.StandardTrustManagerBuilder;
 import org.slf4j.LoggerFactory;
 
 
@@ -273,51 +272,40 @@ public class PullHttpChangeIngestor extends AbstractPullChangeIngestor {
         final String keystoreLocation = properties.getProperty(KEYSTORE_LOCATION_KEY);
         final String keystorePass = properties.getProperty(KEYSTORE_PASSWORD_KEY);
         final String keystoreType = properties.getProperty(KEYSTORE_TYPE_KEY);
-
         assertKeystorePropertiesSet(keystoreLocation, keystorePass, keystoreType);
 
-        // prepare the keystore
-        final KeyStore keyStore = KeyStore.getInstance(keystoreType);
-
-        try (FileInputStream keyStoreStream = new FileInputStream(keystoreLocation)) {
-            keyStore.load(keyStoreStream, keystorePass.toCharArray());
+        final KeyStore keyStore;
+        try (final FileInputStream keyStoreStream = new FileInputStream(keystoreLocation)) {
+            keyStore = new StandardKeyStoreBuilder()
+                    .type(keystoreType)
+                    .inputStream(keyStoreStream)
+                    .password(keystorePass.toCharArray())
+                    .build();
         }
 
-        final KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
-        keyManagerFactory.init(keyStore, keystorePass.toCharArray());
-
-        // load truststore
         final String truststoreLocation = properties.getProperty(TRUSTSTORE_LOCATION_KEY);
         final String truststorePass = properties.getProperty(TRUSTSTORE_PASSWORD_KEY);
         final String truststoreType = properties.getProperty(TRUSTSTORE_TYPE_KEY);
         assertTruststorePropertiesSet(truststoreLocation, truststorePass, truststoreType);
 
-        KeyStore truststore = KeyStore.getInstance(truststoreType);
-        final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("X509");
-        truststore.load(new FileInputStream(truststoreLocation), truststorePass.toCharArray());
-        trustManagerFactory.init(truststore);
-
-        final X509TrustManager x509TrustManager;
-        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
-        if (trustManagers[0] != null) {
-            x509TrustManager = (X509TrustManager) trustManagers[0];
-        } else {
-            throw new IllegalStateException("List of trust managers is null");
-        }
-
-        SSLContext tempSslContext;
-        try {
-            tempSslContext = SSLContext.getInstance("TLS");
-        } catch (NoSuchAlgorithmException e) {
-            logger.warn("Unable to use 'TLS' for the PullHttpChangeIngestor due to NoSuchAlgorithmException. Will attempt to use the default algorithm.", e);
-            tempSslContext = SSLContext.getDefault();
+        final KeyStore truststore;
+        try (final FileInputStream trustStoreStream = new FileInputStream(truststoreLocation)) {
+            truststore = new StandardKeyStoreBuilder()
+                    .type(truststoreType)
+                    .inputStream(trustStoreStream)
+                    .password(truststorePass.toCharArray())
+                    .build();
         }
 
-        final SSLContext sslContext = tempSslContext;
-        sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
-
+        final X509TrustManager trustManager = new StandardTrustManagerBuilder().trustStore(truststore).build();
+        final SSLContext sslContext = new StandardSslContextBuilder()
+                .keyStore(keyStore)
+                .keyPassword(keystorePass.toCharArray())
+                .trustStore(truststore)
+                .build();
         final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
-        okHttpClientBuilder.sslSocketFactory(sslSocketFactory, x509TrustManager);
+
+        okHttpClientBuilder.sslSocketFactory(sslSocketFactory, trustManager);
     }
 
     private void assertKeystorePropertiesSet(String location, String password, String type) {
diff --git a/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/RestChangeIngestorSSLTest.java b/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/RestChangeIngestorSSLTest.java
index 91a56642e9..f58f111677 100644
--- a/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/RestChangeIngestorSSLTest.java
+++ b/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/configuration/ingestors/RestChangeIngestorSSLTest.java
@@ -25,24 +25,21 @@ import org.apache.nifi.minifi.bootstrap.configuration.ConfigurationChangeListene
 import org.apache.nifi.minifi.bootstrap.configuration.ConfigurationChangeNotifier;
 import org.apache.nifi.minifi.bootstrap.configuration.ListenerHandleResult;
 import org.apache.nifi.minifi.bootstrap.configuration.ingestors.common.RestChangeIngestorCommonTest;
+import org.apache.nifi.security.ssl.StandardKeyStoreBuilder;
+import org.apache.nifi.security.ssl.StandardSslContextBuilder;
+import org.apache.nifi.security.ssl.StandardTrustManagerBuilder;
+import org.apache.nifi.security.util.TemporaryKeyStoreBuilder;
+import org.apache.nifi.security.util.TlsConfiguration;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
 import org.mockito.Mockito;
 
-import javax.net.ssl.KeyManagerFactory;
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLSocketFactory;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
 import javax.net.ssl.X509TrustManager;
 import java.io.FileInputStream;
 import java.io.IOException;
-import java.security.KeyManagementException;
 import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.CertificateException;
 import java.util.Collections;
 import java.util.Properties;
 
@@ -52,14 +49,16 @@ import static org.mockito.Mockito.when;
 public class RestChangeIngestorSSLTest extends RestChangeIngestorCommonTest {
 
     @BeforeAll
-    public static void setUpHttps() throws CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException, UnrecoverableKeyException, KeyManagementException, InterruptedException {
+    public static void setUpHttps() throws IOException, InterruptedException {
+        final TlsConfiguration tlsConfiguration = new TemporaryKeyStoreBuilder().trustStoreType("JKS").build();
+
         Properties properties = new Properties();
-        properties.setProperty(RestChangeIngestor.TRUSTSTORE_LOCATION_KEY, "./src/test/resources/localhost-ts.jks");
-        properties.setProperty(RestChangeIngestor.TRUSTSTORE_PASSWORD_KEY, "localtest");
-        properties.setProperty(RestChangeIngestor.TRUSTSTORE_TYPE_KEY, "JKS");
-        properties.setProperty(RestChangeIngestor.KEYSTORE_LOCATION_KEY, "./src/test/resources/localhost-ks.jks");
-        properties.setProperty(RestChangeIngestor.KEYSTORE_PASSWORD_KEY, "localtest");
-        properties.setProperty(RestChangeIngestor.KEYSTORE_TYPE_KEY, "JKS");
+        properties.setProperty(RestChangeIngestor.TRUSTSTORE_LOCATION_KEY, tlsConfiguration.getTruststorePath());
+        properties.setProperty(RestChangeIngestor.TRUSTSTORE_PASSWORD_KEY, tlsConfiguration.getTruststorePassword());
+        properties.setProperty(RestChangeIngestor.TRUSTSTORE_TYPE_KEY, tlsConfiguration.getTruststoreType().getType());
+        properties.setProperty(RestChangeIngestor.KEYSTORE_LOCATION_KEY, tlsConfiguration.getKeystorePath());
+        properties.setProperty(RestChangeIngestor.KEYSTORE_PASSWORD_KEY, tlsConfiguration.getKeystorePassword());
+        properties.setProperty(RestChangeIngestor.KEYSTORE_TYPE_KEY, tlsConfiguration.getKeystoreType().getType());
         properties.setProperty(RestChangeIngestor.NEED_CLIENT_AUTH_KEY, "false");
         properties.put(PullHttpChangeIngestor.OVERRIDE_SECURITY, "true");
         properties.put(PULL_HTTP_BASE_KEY + ".override.core", "true");
@@ -80,50 +79,33 @@ public class RestChangeIngestorSSLTest extends RestChangeIngestorCommonTest {
 
         OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder();
 
-        final String keystoreLocation = "./src/test/resources/localhost-ks.jks";
-        final String keystorePass = "localtest";
-        final String keystoreType = "JKS";
-
-        // prepare the keystore
-        final KeyStore keyStore = KeyStore.getInstance(keystoreType);
-
-        try (FileInputStream keyStoreStream = new FileInputStream(keystoreLocation)) {
-            keyStore.load(keyStoreStream, keystorePass.toCharArray());
+        final KeyStore keyStore;
+        try (final FileInputStream keyStoreStream = new FileInputStream(tlsConfiguration.getKeystorePath())) {
+            keyStore = new StandardKeyStoreBuilder()
+                    .type(tlsConfiguration.getKeystoreType().getType())
+                    .inputStream(keyStoreStream)
+                    .password(tlsConfiguration.getKeystorePassword().toCharArray())
+                    .build();
         }
 
-        final KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
-        keyManagerFactory.init(keyStore, keystorePass.toCharArray());
-
-        // load truststore
-        final String truststoreLocation = "./src/test/resources/localhost-ts.jks";
-        final String truststorePass = "localtest";
-        final String truststoreType = "JKS";
-
-        KeyStore truststore = KeyStore.getInstance(truststoreType);
-        final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("X509");
-        truststore.load(new FileInputStream(truststoreLocation), truststorePass.toCharArray());
-        trustManagerFactory.init(truststore);
-
-        final X509TrustManager x509TrustManager;
-        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
-        if (trustManagers[0] != null) {
-            x509TrustManager = (X509TrustManager) trustManagers[0];
-        } else {
-            throw new IllegalStateException("List of trust managers is null");
+        final KeyStore truststore;
+        try (final FileInputStream trustStoreStream = new FileInputStream(tlsConfiguration.getTruststorePath())) {
+            truststore = new StandardKeyStoreBuilder()
+                    .type(tlsConfiguration.getTruststoreType().getType())
+                    .inputStream(trustStoreStream)
+                    .password(tlsConfiguration.getTruststorePassword().toCharArray())
+                    .build();
         }
 
-        SSLContext tempSslContext;
-        try {
-            tempSslContext = SSLContext.getInstance("TLS");
-        } catch (NoSuchAlgorithmException e) {
-            tempSslContext = SSLContext.getDefault();
-        }
-
-        final SSLContext sslContext = tempSslContext;
-        sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
-
+        final X509TrustManager trustManager = new StandardTrustManagerBuilder().trustStore(truststore).build();
+        final SSLContext sslContext = new StandardSslContextBuilder()
+                .keyStore(keyStore)
+                .keyPassword(tlsConfiguration.getKeyPassword().toCharArray())
+                .trustStore(truststore)
+                .build();
         final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
-        clientBuilder.sslSocketFactory(sslSocketFactory, x509TrustManager);
+
+        clientBuilder.sslSocketFactory(sslSocketFactory, trustManager);
 
         Thread.sleep(1000);
         url = restChangeIngestor.getURI().toURL().toString();
diff --git a/minifi/pom.xml b/minifi/pom.xml
index 4ca1fb68d2..83f3ab8cb0 100644
--- a/minifi/pom.xml
+++ b/minifi/pom.xml
@@ -417,6 +417,11 @@ limitations under the License.
                 <artifactId>nifi-security-utils</artifactId>
                 <version>1.19.0-SNAPSHOT</version>
             </dependency>
+            <dependency>
+                <groupId>org.apache.nifi</groupId>
+                <artifactId>nifi-security-ssl</artifactId>
+                <version>1.19.0-SNAPSHOT</version>
+            </dependency>
             <dependency>
                 <groupId>org.apache.nifi</groupId>
                 <artifactId>nifi-xml-processing</artifactId>
diff --git a/nifi-commons/nifi-security-ssl/src/main/java/org/apache/nifi/security/ssl/StandardSslContextBuilder.java b/nifi-commons/nifi-security-ssl/src/main/java/org/apache/nifi/security/ssl/StandardSslContextBuilder.java
index 9d82ea9c72..d83c7ebd1b 100644
--- a/nifi-commons/nifi-security-ssl/src/main/java/org/apache/nifi/security/ssl/StandardSslContextBuilder.java
+++ b/nifi-commons/nifi-security-ssl/src/main/java/org/apache/nifi/security/ssl/StandardSslContextBuilder.java
@@ -20,7 +20,7 @@ import javax.net.ssl.KeyManager;
 import javax.net.ssl.KeyManagerFactory;
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
 import java.security.KeyManagementException;
 import java.security.KeyStore;
 import java.security.KeyStoreException;
@@ -116,7 +116,7 @@ public class StandardSslContextBuilder implements SslContextBuilder {
             final KeyManagerFactory keyManagerFactory = getKeyManagerFactory();
             try {
                 keyManagerFactory.init(keyStore, keyPassword);
-            } catch (final KeyStoreException|NoSuchAlgorithmException|UnrecoverableKeyException e) {
+            } catch (final KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException e) {
                 throw new BuilderConfigurationException("Key Manager initialization failed", e);
             }
             keyManagers = keyManagerFactory.getKeyManagers();
@@ -129,13 +129,8 @@ public class StandardSslContextBuilder implements SslContextBuilder {
         if (trustStore == null) {
             trustManagers = null;
         } else {
-            final TrustManagerFactory trustManagerFactory = getTrustManagerFactory();
-            try {
-                trustManagerFactory.init(trustStore);
-            } catch (final KeyStoreException e) {
-                throw new BuilderConfigurationException("Trust Manager initialization failed", e);
-            }
-            trustManagers = trustManagerFactory.getTrustManagers();
+            final X509TrustManager trustManager = new StandardTrustManagerBuilder().trustStore(trustStore).build();
+            trustManagers = new TrustManager[]{trustManager};
         }
         return trustManagers;
     }
@@ -150,16 +145,6 @@ public class StandardSslContextBuilder implements SslContextBuilder {
         }
     }
 
-    private TrustManagerFactory getTrustManagerFactory() {
-        final String algorithm = TrustManagerFactory.getDefaultAlgorithm();
-        try {
-            return TrustManagerFactory.getInstance(algorithm);
-        } catch (final NoSuchAlgorithmException e) {
-            final String message = String.format("TrustManagerFactory creation failed with algorithm [%s]", algorithm);
-            throw new BuilderConfigurationException(message, e);
-        }
-    }
-
     private SSLContext getSslContext() {
         try {
             return SSLContext.getInstance(protocol);
diff --git a/nifi-commons/nifi-security-ssl/src/main/java/org/apache/nifi/security/ssl/StandardTrustManagerBuilder.java b/nifi-commons/nifi-security-ssl/src/main/java/org/apache/nifi/security/ssl/StandardTrustManagerBuilder.java
new file mode 100644
index 0000000000..2aca565156
--- /dev/null
+++ b/nifi-commons/nifi-security-ssl/src/main/java/org/apache/nifi/security/ssl/StandardTrustManagerBuilder.java
@@ -0,0 +1,91 @@
+/*
+ * 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.nifi.security.ssl;
+
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.Optional;
+
+/**
+ * Standard implementation of X.509 Trust Manager Builder
+ */
+public class StandardTrustManagerBuilder implements TrustManagerBuilder {
+    private KeyStore trustStore;
+
+    /**
+     * Build X.509 Trust Manager using configured properties
+     *
+     * @return X.509 Trust Manager
+     */
+    @Override
+    public X509TrustManager build() {
+        final TrustManager[] trustManagers = getTrustManagers();
+        if (trustManagers == null) {
+            throw new BuilderConfigurationException("Trust Managers not found: Trust Store required");
+        }
+
+        final Optional<X509TrustManager> configuredTrustManager = Arrays.stream(trustManagers)
+                .filter(trustManager -> trustManager instanceof X509TrustManager)
+                .map(trustManager -> (X509TrustManager) trustManager)
+                .findFirst();
+
+        return configuredTrustManager.orElseThrow(() -> new BuilderConfigurationException("X.509 Trust Manager not found"));
+    }
+
+    /**
+     * Set Trust Store with Certificate Entries
+     *
+     * @param trustStore Trust Store
+     * @return Builder
+     */
+    public StandardTrustManagerBuilder trustStore(final KeyStore trustStore) {
+        this.trustStore = Objects.requireNonNull(trustStore, "Trust Store required");
+        return this;
+    }
+
+    private TrustManager[] getTrustManagers() {
+        final TrustManager[] trustManagers;
+        if (trustStore == null) {
+            trustManagers = null;
+        } else {
+            final TrustManagerFactory trustManagerFactory = getTrustManagerFactory();
+            try {
+                trustManagerFactory.init(trustStore);
+            } catch (final KeyStoreException e) {
+                throw new BuilderConfigurationException("Trust Manager initialization failed", e);
+            }
+            trustManagers = trustManagerFactory.getTrustManagers();
+        }
+        return trustManagers;
+    }
+
+    private TrustManagerFactory getTrustManagerFactory() {
+        final String algorithm = TrustManagerFactory.getDefaultAlgorithm();
+        try {
+            return TrustManagerFactory.getInstance(algorithm);
+        } catch (final NoSuchAlgorithmException e) {
+            final String message = String.format("TrustManagerFactory creation failed with algorithm [%s]", algorithm);
+            throw new BuilderConfigurationException(message, e);
+        }
+    }
+}
diff --git a/nifi-commons/nifi-security-ssl/src/main/java/org/apache/nifi/security/ssl/TrustManagerBuilder.java b/nifi-commons/nifi-security-ssl/src/main/java/org/apache/nifi/security/ssl/TrustManagerBuilder.java
new file mode 100644
index 0000000000..4140f774c6
--- /dev/null
+++ b/nifi-commons/nifi-security-ssl/src/main/java/org/apache/nifi/security/ssl/TrustManagerBuilder.java
@@ -0,0 +1,31 @@
+/*
+ * 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.nifi.security.ssl;
+
+import javax.net.ssl.X509TrustManager;
+
+/**
+ * Builder interface for instances of java.security.ssl.X509TrustManager
+ */
+public interface TrustManagerBuilder {
+    /**
+     * Build X.509 Trust Manager using configured properties
+     *
+     * @return X.509 Trust Manager
+     */
+    X509TrustManager build();
+}
diff --git a/nifi-commons/nifi-site-to-site-client/pom.xml b/nifi-commons/nifi-site-to-site-client/pom.xml
index 73ce08b185..bfbefc1e32 100644
--- a/nifi-commons/nifi-site-to-site-client/pom.xml
+++ b/nifi-commons/nifi-site-to-site-client/pom.xml
@@ -51,6 +51,16 @@
             <artifactId>nifi-security-utils</artifactId>
             <version>1.19.0-SNAPSHOT</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-security-utils-api</artifactId>
+            <version>1.19.0-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-security-ssl</artifactId>
+            <version>1.19.0-SNAPSHOT</version>
+        </dependency>
         <dependency>
             <groupId>org.apache.nifi</groupId>
             <artifactId>nifi-xml-processing</artifactId>
diff --git a/nifi-commons/nifi-site-to-site-client/src/main/java/org/apache/nifi/remote/client/SiteToSiteClient.java b/nifi-commons/nifi-site-to-site-client/src/main/java/org/apache/nifi/remote/client/SiteToSiteClient.java
index 6a91d1dba1..1721f1f61b 100644
--- a/nifi-commons/nifi-site-to-site-client/src/main/java/org/apache/nifi/remote/client/SiteToSiteClient.java
+++ b/nifi-commons/nifi-site-to-site-client/src/main/java/org/apache/nifi/remote/client/SiteToSiteClient.java
@@ -18,19 +18,17 @@ package org.apache.nifi.remote.client;
 
 import java.io.Closeable;
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.Serializable;
 import java.net.InetAddress;
+import java.nio.file.Files;
+import java.nio.file.Paths;
 import java.security.KeyStore;
-import java.security.SecureRandom;
 import java.util.LinkedHashSet;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
-import javax.net.ssl.KeyManagerFactory;
 import javax.net.ssl.SSLContext;
-import javax.net.ssl.TrustManagerFactory;
 import org.apache.nifi.components.state.StateManager;
 import org.apache.nifi.events.EventReporter;
 import org.apache.nifi.remote.Transaction;
@@ -44,8 +42,8 @@ import org.apache.nifi.remote.exception.UnknownPortException;
 import org.apache.nifi.remote.protocol.DataPacket;
 import org.apache.nifi.remote.protocol.SiteToSiteTransportProtocol;
 import org.apache.nifi.remote.protocol.http.HttpProxy;
-import org.apache.nifi.security.util.KeyStoreUtils;
-import org.apache.nifi.security.util.TlsConfiguration;
+import org.apache.nifi.security.ssl.StandardKeyStoreBuilder;
+import org.apache.nifi.security.ssl.StandardSslContextBuilder;
 
 /**
  * <p>
@@ -329,7 +327,7 @@ public interface SiteToSiteClient extends Closeable {
          * Site-to-Site communications are secure (i.e., the client will always
          * use secure or non-secure communications, depending on what the server
          * dictates). <b>Note:</b> The SSLContext provided by this method will be
-         * ignored if using a Serializable Configuration (see {@link #buildSerializableConfig()}).
+         * ignored if using a Serializable Configuration
          * If a Serializable Configuration is required and communications are to be
          * secure, the {@link #keystoreFilename(String)}, {@link #keystorePass(String)},
          * {@link #keystoreType}, {@link #truststoreFilename}, {@link #truststorePass(String)},
@@ -755,8 +753,6 @@ public interface SiteToSiteClient extends Closeable {
 
     }
 
-
-    @SuppressWarnings("deprecation")
     class StandardSiteToSiteClientConfig implements SiteToSiteClientConfig, Serializable {
 
         private static final long serialVersionUID = 1L;
@@ -882,45 +878,48 @@ public interface SiteToSiteClient extends Closeable {
                 return sslContext;
             }
 
-            final KeyManagerFactory keyManagerFactory;
+            final KeyStore keyStore;
             if (keystoreFilename != null && keystorePass != null && keystoreType != null) {
-                try {
-                    // prepare the keystore
-                    final KeyStore keyStore = KeyStoreUtils.getKeyStore(getKeystoreType().name());
-                    try (final InputStream keyStoreStream = new FileInputStream(new File(getKeystoreFilename()))) {
-                        keyStore.load(keyStoreStream, keystorePass.toCharArray());
-                    }
-                    keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
-                    keyManagerFactory.init(keyStore, keystorePass.toCharArray());
-                } catch (final Exception e) {
-                    throw new IllegalStateException("Failed to load Keystore", e);
+                try (final InputStream keyStoreStream = Files.newInputStream(Paths.get(keystoreFilename))) {
+                    keyStore = new StandardKeyStoreBuilder()
+                            .inputStream(keyStoreStream)
+                            .password(keystorePass.toCharArray())
+                            .type(keystoreType.name())
+                            .build();
+                } catch (final IOException e) {
+                    throw new IllegalStateException(String.format("Read Key Store [%s] failed", keystoreFilename), e);
                 }
             } else {
-                keyManagerFactory = null;
+                keyStore = null;
             }
 
-            final TrustManagerFactory trustManagerFactory;
+            final KeyStore trustStore;
             if (truststoreFilename != null && truststorePass != null && truststoreType != null) {
-                try {
-                    trustManagerFactory = KeyStoreUtils.loadTrustManagerFactory(truststoreFilename, truststorePass, getTruststoreType().name());
-                } catch (final Exception e) {
-                    throw new IllegalStateException("Failed to load Truststore", e);
+                try (final InputStream keyStoreStream = Files.newInputStream(Paths.get(truststoreFilename))) {
+                    trustStore = new StandardKeyStoreBuilder()
+                            .inputStream(keyStoreStream)
+                            .password(truststorePass.toCharArray())
+                            .type(truststoreType.name())
+                            .build();
+                } catch (final IOException e) {
+                    throw new IllegalStateException(String.format("Read Trust Store [%s] failed", truststoreFilename), e);
                 }
             } else {
-                trustManagerFactory = null;
+                trustStore = null;
             }
 
-            if (keyManagerFactory != null && trustManagerFactory != null) {
-                try {
-                    // initialize the ssl context
-                    final SSLContext sslContext = SSLContext.getInstance(TlsConfiguration.getHighestCurrentSupportedTlsProtocolVersion());
-                    sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());
-                    sslContext.getDefaultSSLParameters().setNeedClientAuth(true);
+            if (keyStore != null || trustStore != null) {
+                final StandardSslContextBuilder builder = new StandardSslContextBuilder();
 
-                    return sslContext;
-                } catch (final Exception e) {
-                    throw new IllegalStateException("Created keystore and truststore but failed to initialize SSLContext", e);
+                if (keyStore != null) {
+                    final char[] keyPassword = keystorePass.toCharArray();
+                    builder.keyPassword(keyPassword);
+                    builder.keyStore(keyStore);
+                }
+                if (trustStore != null) {
+                    builder.trustStore(trustStore);
                 }
+                return builder.build();
             } else {
                 return null;
             }
diff --git a/nifi-commons/nifi-site-to-site-client/src/test/java/org/apache/nifi/remote/client/http/TestHttpClient.java b/nifi-commons/nifi-site-to-site-client/src/test/java/org/apache/nifi/remote/client/http/TestHttpClient.java
index e26b4b6638..93a1fe8def 100644
--- a/nifi-commons/nifi-site-to-site-client/src/test/java/org/apache/nifi/remote/client/http/TestHttpClient.java
+++ b/nifi-commons/nifi-site-to-site-client/src/test/java/org/apache/nifi/remote/client/http/TestHttpClient.java
@@ -1377,6 +1377,6 @@ public class TestHttpClient {
     }
 
     private static void setTlsConfiguration() {
-        tlsConfiguration = new TemporaryKeyStoreBuilder().build();
+        tlsConfiguration = new TemporaryKeyStoreBuilder().trustStoreType(KeystoreType.JKS.name()).build();
     }
 }
diff --git a/nifi-registry/nifi-registry-core/nifi-registry-client/pom.xml b/nifi-registry/nifi-registry-core/nifi-registry-client/pom.xml
index 91751dba2b..8f1ab84f49 100644
--- a/nifi-registry/nifi-registry-core/nifi-registry-client/pom.xml
+++ b/nifi-registry/nifi-registry-core/nifi-registry-client/pom.xml
@@ -31,6 +31,11 @@
             <artifactId>nifi-registry-security-utils</artifactId>
             <version>1.19.0-SNAPSHOT</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-security-ssl</artifactId>
+            <version>1.19.0-SNAPSHOT</version>
+        </dependency>
         <dependency>
             <groupId>org.glassfish.jersey.core</groupId>
             <artifactId>jersey-client</artifactId>
diff --git a/nifi-registry/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/NiFiRegistryClientConfig.java b/nifi-registry/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/NiFiRegistryClientConfig.java
index 784f77fc99..95ff6d12b1 100644
--- a/nifi-registry/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/NiFiRegistryClientConfig.java
+++ b/nifi-registry/nifi-registry-core/nifi-registry-client/src/main/java/org/apache/nifi/registry/client/NiFiRegistryClientConfig.java
@@ -16,28 +16,24 @@
  */
 package org.apache.nifi.registry.client;
 
-import org.apache.nifi.registry.security.util.CertificateUtils;
-import org.apache.nifi.registry.security.util.KeyStoreUtils;
 import org.apache.nifi.registry.security.util.KeystoreType;
+import org.apache.nifi.security.ssl.StandardKeyStoreBuilder;
+import org.apache.nifi.security.ssl.StandardSslContextBuilder;
 
 import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.KeyManager;
-import javax.net.ssl.KeyManagerFactory;
 import javax.net.ssl.SSLContext;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-import java.io.File;
-import java.io.FileInputStream;
+import java.io.IOException;
 import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
 import java.security.KeyStore;
-import java.security.SecureRandom;
 
 /**
  * Configuration for a NiFiRegistryClient.
  */
 public class NiFiRegistryClientConfig {
 
-    public static final String DEFAULT_PROTOCOL = CertificateUtils.getHighestCurrentSupportedTlsProtocolVersion();
+    private static final String DEFAULT_PROTOCOL = "TLS";
 
     private final String baseUrl;
     private final SSLContext sslContext;
@@ -79,58 +75,49 @@ public class NiFiRegistryClientConfig {
             return sslContext;
         }
 
-        final KeyManagerFactory keyManagerFactory;
+        final KeyStore keyStore;
         if (keystoreFilename != null && keystorePass != null && keystoreType != null) {
-            try {
-                // prepare the keystore
-                final KeyStore keyStore = KeyStoreUtils.getKeyStore(keystoreType.name());
-                try (final InputStream keyStoreStream = new FileInputStream(new File(keystoreFilename))) {
-                    keyStore.load(keyStoreStream, keystorePass.toCharArray());
-                }
-                keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
-
-                if (keyPass == null) {
-                    keyManagerFactory.init(keyStore, keystorePass.toCharArray());
-                } else {
-                    keyManagerFactory.init(keyStore, keyPass.toCharArray());
-                }
-            } catch (final Exception e) {
-                throw new IllegalStateException("Failed to load Keystore", e);
+            try (final InputStream keyStoreStream = Files.newInputStream(Paths.get(keystoreFilename))) {
+                keyStore = new StandardKeyStoreBuilder()
+                        .inputStream(keyStoreStream)
+                        .password(keystorePass.toCharArray())
+                        .type(keystoreType.name())
+                        .build();
+            } catch (final IOException e) {
+                throw new IllegalStateException(String.format("Read Key Store [%s] failed", keystoreFilename), e);
             }
         } else {
-            keyManagerFactory = null;
+            keyStore = null;
         }
 
-        final TrustManagerFactory trustManagerFactory;
+        final KeyStore trustStore;
         if (truststoreFilename != null && truststorePass != null && truststoreType != null) {
-            try {
-                // prepare the truststore
-                final KeyStore trustStore = KeyStoreUtils.getKeyStore(truststoreType.name());
-                try (final InputStream trustStoreStream = new FileInputStream(new File(truststoreFilename))) {
-                    trustStore.load(trustStoreStream, truststorePass.toCharArray());
-                }
-                trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
-                trustManagerFactory.init(trustStore);
-            } catch (final Exception e) {
-                throw new IllegalStateException("Failed to load Truststore", e);
+            try (final InputStream keyStoreStream = Files.newInputStream(Paths.get(truststoreFilename))) {
+                trustStore = new StandardKeyStoreBuilder()
+                        .inputStream(keyStoreStream)
+                        .password(truststorePass.toCharArray())
+                        .type(truststoreType.name())
+                        .build();
+            } catch (final IOException e) {
+                throw new IllegalStateException(String.format("Read Trust Store [%s] failed", truststoreFilename), e);
             }
         } else {
-            trustManagerFactory = null;
+            trustStore = null;
         }
 
-        if (keyManagerFactory != null || trustManagerFactory != null) {
-            try {
-                // initialize the ssl context
-                KeyManager[] keyManagers = keyManagerFactory != null ? keyManagerFactory.getKeyManagers() : null;
-                TrustManager[] trustManagers = trustManagerFactory != null ? trustManagerFactory.getTrustManagers() : null;
-                final SSLContext sslContext = SSLContext.getInstance(getProtocol());
-                sslContext.init(keyManagers, trustManagers, new SecureRandom());
-                sslContext.getDefaultSSLParameters().setNeedClientAuth(true);
-
-                return sslContext;
-            } catch (final Exception e) {
-                throw new IllegalStateException("Created keystore and truststore but failed to initialize SSLContext", e);
+        if (keyStore != null || trustStore != null) {
+            final StandardSslContextBuilder builder = new StandardSslContextBuilder();
+            builder.protocol(protocol);
+
+            if (keyStore != null) {
+                final char[] keyPassword = keyPass == null ? keystorePass.toCharArray() : keyPass.toCharArray();
+                builder.keyPassword(keyPassword);
+                builder.keyStore(keyStore);
+            }
+            if (trustStore != null) {
+                builder.trustStore(trustStore);
             }
+            return builder.build();
         } else {
             return null;
         }
diff --git a/nifi-registry/nifi-registry-core/nifi-registry-framework/pom.xml b/nifi-registry/nifi-registry-core/nifi-registry-framework/pom.xml
index 77dcc7e5a4..1cff5c0cba 100644
--- a/nifi-registry/nifi-registry-core/nifi-registry-framework/pom.xml
+++ b/nifi-registry/nifi-registry-core/nifi-registry-framework/pom.xml
@@ -211,6 +211,11 @@
             <artifactId>nifi-h2-database-migrator</artifactId>
             <version>1.19.0-SNAPSHOT</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-security-ssl</artifactId>
+            <version>1.19.0-SNAPSHOT</version>
+        </dependency>
         <dependency>
             <groupId>org.apache.nifi</groupId>
             <artifactId>nifi-xml-processing</artifactId>
diff --git a/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/ldap/LdapIdentityProvider.java b/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/ldap/LdapIdentityProvider.java
index 4427ed951d..47760c1c86 100644
--- a/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/ldap/LdapIdentityProvider.java
+++ b/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/ldap/LdapIdentityProvider.java
@@ -26,9 +26,9 @@ import org.apache.nifi.registry.security.authentication.exception.IdentityAccess
 import org.apache.nifi.registry.security.authentication.exception.InvalidCredentialsException;
 import org.apache.nifi.registry.security.exception.SecurityProviderCreationException;
 import org.apache.nifi.registry.security.exception.SecurityProviderDestructionException;
-import org.apache.nifi.registry.security.util.SslContextFactory;
-import org.apache.nifi.registry.security.util.SslContextFactory.ClientAuth;
 import org.apache.nifi.registry.util.FormatUtils;
+import org.apache.nifi.security.ssl.StandardKeyStoreBuilder;
+import org.apache.nifi.security.ssl.StandardSslContextBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.ldap.AuthenticationException;
@@ -49,12 +49,9 @@ import org.springframework.security.ldap.userdetails.LdapUserDetails;
 
 import javax.naming.Context;
 import javax.net.ssl.SSLContext;
+import java.io.FileInputStream;
 import java.io.IOException;
-import java.security.KeyManagementException;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.CertificateException;
+import java.security.KeyStore;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
@@ -79,8 +76,9 @@ public class LdapIdentityProvider extends BasicAuthIdentityProvider implements I
             throw new SecurityProviderCreationException("The Authentication Expiration must be specified.");
         }
 
+
         try {
-            expiration = FormatUtils.getTimeDuration(rawExpiration, TimeUnit.MILLISECONDS);
+            expiration = Math.round(FormatUtils.getPreciseTimeDuration(rawExpiration, TimeUnit.MILLISECONDS));
         } catch (final IllegalArgumentException iae) {
             throw new SecurityProviderCreationException(String.format("The Expiration Duration '%s' is not a valid time duration", rawExpiration));
         }
@@ -243,12 +241,11 @@ public class LdapIdentityProvider extends BasicAuthIdentityProvider implements I
         try {
             final String username = authenticationRequest.getUsername();
             final Object credentials = authenticationRequest.getCredentials();
-            final String password = credentials != null && credentials instanceof String ? (String) credentials : null;
 
             // perform the authentication
             final UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, credentials);
             final Authentication authentication = ldapAuthenticationProvider.authenticate(token);
-            logger.debug("Created authentication token: {}", token.toString());
+            logger.debug("Created authentication token: {}", token);
 
             // use dn if configured
             if (IdentityStrategy.USE_DN.equals(identityStrategy)) {
@@ -294,8 +291,8 @@ public class LdapIdentityProvider extends BasicAuthIdentityProvider implements I
         final String rawTimeout = configurationContext.getProperty(configurationProperty);
         if (StringUtils.isNotBlank(rawTimeout)) {
             try {
-                final Long timeout = FormatUtils.getTimeDuration(rawTimeout, TimeUnit.MILLISECONDS);
-                baseEnvironment.put(environmentKey, timeout.toString());
+                final long timeout = Math.round(FormatUtils.getPreciseTimeDuration(rawTimeout, TimeUnit.MILLISECONDS));
+                baseEnvironment.put(environmentKey, Long.toString(timeout));
             } catch (final IllegalArgumentException iae) {
                 throw new SecurityProviderCreationException(String.format("The %s '%s' is not a valid time duration", configurationProperty, rawTimeout));
             }
@@ -309,7 +306,6 @@ public class LdapIdentityProvider extends BasicAuthIdentityProvider implements I
         final String rawTruststore = configurationContext.getProperty("TLS - Truststore");
         final String rawTruststorePassword = configurationContext.getProperty("TLS - Truststore Password");
         final String rawTruststoreType = configurationContext.getProperty("TLS - Truststore Type");
-        final String rawClientAuth = configurationContext.getProperty("TLS - Client Auth");
         final String rawProtocol = configurationContext.getProperty("TLS - Protocol");
 
         // create the ssl context
@@ -323,29 +319,32 @@ public class LdapIdentityProvider extends BasicAuthIdentityProvider implements I
                     throw new SecurityProviderCreationException("TLS - Protocol must be specified.");
                 }
 
-                if (StringUtils.isBlank(rawKeystore)) {
-                    sslContext = SslContextFactory.createTrustSslContext(rawTruststore, rawTruststorePassword.toCharArray(), rawTruststoreType, rawProtocol);
-                } else if (StringUtils.isBlank(rawTruststore)) {
-                    sslContext = SslContextFactory.createSslContext(rawKeystore, rawKeystorePassword.toCharArray(), rawKeystoreType, rawProtocol);
-                } else {
-                    // determine the client auth if specified
-                    final ClientAuth clientAuth;
-                    if (StringUtils.isBlank(rawClientAuth)) {
-                        clientAuth = ClientAuth.NONE;
-                    } else {
-                        try {
-                            clientAuth = ClientAuth.valueOf(rawClientAuth);
-                        } catch (final IllegalArgumentException iae) {
-                            throw new SecurityProviderCreationException(String.format("Unrecognized client auth '%s'. Possible values are [%s]",
-                                    rawClientAuth, StringUtils.join(ClientAuth.values(), ", ")));
-                        }
+                final StandardSslContextBuilder sslContextBuilder = new StandardSslContextBuilder().protocol(rawProtocol);
+
+                if (StringUtils.isNotBlank(rawTruststore)) {
+                    try (final FileInputStream trustStoreStream = new FileInputStream(rawTruststore)) {
+                        final KeyStore trustStore = new StandardKeyStoreBuilder()
+                                .type(rawTruststoreType)
+                                .password(rawTruststorePassword.toCharArray())
+                                .inputStream(trustStoreStream).build();
+                        sslContextBuilder.trustStore(trustStore);
                     }
+                }
 
-                    sslContext = SslContextFactory.createSslContext(rawKeystore, rawKeystorePassword.toCharArray(), rawKeystoreType,
-                            rawTruststore, rawTruststorePassword.toCharArray(), rawTruststoreType, clientAuth, rawProtocol);
+                if (StringUtils.isNotBlank(rawKeystore)) {
+                    try (final FileInputStream keyStoreStream = new FileInputStream(rawKeystore)) {
+                        final KeyStore keyStore = new StandardKeyStoreBuilder()
+                                .type(rawKeystoreType)
+                                .password(rawKeystorePassword.toCharArray())
+                                .inputStream(keyStoreStream).build();
+                        sslContextBuilder.keyStore(keyStore);
+                        sslContextBuilder.keyPassword(rawKeystorePassword.toCharArray());
+                    }
                 }
+
+                sslContext = sslContextBuilder.build();
             }
-        } catch (final KeyStoreException | NoSuchAlgorithmException | CertificateException | UnrecoverableKeyException | KeyManagementException | IOException e) {
+        } catch (final RuntimeException | IOException e) {
             throw new SecurityProviderCreationException(e.getMessage(), e);
         }
 
diff --git a/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/ldap/tenants/LdapUserGroupProvider.java b/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/ldap/tenants/LdapUserGroupProvider.java
index 8ecd56d358..39664d12cd 100644
--- a/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/ldap/tenants/LdapUserGroupProvider.java
+++ b/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/ldap/tenants/LdapUserGroupProvider.java
@@ -31,10 +31,10 @@ import org.apache.nifi.registry.security.identity.IdentityMapper;
 import org.apache.nifi.registry.security.ldap.LdapAuthenticationStrategy;
 import org.apache.nifi.registry.security.ldap.LdapsSocketFactory;
 import org.apache.nifi.registry.security.ldap.ReferralStrategy;
-import org.apache.nifi.registry.security.util.SslContextFactory;
-import org.apache.nifi.registry.security.util.SslContextFactory.ClientAuth;
 import org.apache.nifi.registry.util.FormatUtils;
 import org.apache.nifi.registry.util.PropertyValue;
+import org.apache.nifi.security.ssl.StandardKeyStoreBuilder;
+import org.apache.nifi.security.ssl.StandardSslContextBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.ldap.control.PagedResultsDirContextProcessor;
@@ -60,12 +60,9 @@ import javax.naming.NamingException;
 import javax.naming.directory.Attribute;
 import javax.naming.directory.SearchControls;
 import javax.net.ssl.SSLContext;
+import java.io.FileInputStream;
 import java.io.IOException;
-import java.security.KeyManagementException;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.CertificateException;
+import java.security.KeyStore;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -116,7 +113,7 @@ public class LdapUserGroupProvider implements UserGroupProvider {
     private IdentityMapper identityMapper;
 
     private ScheduledExecutorService ldapSync;
-    private AtomicReference<TenantHolder> tenants = new AtomicReference<>(null);
+    private final AtomicReference<TenantHolder> tenants = new AtomicReference<>(null);
 
     private String userSearchBase;
     private SearchScope userSearchScope;
@@ -366,7 +363,7 @@ public class LdapUserGroupProvider implements UserGroupProvider {
         final long syncInterval;
         if (rawSyncInterval.isSet()) {
             try {
-                syncInterval = FormatUtils.getTimeDuration(rawSyncInterval.getValue(), TimeUnit.MILLISECONDS);
+                syncInterval = Math.round(FormatUtils.getPreciseTimeDuration(rawSyncInterval.getValue(), TimeUnit.MILLISECONDS));
             } catch (final IllegalArgumentException iae) {
                 throw new SecurityProviderCreationException(String.format("The %s '%s' is not a valid time duration", PROP_SYNC_INTERVAL, rawSyncInterval.getValue()));
             }
@@ -389,7 +386,7 @@ public class LdapUserGroupProvider implements UserGroupProvider {
                 try {
                     load(context);
                 } catch (final Throwable t) {
-                    logger.error("Failed to sync User/Groups from LDAP due to {}. Will try again in {} millis.", new Object[] {t.toString(), syncInterval});
+                    logger.error("Failed to sync User/Groups from LDAP due to {}. Will try again in {} millis.", t, syncInterval);
                     if (logger.isDebugEnabled()) {
                         logger.error("", t);
                     }
@@ -560,8 +557,6 @@ public class LdapUserGroupProvider implements UserGroupProvider {
                     groupList.addAll(ldapTemplate.search(groupSearchBase, groupFilter.encode(), groupControls, new AbstractContextMapper<Group>() {
                         @Override
                         protected Group doMapFromContext(DirContextOperations ctx) {
-                            final String dn = ctx.getDn().toString();
-
                             // get the group identity
                             final String name = getGroupName(ctx);
 
@@ -630,7 +625,7 @@ public class LdapUserGroupProvider implements UserGroupProvider {
 
                             // add all users that were associated with this referenced group attribute
                             if (groupToUserIdentifierMappings.containsKey(referencedGroupValue)) {
-                                groupToUserIdentifierMappings.remove(referencedGroupValue).forEach(userIdentifier -> groupBuilder.addUser(userIdentifier));
+                                groupToUserIdentifierMappings.remove(referencedGroupValue).forEach(groupBuilder::addUser);
                             }
 
                             return groupBuilder.build();
@@ -639,11 +634,10 @@ public class LdapUserGroupProvider implements UserGroupProvider {
                 } while (hasMorePages(groupProcessor));
 
                 // any remaining groupDn's were referenced by a user but not found while searching groups
-                groupToUserIdentifierMappings.forEach((referencedGroupValue, userIdentifiers) -> {
-                    logger.debug(String.format("[%s] are members of %s but that group was not found while searching groups. " +
-                                    "This may be due to misconfiguration or because that group is not a NiFi Registry group as defined by the Group Search Base and Filter. " +
-                                    "Ignoring group membership.", StringUtils.join(userIdentifiers, ", "), referencedGroupValue));
-                });
+                groupToUserIdentifierMappings.forEach((referencedGroupValue, userIdentifiers) -> logger.debug(String.format(
+                                "[%s] are members of %s but that group was not found while searching groups. " +
+                                "This may be due to misconfiguration or because that group is not a NiFi Registry group as defined by the Group Search Base and Filter. " +
+                                "Ignoring group membership.", StringUtils.join(userIdentifiers, ", "), referencedGroupValue)));
             } else {
                 // since performGroupSearch is false, then the referenced user attribute must be blank... the group value must be the dn
 
@@ -661,7 +655,7 @@ public class LdapUserGroupProvider implements UserGroupProvider {
                     final Group.Builder groupBuilder = new Group.Builder().identifierGenerateFromSeed(groupName).name(groupName);
 
                     // add each user
-                    userIdentifiers.forEach(userIdentifier -> groupBuilder.addUser(userIdentifier));
+                    userIdentifiers.forEach(groupBuilder::addUser);
 
                     // build the group
                     groupList.add(groupBuilder.build());
@@ -799,8 +793,8 @@ public class LdapUserGroupProvider implements UserGroupProvider {
         final PropertyValue rawTimeout = configurationContext.getProperty(configurationProperty);
         if (rawTimeout.isSet()) {
             try {
-                final Long timeout = FormatUtils.getTimeDuration(rawTimeout.getValue(), TimeUnit.MILLISECONDS);
-                baseEnvironment.put(environmentKey, timeout.toString());
+                final long timeout = Math.round(FormatUtils.getPreciseTimeDuration(rawTimeout.getValue(), TimeUnit.MILLISECONDS));
+                baseEnvironment.put(environmentKey, Long.toString(timeout));
             } catch (final IllegalArgumentException iae) {
                 throw new SecurityProviderCreationException(String.format("The %s '%s' is not a valid time duration", configurationProperty, rawTimeout));
             }
@@ -814,7 +808,6 @@ public class LdapUserGroupProvider implements UserGroupProvider {
         final String rawTruststore = configurationContext.getProperty("TLS - Truststore").getValue();
         final String rawTruststorePassword = configurationContext.getProperty("TLS - Truststore Password").getValue();
         final String rawTruststoreType = configurationContext.getProperty("TLS - Truststore Type").getValue();
-        final String rawClientAuth = configurationContext.getProperty("TLS - Client Auth").getValue();
         final String rawProtocol = configurationContext.getProperty("TLS - Protocol").getValue();
 
         // create the ssl context
@@ -828,29 +821,32 @@ public class LdapUserGroupProvider implements UserGroupProvider {
                     throw new SecurityProviderCreationException("TLS - Protocol must be specified.");
                 }
 
-                if (StringUtils.isBlank(rawKeystore)) {
-                    sslContext = SslContextFactory.createTrustSslContext(rawTruststore, rawTruststorePassword.toCharArray(), rawTruststoreType, rawProtocol);
-                } else if (StringUtils.isBlank(rawTruststore)) {
-                    sslContext = SslContextFactory.createSslContext(rawKeystore, rawKeystorePassword.toCharArray(), rawKeystoreType, rawProtocol);
-                } else {
-                    // determine the client auth if specified
-                    final ClientAuth clientAuth;
-                    if (StringUtils.isBlank(rawClientAuth)) {
-                        clientAuth = ClientAuth.NONE;
-                    } else {
-                        try {
-                            clientAuth = ClientAuth.valueOf(rawClientAuth);
-                        } catch (final IllegalArgumentException iae) {
-                            throw new SecurityProviderCreationException(String.format("Unrecognized client auth '%s'. Possible values are [%s]",
-                                    rawClientAuth, StringUtils.join(ClientAuth.values(), ", ")));
-                        }
+                final StandardSslContextBuilder sslContextBuilder = new StandardSslContextBuilder().protocol(rawProtocol);
+
+                if (StringUtils.isNotBlank(rawTruststore)) {
+                    try (final FileInputStream trustStoreStream = new FileInputStream(rawTruststore)) {
+                        final KeyStore trustStore = new StandardKeyStoreBuilder()
+                                .type(rawTruststoreType)
+                                .password(rawTruststorePassword.toCharArray())
+                                .inputStream(trustStoreStream).build();
+                        sslContextBuilder.trustStore(trustStore);
                     }
+                }
 
-                    sslContext = SslContextFactory.createSslContext(rawKeystore, rawKeystorePassword.toCharArray(), rawKeystoreType,
-                            rawTruststore, rawTruststorePassword.toCharArray(), rawTruststoreType, clientAuth, rawProtocol);
+                if (StringUtils.isNotBlank(rawKeystore)) {
+                    try (final FileInputStream keyStoreStream = new FileInputStream(rawKeystore)) {
+                        final KeyStore keyStore = new StandardKeyStoreBuilder()
+                                .type(rawKeystoreType)
+                                .password(rawKeystorePassword.toCharArray())
+                                .inputStream(keyStoreStream).build();
+                        sslContextBuilder.keyStore(keyStore);
+                        sslContextBuilder.keyPassword(rawKeystorePassword.toCharArray());
+                    }
                 }
+
+                sslContext = sslContextBuilder.build();
             }
-        } catch (final KeyStoreException | NoSuchAlgorithmException | CertificateException | UnrecoverableKeyException | KeyManagementException | IOException e) {
+        } catch (final RuntimeException | IOException e) {
             throw new SecurityProviderCreationException(e.getMessage(), e);
         }
 
diff --git a/nifi-registry/nifi-registry-core/nifi-registry-security-utils/src/main/java/org/apache/nifi/registry/security/util/CertificateUtils.java b/nifi-registry/nifi-registry-core/nifi-registry-security-utils/src/main/java/org/apache/nifi/registry/security/util/CertificateUtils.java
deleted file mode 100644
index d766b577b8..0000000000
--- a/nifi-registry/nifi-registry-core/nifi-registry-security-utils/src/main/java/org/apache/nifi/registry/security/util/CertificateUtils.java
+++ /dev/null
@@ -1,671 +0,0 @@
-/*
- * 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.nifi.registry.security.util;
-
-import org.apache.commons.lang3.StringUtils;
-import org.bouncycastle.asn1.ASN1Encodable;
-import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import org.bouncycastle.asn1.ASN1Set;
-import org.bouncycastle.asn1.DERSequence;
-import org.bouncycastle.asn1.pkcs.Attribute;
-import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-import org.bouncycastle.asn1.x500.AttributeTypeAndValue;
-import org.bouncycastle.asn1.x500.RDN;
-import org.bouncycastle.asn1.x500.X500Name;
-import org.bouncycastle.asn1.x500.style.BCStyle;
-import org.bouncycastle.asn1.x509.BasicConstraints;
-import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
-import org.bouncycastle.asn1.x509.Extension;
-import org.bouncycastle.asn1.x509.Extensions;
-import org.bouncycastle.asn1.x509.KeyPurposeId;
-import org.bouncycastle.asn1.x509.KeyUsage;
-import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
-import org.bouncycastle.cert.CertIOException;
-import org.bouncycastle.cert.X509CertificateHolder;
-import org.bouncycastle.cert.X509v3CertificateBuilder;
-import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
-import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
-import org.bouncycastle.operator.ContentSigner;
-import org.bouncycastle.operator.OperatorCreationException;
-import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
-import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.naming.InvalidNameException;
-import javax.naming.ldap.LdapName;
-import javax.naming.ldap.Rdn;
-import javax.net.ssl.SSLPeerUnverifiedException;
-import javax.net.ssl.SSLSocket;
-import java.io.ByteArrayInputStream;
-import java.math.BigInteger;
-import java.net.Socket;
-import java.security.KeyPair;
-import java.security.NoSuchAlgorithmException;
-import java.security.PublicKey;
-import java.security.Security;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactory;
-import java.security.cert.CertificateParsingException;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-public final class CertificateUtils {
-    private static final Logger logger = LoggerFactory.getLogger(CertificateUtils.class);
-    private static final String PEER_NOT_AUTHENTICATED_MSG = "peer not authenticated";
-    private static final Map<ASN1ObjectIdentifier, Integer> dnOrderMap = createDnOrderMap();
-
-    public static final String JAVA_8_MAX_SUPPORTED_TLS_PROTOCOL_VERSION = "TLSv1.2";
-    public static final String JAVA_11_MAX_SUPPORTED_TLS_PROTOCOL_VERSION = "TLSv1.3";
-    public static final String[] JAVA_8_SUPPORTED_TLS_PROTOCOL_VERSIONS = new String[]{JAVA_8_MAX_SUPPORTED_TLS_PROTOCOL_VERSION};
-    public static final String[] JAVA_11_SUPPORTED_TLS_PROTOCOL_VERSIONS = new String[]{JAVA_11_MAX_SUPPORTED_TLS_PROTOCOL_VERSION, JAVA_8_MAX_SUPPORTED_TLS_PROTOCOL_VERSION};
-
-    static {
-        Security.addProvider(new BouncyCastleProvider());
-    }
-
-    /**
-     * The time in milliseconds that the last unique serial number was generated
-     */
-    private static long lastSerialNumberMillis = 0L;
-
-    /**
-     * An incrementor to add uniqueness to serial numbers generated in the same millisecond
-     */
-    private static int serialNumberIncrementor = 0;
-
-    /**
-     * BigInteger value to use for the base of the unique serial number
-     */
-    private static BigInteger millisecondBigInteger;
-
-    private static Map<ASN1ObjectIdentifier, Integer> createDnOrderMap() {
-        Map<ASN1ObjectIdentifier, Integer> orderMap = new HashMap<>();
-        int count = 0;
-        orderMap.put(BCStyle.CN, count++);
-        orderMap.put(BCStyle.L, count++);
-        orderMap.put(BCStyle.ST, count++);
-        orderMap.put(BCStyle.O, count++);
-        orderMap.put(BCStyle.OU, count++);
-        orderMap.put(BCStyle.C, count++);
-        orderMap.put(BCStyle.STREET, count++);
-        orderMap.put(BCStyle.DC, count++);
-        orderMap.put(BCStyle.UID, count++);
-        return Collections.unmodifiableMap(orderMap);
-    }
-
-    /**
-     * Extracts the username from the specified DN. If the username cannot be extracted because the CN is in an unrecognized format, the entire CN is returned. If the CN cannot be extracted because
-     * the DN is in an unrecognized format, the entire DN is returned.
-     *
-     * @param dn the dn to extract the username from
-     * @return the exatracted username
-     */
-    public static String extractUsername(String dn) {
-        String username = dn;
-
-        // ensure the dn is specified
-        if (StringUtils.isNotBlank(dn)) {
-            // determine the separate
-            final String separator = StringUtils.indexOfIgnoreCase(dn, "/cn=") > 0 ? "/" : ",";
-
-            // attempt to locate the cd
-            final String cnPattern = "cn=";
-            final int cnIndex = StringUtils.indexOfIgnoreCase(dn, cnPattern);
-            if (cnIndex >= 0) {
-                int separatorIndex = StringUtils.indexOf(dn, separator, cnIndex);
-                if (separatorIndex > 0) {
-                    username = StringUtils.substring(dn, cnIndex + cnPattern.length(), separatorIndex);
-                } else {
-                    username = StringUtils.substring(dn, cnIndex + cnPattern.length());
-                }
-            }
-        }
-
-        return username;
-    }
-
-    /**
-     * Returns a list of subject alternative names. Any name that is represented as a String by X509Certificate.getSubjectAlternativeNames() is converted to lowercase and returned.
-     *
-     * @param certificate a certificate
-     * @return a list of subject alternative names; list is never null
-     * @throws CertificateParsingException if parsing the certificate failed
-     */
-    public static List<String> getSubjectAlternativeNames(final X509Certificate certificate) throws CertificateParsingException {
-
-        final Collection<List<?>> altNames = certificate.getSubjectAlternativeNames();
-        if (altNames == null) {
-            return new ArrayList<>();
-        }
-
-        final List<String> result = new ArrayList<>();
-        for (final List<?> generalName : altNames) {
-            /**
-             * generalName has the name type as the first element a String or byte array for the second element. We return any general names that are String types.
-             *
-             * We don't inspect the numeric name type because some certificates incorrectly put IPs and DNS names under the wrong name types.
-             */
-            final Object value = generalName.get(1);
-            if (value instanceof String) {
-                result.add(((String) value).toLowerCase());
-            }
-
-        }
-
-        return result;
-    }
-
-    /**
-     * Returns the DN extracted from the peer certificate (the server DN if run on the client; the client DN (if available) if run on the server).
-     * <p>
-     * If the client auth setting is WANT or NONE and a client certificate is not present, this method will return {@code null}.
-     * If the client auth is NEED, it will throw a {@link CertificateException}.
-     *
-     * @param socket the SSL Socket
-     * @return the extracted DN
-     * @throws CertificateException if there is a problem parsing the certificate
-     */
-    public static String extractPeerDNFromSSLSocket(Socket socket) throws CertificateException {
-        String dn = null;
-        if (socket instanceof SSLSocket) {
-            final SSLSocket sslSocket = (SSLSocket) socket;
-
-            boolean clientMode = sslSocket.getUseClientMode();
-            logger.debug("SSL Socket in {} mode", clientMode ? "client" : "server");
-            SslContextFactory.ClientAuth clientAuth = getClientAuthStatus(sslSocket);
-            logger.debug("SSL Socket client auth status: {}", clientAuth);
-
-            if (clientMode) {
-                logger.debug("This socket is in client mode, so attempting to extract certificate from remote 'server' socket");
-                dn = extractPeerDNFromServerSSLSocket(sslSocket);
-            } else {
-                logger.debug("This socket is in server mode, so attempting to extract certificate from remote 'client' socket");
-                dn = extractPeerDNFromClientSSLSocket(sslSocket);
-            }
-        }
-
-        return dn;
-    }
-
-    /**
-     * Returns the DN extracted from the client certificate.
-     * <p>
-     * If the client auth setting is WANT or NONE and a certificate is not present (and {@code respectClientAuth} is {@code true}), this method will return {@code null}.
-     * If the client auth is NEED, it will throw a {@link CertificateException}.
-     *
-     * @param sslSocket the SSL Socket
-     * @return the extracted DN
-     * @throws CertificateException if there is a problem parsing the certificate
-     */
-    private static String extractPeerDNFromClientSSLSocket(SSLSocket sslSocket) throws CertificateException {
-        String dn = null;
-
-        /** The clientAuth value can be "need", "want", or "none"
-         * A client must send client certificates for need, should for want, and will not for none.
-         * This method should throw an exception if none are provided for need, return null if none are provided for want, and return null (without checking) for none.
-         */
-
-        SslContextFactory.ClientAuth clientAuth = getClientAuthStatus(sslSocket);
-        logger.debug("SSL Socket client auth status: {}", clientAuth);
-
-        if (clientAuth != SslContextFactory.ClientAuth.NONE) {
-            try {
-                final Certificate[] certChains = sslSocket.getSession().getPeerCertificates();
-                if (certChains != null && certChains.length > 0) {
-                    X509Certificate x509Certificate = convertAbstractX509Certificate(certChains[0]);
-                    dn = x509Certificate.getSubjectDN().getName().trim();
-                    logger.debug("Extracted DN={} from client certificate", dn);
-                }
-            } catch (SSLPeerUnverifiedException e) {
-                if (e.getMessage().equals(PEER_NOT_AUTHENTICATED_MSG)) {
-                    logger.error("The incoming request did not contain client certificates and thus the DN cannot" +
-                            " be extracted. Check that the other endpoint is providing a complete client certificate chain");
-                }
-                if (clientAuth == SslContextFactory.ClientAuth.WANT) {
-                    logger.warn("Suppressing missing client certificate exception because client auth is set to 'want'");
-                    return dn;
-                }
-                throw new CertificateException(e);
-            }
-        }
-        return dn;
-    }
-
-    /**
-     * Returns the DN extracted from the server certificate.
-     *
-     * @param socket the SSL Socket
-     * @return the extracted DN
-     * @throws CertificateException if there is a problem parsing the certificate
-     */
-    private static String extractPeerDNFromServerSSLSocket(Socket socket) throws CertificateException {
-        String dn = null;
-        if (socket instanceof SSLSocket) {
-            final SSLSocket sslSocket = (SSLSocket) socket;
-            try {
-                final Certificate[] certChains = sslSocket.getSession().getPeerCertificates();
-                if (certChains != null && certChains.length > 0) {
-                    X509Certificate x509Certificate = convertAbstractX509Certificate(certChains[0]);
-                    dn = x509Certificate.getSubjectDN().getName().trim();
-                    logger.debug("Extracted DN={} from server certificate", dn);
-                }
-            } catch (SSLPeerUnverifiedException e) {
-                if (e.getMessage().equals(PEER_NOT_AUTHENTICATED_MSG)) {
-                    logger.error("The server did not present a certificate and thus the DN cannot" +
-                            " be extracted. Check that the other endpoint is providing a complete certificate chain");
-                }
-                throw new CertificateException(e);
-            }
-        }
-        return dn;
-    }
-
-    private static SslContextFactory.ClientAuth getClientAuthStatus(SSLSocket sslSocket) {
-        return sslSocket.getNeedClientAuth() ? SslContextFactory.ClientAuth.REQUIRED : sslSocket.getWantClientAuth() ? SslContextFactory.ClientAuth.WANT : SslContextFactory.ClientAuth.NONE;
-    }
-
-    /**
-     * Accepts a legacy {@link javax.security.cert.X509Certificate} and returns an {@link X509Certificate}. The {@code javax.*} package certificate classes are for legacy compatibility and should
-     * not be used for new development.
-     *
-     * @param legacyCertificate the {@code javax.security.cert.X509Certificate}
-     * @return a new {@code java.security.cert.X509Certificate}
-     * @throws CertificateException if there is an error generating the new certificate
-     */
-    @SuppressWarnings("deprecation")
-    public static X509Certificate convertLegacyX509Certificate(javax.security.cert.X509Certificate legacyCertificate) throws CertificateException {
-        if (legacyCertificate == null) {
-            throw new IllegalArgumentException("The X.509 certificate cannot be null");
-        }
-
-        try {
-            return formX509Certificate(legacyCertificate.getEncoded());
-        } catch (javax.security.cert.CertificateEncodingException e) {
-            throw new CertificateException(e);
-        }
-    }
-
-    /**
-     * Accepts an abstract {@link java.security.cert.Certificate} and returns an {@link X509Certificate}. Because {@code sslSocket.getSession().getPeerCertificates()} returns an array of the
-     * abstract certificates, they must be translated to X.509 to replace the functionality of {@code sslSocket.getSession().getPeerCertificateChain()}.
-     *
-     * @param abstractCertificate the {@code java.security.cert.Certificate}
-     * @return a new {@code java.security.cert.X509Certificate}
-     * @throws CertificateException if there is an error generating the new certificate
-     */
-    public static X509Certificate convertAbstractX509Certificate(java.security.cert.Certificate abstractCertificate) throws CertificateException {
-        if (abstractCertificate == null || !(abstractCertificate instanceof X509Certificate)) {
-            throw new IllegalArgumentException("The certificate cannot be null and must be an X.509 certificate");
-        }
-
-        try {
-            return formX509Certificate(abstractCertificate.getEncoded());
-        } catch (java.security.cert.CertificateEncodingException e) {
-            throw new CertificateException(e);
-        }
-    }
-
-    private static X509Certificate formX509Certificate(byte[] encodedCertificate) throws CertificateException {
-        try {
-            CertificateFactory cf = CertificateFactory.getInstance("X.509");
-            ByteArrayInputStream bais = new ByteArrayInputStream(encodedCertificate);
-            return (X509Certificate) cf.generateCertificate(bais);
-        } catch (CertificateException e) {
-            logger.error("Error converting the certificate", e);
-            throw e;
-        }
-    }
-
-    /**
-     * Reorders DN to the order the elements appear in the RFC 2253 table
-     * <p>
-     * https://www.ietf.org/rfc/rfc2253.txt
-     * <p>
-     * String  X.500 AttributeType
-     * ------------------------------
-     * CN      commonName
-     * L       localityName
-     * ST      stateOrProvinceName
-     * O       organizationName
-     * OU      organizationalUnitName
-     * C       countryName
-     * STREET  streetAddress
-     * DC      domainComponent
-     * UID     userid
-     *
-     * @param dn a possibly unordered DN
-     * @return the ordered dn
-     */
-    public static String reorderDn(String dn) {
-        RDN[] rdNs = new X500Name(dn).getRDNs();
-        Arrays.sort(rdNs, new Comparator<RDN>() {
-            @Override
-            public int compare(RDN o1, RDN o2) {
-                AttributeTypeAndValue o1First = o1.getFirst();
-                AttributeTypeAndValue o2First = o2.getFirst();
-
-                ASN1ObjectIdentifier o1Type = o1First.getType();
-                ASN1ObjectIdentifier o2Type = o2First.getType();
-
-                Integer o1Rank = dnOrderMap.get(o1Type);
-                Integer o2Rank = dnOrderMap.get(o2Type);
-                if (o1Rank == null) {
-                    if (o2Rank == null) {
-                        int idComparison = o1Type.getId().compareTo(o2Type.getId());
-                        if (idComparison != 0) {
-                            return idComparison;
-                        }
-                        return String.valueOf(o1Type).compareTo(String.valueOf(o2Type));
-                    }
-                    return 1;
-                } else if (o2Rank == null) {
-                    return -1;
-                }
-                return o1Rank - o2Rank;
-            }
-        });
-        return new X500Name(rdNs).toString();
-    }
-
-    /**
-     * Reverses the X500Name in order make the certificate be in the right order
-     * [see http://stackoverflow.com/questions/7567837/attributes-reversed-in-certificate-subject-and-issuer/12645265]
-     *
-     * @param x500Name the X500Name created with the intended order
-     * @return the X500Name reversed
-     */
-    private static X500Name reverseX500Name(X500Name x500Name) {
-        List<RDN> rdns = Arrays.asList(x500Name.getRDNs());
-        Collections.reverse(rdns);
-        return new X500Name(rdns.toArray(new RDN[rdns.size()]));
-    }
-
-    /**
-     * Generates a unique serial number by using the current time in milliseconds left shifted 32 bits (to make room for incrementor) with an incrementor added
-     *
-     * @return a unique serial number (technically unique to this classloader)
-     */
-    protected static synchronized BigInteger getUniqueSerialNumber() {
-        final long currentTimeMillis = System.currentTimeMillis();
-        final int incrementorValue;
-
-        if (lastSerialNumberMillis != currentTimeMillis) {
-            // We can only get into this block once per millisecond
-            millisecondBigInteger = BigInteger.valueOf(currentTimeMillis).shiftLeft(32);
-            lastSerialNumberMillis = currentTimeMillis;
-            incrementorValue = 0;
-            serialNumberIncrementor = 1;
-        } else {
-            // Already created at least one serial number this millisecond
-            incrementorValue = serialNumberIncrementor++;
-        }
-
-        return millisecondBigInteger.add(BigInteger.valueOf(incrementorValue));
-    }
-
-    /**
-     * Generates a self-signed {@link X509Certificate} suitable for use as a Certificate Authority.
-     *
-     * @param keyPair                 the {@link KeyPair} to generate the {@link X509Certificate} for
-     * @param dn                      the distinguished name to user for the {@link X509Certificate}
-     * @param signingAlgorithm        the signing algorithm to use for the {@link X509Certificate}
-     * @param certificateDurationDays the duration in days for which the {@link X509Certificate} should be valid
-     * @return a self-signed {@link X509Certificate} suitable for use as a Certificate Authority
-     * @throws CertificateException if there is an generating the new certificate
-     */
-    public static X509Certificate generateSelfSignedX509Certificate(KeyPair keyPair, String dn, String signingAlgorithm, int certificateDurationDays)
-            throws CertificateException {
-        try {
-            ContentSigner sigGen = new JcaContentSignerBuilder(signingAlgorithm).setProvider(BouncyCastleProvider.PROVIDER_NAME).build(keyPair.getPrivate());
-            SubjectPublicKeyInfo subPubKeyInfo = SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded());
-            Date startDate = new Date();
-            Date endDate = new Date(startDate.getTime() + TimeUnit.DAYS.toMillis(certificateDurationDays));
-
-            X509v3CertificateBuilder certBuilder = new X509v3CertificateBuilder(
-                    reverseX500Name(new X500Name(dn)),
-                    getUniqueSerialNumber(),
-                    startDate, endDate,
-                    reverseX500Name(new X500Name(dn)),
-                    subPubKeyInfo);
-
-            // Set certificate extensions
-            // (1) digitalSignature extension
-            certBuilder.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment | KeyUsage.dataEncipherment
-                    | KeyUsage.keyAgreement | KeyUsage.nonRepudiation | KeyUsage.cRLSign | KeyUsage.keyCertSign));
-
-            certBuilder.addExtension(Extension.basicConstraints, false, new BasicConstraints(true));
-
-            certBuilder.addExtension(Extension.subjectKeyIdentifier, false, new JcaX509ExtensionUtils().createSubjectKeyIdentifier(keyPair.getPublic()));
-
-            certBuilder.addExtension(Extension.authorityKeyIdentifier, false, new JcaX509ExtensionUtils().createAuthorityKeyIdentifier(keyPair.getPublic()));
-
-            // (2) extendedKeyUsage extension
-            certBuilder.addExtension(Extension.extendedKeyUsage, false, new ExtendedKeyUsage(new KeyPurposeId[]{KeyPurposeId.id_kp_clientAuth, KeyPurposeId.id_kp_serverAuth}));
-
-            // Sign the certificate
-            X509CertificateHolder certificateHolder = certBuilder.build(sigGen);
-            return new JcaX509CertificateConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME).getCertificate(certificateHolder);
-        } catch (CertIOException | NoSuchAlgorithmException | OperatorCreationException e) {
-            throw new CertificateException(e);
-        }
-    }
-
-    /**
-     * Generates an issued {@link X509Certificate} from the given issuer certificate and {@link KeyPair}
-     *
-     * @param dn               the distinguished name to use
-     * @param publicKey        the public key to issue the certificate to
-     * @param issuer           the issuer's certificate
-     * @param issuerKeyPair    the issuer's keypair
-     * @param signingAlgorithm the signing algorithm to use
-     * @param days             the number of days it should be valid for
-     * @return an issued {@link X509Certificate} from the given issuer certificate and {@link KeyPair}
-     * @throws CertificateException if there is an error issuing the certificate
-     */
-    public static X509Certificate generateIssuedCertificate(String dn, PublicKey publicKey, X509Certificate issuer, KeyPair issuerKeyPair, String signingAlgorithm, int days)
-            throws CertificateException {
-        return generateIssuedCertificate(dn, publicKey, null, issuer, issuerKeyPair, signingAlgorithm, days);
-    }
-
-    /**
-     * Generates an issued {@link X509Certificate} from the given issuer certificate and {@link KeyPair}
-     *
-     * @param dn               the distinguished name to use
-     * @param publicKey        the public key to issue the certificate to
-     * @param extensions       extensions extracted from the CSR
-     * @param issuer           the issuer's certificate
-     * @param issuerKeyPair    the issuer's keypair
-     * @param signingAlgorithm the signing algorithm to use
-     * @param days             the number of days it should be valid for
-     * @return an issued {@link X509Certificate} from the given issuer certificate and {@link KeyPair}
-     * @throws CertificateException if there is an error issuing the certificate
-     */
-    public static X509Certificate generateIssuedCertificate(String dn, PublicKey publicKey, Extensions extensions, X509Certificate issuer, KeyPair issuerKeyPair, String signingAlgorithm, int days)
-            throws CertificateException {
-        try {
-            ContentSigner sigGen = new JcaContentSignerBuilder(signingAlgorithm).setProvider(BouncyCastleProvider.PROVIDER_NAME).build(issuerKeyPair.getPrivate());
-            SubjectPublicKeyInfo subPubKeyInfo = SubjectPublicKeyInfo.getInstance(publicKey.getEncoded());
-            Date startDate = new Date();
-            Date endDate = new Date(startDate.getTime() + TimeUnit.DAYS.toMillis(days));
-
-            X509v3CertificateBuilder certBuilder = new X509v3CertificateBuilder(
-                    reverseX500Name(new X500Name(issuer.getSubjectX500Principal().getName())),
-                    getUniqueSerialNumber(),
-                    startDate, endDate,
-                    reverseX500Name(new X500Name(dn)),
-                    subPubKeyInfo);
-
-            certBuilder.addExtension(Extension.subjectKeyIdentifier, false, new JcaX509ExtensionUtils().createSubjectKeyIdentifier(publicKey));
-
-            certBuilder.addExtension(Extension.authorityKeyIdentifier, false, new JcaX509ExtensionUtils().createAuthorityKeyIdentifier(issuerKeyPair.getPublic()));
-            // Set certificate extensions
-            // (1) digitalSignature extension
-            certBuilder.addExtension(Extension.keyUsage, true,
-                    new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment | KeyUsage.dataEncipherment | KeyUsage.keyAgreement | KeyUsage.nonRepudiation));
-
-            certBuilder.addExtension(Extension.basicConstraints, false, new BasicConstraints(false));
-
-            // (2) extendedKeyUsage extension
-            certBuilder.addExtension(Extension.extendedKeyUsage, false, new ExtendedKeyUsage(new KeyPurposeId[]{KeyPurposeId.id_kp_clientAuth, KeyPurposeId.id_kp_serverAuth}));
-
-            // (3) subjectAlternativeName
-            if (extensions != null && extensions.getExtension(Extension.subjectAlternativeName) != null) {
-                certBuilder.addExtension(Extension.subjectAlternativeName, false, extensions.getExtensionParsedValue(Extension.subjectAlternativeName));
-            }
-
-            X509CertificateHolder certificateHolder = certBuilder.build(sigGen);
-            return new JcaX509CertificateConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME).getCertificate(certificateHolder);
-        } catch (CertIOException | NoSuchAlgorithmException | OperatorCreationException e) {
-            throw new CertificateException(e);
-        }
-    }
-
-    /**
-     * Returns true if the two provided DNs are equivalent, regardless of the order of the elements. Returns false if one or both are invalid DNs.
-     * <p>
-     * Example:
-     * <p>
-     * CN=test1, O=testOrg, C=US compared to CN=test1, O=testOrg, C=US -> true
-     * CN=test1, O=testOrg, C=US compared to O=testOrg, CN=test1, C=US -> true
-     * CN=test1, O=testOrg, C=US compared to CN=test2, O=testOrg, C=US -> false
-     * CN=test1, O=testOrg, C=US compared to O=testOrg, CN=test2, C=US -> false
-     * CN=test1, O=testOrg, C=US compared to                           -> false
-     * compared to                           -> true
-     *
-     * @param dn1 the first DN to compare
-     * @param dn2 the second DN to compare
-     * @return true if the DNs are equivalent, false otherwise
-     */
-    public static boolean compareDNs(String dn1, String dn2) {
-        if (dn1 == null) {
-            dn1 = "";
-        }
-
-        if (dn2 == null) {
-            dn2 = "";
-        }
-
-        if (StringUtils.isEmpty(dn1) || StringUtils.isEmpty(dn2)) {
-            return dn1.equals(dn2);
-        }
-        try {
-            List<Rdn> rdn1 = new LdapName(dn1).getRdns();
-            List<Rdn> rdn2 = new LdapName(dn2).getRdns();
-
-            return rdn1.size() == rdn2.size() && rdn1.containsAll(rdn2);
-        } catch (InvalidNameException e) {
-            logger.warn("Cannot compare DNs: {} and {} because one or both is not a valid DN", dn1, dn2);
-            return false;
-        }
-    }
-
-    /**
-     * Extract extensions from CSR object
-     */
-    public static Extensions getExtensionsFromCSR(JcaPKCS10CertificationRequest csr) {
-        Attribute[] attributess = csr.getAttributes(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest);
-        for (Attribute attribute : attributess) {
-            ASN1Set attValue = attribute.getAttrValues();
-            if (attValue != null) {
-                ASN1Encodable extension = attValue.getObjectAt(0);
-                if (extension instanceof Extensions) {
-                    return (Extensions) extension;
-                } else if (extension instanceof DERSequence) {
-                    return Extensions.getInstance(extension);
-                }
-            }
-        }
-        return null;
-    }
-
-    /**
-     * Returns the JVM Java major version based on the System properties (e.g. {@code JVM 1.8.0.231} -> {code 8}).
-     *
-     * @return the Java major version
-     */
-    public static int getJavaVersion() {
-        String version = System.getProperty("java.version");
-        return parseJavaVersion(version);
-    }
-
-    /**
-     * Returns the major version parsed from the provided Java version string (e.g. {@code "1.8.0.231"} -> {@code 8}).
-     *
-     * @param version the Java version string
-     * @return the major version as an int
-     */
-    public static int parseJavaVersion(String version) {
-        String majorVersion;
-        if (version.startsWith("1.")) {
-            majorVersion = version.substring(2, 3);
-        } else {
-            Pattern majorVersion9PlusPattern = Pattern.compile("(\\d+).*");
-            Matcher m = majorVersion9PlusPattern.matcher(version);
-            if (m.find()) {
-                majorVersion = m.group(1);
-            } else {
-                throw new IllegalArgumentException("Could not detect major version of " + version);
-            }
-        }
-        return Integer.parseInt(majorVersion);
-    }
-
-    /**
-     * Returns a {@code String[]} of supported TLS protocol versions based on the current Java platform version.
-     *
-     * @return the supported TLS protocol version(s)
-     */
-    public static String[] getCurrentSupportedTlsProtocolVersions() {
-        int javaMajorVersion = getJavaVersion();
-        if (javaMajorVersion < 11) {
-            return JAVA_8_SUPPORTED_TLS_PROTOCOL_VERSIONS;
-        } else {
-            return JAVA_11_SUPPORTED_TLS_PROTOCOL_VERSIONS;
-        }
-    }
-
-    /**
-     * Returns the highest supported TLS protocol version based on the current Java platform version.
-     *
-     * @return the TLS protocol (e.g. {@code "TLSv1.2"})
-     */
-    public static String getHighestCurrentSupportedTlsProtocolVersion() {
-        int javaMajorVersion = getJavaVersion();
-        if (javaMajorVersion < 11) {
-            return JAVA_8_MAX_SUPPORTED_TLS_PROTOCOL_VERSION;
-        } else {
-            return JAVA_11_MAX_SUPPORTED_TLS_PROTOCOL_VERSION;
-        }
-    }
-
-    private CertificateUtils() {
-    }
-}
diff --git a/nifi-registry/nifi-registry-core/nifi-registry-security-utils/src/main/java/org/apache/nifi/registry/security/util/SslContextFactory.java b/nifi-registry/nifi-registry-core/nifi-registry-security-utils/src/main/java/org/apache/nifi/registry/security/util/SslContextFactory.java
deleted file mode 100644
index e10749951b..0000000000
--- a/nifi-registry/nifi-registry-core/nifi-registry-security-utils/src/main/java/org/apache/nifi/registry/security/util/SslContextFactory.java
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * 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.nifi.registry.security.util;
-
-import javax.net.ssl.KeyManager;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.security.KeyManagementException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.CertificateException;
-
-/**
- * A factory for creating SSL contexts using the application's security
- * properties.
- *
- */
-public final class SslContextFactory {
-
-    public static enum ClientAuth {
-
-        WANT,
-        REQUIRED,
-        NONE
-    }
-
-    /**
-     * Creates a SSLContext instance using the given information. The password for the key is assumed to be the same
-     * as the password for the keystore. If this is not the case, the {@link #createSslContext(String, char[], chart[], String, String, char[], String, ClientAuth, String)}
-     * method should be used instead
-     *
-     * @param keystore the full path to the keystore
-     * @param keystorePasswd the keystore password
-     * @param keystoreType the type of keystore (e.g., PKCS12, JKS)
-     * @param truststore the full path to the truststore
-     * @param truststorePasswd the truststore password
-     * @param truststoreType the type of truststore (e.g., PKCS12, JKS)
-     * @param clientAuth the type of client authentication
-     * @param protocol         the protocol to use for the SSL connection
-     *
-     * @return a SSLContext instance
-     * @throws KeyStoreException if any issues accessing the keystore
-     * @throws IOException for any problems loading the keystores
-     * @throws NoSuchAlgorithmException if an algorithm is found to be used but is unknown
-     * @throws CertificateException if there is an issue with the certificate
-     * @throws UnrecoverableKeyException if the key is insufficient
-     * @throws KeyManagementException if unable to manage the key
-     */
-    public static SSLContext createSslContext(
-            final String keystore, final char[] keystorePasswd, final String keystoreType,
-            final String truststore, final char[] truststorePasswd, final String truststoreType,
-            final ClientAuth clientAuth, final String protocol)
-            throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException,
-            UnrecoverableKeyException, KeyManagementException {
-
-        // Pass the keystore password as both the keystore password and the key password.
-        return createSslContext(keystore, keystorePasswd, keystorePasswd, keystoreType, truststore, truststorePasswd, truststoreType, clientAuth, protocol);
-    }
-
-    /**
-     * Creates a SSLContext instance using the given information.
-     *
-     * @param keystore the full path to the keystore
-     * @param keystorePasswd the keystore password
-     * @param keystoreType the type of keystore (e.g., PKCS12, JKS)
-     * @param truststore the full path to the truststore
-     * @param truststorePasswd the truststore password
-     * @param truststoreType the type of truststore (e.g., PKCS12, JKS)
-     * @param clientAuth the type of client authentication
-     * @param protocol         the protocol to use for the SSL connection
-     *
-     * @return a SSLContext instance
-     * @throws KeyStoreException if any issues accessing the keystore
-     * @throws IOException for any problems loading the keystores
-     * @throws NoSuchAlgorithmException if an algorithm is found to be used but is unknown
-     * @throws CertificateException if there is an issue with the certificate
-     * @throws UnrecoverableKeyException if the key is insufficient
-     * @throws KeyManagementException if unable to manage the key
-     */
-    public static SSLContext createSslContext(
-            final String keystore, final char[] keystorePasswd, final char[] keyPasswd, final String keystoreType,
-            final String truststore, final char[] truststorePasswd, final String truststoreType,
-            final ClientAuth clientAuth, final String protocol)
-            throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException,
-            UnrecoverableKeyException, KeyManagementException {
-
-        // prepare the keystore
-        final KeyStore keyStore = KeyStoreUtils.getKeyStore(keystoreType);
-        try (final InputStream keyStoreStream = new FileInputStream(keystore)) {
-            keyStore.load(keyStoreStream, keystorePasswd);
-        }
-        final KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
-        if (keyPasswd == null) {
-            keyManagerFactory.init(keyStore, keystorePasswd);
-        } else {
-            keyManagerFactory.init(keyStore, keyPasswd);
-        }
-
-        // prepare the truststore
-        final KeyStore trustStore = KeyStoreUtils.getKeyStore(truststoreType);
-        try (final InputStream trustStoreStream = new FileInputStream(truststore)) {
-            trustStore.load(trustStoreStream, truststorePasswd);
-        }
-        final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
-        trustManagerFactory.init(trustStore);
-
-        // initialize the ssl context
-        final SSLContext sslContext = SSLContext.getInstance(protocol);
-        sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());
-        if (ClientAuth.REQUIRED == clientAuth) {
-            sslContext.getDefaultSSLParameters().setNeedClientAuth(true);
-        } else if (ClientAuth.WANT == clientAuth) {
-            sslContext.getDefaultSSLParameters().setWantClientAuth(true);
-        } else {
-            sslContext.getDefaultSSLParameters().setWantClientAuth(false);
-        }
-
-        return sslContext;
-
-    }
-
-    /**
-     * Creates a SSLContext instance using the given information. This method assumes that the key password is
-     * the same as the keystore password. If this is not the case, use the {@link #createSslContext(String, char[], char[], String, String)}
-     * method instead.
-     *
-     * @param keystore the full path to the keystore
-     * @param keystorePasswd the keystore password
-     * @param keystoreType the type of keystore (e.g., PKCS12, JKS)
-     * @param protocol the protocol to use for the SSL connection
-     *
-     * @return a SSLContext instance
-     * @throws KeyStoreException if any issues accessing the keystore
-     * @throws IOException for any problems loading the keystores
-     * @throws NoSuchAlgorithmException if an algorithm is found to be used but is unknown
-     * @throws CertificateException if there is an issue with the certificate
-     * @throws UnrecoverableKeyException if the key is insufficient
-     * @throws KeyManagementException if unable to manage the key
-     */
-    public static SSLContext createSslContext(
-        final String keystore, final char[] keystorePasswd, final String keystoreType, final String protocol)
-        throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException,
-        UnrecoverableKeyException, KeyManagementException {
-
-        // create SSL Context passing keystore password as the key password
-        return createSslContext(keystore, keystorePasswd, keystorePasswd, keystoreType, protocol);
-    }
-
-    /**
-     * Creates a SSLContext instance using the given information.
-     *
-     * @param keystore the full path to the keystore
-     * @param keystorePasswd the keystore password
-     * @param keystoreType the type of keystore (e.g., PKCS12, JKS)
-     * @param protocol the protocol to use for the SSL connection
-     *
-     * @return a SSLContext instance
-     * @throws KeyStoreException if any issues accessing the keystore
-     * @throws IOException for any problems loading the keystores
-     * @throws NoSuchAlgorithmException if an algorithm is found to be used but is unknown
-     * @throws CertificateException if there is an issue with the certificate
-     * @throws UnrecoverableKeyException if the key is insufficient
-     * @throws KeyManagementException if unable to manage the key
-     */
-    public static SSLContext createSslContext(
-        final String keystore, final char[] keystorePasswd, final char[] keyPasswd, final String keystoreType, final String protocol)
-            throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException,
-            UnrecoverableKeyException, KeyManagementException {
-
-        // prepare the keystore
-        final KeyStore keyStore = KeyStoreUtils.getKeyStore(keystoreType);
-        try (final InputStream keyStoreStream = new FileInputStream(keystore)) {
-            keyStore.load(keyStoreStream, keystorePasswd);
-        }
-        final KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
-        if (keyPasswd == null) {
-            keyManagerFactory.init(keyStore, keystorePasswd);
-        } else {
-            keyManagerFactory.init(keyStore, keyPasswd);
-        }
-
-        // initialize the ssl context
-        final SSLContext ctx = SSLContext.getInstance(protocol);
-        ctx.init(keyManagerFactory.getKeyManagers(), new TrustManager[0], new SecureRandom());
-
-        return ctx;
-
-    }
-
-    /**
-     * Creates a SSLContext instance using the given information.
-     *
-     * @param truststore the full path to the truststore
-     * @param truststorePasswd the truststore password
-     * @param truststoreType the type of truststore (e.g., PKCS12, JKS)
-     * @param protocol the protocol to use for the SSL connection
-     *
-     * @return a SSLContext instance
-     * @throws KeyStoreException if any issues accessing the keystore
-     * @throws IOException for any problems loading the keystores
-     * @throws NoSuchAlgorithmException if an algorithm is found to be used but is unknown
-     * @throws CertificateException if there is an issue with the certificate
-     * @throws UnrecoverableKeyException if the key is insufficient
-     * @throws KeyManagementException if unable to manage the key
-     */
-    public static SSLContext createTrustSslContext(
-            final String truststore, final char[] truststorePasswd, final String truststoreType, final String protocol)
-            throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException,
-            UnrecoverableKeyException, KeyManagementException {
-
-        // prepare the truststore
-        final KeyStore trustStore = KeyStoreUtils.getKeyStore(truststoreType);
-        try (final InputStream trustStoreStream = new FileInputStream(truststore)) {
-            trustStore.load(trustStoreStream, truststorePasswd);
-        }
-        final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
-        trustManagerFactory.init(trustStore);
-
-        // initialize the ssl context
-        final SSLContext ctx = SSLContext.getInstance(protocol);
-        ctx.init(new KeyManager[0], trustManagerFactory.getTrustManagers(), new SecureRandom());
-
-        return ctx;
-
-    }
-
-}
diff --git a/nifi-toolkit/nifi-toolkit-admin/pom.xml b/nifi-toolkit/nifi-toolkit-admin/pom.xml
index d99c48dc8b..6d33c2f723 100644
--- a/nifi-toolkit/nifi-toolkit-admin/pom.xml
+++ b/nifi-toolkit/nifi-toolkit-admin/pom.xml
@@ -21,6 +21,11 @@ language governing permissions and limitations under the License. -->
     <artifactId>nifi-toolkit-admin</artifactId>
 
     <dependencies>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-security-ssl</artifactId>
+            <version>1.19.0-SNAPSHOT</version>
+        </dependency>
         <dependency>
             <groupId>commons-beanutils</groupId>
             <artifactId>commons-beanutils</artifactId>
diff --git a/nifi-toolkit/nifi-toolkit-admin/src/main/groovy/org/apache/nifi/toolkit/admin/client/NiFiClientFactory.groovy b/nifi-toolkit/nifi-toolkit-admin/src/main/groovy/org/apache/nifi/toolkit/admin/client/NiFiClientFactory.groovy
index 27f75c28a1..44ae51ef83 100644
--- a/nifi-toolkit/nifi-toolkit-admin/src/main/groovy/org/apache/nifi/toolkit/admin/client/NiFiClientFactory.groovy
+++ b/nifi-toolkit/nifi-toolkit-admin/src/main/groovy/org/apache/nifi/toolkit/admin/client/NiFiClientFactory.groovy
@@ -18,42 +18,38 @@ package org.apache.nifi.toolkit.admin.client
 
 import org.apache.commons.lang3.StringUtils
 import org.apache.http.conn.ssl.DefaultHostnameVerifier
+import org.apache.nifi.security.ssl.StandardKeyStoreBuilder
+import org.apache.nifi.security.ssl.StandardSslContextBuilder
 import org.apache.nifi.util.NiFiProperties
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
 
-import javax.net.ssl.KeyManagerFactory
 import javax.net.ssl.SSLContext
-import javax.net.ssl.TrustManagerFactory
 import javax.ws.rs.client.Client
 import javax.ws.rs.client.ClientBuilder
 import java.security.KeyManagementException
 import java.security.KeyStore
 import java.security.KeyStoreException
 import java.security.NoSuchAlgorithmException
-import java.security.SecureRandom
 import java.security.UnrecoverableKeyException
 import java.security.cert.CertificateException
 
 class NiFiClientFactory implements ClientFactory{
 
-    private static final Logger logger = LoggerFactory.getLogger(NiFiClientFactory.class)
     static enum NiFiAuthType{ NONE, SSL }
 
-    public Client getClient(NiFiProperties niFiProperties, String nifiInstallDir) throws Exception {
+    Client getClient(NiFiProperties niFiProperties, String nifiInstallDir) throws Exception {
 
-        final String authTypeStr = StringUtils.isEmpty(niFiProperties.getProperty(NiFiProperties.WEB_HTTPS_HOST)) &&  StringUtils.isEmpty(niFiProperties.getProperty(NiFiProperties.WEB_HTTPS_PORT))  ? NiFiAuthType.NONE : NiFiAuthType.SSL;
-        final NiFiAuthType authType = NiFiAuthType.valueOf(authTypeStr);
+        final String authTypeStr = StringUtils.isEmpty(niFiProperties.getProperty(NiFiProperties.WEB_HTTPS_HOST)) &&  StringUtils.isEmpty(niFiProperties.getProperty(NiFiProperties.WEB_HTTPS_PORT))  ? NiFiAuthType.NONE : NiFiAuthType.SSL
+        final NiFiAuthType authType = NiFiAuthType.valueOf(authTypeStr)
 
-        SSLContext sslContext = null;
+        SSLContext sslContext = null
 
-        if (NiFiAuthType.SSL.equals(authType)) {
-            String keystore = niFiProperties.getProperty(NiFiProperties.SECURITY_KEYSTORE);
-            final String keystoreType = niFiProperties.getProperty(NiFiProperties.SECURITY_KEYSTORE_TYPE);
-            final String keystorePassword = niFiProperties.getProperty(NiFiProperties.SECURITY_KEYSTORE_PASSWD);
-            String truststore = niFiProperties.getProperty(NiFiProperties.SECURITY_TRUSTSTORE);
-            final String truststoreType = niFiProperties.getProperty(NiFiProperties.SECURITY_TRUSTSTORE_TYPE);
-            final String truststorePassword = niFiProperties.getProperty(NiFiProperties.SECURITY_TRUSTSTORE_PASSWD);
+        if (NiFiAuthType.SSL == authType) {
+            String keystore = niFiProperties.getProperty(NiFiProperties.SECURITY_KEYSTORE)
+            final String keystoreType = niFiProperties.getProperty(NiFiProperties.SECURITY_KEYSTORE_TYPE)
+            final String keystorePassword = niFiProperties.getProperty(NiFiProperties.SECURITY_KEYSTORE_PASSWD)
+            String truststore = niFiProperties.getProperty(NiFiProperties.SECURITY_TRUSTSTORE)
+            final String truststoreType = niFiProperties.getProperty(NiFiProperties.SECURITY_TRUSTSTORE_TYPE)
+            final String truststorePassword = niFiProperties.getProperty(NiFiProperties.SECURITY_TRUSTSTORE_PASSWD)
 
             if(keystore.startsWith("./")){
                 keystore = keystore.replace("./",nifiInstallDir+"/")
@@ -69,16 +65,16 @@ class NiFiClientFactory implements ClientFactory{
                     truststore.trim(),
                     truststorePassword.trim().toCharArray(),
                     truststoreType.trim(),
-                    "TLS");
+                    "TLS")
         }
 
-        final ClientBuilder clientBuilder = ClientBuilder.newBuilder();
+        final ClientBuilder clientBuilder = ClientBuilder.newBuilder()
 
         if (sslContext != null) {
-            clientBuilder.sslContext(sslContext).hostnameVerifier(new DefaultHostnameVerifier());
+            clientBuilder.sslContext(sslContext).hostnameVerifier(new DefaultHostnameVerifier())
         }
 
-        return clientBuilder.build();
+        return clientBuilder.build()
 
     }
 
@@ -89,29 +85,29 @@ class NiFiClientFactory implements ClientFactory{
             throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException,
                     UnrecoverableKeyException, KeyManagementException {
 
-        // prepare the keystore
-        final KeyStore keyStore = KeyStore.getInstance(keystoreType);
-        final InputStream keyStoreStream = new FileInputStream(keystore)
-            keyStore.load(keyStoreStream, keystorePasswd);
-
-
-        final KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
-        keyManagerFactory.init(keyStore, keystorePasswd);
-
-        // prepare the truststore
-        final KeyStore trustStore = KeyStore.getInstance(truststoreType);
-        final InputStream trustStoreStream = new FileInputStream(truststore)
-        trustStore.load(trustStoreStream, truststorePasswd);
+        final KeyStore keyStore
+        try (final InputStream keyStoreStream = new FileInputStream(keystore)) {
+            keyStore = new StandardKeyStoreBuilder()
+                    .inputStream(keyStoreStream)
+                    .password(keystorePasswd)
+                    .type(keystoreType)
+                    .build()
+        }
 
-        final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
-        trustManagerFactory.init(trustStore);
+        final KeyStore trustStore
+        try (final InputStream trustStoreStream = new FileInputStream(truststore)) {
+            trustStore = new StandardKeyStoreBuilder()
+                    .inputStream(trustStoreStream)
+                    .password(truststorePasswd)
+                    .type(truststoreType)
+                    .build()
+        }
 
-        // initialize the ssl context
-        final SSLContext sslContext = SSLContext.getInstance(protocol);
-        sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());
-        return sslContext;
+        return new StandardSslContextBuilder()
+                .keyPassword(keystorePasswd)
+                .keyStore(keyStore)
+                .trustStore(trustStore)
+                .protocol(protocol)
+                .build()
     }
-
-
-
 }
diff --git a/nifi-toolkit/nifi-toolkit-cli/pom.xml b/nifi-toolkit/nifi-toolkit-cli/pom.xml
index ffc8052dc1..16acb74f93 100644
--- a/nifi-toolkit/nifi-toolkit-cli/pom.xml
+++ b/nifi-toolkit/nifi-toolkit-cli/pom.xml
@@ -49,6 +49,11 @@
     </build>
 
     <dependencies>
+        <dependency>
+            <groupId>org.apache.nifi</groupId>
+            <artifactId>nifi-security-ssl</artifactId>
+            <version>1.19.0-SNAPSHOT</version>
+        </dependency>
         <dependency>
             <groupId>commons-cli</groupId>
             <artifactId>commons-cli</artifactId>
diff --git a/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/nifi/NiFiClientConfig.java b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/nifi/NiFiClientConfig.java
index 3a1f42e65d..4254ad0884 100644
--- a/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/nifi/NiFiClientConfig.java
+++ b/nifi-toolkit/nifi-toolkit-cli/src/main/java/org/apache/nifi/toolkit/cli/impl/client/nifi/NiFiClientConfig.java
@@ -16,19 +16,16 @@
  */
 package org.apache.nifi.toolkit.cli.impl.client.nifi;
 
-import java.io.File;
-import java.io.FileInputStream;
+import java.io.IOException;
 import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Paths;
 import java.security.KeyStore;
-import java.security.SecureRandom;
 import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.KeyManager;
-import javax.net.ssl.KeyManagerFactory;
 import javax.net.ssl.SSLContext;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.TrustManagerFactory;
-import org.apache.nifi.registry.security.util.KeyStoreUtils;
 import org.apache.nifi.registry.security.util.KeystoreType;
+import org.apache.nifi.security.ssl.StandardKeyStoreBuilder;
+import org.apache.nifi.security.ssl.StandardSslContextBuilder;
 import org.apache.nifi.security.util.TlsConfiguration;
 
 /**
@@ -36,8 +33,6 @@ import org.apache.nifi.security.util.TlsConfiguration;
  */
 public class NiFiClientConfig {
 
-    public static final String DEFAULT_PROTOCOL = TlsConfiguration.getHighestCurrentSupportedTlsProtocolVersion();
-
     private final String baseUrl;
     private final SSLContext sslContext;
     private final String keystoreFilename;
@@ -63,7 +58,7 @@ public class NiFiClientConfig {
         this.truststoreFilename = builder.truststoreFilename;
         this.truststorePass = builder.truststorePass;
         this.truststoreType = builder.truststoreType;
-        this.protocol = builder.protocol == null ? DEFAULT_PROTOCOL : builder.protocol;
+        this.protocol = builder.protocol == null ? TlsConfiguration.TLS_PROTOCOL : builder.protocol;
         this.hostnameVerifier = builder.hostnameVerifier;
         this.readTimeout = builder.readTimeout;
         this.connectTimeout = builder.connectTimeout;
@@ -78,58 +73,49 @@ public class NiFiClientConfig {
             return sslContext;
         }
 
-        final KeyManagerFactory keyManagerFactory;
+        final KeyStore keyStore;
         if (keystoreFilename != null && keystorePass != null && keystoreType != null) {
-            try {
-                // prepare the keystore
-                final KeyStore keyStore = KeyStoreUtils.getKeyStore(keystoreType.name());
-                try (final InputStream keyStoreStream = new FileInputStream(new File(keystoreFilename))) {
-                    keyStore.load(keyStoreStream, keystorePass.toCharArray());
-                }
-                keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
-
-                if (keyPass == null) {
-                    keyManagerFactory.init(keyStore, keystorePass.toCharArray());
-                } else {
-                    keyManagerFactory.init(keyStore, keyPass.toCharArray());
-                }
-            } catch (final Exception e) {
-                throw new IllegalStateException("Failed to load Keystore", e);
+            try (final InputStream keyStoreStream = Files.newInputStream(Paths.get(keystoreFilename))) {
+                keyStore = new StandardKeyStoreBuilder()
+                        .inputStream(keyStoreStream)
+                        .password(keystorePass.toCharArray())
+                        .type(keystoreType.name())
+                        .build();
+            } catch (final IOException e) {
+                throw new IllegalStateException(String.format("Read Key Store [%s] failed", keystoreFilename), e);
             }
         } else {
-            keyManagerFactory = null;
+            keyStore = null;
         }
 
-        final TrustManagerFactory trustManagerFactory;
+        final KeyStore trustStore;
         if (truststoreFilename != null && truststorePass != null && truststoreType != null) {
-            try {
-                // prepare the truststore
-                final KeyStore trustStore = KeyStoreUtils.getKeyStore(truststoreType.name());
-                try (final InputStream trustStoreStream = new FileInputStream(new File(truststoreFilename))) {
-                    trustStore.load(trustStoreStream, truststorePass.toCharArray());
-                }
-                trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
-                trustManagerFactory.init(trustStore);
-            } catch (final Exception e) {
-                throw new IllegalStateException("Failed to load Truststore", e);
+            try (final InputStream keyStoreStream = Files.newInputStream(Paths.get(truststoreFilename))) {
+                trustStore = new StandardKeyStoreBuilder()
+                        .inputStream(keyStoreStream)
+                        .password(truststorePass.toCharArray())
+                        .type(truststoreType.name())
+                        .build();
+            } catch (final IOException e) {
+                throw new IllegalStateException(String.format("Read Trust Store [%s] failed", truststoreFilename), e);
             }
         } else {
-            trustManagerFactory = null;
+            trustStore = null;
         }
 
-        if (keyManagerFactory != null || trustManagerFactory != null) {
-            try {
-                // initialize the ssl context
-                KeyManager[] keyManagers = keyManagerFactory != null ? keyManagerFactory.getKeyManagers() : null;
-                TrustManager[] trustManagers = trustManagerFactory != null ? trustManagerFactory.getTrustManagers() : null;
-                final SSLContext sslContext = SSLContext.getInstance(getProtocol());
-                sslContext.init(keyManagers, trustManagers, new SecureRandom());
-                sslContext.getDefaultSSLParameters().setNeedClientAuth(true);
-
-                return sslContext;
-            } catch (final Exception e) {
-                throw new IllegalStateException("Created keystore and truststore but failed to initialize SSLContext", e);
+        if (keyStore != null || trustStore != null) {
+            final StandardSslContextBuilder builder = new StandardSslContextBuilder();
+            builder.protocol(protocol);
+
+            if (keyStore != null) {
+                final char[] keyPassword = keyPass == null ? keystorePass.toCharArray() : keyPass.toCharArray();
+                builder.keyPassword(keyPassword);
+                builder.keyStore(keyStore);
+            }
+            if (trustStore != null) {
+                builder.trustStore(trustStore);
             }
+            return builder.build();
         } else {
             return null;
         }