1. /*
  2. * @(#)CertificateFactory.java 1.12 01/11/29
  3. *
  4. * Copyright 2002 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.io.InputStream;
  9. import java.util.Collection;
  10. import java.security.Provider;
  11. import java.security.AccessController;
  12. import java.security.PrivilegedAction;
  13. import java.security.NoSuchAlgorithmException;
  14. import java.security.NoSuchProviderException;
  15. import java.lang.reflect.Method;
  16. import java.lang.reflect.InvocationTargetException;
  17. /**
  18. * This class defines the functionality of a certificate factory, which is
  19. * used to generate certificate and certificate revocation list (CRL) objects
  20. * from their encodings.
  21. *
  22. * <p>A certificate factory for X.509 must return certificates that are an
  23. * instance of <code>java.security.cert.X509Certificate</code>, and CRLs
  24. * that are an instance of <code>java.security.cert.X509CRL</code>.
  25. *
  26. * <p>The following example reads a file with Base64 encoded certificates,
  27. * which are each bounded at the beginning by -----BEGIN CERTIFICATE-----, and
  28. * bounded at the end by -----END CERTIFICATE-----. We convert the
  29. * <code>FileInputStream</code> (which does not support <code>mark</code>
  30. * and <code>reset</code>) to a <code>ByteArrayInputStream</code> (which
  31. * supports those methods), so that each call to
  32. * <code>generateCertificate</code> consumes only one certificate, and the
  33. * read position of the input stream is positioned to the next certificate in
  34. * the file:<p>
  35. *
  36. * <pre>
  37. * FileInputStream fis = new FileInputStream(filename);
  38. * DataInputStream dis = new DataInputStream(fis);
  39. *
  40. * CertificateFactory cf = CertificateFactory.getInstance("X.509");
  41. *
  42. * byte[] bytes = new byte[dis.available()];
  43. * dis.readFully(bytes);
  44. * ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
  45. *
  46. * while (bais.available() > 0) {
  47. * Certificate cert = cf.generateCertificate(bais);
  48. * System.out.println(cert.toString());
  49. * }
  50. * </pre>
  51. *
  52. * <p>The following example parses a PKCS#7-formatted certificate reply stored
  53. * in a file and extracts all the certificates from it:<p>
  54. *
  55. * <pre>
  56. * FileInputStream fis = new FileInputStream(filename);
  57. * CertificateFactory cf = CertificateFactory.getInstance("X.509");
  58. * Collection c = cf.generateCertificates(fis);
  59. * Iterator i = c.iterator();
  60. * while (i.hasNext()) {
  61. * Certificate cert = (Certificate)i.next();
  62. * System.out.println(cert);
  63. * }
  64. * </pre>
  65. *
  66. * @author Hemma Prafullchandra
  67. * @author Jan Luehe
  68. *
  69. * @version 1.12
  70. *
  71. * @see Certificate
  72. * @see X509Certificate
  73. * @see CRL
  74. * @see X509CRL
  75. *
  76. * @since JDK1.2
  77. */
  78. public class CertificateFactory {
  79. // for use with the reflection API
  80. private static final Class cl = java.security.Security.class;
  81. private static final Class[] GET_IMPL_PARAMS = { String.class,
  82. String.class,
  83. String.class };
  84. private static Method implMethod;
  85. static {
  86. implMethod = (Method)
  87. AccessController.doPrivileged(new PrivilegedAction() {
  88. public Object run() {
  89. Method m = null;
  90. try {
  91. m = cl.getDeclaredMethod("getImpl", GET_IMPL_PARAMS);
  92. if (m != null)
  93. m.setAccessible(true);
  94. } catch (NoSuchMethodException nsme) {
  95. }
  96. return m;
  97. }
  98. });
  99. }
  100. // The certificate type
  101. private String type;
  102. // The provider
  103. private Provider provider;
  104. // The provider implementation
  105. private CertificateFactorySpi certFacSpi;
  106. /**
  107. * Creates a CertificateFactory object of the given type, and encapsulates
  108. * the given provider implementation (SPI object) in it.
  109. *
  110. * @param certFacSpi the provider implementation.
  111. * @param provider the provider.
  112. * @param type the certificate type.
  113. */
  114. protected CertificateFactory(CertificateFactorySpi certFacSpi,
  115. Provider provider, String type)
  116. {
  117. this.certFacSpi = certFacSpi;
  118. this.provider = provider;
  119. this.type = type;
  120. }
  121. /**
  122. * Generates a certificate factory object that implements the
  123. * specified certificate type. If the default provider package
  124. * provides an implementation of the requested certificate type,
  125. * an instance of certificate factory containing that
  126. * implementation is returned.
  127. * If the type is not available in the default
  128. * package, other packages are searched.
  129. *
  130. * @param type the name of the requested certificate type.
  131. * See Appendix A in the <a href=
  132. * "../../../../guide/security/CryptoSpec.html#AppA">
  133. * Java Cryptography Architecture API Specification & Reference </a>
  134. * for information about standard certificate types.
  135. *
  136. * @return a certificate factory object for the specified type.
  137. *
  138. * @exception CertificateException if the requested certificate type is
  139. * not available in the default provider package or any of the other
  140. * provider packages that were searched.
  141. */
  142. public static final CertificateFactory getInstance(String type)
  143. throws CertificateException
  144. {
  145. try {
  146. if (implMethod == null) {
  147. throw new CertificateException(type + " not found");
  148. }
  149. // The underlying method is static, so we set the object
  150. // argument to null.
  151. Object[] objs = (Object[])implMethod.invoke(null,
  152. new Object[]
  153. { type,
  154. "CertificateFactory",
  155. null
  156. } );
  157. return new CertificateFactory((CertificateFactorySpi)objs[0],
  158. (Provider)objs[1], type);
  159. } catch (IllegalAccessException iae) {
  160. throw new CertificateException(type + " not found");
  161. } catch (InvocationTargetException ite) {
  162. throw new CertificateException(type + " not found");
  163. }
  164. }
  165. /**
  166. * Generates a certificate factory object for the specified
  167. * certificate type from the specified provider.
  168. *
  169. * @param type the certificate type
  170. * @param provider the name of the provider.
  171. *
  172. * @return a certificate factory object for the specified type.
  173. *
  174. * @exception CertificateException if the certificate type is
  175. * not available from the specified provider.
  176. *
  177. * @exception NoSuchProviderException if the provider has not been
  178. * configured.
  179. *
  180. * @see Provider
  181. */
  182. public static final CertificateFactory getInstance(String type,
  183. String provider)
  184. throws CertificateException, NoSuchProviderException
  185. {
  186. if (provider == null || provider.length() == 0)
  187. throw new IllegalArgumentException("missing provider");
  188. try {
  189. if (implMethod == null) {
  190. throw new CertificateException(type + " not found");
  191. }
  192. // The underlying method is static, so we set the object
  193. // argument to null.
  194. Object[] objs = (Object[])implMethod.invoke(null,
  195. new Object[]
  196. { type,
  197. "CertificateFactory",
  198. provider
  199. } );
  200. return new CertificateFactory((CertificateFactorySpi)objs[0],
  201. (Provider)objs[1], type);
  202. } catch (IllegalAccessException iae) {
  203. throw new CertificateException(type + " not found");
  204. } catch (InvocationTargetException ite) {
  205. Throwable t = ite.getTargetException();
  206. if (t!=null && t instanceof NoSuchProviderException) {
  207. throw (NoSuchProviderException)t;
  208. } else {
  209. throw new CertificateException(type + " not found");
  210. }
  211. }
  212. }
  213. /**
  214. * Returns the provider of this certificate factory.
  215. *
  216. * @return the provider of this certificate factory.
  217. */
  218. public final Provider getProvider() {
  219. return this.provider;
  220. }
  221. /**
  222. * Returns the name of the certificate type associated with this
  223. * certificate factory.
  224. *
  225. * @return the name of the certificate type associated with this
  226. * certificate factory.
  227. */
  228. public final String getType() {
  229. return this.type;
  230. }
  231. /**
  232. * Generates a certificate object and initializes it with
  233. * the data read from the input stream <code>inStream</code>.
  234. *
  235. * <p>The given input stream <code>inStream</code> must contain a single
  236. * certificate.
  237. *
  238. * <p>In order to take advantage of the specialized certificate format
  239. * supported by this certificate factory,
  240. * the returned certificate object can be typecast to the corresponding
  241. * certificate class. For example, if this certificate
  242. * factory implements X.509 certificates, the returned certificate object
  243. * can be typecast to the <code>X509Certificate</code> class.
  244. *
  245. * <p>In the case of a certificate factory for X.509 certificates, the
  246. * certificate provided in <code>inStream</code> must be DER-encoded and
  247. * may be supplied in binary or printable (Base64) encoding. If the
  248. * certificate is provided in Base64 encoding, it must be bounded at
  249. * the beginning by -----BEGIN CERTIFICATE-----, and must be bounded at
  250. * the end by -----END CERTIFICATE-----.
  251. *
  252. * <p>Note that if the given input stream does not support
  253. * {@link java.io.InputStream#mark(int) mark} and
  254. * {@link java.io.InputStream#reset() reset}, this method will
  255. * consume the entire input stream.
  256. *
  257. * @param inStream an input stream with the certificate data.
  258. *
  259. * @return a certificate object initialized with the data
  260. * from the input stream.
  261. *
  262. * @exception CertificateException on parsing errors.
  263. */
  264. public final Certificate generateCertificate(InputStream inStream)
  265. throws CertificateException
  266. {
  267. return certFacSpi.engineGenerateCertificate(inStream);
  268. }
  269. /**
  270. * Returns a (possibly empty) collection view of the certificates read
  271. * from the given input stream <code>inStream</code>.
  272. *
  273. * <p>In order to take advantage of the specialized certificate format
  274. * supported by this certificate factory, each element in
  275. * the returned collection view can be typecast to the corresponding
  276. * certificate class. For example, if this certificate
  277. * factory implements X.509 certificates, the elements in the returned
  278. * collection can be typecast to the <code>X509Certificate</code> class.
  279. *
  280. * <p>In the case of a certificate factory for X.509 certificates,
  281. * <code>inStream</code> may contain a sequence of DER-encoded certificates
  282. * in the formats described for
  283. * {@link #generateCertificate(java.io.InputStream) generateCertificate}.
  284. * In addition, <code>inStream</code> may contain a PKCS#7 certificate
  285. * chain. This is a PKCS#7 <i>SignedData</i> object, with the only
  286. * significant field being <i>certificates</i>. In particular, the
  287. * signature and the contents are ignored. This format allows multiple
  288. * certificates to be downloaded at once. If no certificates are present,
  289. * an empty collection is returned.
  290. *
  291. * <p>Note that if the given input stream does not support
  292. * {@link java.io.InputStream#mark(int) mark} and
  293. * {@link java.io.InputStream#reset() reset}, this method will
  294. * consume the entire input stream.
  295. *
  296. * @param inStream the input stream with the certificates.
  297. *
  298. * @return a (possibly empty) collection view of
  299. * java.security.cert.Certificate objects
  300. * initialized with the data from the input stream.
  301. *
  302. * @exception CertificateException on parsing errors.
  303. */
  304. public final Collection generateCertificates(InputStream inStream)
  305. throws CertificateException
  306. {
  307. return certFacSpi.engineGenerateCertificates(inStream);
  308. }
  309. /**
  310. * Generates a certificate revocation list (CRL) object and initializes it
  311. * with the data read from the input stream <code>inStream</code>.
  312. *
  313. * <p>In order to take advantage of the specialized CRL format
  314. * supported by this certificate factory,
  315. * the returned CRL object can be typecast to the corresponding
  316. * CRL class. For example, if this certificate
  317. * factory implements X.509 CRLs, the returned CRL object
  318. * can be typecast to the <code>X509CRL</code> class.
  319. *
  320. * <p>Note that if the given input stream does not support
  321. * {@link java.io.InputStream#mark(int) mark} and
  322. * {@link java.io.InputStream#reset() reset}, this method will
  323. * consume the entire input stream.
  324. *
  325. * @param inStream an input stream with the CRL data.
  326. *
  327. * @return a CRL object initialized with the data
  328. * from the input stream.
  329. *
  330. * @exception CRLException on parsing errors.
  331. */
  332. public final CRL generateCRL(InputStream inStream)
  333. throws CRLException
  334. {
  335. return certFacSpi.engineGenerateCRL(inStream);
  336. }
  337. /**
  338. * Returns a (possibly empty) collection view of the CRLs read
  339. * from the given input stream <code>inStream</code>.
  340. *
  341. * <p>In order to take advantage of the specialized CRL format
  342. * supported by this certificate factory, each element in
  343. * the returned collection view can be typecast to the corresponding
  344. * CRL class. For example, if this certificate
  345. * factory implements X.509 CRLs, the elements in the returned
  346. * collection can be typecast to the <code>X509CRL</code> class.
  347. *
  348. * <p>In the case of a certificate factory for X.509 CRLs,
  349. * <code>inStream</code> may contain a sequence of DER-encoded CRLs.
  350. * In addition, <code>inStream</code> may contain a PKCS#7 CRL
  351. * set. This is a PKCS#7 <i>SignedData</i> object, with the only
  352. * significant field being <i>crls</i>. In particular, the
  353. * signature and the contents are ignored. This format allows multiple
  354. * CRLs to be downloaded at once. If no CRLs are present,
  355. * an empty collection is returned.
  356. *
  357. * <p>Note that if the given input stream does not support
  358. * {@link java.io.InputStream#mark(int) mark} and
  359. * {@link java.io.InputStream#reset() reset}, this method will
  360. * consume the entire input stream.
  361. *
  362. * @param inStream the input stream with the CRLs.
  363. *
  364. * @return a (possibly empty) collection view of
  365. * java.security.cert.CRL objects initialized with the data from the input
  366. * stream.
  367. *
  368. * @exception CRLException on parsing errors.
  369. */
  370. public final Collection generateCRLs(InputStream inStream)
  371. throws CRLException
  372. {
  373. return certFacSpi.engineGenerateCRLs(inStream);
  374. }
  375. }