changeset 1720:7cb359c0e53c

8176536: Improved algorithm constraints checking Reviewed-by: mullan
author ascarpino
date Thu, 23 Mar 2017 08:44:17 -0700
parents a52e30264abb
children 1f6558de9c57
files src/share/classes/sun/security/pkcs/SignerInfo.java src/share/classes/sun/security/provider/certpath/AlgorithmChecker.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/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/PKIXCertPathValidator.java src/share/classes/sun/security/provider/certpath/PKIXExtendedParameters.java src/share/classes/sun/security/provider/certpath/ResponderId.java src/share/classes/sun/security/provider/certpath/SunCertPathBuilder.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/CertConstraintParameters.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/lib/security/java.security-linux src/share/lib/security/java.security-solaris src/share/lib/security/java.security-windows test/ProblemList.txt
diffstat 26 files changed, 2082 insertions(+), 679 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/sun/security/pkcs/SignerInfo.java	Tue Aug 15 11:46:02 2017 -0700
+++ b/src/share/classes/sun/security/pkcs/SignerInfo.java	Thu Mar 23 08:44:17 2017 -0700
@@ -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
@@ -36,6 +36,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.CryptoPrimitive;
+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.
@@ -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/AlgorithmChecker.java	Tue Aug 15 11:46:02 2017 -0700
+++ b/src/share/classes/sun/security/provider/certpath/AlgorithmChecker.java	Thu Mar 23 08:44:17 2017 -0700
@@ -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
@@ -25,15 +25,13 @@
 
 package sun.security.provider.certpath;
 
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Set;
-import java.util.EnumSet;
+import java.util.*;
 import java.math.BigInteger;
 import java.security.PublicKey;
 import java.security.KeyFactory;
 import java.security.AlgorithmParameters;
 import java.security.GeneralSecurityException;
+import java.security.Timestamp;
 import java.security.cert.Certificate;
 import java.security.cert.X509CRL;
 import java.security.cert.X509Certificate;
@@ -42,22 +40,19 @@
 import java.security.cert.CRLException;
 import java.security.cert.CertificateException;
 import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertPathValidator;
 import java.io.IOException;
 import java.security.interfaces.*;
 import java.security.spec.*;
 
-import sun.security.util.AnchorCertificates;
-import sun.security.util.CertConstraintParameters;
-import sun.security.util.AlgorithmConstraints;
-import sun.security.util.CryptoPrimitive;
-import sun.security.util.Debug;
-import sun.security.util.DisabledAlgorithmConstraints;
+import sun.security.util.*;
+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 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
@@ -67,24 +62,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 =
                                     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);
 
@@ -97,64 +95,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
@@ -215,6 +248,27 @@
                         "incorrect KeyUsage extension");
         }
 
+        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);
+        }
+
         // Assume all key usage bits are set if key usage is not present
         Set<CryptoPrimitive> primitives = KU_PRIMITIVE_SET;
 
@@ -250,100 +304,74 @@
             }
         }
 
-        PublicKey currPubKey = cert.getPublicKey();
+        ConstraintsParameters cp =
+                new ConstraintsParameters((X509Certificate)cert,
+                        trustedMatch, pkixdate, jarTimestamp, variant);
 
+        // Check against local constraints if it is DisabledAlgorithmConstrain
         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");
             }
         }
 
-        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);
-            }
-
-            if (!constraints.permits(primitives, currPubKey)) {
-                throw new CertPathValidatorException(
-                    "Algorithm constraints check failed on keysize: " +
-                                sun.security.util.KeyUtil.getKeySize(currPubKey));
-
-            }
+        // 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);
+                            "signature algorithm: " + currSigAlg);
+        }
+
+        // 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");
             }
 
-            // 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
     }
 
     /**
@@ -383,8 +411,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;
@@ -395,26 +425,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");
-        }
+        certPathDefaultConstraints.permits(new ConstraintsParameters(
+                sigAlgName, sigAlgParams, key, variant));
     }
-
 }
--- a/src/share/classes/sun/security/provider/certpath/CrlRevocationChecker.java	Tue Aug 15 11:46:02 2017 -0700
+++ b/src/share/classes/sun/security/provider/certpath/CrlRevocationChecker.java	Thu Mar 23 08:44:17 2017 -0700
@@ -310,7 +310,7 @@
             // all CRLs returned by the DP Fetcher have also been verified
             mApprovedCRLs.addAll(DistributionPointFetcher.getCRLs(sel, signFlag,
                 prevKey, mSigProvider, mStores, reasonsMask, trustAnchors,
-                mParams.getDate()));
+                mParams.getDate(), null));
         } catch (Exception e) {
             if (debug != null) {
                 debug.println("CrlRevocationChecker.verifyRevocationStatus() "
@@ -783,9 +783,13 @@
                  t.hasNext() && !Arrays.equals(reasonsMask, ALL_REASONS); ) {
                 DistributionPoint point = t.next();
                 for (X509CRL crl : crls) {
+                    String variant = null;
+                    if (mParams instanceof PKIXExtendedParameters) {
+                        variant = ((PKIXExtendedParameters)mParams).getVariant();
+                    }
                     if (DistributionPointFetcher.verifyCRL(certImpl, point, crl,
                             reasonsMask, signFlag, prevKey, mSigProvider,
-                            trustAnchors, mStores, mParams.getDate())) {
+                            trustAnchors, mStores, mParams.getDate(), variant)) {
                         results.add(crl);
                     }
                 }
--- a/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java	Tue Aug 15 11:46:02 2017 -0700
+++ b/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java	Thu Mar 23 08:44:17 2017 -0700
@@ -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
@@ -35,6 +35,7 @@
 import sun.security.action.GetBooleanAction;
 import sun.security.util.Debug;
 import sun.security.util.DerOutputStream;
+import sun.security.validator.Validator;
 import sun.security.x509.*;
 
 /**
@@ -84,7 +85,8 @@
                                               List<CertStore> certStores,
                                               boolean[] reasonsMask,
                                               Set<TrustAnchor> trustAnchors,
-                                              Date validity)
+                                              Date validity,
+                                              String variant)
         throws CertStoreException
     {
         if (USE_CRLDP == false) {
@@ -116,7 +118,7 @@
                 DistributionPoint point = t.next();
                 Collection<X509CRL> crls = getCRLs(selector, certImpl,
                     point, reasonsMask, signFlag, prevKey, provider,
-                    certStores, trustAnchors, validity);
+                    certStores, trustAnchors, validity, variant);
                 results.addAll(crls);
             }
             if (debug != null) {
@@ -138,7 +140,7 @@
         X509CertImpl certImpl, DistributionPoint point, boolean[] reasonsMask,
         boolean signFlag, PublicKey prevKey, String provider,
         List<CertStore> certStores, Set<TrustAnchor> trustAnchors,
-        Date validity) {
+        Date validity, String variant) {
 
         // check for full name
         GeneralNames fullName = point.getFullName();
@@ -191,7 +193,7 @@
                 selector.setIssuerNames(null);
                 if (selector.match(crl) && verifyCRL(certImpl, point, crl,
                         reasonsMask, signFlag, prevKey, provider, trustAnchors,
-                        certStores, validity)) {
+                        certStores, validity, variant)) {
                     crls.add(crl);
                 }
             } catch (Exception e) {
@@ -283,7 +285,7 @@
         X509CRL crl, boolean[] reasonsMask, boolean signFlag,
         PublicKey prevKey, String provider,
         Set<TrustAnchor> trustAnchors, List<CertStore> certStores,
-        Date validity) throws CRLException, IOException {
+        Date validity, String variant) throws CRLException, IOException {
 
         boolean indirectCRL = false;
         X509CRLImpl crlImpl = X509CRLImpl.toImpl(crl);
@@ -401,7 +403,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 " +
@@ -616,7 +618,7 @@
 
         // 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);
--- a/src/share/classes/sun/security/provider/certpath/OCSP.java	Tue Aug 15 11:46:02 2017 -0700
+++ b/src/share/classes/sun/security/provider/certpath/OCSP.java	Thu Mar 23 08:44:17 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,6 +33,7 @@
 import java.security.cert.CertificateException;
 import java.security.cert.CertPathValidatorException;
 import java.security.cert.X509Certificate;
+import java.security.cert.TrustAnchor;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Date;
@@ -41,6 +42,7 @@
 
 import static sun.security.provider.certpath.OCSPResponse.*;
 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;
@@ -67,45 +69,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, issuerCert, null);
-        return (RevocationStatus) ocspResponse.getSingleResponse(certId);
-    }
-
-    /**
      * Obtains the revocation status of a certificate using OCSP.
      *
      * @param cert the certificate to be checked
@@ -122,8 +85,16 @@
      */
     public static RevocationStatus check(X509Certificate cert,
         X509Certificate issuerCert, URI responderURI, X509Certificate
-        responderCert, Date date)
+        responderCert, Date date, String variant)
         throws IOException, CertPathValidatorException {
+        return check(cert, responderURI, null, issuerCert, responderCert, date, variant);
+    }
+
+    public static RevocationStatus check(X509Certificate cert, URI responderURI,
+                                         TrustAnchor anchor, X509Certificate issuerCert,
+                                         X509Certificate responderCert, Date date,
+                                         String variant)
+            throws IOException, CertPathValidatorException {
         CertId certId = null;
         try {
             X509CertImpl certImpl = X509CertImpl.toImpl(cert);
@@ -136,15 +107,17 @@
                 ("Exception while encoding OCSPRequest", ioe);
         }
         OCSPResponse ocspResponse = check(Collections.singletonList(certId),
-            responderURI, responderCert, date);
+            responderURI, new OCSPResponse.IssuerInfo(anchor, issuerCert),
+                responderCert, date, 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 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.
@@ -155,21 +128,41 @@
      *    encoding the OCSP Request or validating the OCSP Response
      */
     static OCSPResponse check(List<CertId> certIds, URI responderURI,
-        X509Certificate responderCert, Date date)
+                              OCSPResponse.IssuerInfo issuerInfo,
+                              X509Certificate responderCert, Date date, String variant)
         throws IOException, CertPathValidatorException {
 
-        byte[] bytes = null;
+        OCSPResponse ocspResponse = null;
         try {
-            OCSPRequest request = new OCSPRequest(certIds);
-            bytes = request.encodeBytes();
+            byte[] response = getOCSPBytes(certIds, responderURI);
+            ocspResponse = new OCSPResponse(response, date, responderCert, 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);
         }
+        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
+     *
+     * @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) throws IOException {
+        OCSPRequest request = new OCSPRequest(certIds);
+        byte[] bytes = request.encodeBytes();
 
         InputStream in = null;
         OutputStream out = null;
         byte[] response = null;
+
         try {
             URL url = responderURI.toURL();
             if (debug != null) {
@@ -229,36 +222,7 @@
             }
         }
 
-        OCSPResponse ocspResponse = null;
-        try {
-            ocspResponse = new OCSPResponse(response, date, responderCert);
-        } 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;
     }
 
     /**
--- a/src/share/classes/sun/security/provider/certpath/OCSPChecker.java	Tue Aug 15 11:46:02 2017 -0700
+++ b/src/share/classes/sun/security/provider/certpath/OCSPChecker.java	Thu Mar 23 08:44:17 2017 -0700
@@ -336,8 +336,12 @@
             try {
                 certId = new CertId
                     (issuerCert, currCertImpl.getSerialNumberObject());
-                response = OCSP.check(Collections.singletonList(certId), uri,
-                    responderCert, pkixParams.getDate());
+                String variant = null;
+                if (pkixParams instanceof PKIXExtendedParameters) {
+                    variant = ((PKIXExtendedParameters)pkixParams).getVariant();
+                }
+                response = OCSP.check(Collections.singletonList(certId), uri, null,
+                        responderCert, pkixParams.getDate(), variant);
             } catch (Exception e) {
                 if (e instanceof CertPathValidatorException) {
                     throw (CertPathValidatorException) e;
--- a/src/share/classes/sun/security/provider/certpath/OCSPRequest.java	Tue Aug 15 11:46:02 2017 -0700
+++ b/src/share/classes/sun/security/provider/certpath/OCSPRequest.java	Thu Mar 23 08:44:17 2017 -0700
@@ -30,10 +30,11 @@
 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>
--- a/src/share/classes/sun/security/provider/certpath/OCSPResponse.java	Tue Aug 15 11:46:02 2017 -0700
+++ b/src/share/classes/sun/security/provider/certpath/OCSPResponse.java	Thu Mar 23 08:44:17 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2013, 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
@@ -33,11 +33,15 @@
 import java.security.cert.CertPathValidatorException;
 import java.security.cert.TrustAnchor;
 import java.security.cert.X509Certificate;
+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.*;
@@ -124,7 +128,7 @@
         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 = false;
@@ -174,12 +178,17 @@
         return tmp * 1000;
     }
 
+    private final byte[] responseNonce;
+    private final ResponderId respId;
+    private Date producedAtDate = null;
+    private final Map<String, Extension> responseExtensions;
+
     /*
      * Create an OCSP response from its ASN.1 DER encoding.
      */
     // used by OCSPChecker
     OCSPResponse(byte[] bytes, Date dateCheckedAgainst,
-        X509Certificate responderCert)
+        X509Certificate responderCert, String variant)
         throws IOException, CertPathValidatorException {
 
         // OCSPResponse
@@ -209,6 +218,9 @@
         if (responseStatus != ResponseStatus.SUCCESSFUL) {
             // no need to continue, responseBytes are not set.
             singleResponseMap = Collections.emptyMap();
+            responseNonce = null;
+            responseExtensions = Collections.emptyMap();
+            respId = null;
             return;
         }
 
@@ -277,23 +289,15 @@
         }
 
         // 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) {
