changeset 3476:d4bc38aa7594

7011497: new CertPathValidatorException.BasicReason enum constant for constrained algorithm Summary: add new BasicReason and improve trust anchor searching method during cert path validation Reviewed-by: mullan
author xuelei
date Tue, 01 Feb 2011 04:45:10 -0800
parents f110edeb4428
children 21d7cd823247
files src/share/classes/java/security/cert/CertPathValidatorException.java src/share/classes/sun/security/provider/certpath/AdaptableX509CertSelector.java src/share/classes/sun/security/provider/certpath/AlgorithmChecker.java src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java src/share/classes/sun/security/provider/certpath/ForwardBuilder.java src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java src/share/classes/sun/security/validator/SimpleValidator.java test/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorEndEntity.java test/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorIntermediate.java test/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorTrustAnchor.java
diffstat 10 files changed, 358 insertions(+), 189 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/java/security/cert/CertPathValidatorException.java	Tue Feb 01 00:29:26 2011 -0800
+++ b/src/share/classes/java/security/cert/CertPathValidatorException.java	Tue Feb 01 04:45:10 2011 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2011, 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
@@ -286,6 +286,11 @@
         /**
          * The signature is invalid.
          */
-        INVALID_SIGNATURE
+        INVALID_SIGNATURE,
+
+        /**
+         * The public key or the signature algorithm has been constrained.
+         */
+        ALGORITHM_CONSTRAINED
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/security/provider/certpath/AdaptableX509CertSelector.java	Tue Feb 01 04:45:10 2011 -0800
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.provider.certpath;
+
+import java.io.IOException;
+import java.util.Date;
+
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.security.cert.X509CertSelector;
+import java.security.cert.CertificateException;
+
+import sun.security.util.DerOutputStream;
+import sun.security.x509.SerialNumber;
+import sun.security.x509.KeyIdentifier;
+import sun.security.x509.AuthorityKeyIdentifierExtension;
+
+/**
+ * An adaptable X509 certificate selector for forward certification path
+ * building.
+ *
+ * @since 1.7
+ */
+class AdaptableX509CertSelector extends X509CertSelector {
+    // The start date of a validity period.
+    private Date startDate = null;
+
+    // The end date of a validity period.
+    private Date endDate = null;
+
+    AdaptableX509CertSelector() {
+        super();
+    }
+
+    /**
+     * Sets the criterion of the X509Certificate validity period.
+     *
+     * Normally, we may not have to check that a certificate validity period
+     * must fall within its issuer's certificate validity period. However,
+     * when we face root CA key updates for version 1 certificates, according
+     * to scheme of RFC 4210 or 2510, the validity periods should be checked
+     * to determine the right issuer's certificate.
+     *
+     * Conservatively, we will only check the validity periods for version
+     * 1 and version 2 certificates. For version 3 certificates, we can
+     * determine the right issuer by authority and subject key identifier
+     * extensions.
+     *
+     * @param startDate the start date of a validity period that must fall
+     *        within the certificate validity period for the X509Certificate
+     * @param endDate the end date of a validity period that must fall
+     *        within the certificate validity period for the X509Certificate
+     */
+    void setValidityPeriod(Date startDate, Date endDate) {
+        this.startDate = startDate;
+        this.endDate = endDate;
+    }
+
+    /**
+     * Parse the authority key identifier extension.
+     *
+     * If the keyIdentifier field of the extension is non-null, set the
+     * subjectKeyIdentifier criterion. If the authorityCertSerialNumber
+     * field is non-null, set the serialNumber criterion.
+     *
+     * Note that we will not set the subject criterion according to the
+     * authorityCertIssuer field of the extension. The caller MUST set
+     * the subject criterion before call match().
+     *
+     * @param akidext the authorityKeyIdentifier extension
+     */
+    void parseAuthorityKeyIdentifierExtension(
+            AuthorityKeyIdentifierExtension akidext) throws IOException {
+        if (akidext != null) {
+            KeyIdentifier akid = (KeyIdentifier)akidext.get(akidext.KEY_ID);
+            if (akid != null) {
+                DerOutputStream derout = new DerOutputStream();
+                derout.putOctetString(akid.getIdentifier());
+                super.setSubjectKeyIdentifier(derout.toByteArray());
+            }
+
+            SerialNumber asn =
+                (SerialNumber)akidext.get(akidext.SERIAL_NUMBER);
+            if (asn != null) {
+                super.setSerialNumber(asn.getNumber());
+            }
+
+            // the subject criterion should be set by the caller.
+        }
+    }
+
+    /**
+     * Decides whether a <code>Certificate</code> should be selected.
+     *
+     * For the purpose of compatibility, when a certificate is of
+     * version 1 and version 2, or the certificate does not include
+     * a subject key identifier extension, the selection criterion
+     * of subjectKeyIdentifier will be disabled.
+     */
+    @Override
+    public boolean match(Certificate cert) {
+        if (!(cert instanceof X509Certificate)) {
+            return false;
+        }
+
+        X509Certificate xcert = (X509Certificate)cert;
+        int version = xcert.getVersion();
+
+        // Check the validity period for version 1 and 2 certificate.
+        if (version < 3) {
+            if (startDate != null) {
+                try {
+                    xcert.checkValidity(startDate);
+                } catch (CertificateException ce) {
+                    return false;
+                }
+            }
+
+            if (endDate != null) {
+                try {
+                    xcert.checkValidity(endDate);
+                } catch (CertificateException ce) {
+                    return false;
+                }
+            }
+        }
+
+        if (version < 3 || xcert.getExtensionValue("2.5.29.14") == null) {
+            // If no SubjectKeyIdentifier extension, don't bother to check it.
+            setSubjectKeyIdentifier(null);
+        }
+
+        return super.match(cert);
+    }
+
+    @Override
+    public Object clone() {
+        AdaptableX509CertSelector copy =
+                        (AdaptableX509CertSelector)super.clone();
+        if (startDate != null) {
+            copy.startDate = (Date)startDate.clone();
+        }
+
+        if (endDate != null) {
+            copy.endDate = (Date)endDate.clone();
+        }
+
+        return copy;
+    }
+}
--- a/src/share/classes/sun/security/provider/certpath/AlgorithmChecker.java	Tue Feb 01 00:29:26 2011 -0800
+++ b/src/share/classes/sun/security/provider/certpath/AlgorithmChecker.java	Tue Feb 01 04:45:10 2011 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2011, 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
@@ -46,6 +46,8 @@
 import java.security.cert.CRLException;
 import java.security.cert.CertificateException;
 import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertPathValidatorException.BasicReason;
