• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2000, 2013, 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      */
PKIXCertPathValidator()53     public PKIXCertPathValidator() {}
54 
55     @Override
engineGetRevocationChecker()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
engineValidate(CertPath cp, CertPathParameters params)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 
validate(ValidatorParams params)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             // check the validity period
98             selector.setValidityPeriod(firstCert.getNotBefore(),
99                                        firstCert.getNotAfter());
100             /*
101              * Facilitate certification path construction with authority
102              * key identifier and subject key identifier.
103              */
104             try {
105                 X509CertImpl firstCertImpl = X509CertImpl.toImpl(firstCert);
106                 selector.parseAuthorityKeyIdentifierExtension(
107                             firstCertImpl.getAuthorityKeyIdentifierExtension());
108             } catch (CertificateException | IOException e) {
109                 // ignore
110             }
111         }
112 
113         CertPathValidatorException lastException = null;
114 
115         // We iterate through the set of trust anchors until we find
116         // one that works at which time we stop iterating
117         for (TrustAnchor anchor : params.trustAnchors()) {
118             X509Certificate trustedCert = anchor.getTrustedCert();
119             if (trustedCert != null) {
120                 // if this trust anchor is not worth trying,
121                 // we move on to the next one
122                 if (selector != null && !selector.match(trustedCert)) {
123                     if (debug != null) {
124                         debug.println("NO - don't try this trustedCert");
125                     }
126                     continue;
127                 }
128 
129                 if (debug != null) {
130                     debug.println("YES - try this trustedCert");
131                     debug.println("anchor.getTrustedCert()."
132                         + "getSubjectX500Principal() = "
133                         + trustedCert.getSubjectX500Principal());
134                 }
135             } else {
136                 if (debug != null) {
137                     debug.println("PKIXCertPathValidator.engineValidate(): "
138                         + "anchor.getTrustedCert() == null");
139                 }
140             }
141 
142             try {
143                 return validate(anchor, params);
144             } catch (CertPathValidatorException cpe) {
145                 // remember this exception
146                 lastException = cpe;
147             }
148         }
149 
150         // could not find a trust anchor that verified
151         // (a) if we did a validation and it failed, use that exception
152         if (lastException != null) {
153             throw lastException;
154         }
155         // (b) otherwise, generate new exception
156         throw new CertPathValidatorException
157             ("Path does not chain with any of the trust anchors",
158              null, null, -1, PKIXReason.NO_TRUST_ANCHOR);
159     }
160 
validate(TrustAnchor anchor, ValidatorParams params)161     private static PKIXCertPathValidatorResult validate(TrustAnchor anchor,
162                                                         ValidatorParams params)
163         throws CertPathValidatorException
164     {
165         int certPathLen = params.certificates().size();
166 
167         // create PKIXCertPathCheckers
168         List<PKIXCertPathChecker> certPathCheckers = new ArrayList<>();
169         // add standard checkers that we will be using
170         certPathCheckers.add(new UntrustedChecker());
171         certPathCheckers.add(new AlgorithmChecker(anchor));
172         certPathCheckers.add(new KeyChecker(certPathLen,
173                                             params.targetCertConstraints()));
174         certPathCheckers.add(new ConstraintsChecker(certPathLen));
175         PolicyNodeImpl rootNode =
176             new PolicyNodeImpl(null, PolicyChecker.ANY_POLICY, null, false,
177                                Collections.singleton(PolicyChecker.ANY_POLICY),
178                                false);
179         PolicyChecker pc = new PolicyChecker(params.initialPolicies(),
180                                              certPathLen,
181                                              params.explicitPolicyRequired(),
182                                              params.policyMappingInhibited(),
183                                              params.anyPolicyInhibited(),
184                                              params.policyQualifiersRejected(),
185                                              rootNode);
186         certPathCheckers.add(pc);
187         // default value for date is current time
188         BasicChecker bc = new BasicChecker(anchor, params.date(),
189                                            params.sigProvider(), false);
190         certPathCheckers.add(bc);
191 
192         boolean revCheckerAdded = false;
193         List<PKIXCertPathChecker> checkers = params.certPathCheckers();
194         for (PKIXCertPathChecker checker : checkers) {
195             if (checker instanceof PKIXRevocationChecker) {
196                 if (revCheckerAdded) {
197                     throw new CertPathValidatorException(
198                         "Only one PKIXRevocationChecker can be specified");
199                 }
200                 revCheckerAdded = true;
201                 // if it's our own, initialize it
202                 if (checker instanceof RevocationChecker) {
203                     ((RevocationChecker)checker).init(anchor, params);
204                 }
205             }
206         }
207         // only add a RevocationChecker if revocation is enabled and
208         // a PKIXRevocationChecker has not already been added
209         if (params.revocationEnabled() && !revCheckerAdded) {
210             certPathCheckers.add(new RevocationChecker(anchor, params));
211         }
212         // add user-specified checkers
213         certPathCheckers.addAll(checkers);
214 
215         PKIXMasterCertPathValidator.validate(params.certPath(),
216                                              params.certificates(),
217                                              certPathCheckers);
218 
219         return new PKIXCertPathValidatorResult(anchor, pc.getPolicyTree(),
220                                                bc.getPublicKey());
221     }
222 }
223