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