1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package java.security.cert;
19
20import java.io.InputStream;
21import java.security.NoSuchAlgorithmException;
22import java.security.NoSuchProviderException;
23import java.security.Provider;
24import java.security.Security;
25import java.util.Collection;
26import java.util.Iterator;
27import java.util.List;
28import org.apache.harmony.security.fortress.Engine;
29
30
31/**
32 * This class implements the functionality of a certificate factory algorithm,
33 * relying on parsing a stream of bytes.
34 * <p>
35 * It defines methods for parsing certificate chains (certificate paths) and
36 * <i>Certificate Revocation Lists</i> (CRLs).
37 */
38public class CertificateFactory {
39
40    // Store CertificateFactory service name
41    private static final String SERVICE = "CertificateFactory";
42
43    // Used to access common engine functionality
44    private static final Engine ENGINE = new Engine(SERVICE);
45
46    // Store used provider
47    private final Provider provider;
48
49    // Store used CertificateFactorySpi implementation
50    private final CertificateFactorySpi spiImpl;
51
52    // Store used type
53    private final String type;
54
55    /**
56     * Creates a new {@code CertificateFactory} instance.
57     *
58     * @param certFacSpi
59     *            the implementation delegate.
60     * @param provider
61     *            the associated provider.
62     * @param type
63     *            the certificate type.
64     */
65    protected CertificateFactory(CertificateFactorySpi certFacSpi,
66            Provider provider, String type) {
67        this.provider = provider;
68        this.type = type;
69        this.spiImpl = certFacSpi;
70    }
71
72    /**
73     * Creates a new {@code CertificateFactory} instance that provides the
74     * requested certificate type.
75     *
76     * @param type
77     *            the certificate type.
78     * @return the new {@code CertificateFactory} instance.
79     * @throws CertificateException
80     *             if the specified certificate type is not available at any
81     *             installed provider.
82     * @throws NullPointerException if {@code type == null}
83     */
84    public static final CertificateFactory getInstance(String type)
85            throws CertificateException {
86        if (type == null) {
87            throw new NullPointerException("type == null");
88        }
89        try {
90            Engine.SpiAndProvider sap = ENGINE.getInstance(type, null);
91            return new CertificateFactory((CertificateFactorySpi) sap.spi, sap.provider, type);
92        } catch (NoSuchAlgorithmException e) {
93            throw new CertificateException(e);
94        }
95    }
96
97    /**
98     * Creates a new {@code CertificateFactory} instance from the specified
99     * provider that provides the requested certificate type.
100     *
101     * @param type
102     *            the certificate type.
103     * @param provider
104     *            the name of the provider providing certificates of the
105     *            specified type.
106     * @return the new {@code CertificateFactory} instance.
107     * @throws CertificateException
108     *             if the specified certificate type is not available by the
109     *             specified provider.
110     * @throws NoSuchProviderException
111     *             if no provider with the specified name can be found.
112     * @throws IllegalArgumentException if {@code provider == null || provider.isEmpty()}
113     * @throws NullPointerException
114     *             it {@code type} is {@code null}.
115     */
116    public static final CertificateFactory getInstance(String type,
117            String provider) throws CertificateException,
118            NoSuchProviderException {
119        if (provider == null || provider.isEmpty()) {
120            throw new IllegalArgumentException("provider == null || provider.isEmpty()");
121        }
122        Provider impProvider = Security.getProvider(provider);
123        if (impProvider == null) {
124            throw new NoSuchProviderException(provider);
125        }
126        return getInstance(type, impProvider);
127    }
128
129    /**
130     * Creates a new {@code CertificateFactory} instance from the specified
131     * provider that provides the requested certificate type.
132     *
133     * @param type
134     *            the certificate type.
135     * @param provider
136     *            the name of the provider providing certificates of the
137     *            specified type.
138     * @return the new {@code CertificateFactory} instance.
139     * @throws CertificateException
140     *             if the specified certificate type is not available at the
141     *             specified provider.
142     * @throws IllegalArgumentException
143     *             if the specified provider is {@code null}.
144     * @throws NullPointerException if {@code type == null}
145     * @throws IllegalArgumentException if {@code provider == null}
146     */
147    public static final CertificateFactory getInstance(String type,
148            Provider provider) throws CertificateException {
149        if (provider == null) {
150            throw new IllegalArgumentException("provider == null");
151        }
152        if (type == null) {
153            throw new NullPointerException("type == null");
154        }
155        try {
156            Object spi = ENGINE.getInstance(type, provider, null);
157            return new CertificateFactory((CertificateFactorySpi) spi, provider, type);
158        } catch (NoSuchAlgorithmException e) {
159            throw new CertificateException(e);
160        }
161    }
162
163    /**
164     * Returns the {@code Provider} of the certificate factory represented by
165     * the certificate.
166     *
167     * @return the provider of this certificate factory.
168     */
169    public final Provider getProvider() {
170        return provider;
171    }
172
173    /**
174     * Returns the Certificate type.
175     *
176     * @return type of certificate being used.
177     */
178    public final String getType() {
179        return type;
180    }
181
182    /**
183     * Generates and initializes a {@code Certificate} from the provided input
184     * stream.
185     *
186     * @param inStream
187     *            the stream from where data is read to create the {@code
188     *            Certificate}.
189     * @return an initialized Certificate.
190     * @throws CertificateException
191     *             if parsing problems are detected.
192     */
193    public final Certificate generateCertificate(InputStream inStream)
194            throws CertificateException {
195        return spiImpl.engineGenerateCertificate(inStream);
196    }
197
198    /**
199     * Returns an {@code Iterator} over the supported {@code CertPath} encodings
200     * (as Strings). The first element is the default encoding scheme to apply.
201     *
202     * @return an iterator over supported {@link CertPath} encodings (as
203     *         Strings).
204     */
205    public final Iterator<String> getCertPathEncodings() {
206        return spiImpl.engineGetCertPathEncodings();
207    }
208
209    /**
210     * Generates a {@code CertPath} (a certificate chain) from the provided
211     * {@code InputStream}. The default encoding scheme is applied.
212     *
213     * @param inStream
214     *            {@code InputStream} with encoded data.
215     * @return a {@code CertPath} initialized from the provided data.
216     * @throws CertificateException
217     *             if parsing problems are detected.
218     */
219    public final CertPath generateCertPath(InputStream inStream) throws CertificateException {
220        Iterator<String> it = getCertPathEncodings();
221        if (!it.hasNext()) {
222            throw new CertificateException("There are no CertPath encodings");
223        }
224        return spiImpl.engineGenerateCertPath(inStream, it.next());
225    }
226
227    /**
228     * Generates a {@code CertPath} (a certificate chain) from the provided
229     * {@code InputStream} and the specified encoding scheme.
230     *
231     * @param inStream
232     *            {@code InputStream} containing certificate path data in
233     *            specified encoding.
234     * @param encoding
235     *            encoding of the data in the input stream.
236     * @return a {@code CertPath} initialized from the provided data.
237     * @throws CertificateException
238     *             if parsing problems are detected.
239     * @throws UnsupportedOperationException
240     *             if the provider does not implement this method.
241     */
242    public final CertPath generateCertPath(InputStream inStream, String encoding)
243            throws CertificateException {
244        return spiImpl.engineGenerateCertPath(inStream, encoding);
245    }
246
247    /**
248     * Generates a {@code CertPath} from the provided list of certificates. The
249     * encoding is the default encoding.
250     *
251     * @param certificates
252     *            the list containing certificates in a format supported by the
253     *            {@code CertificateFactory}.
254     * @return a {@code CertPath} initialized from the provided data.
255     * @throws CertificateException
256     *             if parsing problems are detected.
257     * @throws UnsupportedOperationException
258     *             if the provider does not implement this method.
259     */
260    public final CertPath generateCertPath(List<? extends Certificate> certificates)
261            throws CertificateException {
262        return spiImpl.engineGenerateCertPath(certificates);
263    }
264
265    /**
266     * Generates and initializes a collection of (unrelated) certificates from
267     * the provided input stream.
268     *
269     * @param inStream
270     *            the stream from which the data is read to create the
271     *            collection.
272     * @return an initialized collection of certificates.
273     * @throws CertificateException
274     *             if parsing problems are detected.
275     */
276    public final Collection<? extends Certificate> generateCertificates(InputStream inStream)
277            throws CertificateException {
278        return spiImpl.engineGenerateCertificates(inStream);
279    }
280
281    /**
282     * Generates and initializes a <i>Certificate Revocation List</i> (CRL) from
283     * the provided input stream.
284     *
285     * @param inStream
286     *            the stream from where data is read to create the CRL.
287     * @return an initialized CRL.
288     * @exception CRLException
289     *                if parsing problems are detected.
290     */
291    public final CRL generateCRL(InputStream inStream) throws CRLException {
292        return spiImpl.engineGenerateCRL(inStream);
293    }
294
295    /**
296     * Generates and initializes a collection of <i>Certificate Revocation
297     * List</i> (CRL) from the provided input stream.
298     *
299     * @param inStream
300     *            the stream from which the data is read to create the CRLs.
301     * @return an initialized collection of CRLs.
302     * @exception CRLException
303     *                if parsing problems are detected.
304     */
305    public final Collection<? extends CRL> generateCRLs(InputStream inStream)
306            throws CRLException {
307        return spiImpl.engineGenerateCRLs(inStream);
308    }
309}
310