|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.security.ssl; |
|
|
|
import java.io.*; |
|
import java.lang.ref.WeakReference; |
|
import java.security.*; |
|
import java.security.cert.*; |
|
import java.util.*; |
|
import sun.security.action.*; |
|
import sun.security.validator.TrustStoreUtil; |
|
|
|
|
|
|
|
|
|
*/ |
|
final class TrustStoreManager { |
|
|
|
|
|
private static final TrustAnchorManager tam = new TrustAnchorManager(); |
|
|
|
|
|
private TrustStoreManager() { |
|
// empty |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public static Set<X509Certificate> getTrustedCerts() throws Exception { |
|
return tam.getTrustedCerts(TrustStoreDescriptor.createInstance()); |
|
} |
|
|
|
|
|
|
|
*/ |
|
public static KeyStore getTrustedKeyStore() throws Exception { |
|
return tam.getKeyStore(TrustStoreDescriptor.createInstance()); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static final class TrustStoreDescriptor { |
|
private static final String fileSep = File.separator; |
|
private static final String defaultStorePath = |
|
GetPropertyAction.privilegedGetProperty("java.home") + |
|
fileSep + "lib" + fileSep + "security"; |
|
private static final String defaultStore = |
|
defaultStorePath + fileSep + "cacerts"; |
|
private static final String jsseDefaultStore = |
|
defaultStorePath + fileSep + "jssecacerts"; |
|
|
|
|
|
private final String storeName; |
|
|
|
|
|
private final String storeType; |
|
|
|
|
|
private final String storeProvider; |
|
|
|
|
|
private final String storePassword; |
|
|
|
|
|
private final File storeFile; |
|
|
|
|
|
private final long lastModified; |
|
|
|
private TrustStoreDescriptor(String storeName, String storeType, |
|
String storeProvider, String storePassword, |
|
File storeFile, long lastModified) { |
|
this.storeName = storeName; |
|
this.storeType = storeType; |
|
this.storeProvider = storeProvider; |
|
this.storePassword = storePassword; |
|
this.storeFile = storeFile; |
|
this.lastModified = lastModified; |
|
|
|
if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) { |
|
SSLLogger.fine( |
|
"trustStore is: " + storeName + "\n" + |
|
"trustStore type is: " + storeType + "\n" + |
|
"trustStore provider is: " + storeProvider + "\n" + |
|
"the last modified time is: " + (new Date(lastModified))); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
@SuppressWarnings("Convert2Lambda") |
|
static TrustStoreDescriptor createInstance() { |
|
return AccessController.doPrivileged( |
|
new PrivilegedAction<TrustStoreDescriptor>() { |
|
|
|
@Override |
|
public TrustStoreDescriptor run() { |
|
|
|
String storePropName = System.getProperty( |
|
"javax.net.ssl.trustStore", jsseDefaultStore); |
|
String storePropType = System.getProperty( |
|
"javax.net.ssl.trustStoreType", |
|
KeyStore.getDefaultType()); |
|
String storePropProvider = System.getProperty( |
|
"javax.net.ssl.trustStoreProvider", ""); |
|
String storePropPassword = System.getProperty( |
|
"javax.net.ssl.trustStorePassword", ""); |
|
|
|
String temporaryName = ""; |
|
File temporaryFile = null; |
|
long temporaryTime = 0L; |
|
if (!"NONE".equals(storePropName)) { |
|
String[] fileNames = |
|
new String[] {storePropName, defaultStore}; |
|
for (String fileName : fileNames) { |
|
File f = new File(fileName); |
|
if (f.isFile() && f.canRead()) { |
|
temporaryName = fileName;; |
|
temporaryFile = f; |
|
temporaryTime = f.lastModified(); |
|
|
|
break; |
|
} |
|
|
|
|
|
if (SSLLogger.isOn && |
|
SSLLogger.isOn("trustmanager")) { |
|
SSLLogger.fine( |
|
"Inaccessible trust store: " + |
|
storePropName); |
|
} |
|
} |
|
} else { |
|
temporaryName = storePropName; |
|
} |
|
|
|
return new TrustStoreDescriptor( |
|
temporaryName, storePropType, storePropProvider, |
|
storePropPassword, temporaryFile, temporaryTime); |
|
} |
|
}); |
|
} |
|
|
|
@Override |
|
public boolean equals(Object obj) { |
|
if (obj == this) { |
|
return true; |
|
} |
|
|
|
if (obj instanceof TrustStoreDescriptor) { |
|
TrustStoreDescriptor that = (TrustStoreDescriptor)obj; |
|
return ((this.lastModified == that.lastModified) && |
|
Objects.equals(this.storeName, that.storeName) && |
|
Objects.equals(this.storeType, that.storeType) && |
|
Objects.equals(this.storeProvider, that.storeProvider)); |
|
} |
|
|
|
return false; |
|
} |
|
|
|
|
|
// Please be careful if computing security-sensitive attributes' |
|
|
|
@Override |
|
public int hashCode() { |
|
int result = 17; |
|
|
|
if (storeName != null && !storeName.isEmpty()) { |
|
result = 31 * result + storeName.hashCode(); |
|
} |
|
|
|
if (storeType != null && !storeType.isEmpty()) { |
|
result = 31 * result + storeType.hashCode(); |
|
} |
|
|
|
if (storeProvider != null && !storeProvider.isEmpty()) { |
|
result = 31 * result + storeProvider.hashCode(); |
|
} |
|
|
|
if (storeFile != null) { |
|
result = 31 * result + storeFile.hashCode(); |
|
} |
|
|
|
if (lastModified != 0L) { |
|
result = (int)(31 * result + lastModified); |
|
} |
|
|
|
return result; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static final class TrustAnchorManager { |
|
|
|
private TrustStoreDescriptor descriptor; |
|
|
|
// The key store used for the trust anchors. |
|
// |
|
// Use weak reference so that the heavy loaded KeyStore object can |
|
|
|
private WeakReference<KeyStore> ksRef; |
|
|
|
// The trusted X.509 certificates in the key store. |
|
// |
|
// Use weak reference so that the heavy loaded certificates collection |
|
|
|
private WeakReference<Set<X509Certificate>> csRef; |
|
|
|
private TrustAnchorManager() { |
|
this.descriptor = null; |
|
this.ksRef = new WeakReference<>(null); |
|
this.csRef = new WeakReference<>(null); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
synchronized KeyStore getKeyStore( |
|
TrustStoreDescriptor descriptor) throws Exception { |
|
|
|
TrustStoreDescriptor temporaryDesc = this.descriptor; |
|
KeyStore ks = ksRef.get(); |
|
if ((ks != null) && descriptor.equals(temporaryDesc)) { |
|
return ks; |
|
} |
|
|
|
|
|
if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) { |
|
SSLLogger.fine("Reload the trust store"); |
|
} |
|
|
|
ks = loadKeyStore(descriptor); |
|
this.descriptor = descriptor; |
|
this.ksRef = new WeakReference<>(ks); |
|
|
|
return ks; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
synchronized Set<X509Certificate> getTrustedCerts( |
|
TrustStoreDescriptor descriptor) throws Exception { |
|
|
|
KeyStore ks = null; |
|
TrustStoreDescriptor temporaryDesc = this.descriptor; |
|
Set<X509Certificate> certs = csRef.get(); |
|
if (certs != null) { |
|
if (descriptor.equals(temporaryDesc)) { |
|
return certs; |
|
} else { |
|
|
|
this.descriptor = descriptor; |
|
} |
|
} else { |
|
|
|
if (descriptor.equals(temporaryDesc)) { |
|
ks = ksRef.get(); |
|
} else { |
|
|
|
this.descriptor = descriptor; |
|
} |
|
} |
|
|
|
|
|
if (ks == null) { |
|
if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) { |
|
SSLLogger.fine("Reload the trust store"); |
|
} |
|
ks = loadKeyStore(descriptor); |
|
} |
|
|
|
|
|
if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) { |
|
SSLLogger.fine("Reload trust certs"); |
|
} |
|
|
|
certs = loadTrustedCerts(ks); |
|
if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) { |
|
SSLLogger.fine("Reloaded " + certs.size() + " trust certs"); |
|
} |
|
|
|
// Note that as ks is a local variable, it is not |
|
|
|
this.csRef = new WeakReference<>(certs); |
|
|
|
return certs; |
|
} |
|
|
|
|
|
|
|
*/ |
|
private static KeyStore loadKeyStore( |
|
TrustStoreDescriptor descriptor) throws Exception { |
|
if (!"NONE".equals(descriptor.storeName) && |
|
descriptor.storeFile == null) { |
|
|
|
|
|
if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) { |
|
SSLLogger.fine("No available key store"); |
|
} |
|
|
|
return null; |
|
} |
|
|
|
KeyStore ks; |
|
if (descriptor.storeProvider.isEmpty()) { |
|
ks = KeyStore.getInstance(descriptor.storeType); |
|
} else { |
|
ks = KeyStore.getInstance( |
|
descriptor.storeType, descriptor.storeProvider); |
|
} |
|
|
|
char[] password = null; |
|
if (!descriptor.storePassword.isEmpty()) { |
|
password = descriptor.storePassword.toCharArray(); |
|
} |
|
|
|
if (!"NONE".equals(descriptor.storeName)) { |
|
try (FileInputStream fis = AccessController.doPrivileged( |
|
new OpenFileInputStreamAction(descriptor.storeFile))) { |
|
ks.load(fis, password); |
|
} catch (FileNotFoundException fnfe) { |
|
|
|
if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) { |
|
SSLLogger.fine( |
|
"Not available key store: " + descriptor.storeName); |
|
} |
|
|
|
return null; |
|
} |
|
} else { |
|
ks.load(null, password); |
|
} |
|
|
|
return ks; |
|
} |
|
|
|
|
|
|
|
*/ |
|
private static Set<X509Certificate> loadTrustedCerts(KeyStore ks) { |
|
if (ks == null) { |
|
return Collections.<X509Certificate>emptySet(); |
|
} |
|
|
|
return TrustStoreUtil.getTrustedCerts(ks); |
|
} |
|
} |
|
} |