1 /*
2  * Copyright (c) 2000, 2019, 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 java.security.cert;
27 
28 import java.security.AccessController;
29 import java.security.InvalidAlgorithmParameterException;
30 import java.security.NoSuchAlgorithmException;
31 import java.security.NoSuchProviderException;
32 import java.security.PrivilegedAction;
33 import java.security.Provider;
34 import java.security.Security;
35 import java.util.Objects;
36 
37 import sun.security.jca.*;
38 import sun.security.jca.GetInstance.Instance;
39 
40 /**
41  * A class for validating certification paths (also known as certificate
42  * chains).
43  * <p>
44  * This class uses a provider-based architecture.
45  * To create a {@code CertPathValidator},
46  * call one of the static {@code getInstance} methods, passing in the
47  * algorithm name of the {@code CertPathValidator} desired and
48  * optionally the name of the provider desired.
49  *
50  * <p>Once a {@code CertPathValidator} object has been created, it can
51  * be used to validate certification paths by calling the {@link #validate
52  * validate} method and passing it the {@code CertPath} to be validated
53  * and an algorithm-specific set of parameters. If successful, the result is
54  * returned in an object that implements the
55  * {@code CertPathValidatorResult} interface.
56  *
57  * <p>The {@link #getRevocationChecker} method allows an application to specify
58  * additional algorithm-specific parameters and options used by the
59  * {@code CertPathValidator} when checking the revocation status of
60  * certificates. Here is an example demonstrating how it is used with the PKIX
61  * algorithm:
62  *
63  * <pre>
64  * CertPathValidator cpv = CertPathValidator.getInstance("PKIX");
65  * PKIXRevocationChecker rc = (PKIXRevocationChecker)cpv.getRevocationChecker();
66  * rc.setOptions(EnumSet.of(Option.SOFT_FAIL));
67  * params.addCertPathChecker(rc);
68  * CertPathValidatorResult cpvr = cpv.validate(path, params);
69  * </pre>
70  *
71  * <p>Every implementation of the Java platform is required to support the
72  * following standard {@code CertPathValidator} algorithm:
73  * <ul>
74  * <li>{@code PKIX}</li>
75  * </ul>
76  * This algorithm is described in the <a href=
77  * "{@docRoot}/../specs/security/standard-names.html#certpathvalidator-algorithms">
78  * CertPathValidator section</a> of the
79  * Java Security Standard Algorithm Names Specification.
80  * Consult the release documentation for your implementation to see if any
81  * other algorithms are supported.
82  *
83  * <p>
84  * <b>Concurrent Access</b>
85  * <p>
86  * The static methods of this class are guaranteed to be thread-safe.
87  * Multiple threads may concurrently invoke the static methods defined in
88  * this class with no ill effects.
89  * <p>
90  * However, this is not true for the non-static methods defined by this class.
91  * Unless otherwise documented by a specific provider, threads that need to
92  * access a single {@code CertPathValidator} instance concurrently should
93  * synchronize amongst themselves and provide the necessary locking. Multiple
94  * threads each manipulating a different {@code CertPathValidator}
95  * instance need not synchronize.
96  *
97  * @see CertPath
98  *
99  * @since       1.4
100  * @author      Yassir Elley
101  */
102 public class CertPathValidator {
103 
104     /*
105      * Constant to lookup in the Security properties file to determine
106      * the default certpathvalidator type. In the Security properties file,
107      * the default certpathvalidator type is given as:
108      * <pre>
109      * certpathvalidator.type=PKIX
110      * </pre>
111      */
112     private static final String CPV_TYPE = "certpathvalidator.type";
113     private final CertPathValidatorSpi validatorSpi;
114     private final Provider provider;
115     private final String algorithm;
116 
117     /**
118      * Creates a {@code CertPathValidator} object of the given algorithm,
119      * and encapsulates the given provider implementation (SPI object) in it.
120      *
121      * @param validatorSpi the provider implementation
122      * @param provider the provider
123      * @param algorithm the algorithm name
124      */
CertPathValidator(CertPathValidatorSpi validatorSpi, Provider provider, String algorithm)125     protected CertPathValidator(CertPathValidatorSpi validatorSpi,
126         Provider provider, String algorithm)
127     {
128         this.validatorSpi = validatorSpi;
129         this.provider = provider;
130         this.algorithm = algorithm;
131     }
132 
133     /**
134      * Returns a {@code CertPathValidator} object that implements the
135      * specified algorithm.
136      *
137      * <p> This method traverses the list of registered security Providers,
138      * starting with the most preferred Provider.
139      * A new CertPathValidator object encapsulating the
140      * CertPathValidatorSpi implementation from the first
141      * Provider that supports the specified algorithm is returned.
142      *
143      * <p> Note that the list of registered providers may be retrieved via
144      * the {@link Security#getProviders() Security.getProviders()} method.
145      *
146      * @implNote
147      * The JDK Reference Implementation additionally uses the
148      * {@code jdk.security.provider.preferred}
149      * {@link Security#getProperty(String) Security} property to determine
150      * the preferred provider order for the specified algorithm. This
151      * may be different than the order of providers returned by
152      * {@link Security#getProviders() Security.getProviders()}.
153      *
154      * @param algorithm the name of the requested {@code CertPathValidator}
155      * algorithm. See the CertPathValidator section in the <a href=
156      * "{@docRoot}/../specs/security/standard-names.html#certpathvalidator-algorithms">
157      * Java Security Standard Algorithm Names Specification</a>
158      * for information about standard algorithm names.
159      *
160      * @return a {@code CertPathValidator} object that implements the
161      *         specified algorithm
162      *
163      * @throws NoSuchAlgorithmException if no {@code Provider} supports a
164      *         {@code CertPathValidatorSpi} implementation for the
165      *         specified algorithm
166      *
167      * @throws NullPointerException if {@code algorithm} is {@code null}
168      *
169      * @see java.security.Provider
170      */
getInstance(String algorithm)171     public static CertPathValidator getInstance(String algorithm)
172             throws NoSuchAlgorithmException {
173         Objects.requireNonNull(algorithm, "null algorithm name");
174         Instance instance = GetInstance.getInstance("CertPathValidator",
175             CertPathValidatorSpi.class, algorithm);
176         return new CertPathValidator((CertPathValidatorSpi)instance.impl,
177             instance.provider, algorithm);
178     }
179 
180     /**
181      * Returns a {@code CertPathValidator} object that implements the
182      * specified algorithm.
183      *
184      * <p> A new CertPathValidator object encapsulating the
185      * CertPathValidatorSpi implementation from the specified provider
186      * is returned.  The specified provider must be registered
187      * in the security provider list.
188      *
189      * <p> Note that the list of registered providers may be retrieved via
190      * the {@link Security#getProviders() Security.getProviders()} method.
191      *
192      * @param algorithm the name of the requested {@code CertPathValidator}
193      * algorithm. See the CertPathValidator section in the <a href=
194      * "{@docRoot}/../specs/security/standard-names.html#certpathvalidator-algorithms">
195      * Java Security Standard Algorithm Names Specification</a>
196      * for information about standard algorithm names.
197      *
198      * @param provider the name of the provider.
199      *
200      * @return a {@code CertPathValidator} object that implements the
201      *         specified algorithm
202      *
203      * @throws IllegalArgumentException if the {@code provider} is
204      *         {@code null} or empty
205      *
206      * @throws NoSuchAlgorithmException if a {@code CertPathValidatorSpi}
207      *         implementation for the specified algorithm is not
208      *         available from the specified provider
209      *
210      * @throws NoSuchProviderException if the specified provider is not
211      *         registered in the security provider list
212      *
213      * @throws NullPointerException if {@code algorithm} is {@code null}
214      *
215      * @see java.security.Provider
216      */
getInstance(String algorithm, String provider)217     public static CertPathValidator getInstance(String algorithm,
218             String provider) throws NoSuchAlgorithmException,
219             NoSuchProviderException {
220         Objects.requireNonNull(algorithm, "null algorithm name");
221         Instance instance = GetInstance.getInstance("CertPathValidator",
222             CertPathValidatorSpi.class, algorithm, provider);
223         return new CertPathValidator((CertPathValidatorSpi)instance.impl,
224             instance.provider, algorithm);
225     }
226 
227     /**
228      * Returns a {@code CertPathValidator} object that implements the
229      * specified algorithm.
230      *
231      * <p> A new CertPathValidator object encapsulating the
232      * CertPathValidatorSpi implementation from the specified Provider
233      * object is returned.  Note that the specified Provider object
234      * does not have to be registered in the provider list.
235      *
236      * @param algorithm the name of the requested {@code CertPathValidator}
237      * algorithm. See the CertPathValidator section in the <a href=
238      * "{@docRoot}/../specs/security/standard-names.html#certpathvalidator-algorithms">
239      * Java Security Standard Algorithm Names Specification</a>
240      * for information about standard algorithm names.
241      *
242      * @param provider the provider.
243      *
244      * @return a {@code CertPathValidator} object that implements the
245      *          specified algorithm
246      *
247      * @throws IllegalArgumentException if the {@code provider} is
248      *         {@code null}
249      *
250      * @throws NoSuchAlgorithmException if a {@code CertPathValidatorSpi}
251      *         implementation for the specified algorithm is not available
252      *         from the specified Provider object
253      *
254      * @throws NullPointerException if {@code algorithm} is {@code null}
255      *
256      * @see java.security.Provider
257      */
getInstance(String algorithm, Provider provider)258     public static CertPathValidator getInstance(String algorithm,
259             Provider provider) throws NoSuchAlgorithmException {
260         Objects.requireNonNull(algorithm, "null algorithm name");
261         Instance instance = GetInstance.getInstance("CertPathValidator",
262             CertPathValidatorSpi.class, algorithm, provider);
263         return new CertPathValidator((CertPathValidatorSpi)instance.impl,
264             instance.provider, algorithm);
265     }
266 
267     /**
268      * Returns the {@code Provider} of this
269      * {@code CertPathValidator}.
270      *
271      * @return the {@code Provider} of this {@code CertPathValidator}
272      */
getProvider()273     public final Provider getProvider() {
274         return this.provider;
275     }
276 
277     /**
278      * Returns the algorithm name of this {@code CertPathValidator}.
279      *
280      * @return the algorithm name of this {@code CertPathValidator}
281      */
getAlgorithm()282     public final String getAlgorithm() {
283         return this.algorithm;
284     }
285 
286     /**
287      * Validates the specified certification path using the specified
288      * algorithm parameter set.
289      * <p>
290      * The {@code CertPath} specified must be of a type that is
291      * supported by the validation algorithm, otherwise an
292      * {@code InvalidAlgorithmParameterException} will be thrown. For
293      * example, a {@code CertPathValidator} that implements the PKIX
294      * algorithm validates {@code CertPath} objects of type X.509.
295      *
296      * @param certPath the {@code CertPath} to be validated
297      * @param params the algorithm parameters
298      * @return the result of the validation algorithm
299      * @throws    CertPathValidatorException if the {@code CertPath}
300      * does not validate
301      * @throws    InvalidAlgorithmParameterException if the specified
302      * parameters or the type of the specified {@code CertPath} are
303      * inappropriate for this {@code CertPathValidator}
304      */
validate(CertPath certPath, CertPathParameters params)305     public final CertPathValidatorResult validate(CertPath certPath,
306         CertPathParameters params)
307         throws CertPathValidatorException, InvalidAlgorithmParameterException
308     {
309         return validatorSpi.engineValidate(certPath, params);
310     }
311 
312     /**
313      * Returns the default {@code CertPathValidator} type as specified by
314      * the {@code certpathvalidator.type} security property, or the string
315      * {@literal "PKIX"} if no such property exists.
316      *
317      * <p>The default {@code CertPathValidator} type can be used by
318      * applications that do not want to use a hard-coded type when calling one
319      * of the {@code getInstance} methods, and want to provide a default
320      * type in case a user does not specify its own.
321      *
322      * <p>The default {@code CertPathValidator} type can be changed by
323      * setting the value of the {@code certpathvalidator.type} security
324      * property to the desired type.
325      *
326      * @see java.security.Security security properties
327      * @return the default {@code CertPathValidator} type as specified
328      * by the {@code certpathvalidator.type} security property, or the string
329      * {@literal "PKIX"} if no such property exists.
330      */
getDefaultType()331     public static final String getDefaultType() {
332         String cpvtype =
333             AccessController.doPrivileged(new PrivilegedAction<>() {
334                 public String run() {
335                     return Security.getProperty(CPV_TYPE);
336                 }
337             });
338         return (cpvtype == null) ? "PKIX" : cpvtype;
339     }
340 
341     /**
342      * Returns a {@code CertPathChecker} that the encapsulated
343      * {@code CertPathValidatorSpi} implementation uses to check the revocation
344      * status of certificates. A PKIX implementation returns objects of
345      * type {@code PKIXRevocationChecker}. Each invocation of this method
346      * returns a new instance of {@code CertPathChecker}.
347      *
348      * <p>The primary purpose of this method is to allow callers to specify
349      * additional input parameters and options specific to revocation checking.
350      * See the class description for an example.
351      *
352      * @return a {@code CertPathChecker}
353      * @throws UnsupportedOperationException if the service provider does not
354      *         support this method
355      * @since 1.8
356      */
getRevocationChecker()357     public final CertPathChecker getRevocationChecker() {
358         return validatorSpi.engineGetRevocationChecker();
359     }
360 }
361