changeset 8754:1edb6fe8456b

8176536: Improved algorithm constraints checking 6854712: Revocation checking enhancements (JEP-124) 6637288: Add OCSP support to PKIX CertPathBuilder implementation 7126011: ReverseBuilder.getMatchingCACerts may throws NPE 7176627: CertPath/jep124/PreferCRL_SoftFail test fails (Could not determine revocation status) 8007967: Infinite loop can happen in sun.security.provider.certpath.SunCertPathBuilder.depthFirstSearchForward() 8010112: NullPointerException in sun.security.provider.certpath.CertId() 8015571: OCSP validation fails if ocsp.responderCertSubjectName is set 8029788: Certificate validation - java.lang.ClassCastException 8031825: OCSP client can't find responder cert if it uses a different subject key id algorithm than responderID Reviewed-by: xuelei, mullan, vinnie, weijun
author andrew
date Thu, 09 Nov 2017 06:08:09 +0000
parents ad08fea7cd1a
children 1303ee1ee5b8
files src/share/classes/java/util/GregorianCalendar.java src/share/classes/sun/misc/JavaUtilCalendarAccess.java src/share/classes/sun/misc/SharedSecrets.java src/share/classes/sun/security/pkcs/SignerInfo.java src/share/classes/sun/security/provider/certpath/AdjacencyList.java src/share/classes/sun/security/provider/certpath/AlgorithmChecker.java src/share/classes/sun/security/provider/certpath/BasicChecker.java src/share/classes/sun/security/provider/certpath/BuildStep.java src/share/classes/sun/security/provider/certpath/Builder.java src/share/classes/sun/security/provider/certpath/CertId.java src/share/classes/sun/security/provider/certpath/CertPathChecker.java src/share/classes/sun/security/provider/certpath/CertStoreHelper.java src/share/classes/sun/security/provider/certpath/CollectionCertStore.java src/share/classes/sun/security/provider/certpath/ConstraintsChecker.java src/share/classes/sun/security/provider/certpath/CrlRevocationChecker.java src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java src/share/classes/sun/security/provider/certpath/ForwardBuilder.java src/share/classes/sun/security/provider/certpath/ForwardState.java src/share/classes/sun/security/provider/certpath/IndexedCollectionCertStore.java src/share/classes/sun/security/provider/certpath/KeyChecker.java src/share/classes/sun/security/provider/certpath/OCSP.java src/share/classes/sun/security/provider/certpath/OCSPChecker.java src/share/classes/sun/security/provider/certpath/OCSPRequest.java src/share/classes/sun/security/provider/certpath/OCSPResponse.java src/share/classes/sun/security/provider/certpath/PKIX.java src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java src/share/classes/sun/security/provider/certpath/PKIXExtendedParameters.java src/share/classes/sun/security/provider/certpath/PKIXMasterCertPathValidator.java src/share/classes/sun/security/provider/certpath/PKIXRevocationChecker.java src/share/classes/sun/security/provider/certpath/PolicyChecker.java src/share/classes/sun/security/provider/certpath/PolicyNodeImpl.java src/share/classes/sun/security/provider/certpath/ResponderId.java src/share/classes/sun/security/provider/certpath/ReverseBuilder.java src/share/classes/sun/security/provider/certpath/ReverseState.java src/share/classes/sun/security/provider/certpath/RevocationChecker.java src/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java src/share/classes/sun/security/provider/certpath/SunCertPathBuilderParameters.java src/share/classes/sun/security/provider/certpath/URICertStore.java src/share/classes/sun/security/provider/certpath/Vertex.java src/share/classes/sun/security/provider/certpath/X509CertPath.java src/share/classes/sun/security/provider/certpath/X509CertificatePair.java src/share/classes/sun/security/provider/certpath/ldap/LDAPCertStoreHelper.java src/share/classes/sun/security/provider/certpath/ssl/SSLServerCertStoreHelper.java src/share/classes/sun/security/ssl/SSLContextImpl.java src/share/classes/sun/security/ssl/X509KeyManagerImpl.java src/share/classes/sun/security/util/AnchorCertificates.java src/share/classes/sun/security/util/ConstraintsParameters.java src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java src/share/classes/sun/security/util/SignatureFileVerifier.java src/share/classes/sun/security/validator/PKIXValidator.java src/share/classes/sun/security/validator/SimpleValidator.java src/share/classes/sun/security/x509/PKIXExtensions.java src/share/classes/sun/security/x509/X509CertImpl.java src/share/lib/security/java.security-linux src/share/lib/security/java.security-macosx src/share/lib/security/java.security-solaris src/share/lib/security/java.security-windows test/ProblemList.txt test/java/security/cert/PKIXRevocationChecker/UnitTest.java test/sun/security/tools/jarsigner/TimestampCheck.java
diffstat 60 files changed, 6491 insertions(+), 3673 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/java/util/GregorianCalendar.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/java/util/GregorianCalendar.java	Thu Nov 09 06:08:09 2017 +0000
@@ -508,6 +508,18 @@
     // The default value of gregorianCutover.
     static final long DEFAULT_GREGORIAN_CUTOVER = -12219292800000L;
 
+    // Set up JavaUtilCalendarAccess in SharedSecrets
+    static {
+       sun.misc.SharedSecrets.setJavaUtilCalendarAccess(new sun.misc.JavaUtilCalendarAccess() {
+               public GregorianCalendar createCalendar(TimeZone zone, Locale locale) {
+                   return new GregorianCalendar(zone, locale, true);
+               }
+               public void complete(Calendar cal) {
+                   cal.complete();
+               }
+        });
+    }
+
 /////////////////////
 // Instance Variables
 /////////////////////
@@ -722,6 +734,18 @@
         this.internalSet(MILLISECOND, millis);
     }
 
+    /**
+     * Constructs an empty GregorianCalendar.
+     *
+     * @param zone    the given time zone
+     * @param aLocale the given locale
+     * @param flag    the flag requesting an empty instance
+     */
+    GregorianCalendar(TimeZone zone, Locale locale, boolean flag) {
+        super(zone, locale);
+        gdate = (BaseCalendar.Date) gcal.newCalendarDate(getZone());
+    }
+
 /////////////////
 // Public methods
 /////////////////
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/misc/JavaUtilCalendarAccess.java	Thu Nov 09 06:08:09 2017 +0000
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2017 Red Hat, Inc.
+ * 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.misc;
+
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.Locale;
+import java.util.TimeZone;
+
+public interface JavaUtilCalendarAccess {
+
+    /**
+     * Create an empty GregorianCalendar instance.
+     */
+    GregorianCalendar createCalendar(TimeZone zone, Locale locale);
+
+    /**
+     * Fills in any unset fields in the calendar fields. First, the {@link
+     * #computeTime()} method is called if the time value (millisecond offset
+     * from the <a href="#Epoch">Epoch</a>) has not been calculated from
+     * calendar field values. Then, the {@link #computeFields()} method is
+     * called to calculate all calendar field values.
+     *
+     * @param cal the calendar to complete.
+     */
+    void complete(Calendar cal);
+}
--- a/src/share/classes/sun/misc/SharedSecrets.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/misc/SharedSecrets.java	Thu Nov 09 06:08:09 2017 +0000
@@ -25,17 +25,17 @@
 
 package sun.misc;
 
-import java.io.ObjectInputStream;
-import java.util.jar.JarFile;
 import java.io.Console;
 import java.io.FileDescriptor;
 import java.io.ObjectInputStream;
+import java.security.AccessController;
 import java.security.ProtectionDomain;
+import java.util.GregorianCalendar;
+import java.util.jar.JarFile;
 import java.util.zip.Adler32;
+
 import javax.security.auth.kerberos.KeyTab;
 
-import java.security.AccessController;
-
 /** A repository of "shared secrets", which are a mechanism for
     calling implementation-private methods in another package without
     using reflection. A package-private class implements a public
@@ -62,6 +62,7 @@
     private static JavaAWTAccess javaAWTAccess;
     private static JavaOISAccess javaOISAccess;
     private static JavaObjectInputStreamAccess javaObjectInputStreamAccess;
+    private static JavaUtilCalendarAccess javaUtilCalendarAccess;
 
     public static JavaUtilJarAccess javaUtilJarAccess() {
         if (javaUtilJarAccess == null) {
@@ -226,4 +227,15 @@
     public static void setJavaObjectInputStreamAccess(JavaObjectInputStreamAccess access) {
         javaObjectInputStreamAccess = access;
     }
+
+    public static JavaUtilCalendarAccess getJavaUtilCalendarAccess() {
+        if (javaUtilCalendarAccess == null) {
+            unsafe.ensureClassInitialized(GregorianCalendar.class);
+        }
+        return javaUtilCalendarAccess;
+    }
+
+    public static void setJavaUtilCalendarAccess(JavaUtilCalendarAccess access) {
+        javaUtilCalendarAccess = access;
+    }
 }
--- a/src/share/classes/sun/security/pkcs/SignerInfo.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/pkcs/SignerInfo.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, 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
@@ -37,6 +37,7 @@
 import java.security.Signature;
 import java.security.SignatureException;
 import java.security.Timestamp;
+import java.security.cert.CertPathValidatorException;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
 import java.security.cert.CertPath;
@@ -49,6 +50,7 @@
 
 import sun.misc.HexDumpEncoder;
 import sun.security.timestamp.TimestampToken;
+import sun.security.util.ConstraintsParameters;
 import sun.security.util.Debug;
 import sun.security.util.DerEncoder;
 import sun.security.util.DerInputStream;
@@ -209,7 +211,7 @@
 
     /**
      * DER encode this object onto an output stream.
-     * Implements the <code>DerEncoder</code> interface.
+     * Implements the {@code DerEncoder} interface.
      *
      * @param out
      * the output stream on which to write the DER encoding.
@@ -266,7 +268,7 @@
         if (userCert == null)
             return null;
 
-        ArrayList<X509Certificate> certList = new ArrayList<X509Certificate>();
+        ArrayList<X509Certificate> certList = new ArrayList<>();
         certList.add(userCert);
 
         X509Certificate[] pkcsCerts = block.getCertificates();
@@ -321,6 +323,8 @@
                 data = content.getContentBytes();
             }
 
+            ConstraintsParameters cparams =
+                    new ConstraintsParameters(timestamp);
             String digestAlgname = getDigestAlgorithmId().getName();
 
             byte[] dataSigned;
@@ -347,11 +351,11 @@
                 if (messageDigest == null) // fail if there is no message digest
                     return null;
 
-                // check that algorithm is not restricted
-                if (!JAR_DISABLED_CHECK.permits(DIGEST_PRIMITIVE_SET,
-                        digestAlgname, null)) {
-                    throw new SignatureException("Digest check failed. " +
-                            "Disabled algorithm used: " + digestAlgname);
+                // check that digest algorithm is not restricted
+                try {
+                    JAR_DISABLED_CHECK.permits(digestAlgname, cparams);
+                } catch (CertPathValidatorException e) {
+                    throw new SignatureException(e.getMessage(), e);
                 }
 
                 MessageDigest md = MessageDigest.getInstance(
@@ -386,17 +390,18 @@
             String algname = AlgorithmId.makeSigAlg(
                     digestAlgname, encryptionAlgname);
 
-            // check that algorithm is not restricted
-            if (!JAR_DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, algname, null)) {
-                throw new SignatureException("Signature check failed. " +
-                        "Disabled algorithm used: " + algname);
+            // check that jar signature algorithm is not restricted
+            try {
+                JAR_DISABLED_CHECK.permits(algname, cparams);
+            } catch (CertPathValidatorException e) {
+                throw new SignatureException(e.getMessage(), e);
             }
 
             X509Certificate cert = getCertificate(block);
-            PublicKey key = cert.getPublicKey();
             if (cert == null) {
                 return null;
             }
+            PublicKey key = cert.getPublicKey();
 
             // check if the public key is restricted
             if (!JAR_DISABLED_CHECK.permits(SIG_PRIMITIVE_SET, key)) {
@@ -520,7 +525,7 @@
      * Extracts a timestamp from a PKCS7 SignerInfo.
      *
      * Examines the signer's unsigned attributes for a
-     * <tt>signatureTimestampToken</tt> attribute. If present,
+     * {@code signatureTimestampToken} attribute. If present,
      * then it is parsed to extract the date and time at which the
      * timestamp was generated.
      *
--- a/src/share/classes/sun/security/provider/certpath/AdjacencyList.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/provider/certpath/AdjacencyList.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2012, 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
@@ -24,13 +24,11 @@
  */
 package sun.security.provider.certpath;
 
-
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 
-
 /**
  * An AdjacencyList is used to store the history of certification paths
  * attempted in constructing a path from an initiator to a target. The
@@ -123,124 +121,117 @@
      * at the start.
      */
     private boolean buildList(List<List<Vertex>> theList, int index,
-        BuildStep follow) {
+                              BuildStep follow) {
 
         // Each time this method is called, we're examining a new list
         // from the global list. So, we have to start by getting the list
         // that contains the set of Vertexes we're considering.
         List<Vertex> l = theList.get(index);
 
-        try {
-            // we're interested in the case where all indexes are -1...
-            boolean allNegOne = true;
-            // ...and in the case where every entry has a Throwable
-            boolean allXcps = true;
+        // we're interested in the case where all indexes are -1...
+        boolean allNegOne = true;
+        // ...and in the case where every entry has a Throwable
+        boolean allXcps = true;
+
+        for (Vertex v : l) {
+            if (v.getIndex() != -1) {
+                // count an empty list the same as an index of -1...this
+                // is to patch a bug somewhere in the builder
+                if (theList.get(v.getIndex()).size() != 0)
+                    allNegOne = false;
+            } else {
+                if (v.getThrowable() == null)
+                    allXcps = false;
+            }
+            // every entry, regardless of the final use for it, is always
+            // entered as a possible step before we take any actions
+            mStepList.add(new BuildStep(v, BuildStep.POSSIBLE));
+        }
+
+        if (allNegOne) {
+            // There are two cases that we could be looking at here. We
+            // may need to back up, or the build may have succeeded at
+            // this point. This is based on whether or not any
+            // exceptions were found in the list.
+            if (allXcps) {
+                // we need to go back...see if this is the last one
+                if (follow == null)
+                    mStepList.add(new BuildStep(null, BuildStep.FAIL));
+                else
+                    mStepList.add(new BuildStep(follow.getVertex(),
+                                                BuildStep.BACK));
+
+                return false;
+            } else {
+                // we succeeded...now the only question is which is the
+                // successful step? If there's only one entry without
+                // a throwable, then that's the successful step. Otherwise,
+                // we'll have to make some guesses...
+                List<Vertex> possibles = new ArrayList<>();
+                for (Vertex v : l) {
+                    if (v.getThrowable() == null)
+                        possibles.add(v);
+                }
+
+                if (possibles.size() == 1) {
+                    // real easy...we've found the final Vertex
+                    mStepList.add(new BuildStep(possibles.get(0),
+                                                BuildStep.SUCCEED));
+                } else {
+                    // ok...at this point, there is more than one Cert
+                    // which might be the succeed step...how do we know
+                    // which it is? I'm going to assume that our builder
+                    // algorithm is good enough to know which is the
+                    // correct one, and put it first...but a FIXME goes
+                    // here anyway, and we should be comparing to the
+                    // target/initiator Cert...
+                    mStepList.add(new BuildStep(possibles.get(0),
+                                                BuildStep.SUCCEED));
+                }
+
+                return true;
+            }
+        } else {
+            // There's at least one thing that we can try before we give
+            // up and go back. Run through the list now, and enter a new
+            // BuildStep for each path that we try to follow. If none of
+            // the paths we try produce a successful end, we're going to
+            // have to back out ourselves.
+            boolean success = false;
 
             for (Vertex v : l) {
+
+                // Note that we'll only find a SUCCEED case when we're
+                // looking at the last possible path, so we don't need to
+                // consider success in the while loop
+
                 if (v.getIndex() != -1) {
-                    // count an empty list the same as an index of -1...this
-                    // is to patch a bug somewhere in the builder
-                    if (theList.get(v.getIndex()).size() != 0)
-                        allNegOne = false;
+                    if (theList.get(v.getIndex()).size() != 0) {
+                        // If the entry we're looking at doesn't have an
+                        // index of -1, and doesn't lead to an empty list,
+                        // then it's something we follow!
+                        BuildStep bs = new BuildStep(v, BuildStep.FOLLOW);
+                        mStepList.add(bs);
+                        success = buildList(theList, v.getIndex(), bs);
+                    }
                 }
-                else
-                    if (v.getThrowable() == null)
-                        allXcps = false;
-
-                // every entry, regardless of the final use for it, is always
-                // entered as a possible step before we take any actions
-                mStepList.add(new BuildStep(v, BuildStep.POSSIBLE));
             }
 
-            if (allNegOne) {
-                // There are two cases that we could be looking at here. We
-                // may need to back up, or the build may have succeeded at
-                // this point. This is based on whether or not any
-                // exceptions were found in the list.
-                if (allXcps) {
-                    // we need to go back...see if this is the last one
-                    if (follow == null)
-                        mStepList.add(new BuildStep(null, BuildStep.FAIL));
-                    else
-                        mStepList.add(new BuildStep(follow.getVertex(),
-                                                    BuildStep.BACK));
-
-                    return false;
-                } else {
-                    // we succeeded...now the only question is which is the
-                    // successful step? If there's only one entry without
-                    // a throwable, then that's the successful step. Otherwise,
-                    // we'll have to make some guesses...
-                    List<Vertex> possibles = new ArrayList<Vertex>();
-                    for (Vertex v : l) {
-                        if (v.getThrowable() == null)
-                            possibles.add(v);
-                    }
-
-                    if (possibles.size() == 1) {
-                        // real easy...we've found the final Vertex
-                        mStepList.add(new BuildStep(possibles.get(0),
-                                                    BuildStep.SUCCEED));
-                    } else {
-                        // ok...at this point, there is more than one Cert
-                        // which might be the succeed step...how do we know
-                        // which it is? I'm going to assume that our builder
-                        // algorithm is good enough to know which is the
-                        // correct one, and put it first...but a FIXME goes
-                        // here anyway, and we should be comparing to the
-                        // target/initiator Cert...
-                        mStepList.add(new BuildStep(possibles.get(0),
-                                                    BuildStep.SUCCEED));
-                    }
+            if (success) {
+                // We're already finished!
+                return true;
+            } else {
+                // We failed, and we've exhausted all the paths that we
+                // could take. The only choice is to back ourselves out.
+                if (follow == null)
+                    mStepList.add(new BuildStep(null, BuildStep.FAIL));
+                else
+                    mStepList.add(new BuildStep(follow.getVertex(),
+                                                BuildStep.BACK));
 
-                    return true;
-                }
-            } else {
-                // There's at least one thing that we can try before we give
-                // up and go back. Run through the list now, and enter a new
-                // BuildStep for each path that we try to follow. If none of
-                // the paths we try produce a successful end, we're going to
-                // have to back out ourselves.
-                boolean success = false;
-
-                for (Vertex v : l) {
-
-                    // Note that we'll only find a SUCCEED case when we're
-                    // looking at the last possible path, so we don't need to
-                    // consider success in the while loop
-
-                    if (v.getIndex() != -1) {
-                        if (theList.get(v.getIndex()).size() != 0) {
-                            // If the entry we're looking at doesn't have an
-                            // index of -1, and doesn't lead to an empty list,
-                            // then it's something we follow!
-                            BuildStep bs = new BuildStep(v, BuildStep.FOLLOW);
-                            mStepList.add(bs);
-                            success = buildList(theList, v.getIndex(), bs);
-                        }
-                    }
-                }
-
-                if (success) {
-                    // We're already finished!
-                    return true;
-                } else {
-                    // We failed, and we've exhausted all the paths that we
-                    // could take. The only choice is to back ourselves out.
-                    if (follow == null)
-                        mStepList.add(new BuildStep(null, BuildStep.FAIL));
-                    else
-                        mStepList.add(new BuildStep(follow.getVertex(),
-                                                    BuildStep.BACK));
-
-                    return false;
-                }
+                return false;
             }
         }
-        catch (Exception e) {}
-
-        // we'll never get here, but you know java...
-        return false;
     }
 
     /**
@@ -248,23 +239,20 @@
      *
      * @return String representation
      */
+    @Override
     public String toString() {
-        String out = "[\n";
+        StringBuilder sb = new StringBuilder("[\n");
 
         int i = 0;
         for (List<Vertex> l : mOrigList) {
-            out = out + "LinkedList[" + i++ + "]:\n";
+            sb.append("LinkedList[").append(i++).append("]:\n");
 
             for (Vertex step : l) {
-                try {
-                    out = out + step.toString();
-                    out = out + "\n";
-                }
-                catch (Exception e) { out = out + "No Such Element\n"; }
+                sb.append(step.toString()).append("\n");
             }
         }
-        out = out + "]\n";
+        sb.append("]\n");
 
-        return out;
+        return sb.toString();
     }
 }
--- a/src/share/classes/sun/security/provider/certpath/AlgorithmChecker.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/provider/certpath/AlgorithmChecker.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2017, 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
@@ -27,8 +27,11 @@
 
 import java.security.AlgorithmConstraints;
 import java.security.CryptoPrimitive;
+import java.security.Timestamp;
+import java.security.cert.CertPathValidator;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Date;
 import java.util.Set;
 import java.util.EnumSet;
 import java.math.BigInteger;
@@ -51,15 +54,16 @@
 import java.security.spec.DSAPublicKeySpec;
 
 import sun.security.util.AnchorCertificates;
-import sun.security.util.CertConstraintParameters;
+import sun.security.util.ConstraintsParameters;
 import sun.security.util.Debug;
 import sun.security.util.DisabledAlgorithmConstraints;
+import sun.security.validator.Validator;
 import sun.security.x509.X509CertImpl;
 import sun.security.x509.X509CRLImpl;
 import sun.security.x509.AlgorithmId;
 
 /**
- * A <code>PKIXCertPathChecker</code> implementation to check whether a
+ * A {@code PKIXCertPathChecker} implementation to check whether a
  * specified certificate contains the required algorithm constraints.
  * <p>
  * Certificate fields such as the subject public key, the signature
@@ -69,24 +73,27 @@
  * @see PKIXCertPathChecker
  * @see PKIXParameters
  */
-final public class AlgorithmChecker extends PKIXCertPathChecker {
+public final class AlgorithmChecker extends PKIXCertPathChecker {
     private static final Debug debug = Debug.getInstance("certpath");
 
     private final AlgorithmConstraints constraints;
     private final PublicKey trustedPubKey;
+    private final Date pkixdate;
     private PublicKey prevPubKey;
+    private final Timestamp jarTimestamp;
+    private final String variant;
 
-    private final static Set<CryptoPrimitive> SIGNATURE_PRIMITIVE_SET =
+    private static final Set<CryptoPrimitive> SIGNATURE_PRIMITIVE_SET =
         Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE));
 
-    private final static Set<CryptoPrimitive> KU_PRIMITIVE_SET =
+    private static final Set<CryptoPrimitive> KU_PRIMITIVE_SET =
         Collections.unmodifiableSet(EnumSet.of(
             CryptoPrimitive.SIGNATURE,
             CryptoPrimitive.KEY_ENCAPSULATION,
             CryptoPrimitive.PUBLIC_KEY_ENCRYPTION,
             CryptoPrimitive.KEY_AGREEMENT));
 
-    private final static DisabledAlgorithmConstraints
+    private static final DisabledAlgorithmConstraints
         certPathDefaultConstraints = new DisabledAlgorithmConstraints(
             DisabledAlgorithmConstraints.PROPERTY_CERTPATH_DISABLED_ALGS);
 
@@ -99,64 +106,99 @@
     private boolean trustedMatch = false;
 
     /**
-     * Create a new <code>AlgorithmChecker</code> with the algorithm
-     * constraints specified in security property
-     * "jdk.certpath.disabledAlgorithms".
+     * Create a new {@code AlgorithmChecker} with the given algorithm
+     * given {@code TrustAnchor} and {@code String} variant.
      *
      * @param anchor the trust anchor selected to validate the target
      *     certificate
+     * @param variant is the Validator variants of the operation. A null value
+     *                passed will set it to Validator.GENERIC.
      */
-    public AlgorithmChecker(TrustAnchor anchor) {
-        this(anchor, certPathDefaultConstraints);
+    public AlgorithmChecker(TrustAnchor anchor, String variant) {
+        this(anchor, certPathDefaultConstraints, null, null, variant);
     }
 
     /**
-     * Create a new <code>AlgorithmChecker</code> with the
-     * given {@code AlgorithmConstraints}.
-     * <p>
-     * Note that this constructor will be used to check a certification
-     * path where the trust anchor is unknown, or a certificate list which may
-     * contain the trust anchor. This constructor is used by SunJSSE.
+     * Create a new {@code AlgorithmChecker} with the given
+     * {@code AlgorithmConstraints}, {@code Timestamp}, and {@code String}
+     * variant.
+     *
+     * Note that this constructor can initialize a variation of situations where
+     * the AlgorithmConstraints, Timestamp, or Variant maybe known.
      *
      * @param constraints the algorithm constraints (or null)
+     * @param jarTimestamp Timestamp passed for JAR timestamp constraint
+     *                     checking. Set to null if not applicable.
+     * @param variant is the Validator variants of the operation. A null value
+     *                passed will set it to Validator.GENERIC.
      */
-    public AlgorithmChecker(AlgorithmConstraints constraints) {
-        this.prevPubKey = null;
-        this.trustedPubKey = null;
-        this.constraints = constraints;
+    public AlgorithmChecker(AlgorithmConstraints constraints,
+            Timestamp jarTimestamp, String variant) {
+        this(null, constraints, null, jarTimestamp, variant);
     }
 
     /**
-     * Create a new <code>AlgorithmChecker</code> with the
-     * given <code>TrustAnchor</code> and <code>AlgorithmConstraints</code>.
+     * Create a new {@code AlgorithmChecker} with the
+     * given {@code TrustAnchor}, {@code AlgorithmConstraints},
+     * {@code Timestamp}, and {@code String} variant.
      *
      * @param anchor the trust anchor selected to validate the target
      *     certificate
      * @param constraints the algorithm constraints (or null)
-     *
-     * @throws IllegalArgumentException if the <code>anchor</code> is null
+     * @param pkixdate The date specified by the PKIXParameters date.  If the
+     *                 PKIXParameters is null, the current date is used.  This
+     *                 should be null when jar files are being checked.
+     * @param jarTimestamp Timestamp passed for JAR timestamp constraint
+     *                     checking. Set to null if not applicable.
+     * @param variant is the Validator variants of the operation. A null value
+     *                passed will set it to Validator.GENERIC.
      */
     public AlgorithmChecker(TrustAnchor anchor,
-            AlgorithmConstraints constraints) {
+            AlgorithmConstraints constraints, Date pkixdate,
+            Timestamp jarTimestamp, String variant) {
 
-        if (anchor == null) {
-            throw new IllegalArgumentException(
-                        "The trust anchor cannot be null");
+        if (anchor != null) {
+            if (anchor.getTrustedCert() != null) {
+                this.trustedPubKey = anchor.getTrustedCert().getPublicKey();
+                // Check for anchor certificate restrictions
+                trustedMatch = checkFingerprint(anchor.getTrustedCert());
+                if (trustedMatch && debug != null) {
+                    debug.println("trustedMatch = true");
+                }
+            } else {
+                this.trustedPubKey = anchor.getCAPublicKey();
+            }
+        } else {
+            this.trustedPubKey = null;
+            if (debug != null) {
+                debug.println("TrustAnchor is null, trustedMatch is false.");
+            }
         }
 
-        if (anchor.getTrustedCert() != null) {
-            this.trustedPubKey = anchor.getTrustedCert().getPublicKey();
-            // Check for anchor certificate restrictions
-            trustedMatch = checkFingerprint(anchor.getTrustedCert());
-            if (trustedMatch && debug != null) {
-                debug.println("trustedMatch = true");
-            }
-        } else {
-            this.trustedPubKey = anchor.getCAPublicKey();
-        }
+        this.prevPubKey = this.trustedPubKey;
+        this.constraints = (constraints == null ? certPathDefaultConstraints :
+                constraints);
+        // If we are checking jar files, set pkixdate the same as the timestamp
+        // for certificate checking
+        this.pkixdate = (jarTimestamp != null ? jarTimestamp.getTimestamp() :
+                pkixdate);
+        this.jarTimestamp = jarTimestamp;
+        this.variant = (variant == null ? Validator.VAR_GENERIC : variant);
+    }
 
-        this.prevPubKey = trustedPubKey;
-        this.constraints = constraints;
+    /**
+     * Create a new {@code AlgorithmChecker} with the given {@code TrustAnchor},
+     * {@code PKIXParameter} date, and {@code varient}
+     *
+     * @param anchor the trust anchor selected to validate the target
+     *     certificate
+     * @param pkixdate Date the constraints are checked against. The value is
+     *             either the PKIXParameters date or null for the current date.
+     * @param variant is the Validator variants of the operation. A null value
+     *                passed will set it to Validator.GENERIC.
+     */
+    public AlgorithmChecker(TrustAnchor anchor, Date pkixdate, String variant) {
+        this(anchor, certPathDefaultConstraints, pkixdate, null, variant);
     }
 
     // Check this 'cert' for restrictions in the AnchorCertificates
@@ -217,6 +259,28 @@
                 null, null, -1, PKIXReason.INVALID_KEY_USAGE);
         }
 
+        X509CertImpl x509Cert;
+        AlgorithmId algorithmId;
+        try {
+            x509Cert = X509CertImpl.toImpl((X509Certificate)cert);
+            algorithmId = (AlgorithmId)x509Cert.get(X509CertImpl.SIG_ALG);
+        } catch (CertificateException ce) {
+            throw new CertPathValidatorException(ce);
+        }
+
+        AlgorithmParameters currSigAlgParams = algorithmId.getParameters();
+        PublicKey currPubKey = cert.getPublicKey();
+        String currSigAlg = ((X509Certificate)cert).getSigAlgName();
+
+        // Check the signature algorithm and parameters against constraints.
+        if (!constraints.permits(SIGNATURE_PRIMITIVE_SET, currSigAlg,
+                currSigAlgParams)) {
+            throw new CertPathValidatorException(
+                    "Algorithm constraints check failed on signature " +
+                            "algorithm: " + currSigAlg, null, null, -1,
+                    BasicReason.ALGORITHM_CONSTRAINED);
+        }
+
         // Assume all key usage bits are set if key usage is not present
         Set<CryptoPrimitive> primitives = KU_PRIMITIVE_SET;
 
@@ -253,102 +317,75 @@
             }
         }
 
-        PublicKey currPubKey = cert.getPublicKey();
+        ConstraintsParameters cp =
+                new ConstraintsParameters((X509Certificate)cert,
+                        trustedMatch, pkixdate, jarTimestamp, variant);
 
+        // Check against local constraints if it is DisabledAlgorithmConstraints
         if (constraints instanceof DisabledAlgorithmConstraints) {
-            // Check against DisabledAlgorithmConstraints certpath constraints.
-            // permits() will throw exception on failure.
-            ((DisabledAlgorithmConstraints)constraints).permits(primitives,
-                new CertConstraintParameters((X509Certificate)cert,
-                        trustedMatch));
-            // If there is no previous key, set one and exit
-            if (prevPubKey == null) {
-                prevPubKey = currPubKey;
-                return;
+            ((DisabledAlgorithmConstraints)constraints).permits(currSigAlg, cp);
+            // DisabledAlgorithmsConstraints does not check primitives, so key
+            // additional key check.
+
+        } else {
+            // Perform the default constraints checking anyway.
+            certPathDefaultConstraints.permits(currSigAlg, cp);
+            // Call locally set constraints to check key with primitives.
+            if (!constraints.permits(primitives, currPubKey)) {
+                throw new CertPathValidatorException(
+                        "Algorithm constraints check failed on key " +
+                                currPubKey.getAlgorithm() + " with size of " +
+                                sun.security.util.KeyUtil.getKeySize(currPubKey) +
+                                "bits",
+                        null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
             }
         }
 
-        X509CertImpl x509Cert;
-        AlgorithmId algorithmId;
-        try {
-            x509Cert = X509CertImpl.toImpl((X509Certificate)cert);
-            algorithmId = (AlgorithmId)x509Cert.get(X509CertImpl.SIG_ALG);
-        } catch (CertificateException ce) {
-            throw new CertPathValidatorException(ce);
-        }
-
-        AlgorithmParameters currSigAlgParams = algorithmId.getParameters();
-        String currSigAlg = x509Cert.getSigAlgName();
-
-        // If 'constraints' is not of DisabledAlgorithmConstraints, check all
-        // everything individually
-        if (!(constraints instanceof DisabledAlgorithmConstraints)) {
-            // Check the current signature algorithm
-            if (!constraints.permits(
-                    SIGNATURE_PRIMITIVE_SET,
-                    currSigAlg, currSigAlgParams)) {
-                throw new CertPathValidatorException(
-                        "Algorithm constraints check failed on signature " +
-                                "algorithm: " + currSigAlg, null, null, -1,
-                        BasicReason.ALGORITHM_CONSTRAINED);
-            }
-
-        if (!constraints.permits(primitives, currPubKey)) {
-            throw new CertPathValidatorException(
-                        "Algorithm constraints check failed on keysize: " +
-                                sun.security.util.KeyUtil.getKeySize(currPubKey),
-                null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
-        }
+        // If there is no previous key, set one and exit
+        if (prevPubKey == null) {
+            prevPubKey = currPubKey;
+            return;
         }
 
         // Check with previous cert for signature algorithm and public key
-        if (prevPubKey != null) {
-                if (!constraints.permits(
-                        SIGNATURE_PRIMITIVE_SET,
-                        currSigAlg, prevPubKey, currSigAlgParams)) {
-                    throw new CertPathValidatorException(
+        if (!constraints.permits(
+                SIGNATURE_PRIMITIVE_SET,
+                currSigAlg, prevPubKey, currSigAlgParams)) {
+            throw new CertPathValidatorException(
                     "Algorithm constraints check failed on " +
                             "signature algorithm: " + currSigAlg,
-                        null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
-                }
+                    null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
+        }
 
-            // Inherit key parameters from previous key
-            if (currPubKey instanceof DSAPublicKey &&
-                ((DSAPublicKey)currPubKey).getParams() == null) {
-                // Inherit DSA parameters from previous key
-                if (!(prevPubKey instanceof DSAPublicKey)) {
-                    throw new CertPathValidatorException("Input key is not " +
+        // Inherit key parameters from previous key
+        if (currPubKey instanceof DSAPublicKey &&
+            ((DSAPublicKey)currPubKey).getParams() == null) {
+            // Inherit DSA parameters from previous key
+            if (!(prevPubKey instanceof DSAPublicKey)) {
+                throw new CertPathValidatorException("Input key is not " +
                         "of a appropriate type for inheriting parameters");
-                }
+            }
 
-                DSAParams params = ((DSAPublicKey)prevPubKey).getParams();
-                if (params == null) {
-                    throw new CertPathValidatorException(
+            DSAParams params = ((DSAPublicKey)prevPubKey).getParams();
+            if (params == null) {
+                throw new CertPathValidatorException(
                         "Key parameters missing from public key.");
-                }
+            }
 
-                try {
-                    BigInteger y = ((DSAPublicKey)currPubKey).getY();
-                    KeyFactory kf = KeyFactory.getInstance("DSA");
-                    DSAPublicKeySpec ks = new DSAPublicKeySpec(y,
-                                                       params.getP(),
-                                                       params.getQ(),
-                                                       params.getG());
-                    currPubKey = kf.generatePublic(ks);
-                } catch (GeneralSecurityException e) {
-                    throw new CertPathValidatorException("Unable to generate " +
+            try {
+                BigInteger y = ((DSAPublicKey)currPubKey).getY();
+                KeyFactory kf = KeyFactory.getInstance("DSA");
+                DSAPublicKeySpec ks = new DSAPublicKeySpec(y, params.getP(),
+                        params.getQ(), params.getG());
+                currPubKey = kf.generatePublic(ks);
+            } catch (GeneralSecurityException e) {
+                throw new CertPathValidatorException("Unable to generate " +
                         "key with inherited parameters: " + e.getMessage(), e);
-                }
             }
         }
 
         // reset the previous public key
         prevPubKey = currPubKey;
-
-        // check the extended key usage, ignore the check now
-        // List<String> extendedKeyUsages = x509Cert.getExtendedKeyUsage();
-
-        // DO NOT remove any unresolved critical extensions
     }
 
     /**
@@ -388,8 +425,10 @@
      *
      * @param key the public key to verify the CRL signature
      * @param crl the target CRL
+     * @param variant is the Validator variants of the operation. A null value
+     *                passed will set it to Validator.GENERIC.
      */
-    static void check(PublicKey key, X509CRL crl)
+    static void check(PublicKey key, X509CRL crl, String variant)
                         throws CertPathValidatorException {
 
         X509CRLImpl x509CRLImpl = null;
@@ -400,28 +439,23 @@
         }
 
         AlgorithmId algorithmId = x509CRLImpl.getSigAlgId();
-        check(key, algorithmId);
+        check(key, algorithmId, variant);
     }
 
     /**
      * Check the signature algorithm with the specified public key.
      *
      * @param key the public key to verify the CRL signature
-     * @param crl the target CRL
+     * @param algorithmId signature algorithm Algorithm ID
+     * @param variant is the Validator variants of the operation. A null value
+     *                passed will set it to Validator.GENERIC.
      */
-    static void check(PublicKey key, AlgorithmId algorithmId)
+    static void check(PublicKey key, AlgorithmId algorithmId, String variant)
                         throws CertPathValidatorException {
         String sigAlgName = algorithmId.getName();
         AlgorithmParameters sigAlgParams = algorithmId.getParameters();
 
-        if (!certPathDefaultConstraints.permits(
-                SIGNATURE_PRIMITIVE_SET, sigAlgName, key, sigAlgParams)) {
-            throw new CertPathValidatorException(
-                "Algorithm constraints check failed on signature algorithm: " +
-                sigAlgName + " is disabled",
-                null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
-        }
+        certPathDefaultConstraints.permits(new ConstraintsParameters(
+                sigAlgName, sigAlgParams, key, variant));
     }
-
 }
-
--- a/src/share/classes/sun/security/provider/certpath/BasicChecker.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/provider/certpath/BasicChecker.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2012, 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
@@ -62,7 +62,7 @@
     private static final Debug debug = Debug.getInstance("certpath");
     private final PublicKey trustedPubKey;
     private final X500Principal caName;
-    private final Date testDate;
+    private final Date date;
     private final String sigProvider;
     private final boolean sigOnly;
     private X500Principal prevSubject;
@@ -73,14 +73,13 @@
      *
      * @param anchor the anchor selected to validate the target certificate
      * @param testDate the time for which the validity of the certificate
-     * should be determined
+     *        should be determined
      * @param sigProvider the name of the signature provider
      * @param sigOnly true if only signature checking is to be done;
      *        if false, all checks are done
      */
-    BasicChecker(TrustAnchor anchor, Date testDate, String sigProvider,
-        boolean sigOnly) throws CertPathValidatorException
-    {
+    BasicChecker(TrustAnchor anchor, Date date, String sigProvider,
+                 boolean sigOnly) {
         if (anchor.getTrustedCert() != null) {
             this.trustedPubKey = anchor.getTrustedCert().getPublicKey();
             this.caName = anchor.getTrustedCert().getSubjectX500Principal();
@@ -88,10 +87,9 @@
             this.trustedPubKey = anchor.getCAPublicKey();
             this.caName = anchor.getCA();
         }
-        this.testDate = testDate;
+        this.date = date;
         this.sigProvider = sigProvider;
         this.sigOnly = sigOnly;
-        init(false);
     }
 
     /**
@@ -124,33 +122,30 @@
      * @param cert the Certificate
      * @param unresolvedCritExts a Collection of the unresolved critical
      * extensions
-     * @exception CertPathValidatorException Exception thrown if certificate
-     * does not verify.
+     * @throws CertPathValidatorException if certificate does not verify
      */
     public void check(Certificate cert, Collection<String> unresolvedCritExts)
         throws CertPathValidatorException
     {
-        X509Certificate currCert = (X509Certificate) cert;
+        X509Certificate currCert = (X509Certificate)cert;
 
         if (!sigOnly) {
-            verifyTimestamp(currCert, testDate);
-            verifyNameChaining(currCert, prevSubject);
+            verifyTimestamp(currCert);
+            verifyNameChaining(currCert);
         }
-        verifySignature(currCert, prevPubKey, sigProvider);
+        verifySignature(currCert);
 
         updateState(currCert);
     }
 
     /**
-     * Verifies the signature on the certificate using the previous public key
-     * @param cert the Certificate
-     * @param prevPubKey the previous PublicKey
-     * @param sigProvider a String containing the signature provider
-     * @exception CertPathValidatorException Exception thrown if certificate
-     * does not verify.
+     * Verifies the signature on the certificate using the previous public key.
+     *
+     * @param cert the X509Certificate
+     * @throws CertPathValidatorException if certificate does not verify
      */
-    private void verifySignature(X509Certificate cert, PublicKey prevPubKey,
-        String sigProvider) throws CertPathValidatorException
+    private void verifySignature(X509Certificate cert)
+        throws CertPathValidatorException
     {
         String msg = "signature";
         if (debug != null)
@@ -162,7 +157,7 @@
             throw new CertPathValidatorException
                 (msg + " check failed", e, null, -1,
                  BasicReason.INVALID_SIGNATURE);
-        } catch (Exception e) {
+        } catch (GeneralSecurityException e) {
             throw new CertPathValidatorException(msg + " check failed", e);
         }
 
@@ -173,7 +168,7 @@
     /**
      * Internal method to verify the timestamp on a certificate
      */
-    private void verifyTimestamp(X509Certificate cert, Date date)
+    private void verifyTimestamp(X509Certificate cert)
         throws CertPathValidatorException
     {
         String msg = "timestamp";
@@ -197,8 +192,8 @@
     /**
      * Internal method to check that cert has a valid DN to be next in a chain
      */
-    private void verifyNameChaining(X509Certificate cert,
-        X500Principal prevSubject) throws CertPathValidatorException
+    private void verifyNameChaining(X509Certificate cert)
+        throws CertPathValidatorException
     {
         if (prevSubject != null) {
 
@@ -207,8 +202,8 @@
                 debug.println("---checking " + msg + "...");
 
             X500Principal currIssuer = cert.getIssuerX500Principal();
+
             // reject null or empty issuer DNs
-
             if (X500Name.asX500Name(currIssuer).isEmpty()) {
                 throw new CertPathValidatorException
                     (msg + " check failed: " +
--- a/src/share/classes/sun/security/provider/certpath/BuildStep.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/provider/certpath/BuildStep.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2012, 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,7 +25,6 @@
 
 package sun.security.provider.certpath;
 
-import sun.security.util.Debug;
 import java.security.cert.X509Certificate;
 
 /**
@@ -39,7 +38,6 @@
  */
 public class BuildStep {
 
-    private static final Debug debug = Debug.getInstance("certpath");
     private Vertex          vertex;
     private X509Certificate cert;
     private Throwable       throwable;
@@ -86,7 +84,7 @@
     public BuildStep(Vertex vtx, int res) {
         vertex = vtx;
         if (vertex != null) {
-            cert = (X509Certificate)vertex.getCertificate();
+            cert = vertex.getCertificate();
             throwable = vertex.getThrowable();
         }
         result = res;
@@ -117,7 +115,7 @@
      * @returns String form of issuer name or null, if no certificate.
      */
     public String getIssuerName() {
-        return (cert == null ? null : cert.getIssuerX500Principal().toString());
+        return getIssuerName(null);
     }
 
     /**
@@ -142,7 +140,7 @@
      * @returns String form of subject name or null, if no certificate.
      */
     public String getSubjectName() {
-        return (cert == null ? null : cert.getSubjectX500Principal().toString());
+        return getSubjectName(null);
     }
 
     /**
@@ -191,21 +189,21 @@
     public String resultToString(int res) {
         String resultString = "";
         switch (res) {
-            case BuildStep.POSSIBLE:
+            case POSSIBLE:
                 resultString = "Certificate to be tried.\n";
                 break;
-            case BuildStep.BACK:
+            case BACK:
                 resultString = "Certificate backed out since path does not "
                     + "satisfy build requirements.\n";
                 break;
-            case BuildStep.FOLLOW:
+            case FOLLOW:
                 resultString = "Certificate satisfies conditions.\n";
                 break;
-            case BuildStep.FAIL:
+            case FAIL:
                 resultString = "Certificate backed out since path does not "
                     + "satisfy conditions.\n";
                 break;
-            case BuildStep.SUCCEED:
+            case SUCCEED:
                 resultString = "Certificate satisfies conditions.\n";
                 break;
             default:
@@ -220,6 +218,7 @@
      *
      * @returns String
      */
+    @Override
     public String toString() {
         String out = "Internal Error\n";
         switch (result) {
@@ -273,8 +272,6 @@
      * @returns String
      */
     public String fullToString() {
-        String out = resultToString(getResult());
-        out = out + vertex.toString();
-        return out;
+        return resultToString(getResult()) + vertex.toString();
     }
 }
--- a/src/share/classes/sun/security/provider/certpath/Builder.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/provider/certpath/Builder.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2012, 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
@@ -31,9 +31,8 @@
 import java.security.cert.*;
 import java.util.*;
 
-import javax.security.auth.x500.X500Principal;
-
 import sun.security.action.GetBooleanAction;
+import sun.security.provider.certpath.PKIX.BuilderParams;
 import sun.security.util.Debug;
 import sun.security.x509.GeneralNames;
 import sun.security.x509.GeneralNameInterface;
@@ -56,9 +55,7 @@
 
     private static final Debug debug = Debug.getInstance("certpath");
     private Set<String> matchingPolicies;
-    final PKIXBuilderParameters buildParams;
-    final X500Principal targetSubjectDN;
-    final Date date;
+    final BuilderParams buildParams;
     final X509CertSelector targetCertConstraints;
 
     /**
@@ -74,14 +71,10 @@
      *
      * @param params the parameter set used to build a certification path
      */
-    Builder(PKIXBuilderParameters buildParams, X500Principal targetSubjectDN) {
+    Builder(BuilderParams buildParams) {
         this.buildParams = buildParams;
-        this.targetSubjectDN = targetSubjectDN;
-        // Initialize date if not specified
-        Date paramsDate = buildParams.getDate();
-        this.date = paramsDate != null ? paramsDate : new Date();
         this.targetCertConstraints =
-            (X509CertSelector) buildParams.getTargetCertConstraints();
+            (X509CertSelector)buildParams.targetCertConstraints();
     }
 
     /**
@@ -104,7 +97,8 @@
      * @param certPathList the certPathList generated thus far
      */
     abstract void verifyCert(X509Certificate cert, State currentState,
-        List<X509Certificate> certPathList) throws GeneralSecurityException;
+                             List<X509Certificate> certPathList)
+        throws GeneralSecurityException;
 
     /**
      * Verifies whether the input certificate completes the path.
@@ -123,7 +117,7 @@
      * @param certPathList the certification path list
      */
     abstract void addCertToPath(X509Certificate cert,
-        LinkedList<X509Certificate> certPathList);
+                                LinkedList<X509Certificate> certPathList);
 
     /**
      * Removes final certificate from the certPathList
@@ -147,7 +141,8 @@
      *         is a grandparent, etc.
      */
     static int distance(GeneralNameInterface base,
-        GeneralNameInterface test, int incomparable) {
+                        GeneralNameInterface test, int incomparable)
+    {
         switch (base.constrains(test)) {
         case GeneralNameInterface.NAME_DIFF_TYPE:
             if (debug != null) {
@@ -192,7 +187,8 @@
      *         some number of down hops.
      */
     static int hops(GeneralNameInterface base, GeneralNameInterface test,
-        int incomparable) {
+                    int incomparable)
+    {
         int baseRtest = base.constrains(test);
         switch (baseRtest) {
         case GeneralNameInterface.NAME_DIFF_TYPE:
@@ -282,9 +278,9 @@
      * @throws IOException if certificate does not get closer
      */
     static int targetDistance(NameConstraintsExtension constraints,
-            X509Certificate cert, GeneralNameInterface target)
-            throws IOException {
-
+                              X509Certificate cert, GeneralNameInterface target)
+            throws IOException
+    {
         /* ensure that certificate satisfies existing name constraints */
         if (constraints != null && !constraints.verify(cert)) {
             throw new IOException("certificate does not satisfy existing name "
@@ -295,7 +291,7 @@
         try {
             certImpl = X509CertImpl.toImpl(cert);
         } catch (CertificateException e) {
-            throw (IOException)new IOException("Invalid certificate").initCause(e);
+            throw new IOException("Invalid certificate", e);
         }
         /* see if certificate subject matches target */
         X500Name subject = X500Name.asX500Name(certImpl.getSubjectX500Principal());
@@ -398,13 +394,13 @@
      */
     Set<String> getMatchingPolicies() {
         if (matchingPolicies != null) {
-            Set<String> initialPolicies = buildParams.getInitialPolicies();
+            Set<String> initialPolicies = buildParams.initialPolicies();
             if ((!initialPolicies.isEmpty()) &&
                 (!initialPolicies.contains(PolicyChecker.ANY_POLICY)) &&
-                (buildParams.isPolicyMappingInhibited()))
+                (buildParams.policyMappingInhibited()))
             {
-                initialPolicies.add(PolicyChecker.ANY_POLICY);
-                matchingPolicies = initialPolicies;
+                matchingPolicies = new HashSet<>(initialPolicies);
+                matchingPolicies.add(PolicyChecker.ANY_POLICY);
             } else {
                 // we just return an empty set to make sure that there is
                 // at least a certificate policies extension in the cert
@@ -429,13 +425,15 @@
      * Returns true iff resultCerts changed (a cert was added to the collection)
      */
     boolean addMatchingCerts(X509CertSelector selector,
-            Collection<CertStore> certStores,
-            Collection<X509Certificate> resultCerts, boolean checkAll) {
+                             Collection<CertStore> certStores,
+                             Collection<X509Certificate> resultCerts,
+                             boolean checkAll)
+    {
         X509Certificate targetCert = selector.getCertificate();
         if (targetCert != null) {
             // no need to search CertStores
             if (selector.match(targetCert) && !X509CertImpl.isSelfSigned
-                (targetCert, buildParams.getSigProvider())) {
+                (targetCert, buildParams.sigProvider())) {
                 if (debug != null) {
                     debug.println("Builder.addMatchingCerts: adding target cert");
                 }
@@ -450,7 +448,7 @@
                                         store.getCertificates(selector);
                 for (Certificate cert : certs) {
                     if (!X509CertImpl.isSelfSigned
-                        ((X509Certificate)cert, buildParams.getSigProvider())) {
+                        ((X509Certificate)cert, buildParams.sigProvider())) {
                         if (resultCerts.add((X509Certificate)cert)) {
                             add = true;
                         }
@@ -471,16 +469,4 @@
         }
         return add;
     }
-
-    /**
-     * Returns true if CertStore is local. Currently, returns true if
-     * type is Collection or if it has been initialized with
-     * CollectionCertStoreParameters. A new API method should be added
-     * to CertStore that returns local or remote.
-     */
-    static boolean isLocalCertStore(CertStore certStore) {
-        return (certStore.getType().equals("Collection") ||
-                certStore.getCertStoreParameters() instanceof
-                CollectionCertStoreParameters);
-    }
 }
--- a/src/share/classes/sun/security/provider/certpath/CertId.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/provider/certpath/CertId.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2013, 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
@@ -29,8 +29,10 @@
 import java.math.BigInteger;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
 import java.security.cert.X509Certificate;
 import java.util.Arrays;
+import javax.security.auth.x500.X500Principal;
 import sun.misc.HexDumpEncoder;
 import sun.security.x509.*;
 import sun.security.util.*;
@@ -70,6 +72,13 @@
     public CertId(X509Certificate issuerCert, SerialNumber serialNumber)
         throws IOException {
 
+        this(issuerCert.getSubjectX500Principal(),
+             issuerCert.getPublicKey(), serialNumber);
+    }
+
+    public CertId(X500Principal issuerName, PublicKey issuerKey,
+                  SerialNumber serialNumber) throws IOException {
+
         // compute issuerNameHash
         MessageDigest md = null;
         try {
@@ -78,11 +87,11 @@
             throw new IOException("Unable to create CertId", nsae);
         }
         hashAlgId = SHA1_ALGID;
-        md.update(issuerCert.getSubjectX500Principal().getEncoded());
+        md.update(issuerName.getEncoded());
         issuerNameHash = md.digest();
 
         // compute issuerKeyHash (remove the tag and length)
-        byte[] pubKey = issuerCert.getPublicKey().getEncoded();
+        byte[] pubKey = issuerKey.getEncoded();
         DerValue val = new DerValue(pubKey);
         DerValue[] seq = new DerValue[2];
         seq[0] = val.data.getDerValue(); // AlgorithmID
@@ -94,7 +103,7 @@
 
         if (debug) {
             HexDumpEncoder encoder = new HexDumpEncoder();
-            System.out.println("Issuer Certificate is " + issuerCert);
+            System.out.println("Issuer Name is " + issuerName);
             System.out.println("issuerNameHash is " +
                 encoder.encodeBuffer(issuerNameHash));
             System.out.println("issuerKeyHash is " +
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/provider/certpath/CertPathChecker.java	Thu Nov 09 06:08:09 2017 +0000
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2012, 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.provider.certpath;
+
+import java.security.cert.Certificate;
+import java.security.cert.CertPathValidatorException;
+
+/**
+ * <p>Performs one or more checks on each {@code Certificate} of a
+ * {@code CertPath}.
+ *
+ * <p>A {@code CertPathChecker} implementation is typically created to extend
+ * a certification path validation algorithm. For example, an implementation
+ * may check for and process a critical private extension of each certificate
+ * in a certification path.
+ *
+ * @since 1.8
+ */
+public interface CertPathChecker {
+
+    /**
+     * Initializes the internal state of this {@code CertPathChecker}.
+     *
+     * <p>The {@code forward} flag specifies the order that certificates will
+     * be passed to the {@link #check check} method (forward or reverse).
+     *
+     * @param forward the order that certificates are presented to the
+     *        {@code check} method. If {@code true}, certificates are
+     *        presented from target to trust anchor (forward); if
+     *        {@code false}, from trust anchor to target (reverse).
+     * @throws CertPathValidatorException if this {@code CertPathChecker} is
+     *         unable to check certificates in the specified order
+     */
+    void init(boolean forward) throws CertPathValidatorException;
+
+    /**
+     * Indicates if forward checking is supported. Forward checking refers
+     * to the ability of the {@code CertPathChecker} to perform its checks
+     * when certificates are presented to the {@code check} method in the
+     * forward direction (from target to trust anchor).
+     *
+     * @return {@code true} if forward checking is supported, {@code false}
+     *         otherwise
+     */
+    boolean isForwardCheckingSupported();
+
+    /**
+     * Performs the check(s) on the specified certificate using its internal
+     * state. The certificates are presented in the order specified by the
+     * {@code init} method.
+     *
+     * @param cert the {@code Certificate} to be checked
+     * @throws CertPathValidatorException if the specified certificate does
+     *         not pass the check
+     */
+    void check(Certificate cert) throws CertPathValidatorException;
+}
--- a/src/share/classes/sun/security/provider/certpath/CertStoreHelper.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/provider/certpath/CertStoreHelper.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2012, 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
@@ -35,6 +35,7 @@
 import java.security.PrivilegedActionException;
 import java.security.PrivilegedExceptionAction;
 import java.security.cert.CertStore;
+import java.security.cert.CertStoreException;
 import java.security.cert.X509CertSelector;
 import java.security.cert.X509CRLSelector;
 import javax.security.auth.x500.X500Principal;
@@ -82,9 +83,8 @@
                                 = (CertStoreHelper)c.newInstance();
                             cache.put(type, csh);
                             return csh;
-                        } catch (InstantiationException e) {
-                            throw new AssertionError(e);
-                        } catch (IllegalAccessException e) {
+                        } catch (InstantiationException |
+                                 IllegalAccessException e) {
                             throw new AssertionError(e);
                         }
                     }
@@ -96,6 +96,25 @@
         }
     }
 
+    static boolean isCausedByNetworkIssue(String type, CertStoreException cse) {
+        switch (type) {
+            case "LDAP":
+            case "SSLServer":
+                try {
+                    CertStoreHelper csh = CertStoreHelper.getInstance(type);
+                    return csh.isCausedByNetworkIssue(cse);
+                } catch (NoSuchAlgorithmException nsae) {
+                    return false;
+                }
+            case "URI":
+                Throwable t = cse.getCause();
+                return (t != null && t instanceof IOException);
+            default:
+                // we don't know about any other remote CertStore types
+                return false;
+        }
+    }
+
     /**
      * Returns a CertStore using the given URI as parameters.
      */
@@ -119,4 +138,10 @@
                          Collection<X500Principal> certIssuers,
                          String dn)
         throws IOException;
+
+    /**
+     * Returns true if the cause of the CertStoreException is a network
+     * related issue.
+     */
+    public abstract boolean isCausedByNetworkIssue(CertStoreException e);
 }
--- a/src/share/classes/sun/security/provider/certpath/CollectionCertStore.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/provider/certpath/CollectionCertStore.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2012, 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
@@ -31,7 +31,6 @@
 import java.util.Collection;
 import java.util.ConcurrentModificationException;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.security.cert.CertSelector;
 import java.security.cert.CertStore;
 import java.security.cert.CertStoreException;
@@ -114,6 +113,7 @@
      *         match the specified selector
      * @throws CertStoreException if an exception occurs
      */
+    @Override
     public Collection<Certificate> engineGetCertificates
             (CertSelector selector) throws CertStoreException {
         if (coll == null) {
@@ -122,18 +122,15 @@
         // Tolerate a few ConcurrentModificationExceptions
         for (int c = 0; c < 10; c++) {
             try {
-                HashSet<Certificate> result = new HashSet<Certificate>();
-                Iterator<?> i = coll.iterator();
+                HashSet<Certificate> result = new HashSet<>();
                 if (selector != null) {
-                    while (i.hasNext()) {
-                        Object o = i.next();
+                    for (Object o : coll) {
                         if ((o instanceof Certificate) &&
                             selector.match((Certificate) o))
                             result.add((Certificate)o);
                     }
                 } else {
-                    while (i.hasNext()) {
-                        Object o = i.next();
+                    for (Object o : coll) {
                         if (o instanceof Certificate)
                             result.add((Certificate)o);
                     }
@@ -157,6 +154,7 @@
      *         match the specified selector
      * @throws CertStoreException if an exception occurs
      */
+    @Override
     public Collection<CRL> engineGetCRLs(CRLSelector selector)
         throws CertStoreException
     {
@@ -166,22 +164,19 @@
         // Tolerate a few ConcurrentModificationExceptions
         for (int c = 0; c < 10; c++) {
             try {
-                HashSet<CRL> result = new HashSet<CRL>();
-                Iterator<?> i = coll.iterator();
+                HashSet<CRL> result = new HashSet<>();
                 if (selector != null) {
-                    while (i.hasNext()) {
-                        Object o = i.next();
+                    for (Object o : coll) {
                         if ((o instanceof CRL) && selector.match((CRL) o))
                             result.add((CRL)o);
                     }
                 } else {
-                    while (i.hasNext()) {
-                        Object o = i.next();
+                    for (Object o : coll) {
                         if (o instanceof CRL)
                             result.add((CRL)o);
                     }
                 }
-                return(result);
+                return result;
             } catch (ConcurrentModificationException e) { }
         }
         throw new ConcurrentModificationException("Too many "
--- a/src/share/classes/sun/security/provider/certpath/ConstraintsChecker.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/provider/certpath/ConstraintsChecker.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2012, 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,19 +25,20 @@
 
 package sun.security.provider.certpath;
 
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Set;
-import java.util.HashSet;
 import java.io.IOException;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateException;
 import java.security.cert.CertPathValidatorException;
-import java.security.cert.X509Certificate;
 import java.security.cert.PKIXCertPathChecker;
 import java.security.cert.PKIXReason;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
 import sun.security.util.Debug;
-import sun.security.x509.PKIXExtensions;
+import static sun.security.x509.PKIXExtensions.*;
 import sun.security.x509.NameConstraintsExtension;
 import sun.security.x509.X509CertImpl;
 
@@ -66,13 +67,12 @@
      * Creates a ConstraintsChecker.
      *
      * @param certPathLength the length of the certification path
-     * @throws CertPathValidatorException if the checker cannot be initialized
      */
-    ConstraintsChecker(int certPathLength) throws CertPathValidatorException {
+    ConstraintsChecker(int certPathLength) {
         this.certPathLength = certPathLength;
-        init(false);
     }
 
+    @Override
     public void init(boolean forward) throws CertPathValidatorException {
         if (!forward) {
             i = 0;
@@ -84,15 +84,17 @@
         }
     }
 
+    @Override
     public boolean isForwardCheckingSupported() {
         return false;
     }
 
+    @Override
     public Set<String> getSupportedExtensions() {
         if (supportedExts == null) {
-            supportedExts = new HashSet<String>();
-            supportedExts.add(PKIXExtensions.BasicConstraints_Id.toString());
-            supportedExts.add(PKIXExtensions.NameConstraints_Id.toString());
+            supportedExts = new HashSet<String>(2);
+            supportedExts.add(BasicConstraints_Id.toString());
+            supportedExts.add(NameConstraints_Id.toString());
             supportedExts = Collections.unmodifiableSet(supportedExts);
         }
         return supportedExts;
@@ -104,14 +106,15 @@
      *
      * @param cert the <code>Certificate</code> to be checked
      * @param unresCritExts a <code>Collection</code> of OID strings
-     * representing the current set of unresolved critical extensions
+     *        representing the current set of unresolved critical extensions
      * @throws CertPathValidatorException if the specified certificate
-     * does not pass the check
+     *         does not pass the check
      */
+    @Override
     public void check(Certificate cert, Collection<String> unresCritExts)
         throws CertPathValidatorException
     {
-        X509Certificate currCert = (X509Certificate) cert;
+        X509Certificate currCert = (X509Certificate)cert;
 
         i++;
         // MUST run NC check second, since it depends on BC check to
@@ -120,8 +123,8 @@
         verifyNameConstraints(currCert);
 
         if (unresCritExts != null && !unresCritExts.isEmpty()) {
-            unresCritExts.remove(PKIXExtensions.BasicConstraints_Id.toString());
-            unresCritExts.remove(PKIXExtensions.NameConstraints_Id.toString());
+            unresCritExts.remove(BasicConstraints_Id.toString());
+            unresCritExts.remove(NameConstraints_Id.toString());
         }
     }
 
@@ -166,9 +169,9 @@
     /**
      * Helper to fold sets of name constraints together
      */
-    static NameConstraintsExtension
-        mergeNameConstraints(X509Certificate currCert,
-            NameConstraintsExtension prevNC) throws CertPathValidatorException
+    static NameConstraintsExtension mergeNameConstraints(
+        X509Certificate currCert, NameConstraintsExtension prevNC)
+        throws CertPathValidatorException
     {
         X509CertImpl currCertImpl;
         try {
@@ -197,7 +200,7 @@
                 // Make sure we do a clone here, because we're probably
                 // going to modify this object later and we don't want to
                 // be sharing it with a Certificate object!
-                return (NameConstraintsExtension) newConstraints.clone();
+                return (NameConstraintsExtension)newConstraints.clone();
             }
         } else {
             try {
--- a/src/share/classes/sun/security/provider/certpath/CrlRevocationChecker.java	Thu Aug 03 07:28:01 2017 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,800 +0,0 @@
-/*
- * Copyright (c) 2000, 2013, 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.provider.certpath;
-
-import java.math.BigInteger;
-import java.util.Arrays;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.Iterator;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.NoSuchAlgorithmException;
-import java.security.PublicKey;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateRevokedException;
-import java.security.cert.CertPathBuilder;
-import java.security.cert.CertPathBuilderException;
-import java.security.cert.CertPathValidatorException;
-import java.security.cert.CertPathValidatorException.BasicReason;
-import java.security.cert.CertStore;
-import java.security.cert.CollectionCertStoreParameters;
-import java.security.cert.CRLException;
-import java.security.cert.CRLReason;
-import java.security.cert.PKIXBuilderParameters;
-import java.security.cert.PKIXCertPathBuilderResult;
-import java.security.cert.PKIXCertPathChecker;
-import java.security.cert.PKIXParameters;
-import java.security.cert.TrustAnchor;
-import java.security.cert.X509Certificate;
-import java.security.cert.X509CertSelector;
-import java.security.cert.X509CRL;
-import java.security.cert.X509CRLEntry;
-import java.security.cert.X509CRLSelector;
-import java.security.interfaces.DSAPublicKey;
-import sun.security.util.Debug;
-import sun.security.x509.AccessDescription;
-import sun.security.x509.AuthorityInfoAccessExtension;
-import sun.security.x509.CRLDistributionPointsExtension;
-import sun.security.x509.DistributionPoint;
-import sun.security.x509.GeneralName;
-import sun.security.x509.GeneralNames;
-import sun.security.x509.PKIXExtensions;
-import sun.security.x509.X500Name;
-import sun.security.x509.X509CertImpl;
-import sun.security.x509.X509CRLEntryImpl;
-
-/**
- * CrlRevocationChecker is a <code>PKIXCertPathChecker</code> that checks
- * revocation status information on a PKIX certificate using CRLs obtained
- * from one or more <code>CertStores</code>. This is based on section 6.3
- * of RFC 3280 (http://www.ietf.org/rfc/rfc3280.txt).
- *
- * @since       1.4
- * @author      Seth Proctor
- * @author      Steve Hanna
- */
-class CrlRevocationChecker extends PKIXCertPathChecker {
-
-    private static final Debug debug = Debug.getInstance("certpath");
-    private final TrustAnchor mAnchor;
-    private final List<CertStore> mStores;
-    private final String mSigProvider;
-    private final Date mCurrentTime;
-    private PublicKey mPrevPubKey;
-    private boolean mCRLSignFlag;
-    private HashSet<X509CRL> mPossibleCRLs;
-    private HashSet<X509CRL> mApprovedCRLs;
-    private final PKIXParameters mParams;
-    private static final boolean [] mCrlSignUsage =
-        { false, false, false, false, false, false, true };
-    private static final boolean[] ALL_REASONS =
-        {true, true, true, true, true, true, true, true, true};
-    private boolean mOnlyEECert = false;
-
-    // Maximum clock skew in milliseconds (15 minutes) allowed when checking
-    // validity of CRLs
-    private static final long MAX_CLOCK_SKEW = 900000;
-
-    /**
-     * Creates a <code>CrlRevocationChecker</code>.
-     *
-     * @param anchor anchor selected to validate the target certificate
-     * @param params <code>PKIXParameters</code> to be used for
-     *               finding certificates and CRLs, etc.
-     */
-    CrlRevocationChecker(TrustAnchor anchor, PKIXParameters params)
-        throws CertPathValidatorException
-    {
-        this(anchor, params, null);
-    }
-
-    /**
-     * Creates a <code>CrlRevocationChecker</code>, allowing
-     * extra certificates to be supplied beyond those contained
-     * in the <code>PKIXParameters</code>.
-     *
-     * @param anchor anchor selected to validate the target certificate
-     * @param params <code>PKIXParameters</code> to be used for
-     *               finding certificates and CRLs, etc.
-     * @param certs a <code>Collection</code> of certificates
-     *              that may be useful, beyond those available
-     *              through <code>params</code> (<code>null</code>
-     *              if none)
-     */
-    CrlRevocationChecker(TrustAnchor anchor, PKIXParameters params,
-        Collection<X509Certificate> certs) throws CertPathValidatorException
-    {
-        this(anchor, params, certs, false);
-    }
-
-    CrlRevocationChecker(TrustAnchor anchor, PKIXParameters params,
-        Collection<X509Certificate> certs, boolean onlyEECert)
-        throws CertPathValidatorException {
-        mAnchor = anchor;
-        mParams = params;
-        mStores = new ArrayList<CertStore>(params.getCertStores());
-        mSigProvider = params.getSigProvider();
-        if (certs != null) {
-            try {
-                mStores.add(CertStore.getInstance("Collection",
-                    new CollectionCertStoreParameters(certs)));
-            } catch (Exception e) {
-                // should never occur but not necessarily fatal, so log it,
-                // ignore and continue
-                if (debug != null) {
-                    debug.println("CrlRevocationChecker: " +
-                        "error creating Collection CertStore: " + e);
-                }
-            }
-        }
-        Date testDate = params.getDate();
-        mCurrentTime = (testDate != null ? testDate : new Date());
-        mOnlyEECert = onlyEECert;
-        init(false);
-    }
-
-    /**
-     * Initializes the internal state of the checker from parameters
-     * specified in the constructor
-     */
-    public void init(boolean forward) throws CertPathValidatorException
-    {
-        if (!forward) {
-            if (mAnchor != null) {
-                if (mAnchor.getCAPublicKey() != null) {
-                    mPrevPubKey = mAnchor.getCAPublicKey();
-                } else {
-                    mPrevPubKey = mAnchor.getTrustedCert().getPublicKey();
-                }
-            } else {
-                mPrevPubKey = null;
-            }
-            mCRLSignFlag = true;
-        } else {
-            throw new CertPathValidatorException("forward checking "
-                                + "not supported");
-        }
-    }
-
-    public boolean isForwardCheckingSupported() {
-        return false;
-    }
-
-    public Set<String> getSupportedExtensions() {
-        return null;
-    }
-
-    /**
-     * Performs the revocation status check on the certificate using
-     * its internal state.
-     *
-     * @param cert the Certificate
-     * @param unresolvedCritExts a Collection of the unresolved critical
-     * extensions
-     * @exception CertPathValidatorException Exception thrown if
-     * certificate does not verify
-     */
-    public void check(Certificate cert, Collection<String> unresolvedCritExts)
-        throws CertPathValidatorException
-    {
-        X509Certificate currCert = (X509Certificate) cert;
-        verifyRevocationStatus(currCert, mPrevPubKey, mCRLSignFlag, true);
-
-        // Make new public key if parameters are missing
-        PublicKey cKey = currCert.getPublicKey();
-        if (cKey instanceof DSAPublicKey &&
-            ((DSAPublicKey)cKey).getParams() == null) {
-            // cKey needs to inherit DSA parameters from prev key
-            cKey = BasicChecker.makeInheritedParamsKey(cKey, mPrevPubKey);
-        }
-        mPrevPubKey = cKey;
-        mCRLSignFlag = certCanSignCrl(currCert);
-    }
-
-    /**
-     * Performs the revocation status check on the certificate using
-     * the provided state variables, as well as the constant internal
-     * data.
-     *
-     * @param currCert the Certificate
-     * @param prevKey the previous PublicKey in the chain
-     * @param signFlag a boolean as returned from the last call, or true
-     * if this is the first cert in the chain
-     * @return a boolean specifying if the cert is allowed to vouch for the
-     * validity of a CRL for the next iteration
-     * @exception CertPathValidatorException Exception thrown if
-     *            certificate does not verify.
-     */
-    public boolean check(X509Certificate currCert, PublicKey prevKey,
-        boolean signFlag) throws CertPathValidatorException
-    {
-        verifyRevocationStatus(currCert, prevKey, signFlag, true);
-        return certCanSignCrl(currCert);
-    }
-
-    /**
-     * Checks that a cert can be used to verify a CRL.
-     *
-     * @param currCert an X509Certificate to check
-     * @return a boolean specifying if the cert is allowed to vouch for the
-     * validity of a CRL
-     */
-    static boolean certCanSignCrl(X509Certificate currCert) {
-        // if the cert doesn't include the key usage ext, or
-        // the key usage ext asserts cRLSigning, return true,
-        // otherwise return false.
-        boolean[] kbools = currCert.getKeyUsage();
-        if (kbools != null) {
-            return kbools[6];
-        }
-        return false;
-    }
-
-    /**
-     * Internal method to start the verification of a cert
-     */
-    private void verifyRevocationStatus(X509Certificate currCert,
-        PublicKey prevKey, boolean signFlag, boolean allowSeparateKey)
-        throws CertPathValidatorException
-    {
-        verifyRevocationStatus(currCert, prevKey, signFlag,
-                   allowSeparateKey, null, mParams.getTrustAnchors());
-    }
-
-    /**
-     * Internal method to start the verification of a cert
-     * @param stackedCerts a <code>Set</code> of <code>X509Certificate</code>s>
-     *                     whose revocation status depends on the
-     *                     non-revoked status of this cert. To avoid
-     *                     circular dependencies, we assume they're
-     *                     revoked while checking the revocation
-     *                     status of this cert.
-     * @param trustAnchors a <code>Set</code> of <code>TrustAnchor</code>s
-     */
-    private void verifyRevocationStatus(X509Certificate currCert,
-        PublicKey prevKey, boolean signFlag, boolean allowSeparateKey,
-        Set<X509Certificate> stackedCerts,
-        Set<TrustAnchor> trustAnchors) throws CertPathValidatorException {
-
-        String msg = "revocation status";
-        if (debug != null) {
-            debug.println("CrlRevocationChecker.verifyRevocationStatus()" +
-                " ---checking " + msg + "...");
-        }
-
-        if (mOnlyEECert && currCert.getBasicConstraints() != -1) {
-            if (debug != null) {
-                debug.println("Skipping revocation check, not end entity cert");
-            }
-            return;
-        }
-
-        // reject circular dependencies - RFC 3280 is not explicit on how
-        // to handle this, so we feel it is safest to reject them until
-        // the issue is resolved in the PKIX WG.
-        if ((stackedCerts != null) && stackedCerts.contains(currCert)) {
-            if (debug != null) {
-                debug.println("CrlRevocationChecker.verifyRevocationStatus()" +
-                    " circular dependency");
-            }
-            throw new CertPathValidatorException
-                ("Could not determine revocation status", null, null, -1,
-                 BasicReason.UNDETERMINED_REVOCATION_STATUS);
-        }
-
-        // init the state for this run
-        mPossibleCRLs = new HashSet<X509CRL>();
-        mApprovedCRLs = new HashSet<X509CRL>();
-        boolean[] reasonsMask = new boolean[9];
-
-        try {
-            X509CRLSelector sel = new X509CRLSelector();
-            sel.setCertificateChecking(currCert);
-            CertPathHelper.setDateAndTime(sel, mCurrentTime, MAX_CLOCK_SKEW);
-
-            for (CertStore mStore : mStores) {
-                for (java.security.cert.CRL crl : mStore.getCRLs(sel)) {
-                    mPossibleCRLs.add((X509CRL)crl);
-                }
-            }
-            // all CRLs returned by the DP Fetcher have also been verified
-            mApprovedCRLs.addAll(DistributionPointFetcher.getCRLs(sel, signFlag,
-                prevKey, mSigProvider, mStores, reasonsMask, trustAnchors,
-                mParams.getDate()));
-        } catch (Exception e) {
-            if (debug != null) {
-                debug.println("CrlRevocationChecker.verifyRevocationStatus() "
-                    + "unexpected exception: " + e.getMessage());
-            }
-            throw new CertPathValidatorException(e);
-        }
-
-        if (debug != null) {
-            debug.println("CrlRevocationChecker.verifyRevocationStatus() " +
-                "crls.size() = " + mPossibleCRLs.size());
-        }
-        if (!mPossibleCRLs.isEmpty()) {
-            // Now that we have a list of possible CRLs, see which ones can
-            // be approved
-            mApprovedCRLs.addAll(verifyPossibleCRLs(mPossibleCRLs, currCert,
-                signFlag, prevKey, reasonsMask, trustAnchors));
-        }
-        if (debug != null) {
-            debug.println("CrlRevocationChecker.verifyRevocationStatus() " +
-                "approved crls.size() = " + mApprovedCRLs.size());
-        }
-
-        // make sure that we have at least one CRL that _could_ cover
-        // the certificate in question and all reasons are covered
-        if (mApprovedCRLs.isEmpty() ||
-            !Arrays.equals(reasonsMask, ALL_REASONS)) {
-            if (allowSeparateKey) {
-                verifyWithSeparateSigningKey(currCert, prevKey, signFlag,
-                                             stackedCerts);
-                return;
-            } else {
-                throw new CertPathValidatorException
-                ("Could not determine revocation status", null, null, -1,
-                 BasicReason.UNDETERMINED_REVOCATION_STATUS);
-            }
-        }
-
-        // See if the cert is in the set of approved crls.
-        if (debug != null) {
-            BigInteger sn = currCert.getSerialNumber();
-            debug.println("CrlRevocationChecker.verifyRevocationStatus() " +
-                            "starting the final sweep...");
-            debug.println("CrlRevocationChecker.verifyRevocationStatus" +
-                            " cert SN: " + sn.toString());
-        }
-
-        CRLReason reasonCode = CRLReason.UNSPECIFIED;
-        X509CRLEntryImpl entry = null;
-        for (X509CRL crl : mApprovedCRLs) {
-            X509CRLEntry e = crl.getRevokedCertificate(currCert);
-            if (e != null) {
-                try {
-                    entry = X509CRLEntryImpl.toImpl(e);
-                } catch (CRLException ce) {
-                    throw new CertPathValidatorException(ce);
-                }
-                if (debug != null) {
-                    debug.println("CrlRevocationChecker.verifyRevocationStatus"
-                        + " CRL entry: " + entry.toString());
-                }
-
-                /*
-                 * Abort CRL validation and throw exception if there are any
-                 * unrecognized critical CRL entry extensions (see section
-                 * 5.3 of RFC 3280).
-                 */
-                Set<String> unresCritExts = entry.getCriticalExtensionOIDs();
-                if (unresCritExts != null && !unresCritExts.isEmpty()) {
-                    /* remove any that we will process */
-                    unresCritExts.remove
-                        (PKIXExtensions.ReasonCode_Id.toString());
-                    unresCritExts.remove
-                        (PKIXExtensions.CertificateIssuer_Id.toString());
-                    if (!unresCritExts.isEmpty()) {
-                        if (debug != null) {
-                            debug.println("Unrecognized "
-                            + "critical extension(s) in revoked CRL entry: "
-                            + unresCritExts);
-                        }
-                        throw new CertPathValidatorException
-                        ("Could not determine revocation status", null, null,
-                         -1, BasicReason.UNDETERMINED_REVOCATION_STATUS);
-                    }
-                }
-
-                reasonCode = entry.getRevocationReason();
-                if (reasonCode == null) {
-                    reasonCode = CRLReason.UNSPECIFIED;
-                }
-                Throwable t = new CertificateRevokedException
-                    (entry.getRevocationDate(), reasonCode,
-                     crl.getIssuerX500Principal(), entry.getExtensions());
-                throw new CertPathValidatorException(t.getMessage(), t,
-                    null, -1, BasicReason.REVOKED);
-            }
-        }
-    }
-
-    /**
-     * We have a cert whose revocation status couldn't be verified by
-     * a CRL issued by the cert that issued the CRL. See if we can
-     * find a valid CRL issued by a separate key that can verify the
-     * revocation status of this certificate.
-     * <p>
-     * Note that this does not provide support for indirect CRLs,
-     * only CRLs signed with a different key (but the same issuer
-     * name) as the certificate being checked.
-     *
-     * @param currCert the <code>X509Certificate</code> to be checked
-     * @param prevKey the <code>PublicKey</code> that failed
-     * @param signFlag <code>true</code> if that key was trusted to sign CRLs
-     * @param stackedCerts a <code>Set</code> of <code>X509Certificate</code>s>
-     *                     whose revocation status depends on the
-     *                     non-revoked status of this cert. To avoid
-     *                     circular dependencies, we assume they're
-     *                     revoked while checking the revocation
-     *                     status of this cert.
-     * @throws CertPathValidatorException if the cert's revocation status
-     *         cannot be verified successfully with another key
-     */
-    private void verifyWithSeparateSigningKey(X509Certificate currCert,
-        PublicKey prevKey, boolean signFlag, Set<X509Certificate> stackedCerts)
-        throws CertPathValidatorException {
-        String msg = "revocation status";
-        if (debug != null) {
-            debug.println(
-                "CrlRevocationChecker.verifyWithSeparateSigningKey()" +
-                " ---checking " + msg + "...");
-        }
-
-        // reject circular dependencies - RFC 3280 is not explicit on how
-        // to handle this, so we feel it is safest to reject them until
-        // the issue is resolved in the PKIX WG.
-        if ((stackedCerts != null) && stackedCerts.contains(currCert)) {
-            if (debug != null) {
-                debug.println(
-                    "CrlRevocationChecker.verifyWithSeparateSigningKey()" +
-                    " circular dependency");
-            }
-            throw new CertPathValidatorException
-                ("Could not determine revocation status", null, null,
-                 -1, BasicReason.UNDETERMINED_REVOCATION_STATUS);
-        }
-
-        // If prevKey wasn't trusted, maybe we just didn't have the right
-        // path to it. Don't rule that key out.
-        if (!signFlag) {
-            prevKey = null;
-        }
-
-        // Try to find another key that might be able to sign
-        // CRLs vouching for this cert.
-        buildToNewKey(currCert, prevKey, stackedCerts);
-    }
-
-    /**
-     * Tries to find a CertPath that establishes a key that can be
-     * used to verify the revocation status of a given certificate.
-     * Ignores keys that have previously been tried. Throws a
-     * CertPathValidatorException if no such key could be found.
-     *
-     * @param currCert the <code>X509Certificate</code> to be checked
-     * @param prevKey the <code>PublicKey</code> of the certificate whose key
-     *    cannot be used to vouch for the CRL and should be ignored
-     * @param stackedCerts a <code>Set</code> of <code>X509Certificate</code>s>
-     *                     whose revocation status depends on the
-     *                     establishment of this path.
-     * @throws CertPathValidatorException on failure
-     */
-    private void buildToNewKey(X509Certificate currCert,
-        PublicKey prevKey, Set<X509Certificate> stackedCerts)
-        throws CertPathValidatorException {
-
-        if (debug != null) {
-            debug.println("CrlRevocationChecker.buildToNewKey()" +
-                          " starting work");
-        }
-        Set<PublicKey> badKeys = new HashSet<PublicKey>();
-        if (prevKey != null) {
-            badKeys.add(prevKey);
-        }
-        X509CertSelector certSel = new RejectKeySelector(badKeys);
-        certSel.setSubject(currCert.getIssuerX500Principal());
-        certSel.setKeyUsage(mCrlSignUsage);
-
-        Set<TrustAnchor> newAnchors =
-            (mAnchor == null ? mParams.getTrustAnchors() :
-                                Collections.singleton(mAnchor));
-
-        PKIXBuilderParameters builderParams;
-        if (mParams instanceof PKIXBuilderParameters) {
-            builderParams = (PKIXBuilderParameters) mParams.clone();
-            builderParams.setTargetCertConstraints(certSel);
-            // Policy qualifiers must be rejected, since we don't have
-            // any way to convey them back to the application.
-            builderParams.setPolicyQualifiersRejected(true);
-            try {
-                builderParams.setTrustAnchors(newAnchors);
-            } catch (InvalidAlgorithmParameterException iape) {
-                throw new RuntimeException(iape); // should never occur
-            }
-        } else {
-            // It's unfortunate that there's no easy way to make a
-            // PKIXBuilderParameters object from a PKIXParameters
-            // object. This might miss some things if parameters
-            // are added in the future or the validatorParams object
-            // is a custom class derived from PKIXValidatorParameters.
-            try {
-                builderParams = new PKIXBuilderParameters(newAnchors, certSel);
-            } catch (InvalidAlgorithmParameterException iape) {
-                throw new RuntimeException(iape); // should never occur
-            }
-            builderParams.setInitialPolicies(mParams.getInitialPolicies());
-            builderParams.setCertStores(mStores);
-            builderParams.setExplicitPolicyRequired
-                (mParams.isExplicitPolicyRequired());
-            builderParams.setPolicyMappingInhibited
-                (mParams.isPolicyMappingInhibited());
-            builderParams.setAnyPolicyInhibited(mParams.isAnyPolicyInhibited());
-            // Policy qualifiers must be rejected, since we don't have
-            // any way to convey them back to the application.
-            // That's the default, so no need to write code.
-            builderParams.setDate(mParams.getDate());
-            builderParams.setCertPathCheckers(mParams.getCertPathCheckers());
-            builderParams.setSigProvider(mParams.getSigProvider());
-        }
-
-        // Skip revocation during this build to detect circular
-        // references. But check revocation afterwards, using the
-        // key (or any other that works).
-        builderParams.setRevocationEnabled(false);
-
-        // check for AuthorityInformationAccess extension
-        if (Builder.USE_AIA == true) {
-            X509CertImpl currCertImpl = null;
-            try {
-                currCertImpl = X509CertImpl.toImpl(currCert);
-            } catch (CertificateException ce) {
-                // ignore but log it
-                if (debug != null) {
-                    debug.println("CrlRevocationChecker.buildToNewKey: " +
-                        "error decoding cert: " + ce);
-                }
-            }
-            AuthorityInfoAccessExtension aiaExt = null;
-            if (currCertImpl != null) {
-                aiaExt = currCertImpl.getAuthorityInfoAccessExtension();
-            }
-            if (aiaExt != null) {
-                List<AccessDescription> adList = aiaExt.getAccessDescriptions();
-                if (adList != null) {
-                    for (AccessDescription ad : adList) {
-                        CertStore cs = URICertStore.getInstance(ad);
-                        if (cs != null) {
-                            if (debug != null) {
-                                debug.println("adding AIAext CertStore");
-                            }
-                            builderParams.addCertStore(cs);
-                        }
-                    }
-                }
-            }
-        }
-
-        CertPathBuilder builder = null;
-        try {
-            builder = CertPathBuilder.getInstance("PKIX");
-        } catch (NoSuchAlgorithmException nsae) {
-            throw new CertPathValidatorException(nsae);
-        }
-        while (true) {
-            try {
-                if (debug != null) {
-                    debug.println("CrlRevocationChecker.buildToNewKey()" +
-                                  " about to try build ...");
-                }
-                PKIXCertPathBuilderResult cpbr =
-                    (PKIXCertPathBuilderResult) builder.build(builderParams);
-
-                if (debug != null) {
-                    debug.println("CrlRevocationChecker.buildToNewKey()" +
-                                  " about to check revocation ...");
-                }
-                // Now check revocation of all certs in path, assuming that
-                // the stackedCerts are revoked.
-                if (stackedCerts == null) {
-                    stackedCerts = new HashSet<X509Certificate>();
-                }
-                stackedCerts.add(currCert);
-                TrustAnchor ta = cpbr.getTrustAnchor();
-                PublicKey prevKey2 = ta.getCAPublicKey();
-                if (prevKey2 == null) {
-                    prevKey2 = ta.getTrustedCert().getPublicKey();
-                }
-                boolean signFlag = true;
-                List<? extends Certificate> cpList =
-                    cpbr.getCertPath().getCertificates();
-                try {
-                    for (int i = cpList.size()-1; i >= 0; i-- ) {
-                        X509Certificate cert = (X509Certificate) cpList.get(i);
-
-                        if (debug != null) {
-                            debug.println("CrlRevocationChecker.buildToNewKey()"
-                                + " index " + i + " checking " + cert);
-                        }
-                        verifyRevocationStatus(cert, prevKey2, signFlag, true,
-                                stackedCerts, newAnchors);
-                        signFlag = certCanSignCrl(cert);
-                        prevKey2 = cert.getPublicKey();
-                    }
-                } catch (CertPathValidatorException cpve) {
-                    // ignore it and try to get another key
-                    badKeys.add(cpbr.getPublicKey());
-                    continue;
-                }
-
-                if (debug != null) {
-                    debug.println("CrlRevocationChecker.buildToNewKey()" +
-                                  " got key " + cpbr.getPublicKey());
-                }
-                // Now check revocation on the current cert using that key.
-                // If it doesn't check out, try to find a different key.
-                // And if we can't find a key, then return false.
-                PublicKey newKey = cpbr.getPublicKey();
-                try {
-                    verifyRevocationStatus(currCert, newKey, true, false);
-                    // If that passed, the cert is OK!
-                    return;
-                } catch (CertPathValidatorException cpve) {
-                    // If it is revoked, rethrow exception
-                    if (cpve.getReason() == BasicReason.REVOKED) {
-                        throw cpve;
-                    }
-                    // Otherwise, ignore the exception and
-                    // try to get another key.
-                }
-                badKeys.add(newKey);
-            } catch (InvalidAlgorithmParameterException iape) {
-                throw new CertPathValidatorException(iape);
-            } catch (CertPathBuilderException cpbe) {
-                throw new CertPathValidatorException
-                    ("Could not determine revocation status", null, null,
-                     -1, BasicReason.UNDETERMINED_REVOCATION_STATUS);
-            }
-        }
-    }
-
-    /*
-     * This inner class extends the X509CertSelector to add an additional
-     * check to make sure the subject public key isn't on a particular list.
-     * This class is used by buildToNewKey() to make sure the builder doesn't
-     * end up with a CertPath to a public key that has already been rejected.
-     */
-    private static class RejectKeySelector extends X509CertSelector {
-        private final Set<PublicKey> badKeySet;
-
-        /**
-         * Creates a new <code>RejectKeySelector</code>.
-         *
-         * @param badPublicKeys a <code>Set</code> of
-         *                      <code>PublicKey</code>s that
-         *                      should be rejected (or <code>null</code>
-         *                      if no such check should be done)
-         */
-        RejectKeySelector(Set<PublicKey> badPublicKeys) {
-            this.badKeySet = badPublicKeys;
-        }
-
-        /**
-         * Decides whether a <code>Certificate</code> should be selected.
-         *
-         * @param cert the <code>Certificate</code> to be checked
-         * @return <code>true</code> if the <code>Certificate</code> should be
-         *         selected, <code>false</code> otherwise
-         */
-        public boolean match(Certificate cert) {
-            if (!super.match(cert))
-                return(false);
-
-            if (badKeySet.contains(cert.getPublicKey())) {
-                if (debug != null)
-                    debug.println("RejectCertSelector.match: bad key");
-                return false;
-            }
-
-            if (debug != null)
-                debug.println("RejectCertSelector.match: returning true");
-            return true;
-        }
-
-        /**
-         * Return a printable representation of the <code>CertSelector</code>.
-         *
-         * @return a <code>String</code> describing the contents of the
-         *         <code>CertSelector</code>
-         */
-        public String toString() {
-            StringBuilder sb = new StringBuilder();
-            sb.append("RejectCertSelector: [\n");
-            sb.append(super.toString());
-            sb.append(badKeySet);
-            sb.append("]");
-            return sb.toString();
-        }
-    }
-
-    /**
-     * Internal method that verifies a set of possible_crls,
-     * and sees if each is approved, based on the cert.
-     *
-     * @param crls a set of possible CRLs to test for acceptability
-     * @param cert the certificate whose revocation status is being checked
-     * @param signFlag <code>true</code> if prevKey was trusted to sign CRLs
-     * @param prevKey the public key of the issuer of cert
-     * @param reasonsMask the reason code mask
-     * @param trustAnchors a <code>Set</code> of <code>TrustAnchor</code>s>
-     * @return a collection of approved crls (or an empty collection)
-     */
-    private Collection<X509CRL> verifyPossibleCRLs(Set<X509CRL> crls,
-        X509Certificate cert, boolean signFlag, PublicKey prevKey,
-        boolean[] reasonsMask,
-        Set<TrustAnchor> trustAnchors) throws CertPathValidatorException {
-
-        try {
-            X509CertImpl certImpl = X509CertImpl.toImpl(cert);
-            if (debug != null) {
-                debug.println("CRLRevocationChecker.verifyPossibleCRLs: " +
-                        "Checking CRLDPs for "
-                        + certImpl.getSubjectX500Principal());
-            }
-            CRLDistributionPointsExtension ext =
-                certImpl.getCRLDistributionPointsExtension();
-            List<DistributionPoint> points = null;
-            if (ext == null) {
-                // assume a DP with reasons and CRLIssuer fields omitted
-                // and a DP name of the cert issuer.
-                // TODO add issuerAltName too
-                X500Name certIssuer = (X500Name)certImpl.getIssuerDN();
-                DistributionPoint point = new DistributionPoint
-                    (new GeneralNames().add(new GeneralName(certIssuer)),
-                     null, null);
-                points = Collections.singletonList(point);
-            } else {
-                points = ext.get(CRLDistributionPointsExtension.POINTS);
-            }
-            Set<X509CRL> results = new HashSet<X509CRL>();
-            for (Iterator<DistributionPoint> t = points.iterator();
-                 t.hasNext() && !Arrays.equals(reasonsMask, ALL_REASONS); ) {
-                DistributionPoint point = t.next();
-                for (X509CRL crl : crls) {
-                    if (DistributionPointFetcher.verifyCRL(certImpl, point, crl,
-                            reasonsMask, signFlag, prevKey, mSigProvider,
-                            trustAnchors, mStores, mParams.getDate())) {
-                        results.add(crl);
-                    }
-                }
-            }
-            return results;
-        } catch (Exception e) {
-            if (debug != null) {
-                debug.println("Exception while verifying CRL: "+e.getMessage());
-                e.printStackTrace();
-            }
-            return Collections.emptySet();
-        }
-    }
-}
--- a/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2017, 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
@@ -27,14 +27,16 @@
 
 import java.io.*;
 import java.net.URI;
-import java.util.*;
 import java.security.*;
 import java.security.cert.*;
 import javax.security.auth.x500.X500Principal;
+import java.util.*;
 
 import sun.security.action.GetBooleanAction;
 import sun.security.util.Debug;
+import sun.security.validator.Validator;
 import sun.security.util.DerOutputStream;
+import static sun.security.x509.PKIXExtensions.*;
 import sun.security.x509.*;
 
 /**
@@ -78,6 +80,20 @@
      * empty set.
      */
     public static Collection<X509CRL> getCRLs(X509CRLSelector selector,
+            boolean signFlag, PublicKey prevKey, String provider,
+            List<CertStore> certStores, boolean[] reasonsMask,
+            Set<TrustAnchor> trustAnchors, Date validity, String variant)
+            throws CertStoreException
+    {
+        return getCRLs(selector, signFlag, prevKey, null, provider, certStores,
+                reasonsMask, trustAnchors, validity, variant);
+    }
+    /**
+     * Return the X509CRLs matching this selector. The selector must be
+     * an X509CRLSelector with certificateChecking set.
+     */
+    // Called by com.sun.deploy.security.RevocationChecker
+    public static Collection<X509CRL> getCRLs(X509CRLSelector selector,
                                               boolean signFlag,
                                               PublicKey prevKey,
                                               String provider,
@@ -87,6 +103,26 @@
                                               Date validity)
         throws CertStoreException
     {
+        return getCRLs(selector, signFlag, prevKey, null, provider, certStores,
+                reasonsMask, trustAnchors, validity, Validator.VAR_GENERIC);
+    }
+
+    /**
+     * Return the X509CRLs matching this selector. The selector must be
+     * an X509CRLSelector with certificateChecking set.
+     */
+    public static Collection<X509CRL> getCRLs(X509CRLSelector selector,
+                                              boolean signFlag,
+                                              PublicKey prevKey,
+                                              X509Certificate prevCert,
+                                              String provider,
+                                              List<CertStore> certStores,
+                                              boolean[] reasonsMask,
+                                              Set<TrustAnchor> trustAnchors,
+                                              Date validity,
+                                              String variant)
+        throws CertStoreException
+    {
         if (USE_CRLDP == false) {
             return Collections.emptySet();
         }
@@ -110,22 +146,20 @@
             }
             List<DistributionPoint> points =
                     ext.get(CRLDistributionPointsExtension.POINTS);
-            Set<X509CRL> results = new HashSet<X509CRL>();
+            Set<X509CRL> results = new HashSet<>();
             for (Iterator<DistributionPoint> t = points.iterator();
                  t.hasNext() && !Arrays.equals(reasonsMask, ALL_REASONS); ) {
                 DistributionPoint point = t.next();
                 Collection<X509CRL> crls = getCRLs(selector, certImpl,
-                    point, reasonsMask, signFlag, prevKey, provider,
-                    certStores, trustAnchors, validity);
+                    point, reasonsMask, signFlag, prevKey, prevCert, provider,
+                    certStores, trustAnchors, validity, variant);
                 results.addAll(crls);
             }
             if (debug != null) {
                 debug.println("Returning " + results.size() + " CRLs");
             }
             return results;
-        } catch (CertificateException e) {
-            return Collections.emptySet();
-        } catch (IOException e) {
+        } catch (CertificateException | IOException e) {
             return Collections.emptySet();
         }
     }
@@ -133,12 +167,18 @@
     /**
      * Download CRLs from the given distribution point, verify and return them.
      * See the top of the class for current limitations.
+     *
+     * @throws CertStoreException if there is an error retrieving the CRLs
+     *         from one of the GeneralNames and no other CRLs are retrieved from
+     *         the other GeneralNames. If more than one GeneralName throws an
+     *         exception then the one from the last GeneralName is thrown.
      */
     private static Collection<X509CRL> getCRLs(X509CRLSelector selector,
         X509CertImpl certImpl, DistributionPoint point, boolean[] reasonsMask,
-        boolean signFlag, PublicKey prevKey, String provider,
-        List<CertStore> certStores, Set<TrustAnchor> trustAnchors,
-        Date validity) {
+        boolean signFlag, PublicKey prevKey, X509Certificate prevCert,
+        String provider, List<CertStore> certStores,
+        Set<TrustAnchor> trustAnchors, Date validity, String variant)
+            throws CertStoreException {
 
         // check for full name
         GeneralNames fullName = point.getFullName();
@@ -166,35 +206,44 @@
                 return Collections.emptySet();
             }
         }
-        Collection<X509CRL> possibleCRLs = new ArrayList<X509CRL>();
-        Collection<X509CRL> crls = new ArrayList<X509CRL>(2);
+        Collection<X509CRL> possibleCRLs = new ArrayList<>();
+        CertStoreException savedCSE = null;
         for (Iterator<GeneralName> t = fullName.iterator(); t.hasNext(); ) {
-            GeneralName name = t.next();
-            if (name.getType() == GeneralNameInterface.NAME_DIRECTORY) {
-                X500Name x500Name = (X500Name) name.getName();
-                possibleCRLs.addAll(
-                    getCRLs(x500Name, certImpl.getIssuerX500Principal(),
-                            certStores));
-            } else if (name.getType() == GeneralNameInterface.NAME_URI) {
-                URIName uriName = (URIName)name.getName();
-                X509CRL crl = getCRL(uriName);
-                if (crl != null) {
-                    possibleCRLs.add(crl);
+            try {
+                GeneralName name = t.next();
+                if (name.getType() == GeneralNameInterface.NAME_DIRECTORY) {
+                    X500Name x500Name = (X500Name) name.getName();
+                    possibleCRLs.addAll(
+                        getCRLs(x500Name, certImpl.getIssuerX500Principal(),
+                                certStores));
+                } else if (name.getType() == GeneralNameInterface.NAME_URI) {
+                    URIName uriName = (URIName)name.getName();
+                    X509CRL crl = getCRL(uriName);
+                    if (crl != null) {
+                        possibleCRLs.add(crl);
+                    }
                 }
+            } catch (CertStoreException cse) {
+                savedCSE = cse;
             }
         }
+        // only throw CertStoreException if no CRLs are retrieved
+        if (possibleCRLs.isEmpty() && savedCSE != null) {
+            throw savedCSE;
+        }
 
+        Collection<X509CRL> crls = new ArrayList<>(2);
         for (X509CRL crl : possibleCRLs) {
             try {
                 // make sure issuer is not set
                 // we check the issuer in verifyCRLs method
                 selector.setIssuerNames(null);
                 if (selector.match(crl) && verifyCRL(certImpl, point, crl,
-                        reasonsMask, signFlag, prevKey, provider, trustAnchors,
-                        certStores, validity)) {
+                        reasonsMask, signFlag, prevKey, prevCert, provider,
+                        trustAnchors, certStores, validity, variant)) {
                     crls.add(crl);
                 }
-            } catch (Exception e) {
+            } catch (IOException | CRLException e) {
                 // don't add the CRL
                 if (debug != null) {
                     debug.println("Exception verifying CRL: " + e.getMessage());
@@ -208,34 +257,43 @@
     /**
      * Download CRL from given URI.
      */
-    private static X509CRL getCRL(URIName name) {
+    private static X509CRL getCRL(URIName name) throws CertStoreException {
         URI uri = name.getURI();
         if (debug != null) {
             debug.println("Trying to fetch CRL from DP " + uri);
         }
+        CertStore ucs = null;
         try {
-            CertStore ucs = URICertStore.getInstance
+            ucs = URICertStore.getInstance
                 (new URICertStore.URICertStoreParameters(uri));
-            Collection<? extends CRL> crls = ucs.getCRLs(null);
-            if (crls.isEmpty()) {
-                return null;
-            } else {
-                return (X509CRL) crls.iterator().next();
+        } catch (InvalidAlgorithmParameterException |
+                 NoSuchAlgorithmException e) {
+            if (debug != null) {
+                debug.println("Can't create URICertStore: " + e.getMessage());
             }
-        } catch (Exception e) {
-            if (debug != null) {
-                debug.println("Exception getting CRL from CertStore: " + e);
-                e.printStackTrace();
-            }
+            return null;
         }
-        return null;
+
+        Collection<? extends CRL> crls = ucs.getCRLs(null);
+        if (crls.isEmpty()) {
+            return null;
+        } else {
+            return (X509CRL) crls.iterator().next();
+        }
     }
 
     /**
      * Fetch CRLs from certStores.
+     *
+     * @throws CertStoreException if there is an error retrieving the CRLs from
+     *         one of the CertStores and no other CRLs are retrieved from
+     *         the other CertStores. If more than one CertStore throws an
+     *         exception then the one from the last CertStore is thrown.
      */
     private static Collection<X509CRL> getCRLs(X500Name name,
-        X500Principal certIssuer, List<CertStore> certStores)
+                                               X500Principal certIssuer,
+                                               List<CertStore> certStores)
+        throws CertStoreException
     {
         if (debug != null) {
             debug.println("Trying to fetch CRL from DP " + name);
@@ -243,22 +301,28 @@
         X509CRLSelector xcs = new X509CRLSelector();
         xcs.addIssuer(name.asX500Principal());
         xcs.addIssuer(certIssuer);
-        Collection<X509CRL> crls = new ArrayList<X509CRL>();
+        Collection<X509CRL> crls = new ArrayList<>();
+        CertStoreException savedCSE = null;
         for (CertStore store : certStores) {
             try {
                 for (CRL crl : store.getCRLs(xcs)) {
                     crls.add((X509CRL)crl);
                 }
             } catch (CertStoreException cse) {
-                // don't add the CRL
                 if (debug != null) {
-                    debug.println("Non-fatal exception while retrieving " +
+                    debug.println("Exception while retrieving " +
                         "CRLs: " + cse);
                     cse.printStackTrace();
                 }
+                savedCSE = new PKIX.CertStoreTypeException(store.getType(),cse);
             }
         }
-        return crls;
+        // only throw CertStoreException if no CRLs are retrieved
+        if (crls.isEmpty() && savedCSE != null) {
+            throw savedCSE;
+        } else {
+            return crls;
+        }
     }
 
     /**
@@ -271,6 +335,8 @@
      * @param reasonsMask the interim reasons mask
      * @param signFlag true if prevKey can be used to verify the CRL
      * @param prevKey the public key that verifies the certificate's signature
+     * @param prevCert the certificate whose public key verifies
+     *        {@code certImpl}'s signature
      * @param provider the Signature provider to use
      * @param trustAnchors a {@code Set} of {@code TrustAnchor}s
      * @param certStores a {@code List} of {@code CertStore}s to be used in
@@ -281,9 +347,17 @@
      */
     static boolean verifyCRL(X509CertImpl certImpl, DistributionPoint point,
         X509CRL crl, boolean[] reasonsMask, boolean signFlag,
-        PublicKey prevKey, String provider,
+        PublicKey prevKey, X509Certificate prevCert, String provider,
         Set<TrustAnchor> trustAnchors, List<CertStore> certStores,
-        Date validity) throws CRLException, IOException {
+        Date validity, String variant) throws CRLException, IOException {
+
+        if (debug != null) {
+            debug.println("DistributionPointFetcher.verifyCRL: " +
+                "checking revocation status for" +
+                "\n  SN: " + Debug.toHexString(certImpl.getSerialNumber()) +
+                "\n  Subject: " + certImpl.getSubjectX500Principal() +
+                "\n  Issuer: " + certImpl.getIssuerX500Principal());
+        }
 
         boolean indirectCRL = false;
         X509CRLImpl crlImpl = X509CRLImpl.toImpl(crl);
@@ -328,15 +402,15 @@
             }
         } else if (crlIssuer.equals(certIssuer) == false) {
             if (debug != null) {
-                debug.println("crl issuer does not equal cert issuer");
+                debug.println("crl issuer does not equal cert issuer.\n" +
+                              "crl issuer: " + crlIssuer + "\n" +
+                              "cert issuer: " + certIssuer);
             }
             return false;
         } else {
             // in case of self-issued indirect CRL issuer.
-            byte[] certAKID = certImpl.getExtensionValue(
-                                PKIXExtensions.AuthorityKey_Id.toString());
-            byte[] crlAKID = crlImpl.getExtensionValue(
-                                PKIXExtensions.AuthorityKey_Id.toString());
+            KeyIdentifier certAKID = certImpl.getAuthKeyId();
+            KeyIdentifier crlAKID = crlImpl.getAuthKeyId();
 
             if (certAKID == null || crlAKID == null) {
                 // cannot recognize indirect CRL without AKID
@@ -347,7 +421,7 @@
                     // reset the public key used to verify the CRL's signature
                     prevKey = certImpl.getPublicKey();
                 }
-            } else if (!Arrays.equals(certAKID, crlAKID)) {
+            } else if (!certAKID.equals(crlAKID)) {
                 // we accept the case that a CRL issuer provide status
                 // information for itself.
                 if (issues(certImpl, crlImpl, provider)) {
@@ -401,7 +475,7 @@
                         }
                         if (indirectCRL) {
                             if (pointCrlIssuers.size() != 1) {
-                                // RFC 3280: there must be only 1 CRL issuer
+                                // RFC 5280: there must be only 1 CRL issuer
                                 // name when relativeName is present
                                 if (debug != null) {
                                     debug.println("must only be one CRL " +
@@ -581,18 +655,26 @@
                 // the subject criterion will be set by builder automatically.
             }
 
-            // by far, we have validated the previous certificate, we can
-            // trust it during validating the CRL issuer.
-            // Except the performance improvement, another benefit is to break
-            // the dead loop while looking for the issuer back and forth
+            // By now, we have validated the previous certificate, so we can
+            // trust it during the validation of the CRL issuer.
+            // In addition to the performance improvement, another benefit is to
+            // break the dead loop while looking for the issuer back and forth
             // between the delegated self-issued certificate and its issuer.
             Set<TrustAnchor> newTrustAnchors = new HashSet<>(trustAnchors);
 
             if (prevKey != null) {
                 // Add the previous certificate as a trust anchor.
-                X500Principal principal = certImpl.getIssuerX500Principal();
-                TrustAnchor temporary =
-                        new TrustAnchor(principal, prevKey, null);
+                // If prevCert is not null, we want to construct a TrustAnchor
+                // using the cert object because when the certpath for the CRL
+                // is built later, the CertSelector will make comparisons with
+                // the TrustAnchor's trustedCert member rather than its pubKey.
+                TrustAnchor temporary;
+                if (prevCert != null) {
+                    temporary = new TrustAnchor(prevCert, null);
+                } else {
+                    X500Principal principal = certImpl.getIssuerX500Principal();
+                    temporary = new TrustAnchor(principal, prevKey, null);
+                }
                 newTrustAnchors.add(temporary);
             }
 
@@ -610,14 +692,14 @@
                 PKIXCertPathBuilderResult result =
                     (PKIXCertPathBuilderResult) builder.build(params);
                 prevKey = result.getPublicKey();
-            } catch (Exception e) {
+            } catch (GeneralSecurityException e) {
                 throw new CRLException(e);
             }
         }
 
         // check the crl signature algorithm
         try {
-            AlgorithmChecker.check(prevKey, crl);
+            AlgorithmChecker.check(prevKey, crl, variant);
         } catch (CertPathValidatorException cpve) {
             if (debug != null) {
                 debug.println("CRL signature algorithm check failed: " + cpve);
@@ -628,7 +710,7 @@
         // validate the signature on the CRL
         try {
             crl.verify(prevKey, provider);
-        } catch (Exception e) {
+        } catch (GeneralSecurityException e) {
             if (debug != null) {
                 debug.println("CRL signature failed to verify");
             }
@@ -639,15 +721,14 @@
         Set<String> unresCritExts = crl.getCriticalExtensionOIDs();
         // remove any that we have processed
         if (unresCritExts != null) {
-            unresCritExts.remove
-                (PKIXExtensions.IssuingDistributionPoint_Id.toString());
+            unresCritExts.remove(IssuingDistributionPoint_Id.toString());
             if (!unresCritExts.isEmpty()) {
                 if (debug != null) {
                     debug.println("Unrecognized critical extension(s) in CRL: "
                         + unresCritExts);
-                    Iterator<String> i = unresCritExts.iterator();
-                    while (i.hasNext())
-                        debug.println(i.next());
+                    for (String ext : unresCritExts) {
+                        debug.println(ext);
+                    }
                 }
                 return false;
             }
@@ -667,8 +748,9 @@
      * GeneralNames object.
      */
     private static GeneralNames getFullNames(X500Name issuer, RDN rdn)
-        throws IOException {
-        List<RDN> rdns = new ArrayList<RDN>(issuer.rdns());
+        throws IOException
+    {
+        List<RDN> rdns = new ArrayList<>(issuer.rdns());
         rdns.add(rdn);
         X500Name fullName = new X500Name(rdns.toArray(new RDN[0]));
         GeneralNames fullNames = new GeneralNames();
@@ -676,15 +758,16 @@
         return fullNames;
     }
 
-    /** Verifies whether a CRL is issued by a certain certificate
+    /**
+     * Verifies whether a CRL is issued by a certain certificate
      *
      * @param cert the certificate
      * @param crl the CRL to be verified
      * @param provider the name of the signature provider
      */
     private static boolean issues(X509CertImpl cert, X509CRLImpl crl,
-            String provider) throws IOException {
-
+                                  String provider) throws IOException
+    {
         boolean matched = false;
 
         AdaptableX509CertSelector issuerSelector =
@@ -722,7 +805,7 @@
             try {
                 crl.verify(cert.getPublicKey(), provider);
                 matched = true;
-            } catch (Exception e) {
+            } catch (GeneralSecurityException e) {
                 matched = false;
             }
         }
--- a/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2013, 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
@@ -26,10 +26,9 @@
 package sun.security.provider.certpath;
 
 import java.io.IOException;
-import java.util.*;
-
 import java.security.GeneralSecurityException;
 import java.security.InvalidKeyException;
+import java.security.PublicKey;
 import java.security.cert.CertificateException;
 import java.security.cert.CertPathValidatorException;
 import java.security.cert.PKIXReason;
@@ -40,15 +39,15 @@
 import java.security.cert.TrustAnchor;
 import java.security.cert.X509Certificate;
 import java.security.cert.X509CertSelector;
+import java.util.*;
 import javax.security.auth.x500.X500Principal;
 
+import sun.security.provider.certpath.PKIX.BuilderParams;
 import sun.security.util.Debug;
 import sun.security.x509.AccessDescription;
 import sun.security.x509.AuthorityInfoAccessExtension;
-import sun.security.x509.PKIXExtensions;
-import sun.security.x509.PolicyMappingsExtension;
+import static sun.security.x509.PKIXExtensions.*;
 import sun.security.x509.X500Name;
-import sun.security.x509.X509CertImpl;
 import sun.security.x509.AuthorityKeyIdentifierExtension;
 
 /**
@@ -72,21 +71,17 @@
     TrustAnchor trustAnchor;
     private Comparator<X509Certificate> comparator;
     private boolean searchAllCertStores = true;
-    private boolean onlyEECert = false;
 
     /**
      * Initialize the builder with the input parameters.
      *
      * @param params the parameter set used to build a certification path
      */
-    ForwardBuilder(PKIXBuilderParameters buildParams,
-        X500Principal targetSubjectDN, boolean searchAllCertStores,
-        boolean onlyEECert)
-    {
-        super(buildParams, targetSubjectDN);
+    ForwardBuilder(BuilderParams buildParams, boolean searchAllCertStores) {
+        super(buildParams);
 
         // populate sets of trusted certificates and subject DNs
-        trustAnchors = buildParams.getTrustAnchors();
+        trustAnchors = buildParams.trustAnchors();
         trustedCerts = new HashSet<X509Certificate>(trustAnchors.size());
         trustedSubjectDNs = new HashSet<X500Principal>(trustAnchors.size());
         for (TrustAnchor anchor : trustAnchors) {
@@ -100,7 +95,6 @@
         }
         comparator = new PKIXCertComparator(trustedSubjectDNs);
         this.searchAllCertStores = searchAllCertStores;
-        this.onlyEECert = onlyEECert;
     }
 
     /**
@@ -112,9 +106,10 @@
      *        Must be an instance of <code>ForwardState</code>
      * @param certStores list of CertStores
      */
-    Collection<X509Certificate> getMatchingCerts
-        (State currentState, List<CertStore> certStores)
-        throws CertStoreException, CertificateException, IOException
+    @Override
+    Collection<X509Certificate> getMatchingCerts(State currentState,
+                                                 List<CertStore> certStores)
+         throws CertStoreException, CertificateException, IOException
     {
         if (debug != null) {
             debug.println("ForwardBuilder.getMatchingCerts()...");
@@ -127,7 +122,7 @@
          * As each cert is added, it is sorted based on the PKIXCertComparator
          * algorithm.
          */
-        Set<X509Certificate> certs = new TreeSet<X509Certificate>(comparator);
+        Set<X509Certificate> certs = new TreeSet<>(comparator);
 
         /*
          * Only look for EE certs if search has just started.
@@ -145,9 +140,10 @@
      * and requirements specified in the parameters and PKIX state.
      */
     private void getMatchingEECerts(ForwardState currentState,
-        List<CertStore> certStores, Collection<X509Certificate> eeCerts)
-        throws IOException {
-
+                                    List<CertStore> certStores,
+                                    Collection<X509Certificate> eeCerts)
+        throws IOException
+    {
         if (debug != null) {
             debug.println("ForwardBuilder.getMatchingEECerts()...");
         }
@@ -165,12 +161,12 @@
             /*
              * Match on certificate validity date
              */
-            eeSelector.setCertificateValid(date);
+            eeSelector.setCertificateValid(buildParams.date());
 
             /*
              * Policy processing optimizations
              */
-            if (buildParams.isExplicitPolicyRequired()) {
+            if (buildParams.explicitPolicyRequired()) {
                 eeSelector.setPolicy(getMatchingPolicies());
             }
             /*
@@ -188,9 +184,10 @@
      * and requirements specified in the parameters and PKIX state.
      */
     private void getMatchingCACerts(ForwardState currentState,
-        List<CertStore> certStores, Collection<X509Certificate> caCerts)
-        throws IOException {
-
+                                    List<CertStore> certStores,
+                                    Collection<X509Certificate> caCerts)
+        throws IOException
+    {
         if (debug != null) {
             debug.println("ForwardBuilder.getMatchingCACerts()...");
         }
@@ -216,8 +213,8 @@
             }
 
             if (caTargetSelector == null) {
-                caTargetSelector = (X509CertSelector)
-                    targetCertConstraints.clone();
+                caTargetSelector =
+                    (X509CertSelector) targetCertConstraints.clone();
 
                 /*
                  * Since we don't check the validity period of trusted
@@ -229,7 +226,7 @@
                 /*
                  * Policy processing optimizations
                  */
-                if (buildParams.isExplicitPolicyRequired())
+                if (buildParams.explicitPolicyRequired())
                     caTargetSelector.setPolicy(getMatchingPolicies());
             }
 
@@ -249,7 +246,7 @@
                 /*
                  * Policy processing optimizations
                  */
-                if (buildParams.isExplicitPolicyRequired())
+                if (buildParams.explicitPolicyRequired())
                     caSelector.setPolicy(getMatchingPolicies());
             }
 
@@ -278,7 +275,7 @@
              * check the validity period
              */
             caSelector.setValidityPeriod(currentState.cert.getNotBefore(),
-                                            currentState.cert.getNotAfter());
+                                         currentState.cert.getNotAfter());
 
             sel = caSelector;
         }
@@ -307,7 +304,7 @@
          * The trusted certificate matching is completed. We need to match
          * on certificate validity date.
          */
-        sel.setCertificateValid(date);
+        sel.setCertificateValid(buildParams.date());
 
         /*
          * Require CA certs with a pathLenConstraint that allows
@@ -323,11 +320,12 @@
          * certificate pairs.
          */
         if (currentState.isInitial() ||
-           (buildParams.getMaxPathLength() == -1) ||
-           (buildParams.getMaxPathLength() > currentState.traversedCACerts))
+           (buildParams.maxPathLength() == -1) ||
+           (buildParams.maxPathLength() > currentState.traversedCACerts))
         {
             if (addMatchingCerts(sel, certStores,
-                    caCerts, searchAllCertStores) && !searchAllCertStores) {
+                                 caCerts, searchAllCertStores)
+                && !searchAllCertStores) {
                 return;
             }
         }
@@ -356,7 +354,8 @@
     // because of the selector, so the cast is safe
     @SuppressWarnings("unchecked")
     private boolean getCerts(AuthorityInfoAccessExtension aiaExt,
-        Collection<X509Certificate> certs) {
+                             Collection<X509Certificate> certs)
+    {
         if (Builder.USE_AIA == false) {
             return false;
         }
@@ -451,6 +450,7 @@
          * @throws ClassCastException if either argument is not of type
          * X509Certificate
          */
+        @Override
         public int compare(X509Certificate oCert1, X509Certificate oCert2) {
 
             // if certs are the same, return 0
@@ -653,8 +653,10 @@
      * @param currentState the current state against which the cert is verified
      * @param certPathList the certPathList generated thus far
      */
+    @Override
     void verifyCert(X509Certificate cert, State currentState,
-        List<X509Certificate> certPathList) throws GeneralSecurityException
+                    List<X509Certificate> certPathList)
+        throws GeneralSecurityException
     {
         if (debug != null) {
             debug.println("ForwardBuilder.verifyCert(SN: "
@@ -669,32 +671,16 @@
         currState.untrustedChecker.check(cert, Collections.<String>emptySet());
 
         /*
-         * check for looping - abort a loop if
-         * ((we encounter the same certificate twice) AND
-         * ((policyMappingInhibited = true) OR (no policy mapping
-         * extensions can be found between the occurrences of the same
-         * certificate)))
+         * check for looping - abort a loop if we encounter the same
+         * certificate twice
          */
         if (certPathList != null) {
-            boolean policyMappingFound = false;
             for (X509Certificate cpListCert : certPathList) {
-                X509CertImpl cpListCertImpl = X509CertImpl.toImpl(cpListCert);
-                PolicyMappingsExtension policyMappingsExt
-                    = cpListCertImpl.getPolicyMappingsExtension();
-                if (policyMappingsExt != null) {
-                    policyMappingFound = true;
-                }
-                if (debug != null) {
-                    debug.println("policyMappingFound = " + policyMappingFound);
-                }
                 if (cert.equals(cpListCert)) {
-                    if ((buildParams.isPolicyMappingInhibited()) ||
-                        (!policyMappingFound)) {
-                        if (debug != null) {
-                            debug.println("loop detected!!");
-                        }
-                        throw new CertPathValidatorException("loop detected");
+                    if (debug != null) {
+                        debug.println("loop detected!!");
                     }
+                    throw new CertPathValidatorException("loop detected");
                 }
             }
         }
@@ -723,7 +709,7 @@
              * all extensions that all user checkers are capable of
              * processing.
              */
-            for (PKIXCertPathChecker checker : buildParams.getCertPathCheckers()) {
+            for (PKIXCertPathChecker checker : buildParams.certPathCheckers()) {
                 if (!checker.isForwardCheckingSupported()) {
                     Set<String> supportedExts = checker.getSupportedExtensions();
                     if (supportedExts != null) {
@@ -737,23 +723,15 @@
              * to check. If there are any left, throw an exception!
              */
             if (!unresCritExts.isEmpty()) {
-                unresCritExts.remove(
-                    PKIXExtensions.BasicConstraints_Id.toString());
-                unresCritExts.remove(
-                    PKIXExtensions.NameConstraints_Id.toString());
-                unresCritExts.remove(
-                    PKIXExtensions.CertificatePolicies_Id.toString());
-                unresCritExts.remove(
-                    PKIXExtensions.PolicyMappings_Id.toString());
-                unresCritExts.remove(
-                    PKIXExtensions.PolicyConstraints_Id.toString());
-                unresCritExts.remove(
-                    PKIXExtensions.InhibitAnyPolicy_Id.toString());
-                unresCritExts.remove(
-                    PKIXExtensions.SubjectAlternativeName_Id.toString());
-                unresCritExts.remove(PKIXExtensions.KeyUsage_Id.toString());
-                unresCritExts.remove(
-                    PKIXExtensions.ExtendedKeyUsage_Id.toString());
+                unresCritExts.remove(BasicConstraints_Id.toString());
+                unresCritExts.remove(NameConstraints_Id.toString());
+                unresCritExts.remove(CertificatePolicies_Id.toString());
+                unresCritExts.remove(PolicyMappings_Id.toString());
+                unresCritExts.remove(PolicyConstraints_Id.toString());
+                unresCritExts.remove(InhibitAnyPolicy_Id.toString());
+                unresCritExts.remove(SubjectAlternativeName_Id.toString());
+                unresCritExts.remove(KeyUsage_Id.toString());
+                unresCritExts.remove(ExtendedKeyUsage_Id.toString());
 
                 if (!unresCritExts.isEmpty())
                     throw new CertPathValidatorException
@@ -791,31 +769,12 @@
          */
 
         /*
-         * Check revocation for the previous cert
-         */
-        if (buildParams.isRevocationEnabled()) {
-
-            // first off, see if this cert can authorize revocation...
-            if (CrlRevocationChecker.certCanSignCrl(cert)) {
-                // And then check to be sure no key requiring key parameters
-                // has been encountered
-                if (!currState.keyParamsNeeded())
-                    // If all that checks out, we can check the
-                    // revocation status of the cert. Otherwise,
-                    // we'll just wait until the end.
-                    currState.crlChecker.check(currState.cert,
-                                               cert.getPublicKey(),
-                                               true);
-            }
-        }
-
-        /*
          * Check signature only if no key requiring key parameters has been
          * encountered.
          */
         if (!currState.keyParamsNeeded()) {
             (currState.cert).verify(cert.getPublicKey(),
-                                    buildParams.getSigProvider());
+                                    buildParams.sigProvider());
         }
     }
 
@@ -831,6 +790,7 @@
      * @param cert the certificate to test
      * @return a boolean value indicating whether the cert completes the path.
      */
+    @Override
     boolean isPathCompleted(X509Certificate cert) {
         for (TrustAnchor anchor : trustAnchors) {
             if (anchor.getTrustedCert() != null) {
@@ -842,7 +802,7 @@
                 }
             } else {
                 X500Principal principal = anchor.getCA();
-                java.security.PublicKey publicKey = anchor.getCAPublicKey();
+                PublicKey publicKey = anchor.getCAPublicKey();
 
                 if (principal != null && publicKey != null &&
                         principal.equals(cert.getSubjectX500Principal())) {
@@ -861,21 +821,6 @@
                 }
             }
 
-            /* Check revocation if it is enabled */
-            if (buildParams.isRevocationEnabled()) {
-                try {
-                    CrlRevocationChecker crlChecker = new CrlRevocationChecker
-                        (anchor, buildParams, null, onlyEECert);
-                    crlChecker.check(cert, anchor.getCAPublicKey(), true);
-                } catch (CertPathValidatorException cpve) {
-                    if (debug != null) {
-                        debug.println("ForwardBuilder.isPathCompleted() cpve");
-                        cpve.printStackTrace();
-                    }
-                    continue;
-                }
-            }
-
             /*
              * Check signature
              */
@@ -884,18 +829,17 @@
                 // parameters, yet there is no key to inherit the parameters
                 // from.  This is probably such a rare case that it is not worth
                 // trying to detect the situation earlier.
-                cert.verify(anchor.getCAPublicKey(),
-                            buildParams.getSigProvider());
+                cert.verify(anchor.getCAPublicKey(), buildParams.sigProvider());
             } catch (InvalidKeyException ike) {
                 if (debug != null) {
                     debug.println("ForwardBuilder.isPathCompleted() invalid "
-                        + "DSA key found");
+                                  + "DSA key found");
                 }
                 continue;
-            } catch (Exception e){
+            } catch (GeneralSecurityException e){
                 if (debug != null) {
                     debug.println("ForwardBuilder.isPathCompleted() " +
-                        "unexpected exception");
+                                  "unexpected exception");
                     e.printStackTrace();
                 }
                 continue;
@@ -913,8 +857,10 @@
      * @param cert the certificate to be added
      * @param certPathList the certification path list
      */
+    @Override
     void addCertToPath(X509Certificate cert,
-        LinkedList<X509Certificate> certPathList) {
+                       LinkedList<X509Certificate> certPathList)
+    {
         certPathList.addFirst(cert);
     }
 
@@ -922,6 +868,7 @@
      *
      * @param certPathList the certification path list
      */
+    @Override
     void removeFinalCertFromPath(LinkedList<X509Certificate> certPathList) {
         certPathList.removeFirst();
     }
--- a/src/share/classes/sun/security/provider/certpath/ForwardState.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/provider/certpath/ForwardState.java	Thu Nov 09 06:08:09 2017 +0000
@@ -34,7 +34,6 @@
 import java.security.interfaces.DSAPublicKey;
 import java.util.ArrayList;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
 import java.util.ListIterator;
 import javax.security.auth.x500.X500Principal;
@@ -76,9 +75,6 @@
     /* Flag indicating if state is initial (path is just starting) */
     private boolean init = true;
 
-    /* the checker used for revocation status */
-    public CrlRevocationChecker crlChecker;
-
     /* the untrusted certificates checker */
     UntrustedChecker untrustedChecker;
 
@@ -96,6 +92,7 @@
      *
      * @return boolean flag indicating if the state is initial (just starting)
      */
+    @Override
     public boolean isInitial() {
         return init;
     }
@@ -107,6 +104,7 @@
      * @return boolean true if key needing to inherit parameters has been
      * encountered; false otherwise.
      */
+    @Override
     public boolean keyParamsNeeded() {
         return keyParamsNeededFlag;
     }
@@ -114,23 +112,18 @@
     /**
      * Display state for debugging purposes
      */
+    @Override
     public String toString() {
-        StringBuffer sb = new StringBuffer();
-        try {
-            sb.append("State [");
-            sb.append("\n  issuerDN of last cert: " + issuerDN);
-            sb.append("\n  traversedCACerts: " + traversedCACerts);
-            sb.append("\n  init: " + String.valueOf(init));
-            sb.append("\n  keyParamsNeeded: "
-                + String.valueOf(keyParamsNeededFlag));
-            sb.append("\n  subjectNamesTraversed: \n" + subjectNamesTraversed);
-            sb.append("]\n");
-        } catch (Exception e) {
-            if (debug != null) {
-                debug.println("ForwardState.toString() unexpected exception");
-                e.printStackTrace();
-            }
-        }
+        StringBuilder sb = new StringBuilder();
+        sb.append("State [");
+        sb.append("\n  issuerDN of last cert: ").append(issuerDN);
+        sb.append("\n  traversedCACerts: ").append(traversedCACerts);
+        sb.append("\n  init: ").append(String.valueOf(init));
+        sb.append("\n  keyParamsNeeded: ").append
+                 (String.valueOf(keyParamsNeededFlag));
+        sb.append("\n  subjectNamesTraversed: \n").append
+                 (subjectNamesTraversed);
+        sb.append("]\n");
         return sb.toString();
     }
 
@@ -150,12 +143,10 @@
          * that supports forward checking and initialize the forwardCheckers
          */
         forwardCheckers = new ArrayList<PKIXCertPathChecker>();
-        if (certPathCheckers != null) {
-            for (PKIXCertPathChecker checker : certPathCheckers) {
-                if (checker.isForwardCheckingSupported()) {
-                    checker.init(true);
-                    forwardCheckers.add(checker);
-                }
+        for (PKIXCertPathChecker checker : certPathCheckers) {
+            if (checker.isForwardCheckingSupported()) {
+                checker.init(true);
+                forwardCheckers.add(checker);
             }
         }
 
@@ -167,6 +158,7 @@
      *
      * @param cert the certificate which is used to update the state
      */
+    @Override
     public void updateState(X509Certificate cert)
         throws CertificateException, IOException, CertPathValidatorException {
 
@@ -211,13 +203,11 @@
                 if (subjAltNameExt != null) {
                     GeneralNames gNames = subjAltNameExt.get(
                             SubjectAlternativeNameExtension.SUBJECT_NAME);
-                    for (Iterator<GeneralName> t = gNames.iterator();
-                                t.hasNext(); ) {
-                        GeneralNameInterface gName = t.next().getName();
-                        subjectNamesTraversed.add(gName);
+                    for (GeneralName gName : gNames.names()) {
+                        subjectNamesTraversed.add(gName.getName());
                     }
                 }
-            } catch (Exception e) {
+            } catch (IOException e) {
                 if (debug != null) {
                     debug.println("ForwardState.updateState() unexpected "
                         + "exception");
@@ -239,6 +229,7 @@
      * because some of them will
      * not have their contents modified by subsequent calls to updateState.
      */
+    @Override
     @SuppressWarnings("unchecked") // Safe casts assuming clone() works correctly
     public Object clone() {
         try {
--- a/src/share/classes/sun/security/provider/certpath/IndexedCollectionCertStore.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/provider/certpath/IndexedCollectionCertStore.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2012, 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
@@ -180,7 +180,7 @@
                 if (cert.equals(oldEntry)) {
                     return;
                 }
-                List<X509Certificate> list = new ArrayList<X509Certificate>(2);
+                List<X509Certificate> list = new ArrayList<>(2);
                 list.add(cert);
                 list.add((X509Certificate)oldEntry);
                 certSubjects.put(subject, list);
@@ -206,7 +206,7 @@
                 if (crl.equals(oldEntry)) {
                     return;
                 }
-                List<X509CRL> list = new ArrayList<X509CRL>(2);
+                List<X509CRL> list = new ArrayList<>(2);
                 list.add(crl);
                 list.add((X509CRL)oldEntry);
                 crlIssuers.put(issuer, list);
@@ -234,19 +234,20 @@
      *         match the specified selector
      * @throws CertStoreException if an exception occurs
      */
+    @Override
     public Collection<? extends Certificate> engineGetCertificates(CertSelector selector)
             throws CertStoreException {
 
         // no selector means match all
         if (selector == null) {
-            Set<Certificate> matches = new HashSet<Certificate>();
+            Set<Certificate> matches = new HashSet<>();
             matchX509Certs(new X509CertSelector(), matches);
             matches.addAll(otherCertificates);
             return matches;
         }
 
         if (selector instanceof X509CertSelector == false) {
-            Set<Certificate> matches = new HashSet<Certificate>();
+            Set<Certificate> matches = new HashSet<>();
             matchX509Certs(selector, matches);
             for (Certificate cert : otherCertificates) {
                 if (selector.match(cert)) {
@@ -285,7 +286,7 @@
                 // See certSubjects javadoc.
                 @SuppressWarnings("unchecked")
                 List<X509Certificate> list = (List<X509Certificate>)entry;
-                Set<X509Certificate> matches = new HashSet<X509Certificate>(16);
+                Set<X509Certificate> matches = new HashSet<>(16);
                 for (X509Certificate cert : list) {
                     if (x509Selector.match(cert)) {
                         matches.add(cert);
@@ -295,7 +296,7 @@
             }
         }
         // cannot use index, iterate all
-        Set<Certificate> matches = new HashSet<Certificate>(16);
+        Set<Certificate> matches = new HashSet<>(16);
         matchX509Certs(x509Selector, matches);
         return matches;
     }
@@ -338,18 +339,19 @@
      *         match the specified selector
      * @throws CertStoreException if an exception occurs
      */
+    @Override
     public Collection<CRL> engineGetCRLs(CRLSelector selector)
             throws CertStoreException {
 
         if (selector == null) {
-            Set<CRL> matches = new HashSet<CRL>();
+            Set<CRL> matches = new HashSet<>();
             matchX509CRLs(new X509CRLSelector(), matches);
             matches.addAll(otherCRLs);
             return matches;
         }
 
         if (selector instanceof X509CRLSelector == false) {
-            Set<CRL> matches = new HashSet<CRL>();
+            Set<CRL> matches = new HashSet<>();
             matchX509CRLs(selector, matches);
             for (CRL crl : otherCRLs) {
                 if (selector.match(crl)) {
@@ -366,7 +368,7 @@
         // see if the issuer is specified
         Collection<X500Principal> issuers = x509Selector.getIssuers();
         if (issuers != null) {
-            HashSet<CRL> matches = new HashSet<CRL>(16);
+            HashSet<CRL> matches = new HashSet<>(16);
             for (X500Principal issuer : issuers) {
                 Object entry = crlIssuers.get(issuer);
                 if (entry == null) {
@@ -390,7 +392,7 @@
             return matches;
         }
         // cannot use index, iterate all
-        Set<CRL> matches = new HashSet<CRL>(16);
+        Set<CRL> matches = new HashSet<>(16);
         matchX509CRLs(x509Selector, matches);
         return matches;
     }
--- a/src/share/classes/sun/security/provider/certpath/KeyChecker.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/provider/certpath/KeyChecker.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2012, 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
@@ -30,7 +30,7 @@
 import java.security.cert.PKIXReason;
 
 import sun.security.util.Debug;
-import sun.security.x509.PKIXExtensions;
+import static sun.security.x509.PKIXExtensions.*;
 
 /**
  * KeyChecker is a <code>PKIXCertPathChecker</code> that checks that the
@@ -45,33 +45,29 @@
 class KeyChecker extends PKIXCertPathChecker {
 
     private static final Debug debug = Debug.getInstance("certpath");
-    // the index of keyCertSign in the boolean KeyUsage array
-    private static final int keyCertSign = 5;
     private final int certPathLen;
-    private CertSelector targetConstraints;
+    private final CertSelector targetConstraints;
     private int remainingCerts;
 
     private Set<String> supportedExts;
 
     /**
-     * Default Constructor
+     * Creates a KeyChecker.
      *
      * @param certPathLen allowable cert path length
      * @param targetCertSel a CertSelector object specifying the constraints
      * on the target certificate
      */
-    KeyChecker(int certPathLen, CertSelector targetCertSel)
-        throws CertPathValidatorException
-    {
+    KeyChecker(int certPathLen, CertSelector targetCertSel) {
         this.certPathLen = certPathLen;
         this.targetConstraints = targetCertSel;
-        init(false);
     }
 
     /**
      * Initializes the internal state of the checker from parameters
      * specified in the constructor
      */
+    @Override
     public void init(boolean forward) throws CertPathValidatorException {
         if (!forward) {
             remainingCerts = certPathLen;
@@ -81,16 +77,18 @@
         }
     }
 
-    public final boolean isForwardCheckingSupported() {
+    @Override
+    public boolean isForwardCheckingSupported() {
         return false;
     }
 
+    @Override
     public Set<String> getSupportedExtensions() {
         if (supportedExts == null) {
-            supportedExts = new HashSet<String>();
-            supportedExts.add(PKIXExtensions.KeyUsage_Id.toString());
-            supportedExts.add(PKIXExtensions.ExtendedKeyUsage_Id.toString());
-            supportedExts.add(PKIXExtensions.SubjectAlternativeName_Id.toString());
+            supportedExts = new HashSet<String>(3);
+            supportedExts.add(KeyUsage_Id.toString());
+            supportedExts.add(ExtendedKeyUsage_Id.toString());
+            supportedExts.add(SubjectAlternativeName_Id.toString());
             supportedExts = Collections.unmodifiableSet(supportedExts);
         }
         return supportedExts;
@@ -102,20 +100,20 @@
      *
      * @param cert the Certificate
      * @param unresolvedCritExts the unresolved critical extensions
-     * @exception CertPathValidatorException Exception thrown if certificate
-     * does not verify
+     * @throws CertPathValidatorException if certificate does not verify
      */
+    @Override
     public void check(Certificate cert, Collection<String> unresCritExts)
         throws CertPathValidatorException
     {
-        X509Certificate currCert = (X509Certificate) cert;
+        X509Certificate currCert = (X509Certificate)cert;
 
         remainingCerts--;
 
         // if final certificate, check that target constraints are satisfied
         if (remainingCerts == 0) {
-            if ((targetConstraints != null) &&
-                (targetConstraints.match(currCert) == false)) {
+            if (targetConstraints != null &&
+                targetConstraints.match(currCert) == false) {
                 throw new CertPathValidatorException("target certificate " +
                     "constraints check failed");
             }
@@ -126,25 +124,26 @@
 
         // remove the extensions that we have checked
         if (unresCritExts != null && !unresCritExts.isEmpty()) {
-            unresCritExts.remove(PKIXExtensions.KeyUsage_Id.toString());
-            unresCritExts.remove(PKIXExtensions.ExtendedKeyUsage_Id.toString());
-            unresCritExts.remove(
-                PKIXExtensions.SubjectAlternativeName_Id.toString());
+            unresCritExts.remove(KeyUsage_Id.toString());
+            unresCritExts.remove(ExtendedKeyUsage_Id.toString());
+            unresCritExts.remove(SubjectAlternativeName_Id.toString());
         }
     }
 
+    // the index of keyCertSign in the boolean KeyUsage array
+    private static final int KEY_CERT_SIGN = 5;
     /**
-     * Static method to verify that the key usage and extended key usage
-     * extension in a CA cert. The key usage extension, if present, must
-     * assert the keyCertSign bit. The extended key usage extension, if
-     * present, must include anyExtendedKeyUsage.
+     * Verifies the key usage extension in a CA cert.
+     * The key usage extension, if present, must assert the keyCertSign bit.
+     * The extended key usage extension is not checked (see CR 4776794 for
+     * more information).
      */
     static void verifyCAKeyUsage(X509Certificate cert)
             throws CertPathValidatorException {
         String msg = "CA key usage";
         if (debug != null) {
             debug.println("KeyChecker.verifyCAKeyUsage() ---checking " + msg
-                + "...");
+                          + "...");
         }
 
         boolean[] keyUsageBits = cert.getKeyUsage();
@@ -156,7 +155,7 @@
         }
 
         // throw an exception if the keyCertSign bit is not set
-        if (!keyUsageBits[keyCertSign]) {
+        if (!keyUsageBits[KEY_CERT_SIGN]) {
             throw new CertPathValidatorException
                 (msg + " check failed: keyCertSign bit is not set", null,
                  null, -1, PKIXReason.INVALID_KEY_USAGE);
@@ -164,7 +163,7 @@
 
         if (debug != null) {
             debug.println("KeyChecker.verifyCAKeyUsage() " + msg
-                + " verified.");
+                          + " verified.");
         }
     }
 }
--- a/src/share/classes/sun/security/provider/certpath/OCSP.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/provider/certpath/OCSP.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2017, 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
@@ -32,8 +32,10 @@
 import java.net.HttpURLConnection;
 import java.security.cert.CertificateException;
 import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertPathValidatorException.BasicReason;
 import java.security.cert.CRLReason;
 import java.security.cert.Extension;
+import java.security.cert.TrustAnchor;
 import java.security.cert.X509Certificate;
 import java.util.Arrays;
 import java.util.Collections;
@@ -41,13 +43,14 @@
 import java.util.List;
 import java.util.Map;
 
-import static sun.security.provider.certpath.OCSPResponse.*;
 import sun.security.action.GetIntegerAction;
 import sun.security.util.Debug;
+import sun.security.validator.Validator;
 import sun.security.x509.AccessDescription;
 import sun.security.x509.AuthorityInfoAccessExtension;
 import sun.security.x509.GeneralName;
 import sun.security.x509.GeneralNameInterface;
+import sun.security.x509.PKIXExtensions;
 import sun.security.x509.URIName;
 import sun.security.x509.X509CertImpl;
 
@@ -92,44 +95,6 @@
 
     private OCSP() {}
 
-    /**
-     * Obtains the revocation status of a certificate using OCSP using the most
-     * common defaults. The OCSP responder URI is retrieved from the
-     * certificate's AIA extension. The OCSP responder certificate is assumed
-     * to be the issuer's certificate (or issued by the issuer CA).
-     *
-     * @param cert the certificate to be checked
-     * @param issuerCert the issuer certificate
-     * @return the RevocationStatus
-     * @throws IOException if there is an exception connecting to or
-     *    communicating with the OCSP responder
-     * @throws CertPathValidatorException if an exception occurs while
-     *    encoding the OCSP Request or validating the OCSP Response
-     */
-    public static RevocationStatus check(X509Certificate cert,
-        X509Certificate issuerCert)
-            throws IOException, CertPathValidatorException {
-        CertId certId = null;
-        URI responderURI = null;
-        try {
-            X509CertImpl certImpl = X509CertImpl.toImpl(cert);
-            responderURI = getResponderURI(certImpl);
-            if (responderURI == null) {
-                throw new CertPathValidatorException
-                    ("No OCSP Responder URI in certificate");
-            }
-            certId = new CertId(issuerCert, certImpl.getSerialNumberObject());
-        } catch (CertificateException ce) {
-            throw new CertPathValidatorException
-                ("Exception while encoding OCSPRequest", ce);
-        } catch (IOException ioe) {
-            throw new CertPathValidatorException
-                ("Exception while encoding OCSPRequest", ioe);
-        }
-        OCSPResponse ocspResponse = check(Collections.singletonList(certId),
-            responderURI, Collections.singletonList(issuerCert), null);
-        return (RevocationStatus) ocspResponse.getSingleResponse(certId);
-    }
 
     /**
      * Obtains the revocation status of a certificate using OCSP.
@@ -146,59 +111,62 @@
      * @throws CertPathValidatorException if an exception occurs while
      *    encoding the OCSP Request or validating the OCSP Response
      */
+
+    // Called by com.sun.deploy.security.TrustDecider
     public static RevocationStatus check(X509Certificate cert,
-        X509Certificate issuerCert, URI responderURI,
-        X509Certificate responderCert, Date date)
-            throws IOException, CertPathValidatorException {
-
-        return check(cert, issuerCert, responderURI,
-            Collections.singletonList(responderCert), date);
+                                         X509Certificate issuerCert,
+                                         URI responderURI,
+                                         X509Certificate responderCert,
+                                         Date date)
+        throws IOException, CertPathValidatorException
+    {
+        return check(cert, issuerCert, responderURI, responderCert, date,
+                     Collections.<Extension>emptyList(), Validator.VAR_GENERIC);
     }
 
-    /**
-     * Obtains the revocation status of a certificate using OCSP.
-     *
-     * @param cert the certificate to be checked
-     * @param issuerCert the issuer certificate
-     * @param responderURI the URI of the OCSP responder
-     * @param responderCerts the OCSP responder's certificates
-     * @param date the time the validity of the OCSP responder's certificate
-     *    should be checked against. If null, the current time is used.
-     * @return the RevocationStatus
-     * @throws IOException if there is an exception connecting to or
-     *    communicating with the OCSP responder
-     * @throws CertPathValidatorException if an exception occurs while
-     *    encoding the OCSP Request or validating the OCSP Response
-     */
+
     public static RevocationStatus check(X509Certificate cert,
-        X509Certificate issuerCert, URI responderURI,
-        List<X509Certificate> responderCerts, Date date)
-            throws IOException, CertPathValidatorException {
+            X509Certificate issuerCert, URI responderURI,
+            X509Certificate responderCert, Date date, List<Extension> extensions,
+            String variant)
+        throws IOException, CertPathValidatorException
+    {
+        return check(cert, responderURI, null, issuerCert, responderCert, date,
+                extensions, variant);
+    }
 
-        CertId certId = null;
+    public static RevocationStatus check(X509Certificate cert,
+            URI responderURI, TrustAnchor anchor, X509Certificate issuerCert,
+            X509Certificate responderCert, Date date,
+            List<Extension> extensions, String variant)
+            throws IOException, CertPathValidatorException
+    {
+        CertId certId;
         try {
             X509CertImpl certImpl = X509CertImpl.toImpl(cert);
             certId = new CertId(issuerCert, certImpl.getSerialNumberObject());
-        } catch (CertificateException ce) {
+        } catch (CertificateException | IOException e) {
             throw new CertPathValidatorException
-                ("Exception while encoding OCSPRequest", ce);
-        } catch (IOException ioe) {
-            throw new CertPathValidatorException
-                ("Exception while encoding OCSPRequest", ioe);
+                ("Exception while encoding OCSPRequest", e);
         }
         OCSPResponse ocspResponse = check(Collections.singletonList(certId),
-            responderURI, responderCerts, date);
+                responderURI, new OCSPResponse.IssuerInfo(anchor, issuerCert),
+                responderCert, date, extensions, variant);
         return (RevocationStatus) ocspResponse.getSingleResponse(certId);
     }
 
     /**
      * Checks the revocation status of a list of certificates using OCSP.
      *
-     * @param certs the CertIds to be checked
+     * @param certIds the CertIds to be checked
      * @param responderURI the URI of the OCSP responder
-     * @param responderCerts the OCSP responder's certificates
+     * @param issuerInfo the issuer's certificate and/or subject and public key
+     * @param responderCert the OCSP responder's certificate
      * @param date the time the validity of the OCSP responder's certificate
      *    should be checked against. If null, the current time is used.
+     * @param extensions zero or more OCSP extensions to be included in the
+     *    request.  If no extensions are requested, an empty {@code List} must
+     *    be used.  A {@code null} value is not allowed.
      * @return the OCSPResponse
      * @throws IOException if there is an exception connecting to or
      *    communicating with the OCSP responder
@@ -206,21 +174,59 @@
      *    encoding the OCSP Request or validating the OCSP Response
      */
     static OCSPResponse check(List<CertId> certIds, URI responderURI,
-        List<X509Certificate> responderCerts, Date date)
-            throws IOException, CertPathValidatorException {
+                              OCSPResponse.IssuerInfo issuerInfo,
+                              X509Certificate responderCert, Date date,
+                              List<Extension> extensions, String variant)
+        throws IOException, CertPathValidatorException
+    {
+        byte[] nonce = null;
+        for (Extension ext : extensions) {
+            if (ext.getId().equals(PKIXExtensions.OCSPNonce_Id.toString())) {
+                nonce = ext.getValue();
+            }
+        }
 
-        byte[] bytes = null;
+        OCSPResponse ocspResponse = null;
         try {
-            OCSPRequest request = new OCSPRequest(certIds);
-            bytes = request.encodeBytes();
+            byte[] response = getOCSPBytes(certIds, responderURI, extensions);
+            ocspResponse = new OCSPResponse(response);
+
+            // verify the response
+            ocspResponse.verify(certIds, issuerInfo, responderCert, date,
+                    nonce, variant);
         } catch (IOException ioe) {
-            throw new CertPathValidatorException
-                ("Exception while encoding OCSPRequest", ioe);
+            throw new CertPathValidatorException(
+                "Unable to determine revocation status due to network error",
+                ioe, null, -1, BasicReason.UNDETERMINED_REVOCATION_STATUS);
         }
 
+        return ocspResponse;
+    }
+
+
+    /**
+     * Send an OCSP request, then read and return the OCSP response bytes.
+     *
+     * @param certIds the CertIds to be checked
+     * @param responderURI the URI of the OCSP responder
+     * @param extensions zero or more OCSP extensions to be included in the
+     *    request.  If no extensions are requested, an empty {@code List} must
+     *    be used.  A {@code null} value is not allowed.
+     *
+     * @return the OCSP response bytes
+     *
+     * @throws IOException if there is an exception connecting to or
+     *    communicating with the OCSP responder
+     */
+    public static byte[] getOCSPBytes(List<CertId> certIds, URI responderURI,
+            List<Extension> extensions) throws IOException {
+        OCSPRequest request = new OCSPRequest(certIds, extensions);
+        byte[] bytes = request.encodeBytes();
+
         InputStream in = null;
         OutputStream out = null;
         byte[] response = null;
+
         try {
             URL url = responderURI.toURL();
             if (debug != null) {
@@ -279,37 +285,7 @@
                 }
             }
         }
-
-        OCSPResponse ocspResponse = null;
-        try {
-            ocspResponse = new OCSPResponse(response, date, responderCerts);
-        } catch (IOException ioe) {
-            // response decoding exception
-            throw new CertPathValidatorException(ioe);
-        }
-        if (ocspResponse.getResponseStatus() != ResponseStatus.SUCCESSFUL) {
-            throw new CertPathValidatorException
-                ("OCSP response error: " + ocspResponse.getResponseStatus());
-        }
-
-        // Check that the response includes a response for all of the
-        // certs that were supplied in the request
-        for (CertId certId : certIds) {
-            SingleResponse sr = ocspResponse.getSingleResponse(certId);
-            if (sr == null) {
-                if (debug != null) {
-                    debug.println("No response found for CertId: " + certId);
-                }
-                throw new CertPathValidatorException(
-                    "OCSP response does not include a response for a " +
-                    "certificate supplied in the OCSP request");
-            }
-            if (debug != null) {
-                debug.println("Status of certificate (with serial number " +
-                    certId.getSerialNumber() + ") is: " + sr.getCertStatus());
-            }
-        }
-        return ocspResponse;
+        return response;
     }
 
     /**
@@ -320,6 +296,7 @@
      * @param cert the certificate
      * @return the URI of the OCSP Responder, or null if not specified
      */
+    // Called by com.sun.deploy.security.TrustDecider
     public static URI getResponderURI(X509Certificate cert) {
         try {
             return getResponderURI(X509CertImpl.toImpl(cert));
@@ -340,7 +317,7 @@
 
         List<AccessDescription> descriptions = aia.getAccessDescriptions();
         for (AccessDescription description : descriptions) {
-            if (description.getAccessMethod().equals((Object)
+            if (description.getAccessMethod().equals(
                 AccessDescription.Ad_OCSP_Id)) {
 
                 GeneralName generalName = description.getAccessLocation();
@@ -379,4 +356,12 @@
          */
         Map<String, Extension> getSingleExtensions();
     }
+
+    static class NetworkFailureException extends CertPathValidatorException {
+        private static final long serialVersionUID = 0l;
+
+        NetworkFailureException(Throwable t) {
+            super(t);
+        }
+    }
 }
--- a/src/share/classes/sun/security/provider/certpath/OCSPChecker.java	Thu Aug 03 07:28:01 2017 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,522 +0,0 @@
-/*
- * Copyright (c) 2003, 2012, 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.provider.certpath;
-
-import java.io.IOException;
-import java.math.BigInteger;
-import java.util.*;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.security.Security;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateRevokedException;
-import java.security.cert.CertPath;
-import java.security.cert.CertPathValidatorException;
-import java.security.cert.CertPathValidatorException.BasicReason;
-import java.security.cert.CertStore;
-import java.security.cert.CertStoreException;
-import java.security.cert.PKIXCertPathChecker;
-import java.security.cert.PKIXParameters;
-import java.security.cert.TrustAnchor;
-import java.security.cert.X509Certificate;
-import java.security.cert.X509CertSelector;
-import java.net.URI;
-import java.net.URISyntaxException;
-import javax.security.auth.x500.X500Principal;
-
-import static sun.security.provider.certpath.OCSP.*;
-import sun.security.util.Debug;
-import sun.security.x509.*;
-
-/**
- * OCSPChecker is a <code>PKIXCertPathChecker</code> that uses the
- * Online Certificate Status Protocol (OCSP) as specified in RFC 2560
- * <a href="http://www.ietf.org/rfc/rfc2560.txt">
- * http://www.ietf.org/rfc/rfc2560.txt</a>.
- *
- * @author      Ram Marti
- */
-class OCSPChecker extends PKIXCertPathChecker {
-
-    static final String OCSP_ENABLE_PROP = "ocsp.enable";
-    static final String OCSP_URL_PROP = "ocsp.responderURL";
-    static final String OCSP_CERT_SUBJECT_PROP =
-        "ocsp.responderCertSubjectName";
-    static final String OCSP_CERT_ISSUER_PROP = "ocsp.responderCertIssuerName";
-    static final String OCSP_CERT_NUMBER_PROP =
-        "ocsp.responderCertSerialNumber";
-
-    private static final String HEX_DIGITS = "0123456789ABCDEFabcdef";
-    private static final Debug DEBUG = Debug.getInstance("certpath");
-    private static final boolean dump = false;
-
-    private int remainingCerts;
-
-    private X509Certificate[] certs;
-
-    private CertPath cp;
-
-    private PKIXParameters pkixParams;
-
-    private boolean onlyEECert = false;
-
-    /**
-     * Default Constructor
-     *
-     * @param certPath the X509 certification path
-     * @param pkixParams the input PKIX parameter set
-     * @throws CertPathValidatorException if OCSPChecker can not be created
-     */
-    OCSPChecker(CertPath certPath, PKIXParameters pkixParams)
-        throws CertPathValidatorException {
-        this(certPath, pkixParams, false);
-    }
-
-    OCSPChecker(CertPath certPath, PKIXParameters pkixParams, boolean onlyEECert)
-        throws CertPathValidatorException {
-
-        this.cp = certPath;
-        this.pkixParams = pkixParams;
-        this.onlyEECert = onlyEECert;
-        List<? extends Certificate> tmp = cp.getCertificates();
-        certs = tmp.toArray(new X509Certificate[tmp.size()]);
-        init(false);
-    }
-
-    /**
-     * Initializes the internal state of the checker from parameters
-     * specified in the constructor
-     */
-    @Override
-    public void init(boolean forward) throws CertPathValidatorException {
-        if (!forward) {
-            remainingCerts = certs.length + 1;
-        } else {
-            throw new CertPathValidatorException(
-                "Forward checking not supported");
-        }
-    }
-
-    @Override public boolean isForwardCheckingSupported() {
-        return false;
-    }
-
-    @Override public Set<String> getSupportedExtensions() {
-        return Collections.<String>emptySet();
-    }
-
-    /**
-     * Sends an OCSPRequest for the certificate to the OCSP Server and
-     * processes the response back from the OCSP Server.
-     *
-     * @param cert the Certificate
-     * @param unresolvedCritExts the unresolved critical extensions
-     * @exception CertPathValidatorException Exception is thrown if the
-     *            certificate has been revoked.
-     */
-    @Override
-    public void check(Certificate cert, Collection<String> unresolvedCritExts)
-        throws CertPathValidatorException {
-
-        // Decrement the certificate counter
-        remainingCerts--;
-
-        X509CertImpl currCertImpl = null;
-        try {
-            currCertImpl = X509CertImpl.toImpl((X509Certificate)cert);
-        } catch (CertificateException ce) {
-            throw new CertPathValidatorException(ce);
-        }
-
-        if (onlyEECert && currCertImpl.getBasicConstraints() != -1) {
-            if (DEBUG != null) {
-                DEBUG.println("Skipping revocation check, not end entity cert");
-            }
-            return;
-        }
-
-        /*
-         * OCSP security property values, in the following order:
-         *   1. ocsp.responderURL
-         *   2. ocsp.responderCertSubjectName
-         *   3. ocsp.responderCertIssuerName
-         *   4. ocsp.responderCertSerialNumber
-         */
-        // should cache these properties to avoid calling every time?
-        String[] properties = getOCSPProperties();
-
-        // Check whether OCSP is feasible before seeking cert information
-        URI uri = getOCSPServerURI(currCertImpl, properties[0]);
-
-        // When responder's subject name is set then the issuer/serial
-        // properties are ignored
-        X500Principal responderSubjectName = null;
-        X500Principal responderIssuerName = null;
-        BigInteger responderSerialNumber = null;
-        if (properties[1] != null) {
-            responderSubjectName = new X500Principal(properties[1]);
-        } else if (properties[2] != null && properties[3] != null) {
-            responderIssuerName = new X500Principal(properties[2]);
-            // remove colon or space separators
-            String value = stripOutSeparators(properties[3]);
-            responderSerialNumber = new BigInteger(value, 16);
-        } else if (properties[2] != null || properties[3] != null) {
-            throw new CertPathValidatorException(
-                "Must specify both ocsp.responderCertIssuerName and " +
-                "ocsp.responderCertSerialNumber properties");
-        }
-
-        // If the OCSP responder cert properties are set then the
-        // identified cert must be located in the trust anchors or
-        // in the cert stores.
-        boolean seekResponderCert = false;
-        if (responderSubjectName != null || responderIssuerName != null) {
-            seekResponderCert = true;
-        }
-
-        // Set the issuer certificate to the next cert in the chain
-        // (unless we're processing the final cert).
-        X509Certificate issuerCert = null;
-        boolean seekIssuerCert = true;
-        List<X509Certificate> responderCerts = new ArrayList<X509Certificate>();
-
-        if (remainingCerts < certs.length) {
-            issuerCert = certs[remainingCerts];
-            seekIssuerCert = false; // done
-
-            // By default, the OCSP responder's cert is the same as the
-            // issuer of the cert being validated.
-            if (!seekResponderCert) {
-                responderCerts.add(issuerCert);
-                if (DEBUG != null) {
-                    DEBUG.println("Responder's certificate is the same " +
-                        "as the issuer of the certificate being validated");
-                }
-            }
-        }
-
-        // Check anchor certs for:
-        //    - the issuer cert (of the cert being validated)
-        //    - the OCSP responder's cert
-        if (seekIssuerCert || seekResponderCert) {
-
-            if (DEBUG != null && seekResponderCert) {
-                DEBUG.println("Searching trust anchors for issuer or " +
-                    "responder certificate");
-            }
-
-            // Extract the anchor certs
-            Iterator<TrustAnchor> anchors
-                = pkixParams.getTrustAnchors().iterator();
-            if (!anchors.hasNext()) {
-                throw new CertPathValidatorException(
-                    "Must specify at least one trust anchor");
-            }
-
-            X500Principal certIssuerName =
-                currCertImpl.getIssuerX500Principal();
-            byte[] certIssuerKeyId = null;
-
-            while (anchors.hasNext() && (seekIssuerCert || seekResponderCert)) {
-
-                TrustAnchor anchor = anchors.next();
-                X509Certificate anchorCert = anchor.getTrustedCert();
-                X500Principal anchorSubjectName =
-                    anchorCert.getSubjectX500Principal();
-
-                if (dump) {
-                    System.out.println("Issuer DN is " + certIssuerName);
-                    System.out.println("Subject DN is " + anchorSubjectName);
-                }
-
-                // Check if anchor cert is the issuer cert
-                if (seekIssuerCert &&
-                    certIssuerName.equals(anchorSubjectName)) {
-
-                    // Retrieve the issuer's key identifier
-                    if (certIssuerKeyId == null) {
-                        certIssuerKeyId = currCertImpl.getIssuerKeyIdentifier();
-                        if (certIssuerKeyId == null) {
-                            if (DEBUG != null) {
-                                DEBUG.println("No issuer key identifier (AKID) "
-                                    + "in the certificate being validated");
-                            }
-                        }
-                    }
-
-                    // Check that the key identifiers match, if both are present
-                    byte[] anchorKeyId = null;
-                    if (certIssuerKeyId != null &&
-                        (anchorKeyId =
-                            OCSPChecker.getKeyId(anchorCert)) != null) {
-                        if (!Arrays.equals(certIssuerKeyId, anchorKeyId)) {
-                            continue; // try next cert
-                        }
-
-                        if (DEBUG != null) {
-                            DEBUG.println("Issuer certificate key ID: " +
-                                String.format("0x%0" +
-                                    (certIssuerKeyId.length * 2) + "x",
-                                        new BigInteger(1, certIssuerKeyId)));
-                        }
-                    }
-
-                    issuerCert = anchorCert;
-                    seekIssuerCert = false; // done
-
-                    // By default, the OCSP responder's cert is the same as
-                    // the issuer of the cert being validated.
-                    if (!seekResponderCert && responderCerts.isEmpty()) {
-                        responderCerts.add(anchorCert);
-                        if (DEBUG != null) {
-                            DEBUG.println("Responder's certificate is the" +
-                                " same as the issuer of the certificate " +
-                                "being validated");
-                        }
-                    }
-                }
-
-                // Check if anchor cert is the responder cert
-                if (seekResponderCert) {
-                    // Satisfy the responder subject name property only, or
-                    // satisfy the responder issuer name and serial number
-                    // properties only
-                    if ((responderSubjectName != null &&
-                         responderSubjectName.equals(anchorSubjectName)) ||
-                        (responderIssuerName != null &&
-                         responderSerialNumber != null &&
-                         responderIssuerName.equals(
-                         anchorCert.getIssuerX500Principal()) &&
-                         responderSerialNumber.equals(
-                         anchorCert.getSerialNumber()))) {
-
-                        responderCerts.add(anchorCert);
-                    }
-                }
-            }
-            if (issuerCert == null) {
-                throw new CertPathValidatorException(
-                    "No trusted certificate for " + currCertImpl.getIssuerDN());
-            }
-
-            // Check cert stores if responder cert has not yet been found
-            if (seekResponderCert) {
-                if (DEBUG != null) {
-                    DEBUG.println("Searching cert stores for responder's " +
-                        "certificate");
-                }
-                X509CertSelector filter = null;
-                if (responderSubjectName != null) {
-                    filter = new X509CertSelector();
-                    filter.setSubject(responderSubjectName);
-                } else if (responderIssuerName != null &&
-                    responderSerialNumber != null) {
-                    filter = new X509CertSelector();
-                    filter.setIssuer(responderIssuerName);
-                    filter.setSerialNumber(responderSerialNumber);
-                }
-                if (filter != null) {
-                    List<CertStore> certStores = pkixParams.getCertStores();
-                    for (CertStore certStore : certStores) {
-                        try {
-                            for (Certificate storeCert : certStore.getCertificates(filter)) {
-                                if (storeCert instanceof X509Certificate) {
-                                    responderCerts.add((X509Certificate) storeCert);
-                                }
-                            }
-                        } catch (CertStoreException cse) {
-                            // ignore and try next certStore
-                            if (DEBUG != null) {
-                                DEBUG.println("CertStore exception:" + cse);
-                            }
-                            continue;
-                        }
-                    }
-                }
-            }
-        }
-
-        // Could not find the certificate identified in the OCSP properties
-        if (seekResponderCert && responderCerts.isEmpty()) {
-            throw new CertPathValidatorException(
-                "Cannot find the responder's certificate " +
-                "(set using the OCSP security properties).");
-        }
-
-        if (DEBUG != null) {
-            DEBUG.println("Located " + responderCerts.size() +
-                " trusted responder certificate(s)");
-        }
-
-        // The algorithm constraints of the OCSP trusted responder certificate
-        // does not need to be checked in this code. The constraints will be
-        // checked when the responder's certificate is validated.
-
-        CertId certId = null;
-        OCSPResponse response = null;
-        try {
-            certId = new CertId
-                (issuerCert, currCertImpl.getSerialNumberObject());
-            response = OCSP.check(Collections.singletonList(certId), uri,
-                responderCerts, pkixParams.getDate());
-        } catch (Exception e) {
-            if (e instanceof CertPathValidatorException) {
-                throw (CertPathValidatorException) e;
-            } else {
-                // Wrap exceptions in CertPathValidatorException so that
-                // we can fallback to CRLs, if enabled.
-                throw new CertPathValidatorException(e);
-            }
-        }
-
-        RevocationStatus rs = (RevocationStatus) response.getSingleResponse(certId);
-        RevocationStatus.CertStatus certStatus = rs.getCertStatus();
-        if (certStatus == RevocationStatus.CertStatus.REVOKED) {
-            Throwable t = new CertificateRevokedException(
-                rs.getRevocationTime(), rs.getRevocationReason(),
-                responderCerts.get(0).getSubjectX500Principal(),
-                rs.getSingleExtensions());
-            throw new CertPathValidatorException(t.getMessage(), t,
-                null, -1, BasicReason.REVOKED);
-        } else if (certStatus == RevocationStatus.CertStatus.UNKNOWN) {
-            throw new CertPathValidatorException(
-                "Certificate's revocation status is unknown", null, cp,
-                (remainingCerts - 1),
-                BasicReason.UNDETERMINED_REVOCATION_STATUS);
-        }
-    }
-
-    /*
-     * The OCSP security property values are in the following order:
-     *   1. ocsp.responderURL
-     *   2. ocsp.responderCertSubjectName
-     *   3. ocsp.responderCertIssuerName
-     *   4. ocsp.responderCertSerialNumber
-     */
-    private static URI getOCSPServerURI(X509CertImpl currCertImpl,
-        String responderURL) throws CertPathValidatorException {
-
-        if (responderURL != null) {
-            try {
-                return new URI(responderURL);
-            } catch (URISyntaxException e) {
-                throw new CertPathValidatorException(e);
-            }
-        }
-
-        // Examine the certificate's AuthorityInfoAccess extension
-        AuthorityInfoAccessExtension aia =
-            currCertImpl.getAuthorityInfoAccessExtension();
-        if (aia == null) {
-            throw new CertPathValidatorException(
-                "Must specify the location of an OCSP Responder");
-        }
-
-        List<AccessDescription> descriptions = aia.getAccessDescriptions();
-        for (AccessDescription description : descriptions) {
-            if (description.getAccessMethod().equals((Object)
-                AccessDescription.Ad_OCSP_Id)) {
-
-                GeneralName generalName = description.getAccessLocation();
-                if (generalName.getType() == GeneralNameInterface.NAME_URI) {
-                    URIName uri = (URIName) generalName.getName();
-                    return uri.getURI();
-                }
-            }
-        }
-
-        throw new CertPathValidatorException(
-            "Cannot find the location of the OCSP Responder");
-    }
-
-    /*
-     * Retrieves the values of the OCSP security properties.
-     */
-    private static String[] getOCSPProperties() {
-        final String[] properties = new String[4];
-
-        AccessController.doPrivileged(
-            new PrivilegedAction<Void>() {
-                public Void run() {
-                    properties[0] = Security.getProperty(OCSP_URL_PROP);
-                    properties[1] =
-                        Security.getProperty(OCSP_CERT_SUBJECT_PROP);
-                    properties[2] =
-                        Security.getProperty(OCSP_CERT_ISSUER_PROP);
-                    properties[3] =
-                        Security.getProperty(OCSP_CERT_NUMBER_PROP);
-                    return null;
-                }
-            });
-
-        return properties;
-    }
-
-    /*
-     * Removes any non-hexadecimal characters from a string.
-     */
-    private static String stripOutSeparators(String value) {
-        char[] chars = value.toCharArray();
-        StringBuilder hexNumber = new StringBuilder();
-        for (int i = 0; i < chars.length; i++) {
-            if (HEX_DIGITS.indexOf(chars[i]) != -1) {
-                hexNumber.append(chars[i]);
-            }
-        }
-        return hexNumber.toString();
-    }
-
-    /*
-     * Returns the subject key identifier for the supplied certificate, or null
-     */
-    static byte[] getKeyId(X509Certificate cert) {
-        X509CertImpl certImpl = null;
-        byte[] certSubjectKeyId = null;
-
-        try {
-            certImpl = X509CertImpl.toImpl(cert);
-            certSubjectKeyId = certImpl.getSubjectKeyIdentifier();
-
-            if (certSubjectKeyId == null) {
-                if (DEBUG != null) {
-                    DEBUG.println("No subject key identifier (SKID) in the " +
-                        "certificate (Subject: " +
-                        cert.getSubjectX500Principal() + ")");
-                }
-            }
-
-        } catch (CertificateException e) {
-            // Ignore certificate
-            if (DEBUG != null) {
-                DEBUG.println("Error parsing X.509 certificate (Subject: " +
-                    cert.getSubjectX500Principal() + ") " + e);
-            }
-        }
-
-        return certSubjectKeyId;
-    }
-}
--- a/src/share/classes/sun/security/provider/certpath/OCSPRequest.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/provider/certpath/OCSPRequest.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2017, 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
@@ -26,14 +26,17 @@
 package sun.security.provider.certpath;
 
 import java.io.IOException;
+import java.security.cert.Extension;
 import java.util.Collections;
 import java.util.List;
+
 import sun.misc.HexDumpEncoder;
 import sun.security.util.*;
+import sun.security.x509.PKIXExtensions;
 
 /**
  * This class can be used to generate an OCSP request and send it over
- * an outputstream. Currently we do not support signing requests
+ * an output stream. Currently we do not support signing requests.
  * The OCSP Request is specified in RFC 2560 and
  * the ASN.1 definition is as follows:
  * <pre>
@@ -75,21 +78,29 @@
 class OCSPRequest {
 
     private static final Debug debug = Debug.getInstance("certpath");
-    private static final boolean dump = Debug.isOn("ocsp");
+    private static final boolean dump = debug != null && Debug.isOn("ocsp");
 
     // List of request CertIds
     private final List<CertId> certIds;
+    private final List<Extension> extensions;
+    private byte[] nonce;
 
     /*
      * Constructs an OCSPRequest. This constructor is used
      * to construct an unsigned OCSP Request for a single user cert.
      */
     OCSPRequest(CertId certId) {
-        this.certIds = Collections.singletonList(certId);
+        this(Collections.singletonList(certId));
     }
 
     OCSPRequest(List<CertId> certIds) {
         this.certIds = certIds;
+        this.extensions = Collections.<Extension>emptyList();
+    }
+
+    OCSPRequest(List<CertId> certIds, List<Extension> extensions) {
+        this.certIds = certIds;
+        this.extensions = extensions;
     }
 
     byte[] encodeBytes() throws IOException {
@@ -104,7 +115,21 @@
         }
 
         tmp.write(DerValue.tag_Sequence, requestsOut);
-        // No extensions supported
+        if (!extensions.isEmpty()) {
+            DerOutputStream extOut = new DerOutputStream();
+            for (Extension ext : extensions) {
+                ext.encode(extOut);
+                if (ext.getId().equals(
+                        PKIXExtensions.OCSPNonce_Id.toString())) {
+                    nonce = ext.getValue();
+                }
+            }
+            DerOutputStream extsOut = new DerOutputStream();
+            extsOut.write(DerValue.tag_Sequence, extOut);
+            tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT,
+                                         true, (byte)2), extsOut);
+        }
+
         DerOutputStream tbsRequest = new DerOutputStream();
         tbsRequest.write(DerValue.tag_Sequence, tmp);
 
@@ -116,8 +141,8 @@
 
         if (dump) {
             HexDumpEncoder hexEnc = new HexDumpEncoder();
-            debug.println("\nOCSPRequest bytes... ");
-            debug.println(hexEnc.encode(bytes) + "\n");
+            debug.println("OCSPRequest bytes...\n\n" +
+                hexEnc.encode(bytes) + "\n");
         }
 
         return bytes;
@@ -126,4 +151,8 @@
     List<CertId> getCertIds() {
         return certIds;
     }
+
+    byte[] getNonce() {
+        return nonce;
+    }
 }
--- a/src/share/classes/sun/security/provider/certpath/OCSPResponse.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/provider/certpath/OCSPResponse.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2017, 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
@@ -34,12 +34,16 @@
 import java.security.cert.CRLReason;
 import java.security.cert.TrustAnchor;
 import java.security.cert.X509Certificate;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
+import javax.security.auth.x500.X500Principal;
+
 import sun.misc.HexDumpEncoder;
 import sun.security.action.GetIntegerAction;
 import sun.security.x509.*;
@@ -126,15 +130,12 @@
         SIG_REQUIRED,          // Must sign the request
         UNAUTHORIZED           // Request unauthorized
     };
-    private static ResponseStatus[] rsvalues = ResponseStatus.values();
+    private static final ResponseStatus[] rsvalues = ResponseStatus.values();
 
-    private static final Debug DEBUG = Debug.getInstance("certpath");
-    private static final boolean dump = Debug.isOn("ocsp");
+    private static final Debug debug = Debug.getInstance("certpath");
+    private static final boolean dump = debug != null && Debug.isOn("ocsp");
     private static final ObjectIdentifier OCSP_BASIC_RESPONSE_OID =
         ObjectIdentifier.newInternal(new int[] { 1, 3, 6, 1, 5, 5, 7, 48, 1, 1});
-    private static final ObjectIdentifier OCSP_NONCE_EXTENSION_OID =
-        ObjectIdentifier.newInternal(new int[] { 1, 3, 6, 1, 5, 5, 7, 48, 1, 2});
-
     private static final int CERT_STATUS_GOOD = 0;
     private static final int CERT_STATUS_REVOKED = 1;
     private static final int CERT_STATUS_UNKNOWN = 2;
@@ -146,9 +147,6 @@
     // Object identifier for the OCSPSigning key purpose
     private static final String KP_OCSP_SIGNING_OID = "1.3.6.1.5.5.7.3.9";
 
-    private final ResponseStatus responseStatus;
-    private final Map<CertId, SingleResponse> singleResponseMap;
-
     // Default maximum clock skew in milliseconds (15 minutes)
     // allowed when checking validity of OCSP responses
     private static final int DEFAULT_MAX_CLOCK_SKEW = 900000;
@@ -176,20 +174,30 @@
     }
 
     // an array of all of the CRLReasons (used in SingleResponse)
-    private static CRLReason[] values = CRLReason.values();
+    private static final CRLReason[] values = CRLReason.values();
+
+    private final ResponseStatus responseStatus;
+    private final Map<CertId, SingleResponse> singleResponseMap;
+    private final AlgorithmId sigAlgId;
+    private final byte[] signature;
+    private final byte[] tbsResponseData;
+    private final byte[] responseNonce;
+    private List<X509CertImpl> certs;
+    private X509CertImpl signerCert = null;
+    private final ResponderId respId;
+    private Date producedAtDate = null;
+    private final Map<String, java.security.cert.Extension> responseExtensions;
 
     /*
      * Create an OCSP response from its ASN.1 DER encoding.
+     *
+     * @param bytes The DER-encoded bytes for an OCSP response
      */
-    OCSPResponse(byte[] bytes, Date dateCheckedAgainst,
-        List<X509Certificate> responderCerts)
-        throws IOException, CertPathValidatorException {
-
-        // OCSPResponse
+    public OCSPResponse(byte[] bytes) throws IOException {
         if (dump) {
             HexDumpEncoder hexEnc = new HexDumpEncoder();
-            DEBUG.println("\nOCSPResponse bytes...");
-            DEBUG.println(hexEnc.encode(bytes) + "\n");
+            debug.println("OCSPResponse bytes...\n\n" +
+                hexEnc.encode(bytes) + "\n");
         }
         DerValue der = new DerValue(bytes);
         if (der.tag != DerValue.tag_Sequence) {
@@ -206,12 +214,19 @@
             // unspecified responseStatus
             throw new IOException("Unknown OCSPResponse status: " + status);
         }
-        if (DEBUG != null) {
-            DEBUG.println("OCSP response status: " + responseStatus);
+        if (debug != null) {
+            debug.println("OCSP response status: " + responseStatus);
         }
         if (responseStatus != ResponseStatus.SUCCESSFUL) {
             // no need to continue, responseBytes are not set.
             singleResponseMap = Collections.emptyMap();
+            certs = new ArrayList<X509CertImpl>();
+            sigAlgId = null;
+            signature = null;
+            tbsResponseData = null;
+            responseNonce = null;
+            responseExtensions = Collections.emptyMap();
+            respId = null;
             return;
         }
 
@@ -231,15 +246,15 @@
         derIn = tmp.data;
         ObjectIdentifier responseType = derIn.getOID();
         if (responseType.equals((Object)OCSP_BASIC_RESPONSE_OID)) {
-            if (DEBUG != null) {
-                DEBUG.println("OCSP response type: basic");
+            if (debug != null) {
+                debug.println("OCSP response type: basic");
             }
         } else {
-            if (DEBUG != null) {
-                DEBUG.println("OCSP response type: " + responseType);
+            if (debug != null) {
+                debug.println("OCSP response type: " + responseType);
             }
             throw new IOException("Unsupported OCSP response type: " +
-                responseType);
+                                  responseType);
         }
 
         // BasicOCSPResponse
@@ -254,7 +269,7 @@
         DerValue responseData = seqTmp[0];
 
         // Need the DER encoded ResponseData to verify the signature later
-        byte[] responseDataDer = seqTmp[0].toByteArray();
+        tbsResponseData = seqTmp[0].toByteArray();
 
         // tbsResponseData
         if (responseData.tag != DerValue.tag_Sequence) {
@@ -280,79 +295,54 @@
         }
 
         // responderID
-        short tag = (byte)(seq.tag & 0x1f);
-        if (tag == NAME_TAG) {
-            if (DEBUG != null) {
-                X500Name responderName = new X500Name(seq.getData());
-                DEBUG.println("OCSP Responder name: " + responderName);
-            }
-        } else if (tag == KEY_TAG) {
-            seq = seq.data.getDerValue(); // consume tag and length
-            if (DEBUG != null) {
-                byte[] responderKeyId = seq.getOctetString();
-                DEBUG.println("OCSP Responder key ID: " +
-                    String.format("0x%0" +
-                        (responderKeyId.length * 2) + "x",
-                            new BigInteger(1, responderKeyId)));
-            }
-        } else {
-            throw new IOException("Bad encoding in responderID element of " +
-                "OCSP response: expected ASN.1 context specific tag 1 or 2");
+        respId = new ResponderId(seq.toByteArray());
+        if (debug != null) {
+            debug.println("Responder ID: " + respId);
         }
 
         // producedAt
         seq = seqDerIn.getDerValue();
-        if (DEBUG != null) {
-            Date producedAtDate = seq.getGeneralizedTime();
-            DEBUG.println("OCSP response produced at: " + producedAtDate);
+        producedAtDate = seq.getGeneralizedTime();
+        if (debug != null) {
+            debug.println("OCSP response produced at: " + producedAtDate);
         }
 
         // responses
         DerValue[] singleResponseDer = seqDerIn.getSequence(1);
-        singleResponseMap
-            = new HashMap<CertId, SingleResponse>(singleResponseDer.length);
-        if (DEBUG != null) {
-            DEBUG.println("OCSP number of SingleResponses: "
-                + singleResponseDer.length);
+        singleResponseMap = new HashMap<>(singleResponseDer.length);
+        if (debug != null) {
+            debug.println("OCSP number of SingleResponses: "
+                          + singleResponseDer.length);
         }
-        for (int i = 0; i < singleResponseDer.length; i++) {
-            SingleResponse singleResponse
-                = new SingleResponse(singleResponseDer[i], dateCheckedAgainst);
+        for (DerValue srDer : singleResponseDer) {
+            SingleResponse singleResponse = new SingleResponse(srDer);
             singleResponseMap.put(singleResponse.getCertId(), singleResponse);
         }
 
         // responseExtensions
+        Map<String, java.security.cert.Extension> tmpExtMap = new HashMap<>();
         if (seqDerIn.available() > 0) {
             seq = seqDerIn.getDerValue();
             if (seq.isContextSpecific((byte)1)) {
-                DerValue[] responseExtDer = seq.data.getSequence(3);
-                for (int i = 0; i < responseExtDer.length; i++) {
-                    Extension responseExtension
-                        = new Extension(responseExtDer[i]);
-                    if (DEBUG != null) {
-                        DEBUG.println("OCSP extension: " + responseExtension);
-                    }
-                    if (responseExtension.getExtensionId().equals((Object)
-                        OCSP_NONCE_EXTENSION_OID)) {
-                        /*
-                        ocspNonce =
-                            responseExtension[i].getExtensionValue();
-                         */
-                    } else if (responseExtension.isCritical())  {
-                        throw new IOException(
-                            "Unsupported OCSP critical extension: " +
-                            responseExtension.getExtensionId());
-                    }
-                }
+                tmpExtMap = parseExtensions(seq);
             }
         }
+        responseExtensions = tmpExtMap;
+
+        // Attach the nonce value if found in the extension map
+        Extension nonceExt = (Extension)tmpExtMap.get(
+                PKIXExtensions.OCSPNonce_Id.toString());
+        responseNonce = (nonceExt != null) ?
+                nonceExt.getExtensionValue() : null;
+        if (debug != null && responseNonce != null) {
+            debug.println("Response nonce: " + Arrays.toString(responseNonce));
+        }
 
         // signatureAlgorithmId
-        AlgorithmId sigAlgId = AlgorithmId.parse(seqTmp[1]);
+        sigAlgId = AlgorithmId.parse(seqTmp[1]);
 
         // signature
-        byte[] signature = seqTmp[2].getBitString();
-        X509CertImpl[] x509Certs = null;
+        signature = seqTmp[2].getBitString();
 
         // if seq[3] is available , then it is a sequence of certificates
         if (seqTmp.length > 3) {
@@ -362,234 +352,413 @@
                 throw new IOException("Bad encoding in certs element of " +
                     "OCSP response: expected ASN.1 context specific tag 0.");
             }
-            DerValue[] certs = seqCert.getData().getSequence(3);
-            x509Certs = new X509CertImpl[certs.length];
+            DerValue[] derCerts = seqCert.getData().getSequence(3);
+            certs = new ArrayList<X509CertImpl>(derCerts.length);
             try {
-                for (int i = 0; i < certs.length; i++) {
-                    x509Certs[i] = new X509CertImpl(certs[i].toByteArray());
+                for (int i = 0; i < derCerts.length; i++) {
+                    X509CertImpl cert =
+                        new X509CertImpl(derCerts[i].toByteArray());
+                    certs.add(cert);
+
+                    if (debug != null) {
+                        debug.println("OCSP response cert #" + (i + 1) + ": " +
+                            cert.getSubjectX500Principal());
+                    }
                 }
             } catch (CertificateException ce) {
                 throw new IOException("Bad encoding in X509 Certificate", ce);
             }
+        } else {
+            certs = Collections.<X509CertImpl>emptyList();
+        }
+    }
+
+    void verify(List<CertId> certIds, IssuerInfo issuerInfo,
+            X509Certificate responderCert, Date date, byte[] nonce,
+            String variant)
+        throws CertPathValidatorException
+    {
+        if (responseStatus != ResponseStatus.SUCCESSFUL) {
+            throw new CertPathValidatorException
+                ("OCSP response error: " + responseStatus);
         }
 
-        // By default, the OCSP responder's cert is the same as the issuer of
-        // the cert being validated. The issuer cert is the first in the list.
-        X509Certificate trustedResponderCert = responderCerts.get(0);
-
-        // Check whether the signer cert returned by the responder is trusted
-        if (x509Certs != null && x509Certs[0] != null) {
-            X509CertImpl signerCert = x509Certs[0];
+        // Check that the response includes a response for all of the
+        // certs that were supplied in the request
+        for (CertId certId : certIds) {
+            SingleResponse sr = getSingleResponse(certId);
+            if (sr == null) {
+                if (debug != null) {
+                    debug.println("No response found for CertId: " + certId);
+                }
+                throw new CertPathValidatorException(
+                    "OCSP response does not include a response for a " +
+                    "certificate supplied in the OCSP request");
+            }
+            if (debug != null) {
+                debug.println("Status of certificate (with serial number " +
+                    certId.getSerialNumber() + ") is: " + sr.getCertStatus());
+            }
+        }
 
-            if (DEBUG != null) {
-                DEBUG.println("Signer certificate name: " +
-                    signerCert.getSubjectX500Principal());
-
-                byte[] signerKeyId = signerCert.getSubjectKeyIdentifier();
-                if (signerKeyId != null) {
-                    DEBUG.println("Signer certificate key ID: " +
-                        String.format("0x%0" + (signerKeyId.length * 2) + "x",
-                                new BigInteger(1, signerKeyId)));
+        // Locate the signer cert
+        if (signerCert == null) {
+            // Add the Issuing CA cert and/or Trusted Responder cert to the list
+            // of certs from the OCSP response
+            try {
+                if (issuerInfo.getCertificate() != null) {
+                    certs.add(X509CertImpl.toImpl(issuerInfo.getCertificate()));
                 }
+                if (responderCert != null) {
+                    certs.add(X509CertImpl.toImpl(responderCert));
+                }
+            } catch (CertificateException ce) {
+                throw new CertPathValidatorException(
+                    "Invalid issuer or trusted responder certificate", ce);
             }
 
-            byte[] certIssuerKeyId = null;
-
-            for (X509Certificate responderCert : responderCerts) {
-
-                // First check if signer cert matches a trusted responder cert
-                if (signerCert.equals(responderCert)) {
-
-                    // signer cert is trusted, now verify the signed response
-                    trustedResponderCert = responderCert;
-                    if (DEBUG != null) {
-                        DEBUG.println("Signer certificate is a trusted " +
-                            "responder");
+            if (respId.getType() == ResponderId.Type.BY_NAME) {
+                X500Principal rName = respId.getResponderName();
+                for (X509CertImpl cert : certs) {
+                    if (cert.getSubjectX500Principal().equals(rName)) {
+                        signerCert = cert;
+                        break;
                     }
-                    break;
-
-                // Next check if signer cert was issued by a trusted responder
-                // cert
-                } else if (signerCert.getIssuerX500Principal().equals(
-                    responderCert.getSubjectX500Principal())) {
-
-                    // Retrieve the issuer's key identifier
-                    if (certIssuerKeyId == null) {
-                        certIssuerKeyId = signerCert.getIssuerKeyIdentifier();
-                        if (certIssuerKeyId == null) {
-                            if (DEBUG != null) {
-                                DEBUG.println("No issuer key identifier (AKID) "
-                                    + "in the signer certificate");
-                            }
-                        }
-                    }
-
-                    // Check that the key identifiers match, if both are present
-                    byte[] responderKeyId = null;
-                    if (certIssuerKeyId != null &&
-                        (responderKeyId =
-                            OCSPChecker.getKeyId(responderCert)) != null) {
-                        if (!Arrays.equals(certIssuerKeyId, responderKeyId)) {
-                            continue; // try next cert
-                        }
-
-                        if (DEBUG != null) {
-                            DEBUG.println("Issuer certificate key ID: " +
-                                String.format("0x%0" +
-                                    (certIssuerKeyId.length * 2) + "x",
-                                        new BigInteger(1, certIssuerKeyId)));
-                        }
-                    }
-
-                    // Check for the OCSPSigning key purpose
-                    try {
-                        List<String> keyPurposes =
-                            signerCert.getExtendedKeyUsage();
-                        if (keyPurposes == null ||
-                            !keyPurposes.contains(KP_OCSP_SIGNING_OID)) {
-
-                            continue; // try next cert
+                }
+            } else if (respId.getType() == ResponderId.Type.BY_KEY) {
+                KeyIdentifier ridKeyId = respId.getKeyIdentifier();
+                for (X509CertImpl cert : certs) {
+                    // Match responder's key identifier against the cert's SKID
+                    // This will match if the SKID is encoded using the 160-bit
+                    // SHA-1 hash method as defined in RFC 5280.
+                    KeyIdentifier certKeyId = cert.getSubjectKeyId();
+                    if (certKeyId != null && ridKeyId.equals(certKeyId)) {
+                        signerCert = cert;
+                        break;
+                    } else {
+                        // The certificate does not have a SKID or may have
+                        // been using a different algorithm (ex: see RFC 7093).
+                        // Check if the responder's key identifier matches
+                        // against a newly generated key identifier of the
+                        // cert's public key using the 160-bit SHA-1 method.
+                        try {
+                            certKeyId = new KeyIdentifier(cert.getPublicKey());
+                        } catch (IOException e) {
+                            // ignore
                         }
-                    } catch (CertificateParsingException cpe) {
-
-                        continue; // try next cert
-                    }
-
-                    // Check algorithm constraints specified in security
-                    // property "jdk.certpath.disabledAlgorithms".
-                    AlgorithmChecker algChecker = new AlgorithmChecker(
-                                        new TrustAnchor(responderCert, null));
-                    algChecker.init(false);
-                    algChecker.check(signerCert,
-                        Collections.<String>emptySet());
-
-                    // Check the date validity
-                    try {
-                        if (dateCheckedAgainst == null) {
-                            signerCert.checkValidity();
-                        } else {
-                            signerCert.checkValidity(dateCheckedAgainst);
-                        }
-                    } catch (GeneralSecurityException e) {
-                        if (DEBUG != null) {
-                            DEBUG.println("Responder's certificate not within" +
-                            " the validity period " + e);
+                        if (ridKeyId.equals(certKeyId)) {
+                            signerCert = cert;
+                            break;
                         }
-                        continue; // try next cert
-                    }
-
-                    // Check for revocation
-                    //
-                    // A CA may specify that an OCSP client can trust a
-                    // responder for the lifetime of the responder's
-                    // certificate. The CA does so by including the
-                    // extension id-pkix-ocsp-nocheck.
-                    //
-                    Extension noCheck =
-                        signerCert.getExtension(PKIXExtensions.OCSPNoCheck_Id);
-                    if (noCheck != null) {
-                        if (DEBUG != null) {
-                            DEBUG.println("Responder's certificate includes " +
-                                "the extension id-pkix-ocsp-nocheck.");
-                        }
-                    } else {
-                        // we should do the revocation checking of the
-                        // authorized responder in a future update.
-                    }
-
-                    // Verify the signature
-                    try {
-                        signerCert.verify(responderCert.getPublicKey());
-                        trustedResponderCert = signerCert;
-                        // cert is trusted, now verify the signed response
-                        if (DEBUG != null) {
-                            DEBUG.println("Signer certificate was issued by " +
-                                "a trusted responder");
-                        }
-                        break;
-
-                    } catch (GeneralSecurityException e) {
-                        trustedResponderCert = null;
                     }
                 }
             }
         }
 
+        // Check whether the signer cert returned by the responder is trusted
+        if (signerCert != null) {
+            // Check if the response is signed by the issuing CA
+            if (signerCert.getSubjectX500Principal().equals(
+                    issuerInfo.getName()) &&
+                    signerCert.getPublicKey().equals(
+                            issuerInfo.getPublicKey())) {
+                if (debug != null) {
+                    debug.println("OCSP response is signed by the target's " +
+                        "Issuing CA");
+                }
+                // cert is trusted, now verify the signed response
+
+            // Check if the response is signed by a trusted responder
+            } else if (signerCert.equals(responderCert)) {
+                if (debug != null) {
+                    debug.println("OCSP response is signed by a Trusted " +
+                        "Responder");
+                }
+                // cert is trusted, now verify the signed response
+
+            // Check if the response is signed by an authorized responder
+            } else if (signerCert.getIssuerX500Principal().equals(
+                    issuerInfo.getName())) {
+
+                // Check for the OCSPSigning key purpose
+                try {
+                    List<String> keyPurposes = signerCert.getExtendedKeyUsage();
+                    if (keyPurposes == null ||
+                        !keyPurposes.contains(KP_OCSP_SIGNING_OID)) {
+                        throw new CertPathValidatorException(
+                            "Responder's certificate not valid for signing " +
+                            "OCSP responses");
+                    }
+                } catch (CertificateParsingException cpe) {
+                    // assume cert is not valid for signing
+                    throw new CertPathValidatorException(
+                        "Responder's certificate not valid for signing " +
+                        "OCSP responses", cpe);
+                }
+
+                // Check algorithm constraints specified in security property
+                // "jdk.certpath.disabledAlgorithms".
+                AlgorithmChecker algChecker =
+                        new AlgorithmChecker(issuerInfo.getAnchor(), date,
+                                variant);
+                algChecker.init(false);
+                algChecker.check(signerCert, Collections.<String>emptySet());
+
+                // check the validity
+                try {
+                    if (date == null) {
+                        signerCert.checkValidity();
+                    } else {
+                        signerCert.checkValidity(date);
+                    }
+                } catch (CertificateException e) {
+                    throw new CertPathValidatorException(
+                        "Responder's certificate not within the " +
+                        "validity period", e);
+                }
+
+                // check for revocation
+                //
+                // A CA may specify that an OCSP client can trust a
+                // responder for the lifetime of the responder's
+                // certificate. The CA does so by including the
+                // extension id-pkix-ocsp-nocheck.
+                //
+                Extension noCheck =
+                    signerCert.getExtension(PKIXExtensions.OCSPNoCheck_Id);
+                if (noCheck != null) {
+                    if (debug != null) {
+                        debug.println("Responder's certificate includes " +
+                            "the extension id-pkix-ocsp-nocheck.");
+                    }
+                } else {
+                    // we should do the revocation checking of the
+                    // authorized responder in a future update.
+                }
+
+                // verify the signature
+                try {
+                    signerCert.verify(issuerInfo.getPublicKey());
+                    if (debug != null) {
+                        debug.println("OCSP response is signed by an " +
+                            "Authorized Responder");
+                    }
+                    // cert is trusted, now verify the signed response
+
+                } catch (GeneralSecurityException e) {
+                    signerCert = null;
+                }
+            } else {
+                throw new CertPathValidatorException(
+                    "Responder's certificate is not authorized to sign " +
+                    "OCSP responses");
+            }
+        }
+
         // Confirm that the signed response was generated using the public
         // key from the trusted responder cert
-        if (trustedResponderCert != null) {
+        if (signerCert != null) {
             // Check algorithm constraints specified in security property
             // "jdk.certpath.disabledAlgorithms".
-            AlgorithmChecker.check(trustedResponderCert.getPublicKey(),
-                sigAlgId);
+            AlgorithmChecker.check(signerCert.getPublicKey(), sigAlgId, variant);
 
-            if (!verifyResponse(responseDataDer, trustedResponderCert,
-                sigAlgId, signature)) {
+            if (!verifySignature(signerCert)) {
                 throw new CertPathValidatorException(
-                    "Error verifying OCSP Responder's signature");
+                    "Error verifying OCSP Response's signature");
             }
         } else {
             // Need responder's cert in order to verify the signature
             throw new CertPathValidatorException(
-                "Responder's certificate is not trusted for signing " +
-                "OCSP responses");
+                "Unable to verify OCSP Response's signature");
+        }
+
+        if (nonce != null) {
+            if (responseNonce != null && !Arrays.equals(nonce, responseNonce)) {
+                throw new CertPathValidatorException("Nonces don't match");
+            }
+        }
+
+        // Check freshness of OCSPResponse
+        long now = (date == null) ? System.currentTimeMillis() : date.getTime();
+        Date nowPlusSkew = new Date(now + MAX_CLOCK_SKEW);
+        Date nowMinusSkew = new Date(now - MAX_CLOCK_SKEW);
+        for (SingleResponse sr : singleResponseMap.values()) {
+            if (debug != null) {
+                String until = "";
+                if (sr.nextUpdate != null) {
+                    until = " until " + sr.nextUpdate;
+                }
+                debug.println("OCSP response validity interval is from " +
+                        sr.thisUpdate + until);
+                debug.println("Checking validity of OCSP response on: " +
+                        new Date(now));
+            }
+
+            // Check that the test date is within the validity interval:
+            //   [ thisUpdate - MAX_CLOCK_SKEW,
+            //     MAX(thisUpdate, nextUpdate) + MAX_CLOCK_SKEW ]
+            if (nowPlusSkew.before(sr.thisUpdate) ||
+                    nowMinusSkew.after(
+                    sr.nextUpdate != null ? sr.nextUpdate : sr.thisUpdate))
+            {
+                throw new CertPathValidatorException(
+                                      "Response is unreliable: its validity " +
+                                      "interval is out-of-date");
+            }
         }
     }
 
     /**
      * Returns the OCSP ResponseStatus.
+     *
+     * @return the {@code ResponseStatus} for this OCSP response
      */
-    ResponseStatus getResponseStatus() {
+    public ResponseStatus getResponseStatus() {
         return responseStatus;
     }
 
     /*
      * Verify the signature of the OCSP response.
-     * The responder's cert is implicitly trusted.
      */
-    private boolean verifyResponse(byte[] responseData, X509Certificate cert,
-        AlgorithmId sigAlgId, byte[] signBytes)
+    private boolean verifySignature(X509Certificate cert)
         throws CertPathValidatorException {
 
         try {
             Signature respSignature = Signature.getInstance(sigAlgId.getName());
             respSignature.initVerify(cert.getPublicKey());
-            respSignature.update(responseData);
+            respSignature.update(tbsResponseData);
 
-            if (respSignature.verify(signBytes)) {
-                if (DEBUG != null) {
-                    DEBUG.println("Verified signature of OCSP Responder");
+            if (respSignature.verify(signature)) {
+                if (debug != null) {
+                    debug.println("Verified signature of OCSP Response");
                 }
                 return true;
 
             } else {
-                if (DEBUG != null) {
-                    DEBUG.println(
-                        "Error verifying signature of OCSP Responder");
+                if (debug != null) {
+                    debug.println(
+                        "Error verifying signature of OCSP Response");
                 }
                 return false;
             }
-        } catch (InvalidKeyException ike) {
-            throw new CertPathValidatorException(ike);
-        } catch (NoSuchAlgorithmException nsae) {
-            throw new CertPathValidatorException(nsae);
-        } catch (SignatureException se) {
-            throw new CertPathValidatorException(se);
+        } catch (InvalidKeyException | NoSuchAlgorithmException |
+                 SignatureException e)
+        {
+            throw new CertPathValidatorException(e);
         }
     }
 
     /**
      * Returns the SingleResponse of the specified CertId, or null if
      * there is no response for that CertId.
+     *
+     * @param certId the {@code CertId} for a {@code SingleResponse} to be
+     * searched for in the OCSP response.
+     *
+     * @return the {@code SingleResponse} for the provided {@code CertId},
+     * or {@code null} if it is not found.
      */
-    SingleResponse getSingleResponse(CertId certId) {
+    public SingleResponse getSingleResponse(CertId certId) {
         return singleResponseMap.get(certId);
     }
 
+    /**
+     * Return a set of all CertIds in this {@code OCSPResponse}
+     *
+     * @return an unmodifiable set containing every {@code CertId} in this
+     *      response.
+     */
+    public Set<CertId> getCertIds() {
+        return Collections.unmodifiableSet(singleResponseMap.keySet());
+    }
+
+    /*
+     * Returns the certificate for the authority that signed the OCSP response.
+     */
+    X509Certificate getSignerCertificate() {
+        return signerCert; // set in verify()
+    }
+
+    /**
+     * Get the {@code ResponderId} from this {@code OCSPResponse}
+     *
+     * @return the {@code ResponderId} from this response or {@code null}
+     *      if no responder ID is in the body of the response (e.g. a
+     *      response with a status other than SUCCESS.
+     */
+    public ResponderId getResponderId() {
+        return respId;
+    }
+
+    /**
+     * Provide a String representation of an OCSPResponse
+     *
+     * @return a human-readable representation of the OCSPResponse
+     */
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("OCSP Response:\n");
+        sb.append("Response Status: ").append(responseStatus).append("\n");
+        sb.append("Responder ID: ").append(respId).append("\n");
+        sb.append("Produced at: ").append(producedAtDate).append("\n");
+        int count = singleResponseMap.size();
+        sb.append(count).append(count == 1 ?
+                " response:\n" : " responses:\n");
+        for (SingleResponse sr : singleResponseMap.values()) {
+            sb.append(sr).append("\n");
+        }
+        if (responseExtensions != null && responseExtensions.size() > 0) {
+            count = responseExtensions.size();
+            sb.append(count).append(count == 1 ?
+                    " extension:\n" : " extensions:\n");
+            for (String extId : responseExtensions.keySet()) {
+                sb.append(responseExtensions.get(extId)).append("\n");
+            }
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Build a String-Extension map from DER encoded data.
+     * @param derVal A {@code DerValue} object built from a SEQUENCE of
+     *      extensions
+     *
+     * @return a {@code Map} using the OID in string form as the keys.  If no
+     *      extensions are found or an empty SEQUENCE is passed in, then
+     *      an empty {@code Map} will be returned.
+     *
+     * @throws IOException if any decoding errors occur.
+     */
+    private static Map<String, java.security.cert.Extension>
+        parseExtensions(DerValue derVal) throws IOException {
+        DerValue[] extDer = derVal.data.getSequence(3);
+        Map<String, java.security.cert.Extension> extMap =
+                new HashMap<>(extDer.length);
+
+        for (DerValue extDerVal : extDer) {
+            Extension ext = new Extension(extDerVal);
+            if (debug != null) {
+                debug.println("Extension: " + ext);
+            }
+            // We don't support any extensions yet. Therefore, if it
+            // is critical we must throw an exception because we
+            // don't know how to process it.
+            if (ext.isCritical()) {
+                throw new IOException("Unsupported OCSP critical extension: " +
+                        ext.getExtensionId());
+            }
+            extMap.put(ext.getId(), ext);
+        }
+
+        return extMap;
+    }
+
     /*
      * A class representing a single OCSP response.
      */
-    final static class SingleResponse implements OCSP.RevocationStatus {
+    public static final class SingleResponse implements OCSP.RevocationStatus {
         private final CertId certId;
         private final CertStatus certStatus;
         private final Date thisUpdate;
@@ -633,13 +802,13 @@
                     revocationReason = CRLReason.UNSPECIFIED;
                 }
                 // RevokedInfo
-                if (DEBUG != null) {
-                    DEBUG.println("Revocation time: " + revocationTime);
-                    DEBUG.println("Revocation reason: " + revocationReason);
+                if (debug != null) {
+                    debug.println("Revocation time: " + revocationTime);
+                    debug.println("Revocation reason: " + revocationReason);
                 }
             } else {
                 revocationTime = null;
-                revocationReason = CRLReason.UNSPECIFIED;
+                revocationReason = null;
                 if (tag == CERT_STATUS_GOOD) {
                     certStatus = CertStatus.GOOD;
                 } else if (tag == CERT_STATUS_UNKNOWN) {
@@ -650,105 +819,131 @@
             }
 
             thisUpdate = tmp.getGeneralizedTime();
-
-            if (tmp.available() == 0)  {
-                // we are done
-                nextUpdate = null;
-            } else {
-                derVal = tmp.getDerValue();
-                tag = (byte)(derVal.tag & 0x1f);
-                if (tag == 0) {
-                    // next update
-                    nextUpdate = derVal.data.getGeneralizedTime();
+            if (debug != null) {
+                debug.println("thisUpdate: " + thisUpdate);
+            }
 
-                    if (tmp.available() == 0)  {
-                        // we are done
-                    } else {
-                        derVal = tmp.getDerValue();
-                        tag = (byte)(derVal.tag & 0x1f);
-                    }
-                } else {
-                    nextUpdate = null;
-                }
-            }
-            // singleExtensions
+            // Parse optional fields like nextUpdate and singleExtensions
+            Date tmpNextUpdate = null;
+            Map<String, java.security.cert.Extension> tmpMap = null;
+
+            // Check for the first optional item, it could be nextUpdate
+            // [CONTEXT 0] or singleExtensions [CONTEXT 1]
             if (tmp.available() > 0) {
                 derVal = tmp.getDerValue();
-                if (derVal.isContextSpecific((byte)1)) {
-                    DerValue[] singleExtDer = derVal.data.getSequence(3);
-                    singleExtensions =
-                        new HashMap<String, java.security.cert.Extension>
-                            (singleExtDer.length);
-                    for (int i = 0; i < singleExtDer.length; i++) {
-                        Extension ext = new Extension(singleExtDer[i]);
-                        if (DEBUG != null) {
-                            DEBUG.println("OCSP single extension: " + ext);
+
+                // nextUpdate processing
+                if (derVal.isContextSpecific((byte)0)) {
+                    tmpNextUpdate = derVal.data.getGeneralizedTime();
+                    if (debug != null) {
+                        debug.println("nextUpdate: " + tmpNextUpdate);
+                    }
+
+                    // If more data exists in the singleResponse, it
+                    // can only be singleExtensions.  Get this DER value
+                    // for processing in the next block
+                    derVal = tmp.available() > 0 ? tmp.getDerValue() : null;
+                }
+
+                // singleExtensions processing
+                if (derVal != null) {
+                    if (derVal.isContextSpecific((byte)1)) {
+                        tmpMap = parseExtensions(derVal);
+
+                        // There should not be any other items in the
+                        // singleResponse at this point.
+                        if (tmp.available() > 0) {
+                            throw new IOException(tmp.available() +
+                                " bytes of additional data in singleResponse");
                         }
-                        // We don't support any extensions yet. Therefore, if it
-                        // is critical we must throw an exception because we
-                        // don't know how to process it.
-                        if (ext.isCritical()) {
-                            throw new IOException(
-                                "Unsupported OCSP critical extension: " +
-                                ext.getExtensionId());
-                        }
-                        singleExtensions.put(ext.getId(), ext);
+                    } else {
+                        // Unknown item in the singleResponse
+                        throw new IOException("Unsupported singleResponse " +
+                            "item, tag = " + String.format("%02X", derVal.tag));
                     }
-                } else {
-                    singleExtensions = Collections.emptyMap();
                 }
-            } else {
-                singleExtensions = Collections.emptyMap();
             }
 
-            long now = System.currentTimeMillis();
-            Date nowPlusSkew = new Date(now + MAX_CLOCK_SKEW);
-            Date nowMinusSkew = new Date(now - MAX_CLOCK_SKEW);
-            if (DEBUG != null) {
-                String until = "";
-                if (nextUpdate != null) {
-                    until = " until " + nextUpdate;
+            nextUpdate = tmpNextUpdate;
+            singleExtensions = (tmpMap != null) ? tmpMap :
+                    Collections.<String, java.security.cert.Extension>emptyMap();
+            if (debug != null) {
+                for (java.security.cert.Extension ext :
+                        singleExtensions.values()) {
+                   debug.println("singleExtension: " + ext);
                 }
-                DEBUG.println("OCSP response validity interval is from " +
-                              thisUpdate + until);
-                DEBUG.println("Checking validity of OCSP response on: " +
-                    new Date(now));
-            }
-            // Check that the test date is within the validity interval:
-            //   [ thisUpdate - MAX_CLOCK_SKEW,
-            //     MAX(thisUpdate, nextUpdate) + MAX_CLOCK_SKEW ]
-            if (nowPlusSkew.before(thisUpdate) ||
-                nowMinusSkew.after(
-                    nextUpdate != null ? nextUpdate : thisUpdate)) {
-
-                if (DEBUG != null) {
-                    DEBUG.println("Response is unreliable: its validity " +
-                        "interval is out-of-date");
-                }
-                throw new IOException("Response is unreliable: its validity " +
-                    "interval is out-of-date");
             }
         }
 
         /*
          * Return the certificate's revocation status code
          */
-        @Override public CertStatus getCertStatus() {
+        @Override
+        public CertStatus getCertStatus() {
             return certStatus;
         }
 
-        private CertId getCertId() {
+        /**
+         * Get the Cert ID that this SingleResponse is for.
+         *
+         * @return the {@code CertId} for this {@code SingleResponse}
+         */
+        public CertId getCertId() {
             return certId;
         }
 
-        @Override public Date getRevocationTime() {
-            return (Date) revocationTime.clone();
+        /**
+         * Get the {@code thisUpdate} field from this {@code SingleResponse}.
+         *
+         * @return a {@link Date} object containing the thisUpdate date
+         */
+        public Date getThisUpdate() {
+            return (thisUpdate != null ? (Date) thisUpdate.clone() : null);
+        }
+
+        /**
+         * Get the {@code nextUpdate} field from this {@code SingleResponse}.
+         *
+         * @return a {@link Date} object containing the nexUpdate date or
+         * {@code null} if a nextUpdate field is not present in the response.
+         */
+        public Date getNextUpdate() {
+            return (nextUpdate != null ? (Date) nextUpdate.clone() : null);
         }
 
-        @Override public CRLReason getRevocationReason() {
+        /**
+         * Get the {@code revocationTime} field from this
+         * {@code SingleResponse}.
+         *
+         * @return a {@link Date} object containing the revocationTime date or
+         * {@code null} if the {@code SingleResponse} does not have a status
+         * of {@code REVOKED}.
+         */
+        @Override
+        public Date getRevocationTime() {
+            return (revocationTime != null ? (Date) revocationTime.clone() :
+                    null);
+        }
+
+        /**
+         * Get the {@code revocationReason} field for the
+         * {@code SingleResponse}.
+         *
+         * @return a {@link CRLReason} containing the revocation reason, or
+         * {@code null} if a revocation reason was not provided or the
+         * response status is not {@code REVOKED}.
+         */
+        @Override
+        public CRLReason getRevocationReason() {
             return revocationReason;
         }
 
+        /**
+         * Get the {@code singleExtensions} for this {@code SingleResponse}.
+         *
+         * @return a {@link Map} of {@link Extension} objects, keyed by
+         * their OID value in string form.
+         */
         @Override
         public Map<String, java.security.cert.Extension> getSingleExtensions() {
             return Collections.unmodifiableMap(singleExtensions);
@@ -759,18 +954,117 @@
          */
         @Override public String toString() {
             StringBuilder sb = new StringBuilder();
-            sb.append("SingleResponse:  \n");
+            sb.append("SingleResponse:\n");
             sb.append(certId);
-            sb.append("\nCertStatus: "+ certStatus + "\n");
+            sb.append("\nCertStatus: ").append(certStatus).append("\n");
             if (certStatus == CertStatus.REVOKED) {
-                sb.append("revocationTime is " + revocationTime + "\n");
-                sb.append("revocationReason is " + revocationReason + "\n");
+                sb.append("revocationTime is ");
+                sb.append(revocationTime).append("\n");
+                sb.append("revocationReason is ");
+                sb.append(revocationReason).append("\n");
             }
-            sb.append("thisUpdate is " + thisUpdate + "\n");
+            sb.append("thisUpdate is ").append(thisUpdate).append("\n");
             if (nextUpdate != null) {
-                sb.append("nextUpdate is " + nextUpdate + "\n");
+                sb.append("nextUpdate is ").append(nextUpdate).append("\n");
+            }
+            for (java.security.cert.Extension ext : singleExtensions.values()) {
+                sb.append("singleExtension: ");
+                sb.append(ext.toString()).append("\n");
             }
             return sb.toString();
         }
     }
+
+    /**
+     * Helper class that allows consumers to pass in issuer information.  This
+     * will always consist of the issuer's name and public key, but may also
+     * contain a certificate if the originating data is in that form.  The
+     * trust anchor for the certificate chain will be included for certpath
+     * disabled algorithm checking.
+     */
+    static final class IssuerInfo {
+        private final TrustAnchor anchor;
+        private final X509Certificate certificate;
+        private final X500Principal name;
+        private final PublicKey pubKey;
+
+        IssuerInfo(TrustAnchor anchor) {
+            this(anchor, (anchor != null) ? anchor.getTrustedCert() : null);
+        }
+
+        IssuerInfo(X509Certificate issuerCert) {
+            this(null, issuerCert);
+        }
+
+        IssuerInfo(TrustAnchor anchor, X509Certificate issuerCert) {
+            if (anchor == null && issuerCert == null) {
+                throw new NullPointerException("TrustAnchor and issuerCert " +
+                        "cannot be null");
+            }
+            this.anchor = anchor;
+            if (issuerCert != null) {
+                name = issuerCert.getSubjectX500Principal();
+                pubKey = issuerCert.getPublicKey();
+                certificate = issuerCert;
+            } else {
+                name = anchor.getCA();
+                pubKey = anchor.getCAPublicKey();
+                certificate = anchor.getTrustedCert();
+            }
+        }
+
+        /**
+         * Get the certificate in this IssuerInfo if present.
+         *
+         * @return the {@code X509Certificate} used to create this IssuerInfo
+         * object, or {@code null} if a certificate was not used in its
+         * creation.
+         */
+        X509Certificate getCertificate() {
+            return certificate;
+        }
+
+        /**
+         * Get the name of this issuer.
+         *
+         * @return an {@code X500Principal} corresponding to this issuer's
+         * name.  If derived from an issuer's {@code X509Certificate} this
+         * would be equivalent to the certificate subject name.
+         */
+        X500Principal getName() {
+            return name;
+        }
+
+        /**
+         * Get the public key for this issuer.
+         *
+         * @return a {@code PublicKey} for this issuer.
+         */
+        PublicKey getPublicKey() {
+            return pubKey;
+        }
+
+        /**
+         * Get the TrustAnchor for the certificate chain.
+         *
+         * @return a {@code TrustAnchor}.
+         */
+        TrustAnchor getAnchor() {
+            return anchor;
+        }
+
+        /**
+         * Create a string representation of this IssuerInfo.
+         *
+         * @return a {@code String} form of this IssuerInfo object.
+         */
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append("Issuer Info:\n");
+            sb.append("Name: ").append(name.toString()).append("\n");
+            sb.append("Public Key:\n").append(pubKey.toString()).append("\n");
+            return sb.toString();
+        }
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/provider/certpath/PKIX.java	Thu Nov 09 06:08:09 2017 +0000
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2012, 2017, 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.provider.certpath;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyStore;
+import java.security.Timestamp;
+import java.security.cert.*;
+import java.util.*;
+import javax.security.auth.x500.X500Principal;
+
+import sun.security.util.Debug;
+
+/**
+ * Common utility methods and classes used by the PKIX CertPathValidator and
+ * CertPathBuilder implementation.
+ */
+class PKIX {
+
+    private static final Debug debug = Debug.getInstance("certpath");
+
+    private PKIX() { }
+
+    static ValidatorParams checkParams(CertPath cp, CertPathParameters params)
+        throws InvalidAlgorithmParameterException
+    {
+        if (!(params instanceof PKIXParameters)) {
+            throw new InvalidAlgorithmParameterException("inappropriate "
+                + "params, must be an instance of PKIXParameters");
+        }
+        return new ValidatorParams(cp, (PKIXParameters)params);
+    }
+
+    static BuilderParams checkBuilderParams(CertPathParameters params)
+        throws InvalidAlgorithmParameterException
+    {
+        if (!(params instanceof PKIXBuilderParameters)) {
+            throw new InvalidAlgorithmParameterException("inappropriate "
+                + "params, must be an instance of PKIXBuilderParameters");
+        }
+        return new BuilderParams((PKIXBuilderParameters)params);
+    }
+
+    /**
+     * PKIXParameters that are shared by the PKIX CertPathValidator
+     * implementation. Provides additional functionality and avoids
+     * unnecessary cloning.
+     */
+    static class ValidatorParams {
+        private final PKIXParameters params;
+        private CertPath certPath;
+        private List<PKIXCertPathChecker> checkers;
+        private List<CertStore> stores;
+        private boolean gotDate;
+        private Date date;
+        private Set<String> policies;
+        private boolean gotConstraints;
+        private CertSelector constraints;
+        private Set<TrustAnchor> anchors;
+        private List<X509Certificate> certs;
+        private Timestamp timestamp;
+        private String variant;
+
+        ValidatorParams(CertPath cp, PKIXParameters params)
+            throws InvalidAlgorithmParameterException
+        {
+            this(params);
+            if (!cp.getType().equals("X.509") && !cp.getType().equals("X509")) {
+                throw new InvalidAlgorithmParameterException("inappropriate "
+                    + "CertPath type specified, must be X.509 or X509");
+            }
+            this.certPath = cp;
+        }
+
+        ValidatorParams(PKIXParameters params)
+            throws InvalidAlgorithmParameterException
+        {
+            if (params instanceof PKIXExtendedParameters) {
+                timestamp = ((PKIXExtendedParameters) params).getTimestamp();
+                variant = ((PKIXExtendedParameters) params).getVariant();
+            }
+
+            this.anchors = params.getTrustAnchors();
+            // Make sure that none of the trust anchors include name constraints
+            // (not supported).
+            for (TrustAnchor anchor : this.anchors) {
+                if (anchor.getNameConstraints() != null) {
+                    throw new InvalidAlgorithmParameterException
+                        ("name constraints in trust anchor not supported");
+                }
+            }
+            this.params = params;
+        }
+
+        CertPath certPath() {
+            return certPath;
+        }
+        // called by CertPathBuilder after path has been built
+        void setCertPath(CertPath cp) {
+            this.certPath = cp;
+        }
+        List<X509Certificate> certificates() {
+            if (certs == null) {
+                if (certPath == null) {
+                    certs = Collections.emptyList();
+                } else {
+                    // Reverse the ordering for validation so that the target
+                    // cert is the last certificate
+                    @SuppressWarnings("unchecked")
+                    List<X509Certificate> xc = new ArrayList<>
+                        ((List<X509Certificate>)certPath.getCertificates());
+                    Collections.reverse(xc);
+                    certs = xc;
+                }
+            }
+            return certs;
+        }
+        List<PKIXCertPathChecker> certPathCheckers() {
+            if (checkers == null)
+                checkers = params.getCertPathCheckers();
+            return checkers;
+        }
+        List<CertStore> certStores() {
+            if (stores == null)
+                stores = params.getCertStores();
+            return stores;
+        }
+        Date date() {
+            if (!gotDate) {
+                date = params.getDate();
+                if (date == null)
+                    date = new Date();
+                gotDate = true;
+            }
+            return date;
+        }
+        Set<String> initialPolicies() {
+            if (policies == null)
+                policies = params.getInitialPolicies();
+            return policies;
+        }
+        CertSelector targetCertConstraints() {
+            if (!gotConstraints) {
+                constraints = params.getTargetCertConstraints();
+                gotConstraints = true;
+            }
+            return constraints;
+        }
+        Set<TrustAnchor> trustAnchors() {
+            return anchors;
+        }
+        boolean revocationEnabled() {
+            return params.isRevocationEnabled();
+        }
+        boolean policyMappingInhibited() {
+            return params.isPolicyMappingInhibited();
+        }
+        boolean explicitPolicyRequired() {
+            return params.isExplicitPolicyRequired();
+        }
+        boolean policyQualifiersRejected() {
+            return params.getPolicyQualifiersRejected();
+        }
+        String sigProvider() { return params.getSigProvider(); }
+        boolean anyPolicyInhibited() { return params.isAnyPolicyInhibited(); }
+
+        // in rare cases we need access to the original params, for example
+        // in order to clone CertPathCheckers before building a new chain
+        PKIXParameters getPKIXParameters() {
+            return params;
+        }
+
+        Timestamp timestamp() {
+            return timestamp;
+        }
+
+        String variant() {
+            return variant;
+        }
+    }
+
+    static class BuilderParams extends ValidatorParams {
+        private PKIXBuilderParameters params;
+        private boolean buildForward = true;
+        private List<CertStore> stores;
+        private X500Principal targetSubject;
+
+        BuilderParams(PKIXBuilderParameters params)
+            throws InvalidAlgorithmParameterException
+        {
+            super(params);
+            checkParams(params);
+        }
+        private void checkParams(PKIXBuilderParameters params)
+            throws InvalidAlgorithmParameterException
+        {
+            CertSelector sel = targetCertConstraints();
+            if (!(sel instanceof X509CertSelector)) {
+                throw new InvalidAlgorithmParameterException("the "
+                    + "targetCertConstraints parameter must be an "
+                    + "X509CertSelector");
+            }
+            if (params instanceof SunCertPathBuilderParameters) {
+                buildForward =
+                    ((SunCertPathBuilderParameters)params).getBuildForward();
+            }
+            this.params = params;
+            this.targetSubject = getTargetSubject(
+                certStores(), (X509CertSelector)targetCertConstraints());
+        }
+        @Override List<CertStore> certStores() {
+            if (stores == null) {
+                // reorder CertStores so that local CertStores are tried first
+                stores = new ArrayList<>(params.getCertStores());
+                Collections.sort(stores, new CertStoreComparator());
+            }
+            return stores;
+        }
+        int maxPathLength() { return params.getMaxPathLength(); }
+        boolean buildForward() { return buildForward; }
+        PKIXBuilderParameters params() { return params; }
+        X500Principal targetSubject() { return targetSubject; }
+
+        /**
+         * Returns the target subject DN from the first X509Certificate that
+         * is fetched that matches the specified X509CertSelector.
+         */
+        private static X500Principal getTargetSubject(List<CertStore> stores,
+                                                      X509CertSelector sel)
+            throws InvalidAlgorithmParameterException
+        {
+            X500Principal subject = sel.getSubject();
+            if (subject != null) {
+                return subject;
+            }
+            X509Certificate cert = sel.getCertificate();
+            if (cert != null) {
+                subject = cert.getSubjectX500Principal();
+            }
+            if (subject != null) {
+                return subject;
+            }
+            for (CertStore store : stores) {
+                try {
+                    Collection<? extends Certificate> certs =
+                        (Collection<? extends Certificate>)
+                            store.getCertificates(sel);
+                    if (!certs.isEmpty()) {
+                        X509Certificate xc =
+                            (X509Certificate)certs.iterator().next();
+                        return xc.getSubjectX500Principal();
+                    }
+                } catch (CertStoreException e) {
+                    // ignore but log it
+                    if (debug != null) {
+                        debug.println("BuilderParams.getTargetSubjectDN: " +
+                            "non-fatal exception retrieving certs: " + e);
+                        e.printStackTrace();
+                    }
+                }
+            }
+            throw new InvalidAlgorithmParameterException
+                ("Could not determine unique target subject");
+        }
+    }
+
+    /**
+     * A CertStoreException with additional information about the type of
+     * CertStore that generated the exception.
+     */
+    static class CertStoreTypeException extends CertStoreException {
+        private static final long serialVersionUID = 7463352639238322556L;
+
+        private final String type;
+
+        CertStoreTypeException(String type, CertStoreException cse) {
+            super(cse.getMessage(), cse.getCause());
+            this.type = type;
+        }
+        String getType() {
+            return type;
+        }
+    }
+
+    /**
+     * Comparator that orders CertStores so that local CertStores come before
+     * remote CertStores.
+     */
+    private static class CertStoreComparator implements Comparator<CertStore> {
+        @Override
+        public int compare(CertStore store1, CertStore store2) {
+            if (store1.getType().equals("Collection") ||
+                store1.getCertStoreParameters() instanceof
+                CollectionCertStoreParameters) {
+                return -1;
+            } else {
+                return 1;
+            }
+        }
+    }
+}
--- a/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2017, 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,55 +25,37 @@
 
 package sun.security.provider.certpath;
 
-import java.security.AccessController;
+import java.io.IOException;
 import java.security.InvalidAlgorithmParameterException;
-import java.security.cert.CertPath;
-import java.security.cert.CertPathParameters;
-import java.security.cert.CertPathValidatorException;
-import java.security.cert.CertPathValidatorSpi;
-import java.security.cert.CertPathValidatorResult;
-import java.security.cert.PKIXCertPathChecker;
-import java.security.cert.PKIXCertPathValidatorResult;
-import java.security.cert.PKIXParameters;
-import java.security.cert.PKIXReason;
-import java.security.cert.PolicyNode;
-import java.security.cert.TrustAnchor;
-import java.security.cert.X509Certificate;
-import java.util.Collections;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.Set;
-import sun.security.action.GetBooleanSecurityPropertyAction;
+import java.security.cert.*;
+import java.util.*;
+
+import sun.security.provider.certpath.PKIX.ValidatorParams;
+import sun.security.x509.X509CertImpl;
 import sun.security.util.Debug;
 
-import sun.security.x509.X509CertImpl;
-
-
 /**
  * This class implements the PKIX validation algorithm for certification
  * paths consisting exclusively of <code>X509Certificates</code>. It uses
  * the specified input parameter set (which must be a
- * <code>PKIXParameters</code> object) and signature provider (if any).
+ * <code>PKIXParameters</code> object).
  *
  * @since       1.4
  * @author      Yassir Elley
  */
-public class PKIXCertPathValidator extends CertPathValidatorSpi {
+public final class PKIXCertPathValidator extends CertPathValidatorSpi {
 
     private static final Debug debug = Debug.getInstance("certpath");
-    private Date testDate;
-    private List<PKIXCertPathChecker> userCheckers;
-    private String sigProvider;
-    private BasicChecker basicChecker;
-    private boolean ocspEnabled = false;
-    private boolean onlyEECert = false;
 
     /**
      * Default constructor.
      */
     public PKIXCertPathValidator() {}
 
+    public CertPathChecker engineGetRevocationChecker() {
+        return new RevocationChecker();
+    }
+
     /**
      * Validates a certification path consisting exclusively of
      * <code>X509Certificate</code>s using the PKIX validation algorithm,
@@ -81,98 +63,67 @@
      * The input parameter set must be a <code>PKIXParameters</code> object.
      *
      * @param cp the X509 certification path
-     * @param param the input PKIX parameter set
+     * @param params the input PKIX parameter set
      * @return the result
-     * @exception CertPathValidatorException Exception thrown if cert path
-     * does not validate.
-     * @exception InvalidAlgorithmParameterException if the specified
-     * parameters are inappropriate for this certification path validator
+     * @throws CertPathValidatorException if cert path does not validate.
+     * @throws InvalidAlgorithmParameterException if the specified
+     *         parameters are inappropriate for this CertPathValidator
      */
+    @Override
     public CertPathValidatorResult engineValidate(CertPath cp,
-        CertPathParameters param)
+                                                  CertPathParameters params)
         throws CertPathValidatorException, InvalidAlgorithmParameterException
     {
+        ValidatorParams valParams = PKIX.checkParams(cp, params);
+        return validate(valParams);
+    }
+
+    private static PKIXCertPathValidatorResult validate(ValidatorParams params)
+        throws CertPathValidatorException
+    {
         if (debug != null)
             debug.println("PKIXCertPathValidator.engineValidate()...");
 
-        if (!(param instanceof PKIXParameters)) {
-            throw new InvalidAlgorithmParameterException("inappropriate "
-                + "parameters, must be an instance of PKIXParameters");
-        }
-
-        if (!cp.getType().equals("X.509") && !cp.getType().equals("X509")) {
-            throw new InvalidAlgorithmParameterException("inappropriate "
-                + "certification path type specified, must be X.509 or X509");
-        }
-
-        PKIXParameters pkixParam = (PKIXParameters) param;
-
-        // Make sure that none of the trust anchors include name constraints
-        // (not supported).
-        Set<TrustAnchor> anchors = pkixParam.getTrustAnchors();
-        for (TrustAnchor anchor : anchors) {
-            if (anchor.getNameConstraints() != null) {
-                throw new InvalidAlgorithmParameterException
-                    ("name constraints in trust anchor not supported");
-            }
-        }
-
-        // the certpath which has been passed in (cp)
-        // has the target cert as the first certificate - we
-        // need to keep this cp so we can return it
-        // in case of an exception and for policy qualifier
-        // processing - however, for certpath validation,
-        // we need to create a reversed path, where we reverse the
-        // ordering so that the target cert is the last certificate
-
-        // Must copy elements of certList into a new modifiable List before
-        // calling Collections.reverse().
-        // If cp is not an X.509 or X509 certpath, an
-        // InvalidAlgorithmParameterException will have been thrown by now.
-        @SuppressWarnings("unchecked")
-        ArrayList<X509Certificate> certList = new ArrayList<X509Certificate>
-            ((List<X509Certificate>)cp.getCertificates());
-        if (debug != null) {
-            if (certList.isEmpty()) {
-                debug.println("PKIXCertPathValidator.engineValidate() "
-                    + "certList is empty");
-            }
-            debug.println("PKIXCertPathValidator.engineValidate() "
-                + "reversing certpath...");
-        }
-        Collections.reverse(certList);
-
-        // now certList has the target cert as the last cert and we
-        // can proceed with normal validation
-
-        populateVariables(pkixParam);
-
         // Retrieve the first certificate in the certpath
         // (to be used later in pre-screening)
-        X509Certificate firstCert = null;
+        AdaptableX509CertSelector selector = null;
+        List<X509Certificate> certList = params.certificates();
         if (!certList.isEmpty()) {
-            firstCert = certList.get(0);
+            selector = new AdaptableX509CertSelector();
+            X509Certificate firstCert = certList.get(0);
+            // check trusted certificate's subject
+            selector.setSubject(firstCert.getIssuerX500Principal());
+            /*
+             * Facilitate certification path construction with authority
+             * key identifier and subject key identifier.
+             */
+            try {
+                X509CertImpl firstCertImpl = X509CertImpl.toImpl(firstCert);
+                selector.parseAuthorityKeyIdentifierExtension(
+                            firstCertImpl.getAuthorityKeyIdentifierExtension());
+            } catch (CertificateException | IOException e) {
+                // ignore
+            }
         }
 
         CertPathValidatorException lastException = null;
 
         // We iterate through the set of trust anchors until we find
         // one that works at which time we stop iterating
-        for (TrustAnchor anchor : anchors) {
+        for (TrustAnchor anchor : params.trustAnchors()) {
             X509Certificate trustedCert = anchor.getTrustedCert();
             if (trustedCert != null) {
-                if (debug != null) {
-                    debug.println("PKIXCertPathValidator.engineValidate() "
-                        + "anchor.getTrustedCert() != null");
-                }
-
                 // if this trust anchor is not worth trying,
                 // we move on to the next one
-                if (!isWorthTrying(trustedCert, firstCert)) {
+                if (selector != null && !selector.match(trustedCert)) {
+                    if (debug != null) {
+                        debug.println("NO - don't try this trustedCert");
+                    }
                     continue;
                 }
 
                 if (debug != null) {
+                    debug.println("YES - try this trustedCert");
                     debug.println("anchor.getTrustedCert()."
                         + "getSubjectX500Principal() = "
                         + trustedCert.getSubjectX500Principal());
@@ -185,14 +136,7 @@
             }
 
             try {
-                PolicyNodeImpl rootNode = new PolicyNodeImpl(null,
-                    PolicyChecker.ANY_POLICY, null, false,
-                    Collections.singleton(PolicyChecker.ANY_POLICY), false);
-                PolicyNode policyTree =
-                    doValidate(anchor, cp, certList, pkixParam, rootNode);
-                // if this anchor works, return success
-                return new PKIXCertPathValidatorResult(anchor, policyTree,
-                    basicChecker.getPublicKey());
+                return validate(anchor, params);
             } catch (CertPathValidatorException cpe) {
                 // remember this exception
                 lastException = cpe;
@@ -210,148 +154,72 @@
              null, null, -1, PKIXReason.NO_TRUST_ANCHOR);
     }
 
-    /**
-     * Internal method to do some simple checks to see if a given cert is
-     * worth trying to validate in the chain.
-     */
-    private boolean isWorthTrying(X509Certificate trustedCert,
-          X509Certificate firstCert) {
-
-        boolean worthy = false;
-
-        if (debug != null) {
-            debug.println("PKIXCertPathValidator.isWorthTrying() checking "
-                + "if this trusted cert is worth trying ...");
-        }
-
-        if (firstCert == null) {
-            return true;
-        }
-
-        AdaptableX509CertSelector issuerSelector =
-                        new AdaptableX509CertSelector();
-
-        // check trusted certificate's subject
-        issuerSelector.setSubject(firstCert.getIssuerX500Principal());
-
-        /*
-         * Facilitate certification path construction with authority
-         * key identifier and subject key identifier.
-         */
-        try {
-            X509CertImpl firstCertImpl = X509CertImpl.toImpl(firstCert);
-            issuerSelector.parseAuthorityKeyIdentifierExtension(
-                        firstCertImpl.getAuthorityKeyIdentifierExtension());
-
-            worthy = issuerSelector.match(trustedCert);
-        } catch (Exception e) {
-            // It is not worth trying.
-        }
-
-        if (debug != null) {
-            if (worthy) {
-                debug.println("YES - try this trustedCert");
-            } else {
-                debug.println("NO - don't try this trustedCert");
-            }
-        }
-
-        return worthy;
-    }
-
-    /**
-     * Internal method to setup the internal state
-     */
-    private void populateVariables(PKIXParameters pkixParam)
+    private static PKIXCertPathValidatorResult validate(TrustAnchor anchor,
+                                                        ValidatorParams params)
+        throws CertPathValidatorException
     {
-        // default value for testDate is current time
-        testDate = pkixParam.getDate();
-        if (testDate == null) {
-            testDate = new Date(System.currentTimeMillis());
-        }
-
-        userCheckers = pkixParam.getCertPathCheckers();
-        sigProvider = pkixParam.getSigProvider();
-
-        if (pkixParam.isRevocationEnabled()) {
-            // Examine OCSP security property
-            ocspEnabled = AccessController.doPrivileged(
-                new GetBooleanSecurityPropertyAction
-                    (OCSPChecker.OCSP_ENABLE_PROP));
-            onlyEECert = AccessController.doPrivileged(
-                new GetBooleanSecurityPropertyAction
-                    ("com.sun.security.onlyCheckRevocationOfEECert"));
-        }
-    }
-
-    /**
-     * Internal method to actually validate a constructed path.
-     *
-     * @return the valid policy tree
-     */
-    private PolicyNode doValidate(
-            TrustAnchor anchor, CertPath cpOriginal,
-            ArrayList<X509Certificate> certList, PKIXParameters pkixParam,
-            PolicyNodeImpl rootNode) throws CertPathValidatorException
-    {
-        int certPathLen = certList.size();
-
-        basicChecker = new BasicChecker(anchor, testDate, sigProvider, false);
-        AlgorithmChecker algorithmChecker = new AlgorithmChecker(anchor);
-        KeyChecker keyChecker = new KeyChecker(certPathLen,
-            pkixParam.getTargetCertConstraints());
-        ConstraintsChecker constraintsChecker =
-            new ConstraintsChecker(certPathLen);
-
-        PolicyChecker policyChecker =
-            new PolicyChecker(pkixParam.getInitialPolicies(), certPathLen,
-                              pkixParam.isExplicitPolicyRequired(),
-                              pkixParam.isPolicyMappingInhibited(),
-                              pkixParam.isAnyPolicyInhibited(),
-                              pkixParam.getPolicyQualifiersRejected(),
-                              rootNode);
+        // check if anchor is untrusted
         UntrustedChecker untrustedChecker = new UntrustedChecker();
-        // check if anchor is untrusted
         X509Certificate anchorCert = anchor.getTrustedCert();
         if (anchorCert != null) {
             untrustedChecker.check(anchorCert,
                                    Collections.<String>emptySet());
         }
 
-        ArrayList<PKIXCertPathChecker> certPathCheckers =
-            new ArrayList<PKIXCertPathChecker>();
+        int certPathLen = params.certificates().size();
+
+        // create PKIXCertPathCheckers
+        List<PKIXCertPathChecker> certPathCheckers = new ArrayList<>();
         // add standard checkers that we will be using
         certPathCheckers.add(untrustedChecker);
-        certPathCheckers.add(algorithmChecker);
-        certPathCheckers.add(keyChecker);
-        certPathCheckers.add(constraintsChecker);
-        certPathCheckers.add(policyChecker);
-        certPathCheckers.add(basicChecker);
-
-        // only add a revocationChecker if revocation is enabled
-        if (pkixParam.isRevocationEnabled()) {
-
-            // Use OCSP if it has been enabled
-            if (ocspEnabled) {
-                OCSPChecker ocspChecker =
-                    new OCSPChecker(cpOriginal, pkixParam, onlyEECert);
-                certPathCheckers.add(ocspChecker);
-            }
+        certPathCheckers.add(new AlgorithmChecker(anchor, null, params.date(),
+                params.timestamp(), params.variant()));
+        certPathCheckers.add(new KeyChecker(certPathLen,
+                                            params.targetCertConstraints()));
+        certPathCheckers.add(new ConstraintsChecker(certPathLen));
+        PolicyNodeImpl rootNode =
+            new PolicyNodeImpl(null, PolicyChecker.ANY_POLICY, null, false,
+                               Collections.singleton(PolicyChecker.ANY_POLICY),
+                               false);
+        PolicyChecker pc = new PolicyChecker(params.initialPolicies(),
+                                             certPathLen,
+                                             params.explicitPolicyRequired(),
+                                             params.policyMappingInhibited(),
+                                             params.anyPolicyInhibited(),
+                                             params.policyQualifiersRejected(),
+                                             rootNode);
+        certPathCheckers.add(pc);
+        // default value for date is current time
+        BasicChecker bc;
+        bc = new BasicChecker(anchor,
+                (params.timestamp() == null ? params.date() :
+                        params.timestamp().getTimestamp()),
+                params.sigProvider(), false);
+        certPathCheckers.add(bc);
 
-            // Always use CRLs
-            CrlRevocationChecker revocationChecker = new
-                CrlRevocationChecker(anchor, pkixParam, certList, onlyEECert);
-            certPathCheckers.add(revocationChecker);
+        boolean revCheckerAdded = false;
+        List<PKIXCertPathChecker> checkers = params.certPathCheckers();
+        for (PKIXCertPathChecker checker : checkers) {
+            if (checker instanceof PKIXRevocationChecker) {
+                revCheckerAdded = true;
+                // if it's our own, initialize it
+                if (checker instanceof RevocationChecker)
+                    ((RevocationChecker)checker).init(anchor, params);
+            }
         }
-
+        // only add a RevocationChecker if revocation is enabled and
+        // a PKIXRevocationChecker has not already been added
+        if (params.revocationEnabled() && !revCheckerAdded) {
+            certPathCheckers.add(new RevocationChecker(anchor, params));
+        }
         // add user-specified checkers
-        certPathCheckers.addAll(userCheckers);
+        certPathCheckers.addAll(checkers);
 
-        PKIXMasterCertPathValidator masterValidator =
-            new PKIXMasterCertPathValidator(certPathCheckers);
+        PKIXMasterCertPathValidator.validate(params.certPath(),
+                                             params.certificates(),
+                                             certPathCheckers);
 
-        masterValidator.validate(cpOriginal, certList);
-
-        return policyChecker.getPolicyTree();
+        return new PKIXCertPathValidatorResult(anchor, pc.getPolicyTree(),
+                                               bc.getPublicKey());
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/provider/certpath/PKIXExtendedParameters.java	Thu Nov 09 06:08:09 2017 +0000
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2016, 2017, 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.provider.certpath;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.Timestamp;
+import java.security.cert.CertSelector;
+import java.security.cert.CertStore;
+import java.security.cert.PKIXBuilderParameters;
+import java.security.cert.PKIXCertPathChecker;
+import java.security.cert.TrustAnchor;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * This class is a wrapper for PKIXBuilderParameters so that a Timestamp object
+ * and a string for the variant type, can be passed when doing certpath
+ * checking.
+ */
+
+public class PKIXExtendedParameters extends PKIXBuilderParameters {
+
+    private final PKIXBuilderParameters p;
+    private Timestamp jarTimestamp;
+    private final String variant;
+
+    public PKIXExtendedParameters(PKIXBuilderParameters params,
+            Timestamp timestamp, String variant)
+            throws InvalidAlgorithmParameterException {
+        super(params.getTrustAnchors(), null);
+        p = params;
+        jarTimestamp = timestamp;
+        this.variant = variant;
+    }
+
+    public Timestamp getTimestamp() {
+        return jarTimestamp;
+    }
+    public void setTimestamp(Timestamp t) {
+        jarTimestamp = t;
+    }
+
+    public String getVariant() {
+        return variant;
+    }
+
+    @Override
+    public void setDate(Date d) {
+        p.setDate(d);
+    }
+
+    @Override
+    public void addCertPathChecker(PKIXCertPathChecker c) {
+        p.addCertPathChecker(c);
+    }
+
+    @Override
+    public void setMaxPathLength(int maxPathLength) {
+        p.setMaxPathLength(maxPathLength);
+    }
+
+    @Override
+    public int getMaxPathLength() {
+        return p.getMaxPathLength();
+    }
+
+    @Override
+    public String toString() {
+        return p.toString();
+    }
+
+    @Override
+    public Set<TrustAnchor> getTrustAnchors() {
+        return p.getTrustAnchors();
+    }
+
+    @Override
+    public void setTrustAnchors(Set<TrustAnchor> trustAnchors)
+            throws InvalidAlgorithmParameterException {
+        // To avoid problems with PKIXBuilderParameter's constructors
+        if (p == null) {
+            return;
+        }
+        p.setTrustAnchors(trustAnchors);
+    }
+
+    @Override
+    public Set<String> getInitialPolicies() {
+        return p.getInitialPolicies();
+    }
+
+    @Override
+    public void setInitialPolicies(Set<String> initialPolicies) {
+        p.setInitialPolicies(initialPolicies);
+    }
+
+    @Override
+    public void setCertStores(List<CertStore> stores) {
+        p.setCertStores(stores);
+    }
+
+    @Override
+    public void addCertStore(CertStore store) {
+        p.addCertStore(store);
+    }
+
+    @Override
+    public List<CertStore> getCertStores() {
+        return p.getCertStores();
+    }
+
+    @Override
+    public void setRevocationEnabled(boolean val) {
+        p.setRevocationEnabled(val);
+    }
+
+    @Override
+    public boolean isRevocationEnabled() {
+        return p.isRevocationEnabled();
+    }
+
+    @Override
+    public void setExplicitPolicyRequired(boolean val) {
+        p.setExplicitPolicyRequired(val);
+    }
+
+    @Override
+    public boolean isExplicitPolicyRequired() {
+        return p.isExplicitPolicyRequired();
+    }
+
+    @Override
+    public void setPolicyMappingInhibited(boolean val) {
+        p.setPolicyMappingInhibited(val);
+    }
+
+    @Override
+    public boolean isPolicyMappingInhibited() {
+        return p.isPolicyMappingInhibited();
+    }
+
+    @Override
+    public void setAnyPolicyInhibited(boolean val) {
+        p.setAnyPolicyInhibited(val);
+    }
+
+    @Override
+    public boolean isAnyPolicyInhibited() {
+        return p.isAnyPolicyInhibited();
+    }
+
+    @Override
+    public void setPolicyQualifiersRejected(boolean qualifiersRejected) {
+        p.setPolicyQualifiersRejected(qualifiersRejected);
+    }
+
+    @Override
+    public boolean getPolicyQualifiersRejected() {
+        return p.getPolicyQualifiersRejected();
+    }
+
+    @Override
+    public Date getDate() {
+        return p.getDate();
+    }
+
+    @Override
+    public void setCertPathCheckers(List<PKIXCertPathChecker> checkers) {
+        p.setCertPathCheckers(checkers);
+    }
+
+    @Override
+    public List<PKIXCertPathChecker> getCertPathCheckers() {
+        return p.getCertPathCheckers();
+    }
+
+    @Override
+    public String getSigProvider() {
+        return p.getSigProvider();
+    }
+
+    @Override
+    public void setSigProvider(String sigProvider) {
+        p.setSigProvider(sigProvider);
+    }
+
+    @Override
+    public CertSelector getTargetCertConstraints() {
+        return p.getTargetCertConstraints();
+    }
+
+    @Override
+    public void setTargetCertConstraints(CertSelector selector) {
+        // To avoid problems with PKIXBuilderParameter's constructors
+        if (p == null) {
+            return;
+        }
+        p.setTargetCertConstraints(selector);
+    }
+
+}
--- a/src/share/classes/sun/security/provider/certpath/PKIXMasterCertPathValidator.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/provider/certpath/PKIXMasterCertPathValidator.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2012, 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
@@ -30,10 +30,8 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
-import java.security.cert.CertificateRevokedException;
 import java.security.cert.CertPath;
 import java.security.cert.CertPathValidatorException;
-import java.security.cert.CertPathValidatorException.BasicReason;
 import java.security.cert.PKIXCertPathChecker;
 import java.security.cert.PKIXReason;
 import java.security.cert.X509Certificate;
@@ -49,32 +47,22 @@
 class PKIXMasterCertPathValidator {
 
     private static final Debug debug = Debug.getInstance("certpath");
-    private List<PKIXCertPathChecker> certPathCheckers;
-
-    /**
-     * Initializes the list of PKIXCertPathCheckers whose checks
-     * will be performed on each certificate in the certpath.
-     *
-     * @param certPathCheckers a List of checkers to use
-     */
-    PKIXMasterCertPathValidator(List<PKIXCertPathChecker> certPathCheckers) {
-        this.certPathCheckers = certPathCheckers;
-    }
 
     /**
      * Validates a certification path consisting exclusively of
-     * <code>X509Certificate</code>s using the
-     * <code>PKIXCertPathChecker</code>s specified
-     * in the constructor. It is assumed that the
+     * <code>X509Certificate</code>s using the specified
+     * <code>PKIXCertPathChecker</code>s. It is assumed that the
      * <code>PKIXCertPathChecker</code>s
      * have been initialized with any input parameters they may need.
      *
      * @param cpOriginal the original X509 CertPath passed in by the user
      * @param reversedCertList the reversed X509 CertPath (as a List)
-     * @exception CertPathValidatorException Exception thrown if cert
-     * path does not validate.
+     * @param certPathCheckers the PKIXCertPathCheckers
+     * @throws CertPathValidatorException if cert path does not validate
      */
-    void validate(CertPath cpOriginal, List<X509Certificate> reversedCertList)
+    static void validate(CertPath cpOriginal,
+                         List<X509Certificate> reversedCertList,
+                         List<PKIXCertPathChecker> certPathCheckers)
         throws CertPathValidatorException
     {
         // we actually process reversedCertList, but we keep cpOriginal because
@@ -104,20 +92,18 @@
                 debug.println("Checking cert" + (i+1) + " ...");
 
             X509Certificate currCert = reversedCertList.get(i);
-            Set<String> unresolvedCritExts =
-                                        currCert.getCriticalExtensionOIDs();
-            if (unresolvedCritExts == null) {
-                unresolvedCritExts = Collections.<String>emptySet();
+            Set<String> unresCritExts = currCert.getCriticalExtensionOIDs();
+            if (unresCritExts == null) {
+                unresCritExts = Collections.<String>emptySet();
             }
 
-            if (debug != null && !unresolvedCritExts.isEmpty()) {
+            if (debug != null && !unresCritExts.isEmpty()) {
                 debug.println("Set of critical extensions:");
-                for (String oid : unresolvedCritExts) {
+                for (String oid : unresCritExts) {
                     debug.println(oid);
                 }
             }
 
-            CertPathValidatorException ocspCause = null;
             for (int j = 0; j < certPathCheckers.size(); j++) {
 
                 PKIXCertPathChecker currChecker = certPathCheckers.get(j);
@@ -130,96 +116,32 @@
                     currChecker.init(false);
 
                 try {
-                    currChecker.check(currCert, unresolvedCritExts);
+                    currChecker.check(currCert, unresCritExts);
 
-                    // OCSP has validated the cert so skip the CRL check
-                    if (isRevocationCheck(currChecker, j, certPathCheckers)) {
-                        if (debug != null) {
-                            debug.println("-checker" + (j + 1) +
-                                " validation succeeded");
-                        }
-                        j++;
-                        continue; // skip
+                    if (debug != null) {
+                        debug.println("-checker" + (j + 1) +
+                            " validation succeeded");
                     }
 
                 } catch (CertPathValidatorException cpve) {
-                    // Throw the saved OCSP exception unless the CRL
-                    // checker has determined that the cert is revoked
-                    if (ocspCause != null &&
-                            currChecker instanceof CrlRevocationChecker) {
-                        if (cpve.getReason() == BasicReason.REVOKED) {
-                            throw cpve;
-                        } else {
-                            throw ocspCause;
-                        }
-                    }
-                    /*
-                     * Handle failover from OCSP to CRLs
-                     */
-                    CertPathValidatorException currentCause =
-                        new CertPathValidatorException(cpve.getMessage(),
-                        (cpve.getCause() != null) ? cpve.getCause() : cpve,
-                            cpOriginal, cpSize - (i + 1), cpve.getReason());
-
-                    // Check if OCSP has confirmed that the cert was revoked
-                    if (cpve.getReason() == BasicReason.REVOKED) {
-                        throw currentCause;
-                    }
-                    // Check if it is appropriate to failover
-                    if (! isRevocationCheck(currChecker, j, certPathCheckers)) {
-                        // no failover
-                        throw currentCause;
-                    }
-                    // Save the current exception
-                    // (in case the CRL check also fails)
-                    ocspCause = currentCause;
-
-                    // Otherwise, failover to CRLs
-                    if (debug != null) {
-                        debug.println(cpve.getMessage());
-                        debug.println(
-                            "preparing to failover (from OCSP to CRLs)");
-                    }
+                    throw new CertPathValidatorException(cpve.getMessage(),
+                        cpve.getCause(), cpOriginal, cpSize - (i + 1),
+                        cpve.getReason());
                 }
-
-                if (debug != null)
-                    debug.println("-checker" + (j+1) + " validation succeeded");
             }
 
-            if (debug != null)
-                debug.println("checking for unresolvedCritExts");
-            if (!unresolvedCritExts.isEmpty()) {
+            if (!unresCritExts.isEmpty()) {
                 throw new CertPathValidatorException("unrecognized " +
                     "critical extension(s)", null, cpOriginal, cpSize-(i+1),
                     PKIXReason.UNRECOGNIZED_CRIT_EXT);
             }
-
-            if (debug != null)
-                debug.println("\ncert" + (i+1) + " validation succeeded.\n");
         }
 
         if (debug != null) {
             debug.println("Cert path validation succeeded. (PKIX validation "
-                    + "algorithm)");
+                          + "algorithm)");
             debug.println("-------------------------------------------------"
-                    + "-------------");
+                          + "-------------");
         }
     }
-
-    /*
-     * Examines the list of PKIX cert path checkers to determine whether
-     * both the current checker and the next checker are revocation checkers.
-     * OCSPChecker and CrlRevocationChecker are both revocation checkers.
-     */
-    private static boolean isRevocationCheck(PKIXCertPathChecker checker,
-        int index, List<PKIXCertPathChecker> checkers) {
-
-        if (checker instanceof OCSPChecker && index + 1 < checkers.size()) {
-            PKIXCertPathChecker nextChecker = checkers.get(index + 1);
-            if (nextChecker instanceof CrlRevocationChecker) {
-                return true;
-            }
-        }
-        return false;
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/provider/certpath/PKIXRevocationChecker.java	Thu Nov 09 06:08:09 2017 +0000
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2012, 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.provider.certpath;
+
+import java.net.URI;
+import java.security.cert.Certificate;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.Extension;
+import java.security.cert.PKIXCertPathChecker;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+/**
+ * A {@code PKIXCertPathChecker} for checking the revocation status of
+ * certificates with the PKIX algorithm.
+ *
+ * <p>A {@code PKIXRevocationChecker} checks the revocation status of
+ * certificates with the Online Certificate Status Protocol (OCSP) or
+ * Certificate Revocation Lists (CRLs). OCSP is described in RFC 2560 and
+ * is a network protocol for determining the status of a certificate. A CRL
+ * is a time-stamped list identifying revoked certificates, and RFC 5280
+ * describes an algorithm for determining the revocation status of certificates
+ * using CRLs.
+ *
+ * <p>Each {@code PKIXRevocationChecker} must be able to check the revocation
+ * status of certificates with OCSP and CRLs. By default, OCSP is the
+ * preferred mechanism for checking revocation status, with CRLs as the
+ * fallback mechanism. However, this preference can be switched to CRLs with
+ * the {@link Option.PREFER_CRLS} option.
+ *
+ * <p>A {@code PKIXRevocationChecker} is obtained by calling the
+ * {@link CertPathValidator#getRevocationChecker getRevocationChecker} method
+ * of a PKIX {@code CertPathValidator}. Additional parameters and options
+ * specific to revocation can be set (by calling {@link #setOCSPResponder}
+ * method for instance). The {@code PKIXRevocationChecker} is added to
+ * a {@code PKIXParameters} object using the
+ * {@link PKIXParameters#addCertPathChecker addCertPathChecker}
+ * or {@link PKIXParameters#setCertPathCheckers setCertPathCheckers} method,
+ * and then the {@code PKIXParameters} is passed along with the {@code CertPath}
+ * to be validated to the {@link CertPathValidator#validate validate} method
+ * of a PKIX {@code CertPathValidator}. When supplying a revocation checker in
+ * this manner, do not enable the default revocation checking mechanism (by
+ * calling {@link PKIXParameters#setRevocationEnabled}.
+ *
+ * <p>Note that when a {@code PKIXRevocationChecker} is added to
+ * {@code PKIXParameters}, it clones the {@code PKIXRevocationChecker};
+ * thus any subsequent modifications to the {@code PKIXRevocationChecker}
+ * have no effect.
+ *
+ * <p>Any parameter that is not set (or is set to {@code null}) will be set to
+ * the default value for that parameter.
+ *
+ * <p><b>Concurrent Access</b>
+ *
+ * <p>Unless otherwise specified, the methods defined in this class are not
+ * thread-safe. Multiple threads that need to access a single object
+ * concurrently should synchronize amongst themselves and provide the
+ * necessary locking. Multiple threads each manipulating separate objects
+ * need not synchronize.
+ *
+ * @since 1.8
+ */
+public abstract class PKIXRevocationChecker extends PKIXCertPathChecker
+  implements CertPathChecker {
+    private URI ocspResponder;
+    private X509Certificate ocspResponderCert;
+    private List<Extension> ocspExtensions = Collections.<Extension>emptyList();
+    private Map<X509Certificate, byte[]> ocspStapled = Collections.emptyMap();
+    private Set<Option> options = Collections.emptySet();
+
+    protected PKIXRevocationChecker() {}
+
+    /**
+     * Sets the URI that identifies the location of the OCSP responder. This
+     * overrides the {@code ocsp.responderURL} security property and any
+     * responder specified in a certificate's Authority Information Access
+     * Extension, as defined in RFC 5280.
+     *
+     * @param uri the responder URI
+     */
+    public void setOCSPResponder(URI uri) {
+        this.ocspResponder = uri;
+    }
+
+    /**
+     * Gets the URI that identifies the location of the OCSP responder. This
+     * overrides the {@code ocsp.responderURL} security property. If this
+     * parameter or the {@code ocsp.responderURL} property is not set, the
+     * location is determined from the certificate's Authority Information
+     * Access Extension, as defined in RFC 5280.
+     *
+     * @return the responder URI, or {@code null} if not set
+     */
+    public URI getOCSPResponder() {
+        return ocspResponder;
+    }
+
+    /**
+     * Sets the OCSP responder's certificate. This overrides the
+     * {@code ocsp.responderCertSubjectName},
+     * {@code ocsp.responderCertIssuerName},
+     * and {@code ocsp.responderCertSerialNumber} security properties.
+     *
+     * @param cert the responder's certificate
+     */
+    public void setOCSPResponderCert(X509Certificate cert) {
+        this.ocspResponderCert = cert;
+    }
+
+    /**
+     * Gets the OCSP responder's certificate. This overrides the
+     * {@code ocsp.responderCertSubjectName},
+     * {@code ocsp.responderCertIssuerName},
+     * and {@code ocsp.responderCertSerialNumber} security properties. If this
+     * parameter or the aforementioned properties are not set, then the
+     * responder's certificate is determined as specified in RFC 2560.
+     *
+     * @return the responder's certificate, or {@code null} if not set
+     */
+    public X509Certificate getOCSPResponderCert() {
+        return ocspResponderCert;
+    }
+
+    // request extensions; single extensions not supported
+    /**
+     * Sets the optional OCSP request extensions.
+     *
+     * @param extensions a list of extensions. The list is copied to protect
+     *        against subsequent modification.
+     */
+    public void setOCSPExtensions(List<Extension> extensions)
+    {
+        this.ocspExtensions = (extensions == null)
+                              ? Collections.<Extension>emptyList()
+                              : new ArrayList<Extension>(extensions);
+    }
+
+    /**
+     * Gets the optional OCSP request extensions.
+     *
+     * @return an unmodifiable list of extensions. Returns an empty list if no
+     *         extensions have been specified.
+     */
+    public List<Extension> getOCSPExtensions() {
+        return Collections.unmodifiableList(ocspExtensions);
+    }
+
+    /**
+     * Sets the stapled OCSP responses. These responses are used to determine
+     * the revocation status of the specified certificates when OCSP is used.
+     *
+     * @param responses a map of stapled OCSP responses. Each key is an
+     *        {@code X509Certificate} that maps to the corresponding
+     *        DER-encoded OCSP response for that certificate. A deep copy of
+     *        the map is performed to protect against subsequent modification.
+     */
+    public void setOCSPStapledResponses(Map<X509Certificate, byte[]> responses)
+    {
+        if (responses == null) {
+            this.ocspStapled = Collections.<X509Certificate, byte[]>emptyMap();
+        } else {
+            Map<X509Certificate, byte[]> copy = new HashMap<>(responses.size());
+            for (Map.Entry<X509Certificate, byte[]> e : responses.entrySet()) {
+                copy.put(e.getKey(), e.getValue().clone());
+            }
+            this.ocspStapled = copy;
+        }
+    }
+
+    /**
+     * Gets the stapled OCSP responses. These responses are used to determine
+     * the revocation status of the specified certificates when OCSP is used.
+     *
+     * @return a map of stapled OCSP responses. Each key is an
+     *        {@code X509Certificate} that maps to the corresponding
+     *        DER-encoded OCSP response for that certificate. A deep copy of
+     *        the map is returned to protect against subsequent modification.
+     *        Returns an empty map if no responses have been specified.
+     */
+    public Map<X509Certificate, byte[]> getOCSPStapledResponses() {
+        Map<X509Certificate, byte[]> copy = new HashMap<>(ocspStapled.size());
+        for (Map.Entry<X509Certificate, byte[]> e : ocspStapled.entrySet()) {
+            copy.put(e.getKey(), e.getValue().clone());
+        }
+        return copy;
+    }
+
+    /**
+     * Sets the revocation options.
+     *
+     * @param options a set of revocation options. The set is copied to protect
+     *        against subsequent modification.
+     */
+    public void setOptions(Set<Option> options) {
+        this.options = (options == null)
+                       ? Collections.<Option>emptySet()
+                       : new HashSet<Option>(options);
+    }
+
+    /**
+     * Gets the revocation options.
+     *
+     * @return an unmodifiable set of revocation options, or an empty set if
+     *         none are specified
+     */
+    public Set<Option> getOptions() {
+        return Collections.unmodifiableSet(options);
+    }
+
+    @Override
+    public Object clone() {
+        PKIXRevocationChecker copy = (PKIXRevocationChecker)super.clone();
+        copy.ocspExtensions = new ArrayList<>(ocspExtensions);
+        copy.ocspStapled = new HashMap<>(ocspStapled);
+        // deep-copy the encoded stapled responses, since they are mutable
+        for (Map.Entry<X509Certificate, byte[]> entry :
+                 copy.ocspStapled.entrySet())
+        {
+            byte[] encoded = entry.getValue();
+            entry.setValue(encoded.clone());
+        }
+        copy.options = new HashSet<>(options);
+        return copy;
+    }
+
+    /**
+     * Various revocation options that can be specified for the revocation
+     * checking mechanism.
+     */
+    public enum Option {
+        /**
+         * Only check the revocation status of end-entity certificates.
+         */
+        ONLY_END_ENTITY,
+        /**
+         * Prefer CRLs to OSCP. The default behavior is to prefer OCSP. Each
+         * PKIX implementation should document further details of their
+         * specific preference rules and fallback policies.
+         */
+        PREFER_CRLS,
+        /**
+         * Ignore network failures. The default behavior is to consider it a
+         * failure if the revocation status of a certificate cannot be obtained
+         * due to a network error. This option applies to both OCSP and CRLs.
+         */
+        SOFT_FAIL
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation calls
+     * {@code check(cert, java.util.Collections.<String>emptySet())}.
+     */
+    @Override
+    public void check(Certificate cert) throws CertPathValidatorException {
+        check(cert, java.util.Collections.<String>emptySet());
+    }
+}
--- a/src/share/classes/sun/security/provider/certpath/PolicyChecker.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/provider/certpath/PolicyChecker.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2012, 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,9 +25,8 @@
 
 package sun.security.provider.certpath;
 
-import java.util.*;
 import java.io.IOException;
-
+import java.security.GeneralSecurityException;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateException;
 import java.security.cert.CertPathValidatorException;
@@ -36,13 +35,14 @@
 import java.security.cert.PolicyNode;
 import java.security.cert.PolicyQualifierInfo;
 import java.security.cert.X509Certificate;
+import java.util.*;
 
 import sun.security.util.Debug;
 import sun.security.x509.CertificatePoliciesExtension;
 import sun.security.x509.PolicyConstraintsExtension;
 import sun.security.x509.PolicyMappingsExtension;
 import sun.security.x509.CertificatePolicyMap;
-import sun.security.x509.PKIXExtensions;
+import static sun.security.x509.PKIXExtensions.*;
 import sun.security.x509.PolicyInformation;
 import sun.security.x509.X509CertImpl;
 import sun.security.x509.InhibitAnyPolicyExtension;
@@ -88,7 +88,7 @@
     PolicyChecker(Set<String> initialPolicies, int certPathLen,
         boolean expPolicyRequired, boolean polMappingInhibited,
         boolean anyPolicyInhibited, boolean rejectPolicyQualifiers,
-        PolicyNodeImpl rootNode) throws CertPathValidatorException
+        PolicyNodeImpl rootNode)
     {
         if (initialPolicies.isEmpty()) {
             // if no initialPolicies are specified by user, set
@@ -104,18 +104,18 @@
         this.anyPolicyInhibited = anyPolicyInhibited;
         this.rejectPolicyQualifiers = rejectPolicyQualifiers;
         this.rootNode = rootNode;
-        init(false);
     }
 
     /**
      * Initializes the internal state of the checker from parameters
      * specified in the constructor
      *
-     * @param forward a boolean indicating whether this checker should
-     * be initialized capable of building in the forward direction
-     * @exception CertPathValidatorException Exception thrown if user
-     * wants to enable forward checking and forward checking is not supported.
+     * @param forward a boolean indicating whether this checker should be
+     *        initialized capable of building in the forward direction
+     * @throws CertPathValidatorException if user wants to enable forward
+     *         checking and forward checking is not supported.
      */
+    @Override
     public void init(boolean forward) throws CertPathValidatorException {
         if (forward) {
             throw new CertPathValidatorException
@@ -136,6 +136,7 @@
      *
      * @return true if forward checking is supported, false otherwise
      */
+    @Override
     public boolean isForwardCheckingSupported() {
         return false;
     }
@@ -150,13 +151,14 @@
      * @return the Set of extensions supported by this PKIXCertPathChecker,
      * or null if no extensions are supported
      */
+    @Override
     public Set<String> getSupportedExtensions() {
         if (supportedExts == null) {
-            supportedExts = new HashSet<String>();
-            supportedExts.add(PKIXExtensions.CertificatePolicies_Id.toString());
-            supportedExts.add(PKIXExtensions.PolicyMappings_Id.toString());
-            supportedExts.add(PKIXExtensions.PolicyConstraints_Id.toString());
-            supportedExts.add(PKIXExtensions.InhibitAnyPolicy_Id.toString());
+            supportedExts = new HashSet<String>(4);
+            supportedExts.add(CertificatePolicies_Id.toString());
+            supportedExts.add(PolicyMappings_Id.toString());
+            supportedExts.add(PolicyConstraints_Id.toString());
+            supportedExts.add(InhibitAnyPolicy_Id.toString());
             supportedExts = Collections.unmodifiableSet(supportedExts);
         }
         return supportedExts;
@@ -168,9 +170,9 @@
      *
      * @param cert the Certificate to be processed
      * @param unresCritExts the unresolved critical extensions
-     * @exception CertPathValidatorException Exception thrown if
-     * the certificate does not verify.
+     * @throws CertPathValidatorException if the certificate does not verify
      */
+    @Override
     public void check(Certificate cert, Collection<String> unresCritExts)
         throws CertPathValidatorException
     {
@@ -178,10 +180,10 @@
         checkPolicy((X509Certificate) cert);
 
         if (unresCritExts != null && !unresCritExts.isEmpty()) {
-            unresCritExts.remove(PKIXExtensions.CertificatePolicies_Id.toString());
-            unresCritExts.remove(PKIXExtensions.PolicyMappings_Id.toString());
-            unresCritExts.remove(PKIXExtensions.PolicyConstraints_Id.toString());
-            unresCritExts.remove(PKIXExtensions.InhibitAnyPolicy_Id.toString());
+            unresCritExts.remove(CertificatePolicies_Id.toString());
+            unresCritExts.remove(PolicyMappings_Id.toString());
+            unresCritExts.remove(PolicyConstraints_Id.toString());
+            unresCritExts.remove(InhibitAnyPolicy_Id.toString());
         }
     }
 
@@ -290,7 +292,7 @@
                 if (require == 0)
                     explicitPolicy = require;
             }
-        } catch (Exception e) {
+        } catch (IOException e) {
             if (debug != null) {
                 debug.println("PolicyChecker.mergeExplicitPolicy "
                               + "unexpected exception");
@@ -339,7 +341,7 @@
                     policyMapping = inhibit;
                 }
             }
-        } catch (Exception e) {
+        } catch (IOException e) {
             if (debug != null) {
                 debug.println("PolicyChecker.mergePolicyMapping "
                               + "unexpected exception");
@@ -372,7 +374,7 @@
 
         try {
             InhibitAnyPolicyExtension inhAnyPolExt = (InhibitAnyPolicyExtension)
-                currCert.getExtension(PKIXExtensions.InhibitAnyPolicy_Id);
+                currCert.getExtension(InhibitAnyPolicy_Id);
             if (inhAnyPolExt == null)
                 return inhibitAnyPolicy;
 
@@ -387,7 +389,7 @@
                     inhibitAnyPolicy = skipCerts;
                 }
             }
-        } catch (Exception e) {
+        } catch (IOException e) {
             if (debug != null) {
                 debug.println("PolicyChecker.mergeInhibitAnyPolicy "
                               + "unexpected exception");
@@ -429,7 +431,7 @@
         boolean policiesCritical = false;
         List<PolicyInformation> policyInfo;
         PolicyNodeImpl rootNode = null;
-        Set<PolicyQualifierInfo> anyQuals = new HashSet<PolicyQualifierInfo>();
+        Set<PolicyQualifierInfo> anyQuals = new HashSet<>();
 
         if (origRootNode == null)
             rootNode = null;
@@ -600,7 +602,7 @@
         PolicyNodeImpl parentNode = (PolicyNodeImpl)anyNode.getParent();
         parentNode.deleteChild(anyNode);
         // see if there are any initialPolicies not represented by leaf nodes
-        Set<String> initial = new HashSet<String>(initPolicies);
+        Set<String> initial = new HashSet<>(initPolicies);
         for (PolicyNodeImpl node : rootNode.getPolicyNodes(certIndex)) {
             initial.remove(node.getValidPolicy());
         }
@@ -697,7 +699,7 @@
                         }
                     }
 
-                    Set<String> expPols = new HashSet<String>();
+                    Set<String> expPols = new HashSet<>();
                     expPols.add(curParExpPol);
 
                     curNode = new PolicyNodeImpl
@@ -762,8 +764,7 @@
         }
 
         boolean childDeleted = false;
-        for (int j = 0; j < maps.size(); j++) {
-            CertificatePolicyMap polMap = maps.get(j);
+        for (CertificatePolicyMap polMap : maps) {
             String issuerDomain
                 = polMap.getIssuerIdentifier().getIdentifier().toString();
             String subjectDomain
@@ -816,7 +817,7 @@
                         PolicyNodeImpl curAnyNodeParent =
                             (PolicyNodeImpl) curAnyNode.getParent();
 
-                        Set<String> expPols = new HashSet<String>();
+                        Set<String> expPols = new HashSet<>();
                         expPols.add(subjectDomain);
 
                         PolicyNodeImpl curNode = new PolicyNodeImpl
--- a/src/share/classes/sun/security/provider/certpath/PolicyNodeImpl.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/provider/certpath/PolicyNodeImpl.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2012, 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
@@ -134,30 +134,37 @@
              node.mCriticalityIndicator, node.mExpectedPolicySet, false);
     }
 
+    @Override
     public PolicyNode getParent() {
         return mParent;
     }
 
+    @Override
     public Iterator<PolicyNodeImpl> getChildren() {
         return Collections.unmodifiableSet(mChildren).iterator();
     }
 
+    @Override
     public int getDepth() {
         return mDepth;
     }
 
+    @Override
     public String getValidPolicy() {
         return mValidPolicy;
     }
 
+    @Override
     public Set<PolicyQualifierInfo> getPolicyQualifiers() {
         return Collections.unmodifiableSet(mQualifierSet);
     }
 
+    @Override
     public Set<String> getExpectedPolicies() {
         return Collections.unmodifiableSet(mExpectedPolicySet);
     }
 
+    @Override
     public boolean isCritical() {
         return mCriticalityIndicator;
     }
@@ -169,12 +176,12 @@
      *
      * @return a String describing the contents of the Policy Node
      */
+    @Override
     public String toString() {
-        StringBuffer buffer = new StringBuffer(this.asString());
+        StringBuilder buffer = new StringBuilder(this.asString());
 
-        Iterator<PolicyNodeImpl> it = getChildren();
-        while (it.hasNext()) {
-            buffer.append(it.next());
+        for (PolicyNodeImpl node : mChildren) {
+            buffer.append(node);
         }
         return buffer.toString();
     }
@@ -293,7 +300,7 @@
      * @return a <code>Set</code> of all nodes at the specified depth
      */
     Set<PolicyNodeImpl> getPolicyNodes(int depth) {
-        Set<PolicyNodeImpl> set = new HashSet<PolicyNodeImpl>();
+        Set<PolicyNodeImpl> set = new HashSet<>();
         getPolicyNodes(depth, set);
         return set;
     }
@@ -337,7 +344,7 @@
     private Set<PolicyNodeImpl> getPolicyNodesExpectedHelper(int depth,
         String expectedOID, boolean matchAny) {
 
-        HashSet<PolicyNodeImpl> set = new HashSet<PolicyNodeImpl>();
+        HashSet<PolicyNodeImpl> set = new HashSet<>();
 
         if (mDepth < depth) {
             for (PolicyNodeImpl node : mChildren) {
@@ -367,7 +374,7 @@
      * @return a Set of matched <code>PolicyNode</code>s
      */
     Set<PolicyNodeImpl> getPolicyNodesValid(int depth, String validOID) {
-        HashSet<PolicyNodeImpl> set = new HashSet<PolicyNodeImpl>();
+        HashSet<PolicyNodeImpl> set = new HashSet<>();
 
         if (mDepth < depth) {
             for (PolicyNodeImpl node : mChildren) {
@@ -396,7 +403,7 @@
         if (mParent == null) {
             return "anyPolicy  ROOT\n";
         } else {
-            StringBuffer sb = new StringBuffer();
+            StringBuilder sb = new StringBuilder();
             for (int i = 0, n = getDepth(); i < n; i++) {
                 sb.append("  ");
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/provider/certpath/ResponderId.java	Thu Nov 09 06:08:09 2017 +0000
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2015, 2017 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.provider.certpath;
+
+import java.util.Arrays;
+import java.io.IOException;
+import java.security.PublicKey;
+import javax.security.auth.x500.X500Principal;
+import sun.security.x509.KeyIdentifier;
+import sun.security.util.DerValue;
+
+/**
+ * Class for ResponderId entities as described in RFC6960.  ResponderId objects
+ * are used to uniquely identify OCSP responders.
+ * <p>
+ * The RFC 6960 defines a ResponderID structure as:
+ * <pre>
+ * ResponderID ::= CHOICE {
+ *      byName              [1] Name,
+ *      byKey               [2] KeyHash }
+ *
+ * KeyHash ::= OCTET STRING -- SHA-1 hash of responder's public key
+ * (excluding the tag and length fields)
+ *
+ * Name is defined in RFC 5280.
+ * </pre>
+ *
+ * @see ResponderId.Type
+ * @since 9
+ */
+public final class ResponderId {
+
+    /**
+     * A {@code ResponderId} enumeration describing the accepted forms for a
+     * {@code ResponderId}.
+     *
+     * @see ResponderId
+     * @since 9
+     */
+    public static enum Type {
+        /**
+         * A BY_NAME {@code ResponderId} will be built from a subject name,
+         * either as an {@code X500Principal} or a DER-encoded byte array.
+         */
+        BY_NAME(1, "byName"),
+
+        /**
+         * A BY_KEY {@code ResponderId} will be built from a public key
+         * identifier, either derived from a {@code PublicKey} or directly
+         * from a DER-encoded byte array containing the key identifier.
+         */
+        BY_KEY(2, "byKey");
+
+        private final int tagNumber;
+        private final String ridTypeName;
+
+        private Type(int value, String name) {
+            this.tagNumber = value;
+            this.ridTypeName = name;
+        }
+
+        public int value() {
+            return tagNumber;
+        }
+
+        @Override
+        public String toString() {
+            return ridTypeName;
+        }
+    }
+
+    private Type type;
+    private X500Principal responderName;
+    private KeyIdentifier responderKeyId;
+    private byte[] encodedRid;
+
+    /**
+     * Constructs a {@code ResponderId} object using an {@code X500Principal}.
+     * When encoded in DER this object will use the BY_NAME option.
+     *
+     * @param subjectName the subject name of the certificate used
+     * to sign OCSP responses.
+     *
+     * @throws IOException if the internal DER-encoding of the
+     *      {@code X500Principal} fails.
+     */
+    public ResponderId(X500Principal subjectName) throws IOException {
+        responderName = subjectName;
+        responderKeyId = null;
+        encodedRid = principalToBytes();
+        type = Type.BY_NAME;
+    }
+
+    /**
+     * Constructs a {@code ResponderId} object using a {@code PublicKey}.
+     * When encoded in DER this object will use the byKey option, a
+     * SHA-1 hash of the responder's public key.
+     *
+     * @param pubKey the the OCSP responder's public key
+     *
+     * @throws IOException if the internal DER-encoding of the
+     *      {@code KeyIdentifier} fails.
+     */
+    public ResponderId(PublicKey pubKey) throws IOException {
+        responderKeyId = new KeyIdentifier(pubKey);
+        responderName = null;
+        encodedRid = keyIdToBytes();
+        type = Type.BY_KEY;
+    }
+
+    /**
+     * Constructs a {@code ResponderId} object from its DER-encoding.
+     *
+     * @param encodedData the DER-encoded bytes
+     *
+     * @throws IOException if the encodedData is not properly DER encoded
+     */
+    public ResponderId(byte[] encodedData) throws IOException {
+        DerValue outer = new DerValue(encodedData);
+
+        if (outer.isContextSpecific((byte)Type.BY_NAME.value())
+                && outer.isConstructed()) {
+            // Use the X500Principal constructor as a way to sanity
+            // check the incoming data.
+            responderName = new X500Principal(outer.getDataBytes());
+            encodedRid = principalToBytes();
+            type = Type.BY_NAME;
+        } else if (outer.isContextSpecific((byte)Type.BY_KEY.value())
+                && outer.isConstructed()) {
+            // Use the KeyIdentifier constructor as a way to sanity
+            // check the incoming data.
+            responderKeyId =
+                new KeyIdentifier(new DerValue(outer.getDataBytes()));
+            encodedRid = keyIdToBytes();
+            type = Type.BY_KEY;
+        } else {
+            throw new IOException("Invalid ResponderId content");
+        }
+    }
+
+    /**
+     * Encode a {@code ResponderId} in DER form
+     *
+     * @return a byte array containing the DER-encoded representation for this
+     *      {@code ResponderId}
+     */
+    public byte[] getEncoded() {
+        return encodedRid.clone();
+    }
+
+    /**
+     * Return the type of {@ResponderId}
+     *
+     * @return a number corresponding to the context-specific tag number
+     *      used in the DER-encoding for a {@code ResponderId}
+     */
+    public ResponderId.Type getType() {
+        return type;
+    }
+
+    /**
+     * Get the length of the encoded {@code ResponderId} (including the tag and
+     * length of the explicit tagging from the outer ASN.1 CHOICE).
+     *
+     * @return the length of the encoded {@code ResponderId}
+     */
+    public int length() {
+        return encodedRid.length;
+    }
+
+    /**
+     * Obtain the underlying {@code X500Principal} from a {@code ResponderId}
+     *
+     * @return the {@code X500Principal} for this {@code ResponderId} if it
+     *      is a BY_NAME variant.  If the {@code ResponderId} is a BY_KEY
+     *      variant, this routine will return {@code null}.
+     */
+    public X500Principal getResponderName() {
+        return responderName;
+    }
+
+    /**
+     * Obtain the underlying key identifier from a {@code ResponderId}
+     *
+     * @return the {@code KeyIdentifier} for this {@code ResponderId} if it
+     *      is a BY_KEY variant.  If the {@code ResponderId} is a BY_NAME
+     *      variant, this routine will return {@code null}.
+     */
+    public KeyIdentifier getKeyIdentifier() {
+        return responderKeyId;
+    }
+
+    /**
+     * Compares the specified object with this {@code ResponderId} for equality.
+     * A ResponderId will only be considered equivalent if both the type and
+     * data value are equal.  Two ResponderIds initialized by name and
+     * key ID, respectively, will not be equal even if the
+     * ResponderId objects are created from the same source certificate.
+     *
+     * @param obj the object to be compared against
+     *
+     * @return true if the specified object is equal to this {@code Responderid}
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj instanceof ResponderId) {
+            ResponderId respObj = (ResponderId)obj;
+                return Arrays.equals(encodedRid, respObj.getEncoded());
+        }
+
+        return false;
+    }
+
+    /**
+     * Returns the hash code value for this {@code ResponderId}
+     *
+     * @return the hash code value for this {@code ResponderId}
+     */
+    @Override
+    public int hashCode() {
+        return Arrays.hashCode(encodedRid);
+    }
+
+    /**
+     * Create a String representation of this {@code ResponderId}
+     *
+     * @return a String representation of this {@code ResponderId}
+     */
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        switch (type) {
+            case BY_NAME:
+                sb.append(type).append(": ").append(responderName);
+                break;
+            case BY_KEY:
+                sb.append(type).append(": ");
+                for (byte keyIdByte : responderKeyId.getIdentifier()) {
+                    sb.append(String.format("%02X", keyIdByte));
+                }
+                break;
+            default:
+                sb.append("Unknown ResponderId Type: ").append(type);
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Convert the responderName data member into its DER-encoded form
+     *
+     * @return the DER encoding for a responder ID byName option, including
+     *      explicit context-specific tagging.
+     *
+     * @throws IOException if any encoding error occurs
+     */
+    private byte[] principalToBytes() throws IOException {
+        DerValue dv = new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT,
+                true, (byte)Type.BY_NAME.value()),
+                responderName.getEncoded());
+        return dv.toByteArray();
+    }
+
+    /**
+     * Convert the responderKeyId data member into its DER-encoded form
+     *
+     * @return the DER encoding for a responder ID byKey option, including
+     *      explicit context-specific tagging.
+     *
+     * @throws IOException if any encoding error occurs
+     */
+    private byte[] keyIdToBytes() throws IOException {
+        // Place the KeyIdentifier bytes into an OCTET STRING
+        DerValue inner = new DerValue(DerValue.tag_OctetString,
+                responderKeyId.getIdentifier());
+
+        // Mark the OCTET STRING-wrapped KeyIdentifier bytes
+        // as EXPLICIT CONTEXT 2
+        DerValue outer = new DerValue(DerValue.createTag(DerValue.TAG_CONTEXT,
+                true, (byte)Type.BY_KEY.value()), inner.toByteArray());
+
+        return outer.toByteArray();
+    }
+
+}
--- a/src/share/classes/sun/security/provider/certpath/ReverseBuilder.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/provider/certpath/ReverseBuilder.java	Thu Nov 09 06:08:09 2017 +0000
@@ -51,9 +51,10 @@
 
 import javax.security.auth.x500.X500Principal;
 
+import sun.security.provider.certpath.PKIX.BuilderParams;
 import sun.security.util.Debug;
 import sun.security.x509.Extension;
-import sun.security.x509.PKIXExtensions;
+import static sun.security.x509.PKIXExtensions.*;
 import sun.security.x509.X500Name;
 import sun.security.x509.X509CertImpl;
 import sun.security.x509.PolicyMappingsExtension;
@@ -72,28 +73,24 @@
 
     private Debug debug = Debug.getInstance("certpath");
 
-    Set<String> initPolicies;
+    private final Set<String> initPolicies;
 
     /**
      * Initialize the builder with the input parameters.
      *
      * @param params the parameter set used to build a certification path
      */
-    ReverseBuilder(PKIXBuilderParameters buildParams,
-        X500Principal targetSubjectDN) {
+    ReverseBuilder(BuilderParams buildParams) {
+        super(buildParams);
 
-        super(buildParams, targetSubjectDN);
-
-        Set<String> initialPolicies = buildParams.getInitialPolicies();
+        Set<String> initialPolicies = buildParams.initialPolicies();
         initPolicies = new HashSet<String>();
         if (initialPolicies.isEmpty()) {
             // if no initialPolicies are specified by user, set
             // initPolicies to be anyPolicy by default
             initPolicies.add(PolicyChecker.ANY_POLICY);
         } else {
-            for (String policy : initialPolicies) {
-                initPolicies.add(policy);
-            }
+            initPolicies.addAll(initialPolicies);
         }
     }
 
@@ -106,6 +103,7 @@
      *        Must be an instance of <code>ReverseState</code>
      * @param certStores list of CertStores
      */
+    @Override
     Collection<X509Certificate> getMatchingCerts
         (State currState, List<CertStore> certStores)
         throws CertStoreException, CertificateException, IOException
@@ -138,56 +136,56 @@
         (ReverseState currentState, List<CertStore> certStores)
         throws CertStoreException, CertificateException, IOException {
 
-      /*
-       * Compose a CertSelector to filter out
-       * certs which do not satisfy requirements.
-       *
-       * First, retrieve clone of current target cert constraints,
-       * and then add more selection criteria based on current validation state.
-       */
-      X509CertSelector sel = (X509CertSelector) targetCertConstraints.clone();
+        /*
+         * Compose a CertSelector to filter out
+         * certs which do not satisfy requirements.
+         *
+         * First, retrieve clone of current target cert constraints, and
+         * then add more selection criteria based on current validation state.
+         */
+        X509CertSelector sel = (X509CertSelector) targetCertConstraints.clone();
 
-      /*
-       * Match on issuer (subject of previous cert)
-       */
-      sel.setIssuer(currentState.subjectDN);
+        /*
+         * Match on issuer (subject of previous cert)
+         */
+        sel.setIssuer(currentState.subjectDN);
 
-      /*
-       * Match on certificate validity date.
-       */
-      sel.setCertificateValid(date);
+        /*
+         * Match on certificate validity date.
+         */
+        sel.setCertificateValid(buildParams.date());
 
-      /*
-       * Policy processing optimizations
-       */
-      if (currentState.explicitPolicy == 0)
-          sel.setPolicy(getMatchingPolicies());
+        /*
+         * Policy processing optimizations
+         */
+        if (currentState.explicitPolicy == 0)
+            sel.setPolicy(getMatchingPolicies());
 
-      /*
-       * If previous cert has a subject key identifier extension,
-       * use it to match on authority key identifier extension.
-       */
-      /*if (currentState.subjKeyId != null) {
-        AuthorityKeyIdentifierExtension authKeyId = new AuthorityKeyIdentifierExtension(
+        /*
+         * If previous cert has a subject key identifier extension,
+         * use it to match on authority key identifier extension.
+         */
+        /*if (currentState.subjKeyId != null) {
+          AuthorityKeyIdentifierExtension authKeyId = new AuthorityKeyIdentifierExtension(
                 (KeyIdentifier) currentState.subjKeyId.get(SubjectKeyIdentifierExtension.KEY_ID),
                 null, null);
         sel.setAuthorityKeyIdentifier(authKeyId.getExtensionValue());
-      }*/
+        }*/
 
-      /*
-       * Require EE certs
-       */
-      sel.setBasicConstraints(-2);
+        /*
+         * Require EE certs
+         */
+        sel.setBasicConstraints(-2);
 
-      /* Retrieve matching certs from CertStores */
-      HashSet<X509Certificate> eeCerts = new HashSet<X509Certificate>();
-      addMatchingCerts(sel, certStores, eeCerts, true);
+        /* Retrieve matching certs from CertStores */
+        HashSet<X509Certificate> eeCerts = new HashSet<>();
+        addMatchingCerts(sel, certStores, eeCerts, true);
 
-      if (debug != null) {
-        debug.println("ReverseBuilder.getMatchingEECerts got " + eeCerts.size()
-                    + " certs.");
-      }
-      return eeCerts;
+        if (debug != null) {
+            debug.println("ReverseBuilder.getMatchingEECerts got "
+                          + eeCerts.size() + " certs.");
+        }
+        return eeCerts;
     }
 
     /*
@@ -198,63 +196,71 @@
         (ReverseState currentState, List<CertStore> certStores)
         throws CertificateException, CertStoreException, IOException {
 
-      /*
-       * Compose a CertSelector to filter out
-       * certs which do not satisfy requirements.
-       */
-      X509CertSelector sel = new X509CertSelector();
+        /*
+         * Compose a CertSelector to filter out
+         * certs which do not satisfy requirements.
+         */
+        X509CertSelector sel = new X509CertSelector();
 
-      /*
-       * Match on issuer (subject of previous cert)
-       */
-      sel.setIssuer(currentState.subjectDN);
+        /*
+         * Match on issuer (subject of previous cert)
+         */
+        sel.setIssuer(currentState.subjectDN);
 
-      /*
-       * Match on certificate validity date.
-       */
-      sel.setCertificateValid(date);
+        /*
+         * Match on certificate validity date.
+         */
+        sel.setCertificateValid(buildParams.date());
 
-      /*
-       * Match on target subject name (checks that current cert's
-       * name constraints permit it to certify target).
-       * (4 is the integer type for DIRECTORY name).
-       */
-      sel.addPathToName(4, targetCertConstraints.getSubjectAsBytes());
+        /*
+         * Match on target subject name (checks that current cert's
+         * name constraints permit it to certify target).
+         * (4 is the integer type for DIRECTORY name).
+         */
+        byte[] subject = targetCertConstraints.getSubjectAsBytes();
+        if (subject != null) {
+            sel.addPathToName(4, subject);
+        } else {
+            X509Certificate cert = targetCertConstraints.getCertificate();
+            if (cert != null) {
+                sel.addPathToName(4,
+                                  cert.getSubjectX500Principal().getEncoded());
+            }
+        }
 
-      /*
-       * Policy processing optimizations
-       */
-      if (currentState.explicitPolicy == 0)
-          sel.setPolicy(getMatchingPolicies());
+        /*
+         * Policy processing optimizations
+         */
+        if (currentState.explicitPolicy == 0)
+            sel.setPolicy(getMatchingPolicies());
 
-      /*
-       * If previous cert has a subject key identifier extension,
-       * use it to match on authority key identifier extension.
-       */
-      /*if (currentState.subjKeyId != null) {
-        AuthorityKeyIdentifierExtension authKeyId = new AuthorityKeyIdentifierExtension(
+        /*
+         * If previous cert has a subject key identifier extension,
+         * use it to match on authority key identifier extension.
+         */
+        /*if (currentState.subjKeyId != null) {
+          AuthorityKeyIdentifierExtension authKeyId = new AuthorityKeyIdentifierExtension(
                 (KeyIdentifier) currentState.subjKeyId.get(SubjectKeyIdentifierExtension.KEY_ID),
                                 null, null);
-        sel.setAuthorityKeyIdentifier(authKeyId.getExtensionValue());
-      }*/
+          sel.setAuthorityKeyIdentifier(authKeyId.getExtensionValue());
+        }*/
 
-      /*
-       * Require CA certs
-       */
-      sel.setBasicConstraints(0);
+        /*
+         * Require CA certs
+         */
+        sel.setBasicConstraints(0);
 
-      /* Retrieve matching certs from CertStores */
-      ArrayList<X509Certificate> reverseCerts =
-          new ArrayList<X509Certificate>();
-      addMatchingCerts(sel, certStores, reverseCerts, true);
+        /* Retrieve matching certs from CertStores */
+        ArrayList<X509Certificate> reverseCerts = new ArrayList<>();
+        addMatchingCerts(sel, certStores, reverseCerts, true);
 
-      /* Sort remaining certs using name constraints */
-      Collections.sort(reverseCerts, new PKIXCertComparator());
+        /* Sort remaining certs using name constraints */
+        Collections.sort(reverseCerts, new PKIXCertComparator());
 
-      if (debug != null)
-        debug.println("ReverseBuilder.getMatchingCACerts got " +
-                    reverseCerts.size() + " certs.");
-      return reverseCerts;
+        if (debug != null)
+            debug.println("ReverseBuilder.getMatchingCACerts got " +
+                          reverseCerts.size() + " certs.");
+        return reverseCerts;
     }
 
     /*
@@ -269,23 +275,25 @@
 
         private Debug debug = Debug.getInstance("certpath");
 
+        @Override
         public int compare(X509Certificate cert1, X509Certificate cert2) {
 
             /*
              * if either cert certifies the target, always
              * put at head of list.
              */
-            if (cert1.getSubjectX500Principal().equals(targetSubjectDN)) {
+            X500Principal targetSubject = buildParams.targetSubject();
+            if (cert1.getSubjectX500Principal().equals(targetSubject)) {
                 return -1;
             }
-            if (cert2.getSubjectX500Principal().equals(targetSubjectDN)) {
+            if (cert2.getSubjectX500Principal().equals(targetSubject)) {
                 return 1;
             }
 
             int targetDist1;
             int targetDist2;
             try {
-                X500Name targetSubjectName = X500Name.asX500Name(targetSubjectDN);
+                X500Name targetSubjectName = X500Name.asX500Name(targetSubject);
                 targetDist1 = Builder.targetDistance(
                     null, cert1, targetSubjectName);
                 targetDist2 = Builder.targetDistance(
@@ -330,6 +338,7 @@
      * @param currentState the current state against which the cert is verified
      * @param certPathList the certPathList generated thus far
      */
+    @Override
     void verifyCert(X509Certificate cert, State currState,
         List<X509Certificate> certPathList)
         throws GeneralSecurityException
@@ -362,8 +371,7 @@
          * of the same certificate, we reverse the certpathlist first
          */
         if ((certPathList != null) && (!certPathList.isEmpty())) {
-            List<X509Certificate> reverseCertList =
-                new ArrayList<X509Certificate>();
+            List<X509Certificate> reverseCertList = new ArrayList<>();
             for (X509Certificate c : certPathList) {
                 reverseCertList.add(0, c);
             }
@@ -378,8 +386,8 @@
                 }
                 if (debug != null)
                     debug.println("policyMappingFound = " + policyMappingFound);
-                if (cert.equals(cpListCert)){
-                    if ((buildParams.isPolicyMappingInhibited()) ||
+                if (cert.equals(cpListCert)) {
+                    if ((buildParams.policyMappingInhibited()) ||
                         (!policyMappingFound)){
                         if (debug != null)
                             debug.println("loop detected!!");
@@ -390,7 +398,7 @@
         }
 
         /* check if target cert */
-        boolean finalCert = cert.getSubjectX500Principal().equals(targetSubjectDN);
+        boolean finalCert = cert.getSubjectX500Principal().equals(buildParams.targetSubject());
 
         /* check if CA cert */
         boolean caCert = (cert.getBasicConstraints() != -1 ? true : false);
@@ -431,23 +439,20 @@
         /*
          * Check revocation.
          */
-        if (buildParams.isRevocationEnabled()) {
-
-            currentState.crlChecker.check(cert,
-                                          currentState.pubKey,
-                                          currentState.crlSign);
+        if (buildParams.revocationEnabled() && currentState.revChecker != null) {
+            currentState.revChecker.check(cert, Collections.<String>emptySet());
         }
 
         /* Check name constraints if this is not a self-issued cert */
         if (finalCert || !X509CertImpl.isSelfIssued(cert)){
-            if (currentState.nc != null){
+            if (currentState.nc != null) {
                 try {
                     if (!currentState.nc.verify(cert)){
                         throw new CertPathValidatorException
                             ("name constraints check failed", null, null, -1,
                              PKIXReason.INVALID_NAME);
                     }
-                } catch (IOException ioe){
+                } catch (IOException ioe) {
                     throw new CertPathValidatorException(ioe);
                 }
             }
@@ -461,7 +466,7 @@
             (currentState.certIndex, initPolicies,
             currentState.explicitPolicy, currentState.policyMapping,
             currentState.inhibitAnyPolicy,
-            buildParams.getPolicyQualifiersRejected(), currentState.rootNode,
+            buildParams.policyQualifiersRejected(), currentState.rootNode,
             certImpl, finalCert);
 
         /*
@@ -486,15 +491,15 @@
          * already checked. If there are any left, throw an exception!
          */
         if (!unresolvedCritExts.isEmpty()) {
-            unresolvedCritExts.remove(PKIXExtensions.BasicConstraints_Id.toString());
-            unresolvedCritExts.remove(PKIXExtensions.NameConstraints_Id.toString());
-            unresolvedCritExts.remove(PKIXExtensions.CertificatePolicies_Id.toString());
-            unresolvedCritExts.remove(PKIXExtensions.PolicyMappings_Id.toString());
-            unresolvedCritExts.remove(PKIXExtensions.PolicyConstraints_Id.toString());
-            unresolvedCritExts.remove(PKIXExtensions.InhibitAnyPolicy_Id.toString());
-            unresolvedCritExts.remove(PKIXExtensions.SubjectAlternativeName_Id.toString());
-            unresolvedCritExts.remove(PKIXExtensions.KeyUsage_Id.toString());
-            unresolvedCritExts.remove(PKIXExtensions.ExtendedKeyUsage_Id.toString());
+            unresolvedCritExts.remove(BasicConstraints_Id.toString());
+            unresolvedCritExts.remove(NameConstraints_Id.toString());
+            unresolvedCritExts.remove(CertificatePolicies_Id.toString());
+            unresolvedCritExts.remove(PolicyMappings_Id.toString());
+            unresolvedCritExts.remove(PolicyConstraints_Id.toString());
+            unresolvedCritExts.remove(InhibitAnyPolicy_Id.toString());
+            unresolvedCritExts.remove(SubjectAlternativeName_Id.toString());
+            unresolvedCritExts.remove(KeyUsage_Id.toString());
+            unresolvedCritExts.remove(ExtendedKeyUsage_Id.toString());
 
             if (!unresolvedCritExts.isEmpty())
                 throw new CertPathValidatorException
@@ -505,8 +510,8 @@
         /*
          * Check signature.
          */
-        if (buildParams.getSigProvider() != null) {
-            cert.verify(currentState.pubKey, buildParams.getSigProvider());
+        if (buildParams.sigProvider() != null) {
+            cert.verify(currentState.pubKey, buildParams.sigProvider());
         } else {
             cert.verify(currentState.pubKey);
         }
@@ -519,8 +524,9 @@
      * @param cert the certificate to test
      * @return a boolean value indicating whether the cert completes the path.
      */
+    @Override
     boolean isPathCompleted(X509Certificate cert) {
-        return cert.getSubjectX500Principal().equals(targetSubjectDN);
+        return cert.getSubjectX500Principal().equals(buildParams.targetSubject());
     }
 
     /** Adds the certificate to the certPathList
@@ -528,6 +534,7 @@
      * @param cert the certificate to be added
      * @param certPathList the certification path list
      */
+    @Override
     void addCertToPath(X509Certificate cert,
         LinkedList<X509Certificate> certPathList) {
         certPathList.addLast(cert);
@@ -537,6 +544,7 @@
      *
      * @param certPathList the certification path list
      */
+    @Override
     void removeFinalCertFromPath(LinkedList<X509Certificate> certPathList) {
         certPathList.removeLast();
     }
--- a/src/share/classes/sun/security/provider/certpath/ReverseState.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/provider/certpath/ReverseState.java	Thu Nov 09 06:08:09 2017 +0000
@@ -40,6 +40,7 @@
 import java.util.Set;
 import javax.security.auth.x500.X500Principal;
 
+import sun.security.provider.certpath.PKIX.BuilderParams;
 import sun.security.util.Debug;
 import sun.security.x509.NameConstraintsExtension;
 import sun.security.x509.SubjectKeyIdentifierExtension;
@@ -94,7 +95,7 @@
     private boolean init = true;
 
     /* the checker used for revocation status */
-    public CrlRevocationChecker crlChecker;
+    RevocationChecker revChecker;
 
     /* the algorithm checker */
     AlgorithmChecker algorithmChecker;
@@ -108,7 +109,7 @@
     /* Flag indicating if current cert can vouch for the CRL for
      * the next cert
      */
-    public boolean crlSign = true;
+    boolean crlSign = true;
 
     /**
      * Returns a boolean flag indicating if the state is initial
@@ -116,6 +117,7 @@
      *
      * @return boolean flag indicating if the state is initial (just starting)
      */
+    @Override
     public boolean isInitial() {
         return init;
     }
@@ -123,44 +125,32 @@
     /**
      * Display state for debugging purposes
      */
+    @Override
     public String toString() {
-        StringBuffer sb = new StringBuffer();
-        try {
-            sb.append("State [");
-            sb.append("\n  subjectDN of last cert: " + subjectDN);
-            sb.append("\n  subjectKeyIdentifier: " + String.valueOf(subjKeyId));
-            sb.append("\n  nameConstraints: " + String.valueOf(nc));
-            sb.append("\n  certIndex: " + certIndex);
-            sb.append("\n  explicitPolicy: " + explicitPolicy);
-            sb.append("\n  policyMapping:  " + policyMapping);
-            sb.append("\n  inhibitAnyPolicy:  " + inhibitAnyPolicy);
-            sb.append("\n  rootNode: " + rootNode);
-            sb.append("\n  remainingCACerts: " + remainingCACerts);
-            sb.append("\n  crlSign: " + crlSign);
-            sb.append("\n  init: " + init);
-            sb.append("\n]\n");
-        } catch (Exception e) {
-            if (debug != null) {
-                debug.println("ReverseState.toString() unexpected exception");
-                e.printStackTrace();
-            }
-        }
+        StringBuilder sb = new StringBuilder();
+        sb.append("State [");
+        sb.append("\n  subjectDN of last cert: ").append(subjectDN);
+        sb.append("\n  subjectKeyIdentifier: ").append
+                 (String.valueOf(subjKeyId));
+        sb.append("\n  nameConstraints: ").append(String.valueOf(nc));
+        sb.append("\n  certIndex: ").append(certIndex);
+        sb.append("\n  explicitPolicy: ").append(explicitPolicy);
+        sb.append("\n  policyMapping:  ").append(policyMapping);
+        sb.append("\n  inhibitAnyPolicy:  ").append(inhibitAnyPolicy);
+        sb.append("\n  rootNode: ").append(rootNode);
+        sb.append("\n  remainingCACerts: ").append(remainingCACerts);
+        sb.append("\n  crlSign: ").append(crlSign);
+        sb.append("\n  init: ").append(init);
+        sb.append("\n]\n");
         return sb.toString();
     }
 
     /**
      * Initialize the state.
      *
-     * @param maxPathLen The maximum number of CA certs in a path, where -1
-     * means unlimited and 0 means only a single EE cert is allowed.
-     * @param explicitPolicyRequired True, if explicit policy is required.
-     * @param policyMappingInhibited True, if policy mapping is inhibited.
-     * @param anyPolicyInhibited True, if any policy is inhibited.
-     * @param certPathCheckers the list of user-defined PKIXCertPathCheckers
+     * @param buildParams builder parameters
      */
-    public void initState(int maxPathLen, boolean explicitPolicyRequired,
-        boolean policyMappingInhibited, boolean anyPolicyInhibited,
-        List<PKIXCertPathChecker> certPathCheckers)
+    public void initState(BuilderParams buildParams)
         throws CertPathValidatorException
     {
         /*
@@ -168,60 +158,52 @@
          * Note that -1 maxPathLen implies unlimited.
          * 0 implies only an EE cert is acceptable.
          */
-        remainingCACerts = (maxPathLen == -1 ? Integer.MAX_VALUE : maxPathLen);
+        int maxPathLen = buildParams.maxPathLength();
+        remainingCACerts = (maxPathLen == -1) ? Integer.MAX_VALUE
+                                              : maxPathLen;
 
         /* Initialize explicit policy state variable */
-        if (explicitPolicyRequired) {
+        if (buildParams.explicitPolicyRequired()) {
             explicitPolicy = 0;
         } else {
             // unconstrained if maxPathLen is -1,
             // otherwise, we want to initialize this to the value of the
             // longest possible path + 1 (i.e. maxpathlen + finalcert + 1)
-            explicitPolicy = (maxPathLen == -1)
-                ? maxPathLen
-                : maxPathLen + 2;
+            explicitPolicy = (maxPathLen == -1) ? maxPathLen : maxPathLen + 2;
         }
 
         /* Initialize policy mapping state variable */
-        if (policyMappingInhibited) {
+        if (buildParams.policyMappingInhibited()) {
             policyMapping = 0;
         } else {
-            policyMapping = (maxPathLen == -1)
-                ? maxPathLen
-                : maxPathLen + 2;
+            policyMapping = (maxPathLen == -1) ? maxPathLen : maxPathLen + 2;
         }
 
         /* Initialize inhibit any policy state variable */
-        if (anyPolicyInhibited) {
+        if (buildParams.anyPolicyInhibited()) {
             inhibitAnyPolicy = 0;
         } else {
-            inhibitAnyPolicy = (maxPathLen == -1)
-                ? maxPathLen
-                : maxPathLen + 2;
+            inhibitAnyPolicy = (maxPathLen == -1) ? maxPathLen : maxPathLen + 2;
         }
 
         /* Initialize certIndex */
         certIndex = 1;
 
         /* Initialize policy tree */
-        Set<String> initExpPolSet = new HashSet<String>(1);
+        Set<String> initExpPolSet = new HashSet<>(1);
         initExpPolSet.add(PolicyChecker.ANY_POLICY);
 
-        rootNode = new PolicyNodeImpl
-            (null, PolicyChecker.ANY_POLICY, null, false, initExpPolSet, false);
+        rootNode = new PolicyNodeImpl(null, PolicyChecker.ANY_POLICY, null,
+                                      false, initExpPolSet, false);
 
         /*
          * Initialize each user-defined checker
+         * Shallow copy the checkers
          */
-        if (certPathCheckers != null) {
-            /* Shallow copy the checkers */
-            userCheckers = new ArrayList<PKIXCertPathChecker>(certPathCheckers);
-            /* initialize each checker (just in case) */
-            for (PKIXCertPathChecker checker : certPathCheckers) {
-                checker.init(false);
-            }
-        } else {
-            userCheckers = new ArrayList<PKIXCertPathChecker>();
+        userCheckers = new ArrayList<>(buildParams.certPathCheckers());
+        /* initialize each checker (just in case) */
+        for (PKIXCertPathChecker checker : userCheckers) {
+            checker.init(false);
         }
 
         /* Start by trusting the cert to sign CRLs */
@@ -234,8 +216,9 @@
      * Update the state with the specified trust anchor.
      *
      * @param anchor the most-trusted CA
+     * @param buildParams builder parameters
      */
-    public void updateState(TrustAnchor anchor)
+    public void updateState(TrustAnchor anchor, BuilderParams buildParams)
         throws CertificateException, IOException, CertPathValidatorException
     {
         trustAnchor = anchor;
@@ -255,6 +238,12 @@
             }
         }
 
+        // only create a RevocationChecker if revocation is enabled
+        if (buildParams.revocationEnabled()) {
+            revChecker = new RevocationChecker(anchor, buildParams);
+            revChecker.init(false);
+        }
+
         init = false;
     }
 
@@ -313,7 +302,7 @@
         subjKeyId = icert.getSubjectKeyIdentifierExtension();
 
         /* update crlSign */
-        crlSign = CrlRevocationChecker.certCanSignCrl(cert);
+        crlSign = RevocationChecker.certCanSignCrl(cert);
 
         /* update current name constraints */
         if (nc != null) {
@@ -352,6 +341,7 @@
      *
      * @return boolean flag indicating if key lacking parameters encountered.
      */
+    @Override
     public boolean keyParamsNeeded() {
         /* when building in reverse, we immediately get parameters needed
          * or else throw an exception
@@ -368,6 +358,7 @@
      * because some of them (e.g., subjKeyId) will
      * not have their contents modified by subsequent calls to updateState.
      */
+    @Override
     @SuppressWarnings("unchecked") // Safe casts assuming clone() works correctly
     public Object clone() {
         try {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/provider/certpath/RevocationChecker.java	Thu Nov 09 06:08:09 2017 +0000
@@ -0,0 +1,1152 @@
+/*
+ * Copyright (c) 2012, 2017, 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.provider.certpath;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.security.AccessController;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivilegedAction;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.cert.CertPathValidatorException.BasicReason;
+import java.security.cert.Extension;
+import java.security.cert.*;
+import java.security.interfaces.DSAPublicKey;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.security.auth.x500.X500Principal;
+
+import static sun.security.provider.certpath.OCSP.*;
+import static sun.security.provider.certpath.PKIX.*;
+import sun.security.x509.*;
+import static sun.security.x509.PKIXExtensions.*;
+import sun.security.util.Debug;
+
+class RevocationChecker extends PKIXRevocationChecker {
+
+    private static final Debug debug = Debug.getInstance("certpath");
+
+    private TrustAnchor anchor;
+    private ValidatorParams params;
+    private boolean onlyEE;
+    private boolean softFail;
+    private boolean crlDP;
+    private URI responderURI;
+    private X509Certificate responderCert;
+    private List<CertStore> certStores;
+    private Map<X509Certificate, byte[]> ocspStapled;
+    private List<Extension> ocspExtensions;
+    private final boolean legacy;
+
+    // state variables
+    private OCSPResponse.IssuerInfo issuerInfo;
+    private PublicKey prevPubKey;
+    private boolean crlSignFlag;
+
+    private enum Mode { PREFER_OCSP, PREFER_CRLS, ONLY_CRLS };
+    private Mode mode = Mode.PREFER_OCSP;
+
+    private static class RevocationProperties {
+        boolean onlyEE;
+        boolean ocspEnabled;
+        boolean crlDPEnabled;
+        String ocspUrl;
+        String ocspSubject;
+        String ocspIssuer;
+        String ocspSerial;
+    }
+
+    RevocationChecker() {
+        legacy = false;
+    }
+
+    RevocationChecker(TrustAnchor anchor, ValidatorParams params)
+        throws CertPathValidatorException
+    {
+        legacy = true;
+        init(anchor, params);
+    }
+
+    void init(TrustAnchor anchor, ValidatorParams params)
+        throws CertPathValidatorException
+    {
+        RevocationProperties rp = getRevocationProperties();
+        URI uri = getOCSPResponder();
+        responderURI = (uri == null) ? toURI(rp.ocspUrl) : uri;
+        X509Certificate cert = getOCSPResponderCert();
+        responderCert = (cert == null)
+                        ? getResponderCert(rp, params.trustAnchors(),
+                                           params.certStores())
+                        : cert;
+        Set<Option> options = getOptions();
+        for (Option option : options) {
+            switch (option) {
+            case ONLY_END_ENTITY:
+            case PREFER_CRLS:
+            case SOFT_FAIL:
+                break;
+            default:
+                throw new CertPathValidatorException(
+                    "Unrecognized revocation parameter option: " + option);
+            }
+        }
+
+        // set mode, only end entity flag
+        if (legacy) {
+            mode = (rp.ocspEnabled) ? Mode.PREFER_OCSP : Mode.ONLY_CRLS;
+            onlyEE = rp.onlyEE;
+        } else {
+            if (options.contains(Option.PREFER_CRLS)) {
+                mode = Mode.PREFER_CRLS;
+            }
+            onlyEE = options.contains(Option.ONLY_END_ENTITY);
+        }
+        softFail = options.contains(Option.SOFT_FAIL);
+        if (legacy) {
+            crlDP = rp.crlDPEnabled;
+        } else {
+            crlDP = true;
+        }
+        ocspStapled = getOCSPStapledResponses();
+        ocspExtensions = getOCSPExtensions();
+
+        this.anchor = anchor;
+        this.params = params;
+        this.certStores = new ArrayList<>(params.certStores());
+        try {
+            this.certStores.add(CertStore.getInstance("Collection",
+                new CollectionCertStoreParameters(params.certificates())));
+        } catch (InvalidAlgorithmParameterException |
+                 NoSuchAlgorithmException e) {
+            // should never occur but not necessarily fatal, so log it,
+            // ignore and continue
+            if (debug != null) {
+                debug.println("RevocationChecker: " +
+                              "error creating Collection CertStore: " + e);
+            }
+        }
+    }
+
+    private static URI toURI(String uriString)
+        throws CertPathValidatorException
+    {
+        try {
+            if (uriString != null) {
+                return new URI(uriString);
+            }
+            return null;
+        } catch (URISyntaxException e) {
+            throw new CertPathValidatorException(
+                "cannot parse ocsp.responderURL property", e);
+        }
+    }
+
+    private static RevocationProperties getRevocationProperties() {
+        return AccessController.doPrivileged(
+            new PrivilegedAction<RevocationProperties>() {
+                public RevocationProperties run() {
+                    RevocationProperties rp = new RevocationProperties();
+                    String onlyEE = Security.getProperty(
+                        "com.sun.security.onlyCheckRevocationOfEECert");
+                    rp.onlyEE = onlyEE != null
+                                && onlyEE.equalsIgnoreCase("true");
+                    String ocspEnabled = Security.getProperty("ocsp.enable");
+                    rp.ocspEnabled = ocspEnabled != null
+                                     && ocspEnabled.equalsIgnoreCase("true");
+                    rp.ocspUrl = Security.getProperty("ocsp.responderURL");
+                    rp.ocspSubject
+                        = Security.getProperty("ocsp.responderCertSubjectName");
+                    rp.ocspIssuer
+                        = Security.getProperty("ocsp.responderCertIssuerName");
+                    rp.ocspSerial
+                        = Security.getProperty("ocsp.responderCertSerialNumber");
+                    rp.crlDPEnabled
+                        = Boolean.getBoolean("com.sun.security.enableCRLDP");
+                    return rp;
+                }
+            }
+        );
+    }
+
+    private static X509Certificate getResponderCert(RevocationProperties rp,
+                                                    Set<TrustAnchor> anchors,
+                                                    List<CertStore> stores)
+        throws CertPathValidatorException
+    {
+        if (rp.ocspSubject != null) {
+            return getResponderCert(rp.ocspSubject, anchors, stores);
+        } else if (rp.ocspIssuer != null && rp.ocspSerial != null) {
+            return getResponderCert(rp.ocspIssuer, rp.ocspSerial,
+                                    anchors, stores);
+        } else if (rp.ocspIssuer != null || rp.ocspSerial != null) {
+            throw new CertPathValidatorException(
+                "Must specify both ocsp.responderCertIssuerName and " +
+                "ocsp.responderCertSerialNumber properties");
+        }
+        return null;
+    }
+
+    private static X509Certificate getResponderCert(String subject,
+                                                    Set<TrustAnchor> anchors,
+                                                    List<CertStore> stores)
+        throws CertPathValidatorException
+    {
+        X509CertSelector sel = new X509CertSelector();
+        try {
+            sel.setSubject(new X500Principal(subject));
+        } catch (IllegalArgumentException e) {
+            throw new CertPathValidatorException(
+                "cannot parse ocsp.responderCertSubjectName property", e);
+        }
+        return getResponderCert(sel, anchors, stores);
+    }
+
+    private static X509Certificate getResponderCert(String issuer,
+                                                    String serial,
+                                                    Set<TrustAnchor> anchors,
+                                                    List<CertStore> stores)
+        throws CertPathValidatorException
+    {
+        X509CertSelector sel = new X509CertSelector();
+        try {
+            sel.setIssuer(new X500Principal(issuer));
+        } catch (IllegalArgumentException e) {
+            throw new CertPathValidatorException(
+                "cannot parse ocsp.responderCertIssuerName property", e);
+        }
+        try {
+            sel.setSerialNumber(new BigInteger(stripOutSeparators(serial), 16));
+        } catch (NumberFormatException e) {
+            throw new CertPathValidatorException(
+                "cannot parse ocsp.responderCertSerialNumber property", e);
+        }
+        return getResponderCert(sel, anchors, stores);
+    }
+
+    private static X509Certificate getResponderCert(X509CertSelector sel,
+                                                    Set<TrustAnchor> anchors,
+                                                    List<CertStore> stores)
+        throws CertPathValidatorException
+    {
+        // first check TrustAnchors
+        for (TrustAnchor anchor : anchors) {
+            X509Certificate cert = anchor.getTrustedCert();
+            if (cert == null) {
+                continue;
+            }
+            if (sel.match(cert)) {
+                return cert;
+            }
+        }
+        // now check CertStores
+        for (CertStore store : stores) {
+            try {
+                Collection<? extends Certificate> certs =
+                    store.getCertificates(sel);
+                if (!certs.isEmpty()) {
+                    return (X509Certificate)certs.iterator().next();
+                }
+            } catch (CertStoreException e) {
+                // ignore and try next CertStore
+                if (debug != null) {
+                    debug.println("CertStore exception:" + e);
+                }
+                continue;
+            }
+        }
+        throw new CertPathValidatorException(
+            "Cannot find the responder's certificate " +
+            "(set using the OCSP security properties).");
+    }
+
+    @Override
+    public void init(boolean forward) throws CertPathValidatorException {
+        if (forward) {
+            throw new
+                CertPathValidatorException("forward checking not supported");
+        } else {
+            if (anchor != null) {
+            issuerInfo = new OCSPResponse.IssuerInfo(anchor);
+            prevPubKey = issuerInfo.getPublicKey();
+
+            }
+            crlSignFlag = true;
+        }
+    }
+
+    @Override
+    public boolean isForwardCheckingSupported() {
+        return false;
+    }
+
+    @Override
+    public Set<String> getSupportedExtensions() {
+        return null;
+    }
+
+    @Override
+    public void check(Certificate cert, Collection<String> unresolvedCritExts)
+        throws CertPathValidatorException
+    {
+        X509Certificate xcert = (X509Certificate)cert;
+        if (onlyEE && xcert.getBasicConstraints() != -1) {
+            if (debug != null) {
+                debug.println("Skipping revocation check, not end entity cert");
+            }
+        } else {
+            check(xcert, unresolvedCritExts, prevPubKey, crlSignFlag);
+        }
+        updateState(xcert);
+    }
+
+    void check(X509Certificate xcert, Collection<String> unresolvedCritExts,
+               PublicKey pubKey, boolean crlSignFlag)
+        throws CertPathValidatorException
+    {
+        try {
+            switch (mode) {
+                case PREFER_OCSP:
+                    checkOCSP(xcert, unresolvedCritExts);
+                    break;
+                case PREFER_CRLS:
+                case ONLY_CRLS:
+                    checkCRLs(xcert, unresolvedCritExts, null,
+                              pubKey, crlSignFlag);
+                    break;
+            }
+        } catch (CertPathValidatorException e) {
+            if (e.getReason() == BasicReason.REVOKED) {
+                throw e;
+            }
+            CertPathValidatorException cause = e;
+            if (softFail && e instanceof NetworkFailureException) {
+                if (mode == Mode.ONLY_CRLS) return;
+            }
+            // Rethrow the exception if ONLY_CRLS
+            if (mode == Mode.ONLY_CRLS) {
+                throw e;
+            }
+            // Otherwise, failover
+            if (debug != null) {
+                debug.println("RevocationChecker.check() " + e.getMessage());
+                debug.println("RevocationChecker.check() preparing to failover");
+            }
+            try {
+                switch (mode) {
+                    case PREFER_OCSP:
+                        checkCRLs(xcert, unresolvedCritExts, null,
+                                  pubKey, crlSignFlag);
+                        break;
+                    case PREFER_CRLS:
+                        checkOCSP(xcert, unresolvedCritExts);
+                        break;
+                }
+            } catch (CertPathValidatorException x) {
+                if (debug != null) {
+                    debug.println("RevocationChecker.check() failover failed");
+                    debug.println("RevocationChecker.check() " + x.getMessage());
+                }
+                if (x.getReason() == BasicReason.REVOKED) {
+                    throw x;
+                }
+                if (cause != null) {
+                    if (softFail && cause instanceof NetworkFailureException) {
+                        return;
+                    } else {
+                        cause.addSuppressed(x);
+                        throw cause;
+                    }
+                }
+                if (softFail && x instanceof NetworkFailureException) {
+                    return;
+                }
+                throw x;
+            }
+        }
+    }
+
+    private void updateState(X509Certificate cert)
+        throws CertPathValidatorException
+    {
+        issuerInfo = new OCSPResponse.IssuerInfo(anchor, cert);
+
+        // Make new public key if parameters are missing
+        PublicKey pubKey = cert.getPublicKey();
+        if (pubKey instanceof DSAPublicKey &&
+            ((DSAPublicKey)pubKey).getParams() == null) {
+            // pubKey needs to inherit DSA parameters from prev key
+            pubKey = BasicChecker.makeInheritedParamsKey(pubKey, prevPubKey);
+        }
+        prevPubKey = pubKey;
+        crlSignFlag = certCanSignCrl(cert);
+    }
+
+    // Maximum clock skew in milliseconds (15 minutes) allowed when checking
+    // validity of CRLs
+    private static final long MAX_CLOCK_SKEW = 900000;
+    private void checkCRLs(X509Certificate cert,
+                           Collection<String> unresolvedCritExts,
+                           Set<X509Certificate> stackedCerts,
+                           PublicKey pubKey, boolean signFlag)
+        throws CertPathValidatorException
+    {
+        checkCRLs(cert, pubKey, null, signFlag, true,
+                  stackedCerts, params.trustAnchors());
+    }
+
+    static boolean isCausedByNetworkIssue(String type, CertStoreException cse) {
+        boolean result;
+        Throwable t = cse.getCause();
+
+        switch (type) {
+            case "LDAP":
+                if (t != null) {
+                    // These two exception classes are inside java.naming module
+                    String cn = t.getClass().getName();
+                    result = (cn.equals("javax.naming.ServiceUnavailableException") ||
+                        cn.equals("javax.naming.CommunicationException"));
+                } else {
+                    result = false;
+                }
+                break;
+            case "SSLServer":
+                result = (t != null && t instanceof IOException);
+                break;
+            case "URI":
+                result = (t != null && t instanceof IOException);
+                break;
+            default:
+                // we don't know about any other remote CertStore types
+                return false;
+        }
+        return result;
+    }
+
+    private void checkCRLs(X509Certificate cert, PublicKey prevKey,
+                           X509Certificate prevCert, boolean signFlag,
+                           boolean allowSeparateKey,
+                           Set<X509Certificate> stackedCerts,
+                           Set<TrustAnchor> anchors)
+        throws CertPathValidatorException
+    {
+        if (debug != null) {
+            debug.println("RevocationChecker.checkCRLs()" +
+                          " ---checking revocation status ...");
+        }
+
+        // Reject circular dependencies - RFC 5280 is not explicit on how
+        // to handle this, but does suggest that they can be a security
+        // risk and can create unresolvable dependencies
+        if (stackedCerts != null && stackedCerts.contains(cert)) {
+            if (debug != null) {
+                debug.println("RevocationChecker.checkCRLs()" +
+                              " circular dependency");
+            }
+            throw new CertPathValidatorException
+                ("Could not determine revocation status", null, null, -1,
+                 BasicReason.UNDETERMINED_REVOCATION_STATUS);
+        }
+
+        Set<X509CRL> possibleCRLs = new HashSet<>();
+        Set<X509CRL> approvedCRLs = new HashSet<>();
+        X509CRLSelector sel = new X509CRLSelector();
+        sel.setCertificateChecking(cert);
+        CertPathHelper.setDateAndTime(sel, params.date(), MAX_CLOCK_SKEW);
+
+        // First, check user-specified CertStores
+        NetworkFailureException nfe = null;
+        for (CertStore store : certStores) {
+            try {
+                for (CRL crl : store.getCRLs(sel)) {
+                    possibleCRLs.add((X509CRL)crl);
+                }
+            } catch (CertStoreException e) {
+                if (debug != null) {
+                    debug.println("RevocationChecker.checkCRLs() " +
+                                  "CertStoreException: " + e.getMessage());
+                }
+                if (softFail && nfe == null &&
+                    isCausedByNetworkIssue(store.getType(),e)) {
+                    // save this exception, we may need to throw it later
+                    nfe = new NetworkFailureException(e);
+                }
+            }
+        }
+
+        if (debug != null) {
+            debug.println("RevocationChecker.checkCRLs() " +
+                          "possible crls.size() = " + possibleCRLs.size());
+        }
+        boolean[] reasonsMask = new boolean[9];
+        if (!possibleCRLs.isEmpty()) {
+            // Now that we have a list of possible CRLs, see which ones can
+            // be approved
+            approvedCRLs.addAll(verifyPossibleCRLs(possibleCRLs, cert, prevKey,
+                                                   signFlag, reasonsMask,
+                                                   anchors));
+        }
+
+        if (debug != null) {
+            debug.println("RevocationChecker.checkCRLs() " +
+                          "approved crls.size() = " + approvedCRLs.size());
+        }
+
+        // make sure that we have at least one CRL that _could_ cover
+        // the certificate in question and all reasons are covered
+        if (!approvedCRLs.isEmpty() &&
+            Arrays.equals(reasonsMask, ALL_REASONS))
+        {
+            checkApprovedCRLs(cert, approvedCRLs);
+        } else {
+            // Check Distribution Points
+            // all CRLs returned by the DP Fetcher have also been verified
+            try {
+                if (crlDP) {
+                    approvedCRLs.addAll(DistributionPointFetcher.getCRLs(
+                            sel, signFlag, prevKey, prevCert,
+                            params.sigProvider(), certStores, reasonsMask,
+                            anchors, null, params.variant()));
+                }
+            } catch (CertStoreException e) {
+                if (softFail && e instanceof CertStoreTypeException) {
+                    CertStoreTypeException cste = (CertStoreTypeException)e;
+                    if (isCausedByNetworkIssue(cste.getType(), e)) {
+                        throw new NetworkFailureException(e);
+                    }
+                }
+                throw new CertPathValidatorException(e);
+            }
+            if (!approvedCRLs.isEmpty() &&
+                Arrays.equals(reasonsMask, ALL_REASONS))
+            {
+                checkApprovedCRLs(cert, approvedCRLs);
+            } else {
+                if (allowSeparateKey) {
+                    try {
+                        verifyWithSeparateSigningKey(cert, prevKey, signFlag,
+                                                     stackedCerts);
+                        return;
+                    } catch (CertPathValidatorException cpve) {
+                        if (nfe != null) {
+                            // if a network issue previously prevented us from
+                            // retrieving a CRL from one of the user-specified
+                            // CertStores and SOFT_FAIL is enabled, throw it now
+                            // so it can be handled appropriately
+                            throw nfe;
+                        }
+                        throw cpve;
+                    }
+                } else {
+                    if (nfe != null) {
+                        // if a network issue previously prevented us from
+                        // retrieving a CRL from one of the user-specified
+                        // CertStores and SOFT_FAIL is enabled, throw it now
+                        // so it can be handled appropriately
+                        throw nfe;
+                    }
+                    throw new CertPathValidatorException
+                    ("Could not determine revocation status", null, null, -1,
+                     BasicReason.UNDETERMINED_REVOCATION_STATUS);
+                }
+            }
+        }
+    }
+
+    private void checkApprovedCRLs(X509Certificate cert,
+                                   Set<X509CRL> approvedCRLs)
+        throws CertPathValidatorException
+    {
+        // See if the cert is in the set of approved crls.
+        if (debug != null) {
+            BigInteger sn = cert.getSerialNumber();
+            debug.println("RevocationChecker.checkApprovedCRLs() " +
+                          "starting the final sweep...");
+            debug.println("RevocationChecker.checkApprovedCRLs()" +
+                          " cert SN: " + sn.toString());
+        }
+
+        CRLReason reasonCode = CRLReason.UNSPECIFIED;
+        X509CRLEntryImpl entry = null;
+        for (X509CRL crl : approvedCRLs) {
+            X509CRLEntry e = crl.getRevokedCertificate(cert);
+            if (e != null) {
+                try {
+                    entry = X509CRLEntryImpl.toImpl(e);
+                } catch (CRLException ce) {
+                    throw new CertPathValidatorException(ce);
+                }
+                if (debug != null) {
+                    debug.println("RevocationChecker.checkApprovedCRLs()"
+                        + " CRL entry: " + entry.toString());
+                }
+
+                /*
+                 * Abort CRL validation and throw exception if there are any
+                 * unrecognized critical CRL entry extensions (see section
+                 * 5.3 of RFC 5280).
+                 */
+                Set<String> unresCritExts = entry.getCriticalExtensionOIDs();
+                if (unresCritExts != null && !unresCritExts.isEmpty()) {
+                    /* remove any that we will process */
+                    unresCritExts.remove(ReasonCode_Id.toString());
+                    unresCritExts.remove(CertificateIssuer_Id.toString());
+                    if (!unresCritExts.isEmpty()) {
+                        if (debug != null) {
+                            debug.println("Unrecognized "
+                            + "critical extension(s) in revoked CRL entry: "
+                            + unresCritExts);
+                        }
+                        throw new CertPathValidatorException
+                        ("Could not determine revocation status", null, null,
+                         -1, BasicReason.UNDETERMINED_REVOCATION_STATUS);
+                    }
+                }
+
+                reasonCode = entry.getRevocationReason();
+                if (reasonCode == null) {
+                    reasonCode = CRLReason.UNSPECIFIED;
+                }
+                Throwable t = new CertificateRevokedException
+                    (entry.getRevocationDate(), reasonCode,
+                     crl.getIssuerX500Principal(), entry.getExtensions());
+                throw new CertPathValidatorException(t.getMessage(), t,
+                    null, -1, BasicReason.REVOKED);
+            }
+        }
+    }
+
+    private void checkOCSP(X509Certificate cert,
+                           Collection<String> unresolvedCritExts)
+        throws CertPathValidatorException
+    {
+        X509CertImpl currCert = null;
+        try {
+            currCert = X509CertImpl.toImpl(cert);
+        } catch (CertificateException ce) {
+            throw new CertPathValidatorException(ce);
+        }
+
+        URI responderURI = (this.responderURI != null)
+                           ? this.responderURI : getOCSPServerURI(currCert);
+
+        // The algorithm constraints of the OCSP trusted responder certificate
+        // does not need to be checked in this code. The constraints will be
+        // checked when the responder's certificate is validated.
+
+        OCSPResponse response = null;
+        CertId certId = null;
+        try {
+            certId = new CertId(issuerInfo.getName(), issuerInfo.getPublicKey(),
+                    currCert.getSerialNumberObject());
+
+            // check if there is a stapled OCSP response available
+            byte[] responseBytes = ocspStapled.get(cert);
+            if (responseBytes != null) {
+                if (debug != null) {
+                    debug.println("Found stapled OCSP response");
+                }
+                response = new OCSPResponse(responseBytes);
+
+                // verify the response
+                byte[] nonce = null;
+                for (Extension ext : ocspExtensions) {
+                    if (ext.getId().equals("1.3.6.1.5.5.7.48.1.2")) {
+                        nonce = ext.getValue();
+                    }
+                }
+                response.verify(Collections.singletonList(certId), issuerInfo,
+                        responderCert, params.date(), nonce, params.variant());
+
+            } else {
+                response = OCSP.check(Collections.singletonList(certId),
+                        responderURI, issuerInfo, responderCert, null,
+                        ocspExtensions, params.variant());
+            }
+        } catch (IOException e) {
+            throw new CertPathValidatorException(e);
+        }
+
+        RevocationStatus rs =
+            (RevocationStatus)response.getSingleResponse(certId);
+        RevocationStatus.CertStatus certStatus = rs.getCertStatus();
+        if (certStatus == RevocationStatus.CertStatus.REVOKED) {
+            Throwable t = new CertificateRevokedException(
+                rs.getRevocationTime(), rs.getRevocationReason(),
+                response.getSignerCertificate().getSubjectX500Principal(),
+                rs.getSingleExtensions());
+            throw new CertPathValidatorException(t.getMessage(), t, null,
+                                                 -1, BasicReason.REVOKED);
+        } else if (certStatus == RevocationStatus.CertStatus.UNKNOWN) {
+            throw new CertPathValidatorException(
+                "Certificate's revocation status is unknown", null,
+                params.certPath(), -1,
+                BasicReason.UNDETERMINED_REVOCATION_STATUS);
+        }
+    }
+
+    /*
+     * Removes any non-hexadecimal characters from a string.
+     */
+    private static final String HEX_DIGITS = "0123456789ABCDEFabcdef";
+    private static String stripOutSeparators(String value) {
+        char[] chars = value.toCharArray();
+        StringBuilder hexNumber = new StringBuilder();
+        for (int i = 0; i < chars.length; i++) {
+            if (HEX_DIGITS.indexOf(chars[i]) != -1) {
+                hexNumber.append(chars[i]);
+            }
+        }
+        return hexNumber.toString();
+    }
+
+    private static URI getOCSPServerURI(X509CertImpl cert)
+        throws CertPathValidatorException
+    {
+        // Examine the certificate's AuthorityInfoAccess extension
+        AuthorityInfoAccessExtension aia =
+            cert.getAuthorityInfoAccessExtension();
+        if (aia == null) {
+            throw new CertPathValidatorException(
+                "Must specify the location of an OCSP Responder");
+        }
+
+        List<AccessDescription> descriptions = aia.getAccessDescriptions();
+        for (AccessDescription description : descriptions) {
+            if (description.getAccessMethod().equals((Object)
+                AccessDescription.Ad_OCSP_Id)) {
+
+                GeneralName generalName = description.getAccessLocation();
+                if (generalName.getType() == GeneralNameInterface.NAME_URI) {
+                    URIName uri = (URIName)generalName.getName();
+                    return uri.getURI();
+                }
+            }
+        }
+
+        throw new CertPathValidatorException(
+            "Cannot find the location of the OCSP Responder");
+    }
+
+    /**
+     * Checks that a cert can be used to verify a CRL.
+     *
+     * @param cert an X509Certificate to check
+     * @return a boolean specifying if the cert is allowed to vouch for the
+     *         validity of a CRL
+     */
+    static boolean certCanSignCrl(X509Certificate cert) {
+        // if the cert doesn't include the key usage ext, or
+        // the key usage ext asserts cRLSigning, return true,
+        // otherwise return false.
+        boolean[] keyUsage = cert.getKeyUsage();
+        if (keyUsage != null) {
+            return keyUsage[6];
+        }
+        return false;
+    }
+
+    /**
+     * Internal method that verifies a set of possible_crls,
+     * and sees if each is approved, based on the cert.
+     *
+     * @param crls a set of possible CRLs to test for acceptability
+     * @param cert the certificate whose revocation status is being checked
+     * @param signFlag <code>true</code> if prevKey was trusted to sign CRLs
+     * @param prevKey the public key of the issuer of cert
+     * @param reasonsMask the reason code mask
+     * @param trustAnchors a <code>Set</code> of <code>TrustAnchor</code>s>
+     * @return a collection of approved crls (or an empty collection)
+     */
+    private static final boolean[] ALL_REASONS =
+        {true, true, true, true, true, true, true, true, true};
+    private Collection<X509CRL> verifyPossibleCRLs(Set<X509CRL> crls,
+                                                   X509Certificate cert,
+                                                   PublicKey prevKey,
+                                                   boolean signFlag,
+                                                   boolean[] reasonsMask,
+                                                   Set<TrustAnchor> anchors)
+        throws CertPathValidatorException
+    {
+        try {
+            X509CertImpl certImpl = X509CertImpl.toImpl(cert);
+            if (debug != null) {
+                debug.println("RevocationChecker.verifyPossibleCRLs: " +
+                              "Checking CRLDPs for "
+                              + certImpl.getSubjectX500Principal());
+            }
+            CRLDistributionPointsExtension ext =
+                certImpl.getCRLDistributionPointsExtension();
+            List<DistributionPoint> points = null;
+            if (ext == null) {
+                // assume a DP with reasons and CRLIssuer fields omitted
+                // and a DP name of the cert issuer.
+                // TODO add issuerAltName too
+                X500Name certIssuer = (X500Name)certImpl.getIssuerDN();
+                DistributionPoint point = new DistributionPoint(
+                     new GeneralNames().add(new GeneralName(certIssuer)),
+                     null, null);
+                points = Collections.singletonList(point);
+            } else {
+                points = ext.get(CRLDistributionPointsExtension.POINTS);
+            }
+            Set<X509CRL> results = new HashSet<>();
+            for (DistributionPoint point : points) {
+                for (X509CRL crl : crls) {
+                    if (DistributionPointFetcher.verifyCRL(
+                            certImpl, point, crl, reasonsMask, signFlag,
+                            prevKey, null, params.sigProvider(), anchors,
+                            certStores, params.date(), params.variant()))
+                    {
+                        results.add(crl);
+                    }
+                }
+                if (Arrays.equals(reasonsMask, ALL_REASONS))
+                    break;
+            }
+            return results;
+        } catch (CertificateException | CRLException | IOException e) {
+            if (debug != null) {
+                debug.println("Exception while verifying CRL: "+e.getMessage());
+                e.printStackTrace();
+            }
+            return Collections.emptySet();
+        }
+    }
+
+    /**
+     * We have a cert whose revocation status couldn't be verified by
+     * a CRL issued by the cert that issued the CRL. See if we can
+     * find a valid CRL issued by a separate key that can verify the
+     * revocation status of this certificate.
+     * <p>
+     * Note that this does not provide support for indirect CRLs,
+     * only CRLs signed with a different key (but the same issuer
+     * name) as the certificate being checked.
+     *
+     * @param currCert the <code>X509Certificate</code> to be checked
+     * @param prevKey the <code>PublicKey</code> that failed
+     * @param signFlag <code>true</code> if that key was trusted to sign CRLs
+     * @param stackedCerts a <code>Set</code> of <code>X509Certificate</code>s>
+     *                     whose revocation status depends on the
+     *                     non-revoked status of this cert. To avoid
+     *                     circular dependencies, we assume they're
+     *                     revoked while checking the revocation
+     *                     status of this cert.
+     * @throws CertPathValidatorException if the cert's revocation status
+     *         cannot be verified successfully with another key
+     */
+    private void verifyWithSeparateSigningKey(X509Certificate cert,
+                                              PublicKey prevKey,
+                                              boolean signFlag,
+                                              Set<X509Certificate> stackedCerts)
+        throws CertPathValidatorException
+    {
+        String msg = "revocation status";
+        if (debug != null) {
+            debug.println(
+                "RevocationChecker.verifyWithSeparateSigningKey()" +
+                " ---checking " + msg + "...");
+        }
+
+        // Reject circular dependencies - RFC 5280 is not explicit on how
+        // to handle this, but does suggest that they can be a security
+        // risk and can create unresolvable dependencies
+        if ((stackedCerts != null) && stackedCerts.contains(cert)) {
+            if (debug != null) {
+                debug.println(
+                    "RevocationChecker.verifyWithSeparateSigningKey()" +
+                    " circular dependency");
+            }
+            throw new CertPathValidatorException
+                ("Could not determine revocation status", null, null,
+                 -1, BasicReason.UNDETERMINED_REVOCATION_STATUS);
+        }
+
+        // Try to find another key that might be able to sign
+        // CRLs vouching for this cert.
+        // If prevKey wasn't trusted, maybe we just didn't have the right
+        // path to it. Don't rule that key out.
+        if (!signFlag) {
+            buildToNewKey(cert, null, stackedCerts);
+        } else {
+            buildToNewKey(cert, prevKey, stackedCerts);
+        }
+    }
+
+    /**
+     * Tries to find a CertPath that establishes a key that can be
+     * used to verify the revocation status of a given certificate.
+     * Ignores keys that have previously been tried. Throws a
+     * CertPathValidatorException if no such key could be found.
+     *
+     * @param currCert the <code>X509Certificate</code> to be checked
+     * @param prevKey the <code>PublicKey</code> of the certificate whose key
+     *    cannot be used to vouch for the CRL and should be ignored
+     * @param stackedCerts a <code>Set</code> of <code>X509Certificate</code>s>
+     *                     whose revocation status depends on the
+     *                     establishment of this path.
+     * @throws CertPathValidatorException on failure
+     */
+    private static final boolean [] CRL_SIGN_USAGE =
+        { false, false, false, false, false, false, true };
+    private void buildToNewKey(X509Certificate currCert,
+                               PublicKey prevKey,
+                               Set<X509Certificate> stackedCerts)
+        throws CertPathValidatorException
+    {
+
+        if (debug != null) {
+            debug.println("RevocationChecker.buildToNewKey()" +
+                          " starting work");
+        }
+        Set<PublicKey> badKeys = new HashSet<>();
+        if (prevKey != null) {
+            badKeys.add(prevKey);
+        }
+        X509CertSelector certSel = new RejectKeySelector(badKeys);
+        certSel.setSubject(currCert.getIssuerX500Principal());
+        certSel.setKeyUsage(CRL_SIGN_USAGE);
+
+        Set<TrustAnchor> newAnchors = anchor == null ?
+                                      params.trustAnchors() :
+                                      Collections.singleton(anchor);
+
+        PKIXBuilderParameters builderParams;
+        try {
+            builderParams = new PKIXBuilderParameters(newAnchors, certSel);
+        } catch (InvalidAlgorithmParameterException iape) {
+            throw new RuntimeException(iape); // should never occur
+        }
+        builderParams.setInitialPolicies(params.initialPolicies());
+        builderParams.setCertStores(certStores);
+        builderParams.setExplicitPolicyRequired
+            (params.explicitPolicyRequired());
+        builderParams.setPolicyMappingInhibited
+            (params.policyMappingInhibited());
+        builderParams.setAnyPolicyInhibited(params.anyPolicyInhibited());
+        // Policy qualifiers must be rejected, since we don't have
+        // any way to convey them back to the application.
+        // That's the default, so no need to write code.
+        builderParams.setDate(params.date());
+        // CertPathCheckers need to be cloned to start from fresh state
+        builderParams.setCertPathCheckers(
+            params.getPKIXParameters().getCertPathCheckers());
+        builderParams.setSigProvider(params.sigProvider());
+
+        // Skip revocation during this build to detect circular
+        // references. But check revocation afterwards, using the
+        // key (or any other that works).
+        builderParams.setRevocationEnabled(false);
+
+        // check for AuthorityInformationAccess extension
+        if (Builder.USE_AIA == true) {
+            X509CertImpl currCertImpl = null;
+            try {
+                currCertImpl = X509CertImpl.toImpl(currCert);
+            } catch (CertificateException ce) {
+                // ignore but log it
+                if (debug != null) {
+                    debug.println("RevocationChecker.buildToNewKey: " +
+                                  "error decoding cert: " + ce);
+                }
+            }
+            AuthorityInfoAccessExtension aiaExt = null;
+            if (currCertImpl != null) {
+                aiaExt = currCertImpl.getAuthorityInfoAccessExtension();
+            }
+            if (aiaExt != null) {
+                List<AccessDescription> adList = aiaExt.getAccessDescriptions();
+                if (adList != null) {
+                    for (AccessDescription ad : adList) {
+                        CertStore cs = URICertStore.getInstance(ad);
+                        if (cs != null) {
+                            if (debug != null) {
+                                debug.println("adding AIAext CertStore");
+                            }
+                            builderParams.addCertStore(cs);
+                        }
+                    }
+                }
+            }
+        }
+
+        CertPathBuilder builder = null;
+        try {
+            builder = CertPathBuilder.getInstance("PKIX");
+        } catch (NoSuchAlgorithmException nsae) {
+            throw new CertPathValidatorException(nsae);
+        }
+        while (true) {
+            try {
+                if (debug != null) {
+                    debug.println("RevocationChecker.buildToNewKey()" +
+                                  " about to try build ...");
+                }
+                PKIXCertPathBuilderResult cpbr =
+                    (PKIXCertPathBuilderResult)builder.build(builderParams);
+
+                if (debug != null) {
+                    debug.println("RevocationChecker.buildToNewKey()" +
+                                  " about to check revocation ...");
+                }
+                // Now check revocation of all certs in path, assuming that
+                // the stackedCerts are revoked.
+                if (stackedCerts == null) {
+                    stackedCerts = new HashSet<X509Certificate>();
+                }
+                stackedCerts.add(currCert);
+                TrustAnchor ta = cpbr.getTrustAnchor();
+                PublicKey prevKey2 = ta.getCAPublicKey();
+                if (prevKey2 == null) {
+                    prevKey2 = ta.getTrustedCert().getPublicKey();
+                }
+                boolean signFlag = true;
+                List<? extends Certificate> cpList =
+                    cpbr.getCertPath().getCertificates();
+                try {
+                    for (int i = cpList.size()-1; i >= 0; i-- ) {
+                        X509Certificate cert = (X509Certificate)cpList.get(i);
+
+                        if (debug != null) {
+                            debug.println("RevocationChecker.buildToNewKey()"
+                                          + " index " + i + " checking "
+                                          + cert);
+                        }
+                        checkCRLs(cert, prevKey2, null, signFlag, true,
+                                  stackedCerts, newAnchors);
+                        signFlag = certCanSignCrl(cert);
+                        prevKey2 = cert.getPublicKey();
+                    }
+                } catch (CertPathValidatorException cpve) {
+                    // ignore it and try to get another key
+                    badKeys.add(cpbr.getPublicKey());
+                    continue;
+                }
+
+                if (debug != null) {
+                    debug.println("RevocationChecker.buildToNewKey()" +
+                                  " got key " + cpbr.getPublicKey());
+                }
+                // Now check revocation on the current cert using that key and
+                // the corresponding certificate.
+                // If it doesn't check out, try to find a different key.
+                // And if we can't find a key, then return false.
+                PublicKey newKey = cpbr.getPublicKey();
+                try {
+                    checkCRLs(currCert, newKey, (X509Certificate) cpList.get(0),
+                              true, false, null, params.trustAnchors());
+                    // If that passed, the cert is OK!
+                    return;
+                } catch (CertPathValidatorException cpve) {
+                    // If it is revoked, rethrow exception
+                    if (cpve.getReason() == BasicReason.REVOKED) {
+                        throw cpve;
+                    }
+                    // Otherwise, ignore the exception and
+                    // try to get another key.
+                }
+                badKeys.add(newKey);
+            } catch (InvalidAlgorithmParameterException iape) {
+                throw new CertPathValidatorException(iape);
+            } catch (CertPathBuilderException cpbe) {
+                throw new CertPathValidatorException
+                    ("Could not determine revocation status", null, null,
+                     -1, BasicReason.UNDETERMINED_REVOCATION_STATUS);
+            }
+        }
+    }
+
+    /*
+     * This inner class extends the X509CertSelector to add an additional
+     * check to make sure the subject public key isn't on a particular list.
+     * This class is used by buildToNewKey() to make sure the builder doesn't
+     * end up with a CertPath to a public key that has already been rejected.
+     */
+    private static class RejectKeySelector extends X509CertSelector {
+        private final Set<PublicKey> badKeySet;
+
+        /**
+         * Creates a new <code>RejectKeySelector</code>.
+         *
+         * @param badPublicKeys a <code>Set</code> of
+         *                      <code>PublicKey</code>s that
+         *                      should be rejected (or <code>null</code>
+         *                      if no such check should be done)
+         */
+        RejectKeySelector(Set<PublicKey> badPublicKeys) {
+            this.badKeySet = badPublicKeys;
+        }
+
+        /**
+         * Decides whether a <code>Certificate</code> should be selected.
+         *
+         * @param cert the <code>Certificate</code> to be checked
+         * @return <code>true</code> if the <code>Certificate</code> should be
+         *         selected, <code>false</code> otherwise
+         */
+        @Override
+        public boolean match(Certificate cert) {
+            if (!super.match(cert))
+                return(false);
+
+            if (badKeySet.contains(cert.getPublicKey())) {
+                if (debug != null)
+                    debug.println("RejectKeySelector.match: bad key");
+                return false;
+            }
+
+            if (debug != null)
+                debug.println("RejectKeySelector.match: returning true");
+            return true;
+        }
+
+        /**
+         * Return a printable representation of the <code>CertSelector</code>.
+         *
+         * @return a <code>String</code> describing the contents of the
+         *         <code>CertSelector</code>
+         */
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append("RejectKeySelector: [\n");
+            sb.append(super.toString());
+            sb.append(badKeySet);
+            sb.append("]");
+            return sb.toString();
+        }
+    }
+}
--- a/src/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2017, 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
@@ -26,18 +26,16 @@
 package sun.security.provider.certpath;
 
 import java.io.IOException;
-import java.security.AccessController;
 import java.security.GeneralSecurityException;
 import java.security.InvalidAlgorithmParameterException;
-import java.security.Principal;
 import java.security.PublicKey;
 import java.security.cert.*;
+import java.security.cert.CertPathValidatorException.BasicReason;
 import java.security.cert.PKIXReason;
 import java.security.interfaces.DSAPublicKey;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -45,19 +43,18 @@
 import java.util.Set;
 import javax.security.auth.x500.X500Principal;
 
-import sun.security.action.GetBooleanSecurityPropertyAction;
-import sun.security.x509.X500Name;
-import sun.security.x509.PKIXExtensions;
+import sun.security.provider.certpath.PKIX.BuilderParams;
+import static sun.security.x509.PKIXExtensions.*;
 import sun.security.util.Debug;
 
 /**
  * This class is able to build certification paths in either the forward
  * or reverse directions.
  *
- * <p> If successful, it returns a certification path which has succesfully
+ * <p> If successful, it returns a certification path which has successfully
  * satisfied all the constraints and requirements specified in the
  * PKIXBuilderParameters object and has been validated according to the PKIX
- * path validation algorithm defined in RFC 3280.
+ * path validation algorithm defined in RFC 5280.
  *
  * <p> This implementation uses a depth-first search approach to finding
  * certification paths. If it comes to a point in which it cannot find
@@ -78,16 +75,12 @@
     /*
      * private objects shared by methods
      */
-    private PKIXBuilderParameters buildParams;
+    private BuilderParams buildParams;
     private CertificateFactory cf;
     private boolean pathCompleted = false;
-    private X500Principal targetSubjectDN;
     private PolicyNode policyTreeResult;
     private TrustAnchor trustAnchor;
     private PublicKey finalPublicKey;
-    private X509CertSelector targetSel;
-    private List<CertStore> orderedCertStores;
-    private boolean onlyEECert = false;
 
     /**
      * Create an instance of <code>SunCertPathBuilder</code>.
@@ -100,9 +93,10 @@
         } catch (CertificateException e) {
             throw new CertPathBuilderException(e);
         }
-        onlyEECert = AccessController.doPrivileged(
-            new GetBooleanSecurityPropertyAction
-                ("com.sun.security.onlyCheckRevocationOfEECert"));
+    }
+
+    public CertPathChecker engineGetRevocationChecker() {
+        return new RevocationChecker();
     }
 
     /**
@@ -125,6 +119,7 @@
      * @throws InvalidAlgorithmParameterException if the given parameters are
      *  inappropriate for this certification path builder.
      */
+    @Override
     public CertPathBuilderResult engineBuild(CertPathParameters params)
         throws CertPathBuilderException, InvalidAlgorithmParameterException {
 
@@ -132,66 +127,20 @@
             debug.println("SunCertPathBuilder.engineBuild(" + params + ")");
         }
 
-        if (!(params instanceof PKIXBuilderParameters)) {
-            throw new InvalidAlgorithmParameterException("inappropriate " +
-                "parameter type, must be an instance of PKIXBuilderParameters");
-        }
-
-        boolean buildForward = true;
-        if (params instanceof SunCertPathBuilderParameters) {
-            buildForward =
-                ((SunCertPathBuilderParameters)params).getBuildForward();
-        }
-
-        buildParams = (PKIXBuilderParameters)params;
-
-        /* Check mandatory parameters */
-
-        // Make sure that none of the trust anchors include name constraints
-        // (not supported).
-        for (TrustAnchor anchor : buildParams.getTrustAnchors()) {
-            if (anchor.getNameConstraints() != null) {
-                throw new InvalidAlgorithmParameterException
-                    ("name constraints in trust anchor not supported");
-            }
-        }
+        buildParams = PKIX.checkBuilderParams(params);
+        return build();
+    }
 
-        CertSelector sel = buildParams.getTargetCertConstraints();
-        if (!(sel instanceof X509CertSelector)) {
-            throw new InvalidAlgorithmParameterException("the "
-                + "targetCertConstraints parameter must be an "
-                + "X509CertSelector");
-        }
-        targetSel = (X509CertSelector)sel;
-        targetSubjectDN = targetSel.getSubject();
-        if (targetSubjectDN == null) {
-            X509Certificate targetCert = targetSel.getCertificate();
-            if (targetCert != null) {
-                targetSubjectDN = targetCert.getSubjectX500Principal();
-            }
-        }
-        // reorder CertStores so that local CertStores are tried first
-        orderedCertStores =
-            new ArrayList<CertStore>(buildParams.getCertStores());
-        Collections.sort(orderedCertStores, new CertStoreComparator());
-        if (targetSubjectDN == null) {
-            targetSubjectDN = getTargetSubjectDN(orderedCertStores, targetSel);
-        }
-        if (targetSubjectDN == null) {
-            throw new InvalidAlgorithmParameterException
-                ("Could not determine unique target subject");
-        }
-
-        List<List<Vertex>> adjList = new ArrayList<List<Vertex>>();
-        CertPathBuilderResult result =
-            buildCertPath(buildForward, false, adjList);
+    private PKIXCertPathBuilderResult build() throws CertPathBuilderException {
+        List<List<Vertex>> adjList = new ArrayList<>();
+        PKIXCertPathBuilderResult result = buildCertPath(false, adjList);
         if (result == null) {
             if (debug != null) {
                 debug.println("SunCertPathBuilder.engineBuild: 2nd pass");
             }
             // try again
             adjList.clear();
-            result = buildCertPath(buildForward, true, adjList);
+            result = buildCertPath(true, adjList);
             if (result == null) {
                 throw new SunCertPathBuilderException("unable to find valid "
                     + "certification path to requested target",
@@ -201,24 +150,23 @@
         return result;
     }
 
-    private CertPathBuilderResult buildCertPath(boolean buildForward,
-        boolean searchAllCertStores, List<List<Vertex>> adjList)
-        throws CertPathBuilderException {
-
+    private PKIXCertPathBuilderResult buildCertPath(boolean searchAllCertStores,
+                                                    List<List<Vertex>> adjList)
+        throws CertPathBuilderException
+    {
         // Init shared variables and build certification path
         pathCompleted = false;
         trustAnchor = null;
         finalPublicKey = null;
         policyTreeResult = null;
-        LinkedList<X509Certificate> certPathList =
-            new LinkedList<X509Certificate>();
+        LinkedList<X509Certificate> certPathList = new LinkedList<>();
         try {
-            if (buildForward) {
+            if (buildParams.buildForward()) {
                 buildForward(adjList, certPathList, searchAllCertStores);
             } else {
                 buildReverse(adjList, certPathList);
             }
-        } catch (Exception e) {
+        } catch (GeneralSecurityException | IOException e) {
             if (debug != null) {
                 debug.println("SunCertPathBuilder.engineBuild() exception in "
                     + "build");
@@ -242,11 +190,11 @@
                 Collections.reverse(certPathList);
 
                 return new SunCertPathBuilderResult(
-                    cf.generateCertPath(certPathList), this.trustAnchor,
+                    cf.generateCertPath(certPathList), trustAnchor,
                     policyTreeResult, finalPublicKey,
                     new AdjacencyList(adjList));
             }
-        } catch (Exception e) {
+        } catch (CertificateException e) {
             if (debug != null) {
                 debug.println("SunCertPathBuilder.engineBuild() exception "
                               + "in wrap-up");
@@ -264,12 +212,13 @@
      * Private build reverse method.
      */
     private void buildReverse(List<List<Vertex>> adjacencyList,
-        LinkedList<X509Certificate> certPathList) throws Exception
+                              LinkedList<X509Certificate> certPathList)
+        throws GeneralSecurityException, IOException
     {
         if (debug != null) {
             debug.println("SunCertPathBuilder.buildReverse()...");
             debug.println("SunCertPathBuilder.buildReverse() InitialPolicies: "
-                + buildParams.getInitialPolicies());
+                + buildParams.initialPolicies());
         }
 
         ReverseState currentState = new ReverseState();
@@ -281,12 +230,12 @@
          * Perform a search using each trust anchor, until a valid
          * path is found
          */
-        Iterator<TrustAnchor> iter = buildParams.getTrustAnchors().iterator();
+        Iterator<TrustAnchor> iter = buildParams.trustAnchors().iterator();
         while (iter.hasNext()) {
             TrustAnchor anchor = iter.next();
 
             /* check if anchor satisfies target constraints */
-            if (anchorIsTarget(anchor, targetSel)) {
+            if (anchorIsTarget(anchor, buildParams.targetCertConstraints())) {
                 this.trustAnchor = anchor;
                 this.pathCompleted = true;
                 this.finalPublicKey = anchor.getTrustedCert().getPublicKey();
@@ -294,22 +243,18 @@
             }
 
             /* Initialize current state */
-            currentState.initState(buildParams.getMaxPathLength(),
-                       buildParams.isExplicitPolicyRequired(),
-                       buildParams.isPolicyMappingInhibited(),
-                       buildParams.isAnyPolicyInhibited(),
-                       buildParams.getCertPathCheckers());
-            currentState.updateState(anchor);
-            // init the crl checker
-            currentState.crlChecker =
-                new CrlRevocationChecker(null, buildParams, null, onlyEECert);
-            currentState.algorithmChecker = new AlgorithmChecker(anchor);
+            currentState.initState(buildParams);
+            currentState.updateState(anchor, buildParams);
+
+            currentState.algorithmChecker = new AlgorithmChecker(anchor,
+                                                                 buildParams.date(),
+                                                                 null);
             currentState.untrustedChecker = new UntrustedChecker();
             try {
                 depthFirstSearchReverse(null, currentState,
-                new ReverseBuilder(buildParams, targetSubjectDN), adjacencyList,
-                certPathList);
-            } catch (Exception e) {
+                                        new ReverseBuilder(buildParams),
+                                        adjacencyList, certPathList);
+            } catch (GeneralSecurityException | IOException e) {
                 // continue on error if more anchors to try
                 if (iter.hasNext())
                     continue;
@@ -335,7 +280,8 @@
      * Private build forward method.
      */
     private void buildForward(List<List<Vertex>> adjacencyList,
-        LinkedList<X509Certificate> certPathList, boolean searchAllCertStores)
+                              LinkedList<X509Certificate> certPathList,
+                              boolean searchAllCertStores)
         throws GeneralSecurityException, IOException
     {
         if (debug != null) {
@@ -344,21 +290,18 @@
 
         /* Initialize current state */
         ForwardState currentState = new ForwardState();
-        currentState.initState(buildParams.getCertPathCheckers());
+        currentState.initState(buildParams.certPathCheckers());
 
         /* Initialize adjacency list */
         adjacencyList.clear();
         adjacencyList.add(new LinkedList<Vertex>());
 
-        // init the crl checker
-        currentState.crlChecker
-            = new CrlRevocationChecker(null, buildParams, null, onlyEECert);
         currentState.untrustedChecker = new UntrustedChecker();
+        depthFirstSearchForward(buildParams.targetSubject(), currentState,
+                                new ForwardBuilder(buildParams,
+                                                   searchAllCertStores),
+                                adjacencyList, certPathList);
 
-        depthFirstSearchForward(targetSubjectDN, currentState,
-          new ForwardBuilder
-              (buildParams, targetSubjectDN, searchAllCertStores, onlyEECert),
-          adjacencyList, certPathList);
     }
 
     /*
@@ -376,27 +319,28 @@
      * @param dN the distinguished name being currently searched for certs
      * @param currentState the current PKIX validation state
      */
-    void depthFirstSearchForward(X500Principal dN, ForwardState currentState,
-        ForwardBuilder builder, List<List<Vertex>> adjList,
-        LinkedList<X509Certificate> certPathList)
+    private void depthFirstSearchForward(X500Principal dN,
+                                         ForwardState currentState,
+                                         ForwardBuilder builder,
+                                         List<List<Vertex>> adjList,
+                                         LinkedList<X509Certificate> cpList)
         throws GeneralSecurityException, IOException
     {
-        //XXX This method should probably catch & handle exceptions
-
         if (debug != null) {
             debug.println("SunCertPathBuilder.depthFirstSearchForward(" + dN
-                + ", " + currentState.toString() + ")");
+                          + ", " + currentState.toString() + ")");
         }
 
         /*
          * Find all the certificates issued to dN which
          * satisfy the PKIX certification path constraints.
          */
-        List<Vertex> vertices = addVertices
-           (builder.getMatchingCerts(currentState, orderedCertStores), adjList);
+        Collection<X509Certificate> certs =
+            builder.getMatchingCerts(currentState, buildParams.certStores());
+        List<Vertex> vertices = addVertices(certs, adjList);
         if (debug != null) {
             debug.println("SunCertPathBuilder.depthFirstSearchForward(): "
-                + "certs.size=" + vertices.size());
+                          + "certs.size=" + vertices.size());
         }
 
         /*
@@ -416,14 +360,14 @@
              * the next matching cert is tried.
              */
             ForwardState nextState = (ForwardState) currentState.clone();
-            X509Certificate cert = (X509Certificate) vertex.getCertificate();
+            X509Certificate cert = vertex.getCertificate();
 
             try {
-                builder.verifyCert(cert, nextState, certPathList);
+                builder.verifyCert(cert, nextState, cpList);
             } catch (GeneralSecurityException gse) {
                 if (debug != null) {
                     debug.println("SunCertPathBuilder.depthFirstSearchForward()"
-                        + ": validation failed: " + gse);
+                                  + ": validation failed: " + gse);
                     gse.printStackTrace();
                 }
                 vertex.setThrowable(gse);
@@ -441,51 +385,45 @@
              */
             if (builder.isPathCompleted(cert)) {
 
-                BasicChecker basicChecker = null;
                 if (debug != null)
                     debug.println("SunCertPathBuilder.depthFirstSearchForward()"
-                        + ": commencing final verification");
+                                  + ": commencing final verification");
 
-                ArrayList<X509Certificate> appendedCerts =
-                    new ArrayList<X509Certificate>(certPathList);
+                List<X509Certificate> appendedCerts = new ArrayList<>(cpList);
 
                 /*
                  * if the trust anchor selected is specified as a trusted
                  * public key rather than a trusted cert, then verify this
                  * cert (which is signed by the trusted public key), but
-                 * don't add it yet to the certPathList
+                 * don't add it yet to the cpList
                  */
                 if (builder.trustAnchor.getTrustedCert() == null) {
                     appendedCerts.add(0, cert);
                 }
 
-                HashSet<String> initExpPolSet = new HashSet<String>(1);
-                initExpPolSet.add(PolicyChecker.ANY_POLICY);
+                Set<String> initExpPolSet =
+                    Collections.singleton(PolicyChecker.ANY_POLICY);
 
                 PolicyNodeImpl rootNode = new PolicyNodeImpl(null,
                     PolicyChecker.ANY_POLICY, null, false, initExpPolSet, false);
 
+                List<PKIXCertPathChecker> checkers = new ArrayList<>();
                 PolicyChecker policyChecker
-                    = new PolicyChecker(buildParams.getInitialPolicies(),
-                                appendedCerts.size(),
-                                buildParams.isExplicitPolicyRequired(),
-                                buildParams.isPolicyMappingInhibited(),
-                                buildParams.isAnyPolicyInhibited(),
-                                buildParams.getPolicyQualifiersRejected(),
-                                rootNode);
+                    = new PolicyChecker(buildParams.initialPolicies(),
+                                        appendedCerts.size(),
+                                        buildParams.explicitPolicyRequired(),
+                                        buildParams.policyMappingInhibited(),
+                                        buildParams.anyPolicyInhibited(),
+                                        buildParams.policyQualifiersRejected(),
+                                        rootNode);
 
-                List<PKIXCertPathChecker> userCheckers = new
-                    ArrayList<PKIXCertPathChecker>
-                        (buildParams.getCertPathCheckers());
-                int mustCheck = 0;
-                userCheckers.add(mustCheck, policyChecker);
-                mustCheck++;
+                checkers.add(policyChecker);
 
                 // add the algorithm checker
-                userCheckers.add(mustCheck,
-                        new AlgorithmChecker(builder.trustAnchor));
-                mustCheck++;
+                checkers.add(new AlgorithmChecker(builder.trustAnchor,
+                        buildParams.date(), null));
 
+                BasicChecker basicChecker = null;
                 if (nextState.keyParamsNeeded()) {
                     PublicKey rootKey = cert.getPublicKey();
                     if (builder.trustAnchor.getTrustedCert() == null) {
@@ -500,24 +438,38 @@
                         (cert.getSubjectX500Principal(), rootKey, null);
 
                     // add the basic checker
-                    basicChecker = new BasicChecker(anchor,
-                                           builder.date,
-                                           buildParams.getSigProvider(),
-                                           true);
-                    userCheckers.add(mustCheck, basicChecker);
-                    mustCheck++;
+                    basicChecker = new BasicChecker(anchor, buildParams.date(),
+                                                    buildParams.sigProvider(),
+                                                    true);
+                    checkers.add(basicChecker);
+                }
+
+                buildParams.setCertPath(cf.generateCertPath(appendedCerts));
 
-                    // add the crl revocation checker
-                    if (buildParams.isRevocationEnabled()) {
-                        userCheckers.add(mustCheck, new CrlRevocationChecker
-                            (anchor, buildParams, null, onlyEECert));
-                        mustCheck++;
+                boolean revCheckerAdded = false;
+                List<PKIXCertPathChecker> ckrs = buildParams.certPathCheckers();
+                for (PKIXCertPathChecker ckr : ckrs) {
+                    if (ckr instanceof PKIXRevocationChecker) {
+                        revCheckerAdded = true;
+                        // if it's our own, initialize it
+                        if (ckr instanceof RevocationChecker)
+                            ((RevocationChecker)ckr).init(builder.trustAnchor,
+                                                          buildParams);
                     }
                 }
-                // Why we don't need BasicChecker and CrlRevocationChecker
+                // only add a RevocationChecker if revocation is enabled and
+                // a PKIXRevocationChecker has not already been added
+                if (buildParams.revocationEnabled() && !revCheckerAdded) {
+                    checkers.add(new RevocationChecker(builder.trustAnchor,
+                                                       buildParams));
+                }
+
+                checkers.addAll(ckrs);
+
+                // Why we don't need BasicChecker and RevocationChecker
                 // if nextState.keyParamsNeeded() is false?
 
-                for (int i=0; i<appendedCerts.size(); i++) {
+                for (int i = 0; i < appendedCerts.size(); i++) {
                     X509Certificate currCert = appendedCerts.get(i);
                     if (debug != null)
                         debug.println("current subject = "
@@ -528,18 +480,15 @@
                         unresCritExts = Collections.<String>emptySet();
                     }
 
-                    for (int j=0; j<userCheckers.size(); j++) {
-                        PKIXCertPathChecker currChecker = userCheckers.get(j);
-                        if (j < mustCheck ||
-                            !currChecker.isForwardCheckingSupported()) {
+                    for (PKIXCertPathChecker currChecker : checkers) {
+                        if (!currChecker.isForwardCheckingSupported()) {
                             if (i == 0) {
                                 currChecker.init(false);
 
                                 // The user specified
                                 // AlgorithmChecker may not be
                                 // able to set the trust anchor until now.
-                                if (j >= mustCheck &&
-                                    currChecker instanceof AlgorithmChecker) {
+                                if (currChecker instanceof AlgorithmChecker) {
                                     ((AlgorithmChecker)currChecker).
                                         trySetTrustAnchor(builder.trustAnchor);
                                 }
@@ -552,6 +501,12 @@
                                     debug.println
                                     ("SunCertPathBuilder.depthFirstSearchForward(): " +
                                     "final verification failed: " + cpve);
+                                // If the target cert itself is revoked, we
+                                // cannot trust it. We can bail out here.
+                                if (buildParams.targetCertConstraints().match(currCert)
+                                        && cpve.getReason() == BasicReason.REVOKED) {
+                                    throw cpve;
+                                }
                                 vertex.setThrowable(cpve);
                                 continue vertices;
                             }
@@ -565,7 +520,7 @@
                      * are capable of processing.
                      */
                     for (PKIXCertPathChecker checker :
-                         buildParams.getCertPathCheckers())
+                         buildParams.certPathCheckers())
                     {
                         if (checker.isForwardCheckingSupported()) {
                             Set<String> suppExts =
@@ -577,24 +532,16 @@
                     }
 
                     if (!unresCritExts.isEmpty()) {
-                        unresCritExts.remove
-                            (PKIXExtensions.BasicConstraints_Id.toString());
-                        unresCritExts.remove
-                            (PKIXExtensions.NameConstraints_Id.toString());
-                        unresCritExts.remove
-                            (PKIXExtensions.CertificatePolicies_Id.toString());
-                        unresCritExts.remove
-                            (PKIXExtensions.PolicyMappings_Id.toString());
-                        unresCritExts.remove
-                            (PKIXExtensions.PolicyConstraints_Id.toString());
-                        unresCritExts.remove
-                            (PKIXExtensions.InhibitAnyPolicy_Id.toString());
-                        unresCritExts.remove(PKIXExtensions.
+                        unresCritExts.remove(BasicConstraints_Id.toString());
+                        unresCritExts.remove(NameConstraints_Id.toString());
+                        unresCritExts.remove(CertificatePolicies_Id.toString());
+                        unresCritExts.remove(PolicyMappings_Id.toString());
+                        unresCritExts.remove(PolicyConstraints_Id.toString());
+                        unresCritExts.remove(InhibitAnyPolicy_Id.toString());
+                        unresCritExts.remove(
                             SubjectAlternativeName_Id.toString());
-                        unresCritExts.remove
-                            (PKIXExtensions.KeyUsage_Id.toString());
-                        unresCritExts.remove
-                            (PKIXExtensions.ExtendedKeyUsage_Id.toString());
+                        unresCritExts.remove(KeyUsage_Id.toString());
+                        unresCritExts.remove(ExtendedKeyUsage_Id.toString());
 
                         if (!unresCritExts.isEmpty()) {
                             throw new CertPathValidatorException
@@ -611,10 +558,10 @@
                 /*
                  * if the user specified a trusted public key rather than
                  * trusted certs, then add this cert (which is signed by
-                 * the trusted public key) to the certPathList
+                 * the trusted public key) to the cpList
                  */
                 if (builder.trustAnchor.getTrustedCert() == null)
-                    builder.addCertToPath(cert, certPathList);
+                    builder.addCertToPath(cert, cpList);
                 // Save the trust anchor
                 this.trustAnchor = builder.trustAnchor;
 
@@ -625,10 +572,10 @@
                     finalPublicKey = basicChecker.getPublicKey();
                 } else {
                     Certificate finalCert;
-                    if (certPathList.size() == 0) {
+                    if (cpList.isEmpty()) {
                         finalCert = builder.trustAnchor.getTrustedCert();
                     } else {
-                        finalCert = certPathList.get(certPathList.size()-1);
+                        finalCert = cpList.getLast();
                     }
                     finalPublicKey = finalCert.getPublicKey();
                 }
@@ -636,7 +583,7 @@
                 policyTreeResult = policyChecker.getPolicyTree();
                 return;
             } else {
-                builder.addCertToPath(cert, certPathList);
+                builder.addCertToPath(cert, cpList);
             }
 
             /* Update the PKIX state */
@@ -650,8 +597,8 @@
             vertex.setIndex(adjList.size() - 1);
 
             /* recursively search for matching certs at next dN */
-            depthFirstSearchForward(cert.getIssuerX500Principal(),
-                                    nextState, builder, adjList, certPathList);
+            depthFirstSearchForward(cert.getIssuerX500Principal(), nextState,
+                                    builder, adjList, cpList);
 
             /*
              * If path has been completed, return ASAP!
@@ -667,8 +614,8 @@
                  */
                 if (debug != null)
                     debug.println("SunCertPathBuilder.depthFirstSearchForward()"
-                        + ": backtracking");
-                builder.removeFinalCertFromPath(certPathList);
+                                  + ": backtracking");
+                builder.removeFinalCertFromPath(cpList);
             }
         }
     }
@@ -688,9 +635,11 @@
      * @param dN the distinguished name being currently searched for certs
      * @param currentState the current PKIX validation state
      */
-    void depthFirstSearchReverse(X500Principal dN, ReverseState currentState,
-        ReverseBuilder builder, List<List<Vertex>> adjList,
-        LinkedList<X509Certificate> certPathList)
+    private void depthFirstSearchReverse(X500Principal dN,
+                                         ReverseState currentState,
+                                         ReverseBuilder builder,
+                                         List<List<Vertex>> adjList,
+                                         LinkedList<X509Certificate> cpList)
         throws GeneralSecurityException, IOException
     {
         if (debug != null)
@@ -701,8 +650,9 @@
          * Find all the certificates issued by dN which
          * satisfy the PKIX certification path constraints.
          */
-        List<Vertex> vertices = addVertices
-           (builder.getMatchingCerts(currentState, orderedCertStores), adjList);
+        Collection<X509Certificate> certs =
+            builder.getMatchingCerts(currentState, buildParams.certStores());
+        List<Vertex> vertices = addVertices(certs, adjList);
         if (debug != null)
             debug.println("SunCertPathBuilder.depthFirstSearchReverse(): "
                 + "certs.size=" + vertices.size());
@@ -722,9 +672,9 @@
              * the next matching cert is tried.
              */
             ReverseState nextState = (ReverseState) currentState.clone();
-            X509Certificate cert = (X509Certificate) vertex.getCertificate();
+            X509Certificate cert = vertex.getCertificate();
             try {
-                builder.verifyCert(cert, nextState, certPathList);
+                builder.verifyCert(cert, nextState, cpList);
             } catch (GeneralSecurityException gse) {
                 if (debug != null)
                     debug.println("SunCertPathBuilder.depthFirstSearchReverse()"
@@ -738,7 +688,7 @@
              * self-signed cert) and update state
              */
             if (!currentState.isInitial())
-                builder.addCertToPath(cert, certPathList);
+                builder.addCertToPath(cert, cpList);
             // save trust anchor
             this.trustAnchor = currentState.trustAnchor;
 
@@ -787,7 +737,7 @@
 
             /* recursively search for matching certs at next dN */
             depthFirstSearchReverse(cert.getSubjectX500Principal(), nextState,
-                builder, adjList, certPathList);
+                                    builder, adjList, cpList);
 
             /*
              * If path has been completed, return ASAP!
@@ -805,7 +755,7 @@
                     debug.println("SunCertPathBuilder.depthFirstSearchReverse()"
                         + ": backtracking");
                 if (!currentState.isInitial())
-                    builder.removeFinalCertFromPath(certPathList);
+                    builder.removeFinalCertFromPath(cpList);
             }
         }
         if (debug != null)
@@ -817,13 +767,14 @@
      * Adds a collection of matching certificates to the
      * adjacency list.
      */
-    private List<Vertex> addVertices(Collection<X509Certificate> certs,
-        List<List<Vertex>> adjList) {
+    private static List<Vertex> addVertices(Collection<X509Certificate> certs,
+                                            List<List<Vertex>> adjList)
+    {
         List<Vertex> l = adjList.get(adjList.size() - 1);
 
         for (X509Certificate cert : certs) {
-           Vertex v = new Vertex(cert);
-           l.add(v);
+            Vertex v = new Vertex(cert);
+            l.add(v);
         }
 
         return l;
@@ -833,53 +784,13 @@
      * Returns true if trust anchor certificate matches specified
      * certificate constraints.
      */
-    private boolean anchorIsTarget(TrustAnchor anchor, X509CertSelector sel) {
+    private static boolean anchorIsTarget(TrustAnchor anchor,
+                                          CertSelector sel)
+    {
         X509Certificate anchorCert = anchor.getTrustedCert();
         if (anchorCert != null) {
             return sel.match(anchorCert);
         }
         return false;
     }
-
-    /**
-     * Comparator that orders CertStores so that local CertStores come before
-     * remote CertStores.
-     */
-    private static class CertStoreComparator implements Comparator<CertStore> {
-        public int compare(CertStore store1, CertStore store2) {
-            if (Builder.isLocalCertStore(store1)) {
-                return -1;
-            } else {
-                return 1;
-            }
-        }
-    }
-
-    /**
-     * Returns the target subject DN from the first X509Certificate that
-     * is fetched that matches the specified X509CertSelector.
-     */
-    private X500Principal getTargetSubjectDN(List<CertStore> stores,
-        X509CertSelector targetSel) {
-        for (CertStore store : stores) {
-            try {
-                Collection<? extends Certificate> targetCerts =
-                    (Collection<? extends Certificate>)
-                        store.getCertificates(targetSel);
-                if (!targetCerts.isEmpty()) {
-                    X509Certificate targetCert =
-                        (X509Certificate)targetCerts.iterator().next();
-                    return targetCert.getSubjectX500Principal();
-                }
-            } catch (CertStoreException e) {
-                // ignore but log it
-                if (debug != null) {
-                    debug.println("SunCertPathBuilder.getTargetSubjectDN: " +
-                        "non-fatal exception retrieving certs: " + e);
-                    e.printStackTrace();
-                }
-            }
-        }
-        return null;
-    }
 }
--- a/src/share/classes/sun/security/provider/certpath/SunCertPathBuilderParameters.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/provider/certpath/SunCertPathBuilderParameters.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2012, 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,12 +25,11 @@
 
 package sun.security.provider.certpath;
 
-import java.util.Set;
-
 import java.security.InvalidAlgorithmParameterException;
 import java.security.KeyStore;
 import java.security.KeyStoreException;
 import java.security.cert.*;
+import java.util.Set;
 
 /**
  * This class specifies the set of parameters used as input for the Sun
@@ -120,8 +119,9 @@
      *
      * @return a formatted string describing the parameters.
      */
+    @Override
     public String toString() {
-        StringBuffer sb = new StringBuffer();
+        StringBuilder sb = new StringBuilder();
         sb.append("[\n");
         sb.append(super.toString());
         sb.append("  Build Forward Flag: " + String.valueOf(buildForward) + "\n");
--- a/src/share/classes/sun/security/provider/certpath/URICertStore.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/provider/certpath/URICertStore.java	Thu Nov 09 06:08:09 2017 +0000
@@ -242,6 +242,7 @@
      *         match the specified selector
      * @throws CertStoreException if an exception occurs
      */
+    @Override
     @SuppressWarnings("unchecked")
     public synchronized Collection<X509Certificate> engineGetCertificates
         (CertSelector selector) throws CertStoreException {
@@ -351,6 +352,7 @@
      *         match the specified selector
      * @throws CertStoreException if an exception occurs
      */
+    @Override
     @SuppressWarnings("unchecked")
     public synchronized Collection<X509CRL> engineGetCRLs(CRLSelector selector)
         throws CertStoreException {
@@ -367,7 +369,11 @@
             // Fetch the CRLs via LDAP. LDAPCertStore has its own
             // caching mechanism, see the class description for more info.
             // Safe cast since xsel is an X509 certificate selector.
-            return (Collection<X509CRL>) ldapCertStore.getCRLs(xsel);
+            try {
+                return (Collection<X509CRL>) ldapCertStore.getCRLs(xsel);
+            } catch (CertStoreException cse) {
+                throw new PKIX.CertStoreTypeException("LDAP", cse);
+            }
         }
 
         // Return the CRLs for this entry. It returns the cached value
@@ -419,11 +425,12 @@
                 debug.println("Exception fetching CRL:");
                 e.printStackTrace();
             }
+            // exception, forget previous values
+            lastModified = 0;
+            crl = null;
+            throw new PKIX.CertStoreTypeException("URI",
+                                                  new CertStoreException(e));
         }
-        // exception, forget previous values
-        lastModified = 0;
-        crl = null;
-        return Collections.<X509CRL>emptyList();
     }
 
     /**
@@ -448,14 +455,14 @@
         URICertStoreParameters(URI uri) {
             this.uri = uri;
         }
-        public boolean equals(Object obj) {
+        @Override public boolean equals(Object obj) {
             if (!(obj instanceof URICertStoreParameters)) {
                 return false;
             }
             URICertStoreParameters params = (URICertStoreParameters) obj;
             return uri.equals(params.uri);
         }
-        public int hashCode() {
+        @Override public int hashCode() {
             if (hashCode == 0) {
                 int result = 17;
                 result = 37*result + uri.hashCode();
@@ -463,7 +470,7 @@
             }
             return hashCode;
         }
-        public Object clone() {
+        @Override public Object clone() {
             try {
                 return super.clone();
             } catch (CloneNotSupportedException e) {
--- a/src/share/classes/sun/security/provider/certpath/Vertex.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/provider/certpath/Vertex.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2012, 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,12 +25,11 @@
 
 package sun.security.provider.certpath;
 
-import sun.security.util.Debug;
-
-import java.security.cert.Certificate;
+import java.io.IOException;
 import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
 
+import sun.security.util.Debug;
 import sun.security.x509.AuthorityKeyIdentifierExtension;
 import sun.security.x509.KeyIdentifier;
 import sun.security.x509.SubjectKeyIdentifierExtension;
@@ -50,17 +49,17 @@
 public class Vertex {
 
     private static final Debug debug = Debug.getInstance("certpath");
-    private Certificate cert;
-    private int         index;
-    private Throwable   throwable;
+    private X509Certificate cert;
+    private int index;
+    private Throwable throwable;
 
     /**
      * Constructor; creates vertex with index of -1
      * Use setIndex method to set another index.
      *
-     * @param cert Certificate associated with vertex
+     * @param cert X509Certificate associated with vertex
      */
-    Vertex(Certificate cert) {
+    Vertex(X509Certificate cert) {
         this.cert = cert;
         this.index = -1;
     }
@@ -68,9 +67,9 @@
     /**
      * return the certificate for this vertex
      *
-     * @returns Certificate
+     * @returns X509Certificate
      */
-    public Certificate getCertificate() {
+    public X509Certificate getCertificate() {
         return cert;
     }
 
@@ -121,6 +120,7 @@
      *
      * @returns String representation of vertex
      */
+    @Override
     public String toString() {
         return certToString() + throwableToString() + indexToString();
     }
@@ -132,70 +132,65 @@
      * @returns String representation of certificate info
      */
     public String certToString() {
-        String out = "";
-        if (cert == null || ! (cert instanceof X509Certificate))
-            return "Cert:       Not an X509Certificate\n";
+        StringBuilder sb = new StringBuilder();
 
         X509CertImpl x509Cert = null;
         try {
-            x509Cert = X509CertImpl.toImpl((X509Certificate)cert);
+            x509Cert = X509CertImpl.toImpl(cert);
         } catch (CertificateException ce) {
             if (debug != null) {
                 debug.println("Vertex.certToString() unexpected exception");
                 ce.printStackTrace();
             }
-            return out;
+            return sb.toString();
         }
 
-        out =       "Issuer:     " + x509Cert.getIssuerX500Principal() + "\n";
-        out = out + "Subject:    " + x509Cert.getSubjectX500Principal() + "\n";
-        out = out + "SerialNum:  " + (x509Cert.getSerialNumber()).toString(16) + "\n";
-        out = out + "Expires:    " + x509Cert.getNotAfter().toString() + "\n";
+        sb.append("Issuer:     ").append
+                 (x509Cert.getIssuerX500Principal()).append("\n");
+        sb.append("Subject:    ").append
+                 (x509Cert.getSubjectX500Principal()).append("\n");
+        sb.append("SerialNum:  ").append
+                 (x509Cert.getSerialNumber().toString(16)).append("\n");
+        sb.append("Expires:    ").append
+                 (x509Cert.getNotAfter().toString()).append("\n");
         boolean[] iUID = x509Cert.getIssuerUniqueID();
         if (iUID != null) {
-            out = out + "IssuerUID:  ";
-            for (int i=0; i < iUID.length; i++) {
-                out = out + (iUID[i]?1:0);
+            sb.append("IssuerUID:  ");
+            for (boolean b : iUID) {
+                sb.append(b ? 1 : 0);
             }
-            out = out + "\n";
+            sb.append("\n");
         }
         boolean[] sUID = x509Cert.getSubjectUniqueID();
         if (sUID != null) {
-            out = out + "SubjectUID: ";
-            for (int i=0; i< sUID.length; i++) {
-                out = out + (sUID[i]?1:0);
+            sb.append("SubjectUID: ");
+            for (boolean b : sUID) {
+                sb.append(b ? 1 : 0);
             }
-            out = out + "\n";
+            sb.append("\n");
         }
-        SubjectKeyIdentifierExtension sKeyID = null;
         try {
-            sKeyID = x509Cert.getSubjectKeyIdentifierExtension();
+            SubjectKeyIdentifierExtension sKeyID =
+                x509Cert.getSubjectKeyIdentifierExtension();
             if (sKeyID != null) {
                 KeyIdentifier keyID = sKeyID.get(
                         SubjectKeyIdentifierExtension.KEY_ID);
-                out = out + "SubjKeyID:  " + keyID.toString();
+                sb.append("SubjKeyID:  ").append(keyID.toString());
             }
-        } catch (Exception e) {
+            AuthorityKeyIdentifierExtension aKeyID =
+                x509Cert.getAuthorityKeyIdentifierExtension();
+            if (aKeyID != null) {
+                KeyIdentifier keyID = (KeyIdentifier)aKeyID.get(
+                        AuthorityKeyIdentifierExtension.KEY_ID);
+                sb.append("AuthKeyID:  ").append(keyID.toString());
+            }
+        } catch (IOException e) {
             if (debug != null) {
                 debug.println("Vertex.certToString() unexpected exception");
                 e.printStackTrace();
             }
         }
-        AuthorityKeyIdentifierExtension aKeyID = null;
-        try {
-            aKeyID = x509Cert.getAuthorityKeyIdentifierExtension();
-            if (aKeyID != null) {
-                KeyIdentifier keyID = (KeyIdentifier)aKeyID.get(
-                        AuthorityKeyIdentifierExtension.KEY_ID);
-                out = out + "AuthKeyID:  " + keyID.toString();
-            }
-        } catch (Exception e) {
-            if (debug != null) {
-                debug.println("Vertex.certToString() 2 unexpected exception");
-                e.printStackTrace();
-            }
-        }
-        return out;
+        return sb.toString();
     }
 
     /**
@@ -205,13 +200,13 @@
      * @returns String form of exception (or "none")
      */
     public String throwableToString() {
-        String out = "Exception:  ";
+        StringBuilder sb = new StringBuilder("Exception:  ");
         if (throwable != null)
-            out = out + throwable.toString();
+            sb.append(throwable.toString());
         else
-            out = out + "null";
-        out = out + "\n";
-        return out;
+            sb.append("null");
+        sb.append("\n");
+        return sb.toString();
     }
 
     /**
@@ -222,10 +217,10 @@
      * @returns String form of index as "Last cert?  [Yes/No]
      */
     public String moreToString() {
-        String out = "Last cert?  ";
-        out = out + ((index == -1)?"Yes":"No");
-        out = out + "\n";
-        return out;
+        StringBuilder sb = new StringBuilder("Last cert?  ");
+        sb.append((index == -1) ? "Yes" : "No");
+        sb.append("\n");
+        return sb.toString();
     }
 
     /**
@@ -235,7 +230,6 @@
      * @returns String form of index as "Index:     [numeric index]"
      */
     public String indexToString() {
-        String out = "Index:      " + index + "\n";
-        return out;
+        return "Index:      " + index + "\n";
     }
 }
--- a/src/share/classes/sun/security/provider/certpath/X509CertPath.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/provider/certpath/X509CertPath.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2012, 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
@@ -33,9 +33,9 @@
 import java.security.cert.Certificate;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
+import java.security.cert.CertPath;
 import java.security.cert.X509Certificate;
 import java.util.*;
-import java.security.cert.CertPath;
 import sun.security.pkcs.ContentInfo;
 import sun.security.pkcs.PKCS7;
 import sun.security.pkcs.SignerInfo;
@@ -44,7 +44,6 @@
 import sun.security.util.DerOutputStream;
 import sun.security.util.DerInputStream;
 
-
 /**
  * A {@link java.security.cert.CertPath CertPath} (certification path)
  * consisting exclusively of
@@ -83,7 +82,7 @@
     private static final Collection<String> encodingList;
 
     static {
-        List<String> list = new ArrayList<String>(2);
+        List<String> list = new ArrayList<>(2);
         list.add(PKIPATH_ENCODING);
         list.add(PKCS7_ENCODING);
         encodingList = Collections.unmodifiableCollection(list);
@@ -272,6 +271,7 @@
      * @return the encoded bytes
      * @exception CertificateEncodingException if an encoding error occurs
      */
+    @Override
     public byte[] getEncoded() throws CertificateEncodingException {
         // @@@ Should cache the encoded form
         return encodePKIPATH();
@@ -342,6 +342,7 @@
      * @exception CertificateEncodingException if an encoding error occurs or
      *   the encoding requested is not supported
      */
+    @Override
     public byte[] getEncoded(String encoding)
             throws CertificateEncodingException {
         switch (encoding) {
@@ -376,6 +377,7 @@
      * @return an <code>Iterator</code> over the names of the supported
      *         encodings (as Strings)
      */
+    @Override
     public Iterator<String> getEncodings() {
         return getEncodingsStatic();
     }
@@ -387,6 +389,7 @@
      * @return an immutable <code>List</code> of <code>X509Certificate</code>s
      *         (may be empty, but not null)
      */
+    @Override
     public List<X509Certificate> getCertificates() {
         return certs;
     }
--- a/src/share/classes/sun/security/provider/certpath/X509CertificatePair.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/provider/certpath/X509CertificatePair.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2002, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2012, 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
@@ -206,13 +206,14 @@
      *
      * @return A String describing the contents of the pair.
      */
+    @Override
     public String toString() {
-        StringBuffer sb = new StringBuffer();
+        StringBuilder sb = new StringBuilder();
         sb.append("X.509 Certificate Pair: [\n");
         if (forward != null)
-            sb.append("  Forward: " + forward + "\n");
+            sb.append("  Forward: ").append(forward).append("\n");
         if (reverse != null)
-            sb.append("  Reverse: " + reverse + "\n");
+            sb.append("  Reverse: ").append(reverse).append("\n");
         sb.append("]");
         return sb.toString();
     }
--- a/src/share/classes/sun/security/provider/certpath/ldap/LDAPCertStoreHelper.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/provider/certpath/ldap/LDAPCertStoreHelper.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2012, 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,15 +25,18 @@
 
 package sun.security.provider.certpath.ldap;
 
+import java.io.IOException;
 import java.net.URI;
 import java.util.Collection;
 import java.security.NoSuchAlgorithmException;
 import java.security.InvalidAlgorithmParameterException;
 import java.security.cert.CertStore;
+import java.security.cert.CertStoreException;
 import java.security.cert.X509CertSelector;
 import java.security.cert.X509CRLSelector;
+import javax.naming.CommunicationException;
+import javax.naming.ServiceUnavailableException;
 import javax.security.auth.x500.X500Principal;
-import java.io.IOException;
 
 import sun.security.provider.certpath.CertStoreHelper;
 
@@ -68,4 +71,11 @@
     {
         return new LDAPCertStore.LDAPCRLSelector(selector, certIssuers, ldapDN);
     }
+
+    @Override
+    public boolean isCausedByNetworkIssue(CertStoreException e) {
+        Throwable t = e.getCause();
+        return (t != null && (t instanceof ServiceUnavailableException ||
+                              t instanceof CommunicationException));
+    }
 }
--- a/src/share/classes/sun/security/provider/certpath/ssl/SSLServerCertStoreHelper.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/provider/certpath/ssl/SSLServerCertStoreHelper.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2012, 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,15 +25,16 @@
 
 package sun.security.provider.certpath.ssl;
 
+import java.io.IOException;
 import java.net.URI;
-import java.util.Collection;
 import java.security.NoSuchAlgorithmException;
 import java.security.InvalidAlgorithmParameterException;
 import java.security.cert.CertStore;
+import java.security.cert.CertStoreException;
 import java.security.cert.X509CertSelector;
 import java.security.cert.X509CRLSelector;
+import java.util.Collection;
 import javax.security.auth.x500.X500Principal;
-import java.io.IOException;
 
 import sun.security.provider.certpath.CertStoreHelper;
 
@@ -66,4 +67,10 @@
     {
         throw new UnsupportedOperationException();
     }
+
+    @Override
+    public boolean isCausedByNetworkIssue(CertStoreException e) {
+        Throwable t = e.getCause();
+        return (t != null && t instanceof IOException);
+    }
 }
--- a/src/share/classes/sun/security/ssl/SSLContextImpl.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/ssl/SSLContextImpl.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2017, 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
@@ -37,6 +37,7 @@
 
 import sun.security.provider.certpath.AlgorithmChecker;
 import sun.security.action.GetPropertyAction;
+import sun.security.validator.Validator;
 
 public abstract class SSLContextImpl extends SSLContextSpi {
 
@@ -962,7 +963,7 @@
                 constraints = new SSLAlgorithmConstraints(sslSocket, true);
             }
 
-            checkAlgorithmConstraints(chain, constraints);
+            checkAlgorithmConstraints(chain, constraints, isClient);
         }
     }
 
@@ -1004,12 +1005,12 @@
                 constraints = new SSLAlgorithmConstraints(engine, true);
             }
 
-            checkAlgorithmConstraints(chain, constraints);
+            checkAlgorithmConstraints(chain, constraints, isClient);
         }
     }
 
     private void checkAlgorithmConstraints(X509Certificate[] chain,
-            AlgorithmConstraints constraints) throws CertificateException {
+            AlgorithmConstraints constraints, boolean isClient) throws CertificateException {
 
         try {
             // Does the certificate chain end with a trusted certificate?
@@ -1027,7 +1028,9 @@
 
             // A forward checker, need to check from trust to target
             if (checkedLength >= 0) {
-                AlgorithmChecker checker = new AlgorithmChecker(constraints);
+                AlgorithmChecker checker =
+                        new AlgorithmChecker(constraints, null,
+                                (isClient ? Validator.VAR_TLS_CLIENT : Validator.VAR_TLS_SERVER));
                 checker.init(false);
                 for (int i = checkedLength; i >= 0; i--) {
                     Certificate cert = chain[i];
--- a/src/share/classes/sun/security/ssl/X509KeyManagerImpl.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/ssl/X509KeyManagerImpl.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2017, 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
@@ -39,6 +39,7 @@
 import javax.net.ssl.*;
 
 import sun.security.provider.certpath.AlgorithmChecker;
+import sun.security.validator.Validator;
 
 /**
  * The new X509 key manager implementation. The main differences to the
@@ -62,7 +63,7 @@
 
     private static final Debug debug = Debug.getInstance("ssl");
 
-    private final static boolean useDebug =
+    private static final boolean useDebug =
                             (debug != null) && Debug.isOn("keymanager");
 
     // for unit testing only, set via privileged reflection
@@ -576,6 +577,15 @@
                 return CheckResult.EXPIRED;
             }
         }
+
+        public String getValidator() {
+            if (this == CLIENT) {
+                return Validator.VAR_TLS_CLIENT;
+            } else if (this == SERVER) {
+                return Validator.VAR_TLS_SERVER;
+            }
+            return Validator.VAR_GENERIC;
+        }
     }
 
     // enum for the result of the extension check
@@ -685,7 +695,8 @@
 
             // check the algorithm constraints
             if (constraints != null &&
-                    !conformsToAlgorithmConstraints(constraints, chain)) {
+                    !conformsToAlgorithmConstraints(constraints, chain,
+                            checkType.getValidator())) {
 
                 if (useDebug) {
                     debug.println("Ignoring alias " + alias +
@@ -721,13 +732,19 @@
     }
 
     private static boolean conformsToAlgorithmConstraints(
-            AlgorithmConstraints constraints, Certificate[] chain) {
+            AlgorithmConstraints constraints, Certificate[] chain,
+            String variant) {
 
-        AlgorithmChecker checker = new AlgorithmChecker(constraints);
+        AlgorithmChecker checker = new AlgorithmChecker(constraints, null, variant);
         try {
             checker.init(false);
         } catch (CertPathValidatorException cpve) {
             // unlikely to happen
+            if (useDebug) {
+                debug.println(
+                    "Cannot initialize algorithm constraints checker: " + cpve);
+            }
+
             return false;
         }
 
@@ -738,6 +755,11 @@
                 // We don't care about the unresolved critical extensions.
                 checker.check(cert, Collections.<String>emptySet());
             } catch (CertPathValidatorException cpve) {
+                if (useDebug) {
+                    debug.println("Certificate (" + cert +
+                        ") does not conform to algorithm constraints: " + cpve);
+                }
+
                 return false;
             }
         }
--- a/src/share/classes/sun/security/util/AnchorCertificates.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/util/AnchorCertificates.java	Thu Nov 09 06:08:09 2017 +0000
@@ -31,8 +31,10 @@
 import java.security.KeyStore;
 import java.security.PrivilegedAction;
 import java.security.cert.X509Certificate;
+import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashSet;
+import java.util.Set;
 
 import sun.security.x509.X509CertImpl;
 
@@ -44,7 +46,7 @@
 
     private static final Debug debug = Debug.getInstance("certpath");
     private static final String HASH = "SHA-256";
-    private static HashSet<String> certs;
+    private static Set<String> certs = Collections.emptySet();
 
     static  {
         AccessController.doPrivileged(new PrivilegedAction<Void>() {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/util/ConstraintsParameters.java	Thu Nov 09 06:08:09 2017 +0000
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2016, 2017 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.util;
+
+import sun.security.validator.Validator;
+
+import java.security.AlgorithmParameters;
+import java.security.Key;
+import java.security.Timestamp;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+
+/**
+ * This class contains parameters for checking against constraints that extend
+ * past the publicly available parameters in java.security.AlgorithmConstraints.
+
+ * This is currently on passed between  between PKIX, AlgorithmChecker,
+ * and DisabledAlgorithmConstraints.
+ */
+public class ConstraintsParameters {
+    /*
+     * The below 3 values are used the same as the permit() methods
+     * published in java.security.AlgorithmConstraints.
+     */
+    // Algorithm string to be checked against constraints
+    private final String algorithm;
+    // AlgorithmParameters to the algorithm being checked
+    private final AlgorithmParameters algParams;
+    // Public Key being checked against constraints
+    private final Key publicKey;
+
+    /*
+     * New values that are checked against constraints that the current public
+     * API does not support.
+     */
+    // A certificate being passed to check against constraints.
+    private final X509Certificate cert;
+    // This is true if the trust anchor in the certificate chain matches a cert
+    // in AnchorCertificates
+    private final boolean trustedMatch;
+    // PKIXParameter date
+    private final Date pkixDate;
+    // Timestamp of the signed JAR file
+    private final Timestamp jarTimestamp;
+    private final String variant;
+
+    public ConstraintsParameters(X509Certificate c, boolean match,
+            Date pkixdate, Timestamp jarTime, String variant) {
+        cert = c;
+        trustedMatch = match;
+        pkixDate = pkixdate;
+        jarTimestamp = jarTime;
+        this.variant = (variant == null ? Validator.VAR_GENERIC : variant);
+        algorithm = null;
+        algParams = null;
+        publicKey = null;
+    }
+
+    public ConstraintsParameters(String algorithm, AlgorithmParameters params,
+            Key key, String variant) {
+        this.algorithm = algorithm;
+        algParams = params;
+        this.publicKey = key;
+        cert = null;
+        trustedMatch = false;
+        pkixDate = null;
+        jarTimestamp = null;
+        this.variant = (variant == null ? Validator.VAR_GENERIC : variant);
+    }
+
+
+    public ConstraintsParameters(X509Certificate c) {
+        this(c, false, null, null,
+                Validator.VAR_GENERIC);
+    }
+
+    public ConstraintsParameters(Timestamp jarTime) {
+        this(null, false, null, jarTime, Validator.VAR_GENERIC);
+    }
+
+    public String getAlgorithm() {
+        return algorithm;
+    }
+
+    public AlgorithmParameters getAlgParams() {
+        return algParams;
+    }
+
+    public Key getPublicKey() {
+        return publicKey;
+    }
+    // Returns if the trust anchor has a match if anchor checking is enabled.
+    public boolean isTrustedMatch() {
+        return trustedMatch;
+    }
+
+    public X509Certificate getCertificate() {
+        return cert;
+    }
+
+    public Date getPKIXParamDate() {
+        return pkixDate;
+    }
+
+    public Timestamp getJARTimestamp() {
+        return jarTimestamp;
+    }
+
+    public String getVariant() {
+        return variant;
+    }
+}
--- a/src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2017, 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,20 +25,37 @@
 
 package sun.security.util;
 
+import sun.misc.JavaUtilCalendarAccess;
+import sun.misc.SharedSecrets;
+import sun.security.validator.Validator;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
 import java.security.CryptoPrimitive;
 import java.security.AlgorithmParameters;
 import java.security.Key;
 import java.security.cert.CertPathValidatorException;
 import java.security.cert.CertPathValidatorException.BasicReason;
 import java.security.cert.X509Certificate;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
+import java.util.GregorianCalendar;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.TimeZone;
 import java.util.regex.Pattern;
 import java.util.regex.Matcher;
 
+import static java.util.Calendar.FIELD_COUNT;
+
 /**
  * Algorithm constraints for disabled algorithms property
  *
@@ -49,11 +66,11 @@
     private static final Debug debug = Debug.getInstance("certpath");
 
     // the known security property, jdk.certpath.disabledAlgorithms
-    public final static String PROPERTY_CERTPATH_DISABLED_ALGS =
+    public static final String PROPERTY_CERTPATH_DISABLED_ALGS =
             "jdk.certpath.disabledAlgorithms";
 
     // the known security property, jdk.tls.disabledAlgorithms
-    public final static String PROPERTY_TLS_DISABLED_ALGS =
+    public static final String PROPERTY_TLS_DISABLED_ALGS =
             "jdk.tls.disabledAlgorithms";
 
     // the known security property, jdk.jar.disabledAlgorithms
@@ -93,14 +110,8 @@
      * there are keysize or other limit, this method allow the algorithm.
      */
     @Override
-    final public boolean permits(Set<CryptoPrimitive> primitives,
+    public final boolean permits(Set<CryptoPrimitive> primitives,
             String algorithm, AlgorithmParameters parameters) {
-
-        if (primitives == null || primitives.isEmpty()) {
-            throw new IllegalArgumentException(
-                        "No cryptographic primitive specified");
-        }
-
         return checkAlgorithm(disabledAlgorithms, algorithm, decomposer);
     }
 
@@ -109,7 +120,7 @@
      * placed on the key.
      */
     @Override
-    final public boolean permits(Set<CryptoPrimitive> primitives, Key key) {
+    public final boolean permits(Set<CryptoPrimitive> primitives, Key key) {
         return checkConstraints(primitives, "", key, null);
     }
 
@@ -118,7 +129,7 @@
      * been placed on the key.
      */
     @Override
-    final public boolean permits(Set<CryptoPrimitive> primitives,
+    public final boolean permits(Set<CryptoPrimitive> primitives,
             String algorithm, Key key, AlgorithmParameters parameters) {
 
         if (algorithm == null || algorithm.length() == 0) {
@@ -128,6 +139,18 @@
         return checkConstraints(primitives, algorithm, key, parameters);
     }
 
+    public final void permits(ConstraintsParameters cp)
+            throws CertPathValidatorException {
+        permits(cp.getAlgorithm(), cp);
+    }
+
+    public final void permits(String algorithm, Key key,
+            AlgorithmParameters params, String variant)
+            throws CertPathValidatorException {
+        permits(algorithm, new ConstraintsParameters(algorithm, params, key,
+                (variant == null) ? Validator.VAR_GENERIC : variant));
+    }
+
     /*
      * Check if a x509Certificate object is permitted.  Check if all
      * algorithms are allowed, certificate constraints, and the
@@ -135,18 +158,10 @@
      *
      * Uses new style permit() which throws exceptions.
      */
-    public final void permits(Set<CryptoPrimitive> primitives,
-            CertConstraintParameters cp) throws CertPathValidatorException {
-        checkConstraints(primitives, cp);
-    }
 
-    /*
-     * Check if Certificate object is within the constraints.
-     * Uses new style permit() which throws exceptions.
-     */
-    public final void permits(Set<CryptoPrimitive> primitives,
-            X509Certificate cert) throws CertPathValidatorException {
-        checkConstraints(primitives, new CertConstraintParameters(cert));
+    public final void permits(String algorithm, ConstraintsParameters cp)
+            throws CertPathValidatorException {
+        algorithmConstraints.permits(algorithm, cp);
     }
 
     // Check if a string is contained inside the property
@@ -169,7 +184,7 @@
             throw new IllegalArgumentException("The key cannot be null");
         }
 
-        // check the signature algorithm
+        // check the signature algorithm with parameters
         if (algorithm != null && algorithm.length() != 0) {
             if (!permits(primitives, algorithm, parameters)) {
                 return false;
@@ -185,36 +200,6 @@
         return algorithmConstraints.permits(key);
     }
 
-    /*
-     * Check algorithm constraints with Certificate
-     * Uses new style permit() which throws exceptions.
-     */
-    private void checkConstraints(Set<CryptoPrimitive> primitives,
-            CertConstraintParameters cp) throws CertPathValidatorException {
-
-        X509Certificate cert = cp.getCertificate();
-        String algorithm = cert.getSigAlgName();
-
-        // Check signature algorithm is not disabled
-        if (!permits(primitives, algorithm, null)) {
-            throw new CertPathValidatorException(
-                    "Algorithm constraints check failed on disabled "+
-                            "signature algorithm: " + algorithm,
-                    null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
-        }
-
-        // Check key algorithm is not disabled
-        if (!permits(primitives, cert.getPublicKey().getAlgorithm(), null)) {
-            throw new CertPathValidatorException(
-                    "Algorithm constraints check failed on disabled "+
-                            "public key algorithm: " + algorithm,
-                    null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
-        }
-
-        // Check the certificate and key constraints
-        algorithmConstraints.permits(cp);
-
-    }
 
     /**
      * Key and Certificate Constraints
@@ -229,15 +214,18 @@
      * 'true' means the operation is allowed.
      * 'false' means it failed the constraints and is disallowed.
      *
-     * When passing CertConstraintParameters through permit(), an exception
+     * When passing ConstraintsParameters through permit(), an exception
      * will be thrown on a failure to better identify why the operation was
      * disallowed.
      */
 
     private static class Constraints {
-        private Map<String, Set<Constraint>> constraintsMap = new HashMap<>();
-        private static final Pattern keySizePattern = Pattern.compile(
-                "keySize\\s*(<=|<|==|!=|>|>=)\\s*(\\d+)");
+        private Map<String, List<Constraint>> constraintsMap = new HashMap<>();
+
+        private static class Holder {
+            private static final Pattern DENY_AFTER_PATTERN = Pattern.compile(
+                    "denyAfter\\s+(\\d{4})-(\\d{2})-(\\d{2})");
+        }
 
         public Constraints(String[] constraintArray) {
             for (String constraintEntry : constraintArray) {
@@ -252,40 +240,48 @@
 
                 // Check if constraint is a complete disabling of an
                 // algorithm or has conditions.
-                String algorithm;
-                String policy;
                 int space = constraintEntry.indexOf(' ');
-                if (space > 0) {
-                    algorithm = AlgorithmDecomposer.hashName(
-                            constraintEntry.substring(0, space).
-                                    toUpperCase(Locale.ENGLISH));
-                    policy = constraintEntry.substring(space + 1);
-                } else {
-                    String k = constraintEntry.toUpperCase(Locale.ENGLISH);
-                    if (!constraintsMap.containsKey(k)) {
-                        constraintsMap.put(k, new HashSet<Constraint>());
-                    }
+                String algorithm = AlgorithmDecomposer.hashName(
+                        ((space > 0 ? constraintEntry.substring(0, space) :
+                                constraintEntry).
+                                toUpperCase(Locale.ENGLISH)));
+                List<Constraint> constraintList = constraintsMap.get(algorithm);
+                if (constraintList == null) {
+                    constraintList = new ArrayList<>(1);
+                    constraintsMap.put(algorithm, constraintList);
+                }
+                if (space <= 0) {
+                    constraintList.add(new DisabledConstraint(algorithm));
                     continue;
                 }
 
+                String policy = constraintEntry.substring(space + 1);
+
                 // Convert constraint conditions into Constraint classes
-                Constraint c = null;
-                Constraint lastConstraint = null;
+                Constraint c, lastConstraint = null;
                 // Allow only one jdkCA entry per constraint entry
                 boolean jdkCALimit = false;
+                // Allow only one denyAfter entry per constraint entry
+                boolean denyAfterLimit = false;
 
                 for (String entry : policy.split("&")) {
                     entry = entry.trim();
 
-                    Matcher matcher = keySizePattern.matcher(entry);
-                    if (matcher.matches()) {
+                    Matcher matcher;
+                    if (entry.startsWith("keySize")) {
                         if (debug != null) {
                             debug.println("Constraints set to keySize: " +
                                     entry);
                         }
+                        StringTokenizer tokens = new StringTokenizer(entry);
+                        if (!"keySize".equals(tokens.nextToken())) {
+                            throw new IllegalArgumentException("Error in " +
+                                    "security property. Constraint unknown: " +
+                                    entry);
+                        }
                         c = new KeySizeConstraint(algorithm,
-                                KeySizeConstraint.Operator.of(matcher.group(1)),
-                                Integer.parseInt(matcher.group(2)));
+                                KeySizeConstraint.Operator.of(tokens.nextToken()),
+                                Integer.parseInt(tokens.nextToken()));
 
                     } else if (entry.equalsIgnoreCase("jdkCA")) {
                         if (debug != null) {
@@ -298,17 +294,39 @@
                         }
                         c = new jdkCAConstraint(algorithm);
                         jdkCALimit = true;
+
+                    } else if (entry.startsWith("denyAfter") &&
+                            (matcher = Holder.DENY_AFTER_PATTERN.matcher(entry))
+                                    .matches()) {
+                        if (debug != null) {
+                            debug.println("Constraints set to denyAfter");
+                        }
+                        if (denyAfterLimit) {
+                            throw new IllegalArgumentException("Only one " +
+                                    "denyAfter entry allowed in property. " +
+                                    "Constraint: " + constraintEntry);
+                        }
+                        int year = Integer.parseInt(matcher.group(1));
+                        int month = Integer.parseInt(matcher.group(2));
+                        int day = Integer.parseInt(matcher.group(3));
+                        c = new DenyAfterConstraint(algorithm, year, month,
+                                day);
+                        denyAfterLimit = true;
+                    } else if (entry.startsWith("usage")) {
+                        String s[] = (entry.substring(5)).trim().split(" ");
+                        c = new UsageConstraint(algorithm, s);
+                        if (debug != null) {
+                            debug.println("Constraints usage length is " + s.length);
+                        }
+                    } else {
+                        throw new IllegalArgumentException("Error in security" +
+                                " property. Constraint unknown: " + entry);
                     }
 
                     // Link multiple conditions for a single constraint
                     // into a linked list.
                     if (lastConstraint == null) {
-                        if (!constraintsMap.containsKey(algorithm)) {
-                            constraintsMap.put(algorithm, new HashSet<Constraint>());
-                        }
-                        if (c != null) {
-                            constraintsMap.get(algorithm).add(c);
-                        }
+                        constraintList.add(c);
                     } else {
                         lastConstraint.nextConstraint = c;
                     }
@@ -318,61 +336,73 @@
         }
 
         // Get applicable constraints based off the signature algorithm
-        private Set<Constraint> getConstraints(String algorithm) {
+        private List<Constraint> getConstraints(String algorithm) {
             return constraintsMap.get(algorithm);
         }
 
         // Check if KeySizeConstraints permit the specified key
         public boolean permits(Key key) {
-            Set<Constraint> set = getConstraints(key.getAlgorithm());
-            if (set == null) {
+            List<Constraint> list = getConstraints(key.getAlgorithm());
+            if (list == null) {
                 return true;
             }
-            for (Constraint constraint : set) {
+            for (Constraint constraint : list) {
                 if (!constraint.permits(key)) {
                     if (debug != null) {
                         debug.println("keySizeConstraint: failed key " +
                                 "constraint check " + KeyUtil.getKeySize(key));
                     }
-            return false;
-        }
+                    return false;
+                }
             }
-        return true;
-    }
+            return true;
+        }
 
         // Check if constraints permit this cert.
-        public void permits(CertConstraintParameters cp)
+        public void permits(String algorithm, ConstraintsParameters cp)
                 throws CertPathValidatorException {
             X509Certificate cert = cp.getCertificate();
 
             if (debug != null) {
-                debug.println("Constraints.permits(): " + cert.getSigAlgName());
+                debug.println("Constraints.permits(): " + algorithm +
+                        " Variant: " + cp.getVariant());
             }
 
             // Get all signature algorithms to check for constraints
-            Set<String> algorithms =
-                    AlgorithmDecomposer.decomposeOneHash(cert.getSigAlgName());
-            if (algorithms == null || algorithms.isEmpty()) {
-                return;
-    }
+            Set<String> algorithms = new HashSet<>();
+            if (algorithm != null) {
+                algorithms.addAll(AlgorithmDecomposer.decomposeOneHash(algorithm));
+            }
 
-            // Attempt to add the public key algorithm to the set
-            algorithms.add(cert.getPublicKey().getAlgorithm());
-
+            // Attempt to add the public key algorithm if cert provided
+            if (cert != null) {
+                algorithms.add(cert.getPublicKey().getAlgorithm());
+            }
+            if (cp.getPublicKey() != null) {
+                algorithms.add(cp.getPublicKey().getAlgorithm());
+            }
             // Check all applicable constraints
-            for (String algorithm : algorithms) {
-                Set<Constraint> set = getConstraints(algorithm);
-                if (set == null) {
+            for (String alg : algorithms) {
+                List<Constraint> list = getConstraints(alg);
+                if (list == null) {
                     continue;
                 }
-                for (Constraint constraint : set) {
+                for (Constraint constraint : list) {
                     constraint.permits(cp);
                 }
             }
         }
-                        }
+    }
 
-    // Abstract class for algorithm constraint checking
+    /**
+     * This abstract Constraint class for algorithm-based checking
+     * may contain one or more constraints.  If the '&' on the {@Security}
+     * property is used, multiple constraints have been grouped together
+     * requiring all the constraints to fail for the check to be disallowed.
+     *
+     * If the class contains multiple constraints, the next constraint
+     * is stored in {@code nextConstraint} in linked-list fashion.
+     */
     private abstract static class Constraint {
         String algorithm;
         Constraint nextConstraint = null;
@@ -408,22 +438,87 @@
         }
 
         /**
-         * Check if an algorithm constraint permit this key to be used.
+         * Check if an algorithm constraint is permitted with a given key.
+         *
+         * If the check inside of {@code permit()} fails, it must call
+         * {@code next()} with the same {@code Key} parameter passed if
+         * multiple constraints need to be checked.
+         *
          * @param key Public key
-         * @return true if constraints do not match
+         * @return 'true' if constraint is allowed, 'false' if disallowed.
          */
         public boolean permits(Key key) {
             return true;
         }
 
         /**
-         * Check if an algorithm constraint is permit this certificate to
-         * be used.
-         * @param cp CertificateParameter containing certificate and state info
-         * @return true if constraints do not match
+         * Check if an algorithm constraint is permitted with a given
+         * ConstraintsParameters.
+         *
+         * If the check inside of {@code permits()} fails, it must call
+         * {@code next()} with the same {@code ConstraintsParameters}
+         * parameter passed if multiple constraints need to be checked.
+         *
+         * @param cp CertConstraintParameter containing certificate info
+         * @throws CertPathValidatorException if constraint disallows.
+         *
+         */
+        public abstract void permits(ConstraintsParameters cp)
+                throws CertPathValidatorException;
+
+        /**
+         * Recursively check if the constraints are allowed.
+         *
+         * If {@code nextConstraint} is non-null, this method will
+         * call {@code nextConstraint}'s {@code permits()} to check if the
+         * constraint is allowed or denied.  If the constraint's
+         * {@code permits()} is allowed, this method will exit this and any
+         * recursive next() calls, returning 'true'.  If the constraints called
+         * were disallowed, the last constraint will throw
+         * {@code CertPathValidatorException}.
+         *
+         * @param cp ConstraintsParameters
+         * @return 'true' if constraint allows the operation, 'false' if
+         * we are at the end of the constraint list or,
+         * {@code nextConstraint} is null.
          */
-        public abstract void permits(CertConstraintParameters cp)
-                throws CertPathValidatorException;
+        boolean next(ConstraintsParameters cp)
+                throws CertPathValidatorException {
+            if (nextConstraint != null) {
+                nextConstraint.permits(cp);
+                return true;
+            }
+            return false;
+        }
+
+        /**
+         * Recursively check if this constraint is allowed,
+         *
+         * If {@code nextConstraint} is non-null, this method will
+         * call {@code nextConstraint}'s {@code permit()} to check if the
+         * constraint is allowed or denied.  If the constraint's
+         * {@code permit()} is allowed, this method will exit this and any
+         * recursive next() calls, returning 'true'.  If the constraints
+         * called were disallowed the check will exit with 'false'.
+         *
+         * @param key Public key
+         * @return 'true' if constraint allows the operation, 'false' if
+         * the constraint denies the operation.
+         */
+        boolean next(Key key) {
+            if (nextConstraint != null && nextConstraint.permits(key)) {
+                return true;
+            }
+            return false;
+        }
+
+        String extendedMsg(ConstraintsParameters cp) {
+            return (cp.getCertificate() == null ? "." :
+                    " used with certificate: " +
+                            cp.getCertificate().getSubjectX500Principal() +
+                    (cp.getVariant() != Validator.VAR_GENERIC ?
+                            ".  Usage was " + cp.getVariant() : "."));
+        }
     }
 
     /*
@@ -436,30 +531,175 @@
         }
 
         /*
-         * Check if each constraint fails and check if there is a linked
-         * constraint  Any permitted constraint will exit the linked list
-         * to allow the operation.
+         * Check if ConstraintsParameters has a trusted match, if it does
+         * call next() for any following constraints. If it does not, exit
+         * as this constraint(s) does not restrict the operation.
          */
-        public void permits(CertConstraintParameters cp)
+        public void permits(ConstraintsParameters cp)
                 throws CertPathValidatorException {
             if (debug != null) {
                 debug.println("jdkCAConstraints.permits(): " + algorithm);
             }
 
-            // Return false if the chain has a trust anchor in cacerts
+            // Check chain has a trust anchor in cacerts
             if (cp.isTrustedMatch()) {
-                if (nextConstraint != null) {
-                    nextConstraint.permits(cp);
+                if (next(cp)) {
                     return;
                 }
                 throw new CertPathValidatorException(
                         "Algorithm constraints check failed on certificate " +
-                                "anchor limits",
+                        "anchor limits. " + algorithm + extendedMsg(cp),
                         null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
             }
         }
     }
 
+    /*
+     * This class handles the denyAfter constraint.  The date is in the UTC/GMT
+     * timezone.
+     */
+     private static class DenyAfterConstraint extends Constraint {
+         private Date denyAfterDate;
+         private static final SimpleDateFormat dateFormat =
+                 new SimpleDateFormat("EEE, MMM d HH:mm:ss z yyyy");
+
+         DenyAfterConstraint(String algo, int year, int month, int day) {
+             Calendar c;
+
+             algorithm = algo;
+
+             if (debug != null) {
+                 debug.println("DenyAfterConstraint read in as:  year " +
+                         year + ", month = " + month + ", day = " + day);
+             }
+
+             c = new CalendarBuilder().setTimeZone(TimeZone.getTimeZone("GMT"))
+                     .setDate(year, month - 1, day).build();
+
+             if (year > c.getActualMaximum(Calendar.YEAR) ||
+                     year < c.getActualMinimum(Calendar.YEAR)) {
+                 throw new IllegalArgumentException(
+                         "Invalid year given in constraint: " + year);
+             }
+             if ((month - 1) > c.getActualMaximum(Calendar.MONTH) ||
+                     (month - 1) < c.getActualMinimum(Calendar.MONTH)) {
+                 throw new IllegalArgumentException(
+                         "Invalid month given in constraint: " + month);
+             }
+             if (day > c.getActualMaximum(Calendar.DAY_OF_MONTH) ||
+                     day < c.getActualMinimum(Calendar.DAY_OF_MONTH)) {
+                 throw new IllegalArgumentException(
+                         "Invalid Day of Month given in constraint: " + day);
+             }
+
+             denyAfterDate = c.getTime();
+             if (debug != null) {
+                 debug.println("DenyAfterConstraint date set to: " +
+                         dateFormat.format(denyAfterDate));
+             }
+         }
+
+         /*
+          * Checking that the provided date is not beyond the constraint date.
+          * The provided date can be the PKIXParameter date if given,
+          * otherwise it is the current date.
+          *
+          * If the constraint disallows, call next() for any following
+          * constraints. Throw an exception if this is the last constraint.
+          */
+         @Override
+         public void permits(ConstraintsParameters cp)
+                 throws CertPathValidatorException {
+             Date currentDate;
+             String errmsg;
+
+             if (cp.getJARTimestamp() != null) {
+                 currentDate = cp.getJARTimestamp().getTimestamp();
+                 errmsg = "JAR Timestamp date: ";
+             } else if (cp.getPKIXParamDate() != null) {
+                 currentDate = cp.getPKIXParamDate();
+                 errmsg = "PKIXParameter date: ";
+             } else {
+                 currentDate = new Date();
+                 errmsg = "Current date: ";
+             }
+
+             if (!denyAfterDate.after(currentDate)) {
+                 if (next(cp)) {
+                     return;
+                 }
+                 throw new CertPathValidatorException(
+                         "denyAfter constraint check failed: " + algorithm +
+                         " used with Constraint date: " +
+                         dateFormat.format(denyAfterDate) + "; " + errmsg +
+                         dateFormat.format(currentDate) + extendedMsg(cp),
+                         null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
+             }
+         }
+
+         /*
+          * Return result if the constraint's date is beyond the current date
+          * in UTC timezone.
+          */
+         public boolean permits(Key key) {
+             if (next(key)) {
+                 return true;
+             }
+             if (debug != null) {
+                 debug.println("DenyAfterConstraints.permits(): " + algorithm);
+             }
+
+             return denyAfterDate.after(new Date());
+         }
+     }
+
+    /*
+     * The usage constraint is for the "usage" keyword.  It checks against the
+     * variant value in ConstraintsParameters.
+     */
+    private static class UsageConstraint extends Constraint {
+        String[] usages;
+
+        UsageConstraint(String algorithm, String[] usages) {
+            this.algorithm = algorithm;
+            this.usages = usages;
+        }
+
+        public void permits(ConstraintsParameters cp)
+                throws CertPathValidatorException {
+            for (String usage : usages) {
+
+                String v = null;
+                if (usage.compareToIgnoreCase("TLSServer") == 0) {
+                    v = Validator.VAR_TLS_SERVER;
+                } else if (usage.compareToIgnoreCase("TLSClient") == 0) {
+                    v = Validator.VAR_TLS_CLIENT;
+                } else if (usage.compareToIgnoreCase("SignedJAR") == 0) {
+                    v = Validator.VAR_PLUGIN_CODE_SIGNING;
+                }
+
+                if (debug != null) {
+                    debug.println("Checking if usage constraint \"" + v +
+                            "\" matches \"" + cp.getVariant() + "\"");
+                    // Because usage checking can come from many places
+                    // a stack trace is very helpful.
+                    ByteArrayOutputStream ba = new ByteArrayOutputStream();
+                    PrintStream ps = new PrintStream(ba);
+                    (new Exception()).printStackTrace(ps);
+                    debug.println(ba.toString());
+                }
+                if (cp.getVariant().compareTo(v) == 0) {
+                    if (next(cp)) {
+                        return;
+                    }
+                    throw new CertPathValidatorException("Usage constraint " +
+                            usage + " check failed: " + algorithm +
+                            extendedMsg(cp),
+                            null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
+                }
+            }
+        }
+    }
 
     /*
      * This class contains constraints dealing with the key size
@@ -470,6 +710,7 @@
         private int minSize;            // the minimal available key size
         private int maxSize;            // the maximal available key size
         private int prohibitedSize = -1;    // unavailable key sizes
+        private int size;
 
         public KeySizeConstraint(String algo, Operator operator, int length) {
             algorithm = algo;
@@ -513,15 +754,22 @@
          * constraint  Any permitted constraint will exit the linked list
          * to allow the operation.
          */
-        public void permits(CertConstraintParameters cp)
+        public void permits(ConstraintsParameters cp)
                 throws CertPathValidatorException {
-            if (!permitsImpl(cp.getCertificate().getPublicKey())) {
+            Key key = null;
+            if (cp.getPublicKey() != null) {
+                key = cp.getPublicKey();
+            } else if (cp.getCertificate() != null) {
+                key = cp.getCertificate().getPublicKey();
+            }
+            if (key != null && !permitsImpl(key)) {
                 if (nextConstraint != null) {
                     nextConstraint.permits(cp);
                     return;
                 }
                 throw new CertPathValidatorException(
-                        "Algorithm constraints check failed on keysize limits",
+                        "Algorithm constraints check failed on keysize limits. "
+                        + algorithm + " " + size + "bit key" + extendedMsg(cp),
                         null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
             }
         }
@@ -548,7 +796,7 @@
                 return true;
             }
 
-            int size = KeyUtil.getKeySize(key);
+            size = KeyUtil.getKeySize(key);
             if (size == 0) {
                 return false;    // we don't allow any key of size 0.
             } else if (size > 0) {
@@ -559,5 +807,602 @@
 
             return true;
         }
+    }
+
+    /*
+     * This constraint is used for the complete disabling of the algorithm.
+     */
+    private static class DisabledConstraint extends Constraint {
+        DisabledConstraint(String algo) {
+            algorithm = algo;
+        }
+
+        public void permits(ConstraintsParameters cp)
+                throws CertPathValidatorException {
+            throw new CertPathValidatorException(
+                    "Algorithm constraints check failed on disabled " +
+                            "algorithm: " + algorithm + extendedMsg(cp),
+                    null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
+        }
+
+        public boolean permits(Key key) {
+            return false;
         }
     }
+
+    /**
+     * {@code Calendar.Builder} is used for creating a {@code Calendar} from
+     * various date-time parameters.
+     *
+     * <p>There are two ways to set a {@code Calendar} to a date-time value. One
+     * is to set the instant parameter to a millisecond offset from the <a
+     * href="Calendar.html#Epoch">Epoch</a>. The other is to set individual
+     * field parameters, such as {@link Calendar#YEAR YEAR}, to their desired
+     * values. These two ways can't be mixed. Trying to set both the instant and
+     * individual fields will cause an {@link IllegalStateException} to be
+     * thrown. However, it is permitted to override previous values of the
+     * instant or field parameters.
+     *
+     * <p>If no enough field parameters are given for determining date and/or
+     * time, calendar specific default values are used when building a
+     * {@code Calendar}. For example, if the {@link Calendar#YEAR YEAR} value
+     * isn't given for the Gregorian calendar, 1970 will be used. If there are
+     * any conflicts among field parameters, the <a
+     * href="Calendar.html#resolution"> resolution rules</a> are applied.
+     * Therefore, the order of field setting matters.
+     *
+     * <p>In addition to the date-time parameters,
+     * the {@linkplain #setLocale(Locale) locale},
+     * {@linkplain #setTimeZone(TimeZone) time zone},
+     * {@linkplain #setWeekDefinition(int, int) week definition}, and
+     * {@linkplain #setLenient(boolean) leniency mode} parameters can be set.
+     *
+     * <p><b>Examples</b>
+     * <p>The following are sample usages. Sample code assumes that the
+     * {@code Calendar} constants are statically imported.
+     *
+     * <p>The following code produces a {@code Calendar} with date 2012-12-31
+     * (Gregorian) because Monday is the first day of a week with the <a
+     * href="GregorianCalendar.html#iso8601_compatible_setting"> ISO 8601
+     * compatible week parameters</a>.
+     * <pre>
+     *   Calendar cal = new Calendar.Builder().setCalendarType("iso8601")
+     *                        .setWeekDate(2013, 1, MONDAY).build();</pre>
+     * <p>The following code produces a Japanese {@code Calendar} with date
+     * 1989-01-08 (Gregorian), assuming that the default {@link Calendar#ERA ERA}
+     * is <em>Heisei</em> that started on that day.
+     * <pre>
+     *   Calendar cal = new Calendar.Builder().setCalendarType("japanese")
+     *                        .setFields(YEAR, 1, DAY_OF_YEAR, 1).build();</pre>
+     *
+     * @since 1.8
+     * @see Calendar#getInstance(TimeZone, Locale)
+     * @see Calendar#fields
+     */
+    private static class CalendarBuilder {
+        private static final int NFIELDS = FIELD_COUNT + 1; // +1 for WEEK_YEAR
+        private static final int WEEK_YEAR = FIELD_COUNT;
+
+        /**
+         * The corresponding fields[] has no value.
+         */
+        private static final int        UNSET = 0;
+
+        /**
+         * The value of the corresponding fields[] has been calculated internally.
+         */
+        private static final int        COMPUTED = 1;
+
+        /**
+         * The value of the corresponding fields[] has been set externally. Stamp
+         * values which are greater than 1 represents the (pseudo) time when the
+         * corresponding fields[] value was set.
+         */
+        private static final int        MINIMUM_USER_STAMP = 2;
+
+        private long instant;
+        // Calendar.stamp[] (lower half) and Calendar.fields[] (upper half) combined
+        private int[] fields;
+        // Pseudo timestamp starting from MINIMUM_USER_STAMP.
+        // (COMPUTED is used to indicate that the instant has been set.)
+        private int nextStamp;
+        // maxFieldIndex keeps the max index of fields which have been set.
+        // (WEEK_YEAR is never included.)
+        private int maxFieldIndex;
+        private String type;
+        private TimeZone zone;
+        private boolean lenient = true;
+        private Locale locale;
+        private int firstDayOfWeek, minimalDaysInFirstWeek;
+
+        /**
+         * Constructs a {@code Calendar.Builder}.
+         */
+        public CalendarBuilder() {
+        }
+
+        /**
+         * Sets the instant parameter to the given {@code instant} value that is
+         * a millisecond offset from <a href="Calendar.html#Epoch">the
+         * Epoch</a>.
+         *
+         * @param instant a millisecond offset from the Epoch
+         * @return this {@code Calendar.Builder}
+         * @throws IllegalStateException if any of the field parameters have
+         *                               already been set
+         * @see Calendar#setTime(Date)
+         * @see Calendar#setTimeInMillis(long)
+         * @see Calendar#time
+         */
+        public CalendarBuilder setInstant(long instant) {
+            if (fields != null) {
+                throw new IllegalStateException();
+            }
+            this.instant = instant;
+            nextStamp = COMPUTED;
+            return this;
+        }
+
+        /**
+         * Sets the instant parameter to the {@code instant} value given by a
+         * {@link Date}. This method is equivalent to a call to
+         * {@link #setInstant(long) setInstant(instant.getTime())}.
+         *
+         * @param instant a {@code Date} representing a millisecond offset from
+         *                the Epoch
+         * @return this {@code Calendar.Builder}
+         * @throws NullPointerException  if {@code instant} is {@code null}
+         * @throws IllegalStateException if any of the field parameters have
+         *                               already been set
+         * @see Calendar#setTime(Date)
+         * @see Calendar#setTimeInMillis(long)
+         * @see Calendar#time
+         */
+        public CalendarBuilder setInstant(Date instant) {
+            return setInstant(instant.getTime()); // NPE if instant == null
+        }
+
+        /**
+         * Sets the {@code field} parameter to the given {@code value}.
+         * {@code field} is an index to the {@link Calendar#fields}, such as
+         * {@link Calendar#DAY_OF_MONTH DAY_OF_MONTH}. Field value validation is
+         * not performed in this method. Any out of range values are either
+         * normalized in lenient mode or detected as an invalid value in
+         * non-lenient mode when building a {@code Calendar}.
+         *
+         * @param field an index to the {@code Calendar} fields
+         * @param value the field value
+         * @return this {@code Calendar.Builder}
+         * @throws IllegalArgumentException if {@code field} is invalid
+         * @throws IllegalStateException if the instant value has already been set,
+         *                      or if fields have been set too many
+         *                      (approximately {@link Integer#MAX_VALUE}) times.
+         * @see Calendar#set(int, int)
+         */
+        public CalendarBuilder set(int field, int value) {
+            // Note: WEEK_YEAR can't be set with this method.
+            if (field < 0 || field >= FIELD_COUNT) {
+                throw new IllegalArgumentException("field is invalid");
+            }
+            if (isInstantSet()) {
+                throw new IllegalStateException("instant has been set");
+            }
+            allocateFields();
+            internalSet(field, value);
+            return this;
+        }
+
+        /**
+         * Sets field parameters to their values given by
+         * {@code fieldValuePairs} that are pairs of a field and its value.
+         * For example,
+         * <pre>
+         *   setFeilds(Calendar.YEAR, 2013,
+         *             Calendar.MONTH, Calendar.DECEMBER,
+         *             Calendar.DAY_OF_MONTH, 23);</pre>
+         * is equivalent to the sequence of the following
+         * {@link #set(int, int) set} calls:
+         * <pre>
+         *   set(Calendar.YEAR, 2013)
+         *   .set(Calendar.MONTH, Calendar.DECEMBER)
+         *   .set(Calendar.DAY_OF_MONTH, 23);</pre>
+         *
+         * @param fieldValuePairs field-value pairs
+         * @return this {@code Calendar.Builder}
+         * @throws NullPointerException if {@code fieldValuePairs} is {@code null}
+         * @throws IllegalArgumentException if any of fields are invalid,
+         *             or if {@code fieldValuePairs.length} is an odd number.
+         * @throws IllegalStateException    if the instant value has been set,
+         *             or if fields have been set too many (approximately
+         *             {@link Integer#MAX_VALUE}) times.
+         */
+        public CalendarBuilder setFields(int... fieldValuePairs) {
+            int len = fieldValuePairs.length;
+            if ((len % 2) != 0) {
+                throw new IllegalArgumentException();
+            }
+            if (isInstantSet()) {
+                throw new IllegalStateException("instant has been set");
+            }
+            if ((nextStamp + len / 2) < 0) {
+                throw new IllegalStateException("stamp counter overflow");
+            }
+            allocateFields();
+            for (int i = 0; i < len; ) {
+                int field = fieldValuePairs[i++];
+                // Note: WEEK_YEAR can't be set with this method.
+                if (field < 0 || field >= FIELD_COUNT) {
+                    throw new IllegalArgumentException("field is invalid");
+                }
+                internalSet(field, fieldValuePairs[i++]);
+            }
+            return this;
+        }
+
+        /**
+         * Sets the date field parameters to the values given by {@code year},
+         * {@code month}, and {@code dayOfMonth}. This method is equivalent to
+         * a call to:
+         * <pre>
+         *   setFields(Calendar.YEAR, year,
+         *             Calendar.MONTH, month,
+         *             Calendar.DAY_OF_MONTH, dayOfMonth);</pre>
+         *
+         * @param year       the {@link Calendar#YEAR YEAR} value
+         * @param month      the {@link Calendar#MONTH MONTH} value
+         *                   (the month numbering is <em>0-based</em>).
+         * @param dayOfMonth the {@link Calendar#DAY_OF_MONTH DAY_OF_MONTH} value
+         * @return this {@code Calendar.Builder}
+         */
+        public CalendarBuilder setDate(int year, int month, int dayOfMonth) {
+            return setFields(Calendar.YEAR, year, Calendar.MONTH, month,
+                             Calendar.DAY_OF_MONTH, dayOfMonth);
+        }
+
+        /**
+         * Sets the time of day field parameters to the values given by
+         * {@code hourOfDay}, {@code minute}, and {@code second}. This method is
+         * equivalent to a call to:
+         * <pre>
+         *   setTimeOfDay(hourOfDay, minute, second, 0);</pre>
+         *
+         * @param hourOfDay the {@link Calendar#HOUR_OF_DAY HOUR_OF_DAY} value
+         *                  (24-hour clock)
+         * @param minute    the {@link Calendar#MINUTE MINUTE} value
+         * @param second    the {@link Calendar#SECOND SECOND} value
+         * @return this {@code Calendar.Builder}
+         */
+        public CalendarBuilder setTimeOfDay(int hourOfDay, int minute, int second) {
+            return setTimeOfDay(hourOfDay, minute, second, 0);
+        }
+
+        /**
+         * Sets the time of day field parameters to the values given by
+         * {@code hourOfDay}, {@code minute}, {@code second}, and
+         * {@code millis}. This method is equivalent to a call to:
+         * <pre>
+         *   setFields(Calendar.HOUR_OF_DAY, hourOfDay,
+         *             Calendar.MINUTE, minute,
+         *             Calendar.SECOND, second,
+         *             Calendar.MILLISECOND, millis);</pre>
+         *
+         * @param hourOfDay the {@link Calendar#HOUR_OF_DAY HOUR_OF_DAY} value
+         *                  (24-hour clock)
+         * @param minute    the {@link Calendar#MINUTE MINUTE} value
+         * @param second    the {@link Calendar#SECOND SECOND} value
+         * @param millis    the {@link Calendar#MILLISECOND MILLISECOND} value
+         * @return this {@code Calendar.Builder}
+         */
+        public CalendarBuilder setTimeOfDay(int hourOfDay, int minute, int second, int millis) {
+            return setFields(Calendar.HOUR_OF_DAY, hourOfDay, Calendar.MINUTE, minute,
+                             Calendar.SECOND, second, Calendar.MILLISECOND, millis);
+        }
+
+        /**
+         * Sets the week-based date parameters to the values with the given
+         * date specifiers - week year, week of year, and day of week.
+         *
+         * <p>If the specified calendar doesn't support week dates, the
+         * {@link #build() build} method will throw an {@link IllegalArgumentException}.
+         *
+         * @param weekYear   the week year
+         * @param weekOfYear the week number based on {@code weekYear}
+         * @param dayOfWeek  the day of week value: one of the constants
+         *     for the {@link Calendar#DAY_OF_WEEK DAY_OF_WEEK} field:
+         *     {@link Calendar#SUNDAY SUNDAY}, ..., {@link Calendar#SATURDAY SATURDAY}.
+         * @return this {@code Calendar.Builder}
+         * @see Calendar#setWeekDate(int, int, int)
+         * @see Calendar#isWeekDateSupported()
+         */
+        public CalendarBuilder setWeekDate(int weekYear, int weekOfYear, int dayOfWeek) {
+            allocateFields();
+            internalSet(WEEK_YEAR, weekYear);
+            internalSet(Calendar.WEEK_OF_YEAR, weekOfYear);
+            internalSet(Calendar.DAY_OF_WEEK, dayOfWeek);
+            return this;
+        }
+
+        /**
+         * Sets the time zone parameter to the given {@code zone}. If no time
+         * zone parameter is given to this {@code Caledar.Builder}, the
+         * {@linkplain TimeZone#getDefault() default
+         * <code>TimeZone</code>} will be used in the {@link #build() build}
+         * method.
+         *
+         * @param zone the {@link TimeZone}
+         * @return this {@code Calendar.Builder}
+         * @throws NullPointerException if {@code zone} is {@code null}
+         * @see Calendar#setTimeZone(TimeZone)
+         */
+        public CalendarBuilder setTimeZone(TimeZone zone) {
+            if (zone == null) {
+                throw new NullPointerException();
+            }
+            this.zone = zone;
+            return this;
+        }
+
+        /**
+         * Sets the lenient mode parameter to the value given by {@code lenient}.
+         * If no lenient parameter is given to this {@code Calendar.Builder},
+         * lenient mode will be used in the {@link #build() build} method.
+         *
+         * @param lenient {@code true} for lenient mode;
+         *                {@code false} for non-lenient mode
+         * @return this {@code Calendar.Builder}
+         * @see Calendar#setLenient(boolean)
+         */
+        public CalendarBuilder setLenient(boolean lenient) {
+            this.lenient = lenient;
+            return this;
+        }
+
+        /**
+         * Sets the calendar type parameter to the given {@code type}. The
+         * calendar type given by this method has precedence over any explicit
+         * or implicit calendar type given by the
+         * {@linkplain #setLocale(Locale) locale}.
+         *
+         * <p>In addition to the available calendar types returned by the
+         * {@link Calendar#getAvailableCalendarTypes() Calendar.getAvailableCalendarTypes}
+         * method, {@code "gregorian"} and {@code "iso8601"} as aliases of
+         * {@code "gregory"} can be used with this method.
+         *
+         * @param type the calendar type
+         * @return this {@code Calendar.Builder}
+         * @throws NullPointerException if {@code type} is {@code null}
+         * @throws IllegalArgumentException if {@code type} is unknown
+         * @throws IllegalStateException if another calendar type has already been set
+         * @see Calendar#getCalendarType()
+         * @see Calendar#getAvailableCalendarTypes()
+         */
+        public CalendarBuilder setCalendarType(String type) {
+            if (type.equals("gregorian")) { // NPE if type == null
+                type = "gregory";
+            }
+            if (!AvailableCalendarTypes.SET.contains(type)
+                    && !type.equals("iso8601")) {
+                throw new IllegalArgumentException("unknown calendar type: " + type);
+            }
+            if (this.type == null) {
+                this.type = type;
+            } else {
+                if (!this.type.equals(type)) {
+                    throw new IllegalStateException("calendar type override");
+                }
+            }
+            return this;
+        }
+
+        /**
+         * Sets the locale parameter to the given {@code locale}. If no locale
+         * is given to this {@code Calendar.Builder}, the {@linkplain
+         * Locale#getDefault(Locale.Category) default <code>Locale</code>}
+         * for {@link Locale.Category#FORMAT} will be used.
+         *
+         * <p>If no calendar type is explicitly given by a call to the
+         * {@link #setCalendarType(String) setCalendarType} method,
+         * the {@code Locale} value is used to determine what type of
+         * {@code Calendar} to be built.
+         *
+         * <p>If no week definition parameters are explicitly given by a call to
+         * the {@link #setWeekDefinition(int,int) setWeekDefinition} method, the
+         * {@code Locale}'s default values are used.
+         *
+         * @param locale the {@link Locale}
+         * @throws NullPointerException if {@code locale} is {@code null}
+         * @return this {@code Calendar.Builder}
+         * @see Calendar#getInstance(Locale)
+         */
+        public CalendarBuilder setLocale(Locale locale) {
+            if (locale == null) {
+                throw new NullPointerException();
+            }
+            this.locale = locale;
+            return this;
+        }
+
+        /**
+         * Sets the week definition parameters to the values given by
+         * {@code firstDayOfWeek} and {@code minimalDaysInFirstWeek} that are
+         * used to determine the <a href="Calendar.html#First_Week">first
+         * week</a> of a year. The parameters given by this method have
+         * precedence over the default values given by the
+         * {@linkplain #setLocale(Locale) locale}.
+         *
+         * @param firstDayOfWeek the first day of a week; one of
+         *                       {@link Calendar#SUNDAY} to {@link Calendar#SATURDAY}
+         * @param minimalDaysInFirstWeek the minimal number of days in the first
+         *                               week (1..7)
+         * @return this {@code Calendar.Builder}
+         * @throws IllegalArgumentException if {@code firstDayOfWeek} or
+         *                                  {@code minimalDaysInFirstWeek} is invalid
+         * @see Calendar#getFirstDayOfWeek()
+         * @see Calendar#getMinimalDaysInFirstWeek()
+         */
+        public CalendarBuilder setWeekDefinition(int firstDayOfWeek, int minimalDaysInFirstWeek) {
+            if (!isValidWeekParameter(firstDayOfWeek)
+                    || !isValidWeekParameter(minimalDaysInFirstWeek)) {
+                throw new IllegalArgumentException();
+            }
+            this.firstDayOfWeek = firstDayOfWeek;
+            this.minimalDaysInFirstWeek = minimalDaysInFirstWeek;
+            return this;
+        }
+
+        /**
+         * Returns a {@code Calendar} built from the parameters set by the
+         * setter methods. The calendar type given by the {@link #setCalendarType(String)
+         * setCalendarType} method or the {@linkplain #setLocale(Locale) locale} is
+         * used to determine what {@code Calendar} to be created. If no explicit
+         * calendar type is given, the locale's default calendar is created.
+         *
+         * <p>If the calendar type is {@code "iso8601"}, the
+         * {@linkplain GregorianCalendar#setGregorianChange(Date) Gregorian change date}
+         * of a {@link GregorianCalendar} is set to {@code Date(Long.MIN_VALUE)}
+         * to be the <em>proleptic</em> Gregorian calendar. Its week definition
+         * parameters are also set to be <a
+         * href="GregorianCalendar.html#iso8601_compatible_setting">compatible
+         * with the ISO 8601 standard</a>. Note that the
+         * {@link GregorianCalendar#getCalendarType() getCalendarType} method of
+         * a {@code GregorianCalendar} created with {@code "iso8601"} returns
+         * {@code "gregory"}.
+         *
+         * <p>The default values are used for locale and time zone if these
+         * parameters haven't been given explicitly.
+         *
+         * <p>Any out of range field values are either normalized in lenient
+         * mode or detected as an invalid value in non-lenient mode.
+         *
+         * @return a {@code Calendar} built with parameters of this {@code
+         *         Calendar.Builder}
+         * @throws IllegalArgumentException if the calendar type is unknown, or
+         *             if any invalid field values are given in non-lenient mode, or
+         *             if a week date is given for the calendar type that doesn't
+         *             support week dates.
+         * @see Calendar#getInstance(TimeZone, Locale)
+         * @see Locale#getDefault(Locale.Category)
+         * @see TimeZone#getDefault()
+         */
+        public Calendar build() {
+            if (locale == null) {
+                locale = Locale.getDefault();
+            }
+            if (zone == null) {
+                zone = TimeZone.getDefault();
+            }
+            Calendar cal;
+            JavaUtilCalendarAccess access = SharedSecrets.getJavaUtilCalendarAccess();
+            if (type == null) {
+                type = locale.getUnicodeLocaleType("ca");
+            }
+            if (type == null) {
+                if (locale.getCountry() == "TH"
+                    && locale.getLanguage() == "th") {
+                    type = "buddhist";
+                } else {
+                    type = "gregory";
+                }
+            }
+            switch (type) {
+            case "gregory":
+                cal = access.createCalendar(zone, locale);
+                break;
+            case "iso8601":
+                GregorianCalendar gcal = access.createCalendar(zone, locale);
+                // make gcal a proleptic Gregorian
+                gcal.setGregorianChange(new Date(Long.MIN_VALUE));
+                // and week definition to be compatible with ISO 8601
+                setWeekDefinition(Calendar.MONDAY, 4);
+                cal = gcal;
+                break;
+            default:
+                throw new IllegalArgumentException("unknown calendar type: " + type);
+            }
+            cal.setLenient(lenient);
+            if (firstDayOfWeek != 0) {
+                cal.setFirstDayOfWeek(firstDayOfWeek);
+                cal.setMinimalDaysInFirstWeek(minimalDaysInFirstWeek);
+            }
+            if (isInstantSet()) {
+                cal.setTimeInMillis(instant);
+                access.complete(cal);
+                return cal;
+            }
+
+            if (fields != null) {
+                boolean weekDate = isSet(WEEK_YEAR)
+                                       && fields[WEEK_YEAR] > fields[Calendar.YEAR];
+                if (weekDate && !cal.isWeekDateSupported()) {
+                    throw new IllegalArgumentException("week date is unsupported by " + type);
+                }
+
+                // Set the fields from the min stamp to the max stamp so that
+                // the fields resolution works in the Calendar.
+                for (int stamp = MINIMUM_USER_STAMP; stamp < nextStamp; stamp++) {
+                    for (int index = 0; index <= maxFieldIndex; index++) {
+                        if (fields[index] == stamp) {
+                            cal.set(index, fields[NFIELDS + index]);
+                            break;
+                        }
+                    }
+                }
+
+                if (weekDate) {
+                    int weekOfYear = isSet(Calendar.WEEK_OF_YEAR) ? fields[NFIELDS + Calendar.WEEK_OF_YEAR] : 1;
+                    int dayOfWeek = isSet(Calendar.DAY_OF_WEEK)
+                                    ? fields[NFIELDS + Calendar.DAY_OF_WEEK] : cal.getFirstDayOfWeek();
+                    cal.setWeekDate(fields[NFIELDS + WEEK_YEAR], weekOfYear, dayOfWeek);
+                }
+                access.complete(cal);
+            }
+
+            return cal;
+        }
+
+        private void allocateFields() {
+            if (fields == null) {
+                fields = new int[NFIELDS * 2];
+                nextStamp = MINIMUM_USER_STAMP;
+                maxFieldIndex = -1;
+            }
+        }
+
+        private void internalSet(int field, int value) {
+            fields[field] = nextStamp++;
+            if (nextStamp < 0) {
+                throw new IllegalStateException("stamp counter overflow");
+            }
+            fields[NFIELDS + field] = value;
+            if (field > maxFieldIndex && field < WEEK_YEAR) {
+                maxFieldIndex = field;
+            }
+        }
+
+        private boolean isInstantSet() {
+            return nextStamp == COMPUTED;
+        }
+
+        private boolean isSet(int index) {
+            return fields != null && fields[index] > UNSET;
+        }
+
+        private boolean isValidWeekParameter(int value) {
+            return value > 0 && value <= 7;
+        }
+    }
+
+    private static class AvailableCalendarTypes {
+        private static final Set<String> SET;
+        static {
+            Set<String> set = new HashSet<>(3);
+            set.add("gregory");
+            set.add("buddhist");
+            set.add("japanese");
+            SET = Collections.unmodifiableSet(set);
+        }
+        private AvailableCalendarTypes() {
+        }
+    }
+
+}
--- a/src/share/classes/sun/security/util/SignatureFileVerifier.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/util/SignatureFileVerifier.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -28,25 +28,23 @@
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.security.CodeSigner;
-import java.security.CryptoPrimitive;
+import java.security.GeneralSecurityException;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.security.SignatureException;
+import java.security.Timestamp;
 import java.security.cert.CertPath;
 import java.security.cert.X509Certificate;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
 
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
-import java.util.Set;
 import java.util.jar.Attributes;
 import java.util.jar.JarException;
 import java.util.jar.JarFile;
@@ -64,9 +62,6 @@
     /* Are we debugging ? */
     private static final Debug debug = Debug.getInstance("jar");
 
-    private static final Set<CryptoPrimitive> DIGEST_PRIMITIVE_SET =
-            Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.MESSAGE_DIGEST));
-
     private static final DisabledAlgorithmConstraints JAR_DISABLED_CHECK =
             new DisabledAlgorithmConstraints(
                     DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS);
@@ -81,7 +76,7 @@
     private PKCS7 block;
 
     /** the raw bytes of the .SF file */
-    private byte sfBytes[];
+    private byte[] sfBytes;
 
     /** the name of the signature block file, uppercased and without
      *  the extension (.DSA/.RSA/.EC)
@@ -100,6 +95,14 @@
     /* for generating certpath objects */
     private CertificateFactory certificateFactory = null;
 
+    /** Algorithms that have been checked if they are weak. */
+    private Map<String, Boolean> permittedAlgs= new HashMap<>();
+
+    /** TSA timestamp of signed jar.  The newest timestamp is used.  If there
+     *  was no TSA timestamp used when signed, current time is used ("null").
+     */
+    private Timestamp timestamp = null;
+
     /**
      * Create the named SignatureFileVerifier.
      *
@@ -110,7 +113,7 @@
     public SignatureFileVerifier(ArrayList<CodeSigner[]> signerCache,
                                  ManifestDigester md,
                                  String name,
-                                 byte rawBytes[])
+                                 byte[] rawBytes)
         throws IOException, CertificateException
     {
         // new PKCS7() calls CertificateFactory.getInstance()
@@ -124,7 +127,7 @@
         } finally {
             Providers.stopJarVerification(obj);
         }
-        this.name = name.substring(0, name.lastIndexOf("."))
+        this.name = name.substring(0, name.lastIndexOf('.'))
                                                    .toUpperCase(Locale.ENGLISH);
         this.md = md;
         this.signerCache = signerCache;
@@ -155,7 +158,7 @@
      * used to set the raw bytes of the .SF file when it
      * is external to the signature block file.
      */
-    public void setSignatureFile(byte sfBytes[])
+    public void setSignatureFile(byte[] sfBytes)
     {
         this.sfBytes = sfBytes;
     }
@@ -171,11 +174,10 @@
      */
     public static boolean isBlockOrSF(String s) {
         // we currently only support DSA and RSA PKCS7 blocks
-        if (s.endsWith(".SF") || s.endsWith(".DSA") ||
-                s.endsWith(".RSA") || s.endsWith(".EC")) {
-            return true;
-        }
-        return false;
+        return s.endsWith(".SF")
+            || s.endsWith(".DSA")
+            || s.endsWith(".RSA")
+            || s.endsWith(".EC");
     }
 
     /**
@@ -185,7 +187,7 @@
      * unknown signature related files (those starting with SIG- with
      * an optional [A-Z0-9]{1,3} extension right inside META-INF).
      *
-     * @param s file name
+     * @param name file name
      * @return true if the input file name is signature related
      */
     public static boolean isSigningRelated(String name) {
@@ -201,7 +203,7 @@
             return true;
         } else if (name.startsWith("SIG-")) {
             // check filename extension
-            // see https://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html#Digital_Signatures
+            // see http://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html#Digital_Signatures
             // for what filename extensions are legal
             int extIndex = name.lastIndexOf('.');
             if (extIndex != -1) {
@@ -226,17 +228,10 @@
 
     /** get digest from cache */
 
-    private MessageDigest getDigest(String algorithm) throws SignatureException {
-        // check that algorithm is not restricted
-        if (!JAR_DISABLED_CHECK.permits(DIGEST_PRIMITIVE_SET, algorithm, null)) {
-            SignatureException e =
-                    new SignatureException("SignatureFile check failed. " +
-                            "Disabled algorithm used: " + algorithm);
-            throw e;
-        }
-
+    private MessageDigest getDigest(String algorithm)
+            throws SignatureException {
         if (createdDigests == null)
-            createdDigests = new HashMap<String, MessageDigest>();
+            createdDigests = new HashMap<>();
 
         MessageDigest digest = createdDigests.get(algorithm);
 
@@ -307,6 +302,27 @@
         if (newSigners == null)
             return;
 
+        /*
+         * Look for the latest timestamp in the signature block.  If an entry
+         * has no timestamp, use current time (aka null).
+         */
+        for (CodeSigner s: newSigners) {
+            if (debug != null) {
+                debug.println("Gathering timestamp for:  " + s.toString());
+            }
+            if (s.getTimestamp() == null) {
+                timestamp = null;
+                break;
+            } else if (timestamp == null) {
+                timestamp = s.getTimestamp();
+            } else {
+                if (timestamp.getTimestamp().before(
+                        s.getTimestamp().getTimestamp())) {
+                    timestamp = s.getTimestamp();
+                }
+            }
+        }
+
         Iterator<Map.Entry<String,Attributes>> entries =
                                 sf.getEntries().entrySet().iterator();
 
@@ -350,6 +366,68 @@
     }
 
     /**
+     * Check if algorithm is permitted using the permittedAlgs Map.
+     * If the algorithm is not in the map, check against disabled algorithms and
+     * store the result. If the algorithm is in the map use that result.
+     * False is returned for weak algorithm, true for good algorithms.
+     */
+    boolean permittedCheck(String key, String algorithm) {
+        Boolean permitted = permittedAlgs.get(algorithm);
+        if (permitted == null) {
+            try {
+                JAR_DISABLED_CHECK.permits(algorithm,
+                        new ConstraintsParameters(timestamp));
+            } catch(GeneralSecurityException e) {
+                permittedAlgs.put(algorithm, Boolean.FALSE);
+                permittedAlgs.put(key.toUpperCase(), Boolean.FALSE);
+                if (debug != null) {
+                    if (e.getMessage() != null) {
+                        debug.println(key + ":  " + e.getMessage());
+                    } else {
+                        debug.println(key + ":  " + algorithm +
+                                " was disabled, no exception msg given.");
+                        e.printStackTrace();
+                    }
+                }
+                return false;
+            }
+
+            permittedAlgs.put(algorithm, Boolean.TRUE);
+            return true;
+        }
+
+        // Algorithm has already been checked, return the value from map.
+        return permitted.booleanValue();
+    }
+
+    /**
+     * With a given header (*-DIGEST*), return a string that lists all the
+     * algorithms associated with the header.
+     * If there are none, return "Unknown Algorithm".
+     */
+    String getWeakAlgorithms(String header) {
+        String w = "";
+        try {
+            for (String key : permittedAlgs.keySet()) {
+                if (key.endsWith(header)) {
+                    w += key.substring(0, key.length() - header.length()) + " ";
+                }
+            }
+        } catch (RuntimeException e) {
+            w = "Unknown Algorithm(s).  Error processing " + header + ".  " +
+                    e.getMessage();
+        }
+
+        // This means we have an error in finding weak algorithms, run in
+        // debug mode to see permittedAlgs map's values.
+        if (w.length() == 0) {
+            return "Unknown Algorithm(s)";
+        }
+
+        return w;
+    }
+
+    /**
      * See if the whole manifest was signed.
      */
     private boolean verifyManifestHash(Manifest sf,
@@ -360,6 +438,10 @@
     {
         Attributes mattr = sf.getMainAttributes();
         boolean manifestSigned = false;
+        // If only weak algorithms are used.
+        boolean weakAlgs = true;
+        // If a "*-DIGEST-MANIFEST" entry is found.
+        boolean validEntry = false;
 
         // go through all the attributes and process *-Digest-Manifest entries
         for (Map.Entry<Object,Object> se : mattr.entrySet()) {
@@ -369,6 +451,16 @@
             if (key.toUpperCase(Locale.ENGLISH).endsWith("-DIGEST-MANIFEST")) {
                 // 16 is length of "-Digest-Manifest"
                 String algorithm = key.substring(0, key.length()-16);
+                validEntry = true;
+
+                // Check if this algorithm is permitted, skip if false.
+                if (!permittedCheck(key, algorithm)) {
+                    continue;
+                }
+
+                // A non-weak algorithm was used, any weak algorithms found do
+                // not need to be reported.
+                weakAlgs = false;
 
                 manifestDigests.add(key);
                 manifestDigests.add(se.getValue());
@@ -379,15 +471,14 @@
                         decoder.decodeBuffer((String)se.getValue());
 
                     if (debug != null) {
-                     debug.println("Signature File: Manifest digest " +
-                                          digest.getAlgorithm());
-                     debug.println( "  sigfile  " + toHex(expectedHash));
-                     debug.println( "  computed " + toHex(computedHash));
-                     debug.println();
+                        debug.println("Signature File: Manifest digest " +
+                                algorithm);
+                        debug.println( "  sigfile  " + toHex(expectedHash));
+                        debug.println( "  computed " + toHex(computedHash));
+                        debug.println();
                     }
 
-                    if (MessageDigest.isEqual(computedHash,
-                                              expectedHash)) {
+                    if (MessageDigest.isEqual(computedHash, expectedHash)) {
                         manifestSigned = true;
                     } else {
                         //XXX: we will continue and verify each section
@@ -395,16 +486,34 @@
                 }
             }
         }
+
+        if (debug != null) {
+            debug.println("PermittedAlgs mapping: ");
+            for (String key : permittedAlgs.keySet()) {
+                debug.println(key + " : " +
+                        permittedAlgs.get(key).toString());
+            }
+        }
+
+        // If there were only weak algorithms entries used, throw an exception.
+        if (validEntry && weakAlgs) {
+            throw new SignatureException("Manifest hash check failed " +
+                    "(DIGEST-MANIFEST). Disabled algorithm(s) used: " +
+                    getWeakAlgorithms("-DIGEST-MANIFEST"));
+        }
         return manifestSigned;
     }
 
-    private boolean verifyManifestMainAttrs(Manifest sf,
-                                        ManifestDigester md,
-                                        BASE64Decoder decoder)
+    private boolean verifyManifestMainAttrs(Manifest sf, ManifestDigester md,
+                                            BASE64Decoder decoder)
          throws IOException, SignatureException
     {
         Attributes mattr = sf.getMainAttributes();
         boolean attrsVerified = true;
+        // If only weak algorithms are used.
+        boolean weakAlgs = true;
+        // If a ATTR_DIGEST entry is found.
+        boolean validEntry = false;
 
         // go through all the attributes and process
         // digest entries for the manifest main attributes
@@ -414,6 +523,16 @@
             if (key.toUpperCase(Locale.ENGLISH).endsWith(ATTR_DIGEST)) {
                 String algorithm =
                         key.substring(0, key.length() - ATTR_DIGEST.length());
+                validEntry = true;
+
+                // Check if this algorithm is permitted, skip if false.
+                if (!permittedCheck(key, algorithm)) {
+                    continue;
+                }
+
+                // A non-weak algorithm was used, any weak algorithms found do
+                // not need to be reported.
+                weakAlgs = false;
 
                 MessageDigest digest = getDigest(algorithm);
                 if (digest != null) {
@@ -432,8 +551,7 @@
                      debug.println();
                     }
 
-                    if (MessageDigest.isEqual(computedHash,
-                                              expectedHash)) {
+                    if (MessageDigest.isEqual(computedHash, expectedHash)) {
                         // good
                     } else {
                         // we will *not* continue and verify each section
@@ -449,6 +567,22 @@
             }
         }
 
+        if (debug != null) {
+            debug.println("PermittedAlgs mapping: ");
+            for (String key : permittedAlgs.keySet()) {
+                debug.println(key + " : " +
+                        permittedAlgs.get(key).toString());
+            }
+        }
+
+        // If there were only weak algorithms entries used, throw an exception.
+        if (validEntry && weakAlgs) {
+            throw new SignatureException("Manifest Main Attribute check " +
+                    "failed (" + ATTR_DIGEST + ").  " +
+                    "Disabled algorithm(s) used: " +
+                    getWeakAlgorithms(ATTR_DIGEST));
+        }
+
         // this method returns 'true' if either:
         //      . manifest main attributes were not signed, or
         //      . manifest main attributes were signed and verified
@@ -472,6 +606,10 @@
     {
         boolean oneDigestVerified = false;
         ManifestDigester.Entry mde = md.get(name,block.isOldStyle());
+        // If only weak algorithms are used.
+        boolean weakAlgs = true;
+        // If a "*-DIGEST" entry is found.
+        boolean validEntry = false;
 
         if (mde == null) {
             throw new SecurityException(
@@ -479,8 +617,7 @@
         }
 
         if (sfAttr != null) {
-
-            //sun.misc.HexDumpEncoder hex = new sun.misc.HexDumpEncoder();
+            //sun.security.util.HexDumpEncoder hex = new sun.security.util.HexDumpEncoder();
             //hex.encodeBuffer(data, System.out);
 
             // go through all the attributes and process *-Digest entries
@@ -490,6 +627,16 @@
                 if (key.toUpperCase(Locale.ENGLISH).endsWith("-DIGEST")) {
                     // 7 is length of "-Digest"
                     String algorithm = key.substring(0, key.length()-7);
+                    validEntry = true;
+
+                    // Check if this algorithm is permitted, skip if false.
+                    if (!permittedCheck(key, algorithm)) {
+                        continue;
+                    }
+
+                    // A non-weak algorithm was used, any weak algorithms found do
+                    // not need to be reported.
+                    weakAlgs = false;
 
                     MessageDigest digest = getDigest(algorithm);
 
@@ -540,6 +687,22 @@
                 }
             }
         }
+
+        if (debug != null) {
+            debug.println("PermittedAlgs mapping: ");
+            for (String key : permittedAlgs.keySet()) {
+                debug.println(key + " : " +
+                        permittedAlgs.get(key).toString());
+            }
+        }
+
+        // If there were only weak algorithms entries used, throw an exception.
+        if (validEntry && weakAlgs) {
+            throw new SignatureException("Manifest Main Attribute check " +
+                    "failed (DIGEST).  Disabled algorithm(s) used: " +
+                    getWeakAlgorithms("DIGEST"));
+        }
+
         return oneDigestVerified;
     }
 
@@ -548,7 +711,7 @@
      * CodeSigner objects. We do this only *once* for a given
      * signature block file.
      */
-    private CodeSigner[] getSigners(SignerInfo infos[], PKCS7 block)
+    private CodeSigner[] getSigners(SignerInfo[] infos, PKCS7 block)
         throws IOException, NoSuchAlgorithmException, SignatureException,
             CertificateException {
 
@@ -560,7 +723,7 @@
             ArrayList<X509Certificate> chain = info.getCertificateChain(block);
             CertPath certChain = certificateFactory.generateCertPath(chain);
             if (signers == null) {
-                signers = new ArrayList<CodeSigner>();
+                signers = new ArrayList<>();
             }
             // Append the new code signer
             signers.add(new CodeSigner(certChain, info.getTimestamp()));
@@ -589,7 +752,7 @@
 
     static String toHex(byte[] data) {
 
-        StringBuffer sb = new StringBuffer(data.length*2);
+        StringBuilder sb = new StringBuilder(data.length*2);
 
         for (int i=0; i<data.length; i++) {
             sb.append(hexc[(data[i] >>4) & 0x0f]);
--- a/src/share/classes/sun/security/validator/PKIXValidator.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/validator/PKIXValidator.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2017, 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
@@ -33,10 +33,11 @@
 import javax.security.auth.x500.X500Principal;
 import sun.security.action.GetBooleanAction;
 import sun.security.provider.certpath.AlgorithmChecker;
+import sun.security.provider.certpath.PKIXExtendedParameters;
 
 /**
  * Validator implementation built on the PKIX CertPath API. This
- * implementation will be emphasized going forward.<p>
+ * implementation will be emphasized going forward.
  * <p>
  * Note that the validate() implementation tries to use a PKIX validator
  * if that appears possible and a PKIX builder otherwise. This increases
@@ -208,13 +209,22 @@
                 ("null or zero-length certificate chain");
         }
 
-        // add  new algorithm constraints checker
-        PKIXBuilderParameters pkixParameters =
-                    (PKIXBuilderParameters) parameterTemplate.clone();
-        AlgorithmChecker algorithmChecker = null;
+        // Use PKIXExtendedParameters for timestamp and variant additions
+        PKIXBuilderParameters pkixParameters = null;
+        try {
+            pkixParameters = new PKIXExtendedParameters(
+                    (PKIXBuilderParameters) parameterTemplate.clone(),
+                    (parameter instanceof Timestamp) ?
+                            (Timestamp) parameter : null,
+                    variant);
+        } catch (InvalidAlgorithmParameterException e) {
+            // ignore exception
+        }
+
+        // add a new algorithm constraints checker
         if (constraints != null) {
-            algorithmChecker = new AlgorithmChecker(constraints);
-            pkixParameters.addCertPathChecker(algorithmChecker);
+            pkixParameters.addCertPathChecker(
+                    new AlgorithmChecker(constraints, null, variant));
         }
 
         if (TRY_VALIDATOR) {
--- a/src/share/classes/sun/security/validator/SimpleValidator.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/validator/SimpleValidator.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2017, 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
@@ -34,6 +34,7 @@
 import javax.security.auth.x500.X500Principal;
 
 import sun.security.x509.X509CertImpl;
+import sun.security.x509.KeyIdentifier;
 import sun.security.x509.NetscapeCertTypeExtension;
 import sun.security.util.DerValue;
 import sun.security.util.DerInputStream;
@@ -152,12 +153,14 @@
 
         // create default algorithm constraints checker
         TrustAnchor anchor = new TrustAnchor(anchorCert, null);
-        AlgorithmChecker defaultAlgChecker = new AlgorithmChecker(anchor);
+        AlgorithmChecker defaultAlgChecker =
+                new AlgorithmChecker(anchor, variant);
 
         // create application level algorithm constraints checker
         AlgorithmChecker appAlgChecker = null;
         if (constraints != null) {
-            appAlgChecker = new AlgorithmChecker(anchor, constraints);
+            appAlgChecker = new AlgorithmChecker(anchor, constraints, null,
+                    null, variant);
         }
 
         // verify top down, starting at the certificate issued by
--- a/src/share/classes/sun/security/x509/PKIXExtensions.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/x509/PKIXExtensions.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -49,34 +49,39 @@
  */
 public class PKIXExtensions {
     // The object identifiers
-    private static final int AuthorityKey_data [] = { 2, 5, 29, 35 };
-    private static final int SubjectKey_data [] = { 2, 5, 29, 14 };
-    private static final int KeyUsage_data [] = { 2, 5, 29, 15 };
-    private static final int PrivateKeyUsage_data [] = { 2, 5, 29, 16 };
-    private static final int CertificatePolicies_data [] = { 2, 5, 29, 32 };
-    private static final int PolicyMappings_data [] = { 2, 5, 29, 33 };
-    private static final int SubjectAlternativeName_data [] = { 2, 5, 29, 17 };
-    private static final int IssuerAlternativeName_data [] = { 2, 5, 29, 18 };
-    private static final int SubjectDirectoryAttributes_data [] = { 2, 5, 29, 9 };
-    private static final int BasicConstraints_data [] = { 2, 5, 29, 19 };
-    private static final int NameConstraints_data [] = { 2, 5, 29, 30 };
-    private static final int PolicyConstraints_data [] = { 2, 5, 29, 36 };
-    private static final int CRLDistributionPoints_data [] = { 2, 5, 29, 31 };
-    private static final int CRLNumber_data [] = { 2, 5, 29, 20 };
-    private static final int IssuingDistributionPoint_data [] = { 2, 5, 29, 28 };
-    private static final int DeltaCRLIndicator_data [] = { 2, 5, 29, 27 };
-    private static final int ReasonCode_data [] = { 2, 5, 29, 21 };
-    private static final int HoldInstructionCode_data [] = { 2, 5, 29, 23 };
-    private static final int InvalidityDate_data [] = { 2, 5, 29, 24 };
-    private static final int ExtendedKeyUsage_data [] = { 2, 5, 29, 37 };
-    private static final int InhibitAnyPolicy_data [] = { 2, 5, 29, 54 };
-    private static final int CertificateIssuer_data [] = { 2, 5, 29, 29 };
-    private static final int AuthInfoAccess_data [] = { 1, 3, 6, 1, 5, 5, 7, 1, 1};
-    private static final int SubjectInfoAccess_data [] = { 1, 3, 6, 1, 5, 5, 7, 1, 11};
-    private static final int FreshestCRL_data [] = { 2, 5, 29, 46 };
-    private static final int OCSPNoCheck_data [] = { 1, 3, 6, 1, 5, 5, 7,
+    private static final int[] AuthorityKey_data = { 2, 5, 29, 35 };
+    private static final int[] SubjectKey_data = { 2, 5, 29, 14 };
+    private static final int[] KeyUsage_data = { 2, 5, 29, 15 };
+    private static final int[] PrivateKeyUsage_data = { 2, 5, 29, 16 };
+    private static final int[] CertificatePolicies_data = { 2, 5, 29, 32 };
+    private static final int[] PolicyMappings_data = { 2, 5, 29, 33 };
+    private static final int[] SubjectAlternativeName_data = { 2, 5, 29, 17 };
+    private static final int[] IssuerAlternativeName_data = { 2, 5, 29, 18 };
+    private static final int[] SubjectDirectoryAttributes_data = { 2, 5, 29, 9 };
+    private static final int[] BasicConstraints_data = { 2, 5, 29, 19 };
+    private static final int[] NameConstraints_data = { 2, 5, 29, 30 };
+    private static final int[] PolicyConstraints_data = { 2, 5, 29, 36 };
+    private static final int[] CRLDistributionPoints_data = { 2, 5, 29, 31 };
+    private static final int[] CRLNumber_data = { 2, 5, 29, 20 };
+    private static final int[] IssuingDistributionPoint_data = { 2, 5, 29, 28 };
+    private static final int[] DeltaCRLIndicator_data = { 2, 5, 29, 27 };
+    private static final int[] ReasonCode_data = { 2, 5, 29, 21 };
+    private static final int[] HoldInstructionCode_data = { 2, 5, 29, 23 };
+    private static final int[] InvalidityDate_data = { 2, 5, 29, 24 };
+    private static final int[] ExtendedKeyUsage_data = { 2, 5, 29, 37 };
+    private static final int[] InhibitAnyPolicy_data = { 2, 5, 29, 54 };
+    private static final int[] CertificateIssuer_data = { 2, 5, 29, 29 };
+    private static final int[] AuthInfoAccess_data = { 1, 3, 6, 1, 5, 5, 7, 1, 1};
+    private static final int[] SubjectInfoAccess_data = { 1, 3, 6, 1, 5, 5, 7, 1, 11};
+    private static final int[] FreshestCRL_data = { 2, 5, 29, 46 };
+    private static final int[] OCSPNoCheck_data = { 1, 3, 6, 1, 5, 5, 7,
                                                     48, 1, 5};
 
+    // Additional extensions under the PKIX arc that are not necessarily
+    // used in X.509 Certificates or CRLs.
+    private static final int[] OCSPNonce_data = { 1, 3, 6, 1, 5, 5, 7,
+                                                  48, 1, 2};
+
     /**
      * Identifies the particular public key used to sign the certificate.
      */
@@ -104,18 +109,20 @@
     public static final ObjectIdentifier CertificatePolicies_Id;
 
     /**
-     * Lists pairs of objectidentifiers of policies considered equivalent by the
-     * issuing CA to the subject CA.
+     * Lists pairs of object identifiers of policies considered equivalent by
+     * the issuing CA to the subject CA.
      */
     public static final ObjectIdentifier PolicyMappings_Id;
 
     /**
-     * Allows additional identities to be bound to the subject of the certificate.
+     * Allows additional identities to be bound to the subject of the
+     * certificate.
      */
     public static final ObjectIdentifier SubjectAlternativeName_Id;
 
     /**
-     * Allows additional identities to be associated with the certificate issuer.
+     * Allows additional identities to be associated with the certificate
+     * issuer.
      */
     public static final ObjectIdentifier IssuerAlternativeName_Id;
 
@@ -224,6 +231,12 @@
      */
     public static final ObjectIdentifier OCSPNoCheck_Id;
 
+    /**
+     * This extension is used to provide nonce data for OCSP requests
+     * or responses.
+     */
+    public static final ObjectIdentifier OCSPNonce_Id;
+
     static {
         AuthorityKey_Id = ObjectIdentifier.newInternal(AuthorityKey_data);
         SubjectKey_Id   = ObjectIdentifier.newInternal(SubjectKey_data);
@@ -266,5 +279,6 @@
             ObjectIdentifier.newInternal(SubjectInfoAccess_data);
         FreshestCRL_Id = ObjectIdentifier.newInternal(FreshestCRL_data);
         OCSPNoCheck_Id = ObjectIdentifier.newInternal(OCSPNoCheck_data);
+        OCSPNonce_Id = ObjectIdentifier.newInternal(OCSPNonce_data);
     }
 }
--- a/src/share/classes/sun/security/x509/X509CertImpl.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/classes/sun/security/x509/X509CertImpl.java	Thu Nov 09 06:08:09 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2013, 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
@@ -1046,6 +1046,32 @@
     }
 
     /**
+     * Returns the subject's key identifier, or null
+     */
+    public KeyIdentifier getSubjectKeyId() {
+        SubjectKeyIdentifierExtension ski = getSubjectKeyIdentifierExtension();
+        if (ski != null) {
+            try {
+                return (KeyIdentifier)ski.get(
+                    SubjectKeyIdentifierExtension.KEY_ID);
+            } catch (IOException ioe) {} // not possible
+        }
+        return null;
+    }
+
+    public KeyIdentifier getAuthKeyId() {
+        AuthorityKeyIdentifierExtension aki
+            = getAuthorityKeyIdentifierExtension();
+        if (aki != null) {
+            try {
+                return (KeyIdentifier)aki.get(
+                    AuthorityKeyIdentifierExtension.KEY_ID);
+            } catch (IOException ioe) {} // not possible
+        }
+        return null;
+    }
+
+    /**
      * Get AuthorityKeyIdentifier extension
      * @return AuthorityKeyIdentifier object or null (if no such object
      * in certificate)
--- a/src/share/lib/security/java.security-linux	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/lib/security/java.security-linux	Thu Nov 09 06:08:09 2017 +0000
@@ -350,9 +350,7 @@
 # describes the mechanism for disabling algorithms based on algorithm name
 # and/or key length.  This includes algorithms used in certificates, as well
 # as revocation information such as CRLs and signed OCSP Responses.
-#
-# The syntax of the disabled algorithm string is described as this Java
-# BNF-style:
+# The syntax of the disabled algorithm string is described as follows:
 #   DisabledAlgorithms:
 #       " DisabledAlgorithm { , DisabledAlgorithm } "
 #
@@ -363,25 +361,26 @@
 #       (see below)
 #
 #   Constraint:
-#       KeySizeConstraint, CertConstraint
+#       KeySizeConstraint | CAConstraint | DenyAfterConstraint |
+#       UsageConstraint
 #
 #   KeySizeConstraint:
-#       keySize Operator DecimalInteger
+#       keySize Operator KeyLength
 #
 #   Operator:
 #       <= | < | == | != | >= | >
 #
-#   DecimalInteger:
-#       DecimalDigits
+#   KeyLength:
+#       Integer value of the algorithm's key length in bits
 #
-#   DecimalDigits:
-#       DecimalDigit {DecimalDigit}
+#   CAConstraint:
+#       jdkCA
 #
-#   DecimalDigit: one of
-#       1 2 3 4 5 6 7 8 9 0
+#   DenyAfterConstraint:
+#       denyAfter YYYY-MM-DD
 #
-#   CertConstraint
-#       jdkCA
+#   UsageConstraint:
+#       usage [TLSServer] [TLSClient] [SignedJAR]
 #
 # The "AlgorithmName" is the standard algorithm name of the disabled
 # algorithm. See "Java Cryptography Architecture Standard Algorithm Name
@@ -395,27 +394,55 @@
 # that rely on DSA, such as NONEwithDSA, SHA1withDSA.  However, the assertion
 # will not disable algorithms related to "ECDSA".
 #
-# A "Constraint" provides further guidance for the algorithm being specified.
-# The "KeySizeConstraint" requires a key of a valid size range if the
-# "AlgorithmName" is of a key algorithm.  The "DecimalInteger" indicates the
-# key size specified in number of bits.  For example, "RSA keySize <= 1024"
-# indicates that any RSA key with key size less than or equal to 1024 bits
-# should be disabled, and "RSA keySize < 1024, RSA keySize > 2048" indicates
-# that any RSA key with key size less than 1024 or greater than 2048 should
-# be disabled. Note that the "KeySizeConstraint" only makes sense to key
-# algorithms.
+# A "Constraint" defines restrictions on the keys and/or certificates for
+# a specified AlgorithmName:
+#
+#   KeySizeConstraint:
+#     keySize Operator KeyLength
+#       The constraint requires a key of a valid size range if the
+#       "AlgorithmName" is of a key algorithm.  The "KeyLength" indicates
+#       the key size specified in number of bits.  For example,
+#       "RSA keySize <= 1024" indicates that any RSA key with key size less
+#       than or equal to 1024 bits should be disabled, and
+#       "RSA keySize < 1024, RSA keySize > 2048" indicates that any RSA key
+#       with key size less than 1024 or greater than 2048 should be disabled.
+#       This constraint is only used on algorithms that have a key size.
+#
+#   CAConstraint:
+#     jdkCA
+#       This constraint prohibits the specified algorithm only if the
+#       algorithm is used in a certificate chain that terminates at a marked
+#       trust anchor in the lib/security/cacerts keystore.  If the jdkCA
+#       constraint is not set, then all chains using the specified algorithm
+#       are restricted.  jdkCA may only be used once in a DisabledAlgorithm
+#       expression.
+#       Example:  To apply this constraint to SHA-1 certificates, include
+#       the following:  "SHA1 jdkCA"
 #
-# "CertConstraint" specifies additional constraints for
-# certificates that contain algorithms that are restricted:
+#   DenyAfterConstraint:
+#     denyAfter YYYY-MM-DD
+#       This constraint prohibits a certificate with the specified algorithm
+#       from being used after the date regardless of the certificate's
+#       validity.  JAR files that are signed and timestamped before the
+#       constraint date with certificates containing the disabled algorithm
+#       will not be restricted.  The date is processed in the UTC timezone.
+#       This constraint can only be used once in a DisabledAlgorithm
+#       expression.
+#       Example:  To deny usage of RSA 2048 bit certificates after Feb 3 2020,
+#       use the following:  "RSA keySize == 2048 & denyAfter 2020-02-03"
 #
-#   "jdkCA" prohibits the specified algorithm only if the algorithm is used
-#     in a certificate chain that terminates at a marked trust anchor in the
-#     lib/security/cacerts keystore.  All other chains are not affected.
-#     If the jdkCA constraint is not set, then all chains using the
-#     specified algorithm are restricted.  jdkCA may only be used once in
-#     a DisabledAlgorithm expression.
-#     Example:  To apply this constraint to SHA-1 certificates, include
-#     the following:  "SHA1 jdkCA"
+#   UsageConstraint:
+#     usage [TLSServer] [TLSClient] [SignedJAR]
+#       This constraint prohibits the specified algorithm for
+#       a specified usage.  This should be used when disabling an algorithm
+#       for all usages is not practical. 'TLSServer' restricts the algorithm
+#       in TLS server certificate chains when server authentication is
+#       performed. 'TLSClient' restricts the algorithm in TLS client
+#       certificate chains when client authentication is performed.
+#       'SignedJAR' constrains use of certificates in signed jar files.
+#       The usage type follows the keyword and more than one usage type can
+#       be specified with a whitespace delimiter.
+#       Example:  "SHA1 usage TLSServer TLSClient"
 #
 # When an algorithm must satisfy more than one constraint, it must be
 # delimited by an ampersand '&'.  For example, to restrict certificates in a
@@ -428,6 +455,9 @@
 # before larger keysize constraints of the same algorithm.  For example:
 # "RSA keySize < 1024 & jdkCA, RSA keySize < 2048".
 #
+# Note: The algorithm restrictions do not apply to trust anchors or
+# self-signed certificates.
+#
 # Note: This property is currently used by Oracle's PKIX implementation. It
 # is not guaranteed to be examined and used by other implementations.
 #
@@ -435,9 +465,10 @@
 #   jdk.certpath.disabledAlgorithms=MD2, DSA, RSA keySize < 2048
 #
 #
-jdk.certpath.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, \
-    DSA keySize < 1024, EC keySize < 224
+jdk.certpath.disabledAlgorithms=MD2, MD5, SHA1 jdkCA & usage TLSServer, \
+    RSA keySize < 1024, DSA keySize < 1024, EC keySize < 224
 
+#
 # Algorithm restrictions for signed JAR files
 #
 # In some environments, certain algorithms or key lengths may be undesirable
@@ -452,17 +483,20 @@
 #       " DisabledAlgorithm { , DisabledAlgorithm } "
 #
 #   DisabledAlgorithm:
-#       AlgorithmName [Constraint]
+#       AlgorithmName [Constraint] { '&' Constraint }
 #
 #   AlgorithmName:
 #       (see below)
 #
 #   Constraint:
-#       KeySizeConstraint
+#       KeySizeConstraint | DenyAfterConstraint
 #
 #   KeySizeConstraint:
 #       keySize Operator KeyLength
 #
+#   DenyAfterConstraint:
+#       denyAfter YYYY-MM-DD
+#
 #   Operator:
 #       <= | < | == | != | >= | >
 #
@@ -473,8 +507,11 @@
 # implementation. It is not guaranteed to be examined and used by other
 # implementations.
 #
+# See "jdk.certpath.disabledAlgorithms" for syntax descriptions.
+#
 jdk.jar.disabledAlgorithms=MD2, MD5, RSA keySize < 1024
 
+#
 # Algorithm restrictions for Secure Socket Layer/Transport Layer Security
 # (SSL/TLS) processing
 #
@@ -496,6 +533,9 @@
 # See the specification of "jdk.certpath.disabledAlgorithms" for the
 # syntax of the disabled algorithm string.
 #
+# Note: The algorithm restrictions do not apply to trust anchors or
+# self-signed certificates.
+#
 # Note: This property is currently used by the JDK Reference implementation.
 # It is not guaranteed to be examined and used by other implementations.
 #
--- a/src/share/lib/security/java.security-macosx	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/lib/security/java.security-macosx	Thu Nov 09 06:08:09 2017 +0000
@@ -355,9 +355,7 @@
 # describes the mechanism for disabling algorithms based on algorithm name
 # and/or key length.  This includes algorithms used in certificates, as well
 # as revocation information such as CRLs and signed OCSP Responses.
-#
-# The syntax of the disabled algorithm string is described as this Java
-# BNF-style:
+# The syntax of the disabled algorithm string is described as follows:
 #   DisabledAlgorithms:
 #       " DisabledAlgorithm { , DisabledAlgorithm } "
 #
@@ -368,25 +366,26 @@
 #       (see below)
 #
 #   Constraint:
-#       KeySizeConstraint, CertConstraint
+#       KeySizeConstraint | CAConstraint | DenyAfterConstraint |
+#       UsageConstraint
 #
 #   KeySizeConstraint:
-#       keySize Operator DecimalInteger
+#       keySize Operator KeyLength
 #
 #   Operator:
 #       <= | < | == | != | >= | >
 #
-#   DecimalInteger:
-#       DecimalDigits
+#   KeyLength:
+#       Integer value of the algorithm's key length in bits
 #
-#   DecimalDigits:
-#       DecimalDigit {DecimalDigit}
+#   CAConstraint:
+#       jdkCA
 #
-#   DecimalDigit: one of
-#       1 2 3 4 5 6 7 8 9 0
+#   DenyAfterConstraint:
+#       denyAfter YYYY-MM-DD
 #
-#   CertConstraint
-#       jdkCA
+#   UsageConstraint:
+#       usage [TLSServer] [TLSClient] [SignedJAR]
 #
 # The "AlgorithmName" is the standard algorithm name of the disabled
 # algorithm. See "Java Cryptography Architecture Standard Algorithm Name
@@ -400,27 +399,55 @@
 # that rely on DSA, such as NONEwithDSA, SHA1withDSA.  However, the assertion
 # will not disable algorithms related to "ECDSA".
 #
-# A "Constraint" provides further guidance for the algorithm being specified.
-# The "KeySizeConstraint" requires a key of a valid size range if the
-# "AlgorithmName" is of a key algorithm.  The "DecimalInteger" indicates the
-# key size specified in number of bits.  For example, "RSA keySize <= 1024"
-# indicates that any RSA key with key size less than or equal to 1024 bits
-# should be disabled, and "RSA keySize < 1024, RSA keySize > 2048" indicates
-# that any RSA key with key size less than 1024 or greater than 2048 should
-# be disabled. Note that the "KeySizeConstraint" only makes sense to key
-# algorithms.
+# A "Constraint" defines restrictions on the keys and/or certificates for
+# a specified AlgorithmName:
+#
+#   KeySizeConstraint:
+#     keySize Operator KeyLength
+#       The constraint requires a key of a valid size range if the
+#       "AlgorithmName" is of a key algorithm.  The "KeyLength" indicates
+#       the key size specified in number of bits.  For example,
+#       "RSA keySize <= 1024" indicates that any RSA key with key size less
+#       than or equal to 1024 bits should be disabled, and
+#       "RSA keySize < 1024, RSA keySize > 2048" indicates that any RSA key
+#       with key size less than 1024 or greater than 2048 should be disabled.
+#       This constraint is only used on algorithms that have a key size.
+#
+#   CAConstraint:
+#     jdkCA
+#       This constraint prohibits the specified algorithm only if the
+#       algorithm is used in a certificate chain that terminates at a marked
+#       trust anchor in the lib/security/cacerts keystore.  If the jdkCA
+#       constraint is not set, then all chains using the specified algorithm
+#       are restricted.  jdkCA may only be used once in a DisabledAlgorithm
+#       expression.
+#       Example:  To apply this constraint to SHA-1 certificates, include
+#       the following:  "SHA1 jdkCA"
 #
-# "CertConstraint" specifies additional constraints for
-# certificates that contain algorithms that are restricted:
+#   DenyAfterConstraint:
+#     denyAfter YYYY-MM-DD
+#       This constraint prohibits a certificate with the specified algorithm
+#       from being used after the date regardless of the certificate's
+#       validity.  JAR files that are signed and timestamped before the
+#       constraint date with certificates containing the disabled algorithm
+#       will not be restricted.  The date is processed in the UTC timezone.
+#       This constraint can only be used once in a DisabledAlgorithm
+#       expression.
+#       Example:  To deny usage of RSA 2048 bit certificates after Feb 3 2020,
+#       use the following:  "RSA keySize == 2048 & denyAfter 2020-02-03"
 #
-#   "jdkCA" prohibits the specified algorithm only if the algorithm is used
-#     in a certificate chain that terminates at a marked trust anchor in the
-#     lib/security/cacerts keystore.  All other chains are not affected.
-#     If the jdkCA constraint is not set, then all chains using the
-#     specified algorithm are restricted. jdkCA may only be used once in
-#     a DisabledAlgorithm expression.
-#     Example:  To apply this constraint to SHA-1 certificates, include
-#     the following:  "SHA1 jdkCA"
+#   UsageConstraint:
+#     usage [TLSServer] [TLSClient] [SignedJAR]
+#       This constraint prohibits the specified algorithm for
+#       a specified usage.  This should be used when disabling an algorithm
+#       for all usages is not practical. 'TLSServer' restricts the algorithm
+#       in TLS server certificate chains when server authentication is
+#       performed. 'TLSClient' restricts the algorithm in TLS client
+#       certificate chains when client authentication is performed.
+#       'SignedJAR' constrains use of certificates in signed jar files.
+#       The usage type follows the keyword and more than one usage type can
+#       be specified with a whitespace delimiter.
+#       Example:  "SHA1 usage TLSServer TLSClient"
 #
 # When an algorithm must satisfy more than one constraint, it must be
 # delimited by an ampersand '&'.  For example, to restrict certificates in a
@@ -433,6 +460,9 @@
 # before larger keysize constraints of the same algorithm.  For example:
 # "RSA keySize < 1024 & jdkCA, RSA keySize < 2048".
 #
+# Note: The algorithm restrictions do not apply to trust anchors or
+# self-signed certificates.
+#
 # Note: This property is currently used by Oracle's PKIX implementation. It
 # is not guaranteed to be examined and used by other implementations.
 #
@@ -440,9 +470,10 @@
 #   jdk.certpath.disabledAlgorithms=MD2, DSA, RSA keySize < 2048
 #
 #
-jdk.certpath.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, \
-    DSA keySize < 1024, EC keySize < 224
+jdk.certpath.disabledAlgorithms=MD2, MD5, SHA1 jdkCA & usage TLSServer, \
+    RSA keySize < 1024, DSA keySize < 1024, EC keySize < 224
 
+#
 # Algorithm restrictions for signed JAR files
 #
 # In some environments, certain algorithms or key lengths may be undesirable
@@ -457,17 +488,20 @@
 #       " DisabledAlgorithm { , DisabledAlgorithm } "
 #
 #   DisabledAlgorithm:
-#       AlgorithmName [Constraint]
+#       AlgorithmName [Constraint] { '&' Constraint }
 #
 #   AlgorithmName:
 #       (see below)
 #
 #   Constraint:
-#       KeySizeConstraint
+#       KeySizeConstraint | DenyAfterConstraint
 #
 #   KeySizeConstraint:
 #       keySize Operator KeyLength
 #
+#   DenyAfterConstraint:
+#       denyAfter YYYY-MM-DD
+#
 #   Operator:
 #       <= | < | == | != | >= | >
 #
@@ -478,8 +512,11 @@
 # implementation. It is not guaranteed to be examined and used by other
 # implementations.
 #
+# See "jdk.certpath.disabledAlgorithms" for syntax descriptions.
+#
 jdk.jar.disabledAlgorithms=MD2, MD5, RSA keySize < 1024
 
+#
 # Algorithm restrictions for Secure Socket Layer/Transport Layer Security
 # (SSL/TLS) processing
 #
@@ -501,6 +538,9 @@
 # See the specification of "jdk.certpath.disabledAlgorithms" for the
 # syntax of the disabled algorithm string.
 #
+# Note: The algorithm restrictions do not apply to trust anchors or
+# self-signed certificates.
+#
 # Note: This property is currently used by the JDK Reference implementation.
 # It is not guaranteed to be examined and used by other implementations.
 #
--- a/src/share/lib/security/java.security-solaris	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/lib/security/java.security-solaris	Thu Nov 09 06:08:09 2017 +0000
@@ -354,9 +354,7 @@
 # describes the mechanism for disabling algorithms based on algorithm name
 # and/or key length.  This includes algorithms used in certificates, as well
 # as revocation information such as CRLs and signed OCSP Responses.
-#
-# The syntax of the disabled algorithm string is described as this Java
-# BNF-style:
+# The syntax of the disabled algorithm string is described as follows:
 #   DisabledAlgorithms:
 #       " DisabledAlgorithm { , DisabledAlgorithm } "
 #
@@ -367,25 +365,26 @@
 #       (see below)
 #
 #   Constraint:
-#       KeySizeConstraint, CertConstraint
+#       KeySizeConstraint | CAConstraint | DenyAfterConstraint |
+#       UsageConstraint
 #
 #   KeySizeConstraint:
-#       keySize Operator DecimalInteger
+#       keySize Operator KeyLength
 #
 #   Operator:
 #       <= | < | == | != | >= | >
 #
-#   DecimalInteger:
-#       DecimalDigits
+#   KeyLength:
+#       Integer value of the algorithm's key length in bits
 #
-#   DecimalDigits:
-#       DecimalDigit {DecimalDigit}
+#   CAConstraint:
+#       jdkCA
 #
-#   DecimalDigit: one of
-#       1 2 3 4 5 6 7 8 9 0
+#   DenyAfterConstraint:
+#       denyAfter YYYY-MM-DD
 #
-#   CertConstraint
-#       jdkCA
+#   UsageConstraint:
+#       usage [TLSServer] [TLSClient] [SignedJAR]
 #
 # The "AlgorithmName" is the standard algorithm name of the disabled
 # algorithm. See "Java Cryptography Architecture Standard Algorithm Name
@@ -399,27 +398,55 @@
 # that rely on DSA, such as NONEwithDSA, SHA1withDSA.  However, the assertion
 # will not disable algorithms related to "ECDSA".
 #
-# A "Constraint" provides further guidance for the algorithm being specified.
-# The "KeySizeConstraint" requires a key of a valid size range if the
-# "AlgorithmName" is of a key algorithm.  The "DecimalInteger" indicates the
-# key size specified in number of bits.  For example, "RSA keySize <= 1024"
-# indicates that any RSA key with key size less than or equal to 1024 bits
-# should be disabled, and "RSA keySize < 1024, RSA keySize > 2048" indicates
-# that any RSA key with key size less than 1024 or greater than 2048 should
-# be disabled. Note that the "KeySizeConstraint" only makes sense to key
-# algorithms.
+# A "Constraint" defines restrictions on the keys and/or certificates for
+# a specified AlgorithmName:
+#
+#   KeySizeConstraint:
+#     keySize Operator KeyLength
+#       The constraint requires a key of a valid size range if the
+#       "AlgorithmName" is of a key algorithm.  The "KeyLength" indicates
+#       the key size specified in number of bits.  For example,
+#       "RSA keySize <= 1024" indicates that any RSA key with key size less
+#       than or equal to 1024 bits should be disabled, and
+#       "RSA keySize < 1024, RSA keySize > 2048" indicates that any RSA key
+#       with key size less than 1024 or greater than 2048 should be disabled.
+#       This constraint is only used on algorithms that have a key size.
+#
+#   CAConstraint:
+#     jdkCA
+#       This constraint prohibits the specified algorithm only if the
+#       algorithm is used in a certificate chain that terminates at a marked
+#       trust anchor in the lib/security/cacerts keystore.  If the jdkCA
+#       constraint is not set, then all chains using the specified algorithm
+#       are restricted.  jdkCA may only be used once in a DisabledAlgorithm
+#       expression.
+#       Example:  To apply this constraint to SHA-1 certificates, include
+#       the following:  "SHA1 jdkCA"
 #
-# "CertConstraint" specifies additional constraints for
-# certificates that contain algorithms that are restricted:
+#   DenyAfterConstraint:
+#     denyAfter YYYY-MM-DD
+#       This constraint prohibits a certificate with the specified algorithm
+#       from being used after the date regardless of the certificate's
+#       validity.  JAR files that are signed and timestamped before the
+#       constraint date with certificates containing the disabled algorithm
+#       will not be restricted.  The date is processed in the UTC timezone.
+#       This constraint can only be used once in a DisabledAlgorithm
+#       expression.
+#       Example:  To deny usage of RSA 2048 bit certificates after Feb 3 2020,
+#       use the following:  "RSA keySize == 2048 & denyAfter 2020-02-03"
 #
-#   "jdkCA" prohibits the specified algorithm only if the algorithm is used
-#     in a certificate chain that terminates at a marked trust anchor in the
-#     lib/security/cacerts keystore.  All other chains are not affected.
-#     If the jdkCA constraint is not set, then all chains using the
-#     specified algorithm are restricted. jdkCA may only be used once in
-#     a DisabledAlgorithm expression.
-#     Example:  To apply this constraint to SHA-1 certificates, include
-#     the following:  "SHA1 jdkCA"
+#   UsageConstraint:
+#     usage [TLSServer] [TLSClient] [SignedJAR]
+#       This constraint prohibits the specified algorithm for
+#       a specified usage.  This should be used when disabling an algorithm
+#       for all usages is not practical. 'TLSServer' restricts the algorithm
+#       in TLS server certificate chains when server authentication is
+#       performed. 'TLSClient' restricts the algorithm in TLS client
+#       certificate chains when client authentication is performed.
+#       'SignedJAR' constrains use of certificates in signed jar files.
+#       The usage type follows the keyword and more than one usage type can
+#       be specified with a whitespace delimiter.
+#       Example:  "SHA1 usage TLSServer TLSClient"
 #
 # When an algorithm must satisfy more than one constraint, it must be
 # delimited by an ampersand '&'.  For example, to restrict certificates in a
@@ -432,6 +459,9 @@
 # before larger keysize constraints of the same algorithm.  For example:
 # "RSA keySize < 1024 & jdkCA, RSA keySize < 2048".
 #
+# Note: The algorithm restrictions do not apply to trust anchors or
+# self-signed certificates.
+#
 # Note: This property is currently used by Oracle's PKIX implementation. It
 # is not guaranteed to be examined and used by other implementations.
 #
@@ -439,9 +469,10 @@
 #   jdk.certpath.disabledAlgorithms=MD2, DSA, RSA keySize < 2048
 #
 #
-jdk.certpath.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, \
-    DSA keySize < 1024, EC keySize < 224
+jdk.certpath.disabledAlgorithms=MD2, MD5, SHA1 jdkCA & usage TLSServer, \
+    RSA keySize < 1024, DSA keySize < 1024, EC keySize < 224
 
+#
 # Algorithm restrictions for signed JAR files
 #
 # In some environments, certain algorithms or key lengths may be undesirable
@@ -456,17 +487,20 @@
 #       " DisabledAlgorithm { , DisabledAlgorithm } "
 #
 #   DisabledAlgorithm:
-#       AlgorithmName [Constraint]
+#       AlgorithmName [Constraint] { '&' Constraint }
 #
 #   AlgorithmName:
 #       (see below)
 #
 #   Constraint:
-#       KeySizeConstraint
+#       KeySizeConstraint | DenyAfterConstraint
 #
 #   KeySizeConstraint:
 #       keySize Operator KeyLength
 #
+#   DenyAfterConstraint:
+#       denyAfter YYYY-MM-DD
+#
 #   Operator:
 #       <= | < | == | != | >= | >
 #
@@ -477,8 +511,11 @@
 # implementation. It is not guaranteed to be examined and used by other
 # implementations.
 #
+# See "jdk.certpath.disabledAlgorithms" for syntax descriptions.
+#
 jdk.jar.disabledAlgorithms=MD2, MD5, RSA keySize < 1024
 
+#
 # Algorithm restrictions for Secure Socket Layer/Transport Layer Security
 # (SSL/TLS) processing
 #
@@ -500,6 +537,9 @@
 # See the specification of "jdk.certpath.disabledAlgorithms" for the
 # syntax of the disabled algorithm string.
 #
+# Note: The algorithm restrictions do not apply to trust anchors or
+# self-signed certificates.
+#
 # Note: This property is currently used by the JDK Reference implementation.
 # It is not guaranteed to be examined and used by other implementations.
 #
--- a/src/share/lib/security/java.security-windows	Thu Aug 03 07:28:01 2017 +0100
+++ b/src/share/lib/security/java.security-windows	Thu Nov 09 06:08:09 2017 +0000
@@ -355,9 +355,7 @@
 # describes the mechanism for disabling algorithms based on algorithm name
 # and/or key length.  This includes algorithms used in certificates, as well
 # as revocation information such as CRLs and signed OCSP Responses.
-#
-# The syntax of the disabled algorithm string is described as this Java
-# BNF-style:
+# The syntax of the disabled algorithm string is described as follows:
 #   DisabledAlgorithms:
 #       " DisabledAlgorithm { , DisabledAlgorithm } "
 #
@@ -368,25 +366,26 @@
 #       (see below)
 #
 #   Constraint:
-#       KeySizeConstraint, CertConstraint
+#       KeySizeConstraint | CAConstraint | DenyAfterConstraint |
+#       UsageConstraint
 #
 #   KeySizeConstraint:
-#       keySize Operator DecimalInteger
+#       keySize Operator KeyLength
 #
 #   Operator:
 #       <= | < | == | != | >= | >
 #
-#   DecimalInteger:
-#       DecimalDigits
+#   KeyLength:
+#       Integer value of the algorithm's key length in bits
 #
-#   DecimalDigits:
-#       DecimalDigit {DecimalDigit}
+#   CAConstraint:
+#       jdkCA
 #
-#   DecimalDigit: one of
-#       1 2 3 4 5 6 7 8 9 0
+#   DenyAfterConstraint:
+#       denyAfter YYYY-MM-DD
 #
-#   CertConstraint
-#       jdkCA
+#   UsageConstraint:
+#       usage [TLSServer] [TLSClient] [SignedJAR]
 #
 # The "AlgorithmName" is the standard algorithm name of the disabled
 # algorithm. See "Java Cryptography Architecture Standard Algorithm Name
@@ -400,27 +399,55 @@
 # that rely on DSA, such as NONEwithDSA, SHA1withDSA.  However, the assertion
 # will not disable algorithms related to "ECDSA".
 #
-# A "Constraint" provides further guidance for the algorithm being specified.
-# The "KeySizeConstraint" requires a key of a valid size range if the
-# "AlgorithmName" is of a key algorithm.  The "DecimalInteger" indicates the
-# key size specified in number of bits.  For example, "RSA keySize <= 1024"
-# indicates that any RSA key with key size less than or equal to 1024 bits
-# should be disabled, and "RSA keySize < 1024, RSA keySize > 2048" indicates
-# that any RSA key with key size less than 1024 or greater than 2048 should
-# be disabled. Note that the "KeySizeConstraint" only makes sense to key
-# algorithms.
+# A "Constraint" defines restrictions on the keys and/or certificates for
+# a specified AlgorithmName:
+#
+#   KeySizeConstraint:
+#     keySize Operator KeyLength
+#       The constraint requires a key of a valid size range if the
+#       "AlgorithmName" is of a key algorithm.  The "KeyLength" indicates
+#       the key size specified in number of bits.  For example,
+#       "RSA keySize <= 1024" indicates that any RSA key with key size less
+#       than or equal to 1024 bits should be disabled, and
+#       "RSA keySize < 1024, RSA keySize > 2048" indicates that any RSA key
+#       with key size less than 1024 or greater than 2048 should be disabled.
+#       This constraint is only used on algorithms that have a key size.
+#
+#   CAConstraint:
+#     jdkCA
+#       This constraint prohibits the specified algorithm only if the
+#       algorithm is used in a certificate chain that terminates at a marked
+#       trust anchor in the lib/security/cacerts keystore.  If the jdkCA
+#       constraint is not set, then all chains using the specified algorithm
+#       are restricted.  jdkCA may only be used once in a DisabledAlgorithm
+#       expression.
+#       Example:  To apply this constraint to SHA-1 certificates, include
+#       the following:  "SHA1 jdkCA"
 #
-# "CertConstraint" specifies additional constraints for
-# certificates that contain algorithms that are restricted:
+#   DenyAfterConstraint:
+#     denyAfter YYYY-MM-DD
+#       This constraint prohibits a certificate with the specified algorithm
+#       from being used after the date regardless of the certificate's
+#       validity.  JAR files that are signed and timestamped before the
+#       constraint date with certificates containing the disabled algorithm
+#       will not be restricted.  The date is processed in the UTC timezone.
+#       This constraint can only be used once in a DisabledAlgorithm
+#       expression.
+#       Example:  To deny usage of RSA 2048 bit certificates after Feb 3 2020,
+#       use the following:  "RSA keySize == 2048 & denyAfter 2020-02-03"
 #
-#   "jdkCA" prohibits the specified algorithm only if the algorithm is used
-#     in a certificate chain that terminates at a marked trust anchor in the
-#     lib/security/cacerts keystore.  All other chains are not affected.
-#     If the jdkCA constraint is not set, then all chains using the
-#     specified algorithm are restricted.  jdkCA may only be used once in
-#     a DisabledAlgorithm expression.
-#     Example:  To apply this constraint to SHA-1 certificates, include
-#     the following:  "SHA1 jdkCA"
+#   UsageConstraint:
+#     usage [TLSServer] [TLSClient] [SignedJAR]
+#       This constraint prohibits the specified algorithm for
+#       a specified usage.  This should be used when disabling an algorithm
+#       for all usages is not practical. 'TLSServer' restricts the algorithm
+#       in TLS server certificate chains when server authentication is
+#       performed. 'TLSClient' restricts the algorithm in TLS client
+#       certificate chains when client authentication is performed.
+#       'SignedJAR' constrains use of certificates in signed jar files.
+#       The usage type follows the keyword and more than one usage type can
+#       be specified with a whitespace delimiter.
+#       Example:  "SHA1 usage TLSServer TLSClient"
 #
 # When an algorithm must satisfy more than one constraint, it must be
 # delimited by an ampersand '&'.  For example, to restrict certificates in a
@@ -433,6 +460,9 @@
 # before larger keysize constraints of the same algorithm.  For example:
 # "RSA keySize < 1024 & jdkCA, RSA keySize < 2048".
 #
+# Note: The algorithm restrictions do not apply to trust anchors or
+# self-signed certificates.
+#
 # Note: This property is currently used by Oracle's PKIX implementation. It
 # is not guaranteed to be examined and used by other implementations.
 #
@@ -440,9 +470,10 @@
 #   jdk.certpath.disabledAlgorithms=MD2, DSA, RSA keySize < 2048
 #
 #
-jdk.certpath.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, \
-    DSA keySize < 1024, EC keySize < 224
+jdk.certpath.disabledAlgorithms=MD2, MD5, SHA1 jdkCA & usage TLSServer, \
+    RSA keySize < 1024, DSA keySize < 1024, EC keySize < 224
 
+#
 # Algorithm restrictions for signed JAR files
 #
 # In some environments, certain algorithms or key lengths may be undesirable
@@ -457,17 +488,20 @@
 #       " DisabledAlgorithm { , DisabledAlgorithm } "
 #
 #   DisabledAlgorithm:
-#       AlgorithmName [Constraint]
+#       AlgorithmName [Constraint] { '&' Constraint }
 #
 #   AlgorithmName:
 #       (see below)
 #
 #   Constraint:
-#       KeySizeConstraint
+#       KeySizeConstraint | DenyAfterConstraint
 #
 #   KeySizeConstraint:
 #       keySize Operator KeyLength
 #
+#   DenyAfterConstraint:
+#       denyAfter YYYY-MM-DD
+#
 #   Operator:
 #       <= | < | == | != | >= | >
 #
@@ -478,8 +512,11 @@
 # implementation. It is not guaranteed to be examined and used by other
 # implementations.
 #
+# See "jdk.certpath.disabledAlgorithms" for syntax descriptions.
+#
 jdk.jar.disabledAlgorithms=MD2, MD5, RSA keySize < 1024
 
+#
 # Algorithm restrictions for Secure Socket Layer/Transport Layer Security
 # (SSL/TLS) processing
 #
@@ -501,6 +538,9 @@
 # See the specification of "jdk.certpath.disabledAlgorithms" for the
 # syntax of the disabled algorithm string.
 #
+# Note: The algorithm restrictions do not apply to trust anchors or
+# self-signed certificates.
+#
 # Note: This property is currently used by the JDK Reference implementation.
 # It is not guaranteed to be examined and used by other implementations.
 #
--- a/test/ProblemList.txt	Thu Aug 03 07:28:01 2017 +0100
+++ b/test/ProblemList.txt	Thu Nov 09 06:08:09 2017 +0000
@@ -243,6 +243,9 @@
 # 7056489
 com/sun/jndi/ldap/ReadTimeoutTest.java                          generic-all
 
+# 8160071 ClientJSSEServerJSSE.java test failure
+sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java		linux-all
+
 ############################################################################
 
 # jdk_net
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/java/security/cert/PKIXRevocationChecker/UnitTest.java	Thu Nov 09 06:08:09 2017 +0000
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2012, 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.
+ *
+ * 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.
+ */
+
+/**
+ * @test
+ * @bug 6854712
+ * @summary Basic unit test for PKIXRevocationChecker
+ * @compile -XDignore.symbol.file UnitTest.java
+ * @run main UnitTest
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URI;
+import java.security.cert.CertificateFactory;
+import java.security.cert.CertPathValidator;
+import java.security.cert.Extension;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import sun.security.provider.certpath.CertPathChecker;
+import sun.security.provider.certpath.PKIXCertPathValidator;
+import sun.security.provider.certpath.PKIXRevocationChecker;
+import sun.security.provider.certpath.PKIXRevocationChecker.Option;
+
+public class UnitTest {
+
+    public static void main(String[] args) throws Exception {
+
+        /*
+         * We have to call the implementation directly as CertPathValidator
+         * can't be altered in OpenJDK 7.
+         */
+        PKIXCertPathValidator cpv = new PKIXCertPathValidator();
+        CertPathChecker cpc = cpv.engineGetRevocationChecker();
+        PKIXRevocationChecker prc = (PKIXRevocationChecker)cpc;
+
+        System.out.println("Testing that get methods return null or " +
+                           "empty lists/sets/maps");
+        requireNull(prc.getOCSPResponder(), "getOCSPResponder()");
+        requireNull(prc.getOCSPResponderCert(), "getOCSPResponderCert()");
+        requireEmpty(prc.getOCSPExtensions(), "getOCSPExtensions()");
+        requireEmpty(prc.getOCSPStapledResponses(),
+                     "getOCSPStapledResponses()");
+        requireEmpty(prc.getOptions(), "getOptions()");
+
+        System.out.println("Testing that get methods return same parameters " +
+                           "that are passed to set methods");
+        URI uri = new URI("http://localhost");
+        prc.setOCSPResponder(uri);
+        requireEquals(uri, prc.getOCSPResponder(), "getOCSPResponder()");
+
+        X509Certificate cert = getCert();
+        prc.setOCSPResponderCert(cert);
+        requireEquals(cert, prc.getOCSPResponderCert(),
+                      "getOCSPResponderCert()");
+
+        List<Extension> exts = new ArrayList<>();
+        for (String oid : cert.getNonCriticalExtensionOIDs()) {
+            System.out.println(oid);
+            exts.add(new ExtensionImpl(oid,
+                                       cert.getExtensionValue(oid), false));
+        }
+        prc.setOCSPExtensions(exts);
+        requireEquals(exts, prc.getOCSPExtensions(), "getOCSPExtensions()");
+
+        Set<Option> options = EnumSet.of(Option.ONLY_END_ENTITY);
+        prc.setOptions(options);
+        requireEquals(options, prc.getOptions(), "getOptions()");
+
+        System.out.println("Testing that parameters are re-initialized to " +
+                           "default values if null is passed to set methods");
+        prc.setOCSPResponder(null);
+        requireNull(prc.getOCSPResponder(), "getOCSPResponder()");
+        prc.setOCSPResponderCert(null);
+        requireNull(prc.getOCSPResponderCert(), "getOCSPResponderCert()");
+        prc.setOCSPExtensions(null);
+        requireEmpty(prc.getOCSPExtensions(), "getOCSPExtensions()");
+        prc.setOCSPStapledResponses(null);
+        requireEmpty(prc.getOCSPStapledResponses(),
+                     "getOCSPStapledResponses()");
+        prc.setOptions(null);
+        requireEmpty(prc.getOptions(), "getOptions()");
+    }
+
+    static void requireNull(Object o, String msg) throws Exception {
+        if (o != null) {
+            throw new Exception("FAILED: " + msg + " must return null");
+        }
+    }
+
+    static void requireEmpty(Map<?,?> m, String msg) throws Exception {
+        if (!m.isEmpty()) {
+            throw new Exception("FAILED: " + msg + " must return an empty map");
+        }
+    }
+
+    static void requireEmpty(List<?> l, String msg) throws Exception {
+        if (!l.isEmpty()) {
+            throw new Exception("FAILED: " + msg +" must return an empty list");
+        }
+    }
+
+    static void requireEmpty(Set<?> s, String msg) throws Exception {
+        if (!s.isEmpty()) {
+            throw new Exception("FAILED: " + msg + " must return an empty set");
+        }
+    }
+
+    static void requireEquals(Object a, Object b, String msg) throws Exception {
+        if (!a.equals(b)) {
+            throw new Exception("FAILED: " + msg + " does not return the " +
+                                "same object that was set");
+        }
+    }
+
+    static X509Certificate getCert() throws Exception {
+        String b64 =
+        "-----BEGIN CERTIFICATE-----\n" +
+        "MIIBLTCB2KADAgECAgEDMA0GCSqGSIb3DQEBBAUAMA0xCzAJBgNVBAMTAkNBMB4X\n" +
+        "DTAyMTEwNzExNTcwM1oXDTIyMTEwNzExNTcwM1owFTETMBEGA1UEAxMKRW5kIEVu\n" +
+        "dGl0eTBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDVBDfF+uBr5s5jzzDs1njKlZNt\n" +
+        "h8hHzEt3ASh67Peos+QrDzgpUyFXT6fdW2h7iPf0ifjM8eW2xa+3EnPjjU5jAgMB\n" +
+        "AAGjGzAZMBcGA1UdIAQQMA4wBgYEVR0gADAEBgIqADANBgkqhkiG9w0BAQQFAANB\n" +
+        "AFo//WOboCNOCcA1fvcWW9oc4MvV8ZPvFIAbyEbgyFd4id5lGDTRbRPvvNZRvdsN\n" +
+        "NM2gXYr+f87NHIXc9EF3pzw=\n" +
+        "-----END CERTIFICATE-----";
+
+        InputStream is = new ByteArrayInputStream(b64.getBytes("UTF-8"));
+        CertificateFactory cf = CertificateFactory.getInstance("X.509");
+        return (X509Certificate)cf.generateCertificate(is);
+    }
+
+    static class ExtensionImpl implements Extension {
+        private final String oid;
+        private final byte[] val;
+        private final boolean critical;
+
+        ExtensionImpl(String oid, byte[] val, boolean critical) {
+            this.oid = oid;
+            this.val = val;
+            this.critical = critical;
+        }
+
+        public void encode(OutputStream out) throws IOException {
+            throw new UnsupportedOperationException();
+        }
+
+        public String getId() {
+            return oid;
+        }
+
+        public byte[] getValue() {
+            return val.clone();
+        }
+
+        public boolean isCritical() {
+            return critical;
+        }
+    }
+}
--- a/test/sun/security/tools/jarsigner/TimestampCheck.java	Thu Aug 03 07:28:01 2017 +0100
+++ b/test/sun/security/tools/jarsigner/TimestampCheck.java	Thu Nov 09 06:08:09 2017 +0000
@@ -466,7 +466,7 @@
                 .shouldMatch("Timestamp signature algorithm: .*key.*weak");
         verify(file, "-J-Djava.security.debug=jar")
                 .shouldHaveExitValue(0)
-                .shouldMatch("SignatureException:.*Disabled");
+                .shouldMatch("SignatureException:.*disabled");
     }
 
     static void checkHalfWeak(String file) throws Throwable {