• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      */
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             /*
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 
validate(TrustAnchor anchor, ValidatorParams params)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