8129988: JSSE should create a single instance of the cacerts KeyStore
authorxuelei
Fri, 06 Jan 2017 02:03:47 +0000
changeset 43009 5af9f7aa93e5
parent 43008 c6c74a38f1ad
child 43010 f3c984a6f1d9
child 43528 977dab1b9ce9
8129988: JSSE should create a single instance of the cacerts KeyStore Reviewed-by: mullan
jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java
jdk/src/java.base/share/classes/sun/security/ssl/TrustManagerFactoryImpl.java
jdk/src/java.base/share/classes/sun/security/ssl/TrustStoreManager.java
jdk/src/java.base/share/classes/sun/security/ssl/X509TrustManagerImpl.java
jdk/src/java.base/share/classes/sun/security/validator/KeyStores.java
jdk/src/java.base/share/classes/sun/security/validator/TrustStoreUtil.java
jdk/src/java.base/share/classes/sun/security/validator/Validator.java
jdk/test/sun/security/ssl/SSLContextImpl/BadTSProvider.java
jdk/test/sun/security/validator/EndEntityExtensionCheck.java
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java	Fri Jan 06 01:09:03 2017 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java	Fri Jan 06 02:03:47 2017 +0000
@@ -935,12 +935,20 @@
         }
 
         private static TrustManager[] getTrustManagers() throws Exception {
-            KeyStore ks =
-                TrustManagerFactoryImpl.getCacertsKeyStore("defaultctx");
+            TrustManagerFactory tmf = TrustManagerFactory.getInstance(
+                    TrustManagerFactory.getDefaultAlgorithm());
+            if ("SunJSSE".equals(tmf.getProvider().getName())) {
+                // The implementation will load the default KeyStore
+                // automatically.  Cached trust materials may be used
+                // for performance improvement.
+                tmf.init((KeyStore)null);
+            } else {
+                // Use the explicitly specified KeyStore for third party's
+                // TrustManagerFactory implementation.
+                KeyStore ks = TrustStoreManager.getTrustedKeyStore();
+                tmf.init(ks);
+            }
 
-            TrustManagerFactory tmf = TrustManagerFactory.getInstance(
-                TrustManagerFactory.getDefaultAlgorithm());
-            tmf.init(ks);
             return tmf.getTrustManagers();
         }
 
--- a/jdk/src/java.base/share/classes/sun/security/ssl/TrustManagerFactoryImpl.java	Fri Jan 06 01:09:03 2017 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/TrustManagerFactoryImpl.java	Fri Jan 06 02:03:47 2017 +0000
@@ -32,6 +32,7 @@
 import javax.net.ssl.*;
 
 import sun.security.validator.Validator;
+import sun.security.validator.TrustStoreUtil;
 
 abstract class TrustManagerFactoryImpl extends TrustManagerFactorySpi {
 
@@ -47,7 +48,7 @@
     protected void engineInit(KeyStore ks) throws KeyStoreException {
         if (ks == null) {
             try {
-                ks = getCacertsKeyStore("trustmanager");
+                trustManager = getInstance(TrustStoreManager.getTrustedCerts());
             } catch (SecurityException se) {
                 // eat security exceptions but report other throwables
                 if (debug != null && Debug.isOn("trustmanager")) {
@@ -72,14 +73,17 @@
                         "SunX509: skip default keystore: " + e);
                 }
                 throw new KeyStoreException(
-                    "problem accessing trust store" + e);
+                    "problem accessing trust store", e);
             }
+        } else {
+            trustManager = getInstance(TrustStoreUtil.getTrustedCerts(ks));
         }
-        trustManager = getInstance(ks);
+
         isInitialized = true;
     }
 
-    abstract X509TrustManager getInstance(KeyStore ks) throws KeyStoreException;
+    abstract X509TrustManager getInstance(
+            Collection<X509Certificate> trustedCerts);
 
     abstract X509TrustManager getInstance(ManagerFactoryParameters spec)
             throws InvalidAlgorithmParameterException;
