1/*
2 * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24/**
25 *
26 * @author Sean Mullan
27 * @author Steve Hanna
28 *
29 */
30import java.io.ByteArrayOutputStream;
31import java.io.File;
32import java.io.FileInputStream;
33import java.io.InputStream;
34import java.io.IOException;
35import java.security.cert.CertificateFactory;
36import java.security.cert.CertPath;
37import java.security.cert.CertPathBuilder;
38import java.security.cert.CertPathValidator;
39import java.security.cert.CertStore;
40import java.security.cert.CollectionCertStoreParameters;
41import java.security.cert.PKIXBuilderParameters;
42import java.security.cert.PKIXCertPathBuilderResult;
43import java.security.cert.PKIXCertPathValidatorResult;
44import java.security.cert.PKIXParameters;
45import java.security.cert.X509Certificate;
46import java.security.cert.X509CRL;
47import java.util.ArrayList;
48import java.util.HashSet;
49import java.util.List;
50import java.util.Set;
51
52/**
53 * Static utility methods useful for testing certificate/certpath APIs.
54 */
55public class CertUtils {
56
57    private CertUtils() {}
58
59    /**
60     * Get a DER-encoded X.509 certificate from a file.
61     *
62     * @param certFilePath path to file containing DER-encoded certificate
63     * @return X509Certificate
64     * @throws IOException on error
65     */
66    public static X509Certificate getCertFromFile(String certFilePath)
67        throws IOException {
68            X509Certificate cert = null;
69            try {
70                File certFile = new File(System.getProperty("test.src", "."),
71                    certFilePath);
72                if (!certFile.canRead())
73                    throw new IOException("File " +
74                                          certFile.toString() +
75                                          " is not a readable file.");
76                FileInputStream certFileInputStream =
77                    new FileInputStream(certFile);
78                CertificateFactory cf = CertificateFactory.getInstance("X509");
79                cert = (X509Certificate)
80                    cf.generateCertificate(certFileInputStream);
81            } catch (Exception e) {
82                e.printStackTrace();
83                throw new IOException("Can't construct X509Certificate: " +
84                                      e.getMessage());
85            }
86            return cert;
87    }
88
89    /**
90     * Get a DER-encoded X.509 CRL from a file.
91     *
92     * @param crlFilePath path to file containing DER-encoded CRL
93     * @return X509CRL
94     * @throws IOException on error
95     */
96    public static X509CRL getCRLFromFile(String crlFilePath)
97        throws IOException {
98            X509CRL crl = null;
99            try {
100                File crlFile = new File(System.getProperty("test.src", "."),
101                    crlFilePath);
102                if (!crlFile.canRead())
103                    throw new IOException("File " +
104                                          crlFile.toString() +
105                                          " is not a readable file.");
106                FileInputStream crlFileInputStream =
107                    new FileInputStream(crlFile);
108                CertificateFactory cf = CertificateFactory.getInstance("X509");
109                crl = (X509CRL) cf.generateCRL(crlFileInputStream);
110            } catch (Exception e) {
111                e.printStackTrace();
112                throw new IOException("Can't construct X509CRL: " +
113                                      e.getMessage());
114            }
115            return crl;
116    }
117
118    /**
119     * Read a bunch of certs from files and create a CertPath from them.
120     *
121     * @param fileNames an array of <code>String</code>s that are file names
122     * @throws Exception on error
123     */
124    public static CertPath buildPath(String [] fileNames) throws Exception {
125        return buildPath("", fileNames);
126    }
127
128    /**
129     * Read a bunch of certs from files and create a CertPath from them.
130     *
131     * @param relPath relative path containing certs (must end in
132     *    file.separator)
133     * @param fileNames an array of <code>String</code>s that are file names
134     * @throws Exception on error
135     */
136    public static CertPath buildPath(String relPath, String [] fileNames)
137        throws Exception {
138        List<X509Certificate> list = new ArrayList<X509Certificate>();
139        for (int i = 0; i < fileNames.length; i++) {
140            list.add(0, getCertFromFile(relPath + fileNames[i]));
141        }
142        CertificateFactory cf = CertificateFactory.getInstance("X509");
143        return(cf.generateCertPath(list));
144    }
145
146
147    /**
148     * Read a bunch of certs from files and create a CertStore from them.
149     *
150     * @param fileNames an array of <code>String</code>s that are file names
151     * @return the <code>CertStore</code> created
152     * @throws Exception on error
153     */
154    public static CertStore createStore(String [] fileNames) throws Exception {
155        return createStore("", fileNames);
156    }
157
158    /**
159     * Read a bunch of certs from files and create a CertStore from them.
160     *
161     * @param relPath relative path containing certs (must end in
162     *    file.separator)
163     * @param fileNames an array of <code>String</code>s that are file names
164     * @return the <code>CertStore</code> created
165     * @throws Exception on error
166     */
167    public static CertStore createStore(String relPath, String [] fileNames)
168        throws Exception {
169        Set<X509Certificate> certs = new HashSet<X509Certificate>();
170        for (int i = 0; i < fileNames.length; i++) {
171            certs.add(getCertFromFile(relPath + fileNames[i]));
172        }
173        return CertStore.getInstance("Collection",
174            new CollectionCertStoreParameters(certs));
175    }
176
177    /**
178     * Read a bunch of CRLs from files and create a CertStore from them.
179     *
180     * @param fileNames an array of <code>String</code>s that are file names
181     * @return the <code>CertStore</code> created
182     * @throws Exception on error
183     */
184    public static CertStore createCRLStore(String [] fileNames)
185        throws Exception {
186        return createCRLStore("", fileNames);
187    }
188
189    /**
190     * Read a bunch of CRLs from files and create a CertStore from them.
191     *
192     * @param relPath relative path containing CRLs (must end in file.separator)
193     * @param fileNames an array of <code>String</code>s that are file names
194     * @return the <code>CertStore</code> created
195     * @throws Exception on error
196     */
197    public static CertStore createCRLStore(String relPath, String [] fileNames)
198        throws Exception {
199        Set<X509CRL> crls = new HashSet<X509CRL>();
200        for (int i = 0; i < fileNames.length; i++) {
201            crls.add(getCRLFromFile(relPath + fileNames[i]));
202        }
203        return CertStore.getInstance("Collection",
204            new CollectionCertStoreParameters(crls));
205    }
206
207    /**
208     * Perform a PKIX path build. On failure, throw an exception.
209     *
210     * @param params PKIXBuilderParameters to use in validation
211     * @throws Exception on error
212     */
213    public static PKIXCertPathBuilderResult build(PKIXBuilderParameters params)
214        throws Exception {
215        CertPathBuilder builder =
216            CertPathBuilder.getInstance("PKIX");
217        return (PKIXCertPathBuilderResult) builder.build(params);
218    }
219
220    /**
221     * Perform a PKIX validation. On failure, throw an exception.
222     *
223     * @param path CertPath to validate
224     * @param params PKIXParameters to use in validation
225     * @throws Exception on error
226     */
227    public static PKIXCertPathValidatorResult validate
228        (CertPath path, PKIXParameters params) throws Exception {
229        CertPathValidator validator =
230            CertPathValidator.getInstance("PKIX");
231        return (PKIXCertPathValidatorResult) validator.validate(path, params);
232    }
233
234    /*
235     * Reads the entire input stream into a byte array.
236     */
237    private static byte[] getTotalBytes(InputStream is) throws IOException {
238           byte[] buffer = new byte[8192];
239        ByteArrayOutputStream baos = new ByteArrayOutputStream(2048);
240        int n;
241        baos.reset();
242        while ((n = is.read(buffer, 0, buffer.length)) != -1) {
243            baos.write(buffer, 0, n);
244        }
245        return baos.toByteArray();
246    }
247}
248