Skip to content

Commit

Permalink
Update to address concurrent update and caching mismatch
Browse files Browse the repository at this point in the history
  • Loading branch information
haimaychao committed Mar 4, 2024
1 parent 0186157 commit e2eaf8a
Showing 1 changed file with 79 additions and 71 deletions.
150 changes: 79 additions & 71 deletions src/java.base/share/classes/sun/security/ssl/X509KeyManagerImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import java.security.KeyStore.PrivateKeyEntry;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.CertPathValidatorException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
Expand Down Expand Up @@ -80,7 +81,7 @@ final class X509KeyManagerImpl extends X509ExtendedKeyManager

private boolean ksP12;
/*
* The credentials from the KeyStore as
* The credentials from the PKCS12KeyStore as
* Map: String(builderIndex.entryAlias) -> X509Credentials(credentials)
*/
private final Map<String, X509Credentials> credentialsMap;
Expand Down Expand Up @@ -118,18 +119,21 @@ private static class X509Credentials {
break;
}
} catch (Exception e) {
// ignore
if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) {
SSLLogger.fine("KeyMgr: error occurred during " +
"getKeyStore() operation for Keystore builder");
}
}
}

if (foundPKCS12) {
ksP12 = true;
credentialsMap = new ConcurrentHashMap<>();
entryCacheMap = null; // No need for entry cache for PKCS12
entryCacheMap = null;
initializeCredentials();
} else {
ksP12 = false;
credentialsMap = null; // No need for credentials map for non-PKCS12
credentialsMap = null;
entryCacheMap = Collections.synchronizedMap(new SizedMap<>());
}
}
Expand All @@ -153,45 +157,29 @@ private void initializeCredentials() {
if (keyStore == null) {
continue;
}

Enumeration<String> aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
String alias = aliases.nextElement();
if (!keyStore.isKeyEntry(alias)) {
continue;
}
Entry newEntry = keyStore.getEntry(alias,
builder.getProtectionParameter(alias));
if (!(newEntry instanceof PrivateKeyEntry)) {
continue;
}

PrivateKeyEntry privateKeyEntry = (PrivateKeyEntry) newEntry;
PrivateKey privateKey = privateKeyEntry.getPrivateKey();
Certificate[] certs = keyStore.getCertificateChain(alias);
if ((certs == null) || (certs.length == 0) ||
!(certs[0] instanceof X509Certificate)) {
continue;
}
if (!(certs instanceof X509Certificate[])) {
Certificate[] tmp = new X509Certificate[certs.length];
System.arraycopy(certs, 0, tmp, 0, certs.length);
certs = tmp;
}

String builderAlias = i + "." + alias;
X509Credentials cred = new X509Credentials(privateKey,
(X509Certificate[])certs);
credentialsMap.put(builderAlias, cred);

if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) {
SSLLogger.fine("found key for : " +
"keystore builder index = " + i +
" alias = " + alias, (Object[])certs);
boolean mapEntryUpdated = processCredentials(builder,
i, alias);
if (!mapEntryUpdated){
if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) {
SSLLogger.fine("KeyMgr: error occurred during " +
"initializing cached map for PKCS12 " +
"keystore");
}
}

}
} catch (Exception e) {
// ignore
if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) {
SSLLogger.fine("KeyMgr: error occurred during " +
"getKeyStore() operation for Keystore builder");
}
}
}
}
Expand All @@ -209,7 +197,8 @@ public X509Certificate[] getCertificateChain(String alias) {
}

