539 lines · 19.4 KB · Java
RawDownload
/* * Copyright (c) 2000, 2010, 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.security.GeneralSecurityException;import java.security.Principal;import java.security.cert.CertificateException;import java.security.cert.CertPathValidatorException;import java.security.cert.CertStore;import java.security.cert.CertStoreException;import java.security.cert.PKIXBuilderParameters;import java.security.cert.PKIXCertPathChecker;import java.security.cert.PKIXParameters;import java.security.cert.PKIXReason;import java.security.cert.TrustAnchor;import java.security.cert.X509Certificate;import java.security.cert.X509CertSelector;import java.util.ArrayList;import java.util.Collection;import java.util.Collections;import java.util.Comparator;import java.util.HashSet;import java.util.Iterator;import java.util.List;import java.util.LinkedList;import java.util.Set; import javax.security.auth.x500.X500Principal; import sun.security.util.Debug;import sun.security.x509.Extension;import sun.security.x509.PKIXExtensions;import sun.security.x509.X500Name;import sun.security.x509.X509CertImpl;import sun.security.x509.PolicyMappingsExtension; /** * This class represents a reverse builder, which is able to retrieve * matching certificates from CertStores and verify a particular certificate * against a ReverseState. * * @since       1.4 * @author      Sean Mullan * @author      Yassir Elley */ class ReverseBuilder extends Builder {     private Debug debug = Debug.getInstance("certpath");     Set<String> initPolicies;     /**     * Initialize the builder with the input parameters.     *     * @param params the parameter set used to build a certification path     */    ReverseBuilder(PKIXBuilderParameters buildParams,        X500Principal targetSubjectDN) {         super(buildParams, targetSubjectDN);         Set<String> initialPolicies = buildParams.getInitialPolicies();        initPolicies = new HashSet<String>();        if (initialPolicies.isEmpty()) {            // if no initialPolicies are specified by user, set            // initPolicies to be anyPolicy by default            initPolicies.add(PolicyChecker.ANY_POLICY);        } else {            for (String policy : initialPolicies) {                initPolicies.add(policy);            }        }    }     /**     * Retrieves all certs from the specified CertStores that satisfy the     * requirements specified in the parameters and the current     * PKIX state (name constraints, policy constraints, etc).     *     * @param currentState the current state.     *        Must be an instance of <code>ReverseState</code>     * @param certStores list of CertStores     */    Collection<X509Certificate> getMatchingCerts        (State currState, List<CertStore> certStores)        throws CertStoreException, CertificateException, IOException    {        ReverseState currentState = (ReverseState) currState;         if (debug != null)            debug.println("In ReverseBuilder.getMatchingCerts.");         /*         * The last certificate could be an EE or a CA certificate         * (we may be building a partial certification path or         * establishing trust in a CA).         *         * Try the EE certs before the CA certs. It will be more         * common to build a path to an end entity.         */        Collection<X509Certificate> certs =            getMatchingEECerts(currentState, certStores);        certs.addAll(getMatchingCACerts(currentState, certStores));         return certs;    }     /*     * Retrieves all end-entity certificates which satisfy constraints     * and requirements specified in the parameters and PKIX state.     */    private Collection<X509Certificate> getMatchingEECerts        (ReverseState currentState, List<CertStore> certStores)        throws CertStoreException, CertificateException, IOException {       /*       * Compose a CertSelector to filter out       * certs which do not satisfy requirements.       *       * First, retrieve clone of current target cert constraints,       * and then add more selection criteria based on current validation state.       */      X509CertSelector sel = (X509CertSelector) targetCertConstraints.clone();       /*       * Match on issuer (subject of previous cert)       */      sel.setIssuer(currentState.subjectDN);       /*       * Match on certificate validity date.       */      sel.setCertificateValid(date);       /*       * Policy processing optimizations       */      if (currentState.explicitPolicy == 0)          sel.setPolicy(getMatchingPolicies());       /*       * If previous cert has a subject key identifier extension,       * use it to match on authority key identifier extension.       */      /*if (currentState.subjKeyId != null) {        AuthorityKeyIdentifierExtension authKeyId = new AuthorityKeyIdentifierExtension(                (KeyIdentifier) currentState.subjKeyId.get(SubjectKeyIdentifierExtension.KEY_ID),                null, null);        sel.setAuthorityKeyIdentifier(authKeyId.getExtensionValue());      }*/       /*       * Require EE certs       */      sel.setBasicConstraints(-2);       /* Retrieve matching certs from CertStores */      HashSet<X509Certificate> eeCerts = new HashSet<X509Certificate>();      addMatchingCerts(sel, certStores, eeCerts, true);       if (debug != null) {        debug.println("ReverseBuilder.getMatchingEECerts got " + eeCerts.size()                    + " certs.");      }      return eeCerts;    }     /*     * Retrieves all CA certificates which satisfy constraints     * and requirements specified in the parameters and PKIX state.     */    private Collection<X509Certificate> getMatchingCACerts        (ReverseState currentState, List<CertStore> certStores)        throws CertificateException, CertStoreException, IOException {       /*       * Compose a CertSelector to filter out       * certs which do not satisfy requirements.       */      X509CertSelector sel = new X509CertSelector();       /*       * Match on issuer (subject of previous cert)       */      sel.setIssuer(currentState.subjectDN);       /*       * Match on certificate validity date.       */      sel.setCertificateValid(date);       /*       * Match on target subject name (checks that current cert's       * name constraints permit it to certify target).       * (4 is the integer type for DIRECTORY name).       */      sel.addPathToName(4, targetCertConstraints.getSubjectAsBytes());       /*       * Policy processing optimizations       */      if (currentState.explicitPolicy == 0)          sel.setPolicy(getMatchingPolicies());       /*       * If previous cert has a subject key identifier extension,       * use it to match on authority key identifier extension.       */      /*if (currentState.subjKeyId != null) {        AuthorityKeyIdentifierExtension authKeyId = new AuthorityKeyIdentifierExtension(                (KeyIdentifier) currentState.subjKeyId.get(SubjectKeyIdentifierExtension.KEY_ID),                                null, null);        sel.setAuthorityKeyIdentifier(authKeyId.getExtensionValue());      }*/       /*       * Require CA certs       */      sel.setBasicConstraints(0);       /* Retrieve matching certs from CertStores */      ArrayList<X509Certificate> reverseCerts =          new ArrayList<X509Certificate>();      addMatchingCerts(sel, certStores, reverseCerts, true);       /* Sort remaining certs using name constraints */      Collections.sort(reverseCerts, new PKIXCertComparator());       if (debug != null)        debug.println("ReverseBuilder.getMatchingCACerts got " +                    reverseCerts.size() + " certs.");      return reverseCerts;    }     /*     * This inner class compares 2 PKIX certificates according to which     * should be tried first when building a path to the target. For     * now, the algorithm is to look at name constraints in each cert and those     * which constrain the path closer to the target should be     * ranked higher. Later, we may want to consider other components,     * such as key identifiers.     */    class PKIXCertComparator implements Comparator<X509Certificate> {         private Debug debug = Debug.getInstance("certpath");         public int compare(X509Certificate cert1, X509Certificate cert2) {             /*             * if either cert certifies the target, always             * put at head of list.             */            if (cert1.getSubjectX500Principal().equals(targetSubjectDN)) {                return -1;            }            if (cert2.getSubjectX500Principal().equals(targetSubjectDN)) {                return 1;            }             int targetDist1;            int targetDist2;            try {                X500Name targetSubjectName = X500Name.asX500Name(targetSubjectDN);                targetDist1 = Builder.targetDistance(                    null, cert1, targetSubjectName);                targetDist2 = Builder.targetDistance(                    null, cert2, targetSubjectName);            } catch (IOException e) {                if (debug != null) {                    debug.println("IOException in call to Builder.targetDistance");                    e.printStackTrace();                }                throw new ClassCastException                    ("Invalid target subject distinguished name");            }             if (targetDist1 == targetDist2)                return 0;             if (targetDist1 == -1)                return 1;             if (targetDist1 < targetDist2)                return -1;             return 1;        }    }     /**     * Verifies a matching certificate.     *     * This method executes any of the validation steps in the PKIX path validation     * algorithm which were not satisfied via filtering out non-compliant     * certificates with certificate matching rules.     *     * If the last certificate is being verified (the one whose subject     * matches the target subject, then the steps in Section 6.1.4 of the     * Certification Path Validation algorithm are NOT executed,     * regardless of whether or not the last cert is an end-entity     * cert or not. This allows callers to certify CA certs as     * well as EE certs.     *     * @param cert the certificate to be verified     * @param currentState the current state against which the cert is verified     * @param certPathList the certPathList generated thus far     */    void verifyCert(X509Certificate cert, State currState,        List<X509Certificate> certPathList)        throws GeneralSecurityException    {        if (debug != null) {            debug.println("ReverseBuilder.verifyCert(SN: "                + Debug.toHexString(cert.getSerialNumber())                + "\n  Subject: " + cert.getSubjectX500Principal() + ")");        }         ReverseState currentState = (ReverseState) currState;         /* we don't perform any validation of the trusted cert */        if (currentState.isInitial()) {            return;        }         /*         * check for looping - abort a loop if         * ((we encounter the same certificate twice) AND         * ((policyMappingInhibited = true) OR (no policy mapping         * extensions can be found between the occurences of the same         * certificate)))         * in order to facilitate the check to see if there are         * any policy mapping extensions found between the occurences         * of the same certificate, we reverse the certpathlist first         */        if ((certPathList != null) && (!certPathList.isEmpty())) {            List<X509Certificate> reverseCertList =                new ArrayList<X509Certificate>();            for (X509Certificate c : certPathList) {                reverseCertList.add(0, c);            }             boolean policyMappingFound = false;            for (X509Certificate cpListCert : reverseCertList) {                X509CertImpl cpListCertImpl = X509CertImpl.toImpl(cpListCert);                PolicyMappingsExtension policyMappingsExt =                        cpListCertImpl.getPolicyMappingsExtension();                if (policyMappingsExt != null) {                    policyMappingFound = true;                }                if (debug != null)                    debug.println("policyMappingFound = " + policyMappingFound);                if (cert.equals(cpListCert)){                    if ((buildParams.isPolicyMappingInhibited()) ||                        (!policyMappingFound)){                        if (debug != null)                            debug.println("loop detected!!");                        throw new CertPathValidatorException("loop detected");                    }                }            }        }         /* check if target cert */        boolean finalCert = cert.getSubjectX500Principal().equals(targetSubjectDN);         /* check if CA cert */        boolean caCert = (cert.getBasicConstraints() != -1 ? true : false);         /* if there are more certs to follow, verify certain constraints */        if (!finalCert) {             /* check if CA cert */            if (!caCert)                throw new CertPathValidatorException("cert is NOT a CA cert");             /* If the certificate was not self-issued, verify that             * remainingCerts is greater than zero             */            if ((currentState.remainingCACerts <= 0) && !X509CertImpl.isSelfIssued(cert)) {                    throw new CertPathValidatorException                        ("pathLenConstraint violated, path too long", null,                         null, -1, PKIXReason.PATH_TOO_LONG);            }             /*             * Check keyUsage extension (only if CA cert and not final cert)             */            KeyChecker.verifyCAKeyUsage(cert);         } else {             /*             * If final cert, check that it satisfies specified target             * constraints             */            if (targetCertConstraints.match(cert) == false) {                throw new CertPathValidatorException("target certificate " +                    "constraints check failed");            }        }         /*         * Check revocation.         */        if (buildParams.isRevocationEnabled()) {             currentState.crlChecker.check(cert,                                          currentState.pubKey,                                          currentState.crlSign);        }         /* Check name constraints if this is not a self-issued cert */        if (finalCert || !X509CertImpl.isSelfIssued(cert)){            if (currentState.nc != null){                try {                    if (!currentState.nc.verify(cert)){                        throw new CertPathValidatorException                            ("name constraints check failed", null, null, -1,                             PKIXReason.INVALID_NAME);                    }                } catch (IOException ioe){                    throw new CertPathValidatorException(ioe);                }            }        }         /*         * Check policy         */        X509CertImpl certImpl = X509CertImpl.toImpl(cert);        currentState.rootNode = PolicyChecker.processPolicies            (currentState.certIndex, initPolicies,            currentState.explicitPolicy, currentState.policyMapping,            currentState.inhibitAnyPolicy,            buildParams.getPolicyQualifiersRejected(), currentState.rootNode,            certImpl, finalCert);         /*         * Check CRITICAL private extensions         */        Set<String> unresolvedCritExts = cert.getCriticalExtensionOIDs();        if (unresolvedCritExts == null) {            unresolvedCritExts = Collections.<String>emptySet();        }         /*         * Check that the signature algorithm is not disabled.         */        currentState.algorithmChecker.check(cert, unresolvedCritExts);         for (PKIXCertPathChecker checker : currentState.userCheckers) {            checker.check(cert, unresolvedCritExts);        }         /*         * Look at the remaining extensions and remove any ones we have         * already checked. If there are any left, throw an exception!         */        if (!unresolvedCritExts.isEmpty()) {            unresolvedCritExts.remove(PKIXExtensions.BasicConstraints_Id.toString());            unresolvedCritExts.remove(PKIXExtensions.NameConstraints_Id.toString());            unresolvedCritExts.remove(PKIXExtensions.CertificatePolicies_Id.toString());            unresolvedCritExts.remove(PKIXExtensions.PolicyMappings_Id.toString());            unresolvedCritExts.remove(PKIXExtensions.PolicyConstraints_Id.toString());            unresolvedCritExts.remove(PKIXExtensions.InhibitAnyPolicy_Id.toString());            unresolvedCritExts.remove(PKIXExtensions.SubjectAlternativeName_Id.toString());            unresolvedCritExts.remove(PKIXExtensions.KeyUsage_Id.toString());            unresolvedCritExts.remove(PKIXExtensions.ExtendedKeyUsage_Id.toString());             if (!unresolvedCritExts.isEmpty())                throw new CertPathValidatorException                    ("Unrecognized critical extension(s)", null, null, -1,                     PKIXReason.UNRECOGNIZED_CRIT_EXT);        } 

Lines 1–500 of 539.