You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@bookkeeper.apache.org by si...@apache.org on 2018/01/28 09:30:22 UTC

[bookkeeper] branch master updated: ISSUE #933: Add support for PEM Key file formats

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

sijie pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/bookkeeper.git


The following commit(s) were added to refs/heads/master by this push:
     new 76c1fd0  ISSUE #933: Add support for PEM Key file formats
76c1fd0 is described below

commit 76c1fd0d8ad1358fc8799d66b6ec7f242fd2ba71
Author: Kishore Udayashankar <ku...@salesforce.com>
AuthorDate: Sun Jan 28 01:30:15 2018 -0800

    ISSUE #933: Add support for PEM Key file formats
    
    (bug W-4203319) TLS authentication to support PEM format X.509
    certificates along with JKS and PKCS12 formats.
    
    Added another KeyStore Type to the list of formats (JKS, PKCS12)
    currently supported during SSLContext creation.
    
    rev ayegorov
    
    Signed-off-by: Kishore Kasi Udayashankar <kudayashankarsalesforce.com>
    
    Descriptions of the changes in this PR:
    
    (PR description content here)...
    
    Master Issue: #933
    
    Author: Kishore Udayashankar <ku...@salesforce.com>
    
    Reviewers: Enrico Olivelli <eo...@gmail.com>, Sijie Guo <si...@apache.org>
    
    This closes #965 from kishorekasi/tls-pem, closes #933
---
 bookkeeper-server/pom.xml                          |  38 +++-
 .../bookkeeper/conf/AbstractConfiguration.java     |  11 +
 .../bookkeeper/conf/ClientConfiguration.java       |  76 +++++--
 .../bookkeeper/conf/ServerConfiguration.java       |  29 ++-
 .../apache/bookkeeper/proto/BookieNettyServer.java |   1 +
 .../apache/bookkeeper/tls/TLSContextFactory.java   | 221 ++++++++++++++++-----
 .../java/org/apache/bookkeeper/tls/TestTLS.java    | 152 +++++++++++---
 bookkeeper-server/src/test/resources/cacerts       | Bin 110225 -> 0 bytes
 .../src/test/resources/client-cert.pem             |  32 +++
 .../src/test/resources/client-key.jks              | Bin 0 -> 3941 bytes
 .../src/test/resources/client-key.p12              | Bin 0 -> 4189 bytes
 .../src/test/resources/client-key.pem              |  52 +++++
 bookkeeper-server/src/test/resources/client.jks    | Bin 1416 -> 0 bytes
 .../src/test/resources/generateKeysAndCerts.sh     |  76 +++++++
 .../src/test/resources/server-cert.pem             |  32 +++
 .../src/test/resources/server-key.jks              | Bin 0 -> 3941 bytes
 .../src/test/resources/server-key.p12              | Bin 0 -> 4189 bytes
 .../src/test/resources/server-key.pem              |  52 +++++
 bookkeeper-server/src/test/resources/server.jks    | Bin 1393 -> 0 bytes
 .../src/test/resources/trustStorePassword.txt      |   1 -
 20 files changed, 667 insertions(+), 106 deletions(-)

diff --git a/bookkeeper-server/pom.xml b/bookkeeper-server/pom.xml
index 2f537c9..f0721b6 100644
--- a/bookkeeper-server/pom.xml
+++ b/bookkeeper-server/pom.xml
@@ -284,13 +284,16 @@
             <exclude>**/.project</exclude>
             <exclude>**/.checkstyle</exclude>
             <exclude>**/.settings/*</exclude>
-            <exclude>certs/keyStoreClientPassword.txt</exclude>
-            <exclude>certs/keyStoreServerPassword.txt</exclude>
-            <exclude>certs/trustStorePassword.txt</exclude>
-            <exclude>src/test/resources/cacerts</exclude>
+            <exclude>src/test/resources/server-key.pem</exclude>
+            <exclude>src/test/resources/server-key.p12</exclude>
+            <exclude>src/test/resources/server-key.jks</exclude>
+            <exclude>src/test/resources/server-cert.pem</exclude>
+            <exclude>src/test/resources/client-key.pem</exclude>
+            <exclude>src/test/resources/client-key.p12</exclude>
+            <exclude>src/test/resources/client-key.jks</exclude>
+            <exclude>src/test/resources/client-cert.pem</exclude>
             <exclude>src/test/resources/keyStoreClientPassword.txt</exclude>
             <exclude>src/test/resources/keyStoreServerPassword.txt</exclude>
-            <exclude>src/test/resources/trustStorePassword.txt</exclude>
           </excludes>
         </configuration>
       </plugin>
@@ -426,5 +429,30 @@
         </dependency>
       </dependencies>
     </profile>
+    <profile>
+      <id>tls-certs</id>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.codehaus.mojo</groupId>
+            <artifactId>exec-maven-plugin</artifactId>
+            <version>1.6.0</version>
+            <executions>
+              <execution>
+                <id>Generate Self-Signed Certificates</id>
+                <phase>generate-test-resources</phase>
+                <goals>
+                  <goal>exec</goal>
+                </goals>
+                <configuration>
+                  <workingDirectory>${basedir}/src/test/resources</workingDirectory>
+                  <executable>${basedir}/src/test/resources/generateKeysAndCerts.sh</executable>
+                </configuration>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
   </profiles>
 </project>
diff --git a/bookkeeper-server/src/main/java/org/apache/bookkeeper/conf/AbstractConfiguration.java b/bookkeeper-server/src/main/java/org/apache/bookkeeper/conf/AbstractConfiguration.java
index f963f8b..ef8e908 100644
--- a/bookkeeper-server/src/main/java/org/apache/bookkeeper/conf/AbstractConfiguration.java
+++ b/bookkeeper-server/src/main/java/org/apache/bookkeeper/conf/AbstractConfiguration.java
@@ -100,6 +100,17 @@ public abstract class AbstractConfiguration<T extends AbstractConfiguration>
     */
     protected static final String TLS_ENABLED_PROTOCOLS = "tlsEnabledProtocols";
 
+    /**
+     * TLS KeyStore, TrustStore, Password files and Certificate Paths.
+     */
+    protected static final String TLS_KEYSTORE_TYPE = "tlsKeyStoreType";
+    protected static final String TLS_KEYSTORE = "tlsKeyStore";
+    protected static final String TLS_KEYSTORE_PASSWORD_PATH = "tlsKeyStorePasswordPath";
+    protected static final String TLS_TRUSTSTORE_TYPE = "tlsTrustStoreType";
+    protected static final String TLS_TRUSTSTORE = "tlsTrustStore";
+    protected static final String TLS_TRUSTSTORE_PASSWORD_PATH = "tlsTrustStorePasswordPath";
+    protected static final String TLS_CERTIFICATE_PATH = "tlsCertificatePath";
+
     //Netty configuration
     protected static final String NETTY_MAX_FRAME_SIZE = "nettyMaxFrameSizeBytes";
     protected static final int DEFAULT_NETTY_MAX_FRAME_SIZE = 5 * 1024 * 1024; // 5MB
