changeset 8488: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, 6493 insertions(+), 3675 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));
+            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;
-                } 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));
-                    }
-
-                    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 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());
+            }
+        }
 
-        // Check whether the signer cert returned by the responder is trusted
-        if (x509Certs != null && x509Certs[0] != null) {
-            X509CertImpl signerCert = x509Certs[0];
-
-            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");
-                            }
+                }
+            } 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
                         }
-                    }
-
-                    // 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 (ridKeyId.equals(certKeyId)) {
+                            signerCert = cert;
+                            break;
                         }
-
-                        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
-                        }
-                    } 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);
-                        }
-                        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 (debug != null) {
+                debug.println("thisUpdate: " + thisUpdate);
+            }
 
-            if (tmp.available() == 0)  {
-                // we are done
-                nextUpdate = null;
-            } else {
+            // 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();
-                tag = (byte)(derVal.tag & 0x1f);
-                if (tag == 0) {
-                    // next update
-                    nextUpdate = derVal.data.getGeneralizedTime();
 
-                    if (tmp.available() == 0)  {
-                        // we are done
+                // 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");
+                        }
                     } else {
-                        derVal = tmp.getDerValue();
-                        tag = (byte)(derVal.tag & 0x1f);
+                        // Unknown item in the singleResponse
+                        throw new IOException("Unsupported singleResponse " +
+                            "item, tag = " + String.format("%02X", derVal.tag));
                     }
-                } else {
-                    nextUpdate = null;
                 }
             }
-            // singleExtensions
-            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);
-                        }
-                        // 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 {
-                    singleExtensions = Collections.emptyMap();
+
+            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);
                 }
-            } 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;
-                }
-                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);
         }
 
-        @Override public CRLReason getRevocationReason() {
+        /**
+         * 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);
+        }
+
+        /**
+         * 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);
+        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);
 
-        // only add a revocationChecker if revocation is enabled
-        if (pkixParam.isRevocationEnabled()) {
+        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(checkers);
 
-            // Use OCSP if it has been enabled
-            if (ocspEnabled) {
-                OCSPChecker ocspChecker =
-                    new OCSPChecker(cpOriginal, pkixParam, onlyEECert);
-                certPathCheckers.add(ocspChecker);
-            }
+        PKIXMasterCertPathValidator.validate(params.certPath(),
+                                             params.certificates(),
+                                             certPathCheckers);
 
-            // Always use CRLs
-            CrlRevocationChecker revocationChecker = new
-                CrlRevocationChecker(anchor, pkixParam, certList, onlyEECert);
-            certPathCheckers.add(revocationChecker);
-        }
-
-        // add user-specified checkers
-        certPathCheckers.addAll(userCheckers);
-
-        PKIXMasterCertPathValidator masterValidator =
-            new PKIXMasterCertPathValidator(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: " +