1 /*
2  * Copyright (c) 2003, 2015, 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 import static java.lang.System.out;
25 
26 import java.io.ByteArrayInputStream;
27 import java.io.File;
28 import java.io.FileNotFoundException;
29 import java.io.FileOutputStream;
30 import java.io.IOException;
31 import java.nio.file.Files;
32 import java.nio.file.Paths;
33 import java.security.Key;
34 import java.security.KeyStore;
35 import java.security.KeyStoreException;
36 import java.security.NoSuchAlgorithmException;
37 import java.security.NoSuchProviderException;
38 import java.security.UnrecoverableKeyException;
39 import java.security.cert.Certificate;
40 import java.security.cert.CertificateException;
41 import java.security.cert.CertificateFactory;
42 import java.security.cert.X509Certificate;
43 import java.util.Arrays;
44 import java.util.Base64;
45 import java.util.Enumeration;
46 
47 /*
48  * @test
49  * @bug 8048618
50  * @summary Write different types p12 key store to Check the write related
51  *  APIs.
52  * @run main WriteP12Test
53  */
54 
55 public class WriteP12Test {
56 
57     private static final String IN_KEYSTORE_TYPE = "jks";
58     private static final String IN_KEYSTORE_PRV = "SUN";
59 
60     private static final String IN_KEYSTORE_ENDUSER = "keystoreEU.jks.data";
61     private static final String IN_KEYSTORE_CA = "keystoreCA.jks.data";
62     private static final String OUT_KEYSTORE = "outKeyStore.p12";
63 
64     private static final String IN_STORE_PASS = "storepass";
65     private static final String IN_KEY_PASS = "keypass";
66 
67     private static final String CERT_PATH = System.getProperty("test.src", ".")
68             + File.separator + "certs" + File.separator + "writeP12"
69             + File.separator;
70 
71     private static final String CA_CERT_STR = "-----BEGIN CERTIFICATE-----\n"
72             + "MIIDFzCCAf8CBD8+0nAwDQYJKoZIhvcNAQEFBQAwUDELMAkGA1UEBhMCV\n"
73             + "VMxETAPBgNVBAoTCEphdmFTb2Z0MRUwEwYDVQQLEwxTZWN1cml0eSBTUU\n"
74             + "UxFzAVBgNVBAMTDlBLQ1MxMiBUZXN0IENBMB4XDTAzMDgxNzAwNTUxMlo\n"
75             + "XDTEzMDgxNDAwNTUxMlowUDELMAkGA1UEBhMCVVMxETAPBgNVBAoTCEph\n"
76             + "dmFTb2Z0MRUwEwYDVQQLEwxTZWN1cml0eSBTUUUxFzAVBgNVBAMTDlBLQ\n"
77             + "1MxMiBUZXN0IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQ\n"
78             + "EAk7Sh+K/yGsmJacZnjfkZfuWxGNJCPW0q69exwoRP+eBHMQwG00yi9aL\n"
79             + "SsZAqNpJSCDvpgySOAUmBd+f8WFhHqJfRVREVfv3mradDKZCjhqtsUI7I\n"
80             + "wRTYYy9clFkeeK4dHaxbuFMPpUu7yQfwSTXgvOA/UJ4kJuGtaYAdTJI4e\n"
81             + "f1mUASo6+dea0UZA/FHCuV7O6z3hr5VHlyhJL2/o/8M5tGBTBISODJSnn\n"
82             + "GNBvtQLNHnWYvs470UAE2BtuCGYh1V/3HAH1tRirS3MBBcb1XnIkiiXR3\n"
83             + "tjaBSB+XhoCfuG8KtInXXFaAnvKfY9mYFw6VJt9JYQpY2VDC7281/Pbz0\n"
84             + "dQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQBzXZ8zHWrnC8/E+N/n2Czhx\n"
85             + "i18YQc2LPWBDLYTTxoFEazWmYLv1k/JT7Nta1qu1quvxXJ4uV1XHbd9NF\n"
86             + "AJWKwtFQEpfv4o6I7qWUPoxnfA+jyqKXxv27z25tzt+Y4xOEhqvO03G0Q\n"
87             + "imhkiNt9MF7L69y2U0/U73+uFNGzdAEDiI9EibvICiOnr1TeQ5GekK3Yb\n"
88             + "k5qe3lviMZPkkSXepTJI8m0AiXCji+eXj97jVLeH+RxeBchBY+uELrqUr\n"
89             + "sVOVWh7IBCqC/V7FqUTkmD1IFlzkkinatpl42s1MbhJId2yQkzaeBRc\n"
90             + "suE63bDEtuRWp9ynMO3QA4Yu85uBRWGzQ1Di\n"
91             + "-----END CERTIFICATE-----";
92     private static final String LEAD_CERT = "-----BEGIN CERTIFICATE-----\n"
93             + "MIICwDCCAaigAwIBAgIEPz7S1jANBgkqhkiG9w0BAQQFADBQMQswCQYDV\n"
94             + "QQGEwJVUzERMA8GA1UEChMISmF2YVNvZnQxFTATBgNVBAsTDFNlY3VyaX\n"
95             + "R5IFNRRTEXMBUGA1UEAxMOUEtDUzEyIFRlc3QgQ0EwHhcNMDAwODA5MDc\n"
96             + "wMDAwWhcNMTAwODA3MDcwMDAwWjBSMQswCQYDVQQGEwJVUzERMA8GA1UE\n"
97             + "ChMISmF2YVNvZnQxFTATBgNVBAsTDFNlY3VyaXR5IFNRRTEZMBcGA1UEA\n"
98             + "xMQUEtDUzEyIFRlc3QgTGVhZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgY\n"
99             + "kCgYEAzq9X2USz/WjDhT+jUyZWqB5h4A33tS11YqH5qYvqjTXjcUI6gOp\n"
100             + "moXMafDG9RHRlIccvp51xLp7Ap3WMrv411lWBttqtZi5c1/DEC1cEM/Sl\n"
101             + "PCk1r2zFbkJu7QKieXeMcrjZEo6LcBHMwQjIpI+up9cr3VjuyqG/olQkU\n"
102             + "mXVuS0CAwEAAaMkMCIwDwYDVR0PAQH/BAUDAweAADAPBgNVHRMBAf8EBT\n"
103             + "ADAQH/MA0GCSqGSIb3DQEBBAUAA4IBAQBhbuim98TWmtv9vSldRE7RvQ8\n"
104             + "FlS0TyZVO7kcSNtfCUE4R76J1ElN74Koc5pQnUtduLeQJs2ao/mEcCZsE\n"
105             + "zVcwI3mSZrSzPhc8s7w5gOQA4TUwVLSSjKgBCaZ7R3+qJ3QeqPJ5O6sFz\n"
106             + "pvBYkgSa4MWptK41jbmT8cwZQJXFCi8WxFFJ+p97F1Ppm3LgmYmtiUP4M\n"
107             + "ZQwOBvpTZWXU0WrqFXpzWQx0mg4SX19fZm4nLcJAerCEUphf8ILagtpQM\n"
108             + "EErT3/jg6mfCdT3Rj055QXPfF4OiRFevPF5a1fZgrCePCukRQZcd7s8K5\n"
109             + "OBIaryuM0MdFtlzxi6XWeUNpVFFHURcy\n"
110             + "-----END CERTIFICATE-----";
111     private static final String END_CERT = "-----BEGIN CERTIFICATE-----\n"
112             + "MIICNjCCAZ+gAwIBAgIEPz7WtzANBgkqhkiG9w0BAQQFADBSMQswCQYDV\n"
113             + "QQGEwJVUzERMA8GA1UEChMISmF2YVNvZnQxFTATBgNVBAsTDFNlY3VyaX\n"
114             + "R5IFNRRTEZMBcGA1UEAxMQUEtDUzEyIFRlc3QgTGVhZDAeFw0wMDA4MDk\n"
115             + "wNzAwMDBaFw0xMDA4MDcwNzAwMDBaMFgxCzAJBgNVBAYTAlVTMREwDwYD\n"
116             + "VQQKEwhKYXZhU29mdDEVMBMGA1UECxMMU2VjdXJpdHkgU1FFMR8wHQYDV\n"
117             + "QQDExZQS0NTMTIgVGVzdCBFbmQgVXNlciAxMIGfMA0GCSqGSIb3DQEBAQ\n"
118             + "UAA4GNADCBiQKBgQDIKomSYomDzH/V63eDQEG7od0DLcnnVZ81pbWhDss\n"
119             + "8gHV2m8pADdRqdihBmnSQEaMW4D3uZ4sFE1LtkQls6hjd7SdOsG5Y24L8\n"
120             + "15jot9a2JcB73H8H0VKirrObL5BZdt7BtASPDnYtW4Spt++YjDoJFxyF0\n"
121             + "HchkavzXaVTlexakwIDAQABoxMwETAPBgNVHQ8BAf8EBQMDB4AAMA0GCS\n"
122             + "qGSIb3DQEBBAUAA4GBAIFA3JXEmb9AXn3RD7t+Mn6DoyVDIy5jsn6xOKT\n"
123             + "JV25I0obpDUzgw4QaAMmM0ZvusOmZ2wZNS8MtyTUgdANyakbzn5SdxbTy\n"
124             + "TLEqQsFbX8UVC38fx5ZM6ExA5YSAvgmXudZpOVC0ATccoZS3JFU8CxSfW\n"
125             + "+Q3IC2MLh+QTg3hUJ5b\n-----END CERTIFICATE-----";
126 
127     private final Certificate testerCert;
128     private final Certificate testLeadCert;
129     private final Certificate caCert;
130 
WriteP12Test()131     WriteP12Test() throws CertificateException {
132         CertificateFactory cf = CertificateFactory.getInstance("X.509");
133         caCert = cf.generateCertificate(new ByteArrayInputStream(CA_CERT_STR
134                 .getBytes()));
135         testLeadCert = cf.generateCertificate(new ByteArrayInputStream(
136                 LEAD_CERT.getBytes()));
137         testerCert = cf.generateCertificate(new ByteArrayInputStream(END_CERT
138                 .getBytes()));
139     }
140 
main(String[] args)141     public static void main(String[] args) throws CertificateException,
142             UnrecoverableKeyException, KeyStoreException,
143             NoSuchProviderException, NoSuchAlgorithmException, IOException {
144         WriteP12Test jstest = new WriteP12Test();
145         out.println("test WriteP12CertChain");
146         /*
147          * WriteP12CertChain: This test creates a p12 keystore contains one
148          * entry with private key and a certificate chains contains three
149          * certificates in the order of user->lead->ca. This case expects to
150          * pass.
151          */
152         jstest.test(new Certificate[] { jstest.testerCert, jstest.testLeadCert,
153                 jstest.caCert }, IN_KEYSTORE_ENDUSER, "pkcs12testenduser1",
154                 "pass", "pass");
155 
156         /*
157          * WriteP12CertChainBad: same as WriteP12CertChain but chains order is
158          * user-ca-lead, the order is wrong so expects to fail.
159          */
160         out.println("test WriteP12CertChainBad");
161         try {
162             jstest.test(new Certificate[] { jstest.testerCert, jstest.caCert,
163                     jstest.testLeadCert }, IN_KEYSTORE_ENDUSER,
164                     "pkcs12testenduser1", "pass", "pass");
165             throw new RuntimeException(
166                     " Certificate chain is not valid, test should not pass."
167                             + " Test failed.");
168         } catch (KeyStoreException e) {
169             e.printStackTrace();
170             out.println(" Certificate chain is not valid,exception is"
171                     + " expected. Test passed.");
172         }
173         /*
174          * WriteP12PrivateKey:This test creates a p12 contains a self-signed
175          * cert and private key,expects no exception
176          */
177         out.println("test WriteP12PrivateKey");
178         jstest.test(null, IN_KEYSTORE_ENDUSER, "pkcs12testenduser1", "pass",
179                 "pass");
180 
181         /*
182          * WriteP12TwoEntry: This test creates a p12 keystore with different
183          * storepass and keypass, and contains two entries.
184          */
185         out.println("test WriteP12TwoEntry");
186         jstest.testTwoEntry(IN_KEYSTORE_ENDUSER, IN_KEYSTORE_CA,
187                 "pkcs12testenduser1", "pass", "pass");
188         /*
189          * WriteP12TwoPass: This test creates a p12 keystore with different
190          * storepass and keypass, and contains one entry with private key and a
191          * certificate
192          */
193         out.println("test WriteP12TwoPass");
194         jstest.test(null, IN_KEYSTORE_CA, "pkcs12testCA", "storepass",
195                 "keypass");
196     }
197 
test(Certificate certs[], String inKeyStorePath, String userAlias, String outStorePass, String outKeyPass)198     private void test(Certificate certs[], String inKeyStorePath,
199             String userAlias, String outStorePass, String outKeyPass)
200             throws KeyStoreException, NoSuchProviderException, IOException,
201             CertificateException, UnrecoverableKeyException,
202             NoSuchAlgorithmException {
203         // init output key store
204         KeyStore outputKeyStore = KeyStore.getInstance("pkcs12", "SunJSSE");
205         outputKeyStore.load(null, null);
206         try (FileOutputStream fout = new FileOutputStream(OUT_KEYSTORE)) {
207             // KeyStore have encoded by Base64.getMimeEncoder().encode(),need
208             // decode first.
209             byte[] input = Files.readAllBytes(Paths.get(CERT_PATH,
210                     inKeyStorePath));
211             ByteArrayInputStream arrayIn = new ByteArrayInputStream(Base64
212                     .getMimeDecoder().decode(input));
213             // input key store
214             KeyStore inputKeyStore = KeyStore.getInstance(IN_KEYSTORE_TYPE,
215                     IN_KEYSTORE_PRV);
216             inputKeyStore.load(arrayIn, IN_STORE_PASS.toCharArray());
217             // add key/certificate to output key store
218             Key key = inputKeyStore
219                     .getKey(userAlias, IN_KEY_PASS.toCharArray());
220             out.println("Input Key Algorithm " + key.getAlgorithm());
221             out.println("====Input Certs=====");
222             if (certs == null) {
223                 certs = new Certificate[] { inputKeyStore
224                         .getCertificate(userAlias) };
225             }
226             for (Certificate cert : certs) {
227                 out.println(((X509Certificate) cert).getSubjectDN());
228             }
229             outputKeyStore.setKeyEntry(userAlias, key,
230                     outKeyPass.toCharArray(), certs);
231             Certificate retCerts[] = outputKeyStore
232                     .getCertificateChain(userAlias);
233             out.println("====Output Certs=====");
234             for (Certificate retCert : retCerts) {
235                 out.println(((X509Certificate) retCert).getSubjectDN());
236             }
237             out.println("====Output Key Algorithm=====");
238             Key outKey = outputKeyStore.getKey(userAlias,
239                     outKeyPass.toCharArray());
240             out.println(outKey.getAlgorithm());
241 
242             if (!key.equals(outKey)) {
243                 throw new RuntimeException("key don't match");
244             }
245             if (!Arrays.equals(certs, retCerts)) {
246                 throw new RuntimeException("certs don't match");
247             }
248             // save output
249             outputKeyStore.store(fout, outStorePass.toCharArray());
250             // test output
251             testKeyStore(outputKeyStore, outKeyPass.toCharArray());
252         }
253     }
254 
testTwoEntry(String inKeyStoreOnePath, String inKeyStoreTwoPath, String userAlias, String outStorePass, String outKeyPass)255     private void testTwoEntry(String inKeyStoreOnePath,
256             String inKeyStoreTwoPath, String userAlias, String outStorePass,
257             String outKeyPass) throws KeyStoreException,
258             NoSuchProviderException, NoSuchAlgorithmException,
259             CertificateException, IOException, UnrecoverableKeyException {
260         // initial KeyStore
261         KeyStore outputKeyStore = KeyStore.getInstance("pkcs12", "SunJSSE");
262         try (FileOutputStream fout = new FileOutputStream(OUT_KEYSTORE);) {
263             outputKeyStore.load(null, null);
264             KeyStore inputKeyStoreOne, inputKeyStoreTwo;
265             inputKeyStoreOne = KeyStore.getInstance(IN_KEYSTORE_TYPE,
266                     IN_KEYSTORE_PRV);
267             // KeyStore have encoded by Base64.getMimeEncoder().encode(),need
268             // decode first.
269             byte[] inputBytes = Files.readAllBytes(Paths.get(CERT_PATH,
270                     inKeyStoreOnePath));
271             ByteArrayInputStream arrayIn = new ByteArrayInputStream(Base64
272                     .getMimeDecoder().decode(inputBytes));
273             // input key store
274             inputKeyStoreOne.load(arrayIn, IN_STORE_PASS.toCharArray());
275 
276             inputBytes = Files.readAllBytes(Paths.get(CERT_PATH,
277                     inKeyStoreTwoPath));
278             arrayIn = new ByteArrayInputStream(Base64.getMimeDecoder().decode(
279                     inputBytes));
280             inputKeyStoreTwo = KeyStore.getInstance(IN_KEYSTORE_TYPE,
281                     IN_KEYSTORE_PRV);
282             inputKeyStoreTwo.load(arrayIn, IN_STORE_PASS.toCharArray());
283 
284             // add key/certificate to output key store
285             out.println("====First Entry=====");
286             Key inputKey = inputKeyStoreOne.getKey(userAlias,
287                     IN_KEY_PASS.toCharArray());
288             Certificate cert = inputKeyStoreOne.getCertificate(userAlias);
289             Certificate certs[] = new Certificate[1];
290             certs[0] = cert;
291 
292             out.println("====Input1 Key=====");
293             out.println(inputKey.getAlgorithm());
294             out.println("====Input1 Certs=====");
295             out.println("Certificate :");
296             out.println(((X509Certificate) cert).getSubjectDN());
297             outputKeyStore.setKeyEntry("USER", inputKey,
298                     outKeyPass.toCharArray(), certs);
299             out.println("====Second Entry=====");
300             String caAlias = "pkcs12testca";
301             inputKey = inputKeyStoreTwo.getKey(caAlias,
302                     IN_KEY_PASS.toCharArray());
303             cert = inputKeyStoreTwo.getCertificate(caAlias);
304             certs[0] = cert;
305             out.println("====Input2 Key=====");
306             out.println(inputKey.getAlgorithm());
307             out.println("====Input2 Certs=====");
308             out.println("Certificate :");
309             out.println(((X509Certificate) cert).getSubjectDN());
310             outputKeyStore.setKeyEntry("CA", inputKey,
311                     outKeyPass.toCharArray(), certs);
312             // save output
313             outputKeyStore.store(fout, outStorePass.toCharArray());
314             // test output
315             testKeyStore(outputKeyStore, outKeyPass.toCharArray());
316         }
317     }
318 
testKeyStore(KeyStore inputKeyStore, char[] keypass)319     private void testKeyStore(KeyStore inputKeyStore, char[] keypass)
320             throws KeyStoreException, UnrecoverableKeyException,
321             NoSuchAlgorithmException {
322         out.println("========== Key Store ==========");
323         out.println("getProvider : " + inputKeyStore.getProvider());
324         out.println("getType : " + inputKeyStore.getType());
325         out.println("getDefaultType : " + KeyStore.getDefaultType());
326 
327         int idx = 0;
328         Enumeration<String> e = inputKeyStore.aliases();
329         String alias;
330         while (e.hasMoreElements()) {
331             alias = e.nextElement();
332             if (!inputKeyStore.containsAlias(alias)) {
333                 throw new RuntimeException("Alias not found");
334             }
335             out.println("Alias " + idx + " : " + alias);
336             out.println("getCreationDate : "
337                     + inputKeyStore.getCreationDate(alias));
338             X509Certificate cert = (X509Certificate) inputKeyStore
339                     .getCertificate(alias);
340             out.println("getCertificate : " + cert.getSubjectDN());
341             String retAlias = inputKeyStore.getCertificateAlias(cert);
342             if (!retAlias.equals(alias)) {
343                 throw new RuntimeException("Alias mismatch, actually "
344                         + retAlias + ", expected " + alias);
345             }
346             out.println("getCertificateAlias : " + retAlias);
347             Certificate[] certs = inputKeyStore.getCertificateChain(alias);
348             int i = 0;
349             for (Certificate certification : certs) {
350                 out.println("getCertificateChain " + i
351                         + ((X509Certificate) certification).getSubjectDN());
352                 i++;
353             }
354             if (inputKeyStore.isCertificateEntry(alias)) {
355                 throw new RuntimeException(
356                         "inputKeystore should not be certEntry because this"
357                                 + " keystore only contain key pair entries.");
358             }
359             if (!inputKeyStore.isKeyEntry(alias)) {
360                 throw new RuntimeException("Entry type unknown.");
361             }
362             idx++;
363         }
364         int size = inputKeyStore.size();
365         if (idx != size) {
366             throw new RuntimeException("Size not match, actually " + idx
367                     + ", expected " + size);
368         }
369     }
370 
371 }
372