diff --git a/bookkeeper-server/src/main/java/org/apache/bookkeeper/conf/ClientConfiguration.java b/bookkeeper-server/src/main/java/org/apache/bookkeeper/conf/ClientConfiguration.java
index 4d9c774..424ae34 100644
--- a/bookkeeper-server/src/main/java/org/apache/bookkeeper/conf/ClientConfiguration.java
+++ b/bookkeeper-server/src/main/java/org/apache/bookkeeper/conf/ClientConfiguration.java
@@ -51,6 +51,43 @@ public class ClientConfiguration extends AbstractConfiguration<ClientConfigurati
     // Passwd
     protected static final String PASSWD = "passwd";
 
+    // Client TLS (@deprecated since 4.7.0)
+    /**
+     * @deprecated Use {@link #TLS_KEYSTORE_TYPE}
+     */
+    @Deprecated
+    protected static final String CLIENT_TLS_KEYSTORE_TYPE = "clientKeyStoreType";
+
+    /**
+     * @deprecated Use {@link #TLS_KEYSTORE}
+     */
+    @Deprecated
+    protected static final String CLIENT_TLS_KEYSTORE = "clientKeyStore";
+
+    /**
+     * @deprecated Use {@link #TLS_KEYSTORE_PASSWORD_PATH}
+     */
+    @Deprecated
+    protected static final String CLIENT_TLS_KEYSTORE_PASSWORD_PATH = "clientKeyStorePasswordPath";
+
+    /**
+     * @deprecated Use {@link #TLS_TRUSTSTORE_TYPE}
+     */
+    @Deprecated
+    protected static final String CLIENT_TLS_TRUSTSTORE_TYPE = "clientTrustStoreType";
+
+    /**
+     * @deprecated Use {@link #TLS_TRUSTSTORE}
+     */
+    @Deprecated
+    protected static final String CLIENT_TLS_TRUSTSTORE = "clientTrustStore";
+
+    /**
+     * @deprecated Use {@link #TLS_TRUSTSTORE_PASSWORD_PATH}
+     */
+    @Deprecated
+    protected static final String CLIENT_TLS_TRUSTSTORE_PASSWORD_PATH = "clientTrustStorePasswordPath";
+
     // NIO Parameters
     protected static final String CLIENT_TCP_NODELAY = "clientTcpNoDelay";
     protected static final String CLIENT_SOCK_KEEPALIVE = "clientSockKeepalive";
@@ -145,14 +182,6 @@ public class ClientConfiguration extends AbstractConfiguration<ClientConfigurati
     // Client auth provider factory class name. It must be configured on Bookies to for the Auditor
     protected static final String CLIENT_AUTH_PROVIDER_FACTORY_CLASS = "clientAuthProviderFactoryClass";
 
-    // Client TLS
-    protected static final String TLS_KEYSTORE_TYPE = "clientKeyStoreType";
-    protected static final String TLS_KEYSTORE = "clientKeyStore";
-    protected static final String TLS_KEYSTORE_PASSWORD_PATH = "clientKeyStorePasswordPath";
-    protected static final String TLS_TRUSTSTORE_TYPE = "clientTrustStoreType";
-    protected static final String TLS_TRUSTSTORE = "clientTrustStore";
-    protected static final String TLS_TRUSTSTORE_PASSWORD_PATH = "clientTrustStorePasswordPath";
-
     // Registration Client
     protected static final String REGISTRATION_CLIENT_CLASS = "registrationClientClass";
 
@@ -1419,7 +1448,7 @@ public class ClientConfiguration extends AbstractConfiguration<ClientConfigurati
      * @return
      */
     public String getTLSKeyStoreType() {
-        return getString(TLS_KEYSTORE_TYPE, "JKS");
+        return getString(CLIENT_TLS_KEYSTORE_TYPE, getString(TLS_KEYSTORE_TYPE, "JKS"));
     }
 
 
@@ -1439,7 +1468,7 @@ public class ClientConfiguration extends AbstractConfiguration<ClientConfigurati
      * @return
      */
     public String getTLSKeyStore() {
-        return getString(TLS_KEYSTORE, null);
+        return getString(CLIENT_TLS_KEYSTORE, getString(TLS_KEYSTORE, null));
     }
 
     /**
@@ -1458,7 +1487,7 @@ public class ClientConfiguration extends AbstractConfiguration<ClientConfigurati
      * @return
      */
     public String getTLSKeyStorePasswordPath() {
-        return getString(TLS_KEYSTORE_PASSWORD_PATH, null);
+        return getString(CLIENT_TLS_KEYSTORE_PASSWORD_PATH, getString(TLS_KEYSTORE_PASSWORD_PATH, null));
     }
 
     /**
@@ -1477,7 +1506,7 @@ public class ClientConfiguration extends AbstractConfiguration<ClientConfigurati
      * @return
      */
     public String getTLSTrustStoreType() {
-        return getString(TLS_TRUSTSTORE_TYPE, "JKS");
+        return getString(CLIENT_TLS_TRUSTSTORE_TYPE, getString(TLS_TRUSTSTORE_TYPE, "JKS"));
     }
 
     /**
@@ -1496,7 +1525,7 @@ public class ClientConfiguration extends AbstractConfiguration<ClientConfigurati
      * @return
      */
     public String getTLSTrustStore() {
-        return getString(TLS_TRUSTSTORE, null);
+        return getString(CLIENT_TLS_TRUSTSTORE, getString(TLS_TRUSTSTORE, null));
     }
 
     /**
@@ -1516,7 +1545,7 @@ public class ClientConfiguration extends AbstractConfiguration<ClientConfigurati
      * @return
      */
     public String getTLSTrustStorePasswordPath() {
-        return getString(TLS_TRUSTSTORE_PASSWORD_PATH, null);
+        return getString(CLIENT_TLS_TRUSTSTORE_PASSWORD_PATH, getString(TLS_TRUSTSTORE_PASSWORD_PATH, null));
     }
 
     /**
@@ -1530,6 +1559,25 @@ public class ClientConfiguration extends AbstractConfiguration<ClientConfigurati
     }
 
     /**
+     * Get the path to file containing TLS Certificate.
+     *
+     * @return
+     */
+    public String getTLSCertificatePath() {
+        return getString(TLS_CERTIFICATE_PATH, null);
+    }
+
+    /**
+     * Set the path to file containing TLS Certificate.
+     *
+     * @return
+     */
+    public ClientConfiguration setTLSCertificatePath(String arg) {
+        setProperty(TLS_CERTIFICATE_PATH, arg);
+        return this;
+    }
+
+    /**
      * Whether to delay ensemble change or not?
      *
      * @return true if to delay ensemble change, otherwise false.
diff --git a/bookkeeper-server/src/main/java/org/apache/bookkeeper/conf/ServerConfiguration.java b/bookkeeper-server/src/main/java/org/apache/bookkeeper/conf/ServerConfiguration.java
index d6e4d5f..3a7c763 100644
--- a/bookkeeper-server/src/main/java/org/apache/bookkeeper/conf/ServerConfiguration.java
+++ b/bookkeeper-server/src/main/java/org/apache/bookkeeper/conf/ServerConfiguration.java
@@ -168,14 +168,6 @@ public class ServerConfiguration extends AbstractConfiguration<ServerConfigurati
     protected static final String HTTP_SERVER_ENABLED = "httpServerEnabled";
     protected static final String HTTP_SERVER_PORT = "httpServerPort";
 
-    // TLS parameters
-    protected static final String TLS_KEYSTORE_TYPE = "tlsKeyStoreType";
-    protected static final String TLS_KEYSTORE = "tlsKeyStore";
-    protected static final String TLS_KEYSTORE_PASSWORD_PATH = "tlsKeyStorePasswordPath";
-    protected static final String TLS_TRUSTSTORE_TYPE = "tlsTrustStoreType";
-    protected static final String TLS_TRUSTSTORE = "tlsTrustStore";
-    protected static final String TLS_TRUSTSTORE_PASSWORD_PATH = "tlsTrustStorePasswordPath";
-
     // Lifecycle Components
     protected static final String EXTRA_SERVER_COMPONENTS = "extraServerComponents";
 
@@ -2331,7 +2323,7 @@ public class ServerConfiguration extends AbstractConfiguration<ServerConfigurati
     /**
      * Set the keystore path for the client.
      *
-     * @return ServerConfiguration
+     * @return
      */
     public ServerConfiguration setTLSKeyStore(String arg) {
         setProperty(TLS_KEYSTORE, arg);
@@ -2415,6 +2407,25 @@ public class ServerConfiguration extends AbstractConfiguration<ServerConfigurati
         return this;
     }
 