-            // Ignore, for now
-        } else {
-            throw new IOException("Bad encoding in responderID element of " +
-                "OCSP response: expected ASN.1 context specific tag 0 or 1");
+        respId = new ResponderId(seq.toByteArray());
+        if (DEBUG != null) {
+            DEBUG.println("Responder ID: " + respId);
         }
 
         // producedAt
         seq = seqDerIn.getDerValue();
+        producedAtDate = seq.getGeneralizedTime();
         if (DEBUG != null) {
-            Date producedAtDate = seq.getGeneralizedTime();
             DEBUG.println("OCSP response produced at: " + producedAtDate);
         }
 
@@ -305,37 +309,29 @@
             DEBUG.println("OCSP number of SingleResponses: "
                 + singleResponseDer.length);
         }
-        for (int i = 0; i < singleResponseDer.length; i++) {
-            SingleResponse singleResponse
-                = new SingleResponse(singleResponseDer[i]);
+        for (DerValue srDer : singleResponseDer) {
+            SingleResponse singleResponse = new SingleResponse(srDer);
             singleResponseMap.put(singleResponse.getCertId(), singleResponse);
         }
 
         // responseExtensions
+        Map<String, Extension> tmpExtMap = new HashMap<String, Extension>();
         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(
-                        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 = 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]);
@@ -396,7 +392,7 @@
                 // Check algorithm constraints specified in security property
                 // "jdk.certpath.disabledAlgorithms".
                 AlgorithmChecker algChecker = new AlgorithmChecker(
-                                    new TrustAnchor(responderCert, null));
+                                    new TrustAnchor(responderCert, null), variant);
                 algChecker.init(false);
                 algChecker.check(cert, Collections.<String>emptySet());
 
@@ -417,7 +413,7 @@
         if (responderCert != null) {
             // Check algorithm constraints specified in security property
             // "jdk.certpath.disabledAlgorithms".
-            AlgorithmChecker.check(responderCert.getPublicKey(), sigAlgId);
+            AlgorithmChecker.check(responderCert.getPublicKey(), sigAlgId, variant);
 
             if (!verifyResponse(responseDataDer, responderCert,
                 sigAlgId, signature)) {
@@ -433,8 +429,10 @@
 
     /**
      * Returns the OCSP ResponseStatus.
+     *
+     * @return the {@code ResponseStatus} for this OCSP response
      */
-    ResponseStatus getResponseStatus() {
+    public ResponseStatus getResponseStatus() {
         return responseStatus;
     }
 
@@ -476,15 +474,107 @@
     /**
      * 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());
+    }
+
+    /**
+     * 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, Extension>
+        parseExtensions(DerValue derVal) throws IOException {
+        DerValue[] extDer = derVal.data.getSequence(3);
+        Map<String, Extension> extMap =
+                new HashMap<String, Extension>(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.toString(), 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;
@@ -530,7 +620,7 @@
                 }
             } else {
                 revocationTime = null;
-                revocationReason = Reason.UNSPECIFIED;
+                revocationReason = null;
                 if (tag == CERT_STATUS_GOOD) {
                     certStatus = CertStatus.GOOD;
                 } else if (tag == CERT_STATUS_UNKNOWN) {
@@ -627,18 +717,113 @@
          */
         @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");
             }
             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();
+        }
+    }
 }
--- a/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java	Tue Aug 15 11:46:02 2017 -0700
+++ b/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java	Thu Mar 23 08:44:17 2017 -0700
@@ -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
@@ -314,7 +314,14 @@
         int certPathLen = certList.size();
 
         basicChecker = new BasicChecker(anchor, testDate, sigProvider, false);
-        AlgorithmChecker algorithmChecker = new AlgorithmChecker(anchor);
+        String variant = null;
+        if (pkixParam instanceof PKIXExtendedParameters) {
+            variant = ((PKIXExtendedParameters)pkixParam).getVariant();
+        }
+        if (debug != null) {
+            debug.println("PKIXCertPathValidator.doValidate(): create AlgorithmChecker for variant: " + variant);
+        }
+        AlgorithmChecker algorithmChecker = new AlgorithmChecker(anchor, variant);
         KeyChecker keyChecker = new KeyChecker(certPathLen,
             pkixParam.getTargetCertConstraints());
         ConstraintsChecker constraintsChecker =
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/provider/certpath/PKIXExtendedParameters.java	Thu Mar 23 08:44:17 2017 -0700
@@ -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);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/provider/certpath/ResponderId.java	Thu Mar 23 08:44:17 2017 -0700
@@ -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/SunCertPathBuilder.java	Tue Aug 15 11:46:02 2017 -0700
+++ b/src/share/classes/sun/security/provider/certpath/SunCertPathBuilder.java	Thu Mar 23 08:44:17 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -58,7 +58,7 @@
  * <p> If successful, it returns a certification path which has succesfully
  * satisfied all the constraints and requirements specified in the
  * PKIXBuilderParameters object and has been validated according to the PKIX
- * path validation algorithm defined in RFC 3280.
+ * path validation algorithm defined in RFC 5280.
  *
  * <p> This implementation uses a depth-first search approach to finding
  * certification paths. If it comes to a point in which it cannot find
@@ -304,7 +304,7 @@
             // init the crl checker
             currentState.crlChecker =
                 new CrlRevocationChecker(null, buildParams, null, onlyEECert);
