1 /*
2  * Copyright (c) 2000, 2021, 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.Collection;
36 import java.util.Objects;
37 
38 import sun.security.jca.*;
39 import sun.security.jca.GetInstance.Instance;
40 
41 /**
42  * A class for retrieving {@code Certificate}s and {@code CRL}s
43  * from a repository.
44  * <p>
45  * This class uses a provider-based architecture.
46  * To create a {@code CertStore}, call one of the static
47  * {@code getInstance} methods, passing in the type of
48  * {@code CertStore} desired, any applicable initialization parameters
49  * and optionally the name of the provider desired.
50  * <p>
51  * Once the {@code CertStore} has been created, it can be used to
52  * retrieve {@code Certificate}s and {@code CRL}s by calling its
53  * {@link #getCertificates(CertSelector selector) getCertificates} and
54  * {@link #getCRLs(CRLSelector selector) getCRLs} methods.
55  * <p>
56  * Unlike a {@link java.security.KeyStore KeyStore}, which provides access
57  * to a cache of private keys and trusted certificates, a
58  * {@code CertStore} is designed to provide access to a potentially
59  * vast repository of untrusted certificates and CRLs. For example, an LDAP
60  * implementation of {@code CertStore} provides access to certificates
61  * and CRLs stored in one or more directories using the LDAP protocol and the
62  * schema as defined in the RFC service attribute.
63  *
64  * <p> Every implementation of the Java platform is required to support the
65  * following standard {@code CertStore} type:
66  * <ul>
67  * <li>{@code Collection}</li>
68  * </ul>
69  * This type is described in the <a href=
70  * "{@docRoot}/../specs/security/standard-names.html#certstore-types">
71  * CertStore section</a> of the
72  * Java Security Standard Algorithm Names Specification.
73  * Consult the release documentation for your implementation to see if any
74  * other types are supported.
75  *
76  * <p>
77  * <b>Concurrent Access</b>
78  * <p>
79  * All public methods of {@code CertStore} objects must be thread-safe.
80  * That is, multiple threads may concurrently invoke these methods on a
81  * single {@code CertStore} object (or more than one) with no
82  * ill effects. This allows a {@code CertPathBuilder} to search for a
83  * CRL while simultaneously searching for further certificates, for instance.
84  * <p>
85  * The static methods of this class are also guaranteed to be thread-safe.
86  * Multiple threads may concurrently invoke the static methods defined in
87  * this class with no ill effects.
88  *
89  * @since       1.4
90  * @author      Sean Mullan, Steve Hanna
91  */
92 public class CertStore {
93     /*
94      * Constant to lookup in the Security properties file to determine
95      * the default certstore type. In the Security properties file, the
96      * default certstore type is given as:
97      * <pre>
98      * certstore.type=LDAP
99      * </pre>
100      */
101     private static final String CERTSTORE_TYPE = "certstore.type";
102     private CertStoreSpi storeSpi;
103     private Provider provider;
104     private String type;
105     private CertStoreParameters params;
106 
107     /**
108      * Creates a {@code CertStore} object of the given type, and
109      * encapsulates the given provider implementation (SPI object) in it.
110      *
111      * @param storeSpi the provider implementation
112      * @param provider the provider
113      * @param type the type
114      * @param params the initialization parameters (may be {@code null})
115      */
CertStore(CertStoreSpi storeSpi, Provider provider, String type, CertStoreParameters params)116     protected CertStore(CertStoreSpi storeSpi, Provider provider,
117                         String type, CertStoreParameters params) {
118         this.storeSpi = storeSpi;
119         this.provider = provider;
120         this.type = type;
121         if (params != null)
122             this.params = (CertStoreParameters) params.clone();
123     }
124 
125     /**
126      * Returns a {@code Collection} of {@code Certificate}s that
127      * match the specified selector. If no {@code Certificate}s
128      * match the selector, an empty {@code Collection} will be returned.
129      * <p>
130      * For some {@code CertStore} types, the resulting
131      * {@code Collection} may not contain <b>all</b> of the
132      * {@code Certificate}s that match the selector. For instance,
133      * an LDAP {@code CertStore} may not search all entries in the
134      * directory. Instead, it may just search entries that are likely to
135      * contain the {@code Certificate}s it is looking for.
136      * <p>
137      * Some {@code CertStore} implementations (especially LDAP
138      * {@code CertStore}s) may throw a {@code CertStoreException}
139      * unless a non-null {@code CertSelector} is provided that
140      * includes specific criteria that can be used to find the certificates.
141      * Issuer and/or subject names are especially useful criteria.
142      *
143      * @param selector A {@code CertSelector} used to select which
144      *  {@code Certificate}s should be returned. Specify {@code null}
145      *  to return all {@code Certificate}s (if supported).
146      * @return A {@code Collection} of {@code Certificate}s that
147      *         match the specified selector (never {@code null})
148      * @throws CertStoreException if an exception occurs
149      */
getCertificates(CertSelector selector)150     public final Collection<? extends Certificate> getCertificates
151             (CertSelector selector) throws CertStoreException {
152         return storeSpi.engineGetCertificates(selector);
153     }
154 
155     /**
156      * Returns a {@code Collection} of {@code CRL}s that
157      * match the specified selector. If no {@code CRL}s
158      * match the selector, an empty {@code Collection} will be returned.
159      * <p>
160      * For some {@code CertStore} types, the resulting
161      * {@code Collection} may not contain <b>all</b> of the
162      * {@code CRL}s that match the selector. For instance,
163      * an LDAP {@code CertStore} may not search all entries in the
164      * directory. Instead, it may just search entries that are likely to
165      * contain the {@code CRL}s it is looking for.
166      * <p>
167      * Some {@code CertStore} implementations (especially LDAP
168      * {@code CertStore}s) may throw a {@code CertStoreException}
169      * unless a non-null {@code CRLSelector} is provided that
170      * includes specific criteria that can be used to find the CRLs.
171      * Issuer names and/or the certificate to be checked are especially useful.
172      *
173      * @param selector A {@code CRLSelector} used to select which
174      *  {@code CRL}s should be returned. Specify {@code null}
175      *  to return all {@code CRL}s (if supported).
176      * @return A {@code Collection} of {@code CRL}s that
177      *         match the specified selector (never {@code null})
178      * @throws CertStoreException if an exception occurs
179      */
getCRLs(CRLSelector selector)180     public final Collection<? extends CRL> getCRLs(CRLSelector selector)
181             throws CertStoreException {
182         return storeSpi.engineGetCRLs(selector);
183     }
184 
185     /**
186      * Returns a {@code CertStore} object that implements the specified
187      * {@code CertStore} type and is initialized with the specified
188      * parameters.
189      *
190      * <p> This method traverses the list of registered security Providers,
191      * starting with the most preferred Provider.
192      * A new CertStore object encapsulating the
193      * CertStoreSpi implementation from the first
194      * Provider that supports the specified type is returned.
195      *
196      * <p> Note that the list of registered providers may be retrieved via
197      * the {@link Security#getProviders() Security.getProviders()} method.
198      *
199      * <p>The {@code CertStore} that is returned is initialized with the
200      * specified {@code CertStoreParameters}. The type of parameters
201      * needed may vary between different types of {@code CertStore}s.
202      * Note that the specified {@code CertStoreParameters} object is
203      * cloned.
204      *
205      * @implNote
206      * The JDK Reference Implementation additionally uses the
207      * {@code jdk.security.provider.preferred}
208      * {@link Security#getProperty(String) Security} property to determine
209      * the preferred provider order for the specified algorithm. This
210      * may be different than the order of providers returned by
211      * {@link Security#getProviders() Security.getProviders()}.
212      *
213      * @param type the name of the requested {@code CertStore} type.
214      * See the CertStore section in the <a href=
215      * "{@docRoot}/../specs/security/standard-names.html#certstore-types">
216      * Java Security Standard Algorithm Names Specification</a>
217      * for information about standard types.
218      *
219      * @param params the initialization parameters (may be {@code null}).
220      *
221      * @return a {@code CertStore} object that implements the specified
222      *          {@code CertStore} type
223      *
224      * @throws InvalidAlgorithmParameterException if the specified
225      *         initialization parameters are inappropriate for this
226      *         {@code CertStore}
227      *
228      * @throws NoSuchAlgorithmException if no {@code Provider} supports a
229      *         {@code CertStoreSpi} implementation for the specified type
230      *
231      * @throws NullPointerException if {@code type} is {@code null}
232      *
233      * @see java.security.Provider
234      */
getInstance(String type, CertStoreParameters params)235     public static CertStore getInstance(String type, CertStoreParameters params)
236             throws InvalidAlgorithmParameterException,
237             NoSuchAlgorithmException {
238         Objects.requireNonNull(type, "null type name");
239         try {
240             Instance instance = GetInstance.getInstance("CertStore",
241                 CertStoreSpi.class, type, params);
242             return new CertStore((CertStoreSpi)instance.impl,
243                 instance.provider, type, params);
244         } catch (NoSuchAlgorithmException e) {
245             return handleException(e);
246         }
247     }
248 
handleException(NoSuchAlgorithmException e)249     private static CertStore handleException(NoSuchAlgorithmException e)
250             throws NoSuchAlgorithmException,
251             InvalidAlgorithmParameterException {
252         Throwable cause = e.getCause();
253         if (cause instanceof InvalidAlgorithmParameterException) {
254             throw (InvalidAlgorithmParameterException)cause;
255         }
256         throw e;
257     }
258 
259     /**
260      * Returns a {@code CertStore} object that implements the specified
261      * {@code CertStore} type.
262      *
263      * <p> A new CertStore object encapsulating the
264      * CertStoreSpi implementation from the specified provider
265      * is returned.  The specified provider must be registered
266      * in the security provider list.
267      *
268      * <p> Note that the list of registered providers may be retrieved via
269      * the {@link Security#getProviders() Security.getProviders()} method.
270      *
271      * <p>The {@code CertStore} that is returned is initialized with the
272      * specified {@code CertStoreParameters}. The type of parameters
273      * needed may vary between different types of {@code CertStore}s.
274      * Note that the specified {@code CertStoreParameters} object is
275      * cloned.
276      *
277      * @param type the requested {@code CertStore} type.
278      * See the CertStore section in the <a href=
279      * "{@docRoot}/../specs/security/standard-names.html#certstore-types">
280      * Java Security Standard Algorithm Names Specification</a>
281      * for information about standard types.
282      *
283      * @param params the initialization parameters (may be {@code null}).
284      *
285      * @param provider the name of the provider.
286      *
287      * @return a {@code CertStore} object that implements the
288      *          specified type
289      *
290      * @throws IllegalArgumentException if the {@code provider} is
291      *         {@code null} or empty
292      *
293      * @throws InvalidAlgorithmParameterException if the specified
294      *         initialization parameters are inappropriate for this
295      *         {@code CertStore}
296      *
297      * @throws NoSuchAlgorithmException if a {@code CertStoreSpi}
298      *         implementation for the specified type is not
299      *         available from the specified provider
300      *
301      * @throws NoSuchProviderException if the specified provider is not
302      *         registered in the security provider list
303      *
304      * @throws NullPointerException if {@code type} is {@code null}
305      *
306      * @see java.security.Provider
307      */
getInstance(String type, CertStoreParameters params, String provider)308     public static CertStore getInstance(String type,
309             CertStoreParameters params, String provider)
310             throws InvalidAlgorithmParameterException,
311             NoSuchAlgorithmException, NoSuchProviderException {
312         Objects.requireNonNull(type, "null type name");
313         try {
314             Instance instance = GetInstance.getInstance("CertStore",
315                 CertStoreSpi.class, type, params, provider);
316             return new CertStore((CertStoreSpi)instance.impl,
317                 instance.provider, type, params);
318         } catch (NoSuchAlgorithmException e) {
319             return handleException(e);
320         }
321     }
322 
323     /**
324      * Returns a {@code CertStore} object that implements the specified
325      * {@code CertStore} type.
326      *
327      * <p> A new CertStore object encapsulating the
328      * CertStoreSpi implementation from the specified Provider
329      * object is returned.  Note that the specified Provider object
330      * does not have to be registered in the provider list.
331      *
332      * <p>The {@code CertStore} that is returned is initialized with the
333      * specified {@code CertStoreParameters}. The type of parameters
334      * needed may vary between different types of {@code CertStore}s.
335      * Note that the specified {@code CertStoreParameters} object is
336      * cloned.
337      *
338      * @param type the requested {@code CertStore} type.
339      * See the CertStore section in the <a href=
340      * "{@docRoot}/../specs/security/standard-names.html#certstore-types">
341      * Java Security Standard Algorithm Names Specification</a>
342      * for information about standard types.
343      *
344      * @param params the initialization parameters (may be {@code null}).
345      *
346      * @param provider the provider.
347      *
348      * @return a {@code CertStore} object that implements the
349      *          specified type
350      *
351      * @throws IllegalArgumentException if the {@code provider} is
352      *         null
353      *
354      * @throws InvalidAlgorithmParameterException if the specified
355      *         initialization parameters are inappropriate for this
356      *         {@code CertStore}
357      *
358      * @throws NoSuchAlgorithmException if a {@code CertStoreSpi}
359      *         implementation for the specified type is not available
360      *         from the specified Provider object
361      *
362      * @throws NullPointerException if {@code type} is {@code null}
363      *
364      * @see java.security.Provider
365      */
getInstance(String type, CertStoreParameters params, Provider provider)366     public static CertStore getInstance(String type, CertStoreParameters params,
367             Provider provider) throws NoSuchAlgorithmException,
368             InvalidAlgorithmParameterException {
369         Objects.requireNonNull(type, "null type name");
370         try {
371             Instance instance = GetInstance.getInstance("CertStore",
372                 CertStoreSpi.class, type, params, provider);
373             return new CertStore((CertStoreSpi)instance.impl,
374                 instance.provider, type, params);
375         } catch (NoSuchAlgorithmException e) {
376             return handleException(e);
377         }
378     }
379 
380     /**
381      * Returns the parameters used to initialize this {@code CertStore}.
382      * Note that the {@code CertStoreParameters} object is cloned before
383      * it is returned.
384      *
385      * @return the parameters used to initialize this {@code CertStore}
386      * (may be {@code null})
387      */
getCertStoreParameters()388     public final CertStoreParameters getCertStoreParameters() {
389         return (params == null ? null : (CertStoreParameters) params.clone());
390     }
391 
392     /**
393      * Returns the type of this {@code CertStore}.
394      *
395      * @return the type of this {@code CertStore}
396      */
getType()397     public final String getType() {
398         return this.type;
399     }
400 
401     /**
402      * Returns the provider of this {@code CertStore}.
403      *
404      * @return the provider of this {@code CertStore}
405      */
getProvider()406     public final Provider getProvider() {
407         return this.provider;
408     }
409 
410     /**
411      * Returns the default {@code CertStore} type as specified by the
412      * {@code certstore.type} security property, or the string
413      * {@literal "LDAP"} if no such property exists.
414      *
415      * <p>The default {@code CertStore} type can be used by applications
416      * that do not want to use a hard-coded type when calling one of the
417      * {@code getInstance} methods, and want to provide a default
418      * {@code CertStore} type in case a user does not specify its own.
419      *
420      * <p>The default {@code CertStore} type can be changed by setting
421      * the value of the {@code certstore.type} security property to the
422      * desired type.
423      *
424      * @see java.security.Security security properties
425      * @return the default {@code CertStore} type as specified by the
426      * {@code certstore.type} security property, or the string
427      * {@literal "LDAP"} if no such property exists.
428      */
429     @SuppressWarnings("removal")
getDefaultType()430     public static final String getDefaultType() {
431         String cstype;
432         cstype = AccessController.doPrivileged(new PrivilegedAction<>() {
433             public String run() {
434                 return Security.getProperty(CERTSTORE_TYPE);
435             }
436         });
437         if (cstype == null) {
438             cstype = "LDAP";
439         }
440         return cstype;
441     }
442 }
443