+    /**
+     * Get the path to file containing TLS Certificate.
+     *
+     * @return
+     */
+    public String getTLSCertificatePath() {
+        return getString(TLS_CERTIFICATE_PATH, null);
+    }
+
+    /**
+     * Set the path to file containing TLS Certificate.
+     *
+     * @return
+     */
+    public ServerConfiguration setTLSCertificatePath(String arg) {
+        setProperty(TLS_CERTIFICATE_PATH, arg);
+        return this;
+    }
+
 
     /**
      * Whether to enable recording task execution stats.
diff --git a/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/BookieNettyServer.java b/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/BookieNettyServer.java
index dc2cbce..3c5385c 100644
--- a/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/BookieNettyServer.java
+++ b/bookkeeper-server/src/main/java/org/apache/bookkeeper/proto/BookieNettyServer.java
@@ -223,6 +223,7 @@ class BookieNettyServer {
                             result.addAll(Arrays.asList(certificates));
                             return result;
                         } catch (SSLPeerUnverifiedException err) {
+                            LOG.error("Failed to get peer certificates", err);
                             return Collections.emptyList();
                         }
 
diff --git a/bookkeeper-server/src/main/java/org/apache/bookkeeper/tls/TLSContextFactory.java b/bookkeeper-server/src/main/java/org/apache/bookkeeper/tls/TLSContextFactory.java
index a2108a7..2d3f51b 100644
--- a/bookkeeper-server/src/main/java/org/apache/bookkeeper/tls/TLSContextFactory.java
+++ b/bookkeeper-server/src/main/java/org/apache/bookkeeper/tls/TLSContextFactory.java
@@ -34,8 +34,11 @@ import java.io.IOException;
 import java.security.KeyStore;
 import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
 import java.security.UnrecoverableKeyException;
 import java.security.cert.CertificateException;
+import java.security.spec.InvalidKeySpecException;
+import java.util.Arrays;
 
 import javax.net.ssl.KeyManagerFactory;
 import javax.net.ssl.TrustManagerFactory;
@@ -51,6 +54,13 @@ import org.slf4j.LoggerFactory;
  * A factory to manage TLS contexts.
  */
 public class TLSContextFactory implements SecurityHandlerFactory {
+    /**
+     * Supported Key File Types.
+     */
+    public enum KeyStoreType {
+        PKCS12, JKS, PEM;
+    }
+
     private static final Logger LOG = LoggerFactory.getLogger(TLSContextFactory.class);
     private static final String TLSCONTEXT_HANDLER_NAME = "tls";
     private String[] protocols;
@@ -73,6 +83,7 @@ public class TLSContextFactory implements SecurityHandlerFactory {
     private KeyStore loadKeyStore(String keyStoreType, String keyStoreLocation, String keyStorePassword)
             throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
         KeyStore ks = KeyStore.getInstance(keyStoreType);
+
         try (FileInputStream ksin = new FileInputStream(keyStoreLocation)) {
             ks.load(ksin, keyStorePassword.trim().toCharArray());
         }
@@ -85,7 +96,7 @@ public class TLSContextFactory implements SecurityHandlerFactory {
 
     private KeyManagerFactory initKeyManagerFactory(String keyStoreType, String keyStoreLocation,
             String keyStorePasswordPath) throws SecurityException, KeyStoreException, NoSuchAlgorithmException,
-            CertificateException, IOException, UnrecoverableKeyException {
+            CertificateException, IOException, UnrecoverableKeyException, InvalidKeySpecException {
         KeyManagerFactory kmf = null;
 
         if (Strings.isNullOrEmpty(keyStoreLocation)) {
@@ -98,7 +109,7 @@ public class TLSContextFactory implements SecurityHandlerFactory {
             keyStorePassword = getPasswordFromFile(keyStorePasswordPath);
         }
 
-        // Initialize key store
+        // Initialize key file
         KeyStore ks = loadKeyStore(keyStoreType, keyStoreLocation, keyStorePassword);
         kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
         kmf.init(ks, keyStorePassword.trim().toCharArray());
@@ -121,7 +132,7 @@ public class TLSContextFactory implements SecurityHandlerFactory {
             trustStorePassword = getPasswordFromFile(trustStorePasswordPath);
         }
 
-        // Initialize trust store
+        // Initialize trust file
         KeyStore ts = loadKeyStore(trustStoreType, trustStoreLocation, trustStorePassword);
         tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
         tmf.init(ts);
@@ -147,89 +158,179 @@ public class TLSContextFactory implements SecurityHandlerFactory {
         return SslProvider.JDK;
     }
 
-    private void createClientContext(AbstractConfiguration conf) throws SecurityException, KeyStoreException,
-            NoSuchAlgorithmException, CertificateException, IOException, UnrecoverableKeyException {
+    private void createClientContext(AbstractConfiguration conf)
+            throws SecurityException, KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException,
+            UnrecoverableKeyException, InvalidKeySpecException, NoSuchProviderException {
         final SslContextBuilder sslContextBuilder;
         final ClientConfiguration clientConf;
         final SslProvider provider;
-        final boolean authentication;
-
-        KeyManagerFactory kmf = null;
-        TrustManagerFactory tmf = null;
+        final boolean clientAuthentication;
 
-        // get key-store and trust-store locations and passwords
+        // get key-file and trust-file locations and passwords
         if (!(conf instanceof ClientConfiguration)) {
             throw new SecurityException("Client configruation not provided");
         }
 
         clientConf = (ClientConfiguration) conf;
         provider = getTLSProvider(clientConf.getTLSProvider());
-        authentication = clientConf.getTLSClientAuthentication();
+        clientAuthentication = clientConf.getTLSClientAuthentication();
 
-        tmf = initTrustManagerFactory(clientConf.getTLSTrustStoreType(), clientConf.getTLSTrustStore(),
-                clientConf.getTLSTrustStorePasswordPath());
+        switch (KeyStoreType.valueOf(clientConf.getTLSTrustStoreType())) {
+        case PEM:
+            if (Strings.isNullOrEmpty(clientConf.getTLSTrustStore())) {
+                throw new SecurityException("CA Certificate required");
+            }
 
-        if (authentication) {
-            kmf = initKeyManagerFactory(clientConf.getTLSKeyStoreType(), clientConf.getTLSKeyStore(),
-                    clientConf.getTLSKeyStorePasswordPath());
+            sslContextBuilder = SslContextBuilder.forClient()
+                    .trustManager(new File(clientConf.getTLSTrustStore()))
+                    .ciphers(null)
+                    .sessionCacheSize(0)
+                    .sessionTimeout(0)
+                    .sslProvider(provider)
+                    .clientAuth(ClientAuth.REQUIRE);
+
+            break;
+        case JKS:
+            // falling thru, same as PKCS12
+        case PKCS12:
+            TrustManagerFactory tmf = initTrustManagerFactory(clientConf.getTLSTrustStoreType(),
+                    clientConf.getTLSTrustStore(), clientConf.getTLSTrustStorePasswordPath());
+
+            sslContextBuilder = SslContextBuilder.forClient()
+                    .trustManager(tmf)
+                    .ciphers(null)
+                    .sessionCacheSize(0)
+                    .sessionTimeout(0)
+                    .sslProvider(provider)
+                    .clientAuth(ClientAuth.REQUIRE);
+
+            break;
+        default:
+            throw new SecurityException("Invalid Truststore type: " + clientConf.getTLSTrustStoreType());
         }
 
-        // Build Ssl context
-        sslContextBuilder = SslContextBuilder.forClient()
-                                            .trustManager(tmf)
-                                            .ciphers(null)
-                                            .sessionCacheSize(0)
-                                            .sessionTimeout(0)
-                                            .sslProvider(provider)
-                                            .clientAuth(ClientAuth.REQUIRE);
-
-        /* if mutual authentication is enabled */
-        if (authentication) {
-            sslContextBuilder.keyManager(kmf);
+        if (clientAuthentication) {
+            switch (KeyStoreType.valueOf(clientConf.getTLSKeyStoreType())) {
+            case PEM:
+                final String keyPassword;
+
+                if (Strings.isNullOrEmpty(clientConf.getTLSCertificatePath())) {
+                    throw new SecurityException("Valid Certificate is missing");
+                }
+
+                if (Strings.isNullOrEmpty(clientConf.getTLSKeyStore())) {
+                    throw new SecurityException("Valid Key is missing");
+                }
+
+                if (!Strings.isNullOrEmpty(clientConf.getTLSKeyStorePasswordPath())) {
+                    keyPassword = getPasswordFromFile(clientConf.getTLSKeyStorePasswordPath());
+                } else {
+                    keyPassword = null;
+                }
+
+                sslContextBuilder.keyManager(new File(clientConf.getTLSCertificatePath()),
+                        new File(clientConf.getTLSKeyStore()), keyPassword);
+                break;
+            case JKS:
+                // falling thru, same as PKCS12
+            case PKCS12:
+                KeyManagerFactory kmf = initKeyManagerFactory(clientConf.getTLSKeyStoreType(),
+                        clientConf.getTLSKeyStore(), clientConf.getTLSKeyStorePasswordPath());
+
+                sslContextBuilder.keyManager(kmf);
+                break;
+            default:
+                throw new SecurityException("Invalid Keyfile type" + clientConf.getTLSKeyStoreType());
+            }
         }
 
         sslContext = sslContextBuilder.build();
     }
 
     private void createServerContext(AbstractConfiguration conf) throws SecurityException, KeyStoreException,
-            NoSuchAlgorithmException, CertificateException, IOException, UnrecoverableKeyException {
+            NoSuchAlgorithmException, CertificateException, IOException, UnrecoverableKeyException,
+            InvalidKeySpecException, IllegalArgumentException {
         final SslContextBuilder sslContextBuilder;
         final ServerConfiguration serverConf;
         final SslProvider provider;
-        final boolean authentication;
+        final boolean clientAuthentication;
 
-        KeyManagerFactory kmf = null;
-        TrustManagerFactory tmf = null;
-
-        // get key-store and trust-store locations and passwords
+        // get key-file and trust-file locations and passwords
         if (!(conf instanceof ServerConfiguration)) {
             throw new SecurityException("Server configruation not provided");
         }
 
         serverConf = (ServerConfiguration) conf;
         provider = getTLSProvider(serverConf.getTLSProvider());
-        authentication = serverConf.getTLSClientAuthentication();
+        clientAuthentication = serverConf.getTLSClientAuthentication();
+
+        switch (KeyStoreType.valueOf(serverConf.getTLSKeyStoreType())) {
+        case PEM:
+            final String keyPassword;
+
+            if (Strings.isNullOrEmpty(serverConf.getTLSKeyStore())) {
+                throw new SecurityException("Key path is required");
+            }
+
+            if (Strings.isNullOrEmpty(serverConf.getTLSCertificatePath())) {
+                throw new SecurityException("Certificate path is required");
+            }
 
-        kmf = initKeyManagerFactory(serverConf.getTLSKeyStoreType(), serverConf.getTLSKeyStore(),
-                serverConf.getTLSKeyStorePasswordPath());
+            if (!Strings.isNullOrEmpty(serverConf.getTLSKeyStorePasswordPath())) {
+                keyPassword = getPasswordFromFile(serverConf.getTLSKeyStorePasswordPath());
+            } else {
+                keyPassword = null;
+            }
 
-        if (authentication) {
-            tmf = initTrustManagerFactory(serverConf.getTLSTrustStoreType(), serverConf.getTLSTrustStore(),
-                    serverConf.getTLSTrustStorePasswordPath());
+            sslContextBuilder = SslContextBuilder
+                                .forServer(new File(serverConf.getTLSCertificatePath()),
+                            new File(serverConf.getTLSKeyStore()), keyPassword)
+                                .ciphers(null)
+                                .sessionCacheSize(0)
+                                .sessionTimeout(0)
+                                .sslProvider(provider)
+                                .startTls(true);
+
+            break;
+        case JKS:
+            // falling thru, same as PKCS12
+        case PKCS12:
+            KeyManagerFactory kmf = initKeyManagerFactory(serverConf.getTLSKeyStoreType(),
+                    serverConf.getTLSKeyStore(),
+                    serverConf.getTLSKeyStorePasswordPath());
+
+            sslContextBuilder = SslContextBuilder.forServer(kmf)
+                                .ciphers(null)
+                                .sessionCacheSize(0)
+                                .sessionTimeout(0)
+                                .sslProvider(provider)
+                                .startTls(true);
+
+            break;
+        default:
+            throw new SecurityException("Invalid Keyfile type" + serverConf.getTLSKeyStoreType());
         }
 
-        // Build Ssl context
-        sslContextBuilder = SslContextBuilder.forServer(kmf)
-                                            .ciphers(null)
-                                            .sessionCacheSize(0)
-                                            .sessionTimeout(0)
-                                            .sslProvider(provider)
-                                            .startTls(true);
-
-        /* if mutual authentication is enabled */
-        if (authentication) {
-            sslContextBuilder.trustManager(tmf)
-                            .clientAuth(ClientAuth.REQUIRE);
+        if (clientAuthentication) {
+            sslContextBuilder.clientAuth(ClientAuth.REQUIRE);
+
+            switch (KeyStoreType.valueOf(serverConf.getTLSTrustStoreType())) {
+            case PEM:
+                if (Strings.isNullOrEmpty(serverConf.getTLSTrustStore())) {
+                    throw new SecurityException("CA Certificate chain is required");
+                }
+                sslContextBuilder.trustManager(new File(serverConf.getTLSTrustStore()));
+                break;
+            case JKS:
+                // falling thru, same as PKCS12
+            case PKCS12:
+                TrustManagerFactory tmf = initTrustManagerFactory(serverConf.getTLSTrustStoreType(),
+                        serverConf.getTLSTrustStore(), serverConf.getTLSTrustStorePasswordPath());
+                sslContextBuilder.trustManager(tmf);
+                break;
+            default:
+                throw new SecurityException("Invalid Truststore type" + serverConf.getTLSTrustStoreType());
+            }
         }
 
         sslContext = sslContextBuilder.build();
@@ -269,9 +370,15 @@ public class TLSContextFactory implements SecurityHandlerFactory {
         } catch (CertificateException e) {
             throw new SecurityException("Unable to load keystore", e);
         } catch (IOException e) {
-            throw new SecurityException("Error initializing TLSContext", e);
+            throw new SecurityException("Error initializing SSLContext", e);
         } catch (UnrecoverableKeyException e) {
-            throw new SecurityException("Unable to load key manager, possibly wrong password given", e);
+            throw new SecurityException("Unable to load key manager, possibly bad password", e);
+        } catch (InvalidKeySpecException e) {
+            throw new SecurityException("Unable to load key manager", e);
+        } catch (IllegalArgumentException e) {
+            throw new SecurityException("Invalid TLS configuration", e);
+        } catch (NoSuchProviderException e) {
+            throw new SecurityException("No such provider", e);
         }
     }
 
@@ -282,10 +389,16 @@ public class TLSContextFactory implements SecurityHandlerFactory {
         if (protocols != null && protocols.length != 0) {
             sslHandler.engine().setEnabledProtocols(protocols);
         }
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Enabled cipher protocols: {} ", Arrays.toString(sslHandler.engine().getEnabledProtocols()));
+        }
 
         if (ciphers != null && ciphers.length != 0) {
             sslHandler.engine().setEnabledCipherSuites(ciphers);
         }
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Enabled cipher suites: {} ", Arrays.toString(sslHandler.engine().getEnabledCipherSuites()));
+        }
 
         return sslHandler;
     }
diff --git a/bookkeeper-server/src/test/java/org/apache/bookkeeper/tls/TestTLS.java b/bookkeeper-server/src/test/java/org/apache/bookkeeper/tls/TestTLS.java
index 1ba7f94..501fff8 100644
--- a/bookkeeper-server/src/test/java/org/apache/bookkeeper/tls/TestTLS.java
+++ b/bookkeeper-server/src/test/java/org/apache/bookkeeper/tls/TestTLS.java
@@ -55,12 +55,16 @@ import org.apache.bookkeeper.test.BookKeeperClusterTestCase;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
  * Tests with TLS enabled.
  */
+@RunWith(Parameterized.class)
 public class TestTLS extends BookKeeperClusterTestCase {
 
     private static final Logger LOG = LoggerFactory.getLogger(TestPerChannelBookieClient.class);
@@ -71,9 +75,28 @@ public class TestTLS extends BookKeeperClusterTestCase {
     private static boolean secureBookieSideChannel = false;
     private static Collection<Object> secureBookieSideChannelPrincipals = null;
 
-
-    public TestTLS() {
+    private TLSContextFactory.KeyStoreType clientKeyStoreFormat;
+    private TLSContextFactory.KeyStoreType clientTrustStoreFormat;
+    private TLSContextFactory.KeyStoreType serverKeyStoreFormat;
+    private TLSContextFactory.KeyStoreType serverTrustStoreFormat;
+
+    @Parameters
+    public static Collection<Object[]> data() {
+        return Arrays.asList(new Object[][] {
+                { "JKS", "JKS" },
+                { "PEM", "PEM" },
+                { "PKCS12", "PKCS12" },
+                { "JKS", "PEM" },
+                { "PEM", "PKCS12" },
+                { "PKCS12", "JKS" }
+            });
+    }
+    public TestTLS(String keyStoreFormat, String trustStoreFormat) {
         super(3);
+        this.clientKeyStoreFormat = TLSContextFactory.KeyStoreType.valueOf(keyStoreFormat);
+        this.clientTrustStoreFormat = TLSContextFactory.KeyStoreType.valueOf(trustStoreFormat);
+        this.serverKeyStoreFormat = TLSContextFactory.KeyStoreType.valueOf(keyStoreFormat);
+        this.serverTrustStoreFormat = TLSContextFactory.KeyStoreType.valueOf(trustStoreFormat);
     }
 
     @Before
@@ -82,30 +105,113 @@ public class TestTLS extends BookKeeperClusterTestCase {
         /* client configuration */
         baseClientConf.setTLSProviderFactoryClass(TLSContextFactory.class.getName());
         baseClientConf.setTLSClientAuthentication(true);
-        baseClientConf.setTLSKeyStoreType("JKS");
-        baseClientConf.setTLSKeyStore(
-            this.getClass().getClassLoader().getResource("client.jks").toURI().getPath());
-        baseClientConf.setTLSKeyStorePasswordPath(
-            this.getClass().getClassLoader().getResource("keyStoreClientPassword.txt").toURI().getPath());
-        baseClientConf.setTLSTrustStoreType("JKS");
-        baseClientConf.setTLSTrustStore(
-            this.getClass().getClassLoader().getResource("cacerts").toURI().getPath());
-        baseClientConf.setTLSTrustStorePasswordPath(
-            this.getClass().getClassLoader().getResource("trustStorePassword.txt").toURI().getPath());
+
+        switch (clientKeyStoreFormat) {
+        case PEM:
+            baseClientConf.setTLSKeyStoreType("PEM");
+            baseClientConf.setTLSKeyStore(this.getClass().getClassLoader().getResource("client-key.pem").getPath());
+            baseClientConf.setTLSCertificatePath(
+                    this.getClass().getClassLoader().getResource("client-cert.pem").getPath());
+
+            break;
+        case JKS:
+            baseClientConf.setTLSKeyStoreType("JKS");
+            baseClientConf.setTLSKeyStore(this.getClass().getClassLoader().getResource("client-key.jks").getPath());
+            baseClientConf.setTLSKeyStorePasswordPath(
+                    this.getClass().getClassLoader().getResource("keyStoreClientPassword.txt").getPath());
+
+            break;
+        case PKCS12:
+            baseClientConf.setTLSKeyStoreType("PKCS12");
+            baseClientConf.setTLSKeyStore(this.getClass().getClassLoader().getResource("client-key.p12").getPath());
+            baseClientConf.setTLSKeyStorePasswordPath(
+                    this.getClass().getClassLoader().getResource("keyStoreClientPassword.txt").getPath());
+
+            break;
+        default:
+            throw new Exception("Invalid client keystore format" + clientKeyStoreFormat);
+        }
+
+        switch (clientTrustStoreFormat) {
+        case PEM:
+            baseClientConf.setTLSTrustStoreType("PEM");
+            baseClientConf
+                    .setTLSTrustStore(this.getClass().getClassLoader().getResource("server-cert.pem").getPath());
+
+            break;
+        case JKS:
+            baseClientConf.setTLSTrustStoreType("JKS");
+            baseClientConf
+                    .setTLSTrustStore(this.getClass().getClassLoader().getResource("server-key.jks").getPath());
+            baseClientConf.setTLSTrustStorePasswordPath(
+                    this.getClass().getClassLoader().getResource("keyStoreServerPassword.txt").getPath());
+
+            break;
+        case PKCS12:
+            baseClientConf.setTLSTrustStoreType("PKCS12");
+            baseClientConf
+                    .setTLSTrustStore(this.getClass().getClassLoader().getResource("server-key.p12").getPath());
+            baseClientConf.setTLSTrustStorePasswordPath(
+                    this.getClass().getClassLoader().getResource("keyStoreServerPassword.txt").getPath());
+
+            break;
+        default:
+            throw new Exception("Invalid client keystore format" + clientTrustStoreFormat);
+        }
 
         /* server configuration */
         baseConf.setTLSProviderFactoryClass(TLSContextFactory.class.getName());
         baseConf.setTLSClientAuthentication(true);
-        baseConf.setTLSKeyStoreType("JKS");
-        baseConf.setTLSKeyStore(
-            this.getClass().getClassLoader().getResource("server.jks").toURI().getPath());
-        baseConf.setTLSKeyStorePasswordPath(
-            this.getClass().getClassLoader().getResource("keyStoreServerPassword.txt").toURI().getPath());
-        baseConf.setTLSTrustStoreType("JKS");
-        baseConf.setTLSTrustStore(
-            this.getClass().getClassLoader().getResource("cacerts").toURI().getPath());
-        baseConf.setTLSTrustStorePasswordPath(
-            this.getClass().getClassLoader().getResource("trustStorePassword.txt").toURI().getPath());
+
+        switch (serverKeyStoreFormat) {
+        case PEM:
+            baseConf.setTLSKeyStoreType("PEM");
+            baseConf.setTLSKeyStore(this.getClass().getClassLoader().getResource("server-key.pem").getPath());
+            baseConf.setTLSCertificatePath(this.getClass().getClassLoader().getResource("server-cert.pem").getPath());
+
+            break;
+        case JKS:
+            baseConf.setTLSKeyStoreType("JKS");
+            baseConf.setTLSKeyStore(this.getClass().getClassLoader().getResource("server-key.jks").getPath());
+            baseConf.setTLSKeyStorePasswordPath(
+                    this.getClass().getClassLoader().getResource("keyStoreServerPassword.txt").getPath());
+
+            break;
+        case PKCS12:
+            baseConf.setTLSKeyStoreType("PKCS12");
+            baseConf.setTLSKeyStore(this.getClass().getClassLoader().getResource("server-key.p12").getPath());
+            baseConf.setTLSKeyStorePasswordPath(
+                    this.getClass().getClassLoader().getResource("keyStoreServerPassword.txt").getPath());
+
+            break;
+        default:
+            throw new Exception("Invalid server keystore format" + serverKeyStoreFormat);
+        }
+
+        switch (serverTrustStoreFormat) {
+        case PEM:
+            baseConf.setTLSTrustStoreType("PEM");
+            baseConf.setTLSTrustStore(this.getClass().getClassLoader().getResource("client-cert.pem").getPath());
+
+            break;
+        case JKS:
+            baseConf.setTLSTrustStoreType("JKS");
+            baseConf.setTLSTrustStore(this.getClass().getClassLoader().getResource("client-key.jks").getPath());
+            baseConf.setTLSTrustStorePasswordPath(
+                    this.getClass().getClassLoader().getResource("keyStoreClientPassword.txt").getPath());
+
+            break;
+
+        case PKCS12:
+            baseConf.setTLSTrustStoreType("PKCS12");
+            baseConf.setTLSTrustStore(this.getClass().getClassLoader().getResource("client-key.p12").getPath());
+            baseConf.setTLSTrustStorePasswordPath(
+                    this.getClass().getClassLoader().getResource("keyStoreClientPassword.txt").getPath());
+
+            break;
+        default:
+            throw new Exception("Invalid server keystore format" + serverTrustStoreFormat);
+        }
 
         super.setUp();
     }
@@ -119,7 +225,7 @@ public class TestTLS extends BookKeeperClusterTestCase {
     /**
      * Verify that a server will not start if tls is enabled but no cert is specified.
      */
-    @Test
+    @Test(timeout = 60000)
     public void testStartTLSServerNoKeyStore() throws Exception {
         ServerConfiguration bookieConf = newServerConfiguration().setTLSKeyStore(null);
 
diff --git a/bookkeeper-server/src/test/resources/cacerts b/bookkeeper-server/src/test/resources/cacerts
deleted file mode 100644
index 5016b0c..0000000
Binary files a/bookkeeper-server/src/test/resources/cacerts and /dev/null differ
diff --git a/bookkeeper-server/src/test/resources/client-cert.pem b/bookkeeper-server/src/test/resources/client-cert.pem
new file mode 100644
index 0000000..d819f19
--- /dev/null
+++ b/bookkeeper-server/src/test/resources/client-cert.pem
@@ -0,0 +1,32 @@
+-----BEGIN CERTIFICATE-----
+MIIFmTCCA4GgAwIBAgIJAKJZcAdMXw8CMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNV
+BAYTAlVTMQswCQYDVQQIDAJDQTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEOMAwG
+A1UECgwFRHVtbXkxHjAcBgNVBAMMFWFwYWNoZS5ib29ra2VlcGVyLm9yZzAgFw0x
+ODAxMjQxODM2MjRaGA8zMDE3MDUyNzE4MzYyNFowYjELMAkGA1UEBhMCVVMxCzAJ
+BgNVBAgMAkNBMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMQ4wDAYDVQQKDAVEdW1t
+eTEeMBwGA1UEAwwVYXBhY2hlLmJvb2trZWVwZXIub3JnMIICIjANBgkqhkiG9w0B
+AQEFAAOCAg8AMIICCgKCAgEAwdphglnvMvIrEjHgBekeTtg9KmUtmK9yviI0xKdP
+8xMC6r5lvQIXQwcVB2LA7zBl3mI3s2DT9cqZ+E6q9Vz3AF9yV+F2zvPcQOt3P9hO
+CvEj9aXqMuzvSXQYmG+w7lLhm4M7IX7B4smGvXm905WACUeLr2XM1qr2SlpMZIBc
+O35NyaOeB9srQS2NXMB8mIsWDzoftbW0eNji7uz6OuyNvQWcS7rdcXBSoBRyRU2y
+qpQcfQT9aUDttDsAtkvEvuHi8LicKocaF1ufHVFvygdX7nGCNOnC83ZW5HvttwAJ
+C8Spe67etFp98bumwsXYaPO0su7M1Ym1DbphJsGO0LNwdEWstjT4uIsxyXZtblfM
+DBFpxA4s/7hIZtmrjM3CyZuoAuJWsU8UkZOVMWtxfBbY4iCo6K/ScaFSFvMykJ+p
+MST0U83JlDrqH+XjmIxcGrs0FVgD8vtaPcPJFWhm9TUBTFo1CU3Zw74W49ltgRa/
+oOLIzn27XHCcTY0LDRLXhvtGiPOSw+2U192w0MQVby6Q/QxAGTl5UXIeHsp91fkO
+H3pRHYNdjF5CVFn5vsNEcdjQQa1bi4Cr1O64yV6kHBtvsp3bKmkfBPT+mO1OzV+N
+vjfNswk606NCd6rI8UePErDI7YIJJvHphd8EHyz/Kr64ZjLodgKCyETEDWsvVaex
+8eMCAwEAAaNQME4wHQYDVR0OBBYEFCuc137GLVBGagBjH2STNeJ2gZcZMB8GA1Ud
+IwQYMBaAFCuc137GLVBGagBjH2STNeJ2gZcZMAwGA1UdEwQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggIBAJ/PW17Gk5qbsKxnxdpNctqCOlYOLcZ+/45LvTKFQDgi8kYi
+/4WkhvADWHYYTXRibgHYWMxU+/JCbgOgwPP30646mq0cvQGYN7aQTjYY8TRMbbLh
+PGGHu30EwL/siXVsHBS0ZonXpRvYr+Bn5V0JXdw1JNjGs4C3GxyIoK1zVqXRmS/b
+u052AtKN8A+iLw4F/8b5rmpRg1BDguc1kqaVh0c64aVZ49QM1IVpvWx1fIpxZPj2
+9YlHUYmmt7mf6313VplRL98jqH+U959ueJjQ9RmEMwgUeu3iIN75/kytkpGrMLdC
+WwKlDWBid66TJaPgJ8mBUC9LNlndSe5bzpueN12MFtaLgaWopiB8WU5pEdMV2eze
+auvrUJkobl5n6vAcip1+SfrnY4EvXwdrO2VpIVkEhRWLfxsuthKwobi7/gR2jIa/
+DT/o5eqvdlxHwdIZ0VVPDdUwngQT26VkGozyrBFlhuSkv7pI/8mjFPjYF1vMcQbi
+J6C3C/K9gQp8XXOFm8r3Szqd14yzqigx2SWz4VWY7L7vX2iVs5gNb1/Fnjt2lQ20
+XMCDNoN8tO6kIqv03L4MRue5ISbJx5hcFML1/aLaidpOhWWgEBsH5hhOVdzzAOGF
+vWBXMgfSLxq/cD2ZZARq5ZHhsX1x5BeZfw4zS6dJspxF6Io4CETOOxi6AA3L
+-----END CERTIFICATE-----
diff --git a/bookkeeper-server/src/test/resources/client-key.jks b/bookkeeper-server/src/test/resources/client-key.jks
new file mode 100644
index 0000000..5bd6e53
Binary files /dev/null and b/bookkeeper-server/src/test/resources/client-key.jks differ
diff --git a/bookkeeper-server/src/test/resources/client-key.p12 b/bookkeeper-server/src/test/resources/client-key.p12
new file mode 100644
index 0000000..36a9509
Binary files /dev/null and b/bookkeeper-server/src/test/resources/client-key.p12 differ
diff --git a/bookkeeper-server/src/test/resources/client-key.pem b/bookkeeper-server/src/test/resources/client-key.pem
new file mode 100644
index 0000000..d92a0bd
--- /dev/null
+++ b/bookkeeper-server/src/test/resources/client-key.pem
@@ -0,0 +1,52 @@
+-----BEGIN PRIVATE KEY-----
+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
+lZ/dii5O+DlR4aDU90na6bTa5v8ASw==
+-----END PRIVATE KEY-----
diff --git a/bookkeeper-server/src/test/resources/client.jks b/bookkeeper-server/src/test/resources/client.jks
deleted file mode 100644
index a959a9b..0000000
Binary files a/bookkeeper-server/src/test/resources/client.jks and /dev/null differ
diff --git a/bookkeeper-server/src/test/resources/generateKeysAndCerts.sh b/bookkeeper-server/src/test/resources/generateKeysAndCerts.sh
new file mode 100755
index 0000000..3d8fdb6
--- /dev/null
+++ b/bookkeeper-server/src/test/resources/generateKeysAndCerts.sh
@@ -0,0 +1,76 @@
+#!/usr/bin/env bash
+#
+#/**
+# * 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.
+# */
+
+# This script generates keys and self-signed certificates in
+# PEM, JKS and PKCS12 formats.
+
+# remove existing files.
+rm ./server-key.pem \
+    ./server-key.p12 \
+    ./server-key.jks \
+    ./server-cert.pem \
+    ./client-key.pem \
+    ./client-key.p12 \
+    ./client-key.jks \
+    ./client-cert.pem \
+    ./keyStoreServerPassword.txt \
+    ./keyStoreClientPassword.txt
+
+
+# One line command to create server keys and self signed certificates.
+openssl req \
+        -new \
+        -newkey rsa:4096 \
+        -days 365000 \
+        -nodes \
+        -x509 \
+        -subj "/C=US/ST=CA/L=San Francisco/O=Dummy/CN=apache.bookkeeper.org" \
+        -out server-cert.pem \
+        -keyout server-key.pem
+
+# Convert crt/key to PKCS12 format.
+openssl pkcs12 -export -in server-cert.pem -inkey server-key.pem -out server-key.p12 -passout pass:server
+
+# store password in a file
+echo "server" > keyStoreServerPassword.txt
+
+# Convert crt/key to JKS format.
+keytool -importkeystore -srckeystore server-key.p12 -srcstoretype pkcs12 -srcstorepass server -destkeystore server-key.jks -deststoretype jks -deststorepass server
+
+# One line command to create client keys and self signed certificates.
+openssl req \
+        -new \
+        -newkey rsa:4096 \
+        -days 365000 \
+        -nodes \
+        -x509 \
+        -subj "/C=US/ST=CA/L=San Francisco/O=Dummy/CN=apache.bookkeeper.org" \
+        -out client-cert.pem \
+        -keyout client-key.pem
+
+# Convert crt/key to PKCS12 format.
+openssl pkcs12 -export -in client-cert.pem -inkey client-key.pem -out client-key.p12 -passout pass:client
+
+# store password in a file.
+echo "client" > keyStoreClientPassword.txt
+
+# Convert crt/key to JKS format.
+keytool -importkeystore -srckeystore client-key.p12 -srcstoretype pkcs12 -srcstorepass client -destkeystore client-key.jks -deststoretype jks -deststorepass client
+
diff --git a/bookkeeper-server/src/test/resources/server-cert.pem b/bookkeeper-server/src/test/resources/server-cert.pem
new file mode 100644
index 0000000..b19de51
--- /dev/null
+++ b/bookkeeper-server/src/test/resources/server-cert.pem
@@ -0,0 +1,32 @@
+-----BEGIN CERTIFICATE-----
+MIIFmTCCA4GgAwIBAgIJAJLN/+fjRP2hMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNV
+BAYTAlVTMQswCQYDVQQIDAJDQTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEOMAwG
+A1UECgwFRHVtbXkxHjAcBgNVBAMMFWFwYWNoZS5ib29ra2VlcGVyLm9yZzAgFw0x
+ODAxMjQxODM2MjNaGA8zMDE3MDUyNzE4MzYyM1owYjELMAkGA1UEBhMCVVMxCzAJ
+BgNVBAgMAkNBMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMQ4wDAYDVQQKDAVEdW1t
+eTEeMBwGA1UEAwwVYXBhY2hlLmJvb2trZWVwZXIub3JnMIICIjANBgkqhkiG9w0B
+AQEFAAOCAg8AMIICCgKCAgEAvn6D0jbhA9OLpfuklC3ytUOuBXlFlgWlFEXTyqH8
+P54tH70+EJjmkV6d9kzBZohAL1cWgGwwQUR2MMIYLvKjRGnULkaCJor5WBP5D0wi
+jjTCsVNJcdC4gbEUjCl5HSmP4hPRVEHzFfWS61bJ2KDxAL7GCnAz+10MEr04KX62
+fOLr/eCHG8icfwnQ1O2fJs8cGUcxTeE5k/DV/103gH/49K3cFHHPNzyVWad8dgQ5
+Y0IZ1HTh/e/3IvsaOPp2EuKof9WtLYjjWnCMmL9MsmJiBmufetzZVqiIb8WNxa+e
+OR46Cm5lp7DwIXrUurYHTgtugmB9Pm1RL+T2YVHrPSbZ4yKYV7V6RRR/j+y4aI/7
+YXnZKI1zjDQT1GiyZDJGUBSILiMO9G5vbEL4btJlyQ4oBtlKozOLqi36GmlzOpSS
+yMVu7xyx6/va94YbI2VlTvCF/2sSUsf2ZNg4oL44+NfZDGO7vaDVFavdEsdkxxse
+wKa9uYpkfN7i4MZKi7CCR4lZo78xzt5vZ/irCqVngl3gwwBokfKLGskUi7Xwv/Sd
+gu2W88dAOzIfU878+MKeqVN3Uz91RhUgCrFhbhE/8E87WEzM0MZ68UxxlANI6tiA
+sBcYUUvhq154RPc5iY2Mzp48hju4NEKLvSbRDhJLpJGAVuupqzzM6iC1Uw23KwpI
+KOUCAwEAAaNQME4wHQYDVR0OBBYEFBjV9p9fG1YMVK7PrGrJ3wJLx370MB8GA1Ud
+IwQYMBaAFBjV9p9fG1YMVK7PrGrJ3wJLx370MAwGA1UdEwQFMAMBAf8wDQYJKoZI
+hvcNAQELBQADggIBABc8029Iw5b+qS+B110qRRfj0fBHz8x4jjIQdzHah3qqM3FM
+VzpySogESmKT3A+UmNUqzop/l+2V4G4g66UV7ps0rtJkgQU17Q70QF0TCQ8YranA
+5Vy/qZe/AXwrjjeVlmaFRxKpKWDDdlMX84+CjXdhAyMKSSezbtMKDvfERB2oGcjD
+Pz6d0XekRhqX4CiJLA2zkSZ55ABuJwyK24KeOtirsKxZXgQ5pG78zblWm3w2OdJv
+NxictCLqemDmEsMBuk2mlIBogm2tF7U9QBrIa7z2le7SjxLTO/+hWFOcDr41Bwcd
+cWoi1OkdiM3kg2COItCxtcHI8VmU17WL98SQMQsmby9RbVPXr56/x5Xi12CR/5b3
+LKCy6xmX4GEkWgc4VkvJp07eoArRxfQPEeYzZmwXBRcDO4uGRp9680QacwUvCOYe
+9Kkpe+iVdVMY2vAyil0ZmJ1oR3wW3hsiwu0RTEU1bKwrePqCR6t4EC6ihygYn0nG
+Y6PkdKMq/hoWjLo0p0iZuYMbbMNYcZWNAwV90eltw57ITyv8EI+D8hJ/b18wzPIA
+91QyqZ8qd7eo+o/YTGY0YzZHSk147pDk4nqK0d0kszr6SxBwx7i0KSsAB4Kvtrj8
+BLTOlCqwMKKmEuwlNNfonINZyjzRY5cTMeuxj8U7LjTamMOQH4kgnQ0FoEX6
+-----END CERTIFICATE-----
diff --git a/bookkeeper-server/src/test/resources/server-key.jks b/bookkeeper-server/src/test/resources/server-key.jks
new file mode 100644
index 0000000..3949b9d
Binary files /dev/null and b/bookkeeper-server/src/test/resources/server-key.jks differ
diff --git a/bookkeeper-server/src/test/resources/server-key.p12 b/bookkeeper-server/src/test/resources/server-key.p12
new file mode 100644
index 0000000..ab9c8aa
Binary files /dev/null and b/bookkeeper-server/src/test/resources/server-key.p12 differ
diff --git a/bookkeeper-server/src/test/resources/server-key.pem b/bookkeeper-server/src/test/resources/server-key.pem
new file mode 100644
index 0000000..1e2f1ec
--- /dev/null
+++ b/bookkeeper-server/src/test/resources/server-key.pem
@@ -0,0 +1,52 @@
+-----BEGIN PRIVATE KEY-----
+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
+EJRVpONvEXHus+f1sCUmQYWYuhmJHA==
+-----END PRIVATE KEY-----
diff --git a/bookkeeper-server/src/test/resources/server.jks b/bookkeeper-server/src/test/resources/server.jks
deleted file mode 100644
index aa582e6..0000000
Binary files a/bookkeeper-server/src/test/resources/server.jks and /dev/null differ
diff --git a/bookkeeper-server/src/test/resources/trustStorePassword.txt b/bookkeeper-server/src/test/resources/trustStorePassword.txt
deleted file mode 100644
index 1d40192..0000000
--- a/bookkeeper-server/src/test/resources/trustStorePassword.txt
+++ /dev/null
@@ -1 +0,0 @@
-changeit

-- 
To stop receiving notification emails like this one, please contact
sijie@apache.org.