JSSE: refactor KeyManager and TrustManager loading of KeyStore in engineInit(), add support for wolfJCE WKS KeyStore type

pull/178/head
Chris Conlon 2024-03-14 15:36:05 -06:00
parent 1e65f4c215
commit b80a989b4e
3 changed files with 777 additions and 358 deletions

View File

@ -40,13 +40,109 @@ import javax.net.ssl.ManagerFactoryParameters;
* WolfSSL KeyManagerFactory implementation * WolfSSL KeyManagerFactory implementation
*/ */
public class WolfSSLKeyManager extends KeyManagerFactorySpi { public class WolfSSLKeyManager extends KeyManagerFactorySpi {
private char[] pswd; private char[] pswd = null;
private KeyStore store; private KeyStore store = null;
private boolean initialized = false; private boolean initialized = false;
/** Default WolfSSLKeyManager constructor */ /** Default WolfSSLKeyManager constructor */
public WolfSSLKeyManager() { } public WolfSSLKeyManager() { }
/**
* Try to load KeyStore from System properties if set.
*
* If a KeyStore file has been specified in the javax.net.ssl.keyStore
* System property, then we try to load it in the following ways:
*
* 1. Using type specified in javax.net.ssl.keyStoreType. If not given:
* 2. Using wolfJCE WKS type, if available
* 3. Using BKS type if on Android
* 4. Using JKS type if above all fail
*
* @return new KeyStore object that has been created and loaded using
* details specified in System properties.
*
* @throws KeyStoreException if javax.net.ssl.keyStore property is
* set but KeyStore fails to load
*/
private KeyStore LoadKeyStoreFromSystemProperties()
throws KeyStoreException {
KeyStore sysStore = null;
InputStream stream = 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");
boolean wksAvailable = false;
if (file != null) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"Loading certs from: " + file);
/* Check if wolfJCE WKS KeyStore is registered and available */
wksAvailable = WolfSSLUtil.WKSAvailable();
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"wolfJCE WKS KeyStore type available: " + wksAvailable);
/* Set KeyStore password if javax.net.ssl.keyStorePassword set */
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");
}
/* Keystore type given in property, try loading using it */
if (type != null && !type.trim().isEmpty()) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"javax.net.ssl.keyStoreType set: " + type);
sysStore = WolfSSLUtil.LoadKeyStoreFileByType(
file, this.pswd, type);
}
else {
/* Try with wolfJCE WKS type first, in case wolfCrypt
* FIPS is being used */
if (wksAvailable) {
sysStore = WolfSSLUtil.LoadKeyStoreFileByType(
file, this.pswd, "WKS");
}
/* Try with BKS, if we're running on Android */
if ((sysStore == null) && WolfSSLUtil.isAndroid()) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"Detected Android VM, trying BKS KeyStore type");
sysStore = WolfSSLUtil.LoadKeyStoreFileByType(
file, this.pswd, "BKS");
}
/* Try falling back to JKS */
if (sysStore == null) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"javax.net.ssl.keyStoreType system property not set, " +
"trying type: JKS");
sysStore = WolfSSLUtil.LoadKeyStoreFileByType(
file, this.pswd, "JKS");
}
}
if (sysStore == null) {
throw new KeyStoreException(
"Failed to load KeyStore from System properties, " +
"please double check settings");
}
else {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"Loaded certs from KeyStore via System properties");
}
}
return sysStore;
}
@Override @Override
protected void engineInit(KeyStore store, char[] password) protected void engineInit(KeyStore store, char[] password)
throws KeyStoreException, NoSuchAlgorithmException, throws KeyStoreException, NoSuchAlgorithmException,
@ -58,84 +154,21 @@ public class WolfSSLKeyManager extends KeyManagerFactorySpi {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"entering engineInit(KeyStore store, char[] password)"); "entering engineInit(KeyStore store, char[] password)");
/* If no KeyStore passed in, try to load from system property values */ /* If no KeyStore passed in, try to load from system property values
* if they have been set */
if (store == null) { 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.trim().isEmpty()) {
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, WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"Loading certs from " + file); "input KeyStore null, trying to load KeyStore from " +
stream = new FileInputStream(file); "system properties");
certs.load(stream, this.pswd);
stream.close(); certs = LoadKeyStoreFromSystemProperties();
}
else {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"input KeyStore provided, using inside KeyManager");
} }
} 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; this.store = certs;
this.initialized = true; this.initialized = true;
} }

