add support for keyStore/keyStoreType/keyStorePassword system properties

pull/74/head
Chris Conlon 2021-11-17 11:20:00 -07:00
parent d99e0ac49c
commit eceec985d3
10 changed files with 379 additions and 70 deletions

3
.gitignore vendored
View File

@ -16,3 +16,6 @@ build/
lib/
docs/
report/
IDE/Android/.idea/deploymentTargetDropDown.xml
IDE/Android/app/.cxx/
IDE/Android/app/src/main/cpp/wolfssl/

View File

@ -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 <path/to/provider>
```
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 <path/to/provider>
```
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

View File

@ -0,0 +1,13 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* 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

View File

@ -90,8 +90,10 @@ public class WolfSSLAuthStore {
this.currentVersion = version;
store = new SessionStore<Integer,
WolfSSLImplementSSLSession>(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;
}
}

View File

@ -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);

View File

@ -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

View File

@ -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",

View File

@ -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;

View File

@ -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<Void> serverFuture = es.submit(new Callable<Void>() {
@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;

View File

@ -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;