X509Credentials cred = credentialsMap.get(builderAlias);
if (cred == null || !areCertChainsEqual(builderAlias, cred.certificates)) {
if (cred == null || !areCertChainsEqual(builderAlias,
cred.certificates)) {
if (updateCredentialsMap(builderAlias)) {
cred = credentialsMap.get(builderAlias);
return cred.certificates.clone();
Expand All @@ -233,7 +222,8 @@ public PrivateKey getPrivateKey(String alias) {
}

X509Credentials cred = credentialsMap.get(builderAlias);
if (cred == null || !areCertChainsEqual(builderAlias, cred.certificates)) {
if (cred == null || !areCertChainsEqual(builderAlias,
cred.certificates)) {
if (updateCredentialsMap(builderAlias)) {
cred = credentialsMap.get(builderAlias);
return cred.privateKey;
Expand Down Expand Up @@ -325,13 +315,13 @@ private String removeAliasIndex (String alias){
return alias.substring(firstDot + 1);
}

private boolean areCertChainsEqual(String builderAlias, X509Certificate[] cachedCerts) {
private boolean areCertChainsEqual(String builderAlias,
X509Certificate[] cachedCerts) {
int aDot = builderAlias.indexOf('.');
int builderIndex = Integer.parseInt(builderAlias.substring(0, aDot));
String entryAlias = builderAlias.substring(aDot + 1);
try {
int aDot = builderAlias.indexOf('.');
int builderIndex = Integer.parseInt(builderAlias.substring(0, aDot));
String entryAlias = builderAlias.substring(aDot + 1);
Builder builder = builders.get(builderIndex);

KeyStore keyStore = builder.getKeyStore();
if (keyStore == null) {
return false;
Expand All @@ -342,49 +332,32 @@ private boolean areCertChainsEqual(String builderAlias, X509Certificate[] cached
}

// Convert KeyStore certificates to X509Certificates
X509Certificate[] newCerts = new X509Certificate[keyStoreCerts.length];
for (int i = 0; i < keyStoreCerts.length; i++) {
if (!(keyStoreCerts[i] instanceof X509Certificate)) {
return false;
}
newCerts[i] = (X509Certificate) keyStoreCerts[i];
}

if (cachedCerts.length != newCerts.length) {
return false;
}
for (int i = 0; i < cachedCerts.length; i++) {
if (!cachedCerts[i].equals(newCerts[i])) {
return false;
}
}
return true;
X509Certificate[] newCerts = Arrays.copyOf(keyStoreCerts,
keyStoreCerts.length, X509Certificate[].class);
return Arrays.equals(cachedCerts, newCerts);
} catch (Exception e) {
return false;
}
}

// Update the credentialsMap with the up-to-date key and certificates
private synchronized boolean updateCredentialsMap(String builderAlias) {
int aDot = builderAlias.indexOf('.');
int builderIndex = Integer.parseInt(builderAlias.substring(0, aDot));
String entryAlias = builderAlias.substring(aDot + 1);
Builder builder = builders.get(builderIndex);
private boolean processCredentials(Builder builder, int builderIndex,
String alias) throws Exception {
KeyStore keyStore = builder.getKeyStore();
if (keyStore == null) {
return false;
}

try {
KeyStore keyStore = builder.getKeyStore();
if (keyStore == null) {
return false;
}
Entry newEntry = keyStore.getEntry(entryAlias,
builder.getProtectionParameter(entryAlias));
synchronized (keyStore) {
Entry newEntry = keyStore.getEntry(alias,
builder.getProtectionParameter(alias));
if (!(newEntry instanceof PrivateKeyEntry)) {
return false;
}

PrivateKeyEntry privateKeyEntry = (PrivateKeyEntry) newEntry;
PrivateKey privateKey = privateKeyEntry.getPrivateKey();
Certificate[] certs = keyStore.getCertificateChain(entryAlias);
Certificate[] certs = privateKeyEntry.getCertificateChain();

if ((certs == null) || (certs.length == 0) ||
!(certs[0] instanceof X509Certificate)) {
return false;
Expand All @@ -396,10 +369,45 @@ private synchronized boolean updateCredentialsMap(String builderAlias) {
certs = tmp;
}

X509Certificate cert = (X509Certificate) certs[0];
PublicKey publicKey = cert.getPublicKey();
if (!privateKey.getAlgorithm().equals(publicKey.getAlgorithm())) {
return false;
}

// Add to credentials map
String builderAlias = builderIndex + "." + alias;
X509Credentials cred = new X509Credentials(privateKey,
(X509Certificate[]) certs);
credentialsMap.put(builderAlias, cred);

if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) {
SSLLogger.fine("found key for : " +
"keystore builder index = " + builderIndex +
" alias = " + alias, (Object[]) certs);
}

return true;
}
}

// Update the credentialsMap with the up-to-date key and certificates
private boolean updateCredentialsMap(String builderAlias) {
int aDot = builderAlias.indexOf('.');
int builderIndex = Integer.parseInt(builderAlias.substring(0, aDot));
String entryAlias = builderAlias.substring(aDot + 1);
Builder builder = builders.get(builderIndex);

try {
boolean mapEntryUpdated = processCredentials(builder,
builderIndex, entryAlias);
if (!mapEntryUpdated) {
if (SSLLogger.isOn && SSLLogger.isOn("keymanager")) {
SSLLogger.fine("KeyMgr: error occurred during updating " +
"cached map for PKCS12 keystore");
}
}
return mapEntryUpdated;
} catch (Exception e) {
return false;
}
Expand Down

0 comments on commit e2eaf8a

Please sign in to comment.