+import java.security.cert.PKIXReason;
 import java.io.IOException;
 import java.security.interfaces.*;
 import java.security.spec.*;
@@ -196,14 +198,16 @@
                 SIGNATURE_PRIMITIVE_SET,
                 currSigAlg, currSigAlgParams)) {
             throw new CertPathValidatorException(
-                "Algorithm constraints check failed: " + currSigAlg);
+                "Algorithm constraints check failed: " + currSigAlg,
+                null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
         }
 
         // check the key usage and key size
         boolean[] keyUsage = x509Cert.getKeyUsage();
         if (keyUsage != null && keyUsage.length < 9) {
             throw new CertPathValidatorException(
-                        "incorrect KeyUsage extension");
+                "incorrect KeyUsage extension",
+                null, null, -1, PKIXReason.INVALID_KEY_USAGE);
         }
 
         if (keyUsage != null) {
@@ -236,7 +240,8 @@
             if (!primitives.isEmpty()) {
                 if (!constraints.permits(primitives, currPubKey)) {
                     throw new CertPathValidatorException(
-                        "algorithm constraints check failed");
+                        "algorithm constraints check failed",
+                        null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
                 }
             }
         }
@@ -248,7 +253,8 @@
                         SIGNATURE_PRIMITIVE_SET,
                         currSigAlg, prevPubKey, currSigAlgParams)) {
                     throw new CertPathValidatorException(
-                        "Algorithm constraints check failed: " + currSigAlg);
+                        "Algorithm constraints check failed: " + currSigAlg,
+                        null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
                 }
             }
 
