1 module hunt.security.cert.CertificateFactory;
2 
3 import hunt.security.cert.Certificate;
4 import hunt.security.cert.CertificateFactorySpi;
5 import hunt.security.cert.CertPath;
6 import hunt.security.cert.CRL;
7 
8 import hunt.security.Provider;
9 
10 import hunt.collection;
11 import hunt.stream.Common;
12 
13 import hunt.Exceptions;
14 
15 
16 
17 /**
18  * This class defines the functionality of a certificate factory, which is
19  * used to generate certificate, certification path ({@code CertPath})
20  * and certificate revocation list (CRL) objects from their encodings.
21  *
22  * <p>For encodings consisting of multiple certificates, use
23  * {@code generateCertificates} when you want to
24  * parse a collection of possibly unrelated certificates. Otherwise,
25  * use {@code generateCertPath} when you want to generate
26  * a {@code CertPath} (a certificate chain) and subsequently
27  * validate it with a {@code CertPathValidator}.
28  *
29  * <p>A certificate factory for X.509 must return certificates that are an
30  * instance of {@code java.security.cert.X509Certificate}, and CRLs
31  * that are an instance of {@code java.security.cert.X509CRL}.
32  *
33  * <p>The following example reads a file with Base64 encoded certificates,
34  * which are each bounded at the beginning by -----BEGIN CERTIFICATE-----, and
35  * bounded at the end by -----END CERTIFICATE-----. We convert the
36  * {@code FileInputStream} (which does not support {@code mark}
37  * and {@code reset}) to a {@code BufferedInputStream} (which
38  * supports those methods), so that each call to
39  * {@code generateCertificate} consumes only one certificate, and the
40  * read position of the input stream is positioned to the next certificate in
41  * the file:
42  *
43  * <pre>{@code
44  * FileInputStream fis = new FileInputStream(filename);
45  * BufferedInputStream bis = new BufferedInputStream(fis);
46  *
47  * CertificateFactory cf = CertificateFactory.getInstance("X.509");
48  *
49  * while (bis.available() > 0) {
50  *    Certificate cert = cf.generateCertificate(bis);
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:
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  * <p> Every implementation of the Java platform is required to support the
70  * following standard {@code CertificateFactory} type:
71  * <ul>
72  * <li>{@code X.509}</li>
73  * </ul>
74  * and the following standard {@code CertPath} encodings:
75  * <ul>
76  * <li>{@code PKCS7}</li>
77  * <li>{@code PkiPath}</li>
78  * </ul>
79  * The type and encodings are described in the <a href=
80  * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertificateFactory">
81  * CertificateFactory section</a> and the <a href=
82  * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathEncodings">
83  * CertPath Encodings section</a> of the
84  * Java Cryptography Architecture Standard Algorithm Name Documentation.
85  * Consult the release documentation for your implementation to see if any
86  * other types or encodings are supported.
87  *
88  * @author Hemma Prafullchandra
89  * @author Jan Luehe
90  * @author Sean Mullan
91  *
92  * @see Certificate
93  * @see X509Certificate
94  * @see CertPath
95  * @see CRL
96  * @see X509CRL
97  *
98  * @since 1.2
99  */
100 
101 class CertificateFactory {
102 
103     // The certificate type
104     private string type;
105 
106     // The provider
107     private Provider provider;
108 
109     // The provider implementation
110     private CertificateFactorySpi certFacSpi;
111 
112     /**
113      * Creates a CertificateFactory object of the given type, and encapsulates
114      * the given provider implementation (SPI object) in it.
115      *
116      * @param certFacSpi the provider implementation.
117      * @param provider the provider.
118      * @param type the certificate type.
119      */
120     protected this(CertificateFactorySpi certFacSpi,
121                                  Provider provider, string type)
122     {
123         this.certFacSpi = certFacSpi;
124         this.provider = provider;
125         this.type = type;
126     }
127 
128     /**
129      * Returns a certificate factory object that implements the
130      * specified certificate type.
131      *
132      * <p> This method traverses the list of registered security Providers,
133      * starting with the most preferred Provider.
134      * A new CertificateFactory object encapsulating the
135      * CertificateFactorySpi implementation from the first
136      * Provider that supports the specified type is returned.
137      *
138      * <p> Note that the list of registered providers may be retrieved via
139      * the {@link Security#getProviders() Security.getProviders()} method.
140      *
141      * @param type the name of the requested certificate type.
142      * See the CertificateFactory section in the <a href=
143      * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertificateFactory">
144      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
145      * for information about standard certificate types.
146      *
147      * @return a certificate factory object for the specified type.
148      *
149      * @exception CertificateException if no Provider supports a
150      *          CertificateFactorySpi implementation for the
151      *          specified type.
152      *
153      * @see java.security.Provider
154      */
155     static final CertificateFactory getInstance(string type) {
156         try {
157             return new CertificateFactory(getFactorySpi(type),
158                 null, type);
159         } catch (NoSuchAlgorithmException e) {
160             throw new CertificateException(type ~ " not found", e);
161         }
162     }
163 
164     static CertificateFactorySpi getFactorySpi(string type)
165     {
166         if(type == "X.509")
167         {
168             import hunt.security.x509.X509Factory;
169             return new X509Factory();
170         }
171         else
172             throw new NotSupportedException(type);
173     }
174 
175     /**
176      * Returns a certificate factory object for the specified
177      * certificate type.
178      *
179      * <p> A new CertificateFactory object encapsulating the
180      * CertificateFactorySpi implementation from the specified provider
181      * is returned.  The specified provider must be registered
182      * in the security provider list.
183      *
184      * <p> Note that the list of registered providers may be retrieved via
185      * the {@link Security#getProviders() Security.getProviders()} method.
186      *
187      * @param type the certificate type.
188      * See the CertificateFactory section in the <a href=
189      * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertificateFactory">
190      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
191      * for information about standard certificate types.
192      *
193      * @param provider the name of the provider.
194      *
195      * @return a certificate factory object for the specified type.
196      *
197      * @exception CertificateException if a CertificateFactorySpi
198      *          implementation for the specified algorithm is not
199      *          available from the specified provider.
200      *
201      * @exception NoSuchProviderException if the specified provider is not
202      *          registered in the security provider list.
203      *
204      * @exception IllegalArgumentException if the provider name is null
205      *          or empty.
206      *
207      * @see java.security.Provider
208      */
209     // static final CertificateFactory getInstance(string type,
210     //         string provider) {
211     //     try {
212     //         Instance instance = GetInstance.getInstance("CertificateFactory",
213     //             CertificateFactorySpi.class, type, provider);
214     //         return new CertificateFactory((CertificateFactorySpi)instance.impl,
215     //             instance.provider, type);
216     //     } catch (NoSuchAlgorithmException e) {
217     //         throw new CertificateException(type ~ " not found", e);
218     //     }
219     // }
220 
221     /**
222      * Returns a certificate factory object for the specified
223      * certificate type.
224      *
225      * <p> A new CertificateFactory object encapsulating the
226      * CertificateFactorySpi implementation from the specified Provider
227      * object is returned.  Note that the specified Provider object
228      * does not have to be registered in the provider list.
229      *
230      * @param type the certificate type.
231      * See the CertificateFactory section in the <a href=
232      * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertificateFactory">
233      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
234      * for information about standard certificate types.
235      * @param provider the provider.
236      *
237      * @return a certificate factory object for the specified type.
238      *
239      * @exception CertificateException if a CertificateFactorySpi
240      *          implementation for the specified algorithm is not available
241      *          from the specified Provider object.
242      *
243      * @exception IllegalArgumentException if the {@code provider} is
244      *          null.
245      *
246      * @see java.security.Provider
247      *
248      * @since 1.4
249      */
250     // static final CertificateFactory getInstance(string type,
251     //         Provider provider) throws CertificateException {
252     //     try {
253     //         Instance instance = GetInstance.getInstance("CertificateFactory",
254     //             CertificateFactorySpi.class, type, provider);
255     //         return new CertificateFactory((CertificateFactorySpi)instance.impl,
256     //             instance.provider, type);
257     //     } catch (NoSuchAlgorithmException e) {
258     //         throw new CertificateException(type ~ " not found", e);
259     //     }
260     // }
261 
262     /**
263      * Returns the provider of this certificate factory.
264      *
265      * @return the provider of this certificate factory.
266      */
267     final Provider getProvider() {
268         return this.provider;
269     }
270 
271     /**
272      * Returns the name of the certificate type associated with this
273      * certificate factory.
274      *
275      * @return the name of the certificate type associated with this
276      * certificate factory.
277      */
278     final string getType() {
279         return this.type;
280     }
281 
282     /**
283      * Generates a certificate object and initializes it with
284      * the data read from the input stream {@code inStream}.
285      *
286      * <p>In order to take advantage of the specialized certificate format
287      * supported by this certificate factory,
288      * the returned certificate object can be typecast to the corresponding
289      * certificate class. For example, if this certificate
290      * factory implements X.509 certificates, the returned certificate object
291      * can be typecast to the {@code X509Certificate} class.
292      *
293      * <p>In the case of a certificate factory for X.509 certificates, the
294      * certificate provided in {@code inStream} must be DER-encoded and
295      * may be supplied in binary or printable (Base64) encoding. If the
296      * certificate is provided in Base64 encoding, it must be bounded at
297      * the beginning by -----BEGIN CERTIFICATE-----, and must be bounded at
298      * the end by -----END CERTIFICATE-----.
299      *
300      * <p>Note that if the given input stream does not support
301      * {@link java.io.InputStream#mark(int) mark} and
302      * {@link java.io.InputStream#reset() reset}, this method will
303      * consume the entire input stream. Otherwise, each call to this
304      * method consumes one certificate and the read position of the
305      * input stream is positioned to the next available byte after
306      * the inherent end-of-certificate marker. If the data in the input stream
307      * does not contain an inherent end-of-certificate marker (other
308      * than EOF) and there is trailing data after the certificate is parsed, a
309      * {@code CertificateException} is thrown.
310      *
311      * @param inStream an input stream with the certificate data.
312      *
313      * @return a certificate object initialized with the data
314      * from the input stream.
315      *
316      * @exception CertificateException on parsing errors.
317      */
318     final Certificate generateCertificate(InputStream inStream)
319     {
320         return certFacSpi.engineGenerateCertificate(inStream);
321     }
322 
323     /**
324      * Returns an iteration of the {@code CertPath} encodings supported
325      * by this certificate factory, with the default encoding first. See
326      * the CertPath Encodings section in the <a href=
327      * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathEncodings">
328      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
329      * for information about standard encoding names and their formats.
330      * <p>
331      * Attempts to modify the returned {@code Iterator} via its
332      * {@code remove} method result in an
333      * {@code UnsupportedOperationException}.
334      *
335      * @return an {@code Iterator} over the names of the supported
336      *         {@code CertPath} encodings (as {@code string}s)
337      * @since 1.4
338      */
339     final Iterator!string getCertPathEncodings() {
340         return certFacSpi.engineGetCertPathEncodings();
341     }
342 
343     /**
344      * Generates a {@code CertPath} object and initializes it with
345      * the data read from the {@code InputStream} inStream. The data
346      * is assumed to be in the default encoding. The name of the default
347      * encoding is the first element of the {@code Iterator} returned by
348      * the {@link #getCertPathEncodings getCertPathEncodings} method.
349      *
350      * @param inStream an {@code InputStream} containing the data
351      * @return a {@code CertPath} initialized with the data from the
352      *   {@code InputStream}
353      * @exception CertificateException if an exception occurs while decoding
354      * @since 1.4
355      */
356     final CertPath generateCertPath(InputStream inStream)
357     {
358         return certFacSpi.engineGenerateCertPath(inStream);
359     }
360 
361     /**
362      * Generates a {@code CertPath} object and initializes it with
363      * the data read from the {@code InputStream} inStream. The data
364      * is assumed to be in the specified encoding. See
365      * the CertPath Encodings section in the <a href=
366      * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathEncodings">
367      * Java Cryptography Architecture Standard Algorithm Name Documentation</a>
368      * for information about standard encoding names and their formats.
369      *
370      * @param inStream an {@code InputStream} containing the data
371      * @param encoding the encoding used for the data
372      * @return a {@code CertPath} initialized with the data from the
373      *   {@code InputStream}
374      * @exception CertificateException if an exception occurs while decoding or
375      *   the encoding requested is not supported
376      * @since 1.4
377      */
378     final CertPath generateCertPath(InputStream inStream, string encoding)
379     {
380         return certFacSpi.engineGenerateCertPath(inStream, encoding);
381     }
382 
383     /**
384      * Generates a {@code CertPath} object and initializes it with
385      * a {@code List} of {@code Certificate}s.
386      * <p>
387      * The certificates supplied must be of a type supported by the
388      * {@code CertificateFactory}. They will be copied out of the supplied
389      * {@code List} object.
390      *
391      * @param certificates a {@code List} of {@code Certificate}s
392      * @return a {@code CertPath} initialized with the supplied list of
393      *   certificates
394      * @exception CertificateException if an exception occurs
395      * @since 1.4
396      */
397     final CertPath generateCertPath(List!Certificate certificates)
398     {
399         return certFacSpi.engineGenerateCertPath(certificates);
400     }
401 
402     /**
403      * Returns a (possibly empty) collection view of the certificates read
404      * from the given input stream {@code inStream}.
405      *
406      * <p>In order to take advantage of the specialized certificate format
407      * supported by this certificate factory, each element in
408      * the returned collection view can be typecast to the corresponding
409      * certificate class. For example, if this certificate
410      * factory implements X.509 certificates, the elements in the returned
411      * collection can be typecast to the {@code X509Certificate} class.
412      *
413      * <p>In the case of a certificate factory for X.509 certificates,
414      * {@code inStream} may contain a sequence of DER-encoded certificates
415      * in the formats described for
416      * {@link #generateCertificate(java.io.InputStream) generateCertificate}.
417      * In addition, {@code inStream} may contain a PKCS#7 certificate
418      * chain. This is a PKCS#7 <i>SignedData</i> object, with the only
419      * significant field being <i>certificates</i>. In particular, the
420      * signature and the contents are ignored. This format allows multiple
421      * certificates to be downloaded at once. If no certificates are present,
422      * an empty collection is returned.
423      *
424      * <p>Note that if the given input stream does not support
425      * {@link java.io.InputStream#mark(int) mark} and
426      * {@link java.io.InputStream#reset() reset}, this method will
427      * consume the entire input stream.
428      *
429      * @param inStream the input stream with the certificates.
430      *
431      * @return a (possibly empty) collection view of
432      * java.security.cert.Certificate objects
433      * initialized with the data from the input stream.
434      *
435      * @exception CertificateException on parsing errors.
436      */
437     final Collection!Certificate generateCertificates(InputStream inStream) {
438         return certFacSpi.engineGenerateCertificates(inStream);
439     }
440 
441     /**
442      * Generates a certificate revocation list (CRL) object and initializes it
443      * with the data read from the input stream {@code inStream}.
444      *
445      * <p>In order to take advantage of the specialized CRL format
446      * supported by this certificate factory,
447      * the returned CRL object can be typecast to the corresponding
448      * CRL class. For example, if this certificate
449      * factory implements X.509 CRLs, the returned CRL object
450      * can be typecast to the {@code X509CRL} class.
451      *
452      * <p>Note that if the given input stream does not support
453      * {@link java.io.InputStream#mark(int) mark} and
454      * {@link java.io.InputStream#reset() reset}, this method will
455      * consume the entire input stream. Otherwise, each call to this
456      * method consumes one CRL and the read position of the input stream
457      * is positioned to the next available byte after the inherent
458      * end-of-CRL marker. If the data in the
459      * input stream does not contain an inherent end-of-CRL marker (other
460      * than EOF) and there is trailing data after the CRL is parsed, a
461      * {@code CRLException} is thrown.
462      *
463      * @param inStream an input stream with the CRL data.
464      *
465      * @return a CRL object initialized with the data
466      * from the input stream.
467      *
468      * @exception CRLException on parsing errors.
469      */
470     final CRL generateCRL(InputStream inStream)    {
471         return certFacSpi.engineGenerateCRL(inStream);
472     }
473 
474     /**
475      * Returns a (possibly empty) collection view of the CRLs read
476      * from the given input stream {@code inStream}.
477      *
478      * <p>In order to take advantage of the specialized CRL format
479      * supported by this certificate factory, each element in
480      * the returned collection view can be typecast to the corresponding
481      * CRL class. For example, if this certificate
482      * factory implements X.509 CRLs, the elements in the returned
483      * collection can be typecast to the {@code X509CRL} class.
484      *
485      * <p>In the case of a certificate factory for X.509 CRLs,
486      * {@code inStream} may contain a sequence of DER-encoded CRLs.
487      * In addition, {@code inStream} may contain a PKCS#7 CRL
488      * set. This is a PKCS#7 <i>SignedData</i> object, with the only
489      * significant field being <i>crls</i>. In particular, the
490      * signature and the contents are ignored. This format allows multiple
491      * CRLs to be downloaded at once. If no CRLs are present,
492      * an empty collection is returned.
493      *
494      * <p>Note that if the given input stream does not support
495      * {@link java.io.InputStream#mark(int) mark} and
496      * {@link java.io.InputStream#reset() reset}, this method will
497      * consume the entire input stream.
498      *
499      * @param inStream the input stream with the CRLs.
500      *
501      * @return a (possibly empty) collection view of
502      * java.security.cert.CRL objects initialized with the data from the input
503      * stream.
504      *
505      * @exception CRLException on parsing errors.
506      */
507     final Collection!CRL generateCRLs(InputStream inStream) {
508         return certFacSpi.engineGenerateCRLs(inStream);
509     }
510 }