-            currentState.algorithmChecker = new AlgorithmChecker(anchor);
+            currentState.algorithmChecker = new AlgorithmChecker(anchor, null);
             currentState.untrustedChecker = new UntrustedChecker();
             try {
                 depthFirstSearchReverse(null, currentState,
@@ -484,7 +484,7 @@
 
                 // add the algorithm checker
                 userCheckers.add(mustCheck,
-                        new AlgorithmChecker(builder.trustAnchor));
+                        new AlgorithmChecker(builder.trustAnchor, buildParams.getDate(), null));
                 mustCheck++;
 
                 if (nextState.keyParamsNeeded()) {
--- a/src/share/classes/sun/security/ssl/SSLContextImpl.java	Tue Aug 15 11:46:02 2017 -0700
+++ b/src/share/classes/sun/security/ssl/SSLContextImpl.java	Thu Mar 23 08:44:17 2017 -0700
@@ -43,6 +43,7 @@
 
 import sun.security.util.AlgorithmConstraints;
 import sun.security.util.CryptoPrimitive;
+import sun.security.validator.Validator;
 
 public abstract class SSLContextImpl extends SSLContextSpi {
 
--- a/src/share/classes/sun/security/ssl/X509KeyManagerImpl.java	Tue Aug 15 11:46:02 2017 -0700
+++ b/src/share/classes/sun/security/ssl/X509KeyManagerImpl.java	Thu Mar 23 08:44:17 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -38,6 +38,8 @@
 
 import javax.net.ssl.*;
 
+import sun.security.validator.Validator;
+
 /**
  * The new X509 key manager implementation. The main differences to the
  * old SunX509 key manager are:
@@ -60,7 +62,7 @@
 
     private static final Debug debug = Debug.getInstance("ssl");
 
-    private final static boolean useDebug =
+    private static final boolean useDebug =
                             (debug != null) && Debug.isOn("keymanager");
 
     // for unit testing only, set via privileged reflection
@@ -497,6 +499,15 @@
                 return CheckResult.EXPIRED;
             }
         }
+
+        public String getValidator() {
+            if (this == CLIENT) {
+                return Validator.VAR_TLS_CLIENT;
+            } else if (this == SERVER) {
+                return Validator.VAR_TLS_SERVER;
+            }
+            return Validator.VAR_GENERIC;
+        }
     }
 
     // enum for the result of the extension check
--- a/src/share/classes/sun/security/util/AnchorCertificates.java	Tue Aug 15 11:46:02 2017 -0700
+++ b/src/share/classes/sun/security/util/AnchorCertificates.java	Thu Mar 23 08:44:17 2017 -0700
@@ -31,8 +31,10 @@
 import java.security.KeyStore;
 import java.security.PrivilegedAction;
 import java.security.cert.X509Certificate;
+import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashSet;
+import java.util.Set;
 
 import sun.security.x509.X509CertImpl;
 
@@ -44,7 +46,7 @@
 
     private static final Debug debug = Debug.getInstance("certpath");
     private static final String HASH = "SHA-256";
-    private static HashSet<String> certs;
+    private static Set<String> certs = Collections.emptySet();
 
     static  {
         AccessController.doPrivileged(new PrivilegedAction<Void>() {
--- a/src/share/classes/sun/security/util/CertConstraintParameters.java	Tue Aug 15 11:46:02 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.security.util;
-
-import java.security.cert.X509Certificate;
-
-/**
- * This class is a wrapper for keeping state and passing objects between PKIX,
- * AlgorithmChecker, and DisabledAlgorithmConstraints.
- */
-public class CertConstraintParameters {
-    // A certificate being passed to check against constraints.
-    private final X509Certificate cert;
-
-    // This is true if the trust anchor in the certificate chain matches a cert
-    // in AnchorCertificates
-    private final boolean trustedMatch;
-
-    public CertConstraintParameters(X509Certificate c, boolean match) {
-        cert = c;
-        trustedMatch = match;
-    }
-
-    public CertConstraintParameters(X509Certificate c) {
-        this(c, false);
-    }
-
-    // Returns if the trust anchor has a match if anchor checking is enabled.
-    public boolean isTrustedMatch() {
-        return trustedMatch;
-    }
-
-    public X509Certificate getCertificate() {
-        return cert;
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/util/ConstraintsParameters.java	Thu Mar 23 08:44:17 2017 -0700
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2016, 2017 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.util;
+
+import sun.security.validator.Validator;
+
+import java.security.AlgorithmParameters;
+import java.security.Key;
+import java.security.Timestamp;
+import java.security.cert.X509Certificate;
+import java.util.Date;
+
+/**
+ * This class contains parameters for checking against constraints that extend
+ * past the publicly available parameters in java.security.AlgorithmConstraints.
+
+ * This is currently on passed between  between PKIX, AlgorithmChecker,
+ * and DisabledAlgorithmConstraints.
+ */
+public class ConstraintsParameters {
+    /*
+     * The below 3 values are used the same as the permit() methods
+     * published in java.security.AlgorithmConstraints.
+     */
+    // Algorithm string to be checked against constraints
+    private final String algorithm;
+    // AlgorithmParameters to the algorithm being checked
+    private final AlgorithmParameters algParams;
+    // Public Key being checked against constraints
+    private final Key publicKey;
+
+    /*
+     * New values that are checked against constraints that the current public
+     * API does not support.
+     */
+    // A certificate being passed to check against constraints.
+    private final X509Certificate cert;
+    // This is true if the trust anchor in the certificate chain matches a cert
+    // in AnchorCertificates
+    private final boolean trustedMatch;
+    // PKIXParameter date
+    private final Date pkixDate;
+    // Timestamp of the signed JAR file
+    private final Timestamp jarTimestamp;
+    private final String variant;
+
+    public ConstraintsParameters(X509Certificate c, boolean match,
+            Date pkixdate, Timestamp jarTime, String variant) {
+        cert = c;
+        trustedMatch = match;
+        pkixDate = pkixdate;
+        jarTimestamp = jarTime;
+        this.variant = (variant == null ? Validator.VAR_GENERIC : variant);
+        algorithm = null;
+        algParams = null;
+        publicKey = null;
+    }
+
+    public ConstraintsParameters(String algorithm, AlgorithmParameters params,
+            Key key, String variant) {
+        this.algorithm = algorithm;
+        algParams = params;
+        this.publicKey = key;
+        cert = null;
+        trustedMatch = false;
+        pkixDate = null;
+        jarTimestamp = null;
+        this.variant = (variant == null ? Validator.VAR_GENERIC : variant);
+    }
+
+
+    public ConstraintsParameters(X509Certificate c) {
+        this(c, false, null, null,
+                Validator.VAR_GENERIC);
+    }
+
+    public ConstraintsParameters(Timestamp jarTime) {
+        this(null, false, null, jarTime, Validator.VAR_GENERIC);
+    }
+
+    public String getAlgorithm() {
+        return algorithm;
+    }
+
+    public AlgorithmParameters getAlgParams() {
+        return algParams;
+    }
+
+    public Key getPublicKey() {
+        return publicKey;
+    }
+    // Returns if the trust anchor has a match if anchor checking is enabled.
+    public boolean isTrustedMatch() {
+        return trustedMatch;
+    }
+
+    public X509Certificate getCertificate() {
+        return cert;
+    }
+
+    public Date getPKIXParamDate() {
+        return pkixDate;
+    }
+
+    public Timestamp getJARTimestamp() {
+        return jarTimestamp;
+    }
+
+    public String getVariant() {
+        return variant;
+    }
+}
--- a/src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java	Tue Aug 15 11:46:02 2017 -0700
+++ b/src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java	Thu Mar 23 08:44:17 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,15 +25,16 @@
 
 package sun.security.util;
 
+import sun.security.validator.Validator;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
 import java.security.AlgorithmParameters;
 import java.security.Key;
 import java.security.cert.CertPathValidatorException;
 import java.security.cert.X509Certificate;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
+import java.text.SimpleDateFormat;
+import java.util.*;
 import java.util.regex.Pattern;
 import java.util.regex.Matcher;
 
@@ -47,11 +48,11 @@
     private static final Debug debug = Debug.getInstance("certpath");
 
     // the known security property, jdk.certpath.disabledAlgorithms
-    public final static String PROPERTY_CERTPATH_DISABLED_ALGS =
+    public static final String PROPERTY_CERTPATH_DISABLED_ALGS =
             "jdk.certpath.disabledAlgorithms";
 
     // the known security property, jdk.tls.disabledAlgorithms
-    public final static String PROPERTY_TLS_DISABLED_ALGS =
+    public static final String PROPERTY_TLS_DISABLED_ALGS =
             "jdk.tls.disabledAlgorithms";
 
     // the known security property, jdk.jar.disabledAlgorithms
@@ -90,14 +91,9 @@
      * This only checks if the algorithm has been completely disabled.  If
      * there are keysize or other limit, this method allow the algorithm.
      */
-    final public boolean permits(Set<CryptoPrimitive> primitives,
+    @Override
+    public final boolean permits(Set<CryptoPrimitive> primitives,
             String algorithm, AlgorithmParameters parameters) {
-
-        if (primitives == null || primitives.isEmpty()) {
-            throw new IllegalArgumentException(
-                        "No cryptographic primitive specified");
-        }
-
         return checkAlgorithm(disabledAlgorithms, algorithm, decomposer);
     }
 
@@ -105,7 +101,8 @@
      * Checks if the key algorithm has been disabled or constraints have been
      * placed on the key.
      */
-    final public boolean permits(Set<CryptoPrimitive> primitives, Key key) {
+    @Override
+    public final boolean permits(Set<CryptoPrimitive> primitives, Key key) {
         return checkConstraints(primitives, "", key, null);
     }
 
@@ -113,7 +110,8 @@
      * Checks if the key algorithm has been disabled or if constraints have
      * been placed on the key.
      */
-    final public boolean permits(Set<CryptoPrimitive> primitives,
+    @Override
+    public final boolean permits(Set<CryptoPrimitive> primitives,
             String algorithm, Key key, AlgorithmParameters parameters) {
 
         if (algorithm == null || algorithm.length() == 0) {
@@ -123,6 +121,18 @@
         return checkConstraints(primitives, algorithm, key, parameters);
     }
 
+    public final void permits(ConstraintsParameters cp)
+            throws CertPathValidatorException {
+        permits(cp.getAlgorithm(), cp);
+    }
+
+    public final void permits(String algorithm, Key key,
+            AlgorithmParameters params, String variant)
+            throws CertPathValidatorException {
+        permits(algorithm, new ConstraintsParameters(algorithm, params, key,
+                (variant == null) ? Validator.VAR_GENERIC : variant));
+    }
+
     /*
      * Check if a x509Certificate object is permitted.  Check if all
      * algorithms are allowed, certificate constraints, and the
@@ -130,18 +140,10 @@
      *
      * Uses new style permit() which throws exceptions.
      */
-    public final void permits(Set<CryptoPrimitive> primitives,
-            CertConstraintParameters cp) throws CertPathValidatorException {
-        checkConstraints(primitives, cp);
-    }
 
-    /*
-     * Check if Certificate object is within the constraints.
-     * Uses new style permit() which throws exceptions.
-     */
-    public final void permits(Set<CryptoPrimitive> primitives,
-            X509Certificate cert) throws CertPathValidatorException {
-        checkConstraints(primitives, new CertConstraintParameters(cert));
+    public final void permits(String algorithm, ConstraintsParameters cp)
+            throws CertPathValidatorException {
+        algorithmConstraints.permits(algorithm, cp);
     }
 
     // Check if a string is contained inside the property
@@ -164,7 +166,7 @@
             throw new IllegalArgumentException("The key cannot be null");
         }
 
-        // check the signature algorithm
+        // check the signature algorithm with parameters
         if (algorithm != null && algorithm.length() != 0) {
             if (!permits(primitives, algorithm, parameters)) {
                 return false;
@@ -180,35 +182,6 @@
         return algorithmConstraints.permits(key);
     }
 
-    /*
-     * Check algorithm constraints with Certificate
-     * Uses new style permit() which throws exceptions.
-     */
-    private void checkConstraints(Set<CryptoPrimitive> primitives,
-            CertConstraintParameters cp) throws CertPathValidatorException {
-
-        X509Certificate cert = cp.getCertificate();
-        String algorithm = cert.getSigAlgName();
-
-        // Check signature algorithm is not disabled
-        if (!permits(primitives, algorithm, null)) {
-            throw new CertPathValidatorException(
-                    "Algorithm constraints check failed on disabled "+
-                    "signature algorithm: " + algorithm);
-        }
-
-        // Check key algorithm is not disabled
-        if (!permits(primitives, cert.getPublicKey().getAlgorithm(), null)) {
-            throw new CertPathValidatorException(
-                    "Algorithm constraints check failed on disabled "+
-                    "public key algorithm: " + algorithm);
-        }
-
-        // Check the certificate and key constraints
-        algorithmConstraints.permits(cp);
-
-    }
-
     /**
      * Key and Certificate Constraints
      *
@@ -222,15 +195,18 @@
      * 'true' means the operation is allowed.
      * 'false' means it failed the constraints and is disallowed.
      *
-     * When passing CertConstraintParameters through permit(), an exception
+     * When passing ConstraintsParameters through permit(), an exception
      * will be thrown on a failure to better identify why the operation was
      * disallowed.
      */
 
     private static class Constraints {
-        private Map<String, Set<Constraint>> constraintsMap = new HashMap<String, Set<Constraint>>();
-        private static final Pattern keySizePattern = Pattern.compile(
-                "keySize\\s*(<=|<|==|!=|>|>=)\\s*(\\d+)");
+        private Map<String, List<Constraint>> constraintsMap = new HashMap<String, List<Constraint>>();
+
+        private static class Holder {
+            private static final Pattern DENY_AFTER_PATTERN = Pattern.compile(
+                    "denyAfter\\s+(\\d{4})-(\\d{2})-(\\d{2})");
+        }
 
         public Constraints(String[] constraintArray) {
             for (String constraintEntry : constraintArray) {
@@ -245,41 +221,49 @@
 
                 // Check if constraint is a complete disabling of an
                 // algorithm or has conditions.
-                String algorithm;
-                String policy;
                 int space = constraintEntry.indexOf(' ');
-                if (space > 0) {
-                    algorithm = AlgorithmDecomposer.hashName(
-                            constraintEntry.substring(0, space).
-                                    toUpperCase(Locale.ENGLISH));
-                    policy = constraintEntry.substring(space + 1);
-                } else {
-                    final String key = constraintEntry.toUpperCase(Locale.ENGLISH);
-                    if (constraintsMap.get(key) == null) {
-                        constraintsMap.put(key, new HashSet<Constraint>());
-                    }
+                String algorithm = AlgorithmDecomposer.hashName(
+                        ((space > 0 ? constraintEntry.substring(0, space) :
+                                constraintEntry).
+                                toUpperCase(Locale.ENGLISH)));
+
+                List<Constraint> constraintList = constraintsMap.get(algorithm);
+                if (constraintList == null) {
+                    constraintList = new ArrayList<Constraint>(1);
+                    constraintsMap.put(algorithm, constraintList);
+                }
+                if (space <= 0) {
+                    constraintList.add(new DisabledConstraint(algorithm));
                     continue;
                 }
 
+                String policy = constraintEntry.substring(space + 1);
+
                 // Convert constraint conditions into Constraint classes
-                Constraint c = null;
-                Constraint lastConstraint = null;
+                Constraint c, lastConstraint = null;
                 // Allow only one jdkCA entry per constraint entry
                 boolean jdkCALimit = false;
+                // Allow only one denyAfter entry per constraint entry
+                boolean denyAfterLimit = false;
 
                 for (String entry : policy.split("&")) {
                     entry = entry.trim();
 
-                    Matcher matcher = keySizePattern.matcher(entry);
-                    if (matcher.matches()) {
+                    Matcher matcher;
+                    if (entry.startsWith("keySize")) {
                         if (debug != null) {
                             debug.println("Constraints set to keySize: " +
                                     entry);
                         }
+                        StringTokenizer tokens = new StringTokenizer(entry);
+                        if (!"keySize".equals(tokens.nextToken())) {
+                            throw new IllegalArgumentException("Error in " +
+                                    "security property. Constraint unknown: " +
+                                    entry);
+                        }
                         c = new KeySizeConstraint(algorithm,
-                                KeySizeConstraint.Operator.of(matcher.group(1)),
-                                Integer.parseInt(matcher.group(2)));
-
+                                KeySizeConstraint.Operator.of(tokens.nextToken()),
+                                Integer.parseInt(tokens.nextToken()));
                     } else if (entry.equalsIgnoreCase("jdkCA")) {
                         if (debug != null) {
                             debug.println("Constraints set to jdkCA.");
@@ -291,18 +275,39 @@
                         }
                         c = new jdkCAConstraint(algorithm);
                         jdkCALimit = true;
+
+                    } else if (entry.startsWith("denyAfter") &&
+                            (matcher = Holder.DENY_AFTER_PATTERN.matcher(entry))
+                                    .matches()) {
+                        if (debug != null) {
+                            debug.println("Constraints set to denyAfter");
+                        }
+                        if (denyAfterLimit) {
+                            throw new IllegalArgumentException("Only one " +
+                                    "denyAfter entry allowed in property. " +
+                                    "Constraint: " + constraintEntry);
+                        }
+                        int year = Integer.parseInt(matcher.group(1));
+                        int month = Integer.parseInt(matcher.group(2));
+                        int day = Integer.parseInt(matcher.group(3));
+                        c = new DenyAfterConstraint(algorithm, year, month,
+                                day);
+                        denyAfterLimit = true;
+                    } else if (entry.startsWith("usage")) {
+                        String s[] = (entry.substring(5)).trim().split(" ");
+                        c = new UsageConstraint(algorithm, s);
+                        if (debug != null) {
+                            debug.println("Constraints usage length is " + s.length);
+                        }
+                    } else {
+                        throw new IllegalArgumentException("Error in security" +
+                                " property. Constraint unknown: " + entry);
                     }
 
                     // Link multiple conditions for a single constraint
                     // into a linked list.
                     if (lastConstraint == null) {
-                        if (!constraintsMap.containsKey(algorithm)) {
-                            constraintsMap.put(algorithm,
-                                    new HashSet<Constraint>());
-                        }
-                        if (c != null) {
-                            constraintsMap.get(algorithm).add(c);
-                        }
+                        constraintList.add(c);
                     } else {
                         lastConstraint.nextConstraint = c;
                     }
@@ -312,61 +317,73 @@
         }
 
         // Get applicable constraints based off the signature algorithm
-        private Set<Constraint> getConstraints(String algorithm) {
+        private List<Constraint> getConstraints(String algorithm) {
             return constraintsMap.get(algorithm);
         }
 
         // Check if KeySizeConstraints permit the specified key
         public boolean permits(Key key) {
-            Set<Constraint> set = getConstraints(key.getAlgorithm());
-            if (set == null) {
+            List<Constraint> list = getConstraints(key.getAlgorithm());
+            if (list == null) {
                 return true;
             }
-            for (Constraint constraint : set) {
+            for (Constraint constraint : list) {
                 if (!constraint.permits(key)) {
                     if (debug != null) {
                         debug.println("keySizeConstraint: failed key " +
                                 "constraint check " + KeyUtil.getKeySize(key));
                     }
-            return false;
-        }
+                    return false;
+                }
             }
-        return true;
-    }
+            return true;
+        }
 
         // Check if constraints permit this cert.
-        public void permits(CertConstraintParameters cp)
+        public void permits(String algorithm, ConstraintsParameters cp)
                 throws CertPathValidatorException {
             X509Certificate cert = cp.getCertificate();
 
             if (debug != null) {
-                debug.println("Constraints.permits(): " + cert.getSigAlgName());
+                debug.println("Constraints.permits(): " + algorithm +
+                        " Variant: " + cp.getVariant());
             }
 
             // Get all signature algorithms to check for constraints
-            Set<String> algorithms =
-                    AlgorithmDecomposer.decomposeOneHash(cert.getSigAlgName());
-            if (algorithms == null || algorithms.isEmpty()) {
-                return;
-    }
+            Set<String> algorithms = new HashSet<String>();
+            if (algorithm != null) {
+                algorithms.addAll(AlgorithmDecomposer.decomposeOneHash(algorithm));
+            }
 
-            // Attempt to add the public key algorithm to the set
-            algorithms.add(cert.getPublicKey().getAlgorithm());
-
+            // Attempt to add the public key algorithm if cert provided
+            if (cert != null) {
+                algorithms.add(cert.getPublicKey().getAlgorithm());
+            }
+            if (cp.getPublicKey() != null) {
+                algorithms.add(cp.getPublicKey().getAlgorithm());
+            }
             // Check all applicable constraints
-            for (String algorithm : algorithms) {
-                Set<Constraint> set = getConstraints(algorithm);
-                if (set == null) {
+            for (String alg : algorithms) {
+                List<Constraint> list = getConstraints(alg);
+                if (list == null) {
                     continue;
                 }
-                for (Constraint constraint : set) {
+                for (Constraint constraint : list) {
                     constraint.permits(cp);
                 }
             }
         }
-                        }
+    }
 
-    // Abstract class for algorithm constraint checking
+    /**
+     * This abstract Constraint class for algorithm-based checking
+     * may contain one or more constraints.  If the '&' on the {@Security}
+     * property is used, multiple constraints have been grouped together
+     * requiring all the constraints to fail for the check to be disallowed.
+     *
+     * If the class contains multiple constraints, the next constraint
+     * is stored in {@code nextConstraint} in linked-list fashion.
+     */
     private abstract static class Constraint {
         String algorithm;
         Constraint nextConstraint = null;
@@ -400,22 +417,87 @@
         }
 
         /**
-         * Check if an algorithm constraint permit this key to be used.
+         * Check if an algorithm constraint is permitted with a given key.
+         *
+         * If the check inside of {@code permit()} fails, it must call
+         * {@code next()} with the same {@code Key} parameter passed if
+         * multiple constraints need to be checked.
+         *
          * @param key Public key
-         * @return true if constraints do not match
+         * @return 'true' if constraint is allowed, 'false' if disallowed.
          */
         public boolean permits(Key key) {
             return true;
         }
 
         /**
-         * Check if an algorithm constraint is permit this certificate to
-         * be used.
-         * @param cp CertificateParameter containing certificate and state info
-         * @return true if constraints do not match
+         * Check if an algorithm constraint is permitted with a given
+         * ConstraintsParameters.
+         *
+         * If the check inside of {@code permits()} fails, it must call
+         * {@code next()} with the same {@code ConstraintsParameters}
+         * parameter passed if multiple constraints need to be checked.
+         *
+         * @param cp CertConstraintParameter containing certificate info
+         * @throws CertPathValidatorException if constraint disallows.
+         *
+         */
+        public abstract void permits(ConstraintsParameters cp)
+                throws CertPathValidatorException;
+
+        /**
+         * Recursively check if the constraints are allowed.
+         *
+         * If {@code nextConstraint} is non-null, this method will
+         * call {@code nextConstraint}'s {@code permits()} to check if the
+         * constraint is allowed or denied.  If the constraint's
+         * {@code permits()} is allowed, this method will exit this and any
+         * recursive next() calls, returning 'true'.  If the constraints called
+         * were disallowed, the last constraint will throw
+         * {@code CertPathValidatorException}.
+         *
+         * @param cp ConstraintsParameters
+         * @return 'true' if constraint allows the operation, 'false' if
+         * we are at the end of the constraint list or,
+         * {@code nextConstraint} is null.
          */
-        public abstract void permits(CertConstraintParameters cp)
-                throws CertPathValidatorException;
+        boolean next(ConstraintsParameters cp)
+                throws CertPathValidatorException {
+            if (nextConstraint != null) {
+                nextConstraint.permits(cp);
+                return true;
+            }
+            return false;
+        }
+
+        /**
+         * Recursively check if this constraint is allowed,
+         *
+         * If {@code nextConstraint} is non-null, this method will
+         * call {@code nextConstraint}'s {@code permit()} to check if the
+         * constraint is allowed or denied.  If the constraint's
+         * {@code permit()} is allowed, this method will exit this and any
+         * recursive next() calls, returning 'true'.  If the constraints
+         * called were disallowed the check will exit with 'false'.
+         *
+         * @param key Public key
+         * @return 'true' if constraint allows the operation, 'false' if
+         * the constraint denies the operation.
+         */
+        boolean next(Key key) {
+            if (nextConstraint != null && nextConstraint.permits(key)) {
+                return true;
+            }
+            return false;
+        }
+
+        String extendedMsg(ConstraintsParameters cp) {
+            return (cp.getCertificate() == null ? "." :
+                    " used with certificate: " +
+                            cp.getCertificate().getSubjectX500Principal() +
+                    (cp.getVariant() != Validator.VAR_GENERIC ?
+                            ".  Usage was " + cp.getVariant() : "."));
+        }
     }
 
     /*
@@ -428,29 +510,172 @@
         }
 
         /*
-         * Check if each constraint fails and check if there is a linked
-         * constraint  Any permitted constraint will exit the linked list
-         * to allow the operation.
+         * Check if ConstraintsParameters has a trusted match, if it does
+         * call next() for any following constraints. If it does not, exit
+         * as this constraint(s) does not restrict the operation.
          */
-        public void permits(CertConstraintParameters cp)
+        public void permits(ConstraintsParameters cp)
                 throws CertPathValidatorException {
             if (debug != null) {
                 debug.println("jdkCAConstraints.permits(): " + algorithm);
             }
 
-            // Return false if the chain has a trust anchor in cacerts
+            // Check chain has a trust anchor in cacerts
             if (cp.isTrustedMatch()) {
-                if (nextConstraint != null) {
-                    nextConstraint.permits(cp);
+                if (next(cp)) {
                     return;
                 }
                 throw new CertPathValidatorException(
                         "Algorithm constraints check failed on certificate " +
-                        "anchor limits");
+                                "anchor limits. " + algorithm + extendedMsg(cp));
             }
         }
     }
 
+    /*
+     * This class handles the denyAfter constraint.  The date is in the UTC/GMT
+     * timezone.
+     */
+    private static class DenyAfterConstraint extends Constraint {
+        private Date denyAfterDate;
+        private static final SimpleDateFormat dateFormat =
+                new SimpleDateFormat("EEE, MMM d HH:mm:ss z yyyy");
+
+        DenyAfterConstraint(String algo, int year, int month, int day) {
+            Calendar c;
+
+            algorithm = algo;
+
+            if (debug != null) {
+                debug.println("DenyAfterConstraint read in as:  year " +
+                        year + ", month = " + month + ", day = " + day);
+            }
+
+            c = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
+            c.set(year, month - 1, day);
+
+            if (year > c.getActualMaximum(Calendar.YEAR) ||
+                    year < c.getActualMinimum(Calendar.YEAR)) {
+                throw new IllegalArgumentException(
+                        "Invalid year given in constraint: " + year);
+            }
+            if ((month - 1) > c.getActualMaximum(Calendar.MONTH) ||
+                    (month - 1) < c.getActualMinimum(Calendar.MONTH)) {
+                throw new IllegalArgumentException(
+                        "Invalid month given in constraint: " + month);
+            }
+            if (day > c.getActualMaximum(Calendar.DAY_OF_MONTH) ||
+                    day < c.getActualMinimum(Calendar.DAY_OF_MONTH)) {
+                throw new IllegalArgumentException(
+                        "Invalid Day of Month given in constraint: " + day);
+            }
+
+            denyAfterDate = c.getTime();
+            if (debug != null) {
+                debug.println("DenyAfterConstraint date set to: " +
+                        dateFormat.format(denyAfterDate));
+            }
+        }
+
+        /*
+         * Checking that the provided date is not beyond the constraint date.
+         * The provided date can be the PKIXParameter date if given,
+         * otherwise it is the current date.
+         *
+         * If the constraint disallows, call next() for any following
+         * constraints. Throw an exception if this is the last constraint.
+         */
+        @Override
+        public void permits(ConstraintsParameters cp)
+                throws CertPathValidatorException {
+            Date currentDate;
+            String errmsg;
+
+            if (cp.getJARTimestamp() != null) {
+                currentDate = cp.getJARTimestamp().getTimestamp();
+                errmsg = "JAR Timestamp date: ";
+            } else if (cp.getPKIXParamDate() != null) {
+                currentDate = cp.getPKIXParamDate();
+                errmsg = "PKIXParameter date: ";
+            } else {
+                currentDate = new Date();
+                errmsg = "Current date: ";
+            }
+
+            if (!denyAfterDate.after(currentDate)) {
+                if (next(cp)) {
+                    return;
+                }
+                throw new CertPathValidatorException(
+                        "denyAfter constraint check failed: " + algorithm +
+                                " used with Constraint date: " +
+                                dateFormat.format(denyAfterDate) + "; " + errmsg +
+                                dateFormat.format(currentDate) + extendedMsg(cp));
+            }
+        }
+
+        /*
+         * Return result if the constraint's date is beyond the current date
+         * in UTC timezone.
+         */
+        public boolean permits(Key key) {
+            if (next(key)) {
+                return true;
+            }
+            if (debug != null) {
+                debug.println("DenyAfterConstraints.permits(): " + algorithm);
+            }
+
+            return denyAfterDate.after(new Date());
+        }
+    }
+
+    /*
+    * The usage constraint is for the "usage" keyword.  It checks against the
+    * variant value in ConstraintsParameters.
+    */
+    private static class UsageConstraint extends Constraint {
+       String[] usages;
+
+        UsageConstraint(String algorithm, String[] usages) {
+            this.algorithm = algorithm;
+            this.usages = usages;
+        }
+
+        public void permits(ConstraintsParameters cp)
+                throws CertPathValidatorException {
+            for (String usage : usages) {
+
+                String v = null;
+                if (usage.compareToIgnoreCase("TLSServer") == 0) {
+                    v = Validator.VAR_TLS_SERVER;
+                } else if (usage.compareToIgnoreCase("TLSClient") == 0) {
+                    v = Validator.VAR_TLS_CLIENT;
+                } else if (usage.compareToIgnoreCase("SignedJAR") == 0) {
+                    v = Validator.VAR_PLUGIN_CODE_SIGNING;
+                }
+
+                if (debug != null) {
+                    debug.println("Checking if usage constraint \"" + v +
+                            "\" matches \"" + cp.getVariant() + "\"");
+                    // Because usage checking can come from many places
+                    // a stack trace is very helpful.
+                    ByteArrayOutputStream ba = new ByteArrayOutputStream();
+                    PrintStream ps = new PrintStream(ba);
+                    (new Exception()).printStackTrace(ps);
+                    debug.println(ba.toString());
+                }
+                if (cp.getVariant().compareTo(v) == 0) {
+                    if (next(cp)) {
+                        return;
+                    }
+                    throw new CertPathValidatorException("Usage constraint " +
+                            usage + " check failed: " + algorithm +
+                            extendedMsg(cp));
+                }
+            }
+        }
+    }
 
     /*
      * This class contains constraints dealing with the key size
@@ -461,6 +686,7 @@
         private int minSize;            // the minimal available key size
         private int maxSize;            // the maximal available key size
         private int prohibitedSize = -1;    // unavailable key sizes
+        private int size;
 
         public KeySizeConstraint(String algo, Operator operator, int length) {
             algorithm = algo;
@@ -504,15 +730,22 @@
          * constraint  Any permitted constraint will exit the linked list
          * to allow the operation.
          */
-        public void permits(CertConstraintParameters cp)
+        public void permits(ConstraintsParameters cp)
 	    throws CertPathValidatorException {
-            if (!permitsImpl(cp.getCertificate().getPublicKey())) {
+            Key key = null;
+            if (cp.getPublicKey() != null) {
+                key = cp.getPublicKey();
+            } else if (cp.getCertificate() != null) {
+                key = cp.getCertificate().getPublicKey();
+            }
+            if (key != null && !permitsImpl(key)) {
                 if (nextConstraint != null) {
                     nextConstraint.permits(cp);
                     return;
                 }
                 throw new CertPathValidatorException(
-                   "Algorithm constraints check failed on keysize limits");
+                        "Algorithm constraints check failed on keysize limits. "
+                                + algorithm + " " + size + "bit key" + extendedMsg(cp));
             }
         }
 
@@ -537,7 +770,7 @@
                 return true;
             }
 
-            int size = KeyUtil.getKeySize(key);
+            size = KeyUtil.getKeySize(key);
             if (size == 0) {
                 return false;    // we don't allow any key of size 0.
             } else if (size > 0) {
@@ -551,5 +784,25 @@
 
     }
 
+    /*
+     * This constraint is used for the complete disabling of the algorithm.
+     */
+    private static class DisabledConstraint extends Constraint {
+        DisabledConstraint(String algo) {
+            algorithm = algo;
+        }
+
+        public void permits(ConstraintsParameters cp)
+                throws CertPathValidatorException {
+                       throw new CertPathValidatorException(
+                               "Algorithm constraints check failed on disabled " +
+                                       "algorithm: " + algorithm + extendedMsg(cp));
+        }
+
+        public boolean permits(Key key) {
+            return false;
+        }
+    }
+
 }
 
--- a/src/share/classes/sun/security/util/SignatureFileVerifier.java	Tue Aug 15 11:46:02 2017 -0700
+++ b/src/share/classes/sun/security/util/SignatureFileVerifier.java	Thu Mar 23 08:44:17 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,11 +31,8 @@
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.security.SignatureException;
-import java.security.cert.CertPath;
-import java.security.cert.X509Certificate;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactory;
-import java.io.ByteArrayOutputStream;
+import java.security.Timestamp;
+import java.security.cert.*;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -65,9 +62,6 @@
     /* Are we debugging ? */
     private static final Debug debug = Debug.getInstance("jar");
 
-    private static final Set<CryptoPrimitive> DIGEST_PRIMITIVE_SET =
-            Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.MESSAGE_DIGEST));
-
     private static final DisabledAlgorithmConstraints JAR_DISABLED_CHECK =
             new DisabledAlgorithmConstraints(
                     DisabledAlgorithmConstraints.PROPERTY_JAR_DISABLED_ALGS);
@@ -82,7 +76,7 @@
     private PKCS7 block;
 
     /** the raw bytes of the .SF file */
-    private byte sfBytes[];
+    private byte[] sfBytes;
 
     /** the name of the signature block file, uppercased and without
      *  the extension (.DSA/.RSA/.EC)
@@ -101,6 +95,14 @@
     /* for generating certpath objects */
     private CertificateFactory certificateFactory = null;
 
+    /** Algorithms that have been checked if they are weak. */
+    private Map<String, Boolean> permittedAlgs= new HashMap<String, Boolean>();
+
+    /** TSA timestamp of signed jar.  The newest timestamp is used.  If there
+     *  was no TSA timestamp used when signed, current time is used ("null").
+     */
+    private Timestamp timestamp = null;
+
     /**
      * Create the named SignatureFileVerifier.
      *
@@ -111,7 +113,7 @@
     public SignatureFileVerifier(ArrayList<CodeSigner[]> signerCache,
                                  ManifestDigester md,
                                  String name,
-                                 byte rawBytes[])
+                                 byte[] rawBytes)
         throws IOException, CertificateException
     {
         // new PKCS7() calls CertificateFactory.getInstance()
@@ -125,7 +127,7 @@
         } finally {
             Providers.stopJarVerification(obj);
         }
-        this.name = name.substring(0, name.lastIndexOf("."))
+        this.name = name.substring(0, name.lastIndexOf('.'))
                                                    .toUpperCase(Locale.ENGLISH);
         this.md = md;
         this.signerCache = signerCache;
@@ -156,7 +158,7 @@
      * used to set the raw bytes of the .SF file when it
      * is external to the signature block file.
      */
-    public void setSignatureFile(byte sfBytes[])
+    public void setSignatureFile(byte[] sfBytes)
     {
         this.sfBytes = sfBytes;
     }
@@ -172,11 +174,10 @@
      */
     public static boolean isBlockOrSF(String s) {
         // we currently only support DSA and RSA PKCS7 blocks
-        if (s.endsWith(".SF") || s.endsWith(".DSA") ||
-                s.endsWith(".RSA") || s.endsWith(".EC")) {
-            return true;
-        }
-        return false;
+        return s.endsWith(".SF")
+            || s.endsWith(".DSA")
+            || s.endsWith(".RSA")
+            || s.endsWith(".EC");
     }
 
     /**
@@ -186,7 +187,7 @@
      * unknown signature related files (those starting with SIG- with
      * an optional [A-Z0-9]{1,3} extension right inside META-INF).
      *
-     * @param s file name
+     * @param name file name
      * @return true if the input file name is signature related
      */
     public static boolean isSigningRelated(String name) {
@@ -227,15 +228,8 @@
 
     /** get digest from cache */
 
-    private MessageDigest getDigest(String algorithm) throws SignatureException {
-        // check that algorithm is not restricted
-        if (!JAR_DISABLED_CHECK.permits(DIGEST_PRIMITIVE_SET, algorithm, null)) {
-            SignatureException e =
-                    new SignatureException("SignatureFile check failed. " +
-                            "Disabled algorithm used: " + algorithm);
-            throw e;
-        }
-
+    private MessageDigest getDigest(String algorithm)
+            throws SignatureException {
         if (createdDigests == null)
             createdDigests = new HashMap<String, MessageDigest>();
 
@@ -308,6 +302,27 @@
         if (newSigners == null)
             return;
 
+        /*
+         * Look for the latest timestamp in the signature block.  If an entry
+         * has no timestamp, use current time (aka null).
+         */
+        for (CodeSigner s: newSigners) {
+            if (debug != null) {
+                debug.println("Gathering timestamp for:  " + s.toString());
+            }
+            if (s.getTimestamp() == null) {
+                timestamp = null;
+                break;
+            } else if (timestamp == null) {
+                timestamp = s.getTimestamp();
+            } else {
+                if (timestamp.getTimestamp().before(
+                        s.getTimestamp().getTimestamp())) {
+                    timestamp = s.getTimestamp();
+                }
+            }
+        }
+
         Iterator<Map.Entry<String,Attributes>> entries =
                                 sf.getEntries().entrySet().iterator();
 
@@ -348,6 +363,68 @@
     }
 
     /**
+     * Check if algorithm is permitted using the permittedAlgs Map.
+     * If the algorithm is not in the map, check against disabled algorithms and
+     * store the result. If the algorithm is in the map use that result.
+     * False is returned for weak algorithm, true for good algorithms.
+     */
+    boolean permittedCheck(String key, String algorithm) {
+        Boolean permitted = permittedAlgs.get(algorithm);
+        if (permitted == null) {
+            try {
+                JAR_DISABLED_CHECK.permits(algorithm,
+                        new ConstraintsParameters(timestamp));
+            } catch(CertPathValidatorException e) {
+                permittedAlgs.put(algorithm, Boolean.FALSE);
+                permittedAlgs.put(key.toUpperCase(), Boolean.FALSE);
+                if (debug != null) {
+                    if (e.getMessage() != null) {
+                        debug.println(key + ":  " + e.getMessage());
+                    } else {
+                        debug.println(key + ":  " + algorithm +
+                                " was disabled, no exception msg given.");
+                        e.printStackTrace();
+                    }
+                }
+                return false;
+            }
+
+            permittedAlgs.put(algorithm, Boolean.TRUE);
+            return true;
+        }
+
+        // Algorithm has already been checked, return the value from map.
+        return permitted.booleanValue();
+    }
+
+    /**
+     * With a given header (*-DIGEST*), return a string that lists all the
+     * algorithms associated with the header.
+     * If there are none, return "Unknown Algorithm".
+     */
+    String getWeakAlgorithms(String header) {
+        String w = "";
+        try {
+            for (String key : permittedAlgs.keySet()) {
+                if (key.endsWith(header)) {
+                    w += key.substring(0, key.length() - header.length()) + " ";
+                }
+            }
+        } catch (RuntimeException e) {
+            w = "Unknown Algorithm(s).  Error processing " + header + ".  " +
+                    e.getMessage();
+        }
+
+        // This means we have an error in finding weak algorithms, run in
+        // debug mode to see permittedAlgs map's values.
+        if (w.length() == 0) {
+            return "Unknown Algorithm(s)";
+        }
+
+        return w;
+    }
+
+    /**
      * See if the whole manifest was signed.
      */
     private boolean verifyManifestHash(Manifest sf,
@@ -358,6 +435,10 @@
     {
         Attributes mattr = sf.getMainAttributes();
         boolean manifestSigned = false;
+        // If only weak algorithms are used.
+        boolean weakAlgs = true;
+        // If a "*-DIGEST-MANIFEST" entry is found.
+        boolean validEntry = false;
 
         // go through all the attributes and process *-Digest-Manifest entries
         for (Map.Entry<Object,Object> se : mattr.entrySet()) {
@@ -367,6 +448,16 @@
             if (key.toUpperCase(Locale.ENGLISH).endsWith("-DIGEST-MANIFEST")) {
                 // 16 is length of "-Digest-Manifest"
                 String algorithm = key.substring(0, key.length()-16);
+                validEntry = true;
+
+                // Check if this algorithm is permitted, skip if false.
+                if (!permittedCheck(key, algorithm)) {
+                    continue;
+                }
+
+                // A non-weak algorithm was used, any weak algorithms found do
+                // not need to be reported.
+                weakAlgs = false;
 
                 manifestDigests.add(key);
                 manifestDigests.add(se.getValue());
@@ -377,15 +468,14 @@
                         decoder.decodeBuffer((String)se.getValue());
 
                     if (debug != null) {
-                     debug.println("Signature File: Manifest digest " +
-                                          digest.getAlgorithm());
-                     debug.println( "  sigfile  " + toHex(expectedHash));
-                     debug.println( "  computed " + toHex(computedHash));
-                     debug.println();
+                        debug.println("Signature File: Manifest digest " +
+                                algorithm);
+                        debug.println( "  sigfile  " + toHex(expectedHash));
+                        debug.println( "  computed " + toHex(computedHash));
+                        debug.println();
                     }
 
-                    if (MessageDigest.isEqual(computedHash,
-                                              expectedHash)) {
+                    if (MessageDigest.isEqual(computedHash, expectedHash)) {
                         manifestSigned = true;
                     } else {
                         //XXX: we will continue and verify each section
@@ -393,6 +483,21 @@
                 }
             }
         }
+
+        if (debug != null) {
+            debug.println("PermittedAlgs mapping: ");
+            for (String key : permittedAlgs.keySet()) {
+                debug.println(key + " : " +
+                        permittedAlgs.get(key).toString());
+            }
+        }
+
+        // If there were only weak algorithms entries used, throw an exception.
+        if (validEntry && weakAlgs) {
+            throw new SignatureException("Manifest hash check failed " +
+                    "(DIGEST-MANIFEST). Disabled algorithm(s) used: " +
+                    getWeakAlgorithms("-DIGEST-MANIFEST"));
+        }
         return manifestSigned;
     }
 
@@ -403,6 +508,10 @@
     {
         Attributes mattr = sf.getMainAttributes();
         boolean attrsVerified = true;
+        // If only weak algorithms are used.
+        boolean weakAlgs = true;
+        // If a ATTR_DIGEST entry is found.
+        boolean validEntry = false;
 
         // go through all the attributes and process
         // digest entries for the manifest main attributes
@@ -412,6 +521,16 @@
             if (key.toUpperCase(Locale.ENGLISH).endsWith(ATTR_DIGEST)) {
                 String algorithm =
                         key.substring(0, key.length() - ATTR_DIGEST.length());
+                validEntry = true;
+
+                // Check if this algorithm is permitted, skip if false.
+                if (!permittedCheck(key, algorithm)) {
+                    continue;
+                }
+
+                // A non-weak algorithm was used, any weak algorithms found do
+                // not need to be reported.
+                weakAlgs = false;
 
                 MessageDigest digest = getDigest(algorithm);
                 if (digest != null) {
@@ -430,8 +549,7 @@
                      debug.println();
                     }
 
-                    if (MessageDigest.isEqual(computedHash,
-                                              expectedHash)) {
+                    if (MessageDigest.isEqual(computedHash, expectedHash)) {
                         // good
                     } else {
                         // we will *not* continue and verify each section
@@ -447,6 +565,22 @@
             }
         }
 
+        if (debug != null) {
+            debug.println("PermittedAlgs mapping: ");
+            for (String key : permittedAlgs.keySet()) {
+                debug.println(key + " : " +
+                        permittedAlgs.get(key).toString());
+            }
+        }
+
+        // If there were only weak algorithms entries used, throw an exception.
+        if (validEntry && weakAlgs) {
+            throw new SignatureException("Manifest Main Attribute check " +
+                    "failed (" + ATTR_DIGEST + ").  " +
+                    "Disabled algorithm(s) used: " +
+                    getWeakAlgorithms(ATTR_DIGEST));
+        }
+
         // this method returns 'true' if either:
         //      . manifest main attributes were not signed, or
         //      . manifest main attributes were signed and verified
@@ -470,6 +604,10 @@
     {
         boolean oneDigestVerified = false;
         ManifestDigester.Entry mde = md.get(name,block.isOldStyle());
+        // If only weak algorithms are used.
+        boolean weakAlgs = true;
+        // If a "*-DIGEST" entry is found.
+        boolean validEntry = false;
 
         if (mde == null) {
             throw new SecurityException(
@@ -477,8 +615,7 @@
         }
 
         if (sfAttr != null) {
-
-            //sun.misc.HexDumpEncoder hex = new sun.misc.HexDumpEncoder();
+            //sun.security.util.HexDumpEncoder hex = new sun.security.util.HexDumpEncoder();
             //hex.encodeBuffer(data, System.out);
 
             // go through all the attributes and process *-Digest entries
@@ -488,6 +625,16 @@
                 if (key.toUpperCase(Locale.ENGLISH).endsWith("-DIGEST")) {
                     // 7 is length of "-Digest"
                     String algorithm = key.substring(0, key.length()-7);
+                    validEntry = true;
+
+                    // Check if this algorithm is permitted, skip if false.
+                    if (!permittedCheck(key, algorithm)) {
+                        continue;
+                    }
+
+                    // A non-weak algorithm was used, any weak algorithms found do
+                    // not need to be reported.
+                    weakAlgs = false;
 
                     MessageDigest digest = getDigest(algorithm);
 
@@ -538,6 +685,22 @@
                 }
             }
         }
+
+        if (debug != null) {
+            debug.println("PermittedAlgs mapping: ");
+            for (String key : permittedAlgs.keySet()) {
+                debug.println(key + " : " +
+                        permittedAlgs.get(key).toString());
+            }
+        }
+
+        // If there were only weak algorithms entries used, throw an exception.
+        if (validEntry && weakAlgs) {
+            throw new SignatureException("Manifest Main Attribute check " +
+                    "failed (DIGEST).  Disabled algorithm(s) used: " +
+                    getWeakAlgorithms("DIGEST"));
+        }
+
         return oneDigestVerified;
     }
 
@@ -546,7 +709,7 @@
      * CodeSigner objects. We do this only *once* for a given
      * signature block file.
      */
-    private CodeSigner[] getSigners(SignerInfo infos[], PKCS7 block)
+    private CodeSigner[] getSigners(SignerInfo[] infos, PKCS7 block)
         throws IOException, NoSuchAlgorithmException, SignatureException,
             CertificateException {
 
@@ -587,7 +750,7 @@
 
     static String toHex(byte[] data) {
 
-        StringBuffer sb = new StringBuffer(data.length*2);
+        StringBuilder sb = new StringBuilder(data.length*2);
 
         for (int i=0; i<data.length; i++) {
             sb.append(hexc[(data[i] >>4) & 0x0f]);
--- a/src/share/classes/sun/security/validator/PKIXValidator.java	Tue Aug 15 11:46:02 2017 -0700
+++ b/src/share/classes/sun/security/validator/PKIXValidator.java	Thu Mar 23 08:44:17 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,10 +34,11 @@
 import sun.security.action.GetBooleanAction;
 import sun.security.provider.certpath.AlgorithmChecker;
 import sun.security.util.AlgorithmConstraints;
+import sun.security.provider.certpath.PKIXExtendedParameters;
 
 /**
  * Validator implementation built on the PKIX CertPath API. This
- * implementation will be emphasized going forward.<p>
+ * implementation will be emphasized going forward.
  * <p>
  * Note that the validate() implementation tries to use a PKIX validator
  * if that appears possible and a PKIX builder otherwise. This increases
@@ -209,13 +210,22 @@
                 ("null or zero-length certificate chain");
         }
 
-        // add  new algorithm constraints checker
-        PKIXBuilderParameters pkixParameters =
-                    (PKIXBuilderParameters) parameterTemplate.clone();
-        AlgorithmChecker algorithmChecker = null;
+        // Use PKIXExtendedParameters for timestamp and variant additions
+        PKIXBuilderParameters pkixParameters = null;
+        try {
+            pkixParameters = new PKIXExtendedParameters(
+                    (PKIXBuilderParameters) parameterTemplate.clone(),
+                    (parameter instanceof Timestamp) ?
+                            (Timestamp) parameter : null,
+                    variant);
+        } catch (InvalidAlgorithmParameterException e) {
+            // ignore exception
+        }
+
+        // add a new algorithm constraints checker
         if (constraints != null) {
-            algorithmChecker = new AlgorithmChecker(constraints);
-            pkixParameters.addCertPathChecker(algorithmChecker);
+            pkixParameters.addCertPathChecker(
+                    new AlgorithmChecker(constraints, null, variant));
         }
 
         if (TRY_VALIDATOR) {
--- a/src/share/classes/sun/security/validator/SimpleValidator.java	Tue Aug 15 11:46:02 2017 -0700
+++ b/src/share/classes/sun/security/validator/SimpleValidator.java	Thu Mar 23 08:44:17 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,6 +34,7 @@
 import javax.security.auth.x500.X500Principal;
 
 import sun.security.x509.X509CertImpl;
+import sun.security.x509.KeyIdentifier;
 import sun.security.x509.NetscapeCertTypeExtension;
 import sun.security.util.AlgorithmConstraints;
 import sun.security.util.DerValue;
@@ -153,12 +154,14 @@
 
         // create default algorithm constraints checker
         TrustAnchor anchor = new TrustAnchor(anchorCert, null);
-        AlgorithmChecker defaultAlgChecker = new AlgorithmChecker(anchor);
+        AlgorithmChecker defaultAlgChecker =
+                new AlgorithmChecker(anchor, variant);
 
         // create application level algorithm constraints checker
         AlgorithmChecker appAlgChecker = null;
         if (constraints != null) {
-            appAlgChecker = new AlgorithmChecker(anchor, constraints);
+            appAlgChecker = new AlgorithmChecker(anchor, constraints, null,
+                    null, variant);
         }
 
         // verify top down, starting at the certificate issued by
--- a/src/share/classes/sun/security/x509/PKIXExtensions.java	Tue Aug 15 11:46:02 2017 -0700
+++ b/src/share/classes/sun/security/x509/PKIXExtensions.java	Thu Mar 23 08:44:17 2017 -0700
@@ -49,32 +49,37 @@
  */
 public class PKIXExtensions {
     // The object identifiers
-    private static final int AuthorityKey_data [] = { 2, 5, 29, 35 };
-    private static final int SubjectKey_data [] = { 2, 5, 29, 14 };
-    private static final int KeyUsage_data [] = { 2, 5, 29, 15 };
-    private static final int PrivateKeyUsage_data [] = { 2, 5, 29, 16 };
-    private static final int CertificatePolicies_data [] = { 2, 5, 29, 32 };
-    private static final int PolicyMappings_data [] = { 2, 5, 29, 33 };
-    private static final int SubjectAlternativeName_data [] = { 2, 5, 29, 17 };
-    private static final int IssuerAlternativeName_data [] = { 2, 5, 29, 18 };
-    private static final int SubjectDirectoryAttributes_data [] = { 2, 5, 29, 9 };
-    private static final int BasicConstraints_data [] = { 2, 5, 29, 19 };
-    private static final int NameConstraints_data [] = { 2, 5, 29, 30 };
-    private static final int PolicyConstraints_data [] = { 2, 5, 29, 36 };
-    private static final int CRLDistributionPoints_data [] = { 2, 5, 29, 31 };
-    private static final int CRLNumber_data [] = { 2, 5, 29, 20 };
-    private static final int IssuingDistributionPoint_data [] = { 2, 5, 29, 28 };
-    private static final int DeltaCRLIndicator_data [] = { 2, 5, 29, 27 };
-    private static final int ReasonCode_data [] = { 2, 5, 29, 21 };
-    private static final int HoldInstructionCode_data [] = { 2, 5, 29, 23 };
-    private static final int InvalidityDate_data [] = { 2, 5, 29, 24 };
-    private static final int ExtendedKeyUsage_data [] = { 2, 5, 29, 37 };
-    private static final int InhibitAnyPolicy_data [] = { 2, 5, 29, 54 };
-    private static final int CertificateIssuer_data [] = { 2, 5, 29, 29 };
-    private static final int AuthInfoAccess_data [] = { 1, 3, 6, 1, 5, 5, 7, 1, 1};
-    private static final int SubjectInfoAccess_data [] = { 1, 3, 6, 1, 5, 5, 7, 1, 11};
-    private static final int FreshestCRL_data [] = { 2, 5, 29, 46 };
-
+    private static final int[] AuthorityKey_data = { 2, 5, 29, 35 };
+    private static final int[] SubjectKey_data = { 2, 5, 29, 14 };
+    private static final int[] KeyUsage_data = { 2, 5, 29, 15 };
+    private static final int[] PrivateKeyUsage_data = { 2, 5, 29, 16 };
+    private static final int[] CertificatePolicies_data = { 2, 5, 29, 32 };
+    private static final int[] PolicyMappings_data = { 2, 5, 29, 33 };
+    private static final int[] SubjectAlternativeName_data = { 2, 5, 29, 17 };
+    private static final int[] IssuerAlternativeName_data = { 2, 5, 29, 18 };
+    private static final int[] SubjectDirectoryAttributes_data = { 2, 5, 29, 9 };
+    private static final int[] BasicConstraints_data = { 2, 5, 29, 19 };
+    private static final int[] NameConstraints_data = { 2, 5, 29, 30 };
+    private static final int[] PolicyConstraints_data = { 2, 5, 29, 36 };
+    private static final int[] CRLDistributionPoints_data = { 2, 5, 29, 31 };
+    private static final int[] CRLNumber_data = { 2, 5, 29, 20 };
+    private static final int[] IssuingDistributionPoint_data = { 2, 5, 29, 28 };
+    private static final int[] DeltaCRLIndicator_data = { 2, 5, 29, 27 };
+    private static final int[] ReasonCode_data = { 2, 5, 29, 21 };
+    private static final int[] HoldInstructionCode_data = { 2, 5, 29, 23 };
+    private static final int[] InvalidityDate_data = { 2, 5, 29, 24 };
+    private static final int[] ExtendedKeyUsage_data = { 2, 5, 29, 37 };
+    private static final int[] InhibitAnyPolicy_data = { 2, 5, 29, 54 };
+    private static final int[] CertificateIssuer_data = { 2, 5, 29, 29 };
+    private static final int[] AuthInfoAccess_data = { 1, 3, 6, 1, 5, 5, 7, 1, 1};
+    private static final int[] SubjectInfoAccess_data = { 1, 3, 6, 1, 5, 5, 7, 1, 11};
+    private static final int[] FreshestCRL_data = { 2, 5, 29, 46 };
+    private static final int[] OCSPNoCheck_data = { 1, 3, 6, 1, 5, 5, 7,
+                                                    48, 1, 5};
+    // Additional extensions under the PKIX arc that are not necessarily
+    // used in X.509 Certificates or CRLs.
+    private static final int[] OCSPNonce_data = { 1, 3, 6, 1, 5, 5, 7,
+                                                  48, 1, 2};
     /**
      * Identifies the particular public key used to sign the certificate.
      */
@@ -102,18 +107,20 @@
     public static final ObjectIdentifier CertificatePolicies_Id;
 
     /**
-     * Lists pairs of objectidentifiers of policies considered equivalent by the
-     * issuing CA to the subject CA.
+     * Lists pairs of object identifiers of policies considered equivalent by
+     * the issuing CA to the subject CA.
      */
     public static final ObjectIdentifier PolicyMappings_Id;
 
     /**
-     * Allows additional identities to be bound to the subject of the certificate.
+     * Allows additional identities to be bound to the subject of the
+     * certificate.
      */
     public static final ObjectIdentifier SubjectAlternativeName_Id;
 
     /**
-     * Allows additional identities to be associated with the certificate issuer.
+     * Allows additional identities to be associated with the certificate
+     * issuer.
      */
     public static final ObjectIdentifier IssuerAlternativeName_Id;
 
@@ -216,6 +223,18 @@
      */
     public static final ObjectIdentifier FreshestCRL_Id;
 
+    /**
+     * Identifies the OCSP client can trust the responder for the
+     * lifetime of the responder's certificate.
+     */
+    public static final ObjectIdentifier OCSPNoCheck_Id;
+
+    /**
+     * This extension is used to provide nonce data for OCSP requests
+     * or responses.
+     */
+    public static final ObjectIdentifier OCSPNonce_Id;
+
     static {
         AuthorityKey_Id = ObjectIdentifier.newInternal(AuthorityKey_data);
         SubjectKey_Id   = ObjectIdentifier.newInternal(SubjectKey_data);
@@ -257,5 +276,7 @@
         SubjectInfoAccess_Id =
             ObjectIdentifier.newInternal(SubjectInfoAccess_data);
         FreshestCRL_Id = ObjectIdentifier.newInternal(FreshestCRL_data);
+        OCSPNoCheck_Id = ObjectIdentifier.newInternal(OCSPNoCheck_data);
+        OCSPNonce_Id = ObjectIdentifier.newInternal(OCSPNonce_data);
     }
 }
--- a/src/share/lib/security/java.security-linux	Tue Aug 15 11:46:02 2017 -0700
+++ b/src/share/lib/security/java.security-linux	Thu Mar 23 08:44:17 2017 -0700
@@ -368,9 +368,7 @@
 # describes the mechanism for disabling algorithms based on algorithm name
 # and/or key length.  This includes algorithms used in certificates, as well
 # as revocation information such as CRLs and signed OCSP Responses.
-#
-# The syntax of the disabled algorithm string is described as this Java
-# BNF-style:
+# The syntax of the disabled algorithm string is described as follows:
 #   DisabledAlgorithms:
 #       " DisabledAlgorithm { , DisabledAlgorithm } "
 #
@@ -381,25 +379,26 @@
 #       (see below)
 #
 #   Constraint:
-#       KeySizeConstraint, CertConstraint
+#       KeySizeConstraint | CAConstraint | DenyAfterConstraint |
+#       UsageConstraint
 #
 #   KeySizeConstraint:
-#       keySize Operator DecimalInteger
+#       keySize Operator KeyLength
 #
 #   Operator:
 #       <= | < | == | != | >= | >
 #
-#   DecimalInteger:
-#       DecimalDigits
+#   KeyLength:
+#       Integer value of the algorithm's key length in bits
 #
-#   DecimalDigits:
-#       DecimalDigit {DecimalDigit}
+#   CAConstraint:
+#       jdkCA
 #
-#   DecimalDigit: one of
-#       1 2 3 4 5 6 7 8 9 0
+#   DenyAfterConstraint:
+#       denyAfter YYYY-MM-DD
 #
-#   CertConstraint
-#       jdkCA
+#   UsageConstraint:
+#       usage [TLSServer] [TLSClient] [SignedJAR]
 #
 # The "AlgorithmName" is the standard algorithm name of the disabled
 # algorithm. See "Java Cryptography Architecture Standard Algorithm Name
@@ -413,27 +412,55 @@
 # that rely on DSA, such as NONEwithDSA, SHA1withDSA.  However, the assertion
 # will not disable algorithms related to "ECDSA".
 #
-# A "Constraint" provides further guidance for the algorithm being specified.
-# The "KeySizeConstraint" requires a key of a valid size range if the
-# "AlgorithmName" is of a key algorithm.  The "DecimalInteger" indicates the
-# key size specified in number of bits.  For example, "RSA keySize <= 1024"
-# indicates that any RSA key with key size less than or equal to 1024 bits
-# should be disabled, and "RSA keySize < 1024, RSA keySize > 2048" indicates
-# that any RSA key with key size less than 1024 or greater than 2048 should
-# be disabled. Note that the "KeySizeConstraint" only makes sense to key
-# algorithms.
+# A "Constraint" defines restrictions on the keys and/or certificates for
+# a specified AlgorithmName:
+#
+#   KeySizeConstraint:
+#     keySize Operator KeyLength
+#       The constraint requires a key of a valid size range if the
+#       "AlgorithmName" is of a key algorithm.  The "KeyLength" indicates
+#       the key size specified in number of bits.  For example,
+#       "RSA keySize <= 1024" indicates that any RSA key with key size less
+#       than or equal to 1024 bits should be disabled, and
+#       "RSA keySize < 1024, RSA keySize > 2048" indicates that any RSA key
+#       with key size less than 1024 or greater than 2048 should be disabled.
+#       This constraint is only used on algorithms that have a key size.
+#
+#   CAConstraint:
+#     jdkCA
+#       This constraint prohibits the specified algorithm only if the
+#       algorithm is used in a certificate chain that terminates at a marked
+#       trust anchor in the lib/security/cacerts keystore.  If the jdkCA
+#       constraint is not set, then all chains using the specified algorithm
+#       are restricted.  jdkCA may only be used once in a DisabledAlgorithm
+#       expression.
+#       Example:  To apply this constraint to SHA-1 certificates, include
+#       the following:  "SHA1 jdkCA"
 #
-# "CertConstraint" specifies additional constraints for
-# certificates that contain algorithms that are restricted:
+#   DenyAfterConstraint:
+#     denyAfter YYYY-MM-DD
+#       This constraint prohibits a certificate with the specified algorithm
+#       from being used after the date regardless of the certificate's
+#       validity.  JAR files that are signed and timestamped before the
+#       constraint date with certificates containing the disabled algorithm
+#       will not be restricted.  The date is processed in the UTC timezone.
+#       This constraint can only be used once in a DisabledAlgorithm
+#       expression.
+#       Example:  To deny usage of RSA 2048 bit certificates after Feb 3 2020,
+#       use the following:  "RSA keySize == 2048 & denyAfter 2020-02-03"
 #
-#   "jdkCA" prohibits the specified algorithm only if the algorithm is used
-#     in a certificate chain that terminates at a marked trust anchor in the
-#     lib/security/cacerts keystore.  All other chains are not affected.
-#     If the jdkCA constraint is not set, then all chains using the
-#     specified algorithm are restricted.  jdkCA may only be used once in
-#     a DisabledAlgorithm expression.
-#     Example:  To apply this constraint to SHA-1 certificates, include
-#     the following:  "SHA1 jdkCA"
+#   UsageConstraint:
+#     usage [TLSServer] [TLSClient] [SignedJAR]
+#       This constraint prohibits the specified algorithm for
+#       a specified usage.  This should be used when disabling an algorithm
+#       for all usages is not practical. 'TLSServer' restricts the algorithm
+#       in TLS server certificate chains when server authentication is
+#       performed. 'TLSClient' restricts the algorithm in TLS client
+#       certificate chains when client authentication is performed.
+#       'SignedJAR' constrains use of certificates in signed jar files.
+#       The usage type follows the keyword and more than one usage type can
+#       be specified with a whitespace delimiter.
+#       Example:  "SHA1 usage TLSServer TLSClient"
 #
 # When an algorithm must satisfy more than one constraint, it must be
 # delimited by an ampersand '&'.  For example, to restrict certificates in a
@@ -446,6 +473,9 @@
 # before larger keysize constraints of the same algorithm.  For example:
 # "RSA keySize < 1024 & jdkCA, RSA keySize < 2048".
 #
+# Note: The algorithm restrictions do not apply to trust anchors or
+# self-signed certificates.
+#
 # Note: This property is currently used by Oracle's PKIX implementation. It
 # is not guaranteed to be examined and used by other implementations.
 #
@@ -453,9 +483,10 @@
 #   jdk.certpath.disabledAlgorithms=MD2, DSA, RSA keySize < 2048
 #
 #
-jdk.certpath.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, \
-    DSA keySize < 1024, EC keySize < 224
+jdk.certpath.disabledAlgorithms=MD2, MD5, SHA1 jdkCA & usage TLSServer, \
+    RSA keySize < 1024, DSA keySize < 1024, EC keySize < 224
 
+#
 # Algorithm restrictions for signed JAR files
 #
 # In some environments, certain algorithms or key lengths may be undesirable
@@ -470,17 +501,20 @@
 #       " DisabledAlgorithm { , DisabledAlgorithm } "
 #
 #   DisabledAlgorithm:
-#       AlgorithmName [Constraint]
+#       AlgorithmName [Constraint] { '&' Constraint }
 #
 #   AlgorithmName:
 #       (see below)
 #
 #   Constraint:
-#       KeySizeConstraint
+#       KeySizeConstraint | DenyAfterConstraint
 #
 #   KeySizeConstraint:
 #       keySize Operator KeyLength
 #
+#   DenyAfterConstraint:
+#       denyAfter YYYY-MM-DD
+#
 #   Operator:
 #       <= | < | == | != | >= | >
 #
@@ -491,8 +525,11 @@
 # implementation. It is not guaranteed to be examined and used by other
 # implementations.
 #
+# See "jdk.certpath.disabledAlgorithms" for syntax descriptions.
+#
 jdk.jar.disabledAlgorithms=MD2, MD5, RSA keySize < 1024
 
+#
 # Algorithm restrictions for Secure Socket Layer/Transport Layer Security
 # (SSL/TLS) processing
 #
@@ -514,6 +551,9 @@
 # See the specification of "jdk.certpath.disabledAlgorithms" for the
 # syntax of the disabled algorithm string.
 #
+# Note: The algorithm restrictions do not apply to trust anchors or
+# self-signed certificates.
+#
 # Note: This property is currently used by the JDK Reference implementation.
 # It is not guaranteed to be examined and used by other implementations.
 #
--- a/src/share/lib/security/java.security-solaris	Tue Aug 15 11:46:02 2017 -0700
+++ b/src/share/lib/security/java.security-solaris	Thu Mar 23 08:44:17 2017 -0700
@@ -328,9 +328,7 @@
 # describes the mechanism for disabling algorithms based on algorithm name
 # and/or key length.  This includes algorithms used in certificates, as well
 # as revocation information such as CRLs and signed OCSP Responses.
-#
-# The syntax of the disabled algorithm string is described as this Java
-# BNF-style:
+# The syntax of the disabled algorithm string is described as follows:
 #   DisabledAlgorithms:
 #       " DisabledAlgorithm { , DisabledAlgorithm } "
 #
@@ -341,25 +339,26 @@
 #       (see below)
 #
 #   Constraint:
-#       KeySizeConstraint, CertConstraint
+#       KeySizeConstraint | CAConstraint | DenyAfterConstraint |
+#       UsageConstraint
 #
 #   KeySizeConstraint:
-#       keySize Operator DecimalInteger
+#       keySize Operator KeyLength
 #
 #   Operator:
 #       <= | < | == | != | >= | >
 #
-#   DecimalInteger:
-#       DecimalDigits
+#   KeyLength:
+#       Integer value of the algorithm's key length in bits
 #
-#   DecimalDigits:
-#       DecimalDigit {DecimalDigit}
+#   CAConstraint:
+#       jdkCA
 #
-#   DecimalDigit: one of
-#       1 2 3 4 5 6 7 8 9 0
+#   DenyAfterConstraint:
+#       denyAfter YYYY-MM-DD
 #
-#   CertConstraint
-#       jdkCA
+#   UsageConstraint:
+#       usage [TLSServer] [TLSClient] [SignedJAR]
 #
 # The "AlgorithmName" is the standard algorithm name of the disabled
 # algorithm. See "Java Cryptography Architecture Standard Algorithm Name
@@ -373,27 +372,55 @@
 # that rely on DSA, such as NONEwithDSA, SHA1withDSA.  However, the assertion
 # will not disable algorithms related to "ECDSA".
 #
-# A "Constraint" provides further guidance for the algorithm being specified.
-# The "KeySizeConstraint" requires a key of a valid size range if the
-# "AlgorithmName" is of a key algorithm.  The "DecimalInteger" indicates the
-# key size specified in number of bits.  For example, "RSA keySize <= 1024"
-# indicates that any RSA key with key size less than or equal to 1024 bits
-# should be disabled, and "RSA keySize < 1024, RSA keySize > 2048" indicates
-# that any RSA key with key size less than 1024 or greater than 2048 should
-# be disabled. Note that the "KeySizeConstraint" only makes sense to key
-# algorithms.
+# A "Constraint" defines restrictions on the keys and/or certificates for
+# a specified AlgorithmName:
+#
+#   KeySizeConstraint:
+#     keySize Operator KeyLength
+#       The constraint requires a key of a valid size range if the
+#       "AlgorithmName" is of a key algorithm.  The "KeyLength" indicates
+#       the key size specified in number of bits.  For example,
+#       "RSA keySize <= 1024" indicates that any RSA key with key size less
+#       than or equal to 1024 bits should be disabled, and
+#       "RSA keySize < 1024, RSA keySize > 2048" indicates that any RSA key
+#       with key size less than 1024 or greater than 2048 should be disabled.
+#       This constraint is only used on algorithms that have a key size.
+#
+#   CAConstraint:
+#     jdkCA
+#       This constraint prohibits the specified algorithm only if the
+#       algorithm is used in a certificate chain that terminates at a marked
+#       trust anchor in the lib/security/cacerts keystore.  If the jdkCA
+#       constraint is not set, then all chains using the specified algorithm
+#       are restricted.  jdkCA may only be used once in a DisabledAlgorithm
+#       expression.
+#       Example:  To apply this constraint to SHA-1 certificates, include
+#       the following:  "SHA1 jdkCA"
 #
-# "CertConstraint" specifies additional constraints for
-# certificates that contain algorithms that are restricted:
+#   DenyAfterConstraint:
+#     denyAfter YYYY-MM-DD
+#       This constraint prohibits a certificate with the specified algorithm
+#       from being used after the date regardless of the certificate's
+#       validity.  JAR files that are signed and timestamped before the
+#       constraint date with certificates containing the disabled algorithm
+#       will not be restricted.  The date is processed in the UTC timezone.
+#       This constraint can only be used once in a DisabledAlgorithm
+#       expression.
+#       Example:  To deny usage of RSA 2048 bit certificates after Feb 3 2020,
+#       use the following:  "RSA keySize == 2048 & denyAfter 2020-02-03"
 #
-#   "jdkCA" prohibits the specified algorithm only if the algorithm is used
-#     in a certificate chain that terminates at a marked trust anchor in the
-#     lib/security/cacerts keystore.  All other chains are not affected.
-#     If the jdkCA constraint is not set, then all chains using the
-#     specified algorithm are restricted. jdkCA may only be used once in
-#     a DisabledAlgorithm expression.
-#     Example:  To apply this constraint to SHA-1 certificates, include
-#     the following:  "SHA1 jdkCA"
+#   UsageConstraint:
+#     usage [TLSServer] [TLSClient] [SignedJAR]
+#       This constraint prohibits the specified algorithm for
+#       a specified usage.  This should be used when disabling an algorithm
+#       for all usages is not practical. 'TLSServer' restricts the algorithm
+#       in TLS server certificate chains when server authentication is
+#       performed. 'TLSClient' restricts the algorithm in TLS client
+#       certificate chains when client authentication is performed.
+#       'SignedJAR' constrains use of certificates in signed jar files.
+#       The usage type follows the keyword and more than one usage type can
+#       be specified with a whitespace delimiter.
+#       Example:  "SHA1 usage TLSServer TLSClient"
 #
 # When an algorithm must satisfy more than one constraint, it must be
 # delimited by an ampersand '&'.  For example, to restrict certificates in a
@@ -406,6 +433,9 @@
 # before larger keysize constraints of the same algorithm.  For example:
 # "RSA keySize < 1024 & jdkCA, RSA keySize < 2048".
 #
+# Note: The algorithm restrictions do not apply to trust anchors or
+# self-signed certificates.
+#
 # Note: This property is currently used by Oracle's PKIX implementation. It
 # is not guaranteed to be examined and used by other implementations.
 #
@@ -413,9 +443,10 @@
 #   jdk.certpath.disabledAlgorithms=MD2, DSA, RSA keySize < 2048
 #
 #
-jdk.certpath.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, \
-    DSA keySize < 1024, EC keySize < 224
+jdk.certpath.disabledAlgorithms=MD2, MD5, SHA1 jdkCA & usage TLSServer, \
+    RSA keySize < 1024, DSA keySize < 1024, EC keySize < 224
 
+#
 # Algorithm restrictions for signed JAR files
 #
 # In some environments, certain algorithms or key lengths may be undesirable
@@ -430,17 +461,20 @@
 #       " DisabledAlgorithm { , DisabledAlgorithm } "
 #
 #   DisabledAlgorithm:
-#       AlgorithmName [Constraint]
+#       AlgorithmName [Constraint] { '&' Constraint }
 #
 #   AlgorithmName:
 #       (see below)
 #
 #   Constraint:
-#       KeySizeConstraint
+#       KeySizeConstraint | DenyAfterConstraint
 #
 #   KeySizeConstraint:
 #       keySize Operator KeyLength
 #
+#   DenyAfterConstraint:
+#       denyAfter YYYY-MM-DD
+#
 #   Operator:
 #       <= | < | == | != | >= | >
 #
@@ -451,8 +485,11 @@
 # implementation. It is not guaranteed to be examined and used by other
 # implementations.
 #
+# See "jdk.certpath.disabledAlgorithms" for syntax descriptions.
+#
 jdk.jar.disabledAlgorithms=MD2, MD5, RSA keySize < 1024
 
+#
 # Algorithm restrictions for Secure Socket Layer/Transport Layer Security
 # (SSL/TLS) processing
 #
@@ -474,6 +511,9 @@
 # See the specification of "jdk.certpath.disabledAlgorithms" for the
 # syntax of the disabled algorithm string.
 #
+# Note: The algorithm restrictions do not apply to trust anchors or
+# self-signed certificates.
+#
 # Note: This property is currently used by the JDK Reference implementation.
 # It is not guaranteed to be examined and used by other implementations.
 #
--- a/src/share/lib/security/java.security-windows	Tue Aug 15 11:46:02 2017 -0700
+++ b/src/share/lib/security/java.security-windows	Thu Mar 23 08:44:17 2017 -0700
@@ -345,9 +345,7 @@
 # describes the mechanism for disabling algorithms based on algorithm name
 # and/or key length.  This includes algorithms used in certificates, as well
 # as revocation information such as CRLs and signed OCSP Responses.
-#
-# The syntax of the disabled algorithm string is described as this Java
-# BNF-style:
+# The syntax of the disabled algorithm string is described as follows:
 #   DisabledAlgorithms:
 #       " DisabledAlgorithm { , DisabledAlgorithm } "
 #
@@ -358,25 +356,26 @@
 #       (see below)
 #
 #   Constraint:
-#       KeySizeConstraint, CertConstraint
+#       KeySizeConstraint | CAConstraint | DenyAfterConstraint |
+#       UsageConstraint
 #
 #   KeySizeConstraint:
-#       keySize Operator DecimalInteger
+#       keySize Operator KeyLength
 #
 #   Operator:
 #       <= | < | == | != | >= | >
 #
-#   DecimalInteger:
-#       DecimalDigits
+#   KeyLength:
+#       Integer value of the algorithm's key length in bits
 #
-#   DecimalDigits:
-#       DecimalDigit {DecimalDigit}
+#   CAConstraint:
+#       jdkCA
 #
-#   DecimalDigit: one of
-#       1 2 3 4 5 6 7 8 9 0
+#   DenyAfterConstraint:
+#       denyAfter YYYY-MM-DD
 #
-#   CertConstraint
-#       jdkCA
+#   UsageConstraint:
+#       usage [TLSServer] [TLSClient] [SignedJAR]
 #
 # The "AlgorithmName" is the standard algorithm name of the disabled
 # algorithm. See "Java Cryptography Architecture Standard Algorithm Name
@@ -390,27 +389,55 @@
 # that rely on DSA, such as NONEwithDSA, SHA1withDSA.  However, the assertion
 # will not disable algorithms related to "ECDSA".
 #
-# A "Constraint" provides further guidance for the algorithm being specified.
-# The "KeySizeConstraint" requires a key of a valid size range if the
-# "AlgorithmName" is of a key algorithm.  The "DecimalInteger" indicates the
-# key size specified in number of bits.  For example, "RSA keySize <= 1024"
-# indicates that any RSA key with key size less than or equal to 1024 bits
-# should be disabled, and "RSA keySize < 1024, RSA keySize > 2048" indicates
-# that any RSA key with key size less than 1024 or greater than 2048 should
-# be disabled. Note that the "KeySizeConstraint" only makes sense to key
-# algorithms.
+# A "Constraint" defines restrictions on the keys and/or certificates for
+# a specified AlgorithmName:
+#
+#   KeySizeConstraint:
+#     keySize Operator KeyLength
+#       The constraint requires a key of a valid size range if the
+#       "AlgorithmName" is of a key algorithm.  The "KeyLength" indicates
+#       the key size specified in number of bits.  For example,
+#       "RSA keySize <= 1024" indicates that any RSA key with key size less
+#       than or equal to 1024 bits should be disabled, and
+#       "RSA keySize < 1024, RSA keySize > 2048" indicates that any RSA key
+#       with key size less than 1024 or greater than 2048 should be disabled.
+#       This constraint is only used on algorithms that have a key size.
+#
+#   CAConstraint:
+#     jdkCA
+#       This constraint prohibits the specified algorithm only if the
+#       algorithm is used in a certificate chain that terminates at a marked
+#       trust anchor in the lib/security/cacerts keystore.  If the jdkCA
+#       constraint is not set, then all chains using the specified algorithm
+#       are restricted.  jdkCA may only be used once in a DisabledAlgorithm
+#       expression.
+#       Example:  To apply this constraint to SHA-1 certificates, include
+#       the following:  "SHA1 jdkCA"
 #
-# "CertConstraint" specifies additional constraints for
-# certificates that contain algorithms that are restricted:
+#   DenyAfterConstraint:
+#     denyAfter YYYY-MM-DD
+#       This constraint prohibits a certificate with the specified algorithm
+#       from being used after the date regardless of the certificate's
+#       validity.  JAR files that are signed and timestamped before the
+#       constraint date with certificates containing the disabled algorithm
+#       will not be restricted.  The date is processed in the UTC timezone.
+#       This constraint can only be used once in a DisabledAlgorithm
+#       expression.
+#       Example:  To deny usage of RSA 2048 bit certificates after Feb 3 2020,
+#       use the following:  "RSA keySize == 2048 & denyAfter 2020-02-03"
 #
-#   "jdkCA" prohibits the specified algorithm only if the algorithm is used
-#     in a certificate chain that terminates at a marked trust anchor in the
-#     lib/security/cacerts keystore.  All other chains are not affected.
-#     If the jdkCA constraint is not set, then all chains using the
-#     specified algorithm are restricted.  jdkCA may only be used once in
-#     a DisabledAlgorithm expression.
-#     Example:  To apply this constraint to SHA-1 certificates, include
-#     the following:  "SHA1 jdkCA"
+#   UsageConstraint:
+#     usage [TLSServer] [TLSClient] [SignedJAR]
+#       This constraint prohibits the specified algorithm for
+#       a specified usage.  This should be used when disabling an algorithm
+#       for all usages is not practical. 'TLSServer' restricts the algorithm
+#       in TLS server certificate chains when server authentication is
+#       performed. 'TLSClient' restricts the algorithm in TLS client
+#       certificate chains when client authentication is performed.
+#       'SignedJAR' constrains use of certificates in signed jar files.
+#       The usage type follows the keyword and more than one usage type can
+#       be specified with a whitespace delimiter.
+#       Example:  "SHA1 usage TLSServer TLSClient"
 #
 # When an algorithm must satisfy more than one constraint, it must be
 # delimited by an ampersand '&'.  For example, to restrict certificates in a
@@ -423,6 +450,9 @@
 # before larger keysize constraints of the same algorithm.  For example:
 # "RSA keySize < 1024 & jdkCA, RSA keySize < 2048".
 #
+# Note: The algorithm restrictions do not apply to trust anchors or
+# self-signed certificates.
+#
 # Note: This property is currently used by Oracle's PKIX implementation. It
 # is not guaranteed to be examined and used by other implementations.
 #
@@ -430,9 +460,10 @@
 #   jdk.certpath.disabledAlgorithms=MD2, DSA, RSA keySize < 2048
 #
 #
-jdk.certpath.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, \
-    DSA keySize < 1024, EC keySize < 224
+jdk.certpath.disabledAlgorithms=MD2, MD5, SHA1 jdkCA & usage TLSServer, \
+    RSA keySize < 1024, DSA keySize < 1024, EC keySize < 224
 
+#
 # Algorithm restrictions for signed JAR files
 #
 # In some environments, certain algorithms or key lengths may be undesirable
@@ -447,17 +478,20 @@
 #       " DisabledAlgorithm { , DisabledAlgorithm } "
 #
 #   DisabledAlgorithm:
-#       AlgorithmName [Constraint]
+#       AlgorithmName [Constraint] { '&' Constraint }
 #
 #   AlgorithmName:
 #       (see below)
 #
 #   Constraint:
-#       KeySizeConstraint
+#       KeySizeConstraint | DenyAfterConstraint
 #
 #   KeySizeConstraint:
 #       keySize Operator KeyLength
 #
+#   DenyAfterConstraint:
+#       denyAfter YYYY-MM-DD
+#
 #   Operator:
 #       <= | < | == | != | >= | >
 #
@@ -468,8 +502,11 @@
 # implementation. It is not guaranteed to be examined and used by other
 # implementations.
 #
+# See "jdk.certpath.disabledAlgorithms" for syntax descriptions.
+#
 jdk.jar.disabledAlgorithms=MD2, MD5, RSA keySize < 1024
 
+#
 # Algorithm restrictions for Secure Socket Layer/Transport Layer Security
 # (SSL/TLS) processing
 #
@@ -491,6 +528,9 @@
 # See the specification of "jdk.certpath.disabledAlgorithms" for the
 # syntax of the disabled algorithm string.
 #
+# Note: The algorithm restrictions do not apply to trust anchors or
+# self-signed certificates.
+#
 # Note: This property is currently used by the JDK Reference implementation.
 # It is not guaranteed to be examined and used by other implementations.
 #
--- a/test/ProblemList.txt	Tue Aug 15 11:46:02 2017 -0700
+++ b/test/ProblemList.txt	Thu Mar 23 08:44:17 2017 -0700
@@ -595,6 +595,9 @@
 # Only print test left, excluding just because all print tests have been
 javax/print/attribute/MediaMappingsTest.java 			generic-all
 
+# 8160071 ClientJSSEServerJSSE.java test failure
+sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java		linux-all
+
 ############################################################################
 
 # jdk_net