Merge pull request #272 from cconlon/WolfSSLKeyX509_CachedEntries
JSSE: cache KeyStore entries in X509ExtendedKeyManagermaster
commit
1dc7d5a741
13
README.md
13
README.md
|
@ -469,6 +469,7 @@ and used by wolfSSL JNI/JSSE.
|
||||||
| wolfjsse.enabledSignatureAlgorithms | | String | Restricts enabled signature algorithms |
|
| wolfjsse.enabledSignatureAlgorithms | | String | Restricts enabled signature algorithms |
|
||||||
| wolfjsse.keystore.type.required | | String | Restricts KeyStore type |
|
| wolfjsse.keystore.type.required | | String | Restricts KeyStore type |
|
||||||
| wolfjsse.clientSessionCache.disabled | | "true" | Disables client session cache |
|
| wolfjsse.clientSessionCache.disabled | | "true" | Disables client session cache |
|
||||||
|
| wolfjsse.X509KeyManager.disableCache | "false" | "true" | Disables X509KeyManager KeyStore entry caching |
|
||||||
|
|
||||||
**wolfssl.readWriteByteBufferPool.disabled (String)** - Can be used to disable
|
**wolfssl.readWriteByteBufferPool.disabled (String)** - Can be used to disable
|
||||||
the static per-thread ByteBuffer pool used in com.wolfssl.WolfSSLSession
|
the static per-thread ByteBuffer pool used in com.wolfssl.WolfSSLSession
|
||||||
|
@ -554,6 +555,18 @@ cache. The Java client cache is enabled by default.
|
||||||
wolfjsse.clientSessionCache.disabled=true
|
wolfjsse.clientSessionCache.disabled=true
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**wolfjsse.X509KeyManager.disableCache (String)** - Can be used to disable
|
||||||
|
KeyStore entry caching in the WolfSSLKeyX509 (X509ExtendedKeyManager) implementation.
|
||||||
|
When set to "true", the X509KeyManager will revert to the original behavior of
|
||||||
|
calling KeyStore methods directly for each operation instead of using cached
|
||||||
|
entries. This can be useful for debugging, compatibility testing, or when
|
||||||
|
KeyStore contents may change dynamically. Caching is enabled by default for
|
||||||
|
performance. This should be set to the String "true" to disable caching:
|
||||||
|
|
||||||
|
```
|
||||||
|
wolfjsse.X509KeyManager.disableCache=true
|
||||||
|
```
|
||||||
|
|
||||||
If there are other Security properties you would like to use with wolfJSSE,
|
If there are other Security properties you would like to use with wolfJSSE,
|
||||||
please contact support@wolfssl.com.
|
please contact support@wolfssl.com.
|
||||||
|
|
||||||
|
|
|
@ -1081,7 +1081,6 @@ public class WolfSSLImplementSSLSession extends ExtendedSSLSession {
|
||||||
throws UnsupportedOperationException {
|
throws UnsupportedOperationException {
|
||||||
|
|
||||||
byte[] sniRequestArr = null;
|
byte[] sniRequestArr = null;
|
||||||
List<SNIServerName> sniNames = new ArrayList<>(1);
|
|
||||||
|
|
||||||
if (this.ssl == null) {
|
if (this.ssl == null) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
|
@ -1103,6 +1102,7 @@ public class WolfSSLImplementSSLSession extends ExtendedSSLSession {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sniRequestArr != null) {
|
if (sniRequestArr != null) {
|
||||||
|
List<SNIServerName> sniNames = new ArrayList<>(1);
|
||||||
SNIHostName sniName = new SNIHostName(sniRequestArr);
|
SNIHostName sniName = new SNIHostName(sniRequestArr);
|
||||||
sniNames.add(sniName);
|
sniNames.add(sniName);
|
||||||
|
|
||||||
|
|
|
@ -222,8 +222,14 @@ public class WolfSSLKeyManager extends KeyManagerFactorySpi {
|
||||||
"initialized before use, please call init()");
|
"initialized before use, please call init()");
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyManager[] km = {new WolfSSLKeyX509(this.store, this.pswd)};
|
try {
|
||||||
|
KeyManager[] km = { new WolfSSLKeyX509(this.store, this.pswd) };
|
||||||
return km;
|
return km;
|
||||||
|
|
||||||
|
} catch (KeyStoreException e) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Failed to create WolfSSLKeyX509: " + e.getMessage(), e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,10 +26,16 @@ import java.security.KeyStore;
|
||||||
import java.security.KeyStoreException;
|
import java.security.KeyStoreException;
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
|
import java.security.Security;
|
||||||
import java.security.cert.Certificate;
|
import java.security.cert.Certificate;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.Arrays;
|
||||||
import javax.net.ssl.SSLEngine;
|
import javax.net.ssl.SSLEngine;
|
||||||
import javax.net.ssl.X509ExtendedKeyManager;
|
import javax.net.ssl.X509ExtendedKeyManager;
|
||||||
import com.wolfssl.WolfSSLDebug;
|
import com.wolfssl.WolfSSLDebug;
|
||||||
|
@ -43,71 +49,257 @@ import com.wolfssl.WolfSSLDebug;
|
||||||
*/
|
*/
|
||||||
public class WolfSSLKeyX509 extends X509ExtendedKeyManager {
|
public class WolfSSLKeyX509 extends X509ExtendedKeyManager {
|
||||||
|
|
||||||
private KeyStore store;
|
/* Security property to control caching behavior. When set to "true",
|
||||||
private char[] password;
|
* disables KeyStore entry caching and reverts to calling KeyStore
|
||||||
|
* methods directly for each operation. */
|
||||||
|
private static final String DISABLE_CACHE_PROPERTY =
|
||||||
|
"wolfjsse.X509KeyManager.disableCache";
|
||||||
|
|
||||||
|
/* Reference to original KeyStore for non-cached operations */
|
||||||
|
private final KeyStore keyStore;
|
||||||
|
private final char[] keyStorePassword;
|
||||||
|
|
||||||
|
/* Cache behavior determined once at construction time */
|
||||||
|
private final boolean cacheDisabled;
|
||||||
|
|
||||||
|
/* Cache for KeyStore entries to avoid concurrent access issues. Prior
|
||||||
|
* to the addition of these caches, WolfSSLKeyX509 called down directly
|
||||||
|
* to the underlying KeyStore for each operation. Since the KeyStore
|
||||||
|
* operations are synchronized, concurrent threads accessing this
|
||||||
|
* KeyManager can queue up in that scenario and hurt performance.
|
||||||
|
* These caches are only used if caching has not been disabled via
|
||||||
|
* Security property. */
|
||||||
|
private final Map<String, X509Certificate> certificateCache;
|
||||||
|
private final Map<String, X509Certificate[]> certificateChainCache;
|
||||||
|
private final Map<String, PrivateKey> privateKeyCache;
|
||||||
|
private final Set<String> aliasSet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create new WolfSSLKeyX509 object
|
* Create new WolfSSLKeyX509 object
|
||||||
*
|
*
|
||||||
* @param in input KeyStore to use with this object
|
* @param store input KeyStore to cache entries from
|
||||||
* @param password input KeyStore password
|
* @param password input KeyStore password
|
||||||
|
* @throws KeyStoreException if unable to populate cache from KeyStore
|
||||||
*/
|
*/
|
||||||
public WolfSSLKeyX509(KeyStore in, char[] password) {
|
public WolfSSLKeyX509(KeyStore store, char[] password)
|
||||||
this.store = in;
|
throws KeyStoreException {
|
||||||
this.password = password;
|
|
||||||
|
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
() -> "creating new WolfSSLKeyX509 object");
|
() -> "creating new WolfSSLKeyX509 object");
|
||||||
|
|
||||||
|
/* Check Security property once at construction time */
|
||||||
|
this.cacheDisabled = "true".equalsIgnoreCase(
|
||||||
|
Security.getProperty(DISABLE_CACHE_PROPERTY));
|
||||||
|
|
||||||
|
if (this.cacheDisabled) {
|
||||||
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
|
() -> "KeyStore caching disabled via " +
|
||||||
|
DISABLE_CACHE_PROPERTY +
|
||||||
|
" Security property, using direct KeyStore access");
|
||||||
|
|
||||||
|
this.keyStore = store;
|
||||||
|
this.keyStorePassword =
|
||||||
|
(password != null) ? password.clone() : null;
|
||||||
|
|
||||||
|
this.certificateCache = null;
|
||||||
|
this.certificateChainCache = null;
|
||||||
|
this.privateKeyCache = null;
|
||||||
|
this.aliasSet = null;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
|
() -> "KeyStore caching enabled, populating caches");
|
||||||
|
|
||||||
|
this.keyStore = null;
|
||||||
|
this.keyStorePassword = null;
|
||||||
|
|
||||||
|
/* Initialize cache data structures */
|
||||||
|
this.certificateCache = new HashMap<String, X509Certificate>();
|
||||||
|
this.certificateChainCache =
|
||||||
|
new HashMap<String, X509Certificate[]>();
|
||||||
|
this.privateKeyCache = new HashMap<String, PrivateKey>();
|
||||||
|
this.aliasSet = new LinkedHashSet<String>();
|
||||||
|
|
||||||
|
/* Populate caches from KeyStore */
|
||||||
|
populateCache(store, password);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return array of aliases from current KeyStore that matches provided
|
* Populate internal caches with all entries from KeyStore
|
||||||
* type and issuers array.
|
*
|
||||||
|
* @param store KeyStore to read entries from
|
||||||
|
* @param password KeyStore password to access private keys
|
||||||
|
* @throws KeyStoreException if unable to read from KeyStore
|
||||||
|
*/
|
||||||
|
private void populateCache(KeyStore store, char[] password)
|
||||||
|
throws KeyStoreException {
|
||||||
|
|
||||||
|
if (store == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Enumeration<String> aliases = store.aliases();
|
||||||
|
|
||||||
|
while (aliases.hasMoreElements()) {
|
||||||
|
String alias = aliases.nextElement();
|
||||||
|
aliasSet.add(alias);
|
||||||
|
|
||||||
|
try {
|
||||||
|
/* Cache individual certificate */
|
||||||
|
Certificate cert = store.getCertificate(alias);
|
||||||
|
if (cert instanceof X509Certificate) {
|
||||||
|
certificateCache.put(alias, (X509Certificate)cert);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cache certificate chain */
|
||||||
|
Certificate[] certChain = store.getCertificateChain(alias);
|
||||||
|
if (certChain != null) {
|
||||||
|
int x509Cnt = 0;
|
||||||
|
|
||||||
|
/* Count X509Certificate entries */
|
||||||
|
for (int i = 0; i < certChain.length; i++) {
|
||||||
|
if (certChain[i] instanceof X509Certificate) {
|
||||||
|
x509Cnt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Store X509Certificate chain */
|
||||||
|
if (x509Cnt > 0) {
|
||||||
|
int idx = 0;
|
||||||
|
X509Certificate[] x509Chain =
|
||||||
|
new X509Certificate[x509Cnt];
|
||||||
|
|
||||||
|
for (int i = 0; i < certChain.length; i++) {
|
||||||
|
if (certChain[i] instanceof X509Certificate) {
|
||||||
|
x509Chain[idx++] = (X509Certificate)certChain[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
certificateChainCache.put(alias, x509Chain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cache private key */
|
||||||
|
PrivateKey key = (PrivateKey)store.getKey(alias, password);
|
||||||
|
if (key != null) {
|
||||||
|
privateKeyCache.put(alias, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.ERROR,
|
||||||
|
() -> "Error caching entry for alias: " + alias + ", " + e);
|
||||||
|
/* Continue processing other aliases */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
|
() -> "Cached " + aliasSet.size() + " aliases from KeyStore");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return array of aliases from KeyStore that matches provided
|
||||||
|
* type and issuers array (non-cached version).
|
||||||
*
|
*
|
||||||
* Returns:
|
* Returns:
|
||||||
* null - if current KeyStore is null, error getting aliases from store,
|
* null - if no alias matches found in KeyStore.
|
||||||
* or no alias mathes found in current KeyStore.
|
|
||||||
* String[] - aliases, if found that match type and/or issuers
|
* String[] - aliases, if found that match type and/or issuers
|
||||||
*/
|
*/
|
||||||
private String[] getAliases(String type, Principal[] issuers) {
|
private String[] getAliasesFromKeyStore(String type, Principal[] issuers)
|
||||||
Enumeration<String> aliases = null;
|
throws KeyStoreException {
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
ArrayList<String> ret = new ArrayList<String>();
|
ArrayList<String> ret = new ArrayList<String>();
|
||||||
|
|
||||||
if (store == null) {
|
if (keyStore == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
Enumeration<String> aliases = keyStore.aliases();
|
||||||
aliases = this.store.aliases();
|
|
||||||
} catch (KeyStoreException ex) {
|
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.ERROR,
|
|
||||||
() -> "Error getting aliases from current KeyStore");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* loop through each alias in KeyStore */
|
/* loop through each KeyStore alias */
|
||||||
while (aliases.hasMoreElements()) {
|
while (aliases.hasMoreElements()) {
|
||||||
String current = aliases.nextElement();
|
String current = aliases.nextElement();
|
||||||
X509Certificate cert = null;
|
Certificate cert = keyStore.getCertificate(current);
|
||||||
try {
|
|
||||||
cert = (X509Certificate)this.store.getCertificate(current);
|
if (!(cert instanceof X509Certificate)) {
|
||||||
} catch (KeyStoreException ex) {
|
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.ERROR,
|
|
||||||
() -> "Error getting certificate from KeyStore " +
|
|
||||||
"for alias: " + current + ", continuing to next alias");
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
X509Certificate x509cert = (X509Certificate)cert;
|
||||||
|
|
||||||
|
if (type != null &&
|
||||||
|
!x509cert.getPublicKey().getAlgorithm().equals(type)) {
|
||||||
|
/* different public key type, skip */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if issuers is null then it does not matter which issuer */
|
||||||
|
if (issuers == null) {
|
||||||
|
ret.add(current);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* search through issuers for matching issuer name */
|
||||||
|
for (i = 0; i < issuers.length; i++) {
|
||||||
|
String certIssuer = x509cert.getIssuerDN().getName();
|
||||||
|
String issuerName = issuers[i].getName();
|
||||||
|
|
||||||
|
/* normalize spaces after commas, needed on some JDKs */
|
||||||
|
certIssuer = certIssuer.replaceAll(", ", ",");
|
||||||
|
issuerName = issuerName.replaceAll(", ", ",");
|
||||||
|
|
||||||
|
if (certIssuer.equals(issuerName)) {
|
||||||
|
/* matched issuer, add alias and continue on */
|
||||||
|
ret.add(current);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret.size() == 0) {
|
||||||
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
|
() -> "No aliases found in KeyStore that match type " +
|
||||||
|
"and/or issuer");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret.toArray(new String[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return array of aliases that matches provided type and issuers array.
|
||||||
|
* Uses either cached entries or direct KeyStore access based on Security
|
||||||
|
* property configuration.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* null - if no alias matches found.
|
||||||
|
* String[] - aliases, if found that match type and/or issuers
|
||||||
|
*/
|
||||||
|
private String[] getAliases(String type, Principal[] issuers) {
|
||||||
|
|
||||||
|
/* Check if caching is disabled, use direct KeyStore access */
|
||||||
|
if (this.cacheDisabled) {
|
||||||
|
try {
|
||||||
|
return getAliasesFromKeyStore(type, issuers);
|
||||||
|
} catch (KeyStoreException e) {
|
||||||
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.ERROR,
|
||||||
|
() -> "Error accessing KeyStore directly: " +
|
||||||
|
e.getMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use cached entries */
|
||||||
|
int i;
|
||||||
|
ArrayList<String> ret = new ArrayList<String>();
|
||||||
|
|
||||||
|
/* loop through each cached alias */
|
||||||
|
for (String current : aliasSet) {
|
||||||
|
X509Certificate cert = certificateCache.get(current);
|
||||||
|
|
||||||
if (type != null && cert != null &&
|
if (type != null && cert != null &&
|
||||||
!cert.getPublicKey().getAlgorithm().equals(type)) {
|
!cert.getPublicKey().getAlgorithm().equals(type)) {
|
||||||
|
|
||||||
/* free native memory early if X509Certificate is WolfSSLX509 */
|
|
||||||
if (cert instanceof WolfSSLX509) {
|
|
||||||
((WolfSSLX509)cert).free();
|
|
||||||
}
|
|
||||||
cert = null;
|
|
||||||
|
|
||||||
/* different public key type, skip */
|
/* different public key type, skip */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -135,11 +327,11 @@ public class WolfSSLKeyX509 extends X509ExtendedKeyManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} /* end while */
|
}
|
||||||
|
|
||||||
if (ret.size() == 0) {
|
if (ret.size() == 0) {
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
() -> "No aliases found in KeyStore that match type " +
|
() -> "No aliases found in cache that match type " +
|
||||||
"and/or issuer");
|
"and/or issuer");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -244,59 +436,140 @@ public class WolfSSLKeyX509 extends X509ExtendedKeyManager {
|
||||||
@Override
|
@Override
|
||||||
public X509Certificate[] getCertificateChain(String alias) {
|
public X509Certificate[] getCertificateChain(String alias) {
|
||||||
|
|
||||||
X509Certificate[] ret = null;
|
|
||||||
|
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
() -> "entered getCertificateChain(), alias: " + alias);
|
() -> "entered getCertificateChain(), alias: " + alias);
|
||||||
|
|
||||||
if (store == null || alias == null) {
|
if (alias == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check if caching is disabled, use direct KeyStore access */
|
||||||
|
if (this.cacheDisabled) {
|
||||||
try {
|
try {
|
||||||
Certificate[] certs = this.store.getCertificateChain(alias);
|
if (keyStore == null) {
|
||||||
if (certs != null) {
|
return null;
|
||||||
int x509Cnt = 0;
|
}
|
||||||
|
|
||||||
/* count up X509Certificate type in certs[] */
|
Certificate[] certChain = keyStore.getCertificateChain(alias);
|
||||||
for (int i = 0; i < certs.length; i++) {
|
if (certChain == null) {
|
||||||
if (certs[i] instanceof X509Certificate) {
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert to X509Certificate array */
|
||||||
|
int x509Cnt = 0;
|
||||||
|
for (int i = 0; i < certChain.length; i++) {
|
||||||
|
if (certChain[i] instanceof X509Certificate) {
|
||||||
x509Cnt++;
|
x509Cnt++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* store into X509Certificate array */
|
if (x509Cnt == 0) {
|
||||||
ret = new X509Certificate[x509Cnt];
|
|
||||||
for (int i = 0; i < certs.length; i++) {
|
|
||||||
if (certs[i] instanceof X509Certificate) {
|
|
||||||
ret[i] = (X509Certificate)certs[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (KeyStoreException ex) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
X509Certificate[] x509Chain = new X509Certificate[x509Cnt];
|
||||||
|
int idx = 0;
|
||||||
|
for (int i = 0; i < certChain.length; i++) {
|
||||||
|
if (certChain[i] instanceof X509Certificate) {
|
||||||
|
x509Chain[idx++] = (X509Certificate)certChain[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return x509Chain;
|
||||||
|
|
||||||
|
} catch (KeyStoreException e) {
|
||||||
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.ERROR,
|
||||||
|
() -> "Error accessing certificate chain from KeyStore: " +
|
||||||
|
e.getMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return cached certificate chain */
|
||||||
|
return certificateChainCache.get(alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PrivateKey getPrivateKey(String alias) {
|
public PrivateKey getPrivateKey(String alias) {
|
||||||
|
|
||||||
PrivateKey key = null;
|
|
||||||
|
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
() -> "entered getPrivateKey(), alias: " + alias);
|
() -> "entered getPrivateKey(), alias: " + alias);
|
||||||
|
|
||||||
try {
|
if (alias == null) {
|
||||||
key = (PrivateKey)store.getKey(alias, password);
|
return null;
|
||||||
} catch (Exception e) {
|
}
|
||||||
/* @TODO unable to get key */
|
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
/* Check if caching is disabled, use direct KeyStore access */
|
||||||
() -> "failed to load private key: " + e);
|
if (this.cacheDisabled) {
|
||||||
|
try {
|
||||||
|
if (keyStore == null || keyStorePassword == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (PrivateKey)keyStore.getKey(alias, keyStorePassword);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.ERROR,
|
||||||
|
() -> "Error accessing private key from KeyStore: " +
|
||||||
|
e.getMessage());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return cached private key */
|
||||||
|
return privateKeyCache.get(alias);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear sensitive data when object is garbage collected
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void finalize() throws Throwable {
|
||||||
|
try {
|
||||||
|
/* Clear KeyStore password if present */
|
||||||
|
if (keyStorePassword != null) {
|
||||||
|
Arrays.fill(keyStorePassword, (char)0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear cached private keys */
|
||||||
|
if (privateKeyCache != null) {
|
||||||
|
privateKeyCache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free WolfSSLX509 certificates if present */
|
||||||
|
if (certificateCache != null) {
|
||||||
|
for (X509Certificate cert : certificateCache.values()) {
|
||||||
|
if (cert instanceof WolfSSLX509) {
|
||||||
|
((WolfSSLX509)cert).free();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
certificateCache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free WolfSSLX509 certificate chains if present */
|
||||||
|
if (certificateChainCache != null) {
|
||||||
|
for (X509Certificate[] chain : certificateChainCache.values()) {
|
||||||
|
if (chain != null) {
|
||||||
|
for (X509Certificate cert : chain) {
|
||||||
|
if (cert instanceof WolfSSLX509) {
|
||||||
|
((WolfSSLX509)cert).free();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
certificateChainCache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aliasSet != null) {
|
||||||
|
aliasSet.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
|
() -> "WolfSSLKeyX509 finalized, sensitive data cleared");
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
super.finalize();
|
||||||
}
|
}
|
||||||
return key;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.security.KeyStore;
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
import java.security.Provider;
|
import java.security.Provider;
|
||||||
import java.security.Security;
|
import java.security.Security;
|
||||||
|
@ -459,6 +460,657 @@ public class WolfSSLKeyX509Test {
|
||||||
pass("\t... passed");
|
pass("\t... passed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConstructorWithInvalidKeyStore()
|
||||||
|
throws NoSuchAlgorithmException, KeyStoreException,
|
||||||
|
KeyManagementException, CertificateException, IOException,
|
||||||
|
NoSuchProviderException, UnrecoverableKeyException {
|
||||||
|
|
||||||
|
System.out.print("\tTesting with invalid KeyStore");
|
||||||
|
|
||||||
|
/* Test with null KeyStore - should not throw exception */
|
||||||
|
try {
|
||||||
|
com.wolfssl.provider.jsse.WolfSSLKeyX509 km =
|
||||||
|
new com.wolfssl.provider.jsse.WolfSSLKeyX509(null, null);
|
||||||
|
/* Should succeed with empty cache */
|
||||||
|
} catch (Exception e) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("Constructor should handle null KeyStore gracefully: " + e);
|
||||||
|
}
|
||||||
|
|
||||||
|
pass("\t... passed");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCacheConsistencyWithKeyStore()
|
||||||
|
throws NoSuchAlgorithmException, KeyStoreException,
|
||||||
|
KeyManagementException, CertificateException, IOException,
|
||||||
|
NoSuchProviderException, UnrecoverableKeyException {
|
||||||
|
|
||||||
|
KeyManager[] list;
|
||||||
|
X509KeyManager km;
|
||||||
|
String[] aliases;
|
||||||
|
|
||||||
|
System.out.print("\tTesting cache consistency");
|
||||||
|
|
||||||
|
/* Create KeyManager with cached WolfSSLKeyX509 */
|
||||||
|
list = tf.createKeyManager("SunX509", tf.allJKS, provider);
|
||||||
|
km = (X509KeyManager) list[0];
|
||||||
|
|
||||||
|
/* Test that cached aliases match what we expect */
|
||||||
|
aliases = km.getClientAliases("RSA", null);
|
||||||
|
if (aliases == null || aliases.length == 0) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("No RSA client aliases found in cache");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test certificate chain consistency */
|
||||||
|
for (String alias : aliases) {
|
||||||
|
if (alias != null) {
|
||||||
|
X509Certificate[] chain = km.getCertificateChain(alias);
|
||||||
|
if (chain == null) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("Certificate chain missing from cache for alias: " + alias);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test private key consistency */
|
||||||
|
for (String alias : aliases) {
|
||||||
|
if (alias != null) {
|
||||||
|
/* Private key may be null for some aliases, that's expected */
|
||||||
|
km.getPrivateKey(alias);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pass("\t... passed");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEmptyKeyStoreCache()
|
||||||
|
throws NoSuchAlgorithmException, KeyStoreException,
|
||||||
|
KeyManagementException, CertificateException, IOException,
|
||||||
|
NoSuchProviderException, UnrecoverableKeyException {
|
||||||
|
|
||||||
|
System.out.print("\tTesting empty KeyStore cache");
|
||||||
|
|
||||||
|
try {
|
||||||
|
/* Create empty KeyStore */
|
||||||
|
KeyStore emptyStore = KeyStore.getInstance("JKS");
|
||||||
|
emptyStore.load(null, null);
|
||||||
|
|
||||||
|
/* Create WolfSSLKeyX509 with empty KeyStore */
|
||||||
|
com.wolfssl.provider.jsse.WolfSSLKeyX509 km =
|
||||||
|
new com.wolfssl.provider.jsse.WolfSSLKeyX509(emptyStore, null);
|
||||||
|
|
||||||
|
/* Test methods with empty cache */
|
||||||
|
String[] aliases = km.getClientAliases("RSA", null);
|
||||||
|
if (aliases != null) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("Expected null aliases from empty KeyStore");
|
||||||
|
}
|
||||||
|
|
||||||
|
aliases = km.getServerAliases("RSA", null);
|
||||||
|
if (aliases != null) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("Expected null server aliases from empty KeyStore");
|
||||||
|
}
|
||||||
|
|
||||||
|
String alias = km.chooseClientAlias(new String[] {"RSA"}, null, null);
|
||||||
|
if (alias != null) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("Expected null client alias from empty KeyStore");
|
||||||
|
}
|
||||||
|
|
||||||
|
alias = km.chooseServerAlias("RSA", null, null);
|
||||||
|
if (alias != null) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("Expected null server alias from empty KeyStore");
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("Empty KeyStore test failed: " + e);
|
||||||
|
}
|
||||||
|
|
||||||
|
pass("\t... passed");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNullKeyStoreCache()
|
||||||
|
throws NoSuchAlgorithmException, KeyStoreException,
|
||||||
|
KeyManagementException, CertificateException, IOException,
|
||||||
|
NoSuchProviderException, UnrecoverableKeyException {
|
||||||
|
|
||||||
|
System.out.print("\tTesting null KeyStore cache");
|
||||||
|
|
||||||
|
try {
|
||||||
|
/* Create WolfSSLKeyX509 with null KeyStore */
|
||||||
|
com.wolfssl.provider.jsse.WolfSSLKeyX509 km =
|
||||||
|
new com.wolfssl.provider.jsse.WolfSSLKeyX509(null, null);
|
||||||
|
|
||||||
|
/* Test methods with null KeyStore */
|
||||||
|
String[] aliases = km.getClientAliases("RSA", null);
|
||||||
|
if (aliases != null) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("Expected null aliases from null KeyStore");
|
||||||
|
}
|
||||||
|
|
||||||
|
aliases = km.getServerAliases("RSA", null);
|
||||||
|
if (aliases != null) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("Expected null server aliases from null KeyStore");
|
||||||
|
}
|
||||||
|
|
||||||
|
String alias = km.chooseClientAlias(new String[] {"RSA"}, null, null);
|
||||||
|
if (alias != null) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("Expected null client alias from null KeyStore");
|
||||||
|
}
|
||||||
|
|
||||||
|
alias = km.chooseServerAlias("RSA", null, null);
|
||||||
|
if (alias != null) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("Expected null server alias from null KeyStore");
|
||||||
|
}
|
||||||
|
|
||||||
|
X509Certificate[] chain = km.getCertificateChain("nonexistent");
|
||||||
|
if (chain != null) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("Expected null certificate chain from null KeyStore");
|
||||||
|
}
|
||||||
|
|
||||||
|
java.security.PrivateKey key = km.getPrivateKey("nonexistent");
|
||||||
|
if (key != null) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("Expected null private key from null KeyStore");
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("Null KeyStore test failed: " + e);
|
||||||
|
}
|
||||||
|
|
||||||
|
pass("\t... passed");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCertificateChainCaching()
|
||||||
|
throws NoSuchAlgorithmException, KeyStoreException,
|
||||||
|
KeyManagementException, CertificateException, IOException,
|
||||||
|
NoSuchProviderException, UnrecoverableKeyException {
|
||||||
|
|
||||||
|
KeyManager[] list;
|
||||||
|
X509KeyManager km;
|
||||||
|
X509Certificate[] chain1, chain2;
|
||||||
|
|
||||||
|
System.out.print("\tTesting cert chain caching");
|
||||||
|
|
||||||
|
list = tf.createKeyManager("SunX509", tf.allJKS, provider);
|
||||||
|
km = (X509KeyManager) list[0];
|
||||||
|
|
||||||
|
/* Get certificate chain twice to test caching */
|
||||||
|
chain1 = km.getCertificateChain("client");
|
||||||
|
chain2 = km.getCertificateChain("client");
|
||||||
|
|
||||||
|
if (chain1 == null) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("Certificate chain should not be null for 'client' alias");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chain2 == null) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("Second certificate chain retrieval should not be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test that both retrievals return the same cached object */
|
||||||
|
if (chain1 != chain2) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("Certificate chain caching failed - different objects returned");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test with non-existent alias */
|
||||||
|
X509Certificate[] nullChain = km.getCertificateChain("nonexistent");
|
||||||
|
if (nullChain != null) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("Expected null certificate chain for non-existent alias");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test with null alias */
|
||||||
|
nullChain = km.getCertificateChain(null);
|
||||||
|
if (nullChain != null) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("Expected null certificate chain for null alias");
|
||||||
|
}
|
||||||
|
|
||||||
|
pass("\t... passed");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPrivateKeyCaching()
|
||||||
|
throws NoSuchAlgorithmException, KeyStoreException,
|
||||||
|
KeyManagementException, CertificateException, IOException,
|
||||||
|
NoSuchProviderException, UnrecoverableKeyException {
|
||||||
|
|
||||||
|
KeyManager[] list;
|
||||||
|
X509KeyManager km;
|
||||||
|
java.security.PrivateKey key1, key2;
|
||||||
|
|
||||||
|
System.out.print("\tTesting private key caching");
|
||||||
|
|
||||||
|
list = tf.createKeyManager("SunX509", tf.allJKS, provider);
|
||||||
|
km = (X509KeyManager) list[0];
|
||||||
|
|
||||||
|
/* Get private key twice to test caching */
|
||||||
|
key1 = km.getPrivateKey("client");
|
||||||
|
key2 = km.getPrivateKey("client");
|
||||||
|
|
||||||
|
if (key1 == null) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("Private key should not be null for 'client' alias");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key2 == null) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("Second private key retrieval should not be null");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test that both retrievals return the same cached object */
|
||||||
|
if (key1 != key2) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("Private key caching failed - different objects returned");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test with non-existent alias */
|
||||||
|
java.security.PrivateKey nullKey = km.getPrivateKey("nonexistent");
|
||||||
|
if (nullKey != null) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("Expected null private key for non-existent alias");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test with null alias */
|
||||||
|
nullKey = km.getPrivateKey(null);
|
||||||
|
if (nullKey != null) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("Expected null private key for null alias");
|
||||||
|
}
|
||||||
|
|
||||||
|
pass("\t... passed");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCacheDisabledSecurityProperty()
|
||||||
|
throws NoSuchAlgorithmException, KeyStoreException,
|
||||||
|
KeyManagementException, CertificateException, IOException,
|
||||||
|
NoSuchProviderException, UnrecoverableKeyException {
|
||||||
|
|
||||||
|
System.out.print("\tTesting cache disabled");
|
||||||
|
|
||||||
|
/* Save original property value */
|
||||||
|
String originalValue =
|
||||||
|
Security.getProperty("wolfjsse.X509KeyManager.disableCache");
|
||||||
|
|
||||||
|
try {
|
||||||
|
/* Test with caching disabled */
|
||||||
|
Security.setProperty(
|
||||||
|
"wolfjsse.X509KeyManager.disableCache", "true");
|
||||||
|
|
||||||
|
/* Create KeyManager with caching disabled */
|
||||||
|
KeyStore ks = KeyStore.getInstance("JKS");
|
||||||
|
java.io.FileInputStream fis =
|
||||||
|
new java.io.FileInputStream(tf.allJKS);
|
||||||
|
ks.load(fis, "wolfSSL test".toCharArray());
|
||||||
|
fis.close();
|
||||||
|
|
||||||
|
com.wolfssl.provider.jsse.WolfSSLKeyX509 km =
|
||||||
|
new com.wolfssl.provider.jsse.WolfSSLKeyX509(
|
||||||
|
ks, "wolfSSL test".toCharArray());
|
||||||
|
|
||||||
|
/* Test that operations work with caching disabled */
|
||||||
|
String[] aliases = km.getClientAliases("RSA", null);
|
||||||
|
if (aliases == null || aliases.length == 0) {
|
||||||
|
error("\t\t... failed");
|
||||||
|
fail("No RSA client aliases found with caching disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test certificate chain retrieval */
|
||||||
|
X509Certificate[] chain = km.getCertificateChain("client");
|
||||||
|
if (chain == null) {
|
||||||
|
error("\t\t... failed");
|
||||||
|
fail("Certificate chain should not be null with " +
|
||||||
|
"caching disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test private key retrieval */
|
||||||
|
java.security.PrivateKey key = km.getPrivateKey("client");
|
||||||
|
if (key == null) {
|
||||||
|
error("\t\t... failed");
|
||||||
|
fail("Private key should not be null with caching disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test alias selection */
|
||||||
|
String selectedAlias =
|
||||||
|
km.chooseClientAlias(new String[] {"RSA"}, null, null);
|
||||||
|
if (selectedAlias == null) {
|
||||||
|
error("\t\t... failed");
|
||||||
|
fail("Should be able to choose client alias with " +
|
||||||
|
"caching disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
/* Restore original property value */
|
||||||
|
if (originalValue != null) {
|
||||||
|
Security.setProperty(
|
||||||
|
"wolfjsse.X509KeyManager.disableCache", originalValue);
|
||||||
|
} else {
|
||||||
|
/* Remove property if it wasn't set originally */
|
||||||
|
Security.setProperty(
|
||||||
|
"wolfjsse.X509KeyManager.disableCache", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pass("\t\t... passed");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCacheEnabledSecurityProperty()
|
||||||
|
throws NoSuchAlgorithmException, KeyStoreException,
|
||||||
|
KeyManagementException, CertificateException, IOException,
|
||||||
|
NoSuchProviderException, UnrecoverableKeyException {
|
||||||
|
|
||||||
|
System.out.print("\tTesting cache enabled");
|
||||||
|
|
||||||
|
/* Save original property value */
|
||||||
|
String originalValue =
|
||||||
|
Security.getProperty("wolfjsse.X509KeyManager.disableCache");
|
||||||
|
|
||||||
|
try {
|
||||||
|
/* Test with caching explicitly enabled */
|
||||||
|
Security.setProperty(
|
||||||
|
"wolfjsse.X509KeyManager.disableCache", "false");
|
||||||
|
|
||||||
|
/* Create KeyManager with caching enabled */
|
||||||
|
KeyStore ks = KeyStore.getInstance("JKS");
|
||||||
|
java.io.FileInputStream fis =
|
||||||
|
new java.io.FileInputStream(tf.allJKS);
|
||||||
|
ks.load(fis, "wolfSSL test".toCharArray());
|
||||||
|
fis.close();
|
||||||
|
|
||||||
|
com.wolfssl.provider.jsse.WolfSSLKeyX509 km =
|
||||||
|
new com.wolfssl.provider.jsse.WolfSSLKeyX509(
|
||||||
|
ks, "wolfSSL test".toCharArray());
|
||||||
|
|
||||||
|
/* Test that operations work with caching enabled */
|
||||||
|
String[] aliases = km.getClientAliases("RSA", null);
|
||||||
|
if (aliases == null || aliases.length == 0) {
|
||||||
|
error("\t\t... failed");
|
||||||
|
fail("No RSA client aliases found with caching enabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test certificate chain retrieval and caching */
|
||||||
|
X509Certificate[] chain1 = km.getCertificateChain("client");
|
||||||
|
X509Certificate[] chain2 = km.getCertificateChain("client");
|
||||||
|
if (chain1 == null || chain2 == null) {
|
||||||
|
error("\t\t... failed");
|
||||||
|
fail("Certificate chains should not be null " +
|
||||||
|
"with caching enabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* With caching enabled, should return same cached object */
|
||||||
|
if (chain1 != chain2) {
|
||||||
|
error("\t\t... failed");
|
||||||
|
fail("Certificate chain caching failed - different " +
|
||||||
|
"objects returned");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test private key retrieval and caching */
|
||||||
|
java.security.PrivateKey key1 = km.getPrivateKey("client");
|
||||||
|
java.security.PrivateKey key2 = km.getPrivateKey("client");
|
||||||
|
if (key1 == null || key2 == null) {
|
||||||
|
error("\t\t... failed");
|
||||||
|
fail("Private keys should not be null with caching enabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* With caching enabled, should return same cached object */
|
||||||
|
if (key1 != key2) {
|
||||||
|
error("\t\t... failed");
|
||||||
|
fail("Private key caching failed - different objects returned");
|
||||||
|
}
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
/* Restore original property value */
|
||||||
|
if (originalValue != null) {
|
||||||
|
Security.setProperty(
|
||||||
|
"wolfjsse.X509KeyManager.disableCache", originalValue);
|
||||||
|
} else {
|
||||||
|
/* Remove property if it wasn't set originally */
|
||||||
|
Security.setProperty(
|
||||||
|
"wolfjsse.X509KeyManager.disableCache", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pass("\t\t... passed");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDefaultCachingBehavior()
|
||||||
|
throws NoSuchAlgorithmException, KeyStoreException,
|
||||||
|
KeyManagementException, CertificateException, IOException,
|
||||||
|
NoSuchProviderException, UnrecoverableKeyException {
|
||||||
|
|
||||||
|
System.out.print("\tTesting default cache behavior");
|
||||||
|
|
||||||
|
/* Save original property value */
|
||||||
|
String originalValue = Security.getProperty(
|
||||||
|
"wolfjsse.X509KeyManager.disableCache");
|
||||||
|
|
||||||
|
try {
|
||||||
|
/* Clear property to test default behavior */
|
||||||
|
Security.setProperty("wolfjsse.X509KeyManager.disableCache", "");
|
||||||
|
|
||||||
|
/* Create KeyManager with default behavior
|
||||||
|
* (should be caching enabled) */
|
||||||
|
KeyStore ks = KeyStore.getInstance("JKS");
|
||||||
|
java.io.FileInputStream fis =
|
||||||
|
new java.io.FileInputStream(tf.allJKS);
|
||||||
|
ks.load(fis, "wolfSSL test".toCharArray());
|
||||||
|
fis.close();
|
||||||
|
|
||||||
|
com.wolfssl.provider.jsse.WolfSSLKeyX509 km =
|
||||||
|
new com.wolfssl.provider.jsse.WolfSSLKeyX509(
|
||||||
|
ks, "wolfSSL test".toCharArray());
|
||||||
|
|
||||||
|
/* Test that operations work with default behavior */
|
||||||
|
String[] aliases = km.getClientAliases("RSA", null);
|
||||||
|
if (aliases == null || aliases.length == 0) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("No RSA client aliases found with default behavior");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test that caching works by default (same objects returned) */
|
||||||
|
X509Certificate[] chain1 = km.getCertificateChain("client");
|
||||||
|
X509Certificate[] chain2 = km.getCertificateChain("client");
|
||||||
|
if (chain1 == null || chain2 == null) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("Certificate chains should not be null " +
|
||||||
|
"with default behavior");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Default behavior should be caching enabled */
|
||||||
|
if (chain1 != chain2) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("Default behavior should enable caching - " +
|
||||||
|
"different objects returned");
|
||||||
|
}
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
/* Restore original property value */
|
||||||
|
if (originalValue != null) {
|
||||||
|
Security.setProperty(
|
||||||
|
"wolfjsse.X509KeyManager.disableCache", originalValue);
|
||||||
|
} else {
|
||||||
|
/* Remove property if it wasn't set originally */
|
||||||
|
Security.setProperty(
|
||||||
|
"wolfjsse.X509KeyManager.disableCache", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pass("\t... passed");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCaseInsensitiveSecurityProperty()
|
||||||
|
throws NoSuchAlgorithmException, KeyStoreException,
|
||||||
|
KeyManagementException, CertificateException, IOException,
|
||||||
|
NoSuchProviderException, UnrecoverableKeyException {
|
||||||
|
|
||||||
|
System.out.print("\tCase insensitive cache disable");
|
||||||
|
|
||||||
|
/* Save original property value */
|
||||||
|
String originalValue = Security.getProperty(
|
||||||
|
"wolfjsse.X509KeyManager.disableCache");
|
||||||
|
|
||||||
|
try {
|
||||||
|
/* Test different case variations of "true" */
|
||||||
|
String[] trueVariations = {"true", "TRUE", "True", "tRuE"};
|
||||||
|
|
||||||
|
for (String trueValue : trueVariations) {
|
||||||
|
Security.setProperty(
|
||||||
|
"wolfjsse.X509KeyManager.disableCache", trueValue);
|
||||||
|
|
||||||
|
KeyStore ks = KeyStore.getInstance("JKS");
|
||||||
|
java.io.FileInputStream fis =
|
||||||
|
new java.io.FileInputStream(tf.allJKS);
|
||||||
|
ks.load(fis, "wolfSSL test".toCharArray());
|
||||||
|
fis.close();
|
||||||
|
|
||||||
|
com.wolfssl.provider.jsse.WolfSSLKeyX509 km =
|
||||||
|
new com.wolfssl.provider.jsse.WolfSSLKeyX509(
|
||||||
|
ks, "wolfSSL test".toCharArray());
|
||||||
|
|
||||||
|
/* Should work with any case variation of "true" */
|
||||||
|
String[] aliases = km.getClientAliases("RSA", null);
|
||||||
|
if (aliases == null || aliases.length == 0) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("No RSA client aliases found with '" +
|
||||||
|
trueValue + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Test values that should NOT disable caching */
|
||||||
|
String[] falseVariations = {"false", "FALSE", "False", "0",
|
||||||
|
"no", "disabled", "random"};
|
||||||
|
|
||||||
|
for (String falseValue : falseVariations) {
|
||||||
|
Security.setProperty(
|
||||||
|
"wolfjsse.X509KeyManager.disableCache", falseValue);
|
||||||
|
|
||||||
|
KeyStore ks = KeyStore.getInstance("JKS");
|
||||||
|
java.io.FileInputStream fis =
|
||||||
|
new java.io.FileInputStream(tf.allJKS);
|
||||||
|
ks.load(fis, "wolfSSL test".toCharArray());
|
||||||
|
fis.close();
|
||||||
|
|
||||||
|
com.wolfssl.provider.jsse.WolfSSLKeyX509 km =
|
||||||
|
new com.wolfssl.provider.jsse.WolfSSLKeyX509(
|
||||||
|
ks, "wolfSSL test".toCharArray());
|
||||||
|
|
||||||
|
/* Should have caching enabled (same objects returned) */
|
||||||
|
X509Certificate[] chain1 = km.getCertificateChain("client");
|
||||||
|
X509Certificate[] chain2 = km.getCertificateChain("client");
|
||||||
|
if (chain1 == null || chain2 == null) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("Certificate chains should not be null with '" +
|
||||||
|
falseValue + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chain1 != chain2) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("Caching should be enabled with '" +
|
||||||
|
falseValue + "' - different objects returned");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
/* Restore original property value */
|
||||||
|
if (originalValue != null) {
|
||||||
|
Security.setProperty(
|
||||||
|
"wolfjsse.X509KeyManager.disableCache", originalValue);
|
||||||
|
} else {
|
||||||
|
/* Remove property if it wasn't set originally */
|
||||||
|
Security.setProperty(
|
||||||
|
"wolfjsse.X509KeyManager.disableCache", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pass("\t... passed");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNullKeyStoreWithCachingDisabled()
|
||||||
|
throws NoSuchAlgorithmException, KeyStoreException,
|
||||||
|
KeyManagementException, CertificateException, IOException,
|
||||||
|
NoSuchProviderException, UnrecoverableKeyException {
|
||||||
|
|
||||||
|
System.out.print("\tnull KeyStore with no caching");
|
||||||
|
|
||||||
|
/* Save original property value */
|
||||||
|
String originalValue = Security.getProperty(
|
||||||
|
"wolfjsse.X509KeyManager.disableCache");
|
||||||
|
|
||||||
|
try {
|
||||||
|
/* Test with caching disabled and null KeyStore */
|
||||||
|
Security.setProperty(
|
||||||
|
"wolfjsse.X509KeyManager.disableCache", "true");
|
||||||
|
|
||||||
|
com.wolfssl.provider.jsse.WolfSSLKeyX509 km =
|
||||||
|
new com.wolfssl.provider.jsse.WolfSSLKeyX509(null, null);
|
||||||
|
|
||||||
|
/* Test that all operations return null gracefully */
|
||||||
|
String[] aliases = km.getClientAliases("RSA", null);
|
||||||
|
if (aliases != null) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("Expected null aliases with null KeyStore and " +
|
||||||
|
"caching disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
X509Certificate[] chain = km.getCertificateChain("client");
|
||||||
|
if (chain != null) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("Expected null certificate chain with null " +
|
||||||
|
"KeyStore and caching disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
java.security.PrivateKey key = km.getPrivateKey("client");
|
||||||
|
if (key != null) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("Expected null private key with null KeyStore " +
|
||||||
|
"and caching disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
String alias = km.chooseClientAlias(new String[] {"RSA"},
|
||||||
|
null, null);
|
||||||
|
if (alias != null) {
|
||||||
|
error("\t... failed");
|
||||||
|
fail("Expected null alias with null KeyStore and " +
|
||||||
|
"caching disabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
/* Restore original property value */
|
||||||
|
if (originalValue != null) {
|
||||||
|
Security.setProperty(
|
||||||
|
"wolfjsse.X509KeyManager.disableCache", originalValue);
|
||||||
|
} else {
|
||||||
|
/* Remove property if it wasn't set originally */
|
||||||
|
Security.setProperty(
|
||||||
|
"wolfjsse.X509KeyManager.disableCache", "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pass("\t... passed");
|
||||||
|
}
|
||||||
|
|
||||||
private void pass(String msg) {
|
private void pass(String msg) {
|
||||||
WolfSSLTestFactory.pass(msg);
|
WolfSSLTestFactory.pass(msg);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue