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