From c9f62569a4d5087319b87debf88ac5237429c7c8 Mon Sep 17 00:00:00 2001 From: andrew Date: Fri, 26 Apr 2019 15:48:20 +0100 Subject: [PATCH] 8222965: Backport of JDK-8129988 broke the build Summary: Files were missed in the commit of the 8129988 backport Reviewed-by: shade --- .../sun/security/ssl/TrustStoreManager.java | 395 ++++++++++++++++++ .../{KeyStores.java => TrustStoreUtil.java} | 77 +--- 2 files changed, 413 insertions(+), 59 deletions(-) create mode 100644 src/share/classes/sun/security/ssl/TrustStoreManager.java rename src/share/classes/sun/security/validator/{KeyStores.java => TrustStoreUtil.java} (52%) diff --git a/src/share/classes/sun/security/ssl/TrustStoreManager.java b/src/share/classes/sun/security/ssl/TrustStoreManager.java new file mode 100644 index 000000000..3fceccec2 --- /dev/null +++ b/src/share/classes/sun/security/ssl/TrustStoreManager.java @@ -0,0 +1,395 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.ssl; + +import java.lang.ref.WeakReference; +import java.io.*; +import java.util.*; + +import java.security.*; +import java.security.cert.*; +import java.security.cert.Certificate; + +import sun.security.action.*; +import sun.security.validator.TrustStoreUtil; + +/** + * Collection of static utility methods to manage the default trusted KeyStores + * effectively. + */ +final class TrustStoreManager { + private static final Debug debug = Debug.getInstance("ssl"); + + // A singleton service to manage the default trusted KeyStores effectively. + private static final TrustAnchorManager tam = new TrustAnchorManager(); + + // Restrict instantiation of this class. + private TrustStoreManager() { + // empty + } + + /** + * Return an unmodifiable set of all trusted X509Certificates contained + * in the default trusted KeyStore. + */ + public static Set getTrustedCerts() throws Exception { + return tam.getTrustedCerts(TrustStoreDescriptor.createInstance()); + } + + /** + * Return an instance of the default trusted KeyStore. + */ + public static KeyStore getTrustedKeyStore() throws Exception { + return tam.getKeyStore(TrustStoreDescriptor.createInstance()); + } + + /** + * A descriptor of the default trusted KeyStore. + * + * The preference of the default trusted KeyStore is: + * javax.net.ssl.trustStore + * jssecacerts + * cacerts + */ + 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"; + + // the trust store name + private final String storeName; + + // the trust store type, JKS/PKCS12 + private final String storeType; + + // the provider of the trust store + private final String storeProvider; + + // the password used for the trust store + private final String storePassword; + + // the File object of the trust store + private final File storeFile; + + // the last modified time of the store + 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 (debug != null && Debug.isOn("trustmanager")) { + System.out.println( + "trustStore is: " + storeName + "\n" + + "trustStore type is: " + storeType + "\n" + + "trustStore provider is: " + storeProvider + "\n" + + "the last modified time is: " + (new Date(lastModified))); + } + } + + /** + * Create an instance of TrustStoreDescriptor for the default + * trusted KeyStore. + */ + static TrustStoreDescriptor createInstance() { + return AccessController.doPrivileged(new PrivilegedAction() { + + @Override + public TrustStoreDescriptor run() { + // Get the system properties for trust store. + 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; + } + + // Not break, the file is inaccessible. + if (debug != null && + Debug.isOn("trustmanager")) { + System.out.println( + "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' + // hash code. For example the storePassword should not be computed. + @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; + } + } + + /** + * The trust anchors manager used to expedite the performance. + * + * This class can be used to provide singleton services to access default + * trust KeyStore more effectively. + */ + private static final class TrustAnchorManager { + // Last trust store descriptor. + private TrustStoreDescriptor descriptor; + + // The key store used for the trust anchors. + // + // Use weak reference so that the heavy loaded KeyStore object can + // be atomically cleared, and reloaded if needed. + private WeakReference ksRef; + + // The trusted X.509 certificates in the key store. + // + // Use weak reference so that the heavy loaded certificates collection + // objects can be atomically cleared, and reloaded if needed. + private WeakReference> csRef; + + private TrustAnchorManager() { + this.descriptor = null; + this.ksRef = new WeakReference<>(null); + this.csRef = new WeakReference<>(null); + } + + /** + * Get the default trusted KeyStore with the specified descriptor. + * + * @return null if the underlying KeyStore is not available. + */ + synchronized KeyStore getKeyStore( + TrustStoreDescriptor descriptor) throws Exception { + + TrustStoreDescriptor temporaryDesc = this.descriptor; + KeyStore ks = ksRef.get(); + if ((ks != null) && descriptor.equals(temporaryDesc)) { + return ks; + } + + // Reload a new key store. + if ((debug != null) && Debug.isOn("trustmanager")) { + System.out.println("Reload the trust store"); + } + + ks = loadKeyStore(descriptor); + this.descriptor = descriptor; + this.ksRef = new WeakReference<>(ks); + + return ks; + } + + /** + * Get trusted certificates in the default trusted KeyStore with + * the specified descriptor. + * + * @return empty collection if the underlying KeyStore is not available. + */ + synchronized Set getTrustedCerts( + TrustStoreDescriptor descriptor) throws Exception { + + KeyStore ks = null; + TrustStoreDescriptor temporaryDesc = this.descriptor; + Set certs = csRef.get(); + if (certs != null) { + if (descriptor.equals(temporaryDesc)) { + return certs; + } else { + // Use the new descriptor. + this.descriptor = descriptor; + } + } else { + // Try to use the cached store at first. + if (descriptor.equals(temporaryDesc)) { + ks = ksRef.get(); + } else { + // Use the new descriptor. + this.descriptor = descriptor; + } + } + + // Reload the trust store if needed. + if (ks == null) { + if ((debug != null) && Debug.isOn("trustmanager")) { + System.out.println("Reload the trust store"); + } + ks = loadKeyStore(descriptor); + } + + // Reload trust certs from the key store. + if ((debug != null) && Debug.isOn("trustmanager")) { + System.out.println("Reload trust certs"); + } + + certs = loadTrustedCerts(ks); + if ((debug != null) && Debug.isOn("trustmanager")) { + System.out.println("Reloaded " + certs.size() + " trust certs"); + } + + // Note that as ks is a local variable, it is not + // necessary to add it to the ksRef weak reference. + this.csRef = new WeakReference<>(certs); + + return certs; + } + + /** + * Load the the KeyStore as described in the specified descriptor. + */ + private static KeyStore loadKeyStore( + TrustStoreDescriptor descriptor) throws Exception { + if (!"NONE".equals(descriptor.storeName) && + descriptor.storeFile == null) { + + // No file available, no KeyStore available. + if (debug != null && Debug.isOn("trustmanager")) { + System.out.println("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) { + // No file available, no KeyStore available. + if (debug != null && Debug.isOn("trustmanager")) { + System.out.println( + "Not available key store: " + descriptor.storeName); + } + + return null; + } + } else { + ks.load(null, password); + } + + return ks; + } + + /** + * Load trusted certificates from the specified KeyStore. + */ + private static Set loadTrustedCerts(KeyStore ks) { + if (ks == null) { + return Collections.emptySet(); + } + + return TrustStoreUtil.getTrustedCerts(ks); + } + } +} diff --git a/src/share/classes/sun/security/validator/KeyStores.java b/src/share/classes/sun/security/validator/TrustStoreUtil.java similarity index 52% rename from src/share/classes/sun/security/validator/KeyStores.java rename to src/share/classes/sun/security/validator/TrustStoreUtil.java index 8a33cd315..9d610ce62 100644 --- a/src/share/classes/sun/security/validator/KeyStores.java +++ b/src/share/classes/sun/security/validator/TrustStoreUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,76 +25,33 @@ package sun.security.validator; -import java.io.*; -import java.util.*; +import java.util.Set; +import java.util.HashSet; +import java.util.Collections; +import java.util.Enumeration; -import java.security.*; -import java.security.cert.*; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.cert.X509Certificate; import java.security.cert.Certificate; -import sun.security.action.*; - /** - * Collection of static utility methods related to KeyStores. + * Collection of static utility methods related to trust anchor KeyStores. * * @author Andreas Sterbenz */ -public class KeyStores { +public final class TrustStoreUtil { - private KeyStores() { + private TrustStoreUtil() { // empty } - // in the future, all accesses to the system cacerts keystore should - // go through this class. but not right now. -/* - private final static String javaHome = - (String)AccessController.doPrivileged(new GetPropertyAction("java.home")); - - private final static char SEP = File.separatorChar; - - private static KeyStore caCerts; - - private static KeyStore getKeyStore(String type, String name, - char[] password) throws IOException { - if (type == null) { - type = "JKS"; - } - try { - KeyStore ks = KeyStore.getInstance(type); - FileInputStream in = (FileInputStream)AccessController.doPrivileged - (new OpenFileInputStreamAction(name)); - ks.load(in, password); - return ks; - } catch (GeneralSecurityException e) { - // XXX - throw new IOException(); - } catch (PrivilegedActionException e) { - throw (IOException)e.getCause(); - } - } - - /** - * Return a KeyStore with the contents of the lib/security/cacerts file. - * The file is only opened once per JVM invocation and the contents - * cached subsequently. - * - public synchronized static KeyStore getCaCerts() throws IOException { - if (caCerts != null) { - return caCerts; - } - String name = javaHome + SEP + "lib" + SEP + "security" + SEP + "cacerts"; - caCerts = getKeyStore(null, name, null); - return caCerts; - } -*/ - /** - * Return a Set with all trusted X509Certificates contained in - * this KeyStore. + * Return an unmodifiable Set with all trusted X509Certificates contained + * in the specified KeyStore. */ public static Set getTrustedCerts(KeyStore ks) { - Set set = new HashSet(); + Set set = new HashSet<>(); try { for (Enumeration e = ks.aliases(); e.hasMoreElements(); ) { String alias = e.nextElement(); @@ -113,8 +70,10 @@ public class KeyStores { } } catch (KeyStoreException e) { // ignore + // + // This should be rare, but better to log this in the future. } - return set; - } + return Collections.unmodifiableSet(set); + } } -- GitLab