View File

@ -27,10 +27,11 @@ import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.security.InvalidAlgorithmParameterException; import java.security.Security;
import java.security.KeyStore; import java.security.KeyStore;
import java.security.KeyStoreException; import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.InvalidAlgorithmParameterException;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.security.cert.Certificate; import java.security.cert.Certificate;
import java.security.cert.CertificateFactory; import java.security.cert.CertificateFactory;
@ -54,225 +55,407 @@ public class WolfSSLTrustManager extends TrustManagerFactorySpi {
/** Default WolfSSLTrustManager constructor */ /** Default WolfSSLTrustManager constructor */
public WolfSSLTrustManager() { } public WolfSSLTrustManager() { }
/* Initialize TrustManager. Attempts to load CA certifciates as trusted /**
* roots into wolfSSL from user-provided KeyStore. If KeyStore is null, * Try to load KeyStore from System properties if set.
* we attempt to load default system CA certificates in the following *
* priority order: * If a KeyStore file has been specified in the javax.net.ssl.keyStore
* 1. javax.net.ssl.trustStore location, if set. Using password * System property, then we try to load it in the following ways:
* in javax.net.ssl.trustStorePassword. *
* 2. $JAVA_HOME/lib/security/jssecacerts (JDK 9+) * 1. Using type specified in javax.net.ssl.keyStoreType. If not given:
* 3. $JAVA_HOME/jre/lib/security/jssecacerts (JDK <= 8) * 2. Using wolfJCE WKS type, if available
* 4. $JAVA_HOME/lib/security/cacerts (JDK 9+) * 3. Using BKS type if on Android
* 5. $JAVA_HOME/jre/lib/security/cacerts (JDK <= 8) * 4. Using JKS type if above all fail
* 6. /etc/ssl/certs/java/cacerts *
* 7. Android: AndroidCAStore system KeyStore * @param wksAvailable Boolean indicating if wolfJCE WKS KeyStore type
* 8. Android: $ANDROID_ROOT/etc/security/cacerts * is available, true if so, false if not
* @param tsPass javax.net.ssl.trustStorePassword system property
* value, or null
* @param tsFile javax.net.ssl.trustStore system property value, or null
* @param tsType javax.net.ssl.trustStoreType system property value,
* or null
*
* @return new KeyStore object that has been created and loaded using
* details specified in System properties.
*
* @throws KeyStoreException if javax.net.ssl.keyStore property is
* set but KeyStore fails to load
*/ */
@Override private KeyStore LoadKeyStoreFromSystemProperties(boolean wksAvailable,
protected void engineInit(KeyStore in) throws KeyStoreException { String tsPass, String tsFile, String tsType)
KeyStore certs = in; throws KeyStoreException {
char[] passArr = null;
KeyStore sysStore = null;
if (tsFile != null) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"entered engineInit()"); "Loading certs from: " + tsFile);
if (in == null) { /* Set KeyStore password if javax.net.ssl.keyStorePassword set */
String pass = System.getProperty("javax.net.ssl.trustStorePassword"); if (tsPass != null) {
String file = System.getProperty("javax.net.ssl.trustStore");
String type = System.getProperty("javax.net.ssl.trustStoreType");
String vmVendor = System.getProperty("java.vm.vendor");
String javaHome = System.getenv("JAVA_HOME");
String androidRoot = System.getenv("ANDROID_ROOT");
char[] passAr = null;
InputStream stream = null;
boolean systemCertsFound = false;
int aliasCnt = 0;
try {
if (pass != null) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"javax.net.ssl.trustStorePassword system property " + "javax.net.ssl.trustStorePassword system property " +
"set, using password"); "set, using password");
passAr = pass.toCharArray(); passArr = tsPass.toCharArray();
} else { } else {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"javax.net.ssl.trustStorePassword system property " + "javax.net.ssl.trustStorePassword system property " +
"not set"); "not set");
} }
/* default to JKS KeyStore type if not set at system level */ /* System keystore type set, try loading using it first */
/* We default to use a JKS KeyStore type if not set at the if (tsType != null && !tsType.trim().isEmpty()) {
* system level, except on Android we use BKS */
try {
if (type != null && !type.trim().isEmpty()) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"javax.net.ssl.trustStoreType system property " + "javax.net.ssl.trustStoreType set: " + tsType);
"set: " + type); sysStore = WolfSSLUtil.LoadKeyStoreFileByType(
certs = KeyStore.getInstance(type); tsFile, passArr, tsType);
} else { }
if (vmVendor != null && else {
vmVendor.equals("The Android Project")) { /* Try with wolfJCE WKS type first, in case wolfCrypt
* FIPS is being used */
if (wksAvailable) {
sysStore = WolfSSLUtil.LoadKeyStoreFileByType(
tsFile, passArr, "WKS");
}
/* Try with BKS, if we're running on Android */
if (sysStore == null && WolfSSLUtil.isAndroid()) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"Detected Android VM, using BKS KeyStore type"); "Detected Android VM, trying BKS KeyStore type");
certs = KeyStore.getInstance("BKS"); sysStore = WolfSSLUtil.LoadKeyStoreFileByType(
} else { tsFile, passArr, "BKS");
}
/* Try falling back to JKS */
if (sysStore == null) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"javax.net.ssl.trustStoreType system property " + "javax.net.ssl.trustStoreType system property not set, " +
"not set, using type: JKS"); "trying type: JKS");
certs = KeyStore.getInstance("JKS"); sysStore = WolfSSLUtil.LoadKeyStoreFileByType(
tsFile, passArr, "JKS");
} }
} }
} catch (KeyStoreException kse) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.ERROR,
"Unsupported KeyStore type: " + type);
throw kse;
}
try { if (sysStore == null) {
/* initialize KeyStore, loading certs below will throw new KeyStoreException(
* overwrite if needed, otherwise Android needs "Failed to load KeyStore from System properties, " +
* this to be initialized here */ "please double check settings");
certs.load(null, null);
} catch (Exception e) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.ERROR,
"Error initializing KeyStore with load(null, null)");
throw new KeyStoreException(e);
} }
else {
if (file == null) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"javax.net.ssl.trustStore system property not set, " + "Loaded certs from KeyStore via System properties");
"trying to load system certs"); }
/* try to load trusted system certs if possible */
if (javaHome != null) {
if (!javaHome.endsWith("/") &&
!javaHome.endsWith("\\")) {
/* add trailing slash if not there already */
javaHome = javaHome.concat("/");
} }
/* Java 9+ have cacerts under: return sysStore;
* $JAVA_HOME/lib/security/cacerts }
/**
* Try to load system CA certs from jssecacerts or cacerts KeyStore.
*
* Java 9+ has cacerts and/or jssecacerts under:
* $JAVA_HOME/lib/security/[jssecacerts | cacerts]
* Java 8 and earlier use: * Java 8 and earlier use:
* $JAVA_HOME/jre/lib/security/cacerts * $JAVA_HOME/jre/lib/security/[jssecacerts | cacerts ]
*
* If wolfJCE WKS KeyStore type is available (ie: wolfJCE has been
* registered on this system), we first try to load jssecacerts.wks
* or cacerts.wks as WKS type KeyStore before falling back to trying to
* load KeyStore type specified in java.security by 'keystore.type'
* Security property. This is "JKS" type by default on my platforms.
*
* @param jh String value of $JAVA_HOME with trailing slash
* @param wksAvailable Boolean if wolfJCE WKS KeyStore typs is available
* @param tsPass javax.net.ssl.trustStorePassword, or null if not set
* @param certBundleName Name of system certificate bundle, either
* "jssecacerts" or "cacerts"
*
* @return KeyStore object loaded with CA certs from jssecacerts, or
* null if not able to find KeyStore or load certs
*/ */
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, private KeyStore LoadJavaSystemCerts(String jh, boolean wksAvailable,
"$JAVA_HOME = " + javaHome); String tsPass, String certBundleName) {
/* trying: "lib/security/jssecacerts" */ char[] passArr = null;
File f = new File(javaHome.concat( KeyStore sysStore = null;
"lib/security/jssecacerts")); File f = null;
FileInputStream stream = null;
/* Get default KeyStore type, set in java.security and normally JKS */
String storeType = Security.getProperty("keystore.type");
if (storeType != null) {
storeType = storeType.toUpperCase();
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"keystore.type Security property set: " + storeType);
}
if (wksAvailable) {
/* First try wolfJCE WKS converted version for Java 9+ */
f = new File(jh.concat("lib/security/")
.concat(certBundleName).concat(".wks"));
/* Second try wolfJCE WKS converted version for Java <= 8 */
if (!f.exists()) { if (!f.exists()) {
f = new File(javaHome.concat( f = new File(jh.concat("jre/lib/security/")
"jre/lib/security/jssecacerts")); .concat(certBundleName).concat(".wks"));
}
if (f.exists()) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"Loading certs from " + f.getAbsolutePath());
stream = new FileInputStream(f);
certs.load(stream, passAr);
stream.close();
systemCertsFound = true;
} else {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"$JAVA_HOME/(jre/)lib/security/jssecacerts: " +
"not found");
} }
/* trying: "lib/security/cacerts" */ if (f.exists()) {
f = new File(javaHome.concat("lib/security/cacerts")); storeType = "WKS";
}
}
/* Third try normal Java 9+ location */
if ((f == null) || !f.exists()) {
f = new File(jh.concat("lib/security/").concat(certBundleName));
}
/* Fourth try normal Java <= 8 location */
if (!f.exists()) { if (!f.exists()) {
f = new File(javaHome.concat( f = new File(jh.concat("jre/lib/security/").concat(certBundleName));
"jre/lib/security/cacerts"));
} }
if (f.exists()) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"Loading certs from " + f.getAbsolutePath());
try {
sysStore = KeyStore.getInstance(storeType);
} catch (KeyStoreException e) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"Not able to get KeyStore of type: " + storeType);
return null;
}
try {
sysStore.load(null, null);
} catch (IOException | NoSuchAlgorithmException |
CertificateException e) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"Not able to load empty KeyStore(" + storeType + ")");
return null;
}
if (tsPass != null) {
passArr = tsPass.toCharArray();
}
try {
stream = new FileInputStream(f);
} catch (FileNotFoundException e) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"Not able to open KeyStore file for reading: " +
f.getAbsolutePath());
}
try {
sysStore.load(stream, passArr);
} catch (IOException | NoSuchAlgorithmException |
CertificateException e) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"Not able to load KeyStore with file stream: " +
f.getAbsolutePath());
} finally {
try {
if (stream != null) {
stream.close();
}
} catch (IOException e) {
}
}
} else {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"$JAVA_HOME/(jre/)lib/security/" +
certBundleName + ": not found");
}
return sysStore;
}
private KeyStore LoadSystemJsseCaCerts(String jh, boolean wksAvailable,
String tsPass) {
return LoadJavaSystemCerts(jh, wksAvailable, tsPass, "jssecacerts");
}
private KeyStore LoadSystemCaCerts(String jh, boolean wksAvailable,
String tsPass) {
return LoadJavaSystemCerts(jh, wksAvailable, tsPass, "cacerts");
}
/**
* Try to load system CA certs from common KeyStore locations.
*
* Currently includes:
* 1. /etc/ssl/certs/java/cacerts
*
*/
private KeyStore LoadCommonSystemCerts(boolean wksAvailable,
String tsPass) {
char[] passArr = null;
File f = null;
FileInputStream stream = null;
KeyStore sysStore = null;
f = new File("/etc/ssl/certs/java/cacerts");
if (f.exists()) { if (f.exists()) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"Loading certs from " + f.getAbsolutePath()); "Loading certs from " + f.getAbsolutePath());
stream = new FileInputStream(f);
certs.load(stream, passAr); if (tsPass != null) {
stream.close(); passArr = tsPass.toCharArray();
systemCertsFound = true;
} else {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"$JAVA_HOME/(jre/)lib/security/cacerts: " +
"not found");
}
} else {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"$JAVA_HOME not set, unable to load system certs");
} }
if (systemCertsFound == false) { try {
/* try loading from common system paths */
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"Trying to load system certs from common " +
"system paths");
/* trying: "/etc/ssl/certs/java/cacerts" */
File f = new File("/etc/ssl/certs/java/cacerts");
if (f.exists()) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"Loading certs from " + f.getAbsolutePath());
stream = new FileInputStream(f); stream = new FileInputStream(f);
certs.load(stream, passAr); } catch (FileNotFoundException e) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"Not able to open KeyStore file for reading: " +
f.getAbsolutePath());
}
try {
sysStore.load(stream, passArr);
} catch (IOException | NoSuchAlgorithmException |
CertificateException e) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"Not able to load KeyStore with file stream: " +
f.getAbsolutePath());
} finally {
try {
if (stream != null) {
stream.close(); stream.close();
systemCertsFound = true; }
} catch (IOException e) {
}
}
} else { } else {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"/etc/ssl/certs/java/cacerts: not found"); "/etc/ssl/certs/java/cacerts: not found");
} }
return sysStore;
} }
/**
* Try to load Android system CA certs from AndroidCAStore KeyStore.
*
* The AndroidCAStore KeyStore is pre-loaded with Android system CA
* certs. We try to load this first before going on to load root certs
* manually, since it's already pre-imported and set up.
*
* @return KeyStore object referencing AndroidCAStore, or null if not
* found or not able to be loaded
*/
private KeyStore LoadAndroidCAStore() {
KeyStore sysStore = null;
try {
sysStore = KeyStore.getInstance("AndroidCAStore");
} catch (KeyStoreException e) {
/* Error finding AndroidCAStore */
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"AndroidCAStore KeyStore not found, not loading");
return null;
}
try {
sysStore.load(null, null);
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"Using AndroidCAStore KeyStore for default system certs");
} catch (IOException | NoSuchAlgorithmException |
CertificateException e) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"Not able to load AndroidCAStore with null args");
return null;
}
return sysStore;
}
/**
* Try to load Android system root certificates manually by reading
* all PEM certificates in [android_root]/etc/security/cacerts directory.
*
* @return KeyStore object containing Android system CA certificates, or
* null if none found or error loading any certs
*/
private KeyStore LoadAndroidSystemCertsManually() {
int aliasCnt = 0;
byte[] derArray = null;
KeyStore sysStore = null;
CertificateFactory cfactory = null;
ByteArrayInputStream bis = null;
Certificate tmpCert = null;
String androidRoot = System.getenv("ANDROID_ROOT");
if (androidRoot != null) { if (androidRoot != null) {
/* first try to use AndroidCAStore KeyStore, this is /* Android default KeyStore type is BKS */
* pre-loaded with Android system CA certs */
try { try {
certs = KeyStore.getInstance("AndroidCAStore"); sysStore = KeyStore.getInstance("BKS");
certs.load(null, null);
systemCertsFound = true;
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"Using AndroidCAStore KeyStore for default " +
"system certs");
} catch (KeyStoreException e) { } catch (KeyStoreException e) {
/* error finding AndroidCAStore */ /* Unable to get or load empty BKS KeyStore type */
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"AndroidCAStore KeyStore not found, trying " + "Unable to get or load BKS KeyStore instance");
"to manually load system certs"); return null;
systemCertsFound = false;
} }
/* Otherwise, try to manually load system certs */ try {
if (systemCertsFound == false) { sysStore.load(null, null);
} catch (IOException | NoSuchAlgorithmException |
CertificateException e) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"Not able to load BKS KeyStore with null args");
return null;
}
/* Add trailing slash if not there already */
if (!androidRoot.endsWith("/") && if (!androidRoot.endsWith("/") &&
!androidRoot.endsWith("\\")) { !androidRoot.endsWith("\\")) {
/* add trailing slash if not there already */
androidRoot = androidRoot.concat("/"); androidRoot = androidRoot.concat("/");
} }
String caStoreDir = androidRoot.concat( String caStoreDir = androidRoot.concat("etc/security/cacerts");
"etc/security/cacerts");
File cadir = new File(caStoreDir); File cadir = new File(caStoreDir);
String[] cafiles = null; String[] cafiles = null;
try { try {
cafiles = cadir.list(); cafiles = cadir.list();
} catch (Exception e) { } catch (Exception e) {
/* denied access reading cacerts directory */ /* Denied access reading cacerts directory */
WolfSSLDebug.log(getClass(), WolfSSLDebug.ERROR, WolfSSLDebug.log(getClass(), WolfSSLDebug.ERROR,
"Permission error when trying to read " + "Permission error when trying to read system " +
"system CA certificates"); "CA certificates");
throw new KeyStoreException(e); return null;
} }
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"Found " + cafiles.length + " CA files to load " + "Found " + cafiles.length + " CA files to load into KeyStore");
"into KeyStore");
/* get factory for cert creation */ /* Get factory for cert creation */
CertificateFactory cfactory = try {
CertificateFactory.getInstance("X.509"); cfactory = CertificateFactory.getInstance("X.509");
} catch (CertificateException e) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"Not able to get X.509 CertificateFactory instance");
return null;
}
/* loop over all PEM certs */ /* Loop over all PEM certs */
for (String cafile : cafiles) { for (String cafile : cafiles) {
WolfSSLCertificate certPem = null; WolfSSLCertificate certPem = null;
@ -292,66 +475,162 @@ public class WolfSSLTrustManager extends TrustManagerFactorySpi {
continue; continue;
} }
byte[] derArray = certPem.getDer(); try {
derArray = certPem.getDer();
} catch (WolfSSLJNIException e) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"Error getting DER from PEM cert, skipping: " +
fullCertPath);
} finally {
certPem.free(); certPem.free();
ByteArrayInputStream bis = }
new ByteArrayInputStream(derArray);
Certificate tmpCert = null; bis = new ByteArrayInputStream(derArray);
try { try {
tmpCert = cfactory.generateCertificate(bis); tmpCert = cfactory.generateCertificate(bis);
bis.close();
} catch (CertificateException ce) { } catch (CertificateException ce) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.ERROR, WolfSSLDebug.log(getClass(), WolfSSLDebug.ERROR,
"Error generating certificate from " + "Error generating certificate from " +
"ByteArrayInputStream"); "ByteArrayInputStream, skipped loading cert: " +
fullCertPath);
continue;
} finally {
try {
if (bis != null) {
bis.close(); bis.close();
throw new KeyStoreException(ce); }
} catch (IOException e) {
}
} }
String aliasString = "alias" + aliasCnt; String aliasString = "alias" + aliasCnt;
try { try {
certs.setCertificateEntry(aliasString, tmpCert); sysStore.setCertificateEntry(aliasString, tmpCert);
} catch (KeyStoreException kse) { } catch (KeyStoreException kse) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.ERROR, WolfSSLDebug.log(getClass(), WolfSSLDebug.ERROR,
"Error setting certificate entry in " + "Error setting certificate entry in " +
"KeyStore, skipping loading cert"); "KeyStore, skipping loading cert: " +
fullCertPath);
continue; continue;
} }
/* increment alias counter for unique aliases */ /* increment alias counter for unique aliases */
aliasCnt++; aliasCnt++;
} }
systemCertsFound = true;
} /* end Android manual load */ if (aliasCnt == 0) {
/* No certs loaded, don't return empty KeyStore */
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"No root certificates loaded from etc/security/cacerts");
return null;
}
} }
if (systemCertsFound == false) { return sysStore;
}
/**
* Initialize TrustManager, loading root/CA certs.
*
* Attempts to load CA certifciates as trusted roots into wolfSSL from
* user-provided KeyStore. If KeyStore is null, we attempt to load default
* system CA certificates. Certs are loaded in the following priority order:
*
* 1. User-provided KeyStore passed in
* 2. javax.net.ssl.trustStore location, if set. Using password
* in javax.net.ssl.trustStorePassword.
* 3. Java installation 'jssecacerts' bundle:
* a. $JAVA_HOME/lib/security/jssecacerts (JDK 9+)
* b. $JAVA_HOME/jre/lib/security/jssecacerts (JDK less than 9)
* 4. Java installation 'cacerts' bundle:
* a. $JAVA_HOME/lib/security/cacerts (JDK 9+)
* b. $JAVA_HOME/jre/lib/security/cacerts (JDK less than 9)
* 5. Common system CA certs locations:
* a. /etc/ssl/certs/java/cacerts
* 6. Android: AndroidCAStore system KeyStore
* 7. Android: $ANDROID_ROOT/etc/security/cacerts
*
* If none of the locations above work for finding/loading CA certs,
* none are loaded into this TrustManager.
*
* @param in KeyStore from which to load trusted root/CA certificates, may
* be null
*/
@Override
protected void engineInit(KeyStore in) throws KeyStoreException {
KeyStore certs = in;
String javaHome = null;
boolean wksAvailable = false;
String pass = System.getProperty("javax.net.ssl.trustStorePassword");
String file = System.getProperty("javax.net.ssl.trustStore");
String type = System.getProperty("javax.net.ssl.trustStoreType");
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"No trusted system certs found, none " + "entered engineInit(KeyStore in)");
"loaded by default");
/* [1] Just use KeyStore passed in by user if available */
if (in == null) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"input KeyStore null, trying to load system CA certs");
/* Check if wolfJCE WKS KeyStore is registered and available */
wksAvailable = WolfSSLUtil.WKSAvailable();
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"wolfJCE WKS KeyStore type available: " + wksAvailable);
/* [2] Try to load from system property details */
certs = LoadKeyStoreFromSystemProperties(
wksAvailable, pass, file, type);
/* Get JAVA_HOME for trying to load system certs next */
if (certs == null) {
javaHome = WolfSSLUtil.GetJavaHome();
if (javaHome == null) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"$JAVA_HOME not set, unable to load system CA certs");
}
else {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"$JAVA_HOME = " + javaHome);
}
}
/* [3] Try to load system jssecacerts */
if ((certs == null) && (javaHome != null)) {
certs = LoadSystemJsseCaCerts(javaHome, wksAvailable, pass);
}
/* [4] Try to load system cacerts */
if ((certs == null) && (javaHome != null)) {
certs = LoadSystemCaCerts(javaHome, wksAvailable, pass);
}
/* [5] Try to load common CA cert locations */
if (certs == null) {
certs = LoadCommonSystemCerts(wksAvailable, pass);
}
/* [6] Try to load system certs if on Android */
if ((certs == null) && WolfSSLUtil.isAndroid()) {
certs = LoadAndroidCAStore();
}
/* [7] Try to load Android system root certs manually */
if ((certs == null) && WolfSSLUtil.isAndroid()) {
certs = LoadAndroidSystemCertsManually();
} }
} }
else { else {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"Loading certs from " + file); "input KeyStore provided, using for trusted certs");
stream = new FileInputStream(file);
certs.load(stream, passAr);
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);
} catch (WolfSSLJNIException ex) {
throw new KeyStoreException(ex);
}
} }
this.store = certs; this.store = certs;
this.initialized = true; this.initialized = true;
} }

