353 lines · 13.4 KB · Java
RawDownload
/* * 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 * 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.AccessController;import java.security.InvalidAlgorithmParameterException;import java.security.cert.CertPath;import java.security.cert.CertPathParameters;import java.security.cert.CertPathValidatorException;import java.security.cert.CertPathValidatorSpi;import java.security.cert.CertPathValidatorResult;import java.security.cert.PKIXCertPathChecker;import java.security.cert.PKIXCertPathValidatorResult;import java.security.cert.PKIXParameters;import java.security.cert.PKIXReason;import java.security.cert.PolicyNode;import java.security.cert.TrustAnchor;import java.security.cert.X509Certificate;import java.security.cert.X509CertSelector;import java.util.Collections;import java.util.List;import java.util.ArrayList;import java.util.Date;import java.util.Set;import javax.security.auth.x500.X500Principal;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 * the specified input parameter set (which must be a * <code>PKIXParameters</code> object) and signature provider (if any). * * @since       1.4 * @author      Yassir Elley */public class PKIXCertPathValidator extends CertPathValidatorSpi {     private static final Debug debug = Debug.getInstance("certpath");    private Date testDate;    private List<PKIXCertPathChecker> userCheckers;    private String sigProvider;    private BasicChecker basicChecker;    private boolean ocspEnabled = false;    private boolean onlyEECert = false;     /**     * Default constructor.     */    public PKIXCertPathValidator() {}     /**     * Validates a certification path consisting exclusively of     * <code>X509Certificate</code>s using the PKIX validation algorithm,     * which uses the specified input parameter set.     * The input parameter set must be a <code>PKIXParameters</code> object.     *     * @param cp the X509 certification path     * @param param the input PKIX parameter set     * @return the result     * @exception CertPathValidatorException Exception thrown if cert path     * does not validate.     * @exception InvalidAlgorithmParameterException if the specified     * parameters are inappropriate for this certification path validator     */    public CertPathValidatorResult engineValidate(CertPath cp,        CertPathParameters param)        throws CertPathValidatorException, InvalidAlgorithmParameterException    {        if (debug != null)            debug.println("PKIXCertPathValidator.engineValidate()...");         if (!(param instanceof PKIXParameters)) {            throw new InvalidAlgorithmParameterException("inappropriate "                + "parameters, must be an instance of PKIXParameters");        }         if (!cp.getType().equals("X.509") && !cp.getType().equals("X509")) {            throw new InvalidAlgorithmParameterException("inappropriate "                + "certification path type specified, must be X.509 or X509");        }         PKIXParameters pkixParam = (PKIXParameters) param;         // Make sure that none of the trust anchors include name constraints        // (not supported).        Set<TrustAnchor> anchors = pkixParam.getTrustAnchors();        for (TrustAnchor anchor : anchors) {            if (anchor.getNameConstraints() != null) {                throw new InvalidAlgorithmParameterException                    ("name constraints in trust anchor not supported");            }        }         // the certpath which has been passed in (cp)        // has the target cert as the first certificate - we        // need to keep this cp so we can return it        // in case of an exception and for policy qualifier        // processing - however, for certpath validation,        // we need to create a reversed path, where we reverse the        // ordering so that the target cert is the last certificate         // Must copy elements of certList into a new modifiable List before        // calling Collections.reverse().        ArrayList<X509Certificate> certList = new ArrayList<X509Certificate>            ((List<X509Certificate>)cp.getCertificates());        if (debug != null) {            if (certList.isEmpty()) {                debug.println("PKIXCertPathValidator.engineValidate() "                    + "certList is empty");            }            debug.println("PKIXCertPathValidator.engineValidate() "                + "reversing certpath...");        }        Collections.reverse(certList);         // now certList has the target cert as the last cert and we        // can proceed with normal validation         populateVariables(pkixParam);         // Retrieve the first certificate in the certpath        // (to be used later in pre-screening)        X509Certificate firstCert = null;        if (!certList.isEmpty()) {            firstCert = certList.get(0);        }         CertPathValidatorException lastException = null;         // We iterate through the set of trust anchors until we find        // one that works at which time we stop iterating        for (TrustAnchor anchor : anchors) {            X509Certificate trustedCert = anchor.getTrustedCert();            if (trustedCert != null) {                if (debug != null) {                    debug.println("PKIXCertPathValidator.engineValidate() "                        + "anchor.getTrustedCert() != null");                }                 // if this trust anchor is not worth trying,                // we move on to the next one                if (!isWorthTrying(trustedCert, firstCert)) {                    continue;                }                 if (debug != null) {                    debug.println("anchor.getTrustedCert()."                        + "getSubjectX500Principal() = "                        + trustedCert.getSubjectX500Principal());                }            } else {                if (debug != null) {                    debug.println("PKIXCertPathValidator.engineValidate(): "                        + "anchor.getTrustedCert() == null");                }            }             try {                PolicyNodeImpl rootNode = new PolicyNodeImpl(null,                    PolicyChecker.ANY_POLICY, null, false,                    Collections.singleton(PolicyChecker.ANY_POLICY), false);                PolicyNode policyTree =                    doValidate(anchor, cp, certList, pkixParam, rootNode);                // if this anchor works, return success                return new PKIXCertPathValidatorResult(anchor, policyTree,                    basicChecker.getPublicKey());            } catch (CertPathValidatorException cpe) {                // remember this exception                lastException = cpe;            }        }         // could not find a trust anchor that verified        // (a) if we did a validation and it failed, use that exception        if (lastException != null) {            throw lastException;        }        // (b) otherwise, generate new exception        throw new CertPathValidatorException            ("Path does not chain with any of the trust anchors",             null, null, -1, PKIXReason.NO_TRUST_ANCHOR);    }     /**     * Internal method to do some simple checks to see if a given cert is     * worth trying to validate in the chain.     */    private boolean isWorthTrying(X509Certificate trustedCert,          X509Certificate firstCert) {         boolean worthy = false;         if (debug != null) {            debug.println("PKIXCertPathValidator.isWorthTrying() checking "                + "if this trusted cert is worth trying ...");        }         if (firstCert == null) {            return true;        }         AdaptableX509CertSelector issuerSelector =                        new AdaptableX509CertSelector();         // check trusted certificate's subject        issuerSelector.setSubject(firstCert.getIssuerX500Principal());         // 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");            } else {                debug.println("NO - don't try this trustedCert");            }        }         return worthy;    }     /**     * Internal method to setup the internal state     */    private void populateVariables(PKIXParameters pkixParam)    {        // default value for testDate is current time        testDate = pkixParam.getDate();        if (testDate == null) {            testDate = new Date(System.currentTimeMillis());        }         userCheckers = pkixParam.getCertPathCheckers();        sigProvider = pkixParam.getSigProvider();         if (pkixParam.isRevocationEnabled()) {            // Examine OCSP security property            ocspEnabled = AccessController.doPrivileged(                new GetBooleanSecurityPropertyAction                    (OCSPChecker.OCSP_ENABLE_PROP));            onlyEECert = AccessController.doPrivileged(                new GetBooleanSecurityPropertyAction                    ("com.sun.security.onlyCheckRevocationOfEECert"));        }    }     /**     * Internal method to actually validate a constructed path.     *     * @return the valid policy tree     */    private PolicyNode doValidate(            TrustAnchor anchor, CertPath cpOriginal,            ArrayList<X509Certificate> certList, PKIXParameters pkixParam,            PolicyNodeImpl rootNode) throws CertPathValidatorException    {        int certPathLen = certList.size();         basicChecker = new BasicChecker(anchor, testDate, sigProvider, false);        AlgorithmChecker algorithmChecker = new AlgorithmChecker(anchor);        KeyChecker keyChecker = new KeyChecker(certPathLen,            pkixParam.getTargetCertConstraints());        ConstraintsChecker constraintsChecker =            new ConstraintsChecker(certPathLen);         PolicyChecker policyChecker =            new PolicyChecker(pkixParam.getInitialPolicies(), certPathLen,                              pkixParam.isExplicitPolicyRequired(),                              pkixParam.isPolicyMappingInhibited(),                              pkixParam.isAnyPolicyInhibited(),                              pkixParam.getPolicyQualifiersRejected(),                              rootNode);         ArrayList<PKIXCertPathChecker> certPathCheckers =            new ArrayList<PKIXCertPathChecker>();        // add standard checkers that we will be using        certPathCheckers.add(algorithmChecker);        certPathCheckers.add(keyChecker);        certPathCheckers.add(constraintsChecker);        certPathCheckers.add(policyChecker);        certPathCheckers.add(basicChecker);         // only add a revocationChecker if revocation is enabled        if (pkixParam.isRevocationEnabled()) {             // Use OCSP if it has been enabled            if (ocspEnabled) {                OCSPChecker ocspChecker =                    new OCSPChecker(cpOriginal, pkixParam, onlyEECert);                certPathCheckers.add(ocspChecker);            }             // Always use CRLs            CrlRevocationChecker revocationChecker = new                CrlRevocationChecker(anchor, pkixParam, certList, onlyEECert);            certPathCheckers.add(revocationChecker);        }         // add user-specified checkers        certPathCheckers.addAll(userCheckers);         PKIXMasterCertPathValidator masterValidator =            new PKIXMasterCertPathValidator(certPathCheckers);         masterValidator.validate(cpOriginal, certList);         return policyChecker.getPolicyTree();    }}