@@ -258,7 +264,7 @@
                 // Inherit DSA parameters from previous key
                 if (!(prevPubKey instanceof DSAPublicKey)) {
                     throw new CertPathValidatorException("Input key is not " +
-                         "of a appropriate type for inheriting parameters");
+                        "of a appropriate type for inheriting parameters");
                 }
 
                 DSAParams params = ((DSAPublicKey)prevPubKey).getParams();
@@ -352,7 +358,8 @@
         if (!certPathDefaultConstraints.permits(
                 SIGNATURE_PRIMITIVE_SET, sigAlgName, key, sigAlgParams)) {
             throw new CertPathValidatorException(
-                "algorithm check failed: " + sigAlgName + " is disabled");
+                "algorithm check failed: " + sigAlgName + " is disabled",
+                null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
         }
     }
 
--- a/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java	Tue Feb 01 00:29:26 2011 -0800
+++ b/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java	Tue Feb 01 04:45:10 2011 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2011, 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
@@ -317,7 +317,7 @@
 
             // we accept the case that a CRL issuer provide status
             // information for itself.
-            if (ForwardBuilder.issues(certImpl, crlImpl, provider)) {
+            if (issues(certImpl, crlImpl, provider)) {
                 // reset the public key used to verify the CRL's signature
                 prevKey = certImpl.getPublicKey();
             } else {
@@ -338,7 +338,7 @@
             if (!Arrays.equals(certAKID, crlAKID)) {
                 // we accept the case that a CRL issuer provide status
                 // information for itself.
-                if (ForwardBuilder.issues(certImpl, crlImpl, provider)) {
+                if (issues(certImpl, crlImpl, provider)) {
                     // reset the public key used to verify the CRL's signature
                     prevKey = certImpl.getPublicKey();
                 } else {
@@ -687,4 +687,41 @@
         fullNames.add(new GeneralName(fullName));
         return fullNames;
     }
+
+    /** Verifies whether a CRL is issued by a certain certificate
+     *
+     * @param cert the certificate
+     * @param crl the CRL to be verified
+     * @param provider the name of the signature provider
+     */
+    private static boolean issues(X509CertImpl cert, X509CRLImpl crl,
+            String provider) throws IOException {
+
+        AdaptableX509CertSelector issuerSelector =
+                                    new AdaptableX509CertSelector();
+
+        // check certificate's key usage
+        boolean[] usages = cert.getKeyUsage();
+        if (usages != null) {
+            usages[6] = true;       // cRLSign
+            issuerSelector.setKeyUsage(usages);
+        }
+
+        // check certificate's subject
+        X500Principal crlIssuer = crl.getIssuerX500Principal();
+        issuerSelector.setSubject(crlIssuer);
+
+        /*
+         * Facilitate certification path construction with authority
+         * key identifier and subject key identifier.
+         *
+         * In practice, conforming CAs MUST use the key identifier method,
+         * and MUST include authority key identifier extension in all CRLs
+         * issued. [section 5.2.1, RFC 2459]
+         */
+        issuerSelector.parseAuthorityKeyIdentifierExtension(
+                                        crl.getAuthKeyIdExtension());
+
+        return issuerSelector.match(cert);
+    }
 }
--- a/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java	Tue Feb 01 00:29:26 2011 -0800
+++ b/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java	Tue Feb 01 04:45:10 2011 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2011, 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
@@ -77,7 +77,7 @@
     private final Set<X500Principal> trustedSubjectDNs;
     private final Set<TrustAnchor> trustAnchors;
     private X509CertSelector eeSelector;
-    private X509CertSelector caSelector;
+    private AdaptableX509CertSelector caSelector;
     private X509CertSelector caTargetSelector;
     TrustAnchor trustAnchor;
     private Comparator<X509Certificate> comparator;
@@ -230,9 +230,11 @@
                     targetCertConstraints.clone();
 
                 /*
-                 * Match on certificate validity date
+                 * Since we don't check the validity period of trusted
+                 * certificates, please don't set the certificate valid
+                 * criterion unless the trusted certificate matching is
+                 * completed.
                  */
-                caTargetSelector.setCertificateValid(date);
 
                 /*
                  * Policy processing optimizations
@@ -246,17 +248,19 @@
              * at least as many CA certs that have already been traversed
              */
             caTargetSelector.setBasicConstraints(currentState.traversedCACerts);
+
             sel = caTargetSelector;
-
         } else {
 
             if (caSelector == null) {
                 caSelector = new AdaptableX509CertSelector();
 
                 /*
-                 * Match on certificate validity date.
+                 * Since we don't check the validity period of trusted
+                 * certificates, please don't set the certificate valid
+                 * criterion unless the trusted certificate matching is
+                 * completed.
                  */
-                caSelector.setCertificateValid(date);
 
                 /*
                  * Policy processing optimizations
@@ -290,42 +294,19 @@
              */
             AuthorityKeyIdentifierExtension akidext =
                     currentState.cert.getAuthorityKeyIdentifierExtension();
-            if (akidext != null) {
-                KeyIdentifier akid = (KeyIdentifier)akidext.get(akidext.KEY_ID);
-                if (akid != null) {
-                    DerOutputStream derout = new DerOutputStream();
-                    derout.putOctetString(akid.getIdentifier());
-                    caSelector.setSubjectKeyIdentifier(derout.toByteArray());
-                }
+            caSelector.parseAuthorityKeyIdentifierExtension(akidext);
 
-                SerialNumber asn =
-                    (SerialNumber)akidext.get(akidext.SERIAL_NUMBER);
-                if (asn != null) {
-                    caSelector.setSerialNumber(asn.getNumber());
-                }
-                // the subject criterion was set previously.
-            }
+            /*
+             * check the validity period
+             */
+            caSelector.setValidityPeriod(currentState.cert.getNotBefore(),
+                                            currentState.cert.getNotAfter());
 
             sel = caSelector;
         }
 
-        /*
-         * Check if any of the trusted certs could be a match.
-         * Since we are not validating the trusted cert, we can't
-         * re-use the selector we've built up (sel) - we need
-         * to use a new selector (trustedSel)
-         */
-        X509CertSelector trustedSel = null;
-        if (currentState.isInitial()) {
-            trustedSel = targetCertConstraints;
-        } else {
-            trustedSel = new X509CertSelector();
-            trustedSel.setSubject(currentState.issuerDN);
-        }
-
-        boolean foundMatchingCert = false;
         for (X509Certificate trustedCert : trustedCerts) {
-            if (trustedSel.match(trustedCert)) {
+            if (sel.match(trustedCert)) {
                 if (debug != null) {
                     debug.println("ForwardBuilder.getMatchingCACerts: "
                         + "found matching trust anchor");
@@ -336,6 +317,11 @@
             }
         }
 
+        /*
+         * The trusted certificate matching is completed. We need to match
+         * on certificate validity date.
+         */
+        sel.setCertificateValid(date);
 
         /*
          * If we have already traversed as many CA certs as the maxPathLength
@@ -348,8 +334,8 @@
            (buildParams.getMaxPathLength() == -1) ||
            (buildParams.getMaxPathLength() > currentState.traversedCACerts))
         {
-            if (addMatchingCerts(sel, certStores, caCerts, searchAllCertStores)
-                && !searchAllCertStores) {
+            if (addMatchingCerts(sel, certStores,
+                    caCerts, searchAllCertStores) && !searchAllCertStores) {
                 return;
             }
         }
@@ -939,120 +925,4 @@
     void removeFinalCertFromPath(LinkedList<X509Certificate> certPathList) {
         certPathList.removeFirst();
     }
-
-    /** Verifies whether a CRL is issued by a certain certificate
-     *
-     * @param cert the certificate
-     * @param crl the CRL to be verified
-     * @param provider the name of the signature provider
-     */
-    static boolean issues(X509CertImpl cert, X509CRLImpl crl, String provider)
-            throws IOException {
-
-        boolean kidmatched = false;
-
-        // check certificate's key usage
-        boolean[] usages = cert.getKeyUsage();
-        if (usages != null && !usages[6]) {
-            return false;
-        }
-
-        // check certificate's SKID and CRL's AKID
-        AuthorityKeyIdentifierExtension akidext = crl.getAuthKeyIdExtension();
-        if (akidext != null) {
-            // the highest priority, matching KID
-            KeyIdentifier akid = (KeyIdentifier)akidext.get(akidext.KEY_ID);
-            if (akid != null) {
-                SubjectKeyIdentifierExtension skidext =
-                            cert.getSubjectKeyIdentifierExtension();
-                if (skidext != null) {
-                    KeyIdentifier skid =
-                            (KeyIdentifier)skidext.get(skidext.KEY_ID);
-                    if (!akid.equals(skid)) {
-                        return false;
-                    }
-
-                    kidmatched = true;
-                }
-                // conservatively, in case of X509 V1 certificate,
-                // does return false here if no SKID extension.
-            }
-
-            // the medium priority, matching issuer name/serial number
-            SerialNumber asn = (SerialNumber)akidext.get(akidext.SERIAL_NUMBER);
-            GeneralNames anames = (GeneralNames)akidext.get(akidext.AUTH_NAME);
-            if (asn != null && anames != null) {
-                X500Name subject = (X500Name)cert.getSubjectDN();
-                BigInteger serial = cert.getSerialNumber();
-
-                if (serial != null && subject != null) {
-                    if (serial.equals(asn.getNumber())) {
-                        return false;
-                    }
-
-                    for (GeneralName name : anames.names()) {
-                        GeneralNameInterface gni = name.getName();
-                        if (subject.equals(gni)) {
-                            return true;
-                        }
-                    }
-                }
-
-                return false;
-            }
-
-            if (kidmatched) {
-                return true;
-            }
-        }
-
-        // the last priority, verify the CRL signature with the cert.
-        X500Principal crlIssuer = crl.getIssuerX500Principal();
-        X500Principal certSubject = cert.getSubjectX500Principal();
-        if (certSubject != null && certSubject.equals(crlIssuer)) {
-            try {
-                crl.verify(cert.getPublicKey(), provider);
-                return true;
-            } catch (Exception e) {
-                // ignore all exceptions.
-            }
-        }
-
-        return false;
-    }
-
-    /**
-     * An adaptable X509 certificate selector for forward certification path
-     * building.
-     */
-    private static class AdaptableX509CertSelector extends X509CertSelector {
-        public AdaptableX509CertSelector() {
-            super();
-        }
-
-        /**
-         * Decides whether a <code>Certificate</code> should be selected.
-         *
-         * For the purpose of compatibility, when a certificate is of
-         * version 1 and version 2, or the certificate does not include
-         * a subject key identifier extension, the selection criterion
-         * of subjectKeyIdentifier will be disabled.
-         *
-         * @Override
-         */
-        public boolean match(Certificate cert) {
-            if (!(cert instanceof X509Certificate)) {
-                return false;
-            }
-            X509Certificate xcert = (X509Certificate)cert;
-
-            if (xcert.getVersion() < 3 ||
-                xcert.getExtensionValue("2.5.29.14") == null) {
-                // disable the subjectKeyIdentifier criterion
-                setSubjectKeyIdentifier(null);
-            }
-
-            return super.match(cert);
-        }
-    }
 }
--- a/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java	Tue Feb 01 00:29:26 2011 -0800
+++ b/src/share/classes/sun/security/provider/certpath/PKIXCertPathValidator.java	Tue Feb 01 04:45:10 2011 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2011, 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
@@ -50,6 +50,9 @@
 import sun.security.action.GetBooleanSecurityPropertyAction;
 import sun.security.util.Debug;
 
+import sun.security.x509.X509CertImpl;
+
+
 /**
  * This class implements the PKIX validation algorithm for certification
  * paths consisting exclusively of <code>X509Certificates</code>. It uses
@@ -162,6 +165,7 @@
                     debug.println("PKIXCertPathValidator.engineValidate() "
                         + "anchor.getTrustedCert() != null");
                 }
+
                 // if this trust anchor is not worth trying,
                 // we move on to the next one
                 if (!isWorthTrying(trustedCert, firstCert)) {
@@ -211,8 +215,10 @@
      * worth trying to validate in the chain.
      */
     private boolean isWorthTrying(X509Certificate trustedCert,
-                                  X509Certificate firstCert)
-    {
+          X509Certificate firstCert) {
+
+        boolean worthy = false;
+
         if (debug != null) {
             debug.println("PKIXCertPathValidator.isWorthTrying() checking "
                 + "if this trusted cert is worth trying ...");
@@ -222,19 +228,46 @@
             return true;
         }
 
-        // the subject of the trusted cert should match the
-        // issuer of the first cert in the certpath
+        AdaptableX509CertSelector issuerSelector =
+                        new AdaptableX509CertSelector();
 
-        X500Principal trustedSubject = trustedCert.getSubjectX500Principal();
-        if (trustedSubject.equals(firstCert.getIssuerX500Principal())) {
-            if (debug != null)
+        // check trusted certificate's key usage
+        boolean[] usages = trustedCert.getKeyUsage();
+        if (usages != null) {
+            usages[5] = true;    // keyCertSign
+            issuerSelector.setKeyUsage(usages);
+        }
+
+        // check trusted certificate's subject
+        issuerSelector.setSubject(firstCert.getIssuerX500Principal());
+
+        // check the validity period
+        issuerSelector.setValidityPeriod(firstCert.getNotBefore(),
+                                                firstCert.getNotAfter());
+
+        /*
+         * Facilitate certification path construction with authority
+         * key identifier and subject key identifier.
+         */
+        try {
+            X509CertImpl firstCertImpl = X509CertImpl.toImpl(firstCert);
+            issuerSelector.parseAuthorityKeyIdentifierExtension(
+                        firstCertImpl.getAuthorityKeyIdentifierExtension());
+
+            worthy = issuerSelector.match(trustedCert);
+        } catch (Exception e) {
+            // It is not worth trying.
+        }
+
+        if (debug != null) {
+            if (worthy) {
                 debug.println("YES - try this trustedCert");
-            return true;
-        } else {
-            if (debug != null)
+            } else {
                 debug.println("NO - don't try this trustedCert");
-            return false;
+            }
         }
+
+        return worthy;
     }
 
     /**
--- a/src/share/classes/sun/security/validator/SimpleValidator.java	Tue Feb 01 00:29:26 2011 -0800
+++ b/src/share/classes/sun/security/validator/SimpleValidator.java	Tue Feb 01 04:45:10 2011 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2011, 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
@@ -156,8 +156,8 @@
 
             // check certificate algorithm
             try {
-                // Algorithm checker don't care about the unresolved critical
-                // extensions.
+                // Algorithm checker does not care about the unresolved
+                // critical extensions.
                 defaultAlgChecker.check(cert, Collections.<String>emptySet());
                 if (appAlgChecker != null) {
                     appAlgChecker.check(cert, Collections.<String>emptySet());
--- a/test/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorEndEntity.java	Tue Feb 01 00:29:26 2011 -0800
+++ b/test/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorEndEntity.java	Tue Feb 01 04:45:10 2011 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,8 +24,10 @@
 /**
  * @test
  *
- * @bug 6861062
- * @summary Disable MD2 support
+ * @bug 6861062 7011497
+ * @summary Disable MD2 support.
+ *          New CertPathValidatorException.BasicReason enum constant for
+ *     constrained algorithm.
  *
  * @author Xuelei Fan
  */
@@ -35,6 +37,7 @@
 import java.util.*;
 import java.security.Security;
 import java.security.cert.*;
+import java.security.cert.CertPathValidatorException.*;
 
 public class CPValidatorEndEntity {
 
@@ -329,6 +332,13 @@
                                     intermediate_SHA1withRSA_1024_1024);
             throw new Exception("expected algorithm disabled exception");
         } catch (CertPathValidatorException cpve) {
+            // we may get ClassCastException here
+            BasicReason reason = (BasicReason)cpve.getReason();
+            if (reason != BasicReason.ALGORITHM_CONSTRAINED) {
+                throw new Exception(
+                    "Expect to get ALGORITHM_CONSTRAINED CPVE", cpve);
+            }
+
             System.out.println("Get the expected exception " + cpve);
         }
 
@@ -337,6 +347,13 @@
                                     intermediate_SHA1withRSA_512_1024);
             throw new Exception("expected algorithm disabled exception");
         } catch (CertPathValidatorException cpve) {
+            // we may get ClassCastException here
+            BasicReason reason = (BasicReason)cpve.getReason();
+            if (reason != BasicReason.ALGORITHM_CONSTRAINED) {
+                throw new Exception(
+                    "Expect to get ALGORITHM_CONSTRAINED CPVE", cpve);
+            }
+
             System.out.println("Get the expected exception " + cpve);
         }
     }
--- a/test/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorIntermediate.java	Tue Feb 01 00:29:26 2011 -0800
+++ b/test/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorIntermediate.java	Tue Feb 01 04:45:10 2011 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,8 +24,10 @@
 /**
  * @test
  *
- * @bug 6861062
+ * @bug 6861062 7011497
  * @summary Disable MD2 support
+ *          new CertPathValidatorException.BasicReason enum constant for
+ *     constrained algorithm
  *
  * @author Xuelei Fan
  */
@@ -35,6 +37,7 @@
 import java.util.*;
 import java.security.Security;
 import java.security.cert.*;
+import java.security.cert.CertPathValidatorException.*;
 
 public class CPValidatorIntermediate {
 
@@ -223,6 +226,13 @@
             validate(intermediate_MD2withRSA_1024_1024);
             throw new Exception("expected algorithm disabled exception");
         } catch (CertPathValidatorException cpve) {
+            // we may get ClassCastException here
+            BasicReason reason = (BasicReason)cpve.getReason();
+            if (reason != BasicReason.ALGORITHM_CONSTRAINED) {
+                throw new Exception(
+                    "Expect to get ALGORITHM_CONSTRAINED CPVE", cpve);
+            }
+
             System.out.println("Get the expected exception " + cpve);
         }
 
@@ -230,6 +240,13 @@
             validate(intermediate_MD2withRSA_1024_512);
             throw new Exception("expected algorithm disabled exception");
         } catch (CertPathValidatorException cpve) {
+            // we may get ClassCastException here
+            BasicReason reason = (BasicReason)cpve.getReason();
+            if (reason != BasicReason.ALGORITHM_CONSTRAINED) {
+                throw new Exception(
+                    "Expect to get ALGORITHM_CONSTRAINED CPVE", cpve);
+            }
+
             System.out.println("Get the expected exception " + cpve);
         }
     }