View File

@ -25,7 +25,13 @@ import java.util.Arrays;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.Security; import java.security.Security;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import com.wolfssl.WolfSSLException; import com.wolfssl.WolfSSLException;
@ -274,5 +280,106 @@ public class WolfSSLUtil {
return ret; return ret;
} }
/**
* Get path that JAVA_HOME is set, append trailing slash if needed.
*
* @return String that JAVA_HOME is set to, otherwise null if not set
*/
protected static String GetJavaHome() {
String javaHome = System.getenv("JAVA_HOME");
if (javaHome != null) {
if (!javaHome.endsWith("/") &&
!javaHome.endsWith("\\")) {
/* add trailing slash if not there already */
javaHome = javaHome.concat("/");
}
}
return javaHome;
}
/**
* Detect if we are running on Android or not.
*
* @return true if we are running on an Android VM, otherwise false
*/
protected static boolean isAndroid() {
String vmVendor = System.getProperty("java.vm.vendor");
if ((vmVendor != null) &&
vmVendor.equals("The Android Project")) {
return true;
}
return false;
}
/**
* Check if wolfJCE WKS KeyStore is available for use.
*
* @return true if WKS KeyStore type available, otherwise false
*/
protected static boolean WKSAvailable() {
boolean wksAvailable = false;
try {
KeyStore.getInstance("WKS");
wksAvailable = true;
} catch (KeyStoreException e) {
/* wolfJCE WKS not available, may be that wolfJCE is not being
* used or hasn't bee installed in system */
}
return wksAvailable;
}
/**
* Try to get KeyStore instance of type specified and load from
* given file using provided password.
*
* @param file KeyStore file to load into new KeyStore object
* @param pass KeyStore password used to verify KeyStore integrity
* @param type KeyStore type of file to load
*
* @return new KeyStore object loaded with KeyStore file, or null
* if unable to load KeyStore
*/
protected static KeyStore LoadKeyStoreFileByType(String file, char[] pass,
String type) {
KeyStore ks = null;
FileInputStream stream = null;
try {
ks = KeyStore.getInstance(type);
try {
/* Initialize KeyStore, loading certs below will overwrite if
* needed, but Android needs this to be initialized here */
ks.load(null, null);
} catch (Exception e) {
WolfSSLDebug.log(WolfSSLUtil.class, WolfSSLDebug.ERROR,
"Error initializing KeyStore with load(null, null)");
return null;
}
stream = new FileInputStream(file);
ks.load(stream, pass);
stream.close();
} catch (KeyStoreException | IOException | NoSuchAlgorithmException |
CertificateException e) {
return null;
}
return ks;
}
} }