1. /*
  2. * @(#)CertPathValidator.java 1.6 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 sun.security.util.Debug;
  16. import java.lang.reflect.Method;
  17. import java.lang.reflect.InvocationTargetException;
  18. /**
  19. * A class for validating certification paths (also known as certificate
  20. * chains).
  21. * <p>
  22. * This class uses a provider-based architecture, as described in the Java
  23. * Cryptography Architecture. To create a <code>CertPathValidator</code>,
  24. * call one of the static <code>getInstance</code> methods, passing in the
  25. * algorithm name of the <code>CertPathValidator</code> desired and
  26. * optionally the name of the provider desired.
  27. * <p>
  28. * Once a <code>CertPathValidator</code> object has been created, it can
  29. * be used to validate certification paths by calling the {@link #validate
  30. * validate} method and passing it the <code>CertPath</code> to be validated
  31. * and an algorithm-specific set of parameters. If successful, the result is
  32. * returned in an object that implements the
  33. * <code>CertPathValidatorResult</code> interface.
  34. * <p>
  35. * <b>Concurrent Access</b>
  36. * <p>
  37. * The static methods of this class are guaranteed to be thread-safe.
  38. * Multiple threads may concurrently invoke the static methods defined in
  39. * this class with no ill effects.
  40. * <p>
  41. * However, this is not true for the non-static methods defined by this class.
  42. * Unless otherwise documented by a specific provider, threads that need to
  43. * access a single <code>CertPathValidator</code> instance concurrently should
  44. * synchronize amongst themselves and provide the necessary locking. Multiple
  45. * threads each manipulating a different <code>CertPathValidator</code>
  46. * instance need not synchronize.
  47. *
  48. * @see CertPath
  49. *
  50. * @version 1.6 01/23/03
  51. * @since 1.4
  52. * @author Yassir Elley
  53. */
  54. public class CertPathValidator {
  55. /*
  56. * Constant to lookup in the Security properties file to determine
  57. * the default certpathvalidator type. In the Security properties file,
  58. * the default certpathvalidator type is given as:
  59. * <pre>
  60. * certpathvalidator.type=PKIX
  61. * </pre>
  62. */
  63. private static final String CPV_TYPE = "certpathvalidator.type";
  64. private static final Debug debug = Debug.getInstance("certpath");
  65. private CertPathValidatorSpi validatorSpi;
  66. private Provider provider;
  67. private String algorithm;
  68. // for use with the reflection API
  69. private static final Class cl = java.security.Security.class;
  70. private static final Class[] GET_IMPL_PARAMS = { String.class,
  71. String.class,
  72. String.class };
  73. private static final Class[] GET_IMPL_PARAMS2 = { String.class,
  74. String.class,
  75. Provider.class };
  76. // Get the implMethod via the name of a provider. Note: the name could
  77. // be null.
  78. private static Method implMethod;
  79. // Get the implMethod2 via a Provider object.
  80. private static Method implMethod2;
  81. private static Boolean implMethod2Set = new Boolean(false);
  82. static {
  83. implMethod = (Method)
  84. AccessController.doPrivileged(new PrivilegedAction() {
  85. public Object run() {
  86. Method m = null;
  87. try {
  88. m = cl.getDeclaredMethod("getImpl", GET_IMPL_PARAMS);
  89. if (m != null)
  90. m.setAccessible(true);
  91. } catch (NoSuchMethodException nsme) {
  92. }
  93. return m;
  94. }
  95. });
  96. }
  97. /**
  98. * Creates a <code>CertPathValidator</code> object of the given algorithm,
  99. * and encapsulates the given provider implementation (SPI object) in it.
  100. *
  101. * @param validatorSpi the provider implementation
  102. * @param provider the provider
  103. * @param algorithm the algorithm name
  104. */
  105. protected CertPathValidator(CertPathValidatorSpi validatorSpi,
  106. Provider provider, String algorithm)
  107. {
  108. this.validatorSpi = validatorSpi;
  109. this.provider = provider;
  110. this.algorithm = algorithm;
  111. }
  112. /**
  113. * Returns a <code>CertPathValidator</code> object that implements the
  114. * specified algorithm.
  115. *
  116. * <p> If the default provider package provides an implementation of the
  117. * specified <code>CertPathValidator</code> algorithm, an instance of
  118. * <code>CertPathValidator</code> containing that implementation is
  119. * returned. If the requested algorithm is not available in the default
  120. * package, other packages are searched.
  121. *
  122. * @param algorithm the name of the requested <code>CertPathValidator</code>
  123. * algorithm
  124. * @return a <code>CertPathValidator</code> object that implements the
  125. * specified algorithm
  126. * @exception NoSuchAlgorithmException if the requested algorithm
  127. * is not available in the default provider package or any of the other
  128. * provider packages that were searched
  129. */
  130. public static CertPathValidator getInstance(String algorithm)
  131. throws NoSuchAlgorithmException
  132. {
  133. try {
  134. if (implMethod == null) {
  135. throw new NoSuchAlgorithmException(algorithm + " not found");
  136. }
  137. // The underlying method is static, so we set the object
  138. // argument to null.
  139. Object[] objs = (Object[])implMethod.invoke(null,
  140. new Object[]
  141. { algorithm,
  142. "CertPathValidator",
  143. (String)null
  144. } );
  145. return new CertPathValidator((CertPathValidatorSpi)objs[0],
  146. (Provider)objs[1], algorithm);
  147. } catch (IllegalAccessException iae) {
  148. NoSuchAlgorithmException nsae = new
  149. NoSuchAlgorithmException(algorithm + " not found");
  150. nsae.initCause(iae);
  151. throw nsae;
  152. } catch (InvocationTargetException ite) {
  153. Throwable t = ite.getCause();
  154. if (t != null && t instanceof NoSuchAlgorithmException)
  155. throw (NoSuchAlgorithmException)t;
  156. NoSuchAlgorithmException nsae = new
  157. NoSuchAlgorithmException(algorithm + " not found");
  158. nsae.initCause(ite);
  159. throw nsae;
  160. }
  161. }
  162. /**
  163. * Returns a <code>CertPathValidator</code> object that implements the
  164. * specified algorithm, as supplied by the specified provider.
  165. *
  166. * @param algorithm the name of the requested <code>CertPathValidator</code>
  167. * algorithm
  168. * @param provider the name of the provider
  169. * @return a <code>CertPathValidator</code> object that implements the
  170. * specified algorithm, as supplied by the specified provider
  171. * @exception NoSuchAlgorithmException if the requested algorithm
  172. * is not available from the specified provider
  173. * @exception NoSuchProviderException if the provider has not been
  174. * configured
  175. * @exception IllegalArgumentException if the <code>provider</code> is
  176. * null
  177. */
  178. public static CertPathValidator getInstance(String algorithm,
  179. String provider)
  180. throws NoSuchAlgorithmException, NoSuchProviderException
  181. {
  182. if (provider == null || provider.length() == 0)
  183. throw new IllegalArgumentException("missing provider");
  184. try {
  185. if (implMethod == null) {
  186. throw new NoSuchAlgorithmException(algorithm + " not found");
  187. }
  188. // The underlying method is static, so we set the object
  189. // argument to null.
  190. Object[] objs = (Object[])implMethod.invoke(null,
  191. new Object[]
  192. { algorithm,
  193. "CertPathValidator",
  194. provider
  195. } );
  196. return new CertPathValidator((CertPathValidatorSpi)objs[0],
  197. (Provider)objs[1], algorithm);
  198. } catch (IllegalAccessException iae) {
  199. NoSuchAlgorithmException nsae = new
  200. NoSuchAlgorithmException(algorithm + " not found");
  201. nsae.initCause(iae);
  202. throw nsae;
  203. } catch (InvocationTargetException ite) {
  204. Throwable t = ite.getTargetException();
  205. if (t != null) {
  206. if (t instanceof NoSuchProviderException)
  207. throw (NoSuchProviderException)t;
  208. if (t instanceof NoSuchAlgorithmException)
  209. throw (NoSuchAlgorithmException)t;
  210. }
  211. NoSuchAlgorithmException nsae = new
  212. NoSuchAlgorithmException(algorithm + " not found");
  213. nsae.initCause(ite);
  214. throw nsae;
  215. }
  216. }
  217. /**
  218. * Returns a <code>CertPathValidator</code> object that implements the
  219. * specified algorithm, as supplied by the specified provider.
  220. * Note: the <code>provider</code> doesn't have to be registered.
  221. *
  222. * @param algorithm the name of the requested
  223. * <code>CertPathValidator</code> algorithm
  224. * @param provider the provider
  225. * @return a <code>CertPathValidator</code> object that implements the
  226. * specified algorithm, as supplied by the specified provider
  227. * @exception NoSuchAlgorithmException if the requested algorithm
  228. * is not available from the specified provider
  229. * @exception IllegalArgumentException if the <code>provider</code> is
  230. * null
  231. */
  232. public static CertPathValidator getInstance(String algorithm,
  233. Provider provider)
  234. throws NoSuchAlgorithmException
  235. {
  236. if (provider == null)
  237. throw new IllegalArgumentException("missing provider");
  238. if (implMethod2Set.booleanValue() == false) {
  239. synchronized (implMethod2Set) {
  240. if (implMethod2Set.booleanValue() == false) {
  241. implMethod2 = (Method)
  242. AccessController.doPrivileged(
  243. new PrivilegedAction() {
  244. public Object run() {
  245. Method m = null;
  246. try {
  247. m = cl.getDeclaredMethod("getImpl",
  248. GET_IMPL_PARAMS2);
  249. if (m != null)
  250. m.setAccessible(true);
  251. } catch (NoSuchMethodException nsme) {
  252. if (debug != null)
  253. debug.println("CertPathValidator." +
  254. "getInstance(): Cannot find " +
  255. "Security.getImpl(String, " +
  256. "String, Provider)");
  257. }
  258. return m;
  259. }
  260. });
  261. implMethod2Set = new Boolean(true);
  262. }
  263. }
  264. }
  265. if (implMethod2 == null) {
  266. throw new NoSuchAlgorithmException(algorithm +
  267. " not found");
  268. }
  269. try {
  270. // The underlying method is static, so we set the object
  271. // argument to null.
  272. Object[] objs = (Object[])implMethod2.invoke(null,
  273. new Object[]
  274. { algorithm,
  275. "CertPathValidator",
  276. provider
  277. } );
  278. return new CertPathValidator((CertPathValidatorSpi)objs[0],
  279. (Provider)objs[1], algorithm);
  280. } catch (IllegalAccessException iae) {
  281. NoSuchAlgorithmException nsae = new
  282. NoSuchAlgorithmException(algorithm + " not found");
  283. nsae.initCause(iae);
  284. throw nsae;
  285. } catch (InvocationTargetException ite) {
  286. Throwable t = ite.getCause();
  287. if (t != null && t instanceof NoSuchAlgorithmException)
  288. throw (NoSuchAlgorithmException)t;
  289. NoSuchAlgorithmException nsae = new
  290. NoSuchAlgorithmException(algorithm + " not found");
  291. nsae.initCause(ite);
  292. throw nsae;
  293. }
  294. }
  295. /**
  296. * Returns the <code>Provider</code> of this
  297. * <code>CertPathValidator</code>.
  298. *
  299. * @return the <code>Provider</code> of this <code>CertPathValidator</code>
  300. */
  301. public final Provider getProvider() {
  302. return this.provider;
  303. }
  304. /**
  305. * Returns the algorithm name of this <code>CertPathValidator</code>.
  306. *
  307. * @return the algorithm name of this <code>CertPathValidator</code>
  308. */
  309. public final String getAlgorithm() {
  310. return this.algorithm;
  311. }
  312. /**
  313. * Validates the specified certification path using the specified
  314. * algorithm parameter set.
  315. * <p>
  316. * The <code>CertPath</code> specified must be of a type that is
  317. * supported by the validation algorithm, otherwise an
  318. * <code>InvalidAlgorithmParameterException</code> will be thrown. For
  319. * example, a <code>CertPathValidator</code> that implements the PKIX
  320. * algorithm validates <code>CertPath</code> objects of type X.509.
  321. *
  322. * @param certPath the <code>CertPath</code> to be validated
  323. * @param params the algorithm parameters
  324. * @return the result of the validation algorithm
  325. * @exception CertPathValidatorException if the <code>CertPath</code>
  326. * does not validate
  327. * @exception InvalidAlgorithmParameterException if the specified
  328. * parameters or the type of the specified <code>CertPath</code> are
  329. * inappropriate for this <code>CertPathValidator</code>
  330. */
  331. public final CertPathValidatorResult validate(CertPath certPath,
  332. CertPathParameters params)
  333. throws CertPathValidatorException, InvalidAlgorithmParameterException
  334. {
  335. return validatorSpi.engineValidate(certPath, params);
  336. }
  337. /**
  338. * Returns the default <code>CertPathValidator</code> type as specified in
  339. * the Java security properties file, or the string "PKIX"
  340. * if no such property exists. The Java security properties file is
  341. * located in the file named <JAVA_HOME>/lib/security/java.security,
  342. * where <JAVA_HOME> refers to the directory where the SDK was
  343. * installed.
  344. *
  345. * <p>The default <code>CertPathValidator</code> type can be used by
  346. * applications that do not want to use a hard-coded type when calling one
  347. * of the <code>getInstance</code> methods, and want to provide a default
  348. * type in case a user does not specify its own.
  349. *
  350. * <p>The default <code>CertPathValidator</code> type can be changed by
  351. * setting the value of the "certpathvalidator.type" security property
  352. * (in the Java security properties file) to the desired type.
  353. *
  354. * @return the default <code>CertPathValidator</code> type as specified
  355. * in the Java security properties file, or the string "PKIX"
  356. * if no such property exists.
  357. */
  358. public final static String getDefaultType() {
  359. String cpvtype;
  360. cpvtype = (String)AccessController.doPrivileged(new PrivilegedAction() {
  361. public Object run() {
  362. return Security.getProperty(CPV_TYPE);
  363. }
  364. });
  365. if (cpvtype == null) {
  366. cpvtype = "PKIX";
  367. }
  368. return cpvtype;
  369. }
  370. }