--- a/test/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorTrustAnchor.java	Tue Feb 01 00:29:26 2011 -0800
+++ b/test/sun/security/provider/certpath/DisabledAlgorithms/CPValidatorTrustAnchor.java	Tue Feb 01 04:45:10 2011 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,8 +24,10 @@
 /**
  * @test
  *
- * @bug 6861062
+ * @bug 6861062 7011497
  * @summary Disable MD2 support
+ *          new CertPathValidatorException.BasicReason enum constant for
+ *     constrained algorithm
  *
  * @author Xuelei Fan
  */
@@ -35,6 +37,7 @@
 import java.util.*;
 import java.security.Security;
 import java.security.cert.*;
+import java.security.cert.CertPathValidatorException.*;
 
 public class CPValidatorTrustAnchor {
 
@@ -142,6 +145,13 @@
             validate(trustAnchor_MD2withRSA_2048);
             throw new Exception("expected algorithm disabled exception");
         } catch (CertPathValidatorException cpve) {
+            // we may get ClassCastException here
+            BasicReason reason = (BasicReason)cpve.getReason();
+            if (reason != BasicReason.ALGORITHM_CONSTRAINED) {
+                throw new Exception(
+                    "Expect to get ALGORITHM_CONSTRAINED CPVE", cpve);
+            }
+
             System.out.println("Get the expected exception " + cpve);
         }
     }