diff --git a/.gitignore b/.gitignore index 80fa4b6..e4d478a 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,6 @@ build/ lib/ docs/ report/ +IDE/Android/.idea/deploymentTargetDropDown.xml +IDE/Android/app/.cxx/ +IDE/Android/app/src/main/cpp/wolfssl/ diff --git a/IDE/Android/README.md b/IDE/Android/README.md index 9ce9657..0c031ac 100644 --- a/IDE/Android/README.md +++ b/IDE/Android/README.md @@ -15,42 +15,7 @@ Tool and version information used when testing this project: The following sections outline steps required to run this example on an Android device or emulator. -## Converting JKS to BKS for Android Use - -On the Android device BKS format key stores are expected. To convert the -JKS example bundles to BKS use the following commands. Note: you will need -to download a version of the bcprov JAR from the Bouncy Castle website: - -``` -cd examples/provider -./convert-to-bks.sh -``` - -For exmaple, when using bcprov-ext-jdk15on-169.jar: - -``` -cd examples/provider -./convert-to-bks.sh ~/Downloads/bcprov-ext-jdk15on-169.jar -``` - -## Push BKS to Android Device or Emulator - -Push BKS bundles up to the device along with certificates. To do this start -up the emulator/device and use `adb push`. An example of this would be the -following commands from root wolfssljni directory: - -``` -adb shell -cd sdcard -mkdir examples -mkdir examples/provider -mkdir examples/certs -exit -adb push ./examples/provider/*.bks /sdcard/examples/provider/ -adb push ./examples/certs/ /sdcard/examples/ -``` - -## Add Native wolfSSL Library Source Code to Project +## 1. Add Native wolfSSL Library Source Code to Project This example project is already set up to compile and build the native wolfSSL library source files, but the wolfSSL files themselves have not been @@ -85,16 +50,54 @@ $ cd /IDE/Android/app/src/main/cpp/ $ ln -s /path/to/local/wolfssl ./wolfssl ``` -## Importing and Building the Example Project with Android Studio +## 2. Convert Example JKS files to BKS for Android Use -4) Open the Android Studio project by double clicking on the `Android` folder -in wolfssljni/IDE/ +On an Android device BKS format key stores are expected. To convert the +JKS example bundles to BKS use the following commands. Note: you will need +to download a version of the bcprov JAR from the Bouncy Castle website: -5) Build the project and run MainActivity from app -> java/com/example.wolfssl. +``` +cd examples/provider +./convert-to-bks.sh +``` + +For exmaple, when using bcprov-ext-jdk15on-169.jar: + +``` +cd examples/provider +./convert-to-bks.sh ~/Downloads/bcprov-ext-jdk15on-169.jar +``` + +## 3. Push BKS files to Android Device or Emulator + +Push BKS bundles up to the device along with certificates. To do this start +up the emulator/device and use `adb push`. An example of this would be the +following commands from root wolfssljni directory. This step may be done +after the starting Android Studio and compiling the project, but must be done +before running the app or test cases. + +``` +adb shell +cd sdcard +mkdir examples +mkdir examples/provider +mkdir examples/certs +exit +adb push ./examples/provider/*.bks /sdcard/examples/provider/ +adb push ./examples/certs/ /sdcard/examples/ +``` + +## 4. Import and Build the Example Project with Android Studio + +1) Open the Android Studio project by double clicking on the `Android` folder +in wolfssljni/IDE/. Or, from inside Android Studio, open the `Android` project +located in the wolfssljni/IDE directory. + +2) Build the project and run MainActivity from app -> java/com/example.wolfssl. This will ask for permissions to access the certificates in the /sdcard/ directory and then print out the server certificate information on success. -6) OPTIONAL: The androidTests can be run after permissions has been given. +3) OPTIONAL: The androidTests can be run after permissions has been given. app->java->com.wolfssl->provider.jsse.test->WolfSSLJSSETestSuite and app->java->com.wolfssl->test->WolfSSLTestSuite diff --git a/native/com_wolfssl_WolfSSL_TLS_VERSION.h b/native/com_wolfssl_WolfSSL_TLS_VERSION.h new file mode 100644 index 0000000..97e791d --- /dev/null +++ b/native/com_wolfssl_WolfSSL_TLS_VERSION.h @@ -0,0 +1,13 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class com_wolfssl_WolfSSL_TLS_VERSION */ + +#ifndef _Included_com_wolfssl_WolfSSL_TLS_VERSION +#define _Included_com_wolfssl_WolfSSL_TLS_VERSION +#ifdef __cplusplus +extern "C" { +#endif +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLAuthStore.java b/src/java/com/wolfssl/provider/jsse/WolfSSLAuthStore.java index e86bfac..bc26ebe 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLAuthStore.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLAuthStore.java @@ -90,8 +90,10 @@ public class WolfSSLAuthStore { this.currentVersion = version; store = new SessionStore(defaultCacheSize); - this.serverCtx = new WolfSSLSessionContext(this, defaultCacheSize, WolfSSL.WOLFSSL_SERVER_END); - this.clientCtx = new WolfSSLSessionContext(this, defaultCacheSize, WolfSSL.WOLFSSL_CLIENT_END); + this.serverCtx = new WolfSSLSessionContext( + this, defaultCacheSize, WolfSSL.WOLFSSL_SERVER_END); + this.clientCtx = new WolfSSLSessionContext( + this, defaultCacheSize, WolfSSL.WOLFSSL_CLIENT_END); } /** @@ -106,7 +108,8 @@ public class WolfSSLAuthStore { if (managers == null || managers.length == 0) { try { WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, - "searching installed providers for X509KeyManager"); + "searching installed providers for X509KeyManager (type: " + + KeyManagerFactory.getDefaultAlgorithm() +")"); /* use key managers from installed security providers */ KeyManagerFactory kmFactory = KeyManagerFactory.getInstance( @@ -126,9 +129,9 @@ public class WolfSSLAuthStore { if (managers != null) { for (int i = 0; i < managers.length; i++) { if (managers[i] instanceof X509KeyManager) { - WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, - "located X509KeyManager instance"); km = (X509KeyManager)managers[i]; + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + "located X509KeyManager instance: " + km); break; } } @@ -166,9 +169,9 @@ public class WolfSSLAuthStore { if (managers != null) { for (int i = 0; i < managers.length; i++) { if (managers[i] instanceof X509TrustManager) { - WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, - "located X509TrustManager instance"); tm = (X509TrustManager)managers[i]; + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + "located X509TrustManager instance: " + tm); break; } } diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLContext.java b/src/java/com/wolfssl/provider/jsse/WolfSSLContext.java index 0024d9e..e5b7d0c 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLContext.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLContext.java @@ -341,7 +341,7 @@ public class WolfSSLContext extends SSLContextSpi { SecureRandom sr) throws KeyManagementException { WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, - "entered engineInit()"); + "entered engineInit(" + km + ", " + tm + ", " + sr +")"); try { authStore = new WolfSSLAuthStore(km, tm, sr, currentVersion); diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLKeyManager.java b/src/java/com/wolfssl/provider/jsse/WolfSSLKeyManager.java index beb0088..248a9cb 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLKeyManager.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLKeyManager.java @@ -22,14 +22,21 @@ package com.wolfssl.provider.jsse; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; import java.security.InvalidAlgorithmParameterException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactorySpi; import javax.net.ssl.ManagerFactoryParameters; +import com.wolfssl.WolfSSLCertificate; +import com.wolfssl.WolfSSLException; /** * WolfSSL KeyManagerFactory implementation @@ -45,11 +52,92 @@ public class WolfSSLKeyManager extends KeyManagerFactorySpi { protected void engineInit(KeyStore store, char[] password) throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException { - this.store = store; + this.pswd = password; + KeyStore certs = store; WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, "entering engineInit(KeyStore store, char[] password)"); + + /* If no KeyStore passed in, try to load from system property values */ + if (store == null) { + String pass = System.getProperty("javax.net.ssl.keyStorePassword"); + String file = System.getProperty("javax.net.ssl.keyStore"); + String type = System.getProperty("javax.net.ssl.keyStoreType"); + String vmVendor = System.getProperty("java.vm.vendor"); + InputStream stream = null; + + try { + if (file != null) { + if (pass != null) { + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + "javax.net.ssl.keyStorePassword system property " + + "set, using password"); + this.pswd = pass.toCharArray(); + } else { + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + "javax.net.ssl.keyStorePassword system property " + + "not set"); + } + + /* We default to use a JKS KeyStore type if not set at the + * system level, except on Android we use BKS */ + try { + if (type != null && type != "") { + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + "javax.net.ssl.keyStoreType system property " + + "set: " + type); + certs = KeyStore.getInstance(type); + } else { + if (vmVendor != null && + vmVendor.equals("The Android Project")) { + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + "Detected Android VM, " + + "using BKS KeyStore type"); + certs = KeyStore.getInstance("BKS"); + } else { + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + "javax.net.ssl.keyStoreType system property " + + "not set, using type: JKS"); + certs = KeyStore.getInstance("JKS"); + } + } + } catch (KeyStoreException kse) { + WolfSSLDebug.log(getClass(), WolfSSLDebug.ERROR, + "Unsupported KeyStore type: " + type); + throw kse; + } + + try { + /* initialize KeyStore, loading certs below will + * overwrite if needed, otherwise Android needs + * this to be initialized here */ + certs.load(null, null); + + } catch (Exception e) { + WolfSSLDebug.log(getClass(), WolfSSLDebug.ERROR, + "Error initializing KeyStore with load(null, null)"); + throw e; + } + + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + "Loading certs from " + file); + stream = new FileInputStream(file); + certs.load(stream, this.pswd); + stream.close(); + } + + } catch (FileNotFoundException ex) { + throw new KeyStoreException(ex); + } catch (IOException ex) { + throw new KeyStoreException(ex); + } catch (NoSuchAlgorithmException ex) { + throw new KeyStoreException(ex); + } catch (CertificateException ex) { + throw new KeyStoreException(ex); + } + } + this.store = certs; } @Override diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLProvider.java b/src/java/com/wolfssl/provider/jsse/WolfSSLProvider.java index 3716a51..e9271ac 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLProvider.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLProvider.java @@ -111,6 +111,8 @@ public final class WolfSSLProvider extends Provider { } /* Key Factory */ + put("KeyManagerFactory.PKIX", + "com.wolfssl.provider.jsse.WolfSSLKeyManager"); put("KeyManagerFactory.X509", "com.wolfssl.provider.jsse.WolfSSLKeyManager"); put("KeyManagerFactory.SunX509", diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLTrustManager.java b/src/java/com/wolfssl/provider/jsse/WolfSSLTrustManager.java index e2d1945..eb31801 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLTrustManager.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLTrustManager.java @@ -34,8 +34,6 @@ import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; -import java.util.logging.Level; -import java.util.logging.Logger; import javax.net.ssl.ManagerFactoryParameters; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactorySpi; @@ -136,7 +134,7 @@ public class WolfSSLTrustManager extends TrustManagerFactorySpi { } catch (Exception e) { WolfSSLDebug.log(getClass(), WolfSSLDebug.ERROR, "Error initializing KeyStore with load(null, null)"); - throw e; + throw new KeyStoreException(e); } if (file == null) { @@ -262,7 +260,7 @@ public class WolfSSLTrustManager extends TrustManagerFactorySpi { WolfSSLDebug.log(getClass(), WolfSSLDebug.ERROR, "Permission error when trying to read " + "system CA certificates"); - throw e; + throw new KeyStoreException(e); } WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, "Found " + cafiles.length + " CA files to load " + @@ -306,7 +304,7 @@ public class WolfSSLTrustManager extends TrustManagerFactorySpi { "Error generating certificate from " + "ByteArrayInputStream"); bis.close(); - throw ce; + throw new KeyStoreException(ce); } String aliasString = "alias" + aliasCnt; @@ -341,21 +339,13 @@ public class WolfSSLTrustManager extends TrustManagerFactorySpi { stream.close(); } } catch (FileNotFoundException ex) { - Logger.getLogger( - WolfSSLTrustManager.class.getName()).log( - Level.SEVERE, null, ex); + throw new KeyStoreException(ex); } catch (IOException ex) { - Logger.getLogger( - WolfSSLTrustManager.class.getName()).log( - Level.SEVERE, null, ex); + throw new KeyStoreException(ex); } catch (NoSuchAlgorithmException ex) { - Logger.getLogger( - WolfSSLTrustManager.class.getName()).log( - Level.SEVERE, null, ex); + throw new KeyStoreException(ex); } catch (CertificateException ex) { - Logger.getLogger( - WolfSSLTrustManager.class.getName()).log( - Level.SEVERE, null, ex); + throw new KeyStoreException(ex); } } this.store = certs; diff --git a/src/test/com/wolfssl/provider/jsse/test/WolfSSLSocketTest.java b/src/test/com/wolfssl/provider/jsse/test/WolfSSLSocketTest.java index 477a458..6f2ff48 100644 --- a/src/test/com/wolfssl/provider/jsse/test/WolfSSLSocketTest.java +++ b/src/test/com/wolfssl/provider/jsse/test/WolfSSLSocketTest.java @@ -175,12 +175,12 @@ public class WolfSSLSocketTest { try { /* set up KeyStore */ InputStream stream = new FileInputStream(tf.clientJKS); - pKey = KeyStore.getInstance("JKS"); + pKey = KeyStore.getInstance(tf.keyStoreType); pKey.load(stream, jksPass); stream.close(); stream = new FileInputStream(tf.clientJKS); - cert = KeyStore.getInstance("JKS"); + cert = KeyStore.getInstance(tf.keyStoreType); cert.load(stream, jksPass); stream.close(); @@ -1543,6 +1543,212 @@ public class WolfSSLSocketTest { System.out.println("\t... passed"); } + + @Test + public void testClientServerUsingSystemProperties() throws Exception { + + System.out.print("\tSystem Property Store Support"); + + System.setProperty("javax.net.ssl.trustStore", tf.clientJKS); + System.setProperty("javax.net.ssl.trustStoreType", tf.keyStoreType); + System.setProperty("javax.net.ssl.trustStorePassword", tf.jksPassStr); + + System.setProperty("javax.net.ssl.keyStore", tf.clientJKS); + System.setProperty("javax.net.ssl.keyStoreType", tf.keyStoreType); + System.setProperty("javax.net.ssl.keyStorePassword", tf.jksPassStr); + + SSLContext ctx = SSLContext.getInstance("TLS", ctxProvider); + + /* not specifying TrustStore and KeyStore, expect to load from + * system properties set above */ + ctx.init(null, null, null); + + /* create SSLServerSocket first to get ephemeral port */ + SSLServerSocket ss = (SSLServerSocket)ctx.getServerSocketFactory() + .createServerSocket(0); + + SSLSocket cs = (SSLSocket)ctx.getSocketFactory().createSocket(); + cs.connect(new InetSocketAddress(ss.getLocalPort())); + final SSLSocket server = (SSLSocket)ss.accept(); + + ExecutorService es = Executors.newSingleThreadExecutor(); + Future serverFuture = es.submit(new Callable() { + @Override + public Void call() throws Exception { + try { + server.startHandshake(); + + } catch (SSLException e) { + System.out.println("\t... failed"); + fail(); + } + return null; + } + }); + + try { + cs.startHandshake(); + + } catch (SSLHandshakeException e) { + System.out.println("\t... failed"); + fail(); + } + + es.shutdown(); + serverFuture.get(); + cs.close(); + server.close(); + ss.close(); + + /* ------------------------------------------------ */ + /* Test with bad trustStorePassword, expect to fail */ + /* ------------------------------------------------ */ + System.setProperty("javax.net.ssl.trustStore", tf.clientJKS); + System.setProperty("javax.net.ssl.trustStoreType", tf.keyStoreType); + System.setProperty("javax.net.ssl.trustStorePassword", "badpass"); + + System.setProperty("javax.net.ssl.keyStore", tf.clientJKS); + System.setProperty("javax.net.ssl.keyStoreType", tf.keyStoreType); + System.setProperty("javax.net.ssl.keyStorePassword", tf.jksPassStr); + + ctx = SSLContext.getInstance("TLS", ctxProvider); + + try { + /* not specifying TrustStore and KeyStore, expect to load from + * system properties set above */ + ctx.init(null, null, null); + System.out.println("\t... failed"); + fail(); + } catch (KeyManagementException e) { + /* expected: java.io.IOException: keystore password was incorrect */ + } + + /* ------------------------------------------------ */ + /* Test with bad trustStore path, expect to fail */ + /* ------------------------------------------------ */ + System.setProperty("javax.net.ssl.trustStore", "badstorepath"); + System.setProperty("javax.net.ssl.trustStoreType", tf.keyStoreType); + System.setProperty("javax.net.ssl.trustStorePassword", tf.jksPassStr); + + System.setProperty("javax.net.ssl.keyStore", tf.clientJKS); + System.setProperty("javax.net.ssl.keyStoreType", tf.keyStoreType); + System.setProperty("javax.net.ssl.keyStorePassword", tf.jksPassStr); + + ctx = SSLContext.getInstance("TLS", ctxProvider); + + try { + /* not specifying TrustStore and KeyStore, expect to load from + * system properties set above */ + ctx.init(null, null, null); + System.out.println("\t... failed"); + fail(); + } catch (KeyManagementException e) { + /* expected: java.io.IOException: keystore password was incorrect */ + } + + /* ------------------------------------------------ */ + /* Test with bad trustStore type, expect to fail */ + /* ------------------------------------------------ */ + System.setProperty("javax.net.ssl.trustStore", tf.clientJKS); + System.setProperty("javax.net.ssl.trustStoreType", "badtype"); + System.setProperty("javax.net.ssl.trustStorePassword", tf.jksPassStr); + + System.setProperty("javax.net.ssl.keyStore", tf.clientJKS); + System.setProperty("javax.net.ssl.keyStoreType", tf.keyStoreType); + System.setProperty("javax.net.ssl.keyStorePassword", tf.jksPassStr); + + ctx = SSLContext.getInstance("TLS", ctxProvider); + + try { + /* not specifying TrustStore and KeyStore, expect to load from + * system properties set above */ + ctx.init(null, null, null); + System.out.println("\t... failed"); + fail(); + } catch (KeyManagementException e) { + /* expected: java.io.IOException: keystore password was incorrect */ + } + + /* ------------------------------------------------ */ + /* Test with bad keyStorePassword, expect to fail */ + /* ------------------------------------------------ */ + System.setProperty("javax.net.ssl.trustStore", tf.clientJKS); + System.setProperty("javax.net.ssl.trustStoreType", tf.keyStoreType); + System.setProperty("javax.net.ssl.trustStorePassword", tf.jksPassStr); + + System.setProperty("javax.net.ssl.keyStore", tf.clientJKS); + System.setProperty("javax.net.ssl.keyStoreType", tf.keyStoreType); + System.setProperty("javax.net.ssl.keyStorePassword", "badpass"); + + ctx = SSLContext.getInstance("TLS", ctxProvider); + + try { + /* not specifying TrustStore and KeyStore, expect to load from + * system properties set above */ + ctx.init(null, null, null); + System.out.println("\t... failed"); + fail(); + } catch (KeyManagementException e) { + /* expected: java.io.IOException: keystore password was incorrect */ + } + + /* ------------------------------------------------ */ + /* Test with bad keyStore path, expect to fail */ + /* ------------------------------------------------ */ + System.setProperty("javax.net.ssl.trustStore", tf.clientJKS); + System.setProperty("javax.net.ssl.trustStoreType", tf.keyStoreType); + System.setProperty("javax.net.ssl.trustStorePassword", tf.jksPassStr); + + System.setProperty("javax.net.ssl.keyStore", "badpath"); + System.setProperty("javax.net.ssl.keyStoreType", tf.keyStoreType); + System.setProperty("javax.net.ssl.keyStorePassword", tf.jksPassStr); + + ctx = SSLContext.getInstance("TLS", ctxProvider); + + try { + /* not specifying TrustStore and KeyStore, expect to load from + * system properties set above */ + ctx.init(null, null, null); + System.out.println("\t... failed"); + fail(); + } catch (KeyManagementException e) { + /* expected: java.io.IOException: keystore password was incorrect */ + } + + /* ------------------------------------------------ */ + /* Test with bad keyStore type, expect to fail */ + /* ------------------------------------------------ */ + System.setProperty("javax.net.ssl.trustStore", tf.clientJKS); + System.setProperty("javax.net.ssl.trustStoreType", tf.keyStoreType); + System.setProperty("javax.net.ssl.trustStorePassword", tf.jksPassStr); + + System.setProperty("javax.net.ssl.keyStore", tf.clientJKS); + System.setProperty("javax.net.ssl.keyStoreType", "badtype"); + System.setProperty("javax.net.ssl.keyStorePassword", tf.jksPassStr); + + ctx = SSLContext.getInstance("TLS", ctxProvider); + + try { + /* not specifying TrustStore and KeyStore, expect to load from + * system properties set above */ + ctx.init(null, null, null); + System.out.println("\t... failed"); + fail(); + } catch (KeyManagementException e) { + /* expected: java.io.IOException: keystore password was incorrect */ + } + + /* reset properties back to empty */ + System.clearProperty("javax.net.ssl.trustStore"); + System.clearProperty("javax.net.ssl.trustStoreType"); + System.clearProperty("javax.net.ssl.trustStorePassword"); + System.clearProperty("javax.net.ssl.keyStore"); + System.clearProperty("javax.net.ssl.keyStoreType"); + System.clearProperty("javax.net.ssl.keyStorePassword"); + + System.out.println("\t... passed"); + } + protected class TestServer extends Thread { private SSLContext ctx; diff --git a/src/test/com/wolfssl/provider/jsse/test/WolfSSLTestFactory.java b/src/test/com/wolfssl/provider/jsse/test/WolfSSLTestFactory.java index 85307e3..0f14951 100644 --- a/src/test/com/wolfssl/provider/jsse/test/WolfSSLTestFactory.java +++ b/src/test/com/wolfssl/provider/jsse/test/WolfSSLTestFactory.java @@ -75,7 +75,8 @@ class WolfSSLTestFactory { protected String googleCACert; protected String exampleComCert; - protected final static char[] jksPass = "wolfSSL test".toCharArray(); + protected final static String jksPassStr = "wolfSSL test"; + protected final static char[] jksPass = jksPassStr.toCharArray(); protected String keyStoreType = "JKS"; private boolean extraDebug = false;