1. /*
  2. * @(#)CertStore.java 1.9 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.security.cert;
  8. import java.security.AccessController;
  9. import java.security.InvalidAlgorithmParameterException;
  10. import java.security.NoSuchAlgorithmException;
  11. import java.security.NoSuchProviderException;
  12. import java.security.PrivilegedAction;
  13. import java.security.Provider;
  14. import java.security.Security;
  15. import java.util.Collection;
  16. import java.lang.reflect.Method;
  17. import java.lang.reflect.InvocationTargetException;
  18. /**
  19. * A class for retrieving <code>Certificate</code>s and <code>CRL</code>s
  20. * from a repository.
  21. * <p>
  22. * This class uses a provider-based architecture, as described in the
  23. * Java Cryptography Architecture.
  24. * To create a <code>CertStore</code>, call one of the static
  25. * <code>getInstance</code> methods, passing in the type of
  26. * <code>CertStore</code> desired, any applicable initialization parameters
  27. * and optionally the name of the provider desired.
  28. * <p>
  29. * Once the <code>CertStore</code> has been created, it can be used to
  30. * retrieve <code>Certificate</code>s and <code>CRL</code>s by calling its
  31. * {@link #getCertificates(CertSelector selector) getCertificates} and
  32. * {@link #getCRLs(CRLSelector selector) getCRLs} methods.
  33. * <p>
  34. * Unlike a {@link java.security.KeyStore KeyStore}, which provides access
  35. * to a cache of private keys and trusted certificates, a
  36. * <code>CertStore</code> is designed to provide access to a potentially
  37. * vast repository of untrusted certificates and CRLs. For example, an LDAP
  38. * implementation of <code>CertStore</code> provides access to certificates
  39. * and CRLs stored in one or more directories using the LDAP protocol and the
  40. * schema as defined in the RFC service attribute. See Appendix A in the
  41. * <a href= "../../../../guide/security/certpath/CertPathProgGuide.html#AppA">
  42. * Java Certification Path API Programmer's Guide</a> for more information about
  43. * standard <code>CertStore</code> types.
  44. * <p>
  45. * <b>Concurrent Access</b>
  46. * <p>
  47. * All public methods of <code>CertStore</code> objects must be thread-safe.
  48. * That is, multiple threads may concurrently invoke these methods on a
  49. * single <code>CertStore</code> object (or more than one) with no
  50. * ill effects. This allows a <code>CertPathBuilder</code> to search for a
  51. * CRL while simultaneously searching for further certificates, for instance.
  52. * <p>
  53. * The static methods of this class are also guaranteed to be thread-safe.
  54. * Multiple threads may concurrently invoke the static methods defined in
  55. * this class with no ill effects.
  56. *
  57. * @version 1.9 01/23/03
  58. * @since 1.4
  59. * @author Sean Mullan, Steve Hanna
  60. */
  61. public class CertStore {
  62. /*
  63. * Constant to lookup in the Security properties file to determine
  64. * the default certstore type. In the Security properties file, the
  65. * default certstore type is given as:
  66. * <pre>
  67. * certstore.type=LDAP
  68. * </pre>
  69. */
  70. private static final String CERTSTORE_TYPE = "certstore.type";
  71. private CertStoreSpi storeSpi;
  72. private Provider provider;
  73. private String type;
  74. private CertStoreParameters params;
  75. // for use with the reflection API
  76. private static final Class cl = java.security.Security.class;
  77. private static final Class[] GET_IMPL_PARAMS = { String.class,
  78. String.class,
  79. String.class,
  80. Object.class };
  81. private static final Class[] GET_IMPL_PARAMS2 = { String.class,
  82. String.class,
  83. Provider.class,
  84. Object.class };
  85. // Get the implMethod via the name of a provider. Note: the name could
  86. // be null.
  87. private static Method implMethod;
  88. // Get the implMethod2 via a Provider object.
  89. private static Method implMethod2;
  90. private static Boolean implMethod2Set = new Boolean(false);
  91. static {
  92. implMethod = (Method)
  93. AccessController.doPrivileged(new PrivilegedAction() {
  94. public Object run() {
  95. Method m = null;
  96. try {
  97. m = cl.getDeclaredMethod("getImpl", GET_IMPL_PARAMS);
  98. if (m != null)
  99. m.setAccessible(true);
  100. } catch (NoSuchMethodException nsme) {
  101. }
  102. return m;
  103. }
  104. });
  105. }
  106. /**
  107. * Creates a <code>CertStore</code> object of the given type, and
  108. * encapsulates the given provider implementation (SPI object) in it.
  109. *
  110. * @param storeSpi the provider implementation
  111. * @param provider the provider
  112. * @param type the type
  113. * @param params the initialization parameters (may be <code>null</code>)
  114. */
  115. protected CertStore(CertStoreSpi storeSpi, Provider provider,
  116. String type, CertStoreParameters params) {
  117. this.storeSpi = storeSpi;
  118. this.provider = provider;
  119. this.type = type;
  120. if (params != null)
  121. this.params = (CertStoreParameters) params.clone();
  122. }
  123. /**
  124. * Returns a <code>Collection</code> of <code>Certificate</code>s that
  125. * match the specified selector. If no <code>Certificate</code>s
  126. * match the selector, an empty <code>Collection</code> will be returned.
  127. * <p>
  128. * For some <code>CertStore</code> types, the resulting
  129. * <code>Collection</code> may not contain <b>all</b> of the
  130. * <code>Certificate</code>s that match the selector. For instance,
  131. * an LDAP <code>CertStore</code> may not search all entries in the
  132. * directory. Instead, it may just search entries that are likely to
  133. * contain the <code>Certificate</code>s it is looking for.
  134. * <p>
  135. * Some <code>CertStore</code> implementations (especially LDAP
  136. * <code>CertStore</code>s) may throw a <code>CertStoreException</code>
  137. * unless a non-null <code>CertSelector</code> is provided that
  138. * includes specific criteria that can be used to find the certificates.
  139. * Issuer and/or subject names are especially useful criteria.
  140. *
  141. * @param selector A <code>CertSelector</code> used to select which
  142. * <code>Certificate</code>s should be returned. Specify <code>null</code>
  143. * to return all <code>Certificate</code>s (if supported).
  144. * @return A <code>Collection</code> of <code>Certificate</code>s that
  145. * match the specified selector (never <code>null</code>)
  146. * @throws CertStoreException if an exception occurs
  147. */
  148. public final Collection getCertificates(CertSelector selector)
  149. throws CertStoreException
  150. {
  151. return(storeSpi.engineGetCertificates(selector));
  152. }
  153. /**
  154. * Returns a <code>Collection</code> of <code>CRL</code>s that
  155. * match the specified selector. If no <code>CRL</code>s
  156. * match the selector, an empty <code>Collection</code> will be returned.
  157. * <p>
  158. * For some <code>CertStore</code> types, the resulting
  159. * <code>Collection</code> may not contain <b>all</b> of the
  160. * <code>CRL</code>s that match the selector. For instance,
  161. * an LDAP <code>CertStore</code> may not search all entries in the
  162. * directory. Instead, it may just search entries that are likely to
  163. * contain the <code>CRL</code>s it is looking for.
  164. * <p>
  165. * Some <code>CertStore</code> implementations (especially LDAP
  166. * <code>CertStore</code>s) may throw a <code>CertStoreException</code>
  167. * unless a non-null <code>CRLSelector</code> is provided that
  168. * includes specific criteria that can be used to find the CRLs.
  169. * Issuer names and/or the certificate to be checked are especially useful.
  170. *
  171. * @param selector A <code>CRLSelector</code> used to select which
  172. * <code>CRL</code>s should be returned. Specify <code>null</code>
  173. * to return all <code>CRL</code>s (if supported).
  174. * @return A <code>Collection</code> of <code>CRL</code>s that
  175. * match the specified selector (never <code>null</code>)
  176. * @throws CertStoreException if an exception occurs
  177. */
  178. public final Collection getCRLs(CRLSelector selector)
  179. throws CertStoreException
  180. {
  181. return(storeSpi.engineGetCRLs(selector));
  182. }
  183. /**
  184. * Returns a <code>CertStore</code> object that implements the specified
  185. * <code>CertStore</code> type and is initialized with the specified
  186. * parameters.
  187. *
  188. * <p>If the default provider package provides an implementation
  189. * of the specified <code>CertStore</code> type, an instance of
  190. * <code>CertStore</code> containing that implementation is returned.
  191. * If the requested type is not available in the default package, other
  192. * packages are searched.
  193. *
  194. * <p>The <code>CertStore</code> that is returned is initialized with the
  195. * specified <code>CertStoreParameters</code>. The type of parameters
  196. * needed may vary between different types of <code>CertStore</code>s.
  197. * Note that the specified <code>CertStoreParameters</code> object is
  198. * cloned.
  199. *
  200. * @param type the name of the requested <code>CertStore</code> type
  201. * @param params the initialization parameters (may be <code>null</code>)
  202. * @return a <code>CertStore</code> object that implements the specified
  203. * <code>CertStore</code> type
  204. * @throws NoSuchAlgorithmException if the requested type is not
  205. * available in the default provider package or any of the other provider
  206. * packages that were searched
  207. * @throws InvalidAlgorithmParameterException if the specified
  208. * initialization parameters are inappropriate for this
  209. * <code>CertStore</code>
  210. */
  211. public static CertStore getInstance(String type, CertStoreParameters params)
  212. throws InvalidAlgorithmParameterException, NoSuchAlgorithmException
  213. {
  214. try {
  215. if (implMethod == null) {
  216. throw new NoSuchAlgorithmException(type + " not found");
  217. }
  218. // The underlying method is static, so we set the object
  219. // argument to null.
  220. Object[] objs = (Object[])implMethod.invoke(null,
  221. new Object[]
  222. { type,
  223. "CertStore",
  224. (String)null,
  225. params
  226. } );
  227. return new CertStore((CertStoreSpi)objs[0],
  228. (Provider)objs[1], type, params);
  229. } catch (IllegalAccessException iae) {
  230. NoSuchAlgorithmException nsae = new
  231. NoSuchAlgorithmException(type + " not found");
  232. nsae.initCause(iae);
  233. throw nsae;
  234. } catch (InvocationTargetException ite) {
  235. Throwable t = ite.getCause();
  236. if (t != null) {
  237. if (t instanceof InvalidAlgorithmParameterException)
  238. throw (InvalidAlgorithmParameterException)t;
  239. if (t instanceof NoSuchAlgorithmException)
  240. throw (NoSuchAlgorithmException)t;
  241. }
  242. NoSuchAlgorithmException nsae = new
  243. NoSuchAlgorithmException(type + " not found");
  244. nsae.initCause(ite);
  245. throw nsae;
  246. }
  247. }
  248. /**
  249. * Returns a <code>CertStore</code> object that implements the specified
  250. * <code>CertStore</code> type, as supplied by the specified provider
  251. * and initialized with the specified parameters.
  252. *
  253. * <p>The <code>CertStore</code> that is returned is initialized with the
  254. * specified <code>CertStoreParameters</code>. The type of parameters
  255. * needed may vary between different types of <code>CertStore</code>s.
  256. * Note that the specified <code>CertStoreParameters</code> object is
  257. * cloned.
  258. *
  259. * @param type the requested <code>CertStore</code> type
  260. * @param params the initialization parameters (may be <code>null</code>)
  261. * @param provider the name of the provider
  262. * @return a <code>CertStore</code> object that implements the
  263. * specified type, as supplied by the specified provider
  264. * @throws NoSuchAlgorithmException if the requested type is not
  265. * available from the specified provider
  266. * @throws InvalidAlgorithmParameterException if the specified
  267. * initialization parameters are inappropriate for this
  268. * <code>CertStore</code>
  269. * @throws NoSuchProviderException if the provider has not been configured
  270. * @exception IllegalArgumentException if the <code>provider</code> is
  271. * null
  272. */
  273. public static CertStore getInstance(String type,
  274. CertStoreParameters params, String provider)
  275. throws InvalidAlgorithmParameterException, NoSuchAlgorithmException,
  276. NoSuchProviderException
  277. {
  278. if (provider == null || provider.length() == 0)
  279. throw new IllegalArgumentException("missing provider");
  280. try {
  281. if (implMethod == null) {
  282. throw new NoSuchAlgorithmException(type + " not found");
  283. }
  284. // The underlying method is static, so we set the object
  285. // argument to null.
  286. Object[] objs = (Object[])implMethod.invoke(null,
  287. new Object[]
  288. { type,
  289. "CertStore",
  290. provider,
  291. params
  292. } );
  293. return new CertStore((CertStoreSpi)objs[0],
  294. (Provider)objs[1], type, params);
  295. } catch (IllegalAccessException iae) {
  296. NoSuchAlgorithmException nsae = new
  297. NoSuchAlgorithmException(type + " not found");
  298. nsae.initCause(iae);
  299. throw nsae;
  300. } catch (InvocationTargetException ite) {
  301. Throwable t = ite.getCause();
  302. if (t != null) {
  303. if (t instanceof NoSuchProviderException)
  304. throw (NoSuchProviderException)t;
  305. if (t instanceof InvalidAlgorithmParameterException)
  306. throw (InvalidAlgorithmParameterException)t;
  307. if (t instanceof NoSuchAlgorithmException)
  308. throw (NoSuchAlgorithmException)t;
  309. }
  310. NoSuchAlgorithmException nsae = new
  311. NoSuchAlgorithmException(type + " not found");
  312. nsae.initCause(ite);
  313. throw nsae;
  314. }
  315. }
  316. /**
  317. * Returns a <code>CertStore</code> object that implements the specified
  318. * <code>CertStore</code> type, as supplied by the specified provider and
  319. * initialized with the specified parameters.
  320. * Note: the <code>provider</code> doesn't have to be registered.
  321. *
  322. * <p>The <code>CertStore</code> that is returned is initialized with the
  323. * specified <code>CertStoreParameters</code>. The type of parameters
  324. * needed may vary between different types of <code>CertStore</code>s.
  325. * Note that the specified <code>CertStoreParameters</code> object is
  326. * cloned.
  327. *
  328. * @param type the requested <code>CertStore</code> type
  329. * @param params the initialization parameters (may be <code>null</code>)
  330. * @param provider the provider
  331. * @return a <code>CertStore</code> object that implements the
  332. * specified type, as supplied by the specified provider
  333. * @exception NoSuchAlgorithmException if the requested type is not
  334. * available from the specified provider
  335. * @throws InvalidAlgorithmParameterException if the specified
  336. * initialization parameters are inappropriate for this
  337. * <code>CertStore</code>
  338. * @exception IllegalArgumentException if the <code>provider</code> is
  339. * null
  340. */
  341. public static CertStore getInstance(String type, CertStoreParameters params,
  342. Provider provider)
  343. throws NoSuchAlgorithmException, InvalidAlgorithmParameterException
  344. {
  345. if (provider == null)
  346. throw new IllegalArgumentException("missing provider");
  347. if (implMethod2Set.booleanValue() == false) {
  348. synchronized (implMethod2Set) {
  349. if (implMethod2Set.booleanValue() == false) {
  350. implMethod2 = (Method)
  351. AccessController.doPrivileged(
  352. new PrivilegedAction() {
  353. public Object run() {
  354. Method m = null;
  355. try {
  356. m = cl.getDeclaredMethod("getImpl",
  357. GET_IMPL_PARAMS2);
  358. if (m != null)
  359. m.setAccessible(true);
  360. } catch (NoSuchMethodException nsme) {
  361. }
  362. return m;
  363. }
  364. });
  365. implMethod2Set = new Boolean(true);
  366. }
  367. }
  368. }
  369. if (implMethod2 == null) {
  370. throw new NoSuchAlgorithmException(type + " not found");
  371. }
  372. try {
  373. // The underlying method is static, so we set the object
  374. // argument to null.
  375. Object[] objs = (Object[])implMethod2.invoke(null,
  376. new Object[]
  377. { type,
  378. "CertStore",
  379. provider,
  380. params
  381. } );
  382. return new CertStore((CertStoreSpi)objs[0],
  383. (Provider)objs[1], type, params);
  384. } catch (IllegalAccessException iae) {
  385. NoSuchAlgorithmException nsae = new
  386. NoSuchAlgorithmException(type + " not found");
  387. nsae.initCause(iae);
  388. throw nsae;
  389. } catch (InvocationTargetException ite) {
  390. Throwable t = ite.getCause();
  391. if (t != null) {
  392. if (t instanceof InvalidAlgorithmParameterException)
  393. throw (InvalidAlgorithmParameterException)t;
  394. if (t instanceof NoSuchAlgorithmException)
  395. throw (NoSuchAlgorithmException)t;
  396. }
  397. NoSuchAlgorithmException nsae = new
  398. NoSuchAlgorithmException(type + " not found");
  399. nsae.initCause(ite);
  400. throw nsae;
  401. }
  402. }
  403. /**
  404. * Returns the parameters used to initialize this <code>CertStore</code>.
  405. * Note that the <code>CertStoreParameters</code> object is cloned before
  406. * it is returned.
  407. *
  408. * @return the parameters used to initialize this <code>CertStore</code>
  409. * (may be <code>null</code>)
  410. */
  411. public final CertStoreParameters getCertStoreParameters() {
  412. return (params == null ? null : (CertStoreParameters) params.clone());
  413. }
  414. /**
  415. * Returns the type of this <code>CertStore</code>.
  416. *
  417. * @return the type of this <code>CertStore</code>
  418. */
  419. public final String getType() {
  420. return this.type;
  421. }
  422. /**
  423. * Returns the provider of this <code>CertStore</code>.
  424. *
  425. * @return the provider of this <code>CertStore</code>
  426. */
  427. public final Provider getProvider() {
  428. return this.provider;
  429. }
  430. /**
  431. * Returns the default <code>CertStore</code> type as specified in the
  432. * Java security properties file, or the string "LDAP" if no
  433. * such property exists. The Java security properties file is located in
  434. * the file named <JAVA_HOME>/lib/security/java.security, where
  435. * <JAVA_HOME> refers to the directory where the SDK was installed.
  436. *
  437. * <p>The default <code>CertStore</code> type can be used by applications
  438. * that do not want to use a hard-coded type when calling one of the
  439. * <code>getInstance</code> methods, and want to provide a default
  440. * <code>CertStore</code> type in case a user does not specify its own.
  441. *
  442. * <p>The default <code>CertStore</code> type can be changed by setting
  443. * the value of the "certstore.type" security property (in the Java
  444. * security properties file) to the desired type.
  445. *
  446. * @return the default <code>CertStore</code> type as specified in the
  447. * Java security properties file, or the string "LDAP"
  448. * if no such property exists.
  449. */
  450. public final static String getDefaultType() {
  451. String cstype;
  452. cstype = (String)AccessController.doPrivileged(new PrivilegedAction() {
  453. public Object run() {
  454. return Security.getProperty(CERTSTORE_TYPE);
  455. }
  456. });
  457. if (cstype == null) {
  458. cstype = "LDAP";
  459. }
  460. return cstype;
  461. }
  462. }