Home | History | Annotate | Download | only in certpath
      1 /*
      2  * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
      3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
      4  *
      5  * This code is free software; you can redistribute it and/or modify it
      6  * under the terms of the GNU General Public License version 2 only, as
      7  * published by the Free Software Foundation.  Oracle designates this
      8  * particular file as subject to the "Classpath" exception as provided
      9  * by Oracle in the LICENSE file that accompanied this code.
     10  *
     11  * This code is distributed in the hope that it will be useful, but WITHOUT
     12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14  * version 2 for more details (a copy is included in the LICENSE file that
     15  * accompanied this code).
     16  *
     17  * You should have received a copy of the GNU General Public License version
     18  * 2 along with this work; if not, write to the Free Software Foundation,
     19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
     20  *
     21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
     22  * or visit www.oracle.com if you need additional information or have any
     23  * questions.
     24  */
     25 
     26 package sun.security.provider.certpath;
     27 
     28 import java.io.IOException;
     29 import java.security.InvalidAlgorithmParameterException;
     30 import java.security.cert.*;
     31 import java.util.*;
     32 
     33 import sun.security.provider.certpath.PKIX.ValidatorParams;
     34 import sun.security.x509.X509CertImpl;
     35 import sun.security.util.Debug;
     36 
     37 /**
     38  * This class implements the PKIX validation algorithm for certification
     39  * paths consisting exclusively of <code>X509Certificates</code>. It uses
     40  * the specified input parameter set (which must be a
     41  * <code>PKIXParameters</code> object).
     42  *
     43  * @since       1.4
     44  * @author      Yassir Elley
     45  */
     46 public final class PKIXCertPathValidator extends CertPathValidatorSpi {
     47 
     48     private static final Debug debug = Debug.getInstance("certpath");
     49 
     50     /**
     51      * Default constructor.
     52      */
     53     public PKIXCertPathValidator() {}
     54 
     55     @Override
     56     public CertPathChecker engineGetRevocationChecker() {
     57         return new RevocationChecker();
     58     }
     59 
     60     /**
     61      * Validates a certification path consisting exclusively of
     62      * <code>X509Certificate</code>s using the PKIX validation algorithm,
     63      * which uses the specified input parameter set.
     64      * The input parameter set must be a <code>PKIXParameters</code> object.
     65      *
     66      * @param cp the X509 certification path
     67      * @param params the input PKIX parameter set
     68      * @return the result
     69      * @throws CertPathValidatorException if cert path does not validate.
     70      * @throws InvalidAlgorithmParameterException if the specified
     71      *         parameters are inappropriate for this CertPathValidator
     72      */
     73     @Override
     74     public CertPathValidatorResult engineValidate(CertPath cp,
     75                                                   CertPathParameters params)
     76         throws CertPathValidatorException, InvalidAlgorithmParameterException
     77     {
     78         ValidatorParams valParams = PKIX.checkParams(cp, params);
     79         return validate(valParams);
     80     }
     81 
     82     private static PKIXCertPathValidatorResult validate(ValidatorParams params)
     83         throws CertPathValidatorException
     84     {
     85         if (debug != null)
     86             debug.println("PKIXCertPathValidator.engineValidate()...");
     87 
     88         // Retrieve the first certificate in the certpath
     89         // (to be used later in pre-screening)
     90         AdaptableX509CertSelector selector = null;
     91         List<X509Certificate> certList = params.certificates();
     92         if (!certList.isEmpty()) {
     93             selector = new AdaptableX509CertSelector();
     94             X509Certificate firstCert = certList.get(0);
     95             // check trusted certificate's subject
     96             selector.setSubject(firstCert.getIssuerX500Principal());
     97             /*
     98              * Facilitate certification path construction with authority
     99              * key identifier and subject key identifier.
    100              */
    101             try {
    102                 X509CertImpl firstCertImpl = X509CertImpl.toImpl(firstCert);
    103                 selector.setSkiAndSerialNumber(
    104                             firstCertImpl.getAuthorityKeyIdentifierExtension());
    105             } catch (CertificateException | IOException e) {
    106                 // ignore
    107             }
    108         }
    109 
    110         CertPathValidatorException lastException = null;
    111 
    112         // We iterate through the set of trust anchors until we find
    113         // one that works at which time we stop iterating
    114         for (TrustAnchor anchor : params.trustAnchors()) {
    115             X509Certificate trustedCert = anchor.getTrustedCert();
    116             if (trustedCert != null) {
    117                 // if this trust anchor is not worth trying,
    118                 // we move on to the next one
    119                 if (selector != null && !selector.match(trustedCert)) {
    120                     if (debug != null) {
    121                         debug.println("NO - don't try this trustedCert");
    122                     }
    123                     continue;
    124                 }
    125 
    126                 if (debug != null) {
    127                     debug.println("YES - try this trustedCert");
    128                     debug.println("anchor.getTrustedCert()."
    129                         + "getSubjectX500Principal() = "
    130                         + trustedCert.getSubjectX500Principal());
    131                 }
    132             } else {
    133                 if (debug != null) {
    134                     debug.println("PKIXCertPathValidator.engineValidate(): "
    135                         + "anchor.getTrustedCert() == null");
    136                 }
    137             }
    138 
    139             try {
    140                 return validate(anchor, params);
    141             } catch (CertPathValidatorException cpe) {
    142                 // remember this exception
    143                 lastException = cpe;
    144             }
    145         }
    146 
    147         // could not find a trust anchor that verified
    148         // (a) if we did a validation and it failed, use that exception
    149         if (lastException != null) {
    150             throw lastException;
    151         }
    152         // (b) otherwise, generate new exception
    153         throw new CertPathValidatorException
    154             ("Path does not chain with any of the trust anchors",
    155              null, null, -1, PKIXReason.NO_TRUST_ANCHOR);
    156     }
    157 
    158     private static PKIXCertPathValidatorResult validate(TrustAnchor anchor,
    159                                                         ValidatorParams params)
    160         throws CertPathValidatorException
    161     {
    162         // add standard checkers that we will be using
    163         // Android-removed: Android doesn't use this mechanism for checking untrusted certificates.
    164         // check if anchor is untrusted
    165         //UntrustedChecker untrustedChecker = new UntrustedChecker();
    166         //X509Certificate anchorCert = anchor.getTrustedCert();
    167         //if (anchorCert != null) {
    168         //    untrustedChecker.check(anchorCert);
    169         //}
    170 
    171         int certPathLen = params.certificates().size();
    172 
    173         // create PKIXCertPathCheckers
    174         List<PKIXCertPathChecker> certPathCheckers = new ArrayList<>();
    175         // add standard checkers that we will be using
    176         // Android-removed: Android doesn't use this mechanism for checking untrusted certificates.
    177         // certPathCheckers.add(untrustedChecker);
    178         certPathCheckers.add(new AlgorithmChecker(anchor));
    179         certPathCheckers.add(new KeyChecker(certPathLen,
    180                                             params.targetCertConstraints()));
    181         certPathCheckers.add(new ConstraintsChecker(certPathLen));
    182         PolicyNodeImpl rootNode =
    183             new PolicyNodeImpl(null, PolicyChecker.ANY_POLICY, null, false,
    184                                Collections.singleton(PolicyChecker.ANY_POLICY),
    185                                false);
    186         PolicyChecker pc = new PolicyChecker(params.initialPolicies(),
    187                                              certPathLen,
    188                                              params.explicitPolicyRequired(),
    189                                              params.policyMappingInhibited(),
    190                                              params.anyPolicyInhibited(),
    191                                              params.policyQualifiersRejected(),
    192                                              rootNode);
    193         certPathCheckers.add(pc);
    194         // default value for date is current time
    195         BasicChecker bc = new BasicChecker(anchor, params.date(),
    196                                            params.sigProvider(), false);
    197         certPathCheckers.add(bc);
    198 
    199         boolean revCheckerAdded = false;
    200         List<PKIXCertPathChecker> checkers = params.certPathCheckers();
    201         for (PKIXCertPathChecker checker : checkers) {
    202             if (checker instanceof PKIXRevocationChecker) {
    203                 if (revCheckerAdded) {
    204                     throw new CertPathValidatorException(
    205                         "Only one PKIXRevocationChecker can be specified");
    206                 }
    207                 revCheckerAdded = true;
    208                 // if it's our own, initialize it
    209                 if (checker instanceof RevocationChecker) {
    210                     ((RevocationChecker)checker).init(anchor, params);
    211                 }
    212             }
    213         }
    214         // only add a RevocationChecker if revocation is enabled and
    215         // a PKIXRevocationChecker has not already been added
    216         if (params.revocationEnabled() && !revCheckerAdded) {
    217             certPathCheckers.add(new RevocationChecker(anchor, params));
    218         }
    219         // add user-specified checkers
    220         certPathCheckers.addAll(checkers);
    221 
    222         PKIXMasterCertPathValidator.validate(params.certPath(),
    223                                              params.certificates(),
    224                                              certPathCheckers);
    225 
    226         return new PKIXCertPathValidatorResult(anchor, pc.getPolicyTree(),
    227                                                bc.getPublicKey());
    228     }
    229 }
    230