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. The
132     * {@code provider} supplied does not have to be registered.
133     *
134     * @param type
135     *            the certificate type.
136     * @param provider
137     *            the name of the provider providing certificates of the
138     *            specified type.
139     * @return the new {@code CertificateFactory} instance.
140     * @throws CertificateException
141     *             if the specified certificate type is not available at the
142     *             specified provider.
143     * @throws IllegalArgumentException
144     *             if the specified provider is {@code null}.
145     * @throws NullPointerException if {@code type == null}
146     * @throws IllegalArgumentException if {@code provider == null}
147     */
148    public static final CertificateFactory getInstance(String type,
149            Provider provider) throws CertificateException {
150        if (provider == null) {
151            throw new IllegalArgumentException("provider == null");
152        }
153        if (type == null) {
154            throw new NullPointerException("type == null");
155        }
156        try {
157            Object spi = ENGINE.getInstance(type, provider, null);
158            return new CertificateFactory((CertificateFactorySpi) spi, provider, type);
159        } catch (NoSuchAlgorithmException e) {
160            throw new CertificateException(e);
161        }
162    }
163
164    /**
165     * Returns the {@code Provider} of the certificate factory represented by
166     * the certificate.
167     *
168     * @return the provider of this certificate factory.
169     */
170    public final Provider getProvider() {
171        return provider;
172    }
173
174    /**
175     * Returns the Certificate type.
176     *
177     * @return type of certificate being used.
178     */
179    public final String getType() {
180        return type;
181    }
182
183    /**
184     * Generates and initializes a {@code Certificate} from the provided input
185     * stream.
186     *
187     * @param inStream
188     *            the stream from where data is read to create the {@code
189     *            Certificate}.
190     * @return an initialized Certificate.
191     * @throws CertificateException
192     *             if parsing problems are detected.
193     */
194    public final Certificate generateCertificate(InputStream inStream)
195            throws CertificateException {
196        return spiImpl.engineGenerateCertificate(inStream);
197    }
198
199    /**
200     * Returns an {@code Iterator} over the supported {@code CertPath} encodings
201     * (as Strings). The first element is the default encoding scheme to apply.
202     *
203     * @return an iterator over supported {@link CertPath} encodings (as
204     *         Strings).
205     */
206    public final Iterator<String> getCertPathEncodings() {
207        return spiImpl.engineGetCertPathEncodings();
208    }
209
210    /**
211     * Generates a {@code CertPath} (a certificate chain) from the provided
212     * {@code InputStream}. The default encoding scheme is applied.
213     *
214     * @param inStream
215     *            {@code InputStream} with encoded data.
216     * @return a {@code CertPath} initialized from the provided data.
217     * @throws CertificateException
218     *             if parsing problems are detected.
219     */
220    public final CertPath generateCertPath(InputStream inStream) throws CertificateException {
221        Iterator<String> it = getCertPathEncodings();
222        if (!it.hasNext()) {
223            throw new CertificateException("There are no CertPath encodings");
224        }
225        return spiImpl.engineGenerateCertPath(inStream, it.next());
226    }
227
228    /**
229     * Generates a {@code CertPath} (a certificate chain) from the given
230     * {@code inputStream}, assuming the given {@code encoding} from
231     * {@link #getCertPathEncodings()}.
232     *
233     * @throws CertificateException
234     *             if parsing problems are detected.
235     * @throws UnsupportedOperationException
236     *             if the provider does not implement this method.
237     */
238    public final CertPath generateCertPath(InputStream inputStream, String encoding)
239            throws CertificateException {
240        return spiImpl.engineGenerateCertPath(inputStream, encoding);
241    }
242
243    /**
244     * Generates a {@code CertPath} from the provided list of certificates. The
245     * encoding is the default encoding.
246     *
247     * @param certificates
248     *            the list containing certificates in a format supported by the
249     *            {@code CertificateFactory}.
250     * @return a {@code CertPath} initialized from the provided data.
251     * @throws CertificateException
252     *             if parsing problems are detected.
253     * @throws UnsupportedOperationException
254     *             if the provider does not implement this method.
255     */
256    public final CertPath generateCertPath(List<? extends Certificate> certificates)
257            throws CertificateException {
258        return spiImpl.engineGenerateCertPath(certificates);
259    }
260
261    /**
262     * Generates and initializes a collection of (unrelated) certificates from
263     * the provided input stream.
264     *
265     * @param inStream
266     *            the stream from which the data is read to create the
267     *            collection.
268     * @return an initialized collection of certificates.
269     * @throws CertificateException
270     *             if parsing problems are detected.
271     */
272    public final Collection<? extends Certificate> generateCertificates(InputStream inStream)
273            throws CertificateException {
274        return spiImpl.engineGenerateCertificates(inStream);
275    }
276
277    /**
278     * Generates and initializes a <i>Certificate Revocation List</i> (CRL) from
279     * the provided input stream.
280     *
281     * @param inStream
282     *            the stream from where data is read to create the CRL.
283     * @return an initialized CRL.
284     * @throws CRLException
285     *                if parsing problems are detected.
286     */
287    public final CRL generateCRL(InputStream inStream) throws CRLException {
288        return spiImpl.engineGenerateCRL(inStream);
289    }
290
291    /**
292     * Generates and initializes a collection of <i>Certificate Revocation
293     * List</i> (CRL) from the provided input stream.
294     *
295     * @param inStream
296     *            the stream from which the data is read to create the CRLs.
297     * @return an initialized collection of CRLs.
298     * @throws CRLException
299     *                if parsing problems are detected.
300     */
301    public final Collection<? extends CRL> generateCRLs(InputStream inStream)
302            throws CRLException {
303        return spiImpl.engineGenerateCRLs(inStream);
304    }
305}
306