1. /*
  2. * @(#)CertificateFactory.java 1.24 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.io.InputStream;
  9. import java.util.Collection;
  10. import java.util.Iterator;
  11. import java.util.List;
  12. import java.security.Provider;
  13. import java.security.AccessController;
  14. import java.security.PrivilegedAction;
  15. import java.security.NoSuchAlgorithmException;
  16. import java.security.NoSuchProviderException;
  17. import java.lang.reflect.Method;
  18. import java.lang.reflect.InvocationTargetException;
  19. /**
  20. * This class defines the functionality of a certificate factory, which is
  21. * used to generate certificate, certification path (<code>CertPath</code>)
  22. * and certificate revocation list (CRL) objects from their encodings.
  23. *
  24. * <p>For encodings consisting of multiple certificates, use
  25. * <code>generateCertificates</code> when you want to
  26. * parse a collection of possibly unrelated certificates. Otherwise,
  27. * use <code>generateCertPath</code> when you want to generate
  28. * a <code>CertPath</code> (a certificate chain) and subsequently
  29. * validate it with a <code>CertPathValidator</code>.
  30. *
  31. * <p>A certificate factory for X.509 must return certificates that are an
  32. * instance of <code>java.security.cert.X509Certificate</code>, and CRLs
  33. * that are an instance of <code>java.security.cert.X509CRL</code>.
  34. *
  35. * <p>The following example reads a file with Base64 encoded certificates,
  36. * which are each bounded at the beginning by -----BEGIN CERTIFICATE-----, and
  37. * bounded at the end by -----END CERTIFICATE-----. We convert the
  38. * <code>FileInputStream</code> (which does not support <code>mark</code>
  39. * and <code>reset</code>) to a <code>BufferedInputStream</code> (which
  40. * supports those methods), so that each call to
  41. * <code>generateCertificate</code> consumes only one certificate, and the
  42. * read position of the input stream is positioned to the next certificate in
  43. * the file:<p>
  44. *
  45. * <pre>
  46. * FileInputStream fis = new FileInputStream(filename);
  47. * BufferedInputStream bis = new BufferedInputStream(fis);
  48. *
  49. * CertificateFactory cf = CertificateFactory.getInstance("X.509");
  50. *
  51. * while (bis.available() > 0) {
  52. * Certificate cert = cf.generateCertificate(bis);
  53. * System.out.println(cert.toString());
  54. * }
  55. * </pre>
  56. *
  57. * <p>The following example parses a PKCS#7-formatted certificate reply stored
  58. * in a file and extracts all the certificates from it:<p>
  59. *
  60. * <pre>
  61. * FileInputStream fis = new FileInputStream(filename);
  62. * CertificateFactory cf = CertificateFactory.getInstance("X.509");
  63. * Collection c = cf.generateCertificates(fis);
  64. * Iterator i = c.iterator();
  65. * while (i.hasNext()) {
  66. * Certificate cert = (Certificate)i.next();
  67. * System.out.println(cert);
  68. * }
  69. * </pre>
  70. *
  71. * @author Hemma Prafullchandra
  72. * @author Jan Luehe
  73. * @author Sean Mullan
  74. *
  75. * @version 1.24, 01/23/03
  76. *
  77. * @see Certificate
  78. * @see X509Certificate
  79. * @see CertPath
  80. * @see CRL
  81. * @see X509CRL
  82. *
  83. * @since 1.2
  84. */
  85. public class CertificateFactory {
  86. // for use with the reflection API
  87. private static final Class cl = java.security.Security.class;
  88. private static final Class[] GET_IMPL_PARAMS = { String.class,
  89. String.class,
  90. String.class };
  91. private static final Class[] GET_IMPL_PARAMS2 = { String.class,
  92. String.class,
  93. Provider.class };
  94. // Get the implMethod via the name of a provider. Note: the name could
  95. // be null.
  96. private static Method implMethod;
  97. // Get the implMethod2 via a Provider object.
  98. private static Method implMethod2;
  99. private static Boolean implMethod2Set = new Boolean(false);
  100. static {
  101. implMethod = (Method)
  102. AccessController.doPrivileged(new PrivilegedAction() {
  103. public Object run() {
  104. Method m = null;
  105. try {
  106. m = cl.getDeclaredMethod("getImpl", GET_IMPL_PARAMS);
  107. if (m != null)
  108. m.setAccessible(true);
  109. } catch (NoSuchMethodException nsme) {
  110. }
  111. return m;
  112. }
  113. });
  114. }
  115. // The certificate type
  116. private String type;
  117. // The provider
  118. private Provider provider;
  119. // The provider implementation
  120. private CertificateFactorySpi certFacSpi;
  121. /**
  122. * Creates a CertificateFactory object of the given type, and encapsulates
  123. * the given provider implementation (SPI object) in it.
  124. *
  125. * @param certFacSpi the provider implementation.
  126. * @param provider the provider.
  127. * @param type the certificate type.
  128. */
  129. protected CertificateFactory(CertificateFactorySpi certFacSpi,
  130. Provider provider, String type)
  131. {
  132. this.certFacSpi = certFacSpi;
  133. this.provider = provider;
  134. this.type = type;
  135. }
  136. /**
  137. * Generates a certificate factory object that implements the
  138. * specified certificate type. If the default provider package
  139. * provides an implementation of the requested certificate type,
  140. * an instance of certificate factory containing that
  141. * implementation is returned.
  142. * If the type is not available in the default
  143. * package, other packages are searched.
  144. *
  145. * @param type the name of the requested certificate type.
  146. * See Appendix A in the <a href=
  147. * "../../../../guide/security/CryptoSpec.html#AppA">
  148. * Java Cryptography Architecture API Specification & Reference </a>
  149. * for information about standard certificate types.
  150. *
  151. * @return a certificate factory object for the specified type.
  152. *
  153. * @exception CertificateException if the requested certificate type is
  154. * not available in the default provider package or any of the other
  155. * provider packages that were searched.
  156. */
  157. public static final CertificateFactory getInstance(String type)
  158. throws CertificateException
  159. {
  160. try {
  161. if (implMethod == null) {
  162. throw new CertificateException(type + " not found");
  163. }
  164. // The underlying method is static, so we set the object
  165. // argument to null.
  166. Object[] objs = (Object[])implMethod.invoke(null,
  167. new Object[]
  168. { type,
  169. "CertificateFactory",
  170. null
  171. } );
  172. return new CertificateFactory((CertificateFactorySpi)objs[0],
  173. (Provider)objs[1], type);
  174. } catch (IllegalAccessException iae) {
  175. CertificateException ce = new
  176. CertificateException(type + " not found");
  177. ce.initCause(iae);
  178. throw ce;
  179. } catch (InvocationTargetException ite) {
  180. CertificateException ce = new
  181. CertificateException(type + " not found");
  182. ce.initCause(ite);
  183. throw ce;
  184. }
  185. }
  186. /**
  187. * Generates a certificate factory object for the specified
  188. * certificate type from the specified provider.
  189. *
  190. * @param type the certificate type
  191. * @param provider the name of the provider.
  192. *
  193. * @return a certificate factory object for the specified type.
  194. *
  195. * @exception CertificateException if the certificate type is
  196. * not available from the specified provider.
  197. *
  198. * @exception NoSuchProviderException if the provider has not been
  199. * configured.
  200. *
  201. * @see Provider
  202. */
  203. public static final CertificateFactory getInstance(String type,
  204. String provider)
  205. throws CertificateException, NoSuchProviderException
  206. {
  207. if (provider == null || provider.length() == 0)
  208. throw new IllegalArgumentException("missing provider");
  209. try {
  210. if (implMethod == null) {
  211. throw new CertificateException(type + " not found");
  212. }
  213. // The underlying method is static, so we set the object
  214. // argument to null.
  215. Object[] objs = (Object[])implMethod.invoke(null,
  216. new Object[]
  217. { type,
  218. "CertificateFactory",
  219. provider
  220. } );
  221. return new CertificateFactory((CertificateFactorySpi)objs[0],
  222. (Provider)objs[1], type);
  223. } catch (IllegalAccessException iae) {
  224. CertificateException ce = new
  225. CertificateException(type + " not found");
  226. ce.initCause(iae);
  227. throw ce;
  228. } catch (InvocationTargetException ite) {
  229. Throwable t = ite.getTargetException();
  230. if (t != null && t instanceof NoSuchProviderException)
  231. throw (NoSuchProviderException)t;
  232. CertificateException ce = new
  233. CertificateException(type + " not found");
  234. ce.initCause(ite);
  235. throw ce;
  236. }
  237. }
  238. /**
  239. * Generates a certificate factory object for the specified
  240. * certificate type from the specified provider.
  241. * Note: the <code>provider</code> doesn't have to be registered.
  242. *
  243. * @param type the certificate type
  244. * @param provider the provider
  245. *
  246. * @return a certificate factory object for the specified type.
  247. *
  248. * @exception CertificateException if the certificate type is
  249. * not available from the specified provider.
  250. *
  251. * @exception IllegalArgumentException if the <code>provider</code> is
  252. * null.
  253. *
  254. * @see Provider
  255. *
  256. * @since 1.4
  257. */
  258. public static final CertificateFactory getInstance(String type,
  259. Provider provider)
  260. throws CertificateException
  261. {
  262. if (provider == null)
  263. throw new IllegalArgumentException("missing provider");
  264. if (implMethod2Set.booleanValue() == false) {
  265. synchronized (implMethod2Set) {
  266. if (implMethod2Set.booleanValue() == false) {
  267. implMethod2 = (Method)
  268. AccessController.doPrivileged(
  269. new PrivilegedAction() {
  270. public Object run() {
  271. Method m = null;
  272. try {
  273. m = cl.getDeclaredMethod("getImpl",
  274. GET_IMPL_PARAMS2);
  275. if (m != null)
  276. m.setAccessible(true);
  277. } catch (NoSuchMethodException nsme) {
  278. }
  279. return m;
  280. }
  281. });
  282. implMethod2Set = new Boolean(true);
  283. }
  284. }
  285. }
  286. if (implMethod2 == null) {
  287. throw new CertificateException(type + " not found");
  288. }
  289. try {
  290. // The underlying method is static, so we set the object
  291. // argument to null.
  292. Object[] objs = (Object[])implMethod2.invoke(null,
  293. new Object[]
  294. { type,
  295. "CertificateFactory",
  296. provider
  297. } );
  298. return new CertificateFactory((CertificateFactorySpi)objs[0],
  299. (Provider)objs[1], type);
  300. } catch (IllegalAccessException iae) {
  301. CertificateException ce = new
  302. CertificateException(type + " not found");
  303. ce.initCause(iae);
  304. throw ce;
  305. } catch (InvocationTargetException ite) {
  306. CertificateException ce = new
  307. CertificateException(type + " not found");
  308. ce.initCause(ite);
  309. throw ce;
  310. }
  311. }
  312. /**
  313. * Returns the provider of this certificate factory.
  314. *
  315. * @return the provider of this certificate factory.
  316. */
  317. public final Provider getProvider() {
  318. return this.provider;
  319. }
  320. /**
  321. * Returns the name of the certificate type associated with this
  322. * certificate factory.
  323. *
  324. * @return the name of the certificate type associated with this
  325. * certificate factory.
  326. */
  327. public final String getType() {
  328. return this.type;
  329. }
  330. /**
  331. * Generates a certificate object and initializes it with
  332. * the data read from the input stream <code>inStream</code>.
  333. *
  334. * <p>In order to take advantage of the specialized certificate format
  335. * supported by this certificate factory,
  336. * the returned certificate object can be typecast to the corresponding
  337. * certificate class. For example, if this certificate
  338. * factory implements X.509 certificates, the returned certificate object
  339. * can be typecast to the <code>X509Certificate</code> class.
  340. *
  341. * <p>In the case of a certificate factory for X.509 certificates, the
  342. * certificate provided in <code>inStream</code> must be DER-encoded and
  343. * may be supplied in binary or printable (Base64) encoding. If the
  344. * certificate is provided in Base64 encoding, it must be bounded at
  345. * the beginning by -----BEGIN CERTIFICATE-----, and must be bounded at
  346. * the end by -----END CERTIFICATE-----.
  347. *
  348. * <p>Note that if the given input stream does not support
  349. * {@link java.io.InputStream#mark(int) mark} and
  350. * {@link java.io.InputStream#reset() reset}, this method will
  351. * consume the entire input stream. Otherwise, each call to this
  352. * method consumes one certificate and the read position of the
  353. * input stream is positioned to the next available byte after
  354. * the inherent end-of-certificate marker. If the data in the input stream
  355. * does not contain an inherent end-of-certificate marker (other
  356. * than EOF) and there is trailing data after the certificate is parsed, a
  357. * <code>CertificateException</code> is thrown.
  358. *
  359. * @param inStream an input stream with the certificate data.
  360. *
  361. * @return a certificate object initialized with the data
  362. * from the input stream.
  363. *
  364. * @exception CertificateException on parsing errors.
  365. */
  366. public final Certificate generateCertificate(InputStream inStream)
  367. throws CertificateException
  368. {
  369. return certFacSpi.engineGenerateCertificate(inStream);
  370. }
  371. /**
  372. * Returns an iteration of the <code>CertPath</code> encodings supported
  373. * by this certificate factory, with the default encoding first. See
  374. * Appendix A in the
  375. * <a href="../../../../guide/security/certpath/CertPathProgGuide.html#AppA">
  376. * Java Certification Path API Programmer's Guide</a> for information about
  377. * standard encoding names and their formats.
  378. * <p>
  379. * Attempts to modify the returned <code>Iterator</code> via its
  380. * <code>remove</code> method result in an
  381. * <code>UnsupportedOperationException</code>.
  382. *
  383. * @return an <code>Iterator</code> over the names of the supported
  384. * <code>CertPath</code> encodings (as <code>String</code>s)
  385. * @since 1.4
  386. */
  387. public final Iterator getCertPathEncodings() {
  388. return(certFacSpi.engineGetCertPathEncodings());
  389. }
  390. /**
  391. * Generates a <code>CertPath</code> object and initializes it with
  392. * the data read from the <code>InputStream</code> inStream. The data
  393. * is assumed to be in the default encoding. The name of the default
  394. * encoding is the first element of the <code>Iterator</code> returned by
  395. * the {@link #getCertPathEncodings getCertPathEncodings} method.
  396. *
  397. * @param inStream an <code>InputStream</code> containing the data
  398. * @return a <code>CertPath</code> initialized with the data from the
  399. * <code>InputStream</code>
  400. * @exception CertificateException if an exception occurs while decoding
  401. * @since 1.4
  402. */
  403. public final CertPath generateCertPath(InputStream inStream)
  404. throws CertificateException
  405. {
  406. return(certFacSpi.engineGenerateCertPath(inStream));
  407. }
  408. /**
  409. * Generates a <code>CertPath</code> object and initializes it with
  410. * the data read from the <code>InputStream</code> inStream. The data
  411. * is assumed to be in the specified encoding. See Appendix A in the
  412. * <a href="../../../../guide/security/certpath/CertPathProgGuide.html#AppA">
  413. * Java Certification Path API Programmer's Guide</a>
  414. * for information about standard encoding names and their formats.
  415. *
  416. * @param inStream an <code>InputStream</code> containing the data
  417. * @param encoding the encoding used for the data
  418. * @return a <code>CertPath</code> initialized with the data from the
  419. * <code>InputStream</code>
  420. * @exception CertificateException if an exception occurs while decoding or
  421. * the encoding requested is not supported
  422. * @since 1.4
  423. */
  424. public final CertPath generateCertPath(InputStream inStream,
  425. String encoding) throws CertificateException
  426. {
  427. return(certFacSpi.engineGenerateCertPath(inStream, encoding));
  428. }
  429. /**
  430. * Generates a <code>CertPath</code> object and initializes it with
  431. * a <code>List</code> of <code>Certificate</code>s.
  432. * <p>
  433. * The certificates supplied must be of a type supported by the
  434. * <code>CertificateFactory</code>. They will be copied out of the supplied
  435. * <code>List</code> object.
  436. *
  437. * @param certificates a <code>List</code> of <code>Certificate</code>s
  438. * @return a <code>CertPath</code> initialized with the supplied list of
  439. * certificates
  440. * @exception CertificateException if an exception occurs
  441. * @since 1.4
  442. */
  443. public final CertPath generateCertPath(List certificates)
  444. throws CertificateException
  445. {
  446. return(certFacSpi.engineGenerateCertPath(certificates));
  447. }
  448. /**
  449. * Returns a (possibly empty) collection view of the certificates read
  450. * from the given input stream <code>inStream</code>.
  451. *
  452. * <p>In order to take advantage of the specialized certificate format
  453. * supported by this certificate factory, each element in
  454. * the returned collection view can be typecast to the corresponding
  455. * certificate class. For example, if this certificate
  456. * factory implements X.509 certificates, the elements in the returned
  457. * collection can be typecast to the <code>X509Certificate</code> class.
  458. *
  459. * <p>In the case of a certificate factory for X.509 certificates,
  460. * <code>inStream</code> may contain a sequence of DER-encoded certificates
  461. * in the formats described for
  462. * {@link #generateCertificate(java.io.InputStream) generateCertificate}.
  463. * In addition, <code>inStream</code> may contain a PKCS#7 certificate
  464. * chain. This is a PKCS#7 <i>SignedData</i> object, with the only
  465. * significant field being <i>certificates</i>. In particular, the
  466. * signature and the contents are ignored. This format allows multiple
  467. * certificates to be downloaded at once. If no certificates are present,
  468. * an empty collection is returned.
  469. *
  470. * <p>Note that if the given input stream does not support
  471. * {@link java.io.InputStream#mark(int) mark} and
  472. * {@link java.io.InputStream#reset() reset}, this method will
  473. * consume the entire input stream.
  474. *
  475. * @param inStream the input stream with the certificates.
  476. *
  477. * @return a (possibly empty) collection view of
  478. * java.security.cert.Certificate objects
  479. * initialized with the data from the input stream.
  480. *
  481. * @exception CertificateException on parsing errors.
  482. */
  483. public final Collection generateCertificates(InputStream inStream)
  484. throws CertificateException
  485. {
  486. return certFacSpi.engineGenerateCertificates(inStream);
  487. }
  488. /**
  489. * Generates a certificate revocation list (CRL) object and initializes it
  490. * with the data read from the input stream <code>inStream</code>.
  491. *
  492. * <p>In order to take advantage of the specialized CRL format
  493. * supported by this certificate factory,
  494. * the returned CRL object can be typecast to the corresponding
  495. * CRL class. For example, if this certificate
  496. * factory implements X.509 CRLs, the returned CRL object
  497. * can be typecast to the <code>X509CRL</code> class.
  498. *
  499. * <p>Note that if the given input stream does not support
  500. * {@link java.io.InputStream#mark(int) mark} and
  501. * {@link java.io.InputStream#reset() reset}, this method will
  502. * consume the entire input stream. Otherwise, each call to this
  503. * method consumes one CRL and the read position of the input stream
  504. * is positioned to the next available byte after the the inherent
  505. * end-of-CRL marker. If the data in the
  506. * input stream does not contain an inherent end-of-CRL marker (other
  507. * than EOF) and there is trailing data after the CRL is parsed, a
  508. * <code>CRLException</code> is thrown.
  509. *
  510. * @param inStream an input stream with the CRL data.
  511. *
  512. * @return a CRL object initialized with the data
  513. * from the input stream.
  514. *
  515. * @exception CRLException on parsing errors.
  516. */
  517. public final CRL generateCRL(InputStream inStream)
  518. throws CRLException
  519. {
  520. return certFacSpi.engineGenerateCRL(inStream);
  521. }
  522. /**
  523. * Returns a (possibly empty) collection view of the CRLs read
  524. * from the given input stream <code>inStream</code>.
  525. *
  526. * <p>In order to take advantage of the specialized CRL format
  527. * supported by this certificate factory, each element in
  528. * the returned collection view can be typecast to the corresponding
  529. * CRL class. For example, if this certificate
  530. * factory implements X.509 CRLs, the elements in the returned
  531. * collection can be typecast to the <code>X509CRL</code> class.
  532. *
  533. * <p>In the case of a certificate factory for X.509 CRLs,
  534. * <code>inStream</code> may contain a sequence of DER-encoded CRLs.
  535. * In addition, <code>inStream</code> may contain a PKCS#7 CRL
  536. * set. This is a PKCS#7 <i>SignedData</i> object, with the only
  537. * significant field being <i>crls</i>. In particular, the
  538. * signature and the contents are ignored. This format allows multiple
  539. * CRLs to be downloaded at once. If no CRLs are present,
  540. * an empty collection is returned.
  541. *
  542. * <p>Note that if the given input stream does not support
  543. * {@link java.io.InputStream#mark(int) mark} and
  544. * {@link java.io.InputStream#reset() reset}, this method will
  545. * consume the entire input stream.
  546. *
  547. * @param inStream the input stream with the CRLs.
  548. *
  549. * @return a (possibly empty) collection view of
  550. * java.security.cert.CRL objects initialized with the data from the input
  551. * stream.
  552. *
  553. * @exception CRLException on parsing errors.
  554. */
  555. public final Collection generateCRLs(InputStream inStream)
  556. throws CRLException
  557. {
  558. return certFacSpi.engineGenerateCRLs(inStream);
  559. }
  560. }