@@ -126,126 +130,14 @@
                 });
     }
 
-    /**
-     * Returns the keystore with the configured CA certificates.
-     */
-    static KeyStore getCacertsKeyStore(String dbgname) throws Exception
-    {
-        String storeFileName = null;
-        File storeFile = null;
-        FileInputStream fis = null;
-        String defaultTrustStoreType;
-        String defaultTrustStoreProvider;
-        final HashMap<String,String> props = new HashMap<>();
-        final String sep = File.separator;
-        KeyStore ks = null;
-
-        AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
-            @Override
-            public Void run() throws Exception {
-                props.put("trustStore", System.getProperty(
-                                "javax.net.ssl.trustStore"));
-                props.put("javaHome", System.getProperty(
-                                        "java.home"));
-                props.put("trustStoreType", System.getProperty(
-                                "javax.net.ssl.trustStoreType",
-                                KeyStore.getDefaultType()));
-                props.put("trustStoreProvider", System.getProperty(
-                                "javax.net.ssl.trustStoreProvider", ""));
-                props.put("trustStorePasswd", System.getProperty(
-                                "javax.net.ssl.trustStorePassword", ""));
-                return null;
-            }
-        });
-
-        /*
-         * Try:
-         *      javax.net.ssl.trustStore  (if this variable exists, stop)
-         *      jssecacerts
-         *      cacerts
-         *
-         * If none exists, we use an empty keystore.
-         */
-
-        try {
-            storeFileName = props.get("trustStore");
-            if (!"NONE".equals(storeFileName)) {
-                if (storeFileName != null) {
-                    storeFile = new File(storeFileName);
-                    fis = getFileInputStream(storeFile);
-                } else {
-                    String javaHome = props.get("javaHome");
-                    storeFile = new File(javaHome + sep + "lib" + sep
-                                                    + "security" + sep +
-                                                    "jssecacerts");
-                    if ((fis = getFileInputStream(storeFile)) == null) {
-                        storeFile = new File(javaHome + sep + "lib" + sep
-                                                    + "security" + sep +
-                                                    "cacerts");
-                        fis = getFileInputStream(storeFile);
-                    }
-                }
-
-                if (fis != null) {
-                    storeFileName = storeFile.getPath();
-                } else {
-                    storeFileName = "No File Available, using empty keystore.";
-                }
-            }
-
-            defaultTrustStoreType = props.get("trustStoreType");
-            defaultTrustStoreProvider = props.get("trustStoreProvider");
-            if (debug != null && Debug.isOn(dbgname)) {
-                System.out.println("trustStore is: " + storeFileName);
-                System.out.println("trustStore type is : " +
-                                    defaultTrustStoreType);
-                System.out.println("trustStore provider is : " +
-                                    defaultTrustStoreProvider);
-            }
-
-            /*
-             * Try to initialize trust store.
-             */
-            if (defaultTrustStoreType.length() != 0) {
-                if (debug != null && Debug.isOn(dbgname)) {
-                    System.out.println("init truststore");
-                }
-                if (defaultTrustStoreProvider.length() == 0) {
-                    ks = KeyStore.getInstance(defaultTrustStoreType);
-                } else {
-                    ks = KeyStore.getInstance(defaultTrustStoreType,
-                                            defaultTrustStoreProvider);
-                }
-                char[] passwd = null;
-                String defaultTrustStorePassword =
-                        props.get("trustStorePasswd");
-                if (defaultTrustStorePassword.length() != 0)
-                    passwd = defaultTrustStorePassword.toCharArray();
-
-                // if trustStore is NONE, fis will be null
-                ks.load(fis, passwd);
-
-                // Zero out the temporary password storage
-                if (passwd != null) {
-                    for (int i = 0; i < passwd.length; i++) {
-                        passwd[i] = (char)0;
-                    }
-                }
-            }
-        } finally {
-            if (fis != null) {
-                fis.close();
-            }
+    public static final class SimpleFactory extends TrustManagerFactoryImpl {
+        @Override
+        X509TrustManager getInstance(
+                Collection<X509Certificate> trustedCerts) {
+            return new X509TrustManagerImpl(
+                    Validator.TYPE_SIMPLE, trustedCerts);
         }
 
-        return ks;
-    }
-
-    public static final class SimpleFactory extends TrustManagerFactoryImpl {
-        @Override
-        X509TrustManager getInstance(KeyStore ks) throws KeyStoreException {
-            return new X509TrustManagerImpl(Validator.TYPE_SIMPLE, ks);
-        }
         @Override
         X509TrustManager getInstance(ManagerFactoryParameters spec)
                 throws InvalidAlgorithmParameterException {
@@ -253,13 +145,15 @@
                 ("SunX509 TrustManagerFactory does not use "
                 + "ManagerFactoryParameters");
         }
-   }
+    }
 
     public static final class PKIXFactory extends TrustManagerFactoryImpl {
         @Override
-        X509TrustManager getInstance(KeyStore ks) throws KeyStoreException {
-            return new X509TrustManagerImpl(Validator.TYPE_PKIX, ks);
+        X509TrustManager getInstance(
+                Collection<X509Certificate> trustedCerts) {
+            return new X509TrustManagerImpl(Validator.TYPE_PKIX, trustedCerts);
         }
+
         @Override
         X509TrustManager getInstance(ManagerFactoryParameters spec)
                 throws InvalidAlgorithmParameterException {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/TrustStoreManager.java	Fri Jan 06 02:03:47 2017 +0000
@@ -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<X509Certificate> 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<KeyStore> 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<Set<X509Certificate>> 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<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 {
+                    // 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<X509Certificate> loadTrustedCerts(KeyStore ks) {
+            if (ks == null) {
+                return Collections.<X509Certificate>emptySet();
+            }
+
+            return TrustStoreUtil.getTrustedCerts(ks);
+        }
+    }
+}
--- a/jdk/src/java.base/share/classes/sun/security/ssl/X509TrustManagerImpl.java	Fri Jan 06 01:09:03 2017 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/X509TrustManagerImpl.java	Fri Jan 06 02:03:47 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -68,16 +68,21 @@
 
     private static final Debug debug = Debug.getInstance("ssl");
 
-    X509TrustManagerImpl(String validatorType, KeyStore ks)
-            throws KeyStoreException {
+    X509TrustManagerImpl(String validatorType,
+            Collection<X509Certificate> trustedCerts) {
+
         this.validatorType = validatorType;
         this.pkixParams = null;
-        if (ks == null) {
+
+        if (trustedCerts == null) {
             trustedCerts = Collections.<X509Certificate>emptySet();
-        } else {
-            trustedCerts = KeyStores.getTrustedCerts(ks);
         }
-        showTrustedCerts();
+
+        this.trustedCerts = trustedCerts;
+
+        if (debug != null && Debug.isOn("trustmanager")) {
+            showTrustedCerts();
+        }
     }
 
     X509TrustManagerImpl(String validatorType, PKIXBuilderParameters params) {
@@ -90,7 +95,10 @@
         Validator v = getValidator(Validator.VAR_TLS_SERVER);
         trustedCerts = v.getTrustedCertificates();
         serverValidator = v;
-        showTrustedCerts();
+
+        if (debug != null && Debug.isOn("trustmanager")) {
+            showTrustedCerts();
+        }
     }
 
     @Override
@@ -305,22 +313,20 @@
     }
 
     private void showTrustedCerts() {
-        if (debug != null && Debug.isOn("trustmanager")) {
-            for (X509Certificate cert : trustedCerts) {
-                System.out.println("adding as trusted cert:");
-                System.out.println("  Subject: "
-                                        + cert.getSubjectX500Principal());
-                System.out.println("  Issuer:  "
-                                        + cert.getIssuerX500Principal());
-                System.out.println("  Algorithm: "
-                                        + cert.getPublicKey().getAlgorithm()
-                                        + "; Serial number: 0x"
-                                        + cert.getSerialNumber().toString(16));
-                System.out.println("  Valid from "
-                                        + cert.getNotBefore() + " until "
-                                        + cert.getNotAfter());
-                System.out.println();
-            }
+        for (X509Certificate cert : trustedCerts) {
+            System.out.println("adding as trusted cert:");
+            System.out.println("  Subject: "
+                                    + cert.getSubjectX500Principal());
+            System.out.println("  Issuer:  "
+                                    + cert.getIssuerX500Principal());
+            System.out.println("  Algorithm: "
+                                    + cert.getPublicKey().getAlgorithm()
+                                    + "; Serial number: 0x"
+                                    + cert.getSerialNumber().toString(16));
+            System.out.println("  Valid from "
+                                    + cert.getNotBefore() + " until "
+                                    + cert.getNotAfter());
+            System.out.println();
         }
     }
 
--- a/jdk/src/java.base/share/classes/sun/security/validator/KeyStores.java	Fri Jan 06 01:09:03 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,120 +0,0 @@
-/*
- * Copyright (c) 2002, 2006, 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.validator;
-
-import java.io.*;
-import java.util.*;
-
-import java.security.*;
-import java.security.cert.*;
-import java.security.cert.Certificate;
-
-import sun.security.action.*;
-
-/**
- * Collection of static utility methods related to KeyStores.
- *
- * @author Andreas Sterbenz
- */
-public class KeyStores {
-
-    private KeyStores() {
-        // empty
-    }
-
-    // in the future, all accesses to the system cacerts keystore should
-    // go through this class. but not right now.
-/*
-    private static final String javaHome =
-        (String)AccessController.doPrivileged(new GetPropertyAction("java.home"));
-
-    private static final 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 static synchronized 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.
-     */
-    public static Set<X509Certificate> getTrustedCerts(KeyStore ks) {
-        Set<X509Certificate> set = new HashSet<X509Certificate>();
-        try {
-            for (Enumeration<String> e = ks.aliases(); e.hasMoreElements(); ) {
-                String alias = e.nextElement();
-                if (ks.isCertificateEntry(alias)) {
-                    Certificate cert = ks.getCertificate(alias);
-                    if (cert instanceof X509Certificate) {
-                        set.add((X509Certificate)cert);
-                    }
-                } else if (ks.isKeyEntry(alias)) {
-                    Certificate[] certs = ks.getCertificateChain(alias);
-                    if ((certs != null) && (certs.length > 0) &&
-                            (certs[0] instanceof X509Certificate)) {
-                        set.add((X509Certificate)certs[0]);
-                    }
-                }
-            }
-        } catch (KeyStoreException e) {
-            // ignore
-        }
-        return set;
-    }
-
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/validator/TrustStoreUtil.java	Fri Jan 06 02:03:47 2017 +0000
@@ -0,0 +1,79 @@
+/*
+ * 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
+ * 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.validator;
+
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Collections;
+import java.util.Enumeration;
+
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.cert.X509Certificate;
+import java.security.cert.Certificate;
+
+/**
+ * Collection of static utility methods related to trust anchor KeyStores.
+ *
+ * @author Andreas Sterbenz
+ */
+public final class TrustStoreUtil {
+
+    private TrustStoreUtil() {
+        // empty
+    }
+
+    /**
+     * Return an unmodifiable Set with all trusted X509Certificates contained
+     * in the specified KeyStore.
+     */
+    public static Set<X509Certificate> getTrustedCerts(KeyStore ks) {
+        Set<X509Certificate> set = new HashSet<>();
+        try {
+            for (Enumeration<String> e = ks.aliases(); e.hasMoreElements(); ) {
+                String alias = e.nextElement();
+                if (ks.isCertificateEntry(alias)) {
+                    Certificate cert = ks.getCertificate(alias);
+                    if (cert instanceof X509Certificate) {
+                        set.add((X509Certificate)cert);
+                    }
+                } else if (ks.isKeyEntry(alias)) {
+                    Certificate[] certs = ks.getCertificateChain(alias);
+                    if ((certs != null) && (certs.length > 0) &&
+                            (certs[0] instanceof X509Certificate)) {
+                        set.add((X509Certificate)certs[0]);
+                    }
+                }
+            }
+        } catch (KeyStoreException e) {
+            // ignore
+            //
+            // This should be rare, but better to log this in the future.
+        }
+
+        return Collections.unmodifiableSet(set);
+    }
+}
--- a/jdk/src/java.base/share/classes/sun/security/validator/Validator.java	Fri Jan 06 01:09:03 2017 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/validator/Validator.java	Fri Jan 06 02:03:47 2017 +0000
@@ -166,7 +166,7 @@
      */
     public static Validator getInstance(String type, String variant,
             KeyStore ks) {
-        return getInstance(type, variant, KeyStores.getTrustedCerts(ks));
+        return getInstance(type, variant, TrustStoreUtil.getTrustedCerts(ks));
     }
 
     /**
--- a/jdk/test/sun/security/ssl/SSLContextImpl/BadTSProvider.java	Fri Jan 06 01:09:03 2017 +0000
+++ b/jdk/test/sun/security/ssl/SSLContextImpl/BadTSProvider.java	Fri Jan 06 02:03:47 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -21,18 +21,21 @@
  * questions.
  */
 
+//
+// SunJSSE does not support dynamic system properties, no way to re-use
+// system properties in samevm/agentvm mode.
+//
+
 /*
  * @test
  * @bug 4919147
  * @summary Support for token-based KeyStores
  * @run main/othervm BadTSProvider
- *
- *     SunJSSE does not support dynamic system properties, no way to re-use
- *     system properties in samevm/agentvm mode.
  */
 
 import java.io.*;
 import java.net.*;
+import java.security.*;
 import javax.net.ssl.*;
 
 public class BadTSProvider {
@@ -179,13 +182,19 @@
             // XXX this test must be updated if the exception message changes
 
             Throwable cause = se.getCause();
-            if (cause instanceof java.security.NoSuchAlgorithmException == false) {
+            if (!(cause instanceof NoSuchAlgorithmException)) {
                 se.printStackTrace();
                 throw new Exception("Unexpected exception" + se);
             }
 
             cause = cause.getCause();
-            if (cause instanceof java.security.NoSuchProviderException == false) {
+            if (!(cause instanceof KeyStoreException)) {
+                se.printStackTrace();
+                throw new Exception("Unexpected exception" + se);
+            }
+
+            cause = cause.getCause();
+            if (!(cause instanceof NoSuchProviderException)) {
                 se.printStackTrace();
                 throw new Exception("Unexpected exception" + se);
             }
--- a/jdk/test/sun/security/validator/EndEntityExtensionCheck.java	Fri Jan 06 01:09:03 2017 +0000
+++ b/jdk/test/sun/security/validator/EndEntityExtensionCheck.java	Fri Jan 06 02:03:47 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -45,7 +45,7 @@
 import java.util.Date;
 import java.util.HashSet;
 import java.util.Set;
-import sun.security.validator.KeyStores;
+import sun.security.validator.TrustStoreUtil;
 import sun.security.validator.Validator;
 
 
@@ -113,7 +113,7 @@
 
         Validator v = Validator.getInstance(Validator.TYPE_SIMPLE,
                                             Validator.VAR_TLS_CLIENT,
-                                            KeyStores.getTrustedCerts(ks));
+                                            TrustStoreUtil.getTrustedCerts(ks));
         try {
             v.validate(chain);
             throw new Exception("Chain should not have validated " +