| /* | |
| * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| import static java.lang.System.out; | |
| import java.io.ByteArrayInputStream; | |
| import java.io.File; | |
| import java.io.FileOutputStream; | |
| import java.nio.file.Files; | |
| import java.nio.file.Paths; | |
| import java.security.Key; | |
| import java.security.KeyStore; | |
| import java.security.KeyStoreException; | |
| import java.security.NoSuchAlgorithmException; | |
| import java.security.UnrecoverableKeyException; | |
| import java.security.cert.Certificate; | |
| import java.util.Arrays; | |
| import java.util.Base64; | |
| import java.util.Enumeration; | |
| /* | |
| * @test | |
| * @bug 8048619 | |
| * @author Bill Situ | |
| * @summary Test converting keystore from jceks to P12 and from P12 to other | |
| * (jceks,jks). including following test cases: | |
| * Read jceks key store and convert to the p12 key store, then compare entries | |
| * in the two key stores. | |
| * Read p12 key store and convert to the jceks key store, then compare entries | |
| * in the two key stores. | |
| * Read p12 key store (contains only private key and a self-signed certificate) | |
| * and convert to the jceks key store, then compare entries of two key stores. | |
| * Read p12 key store (contains 2 entries) and convert to the jceks key store, | |
| * then compare entries in the two key stores. | |
| * Read p12 key store (entry password and key store password are different) and | |
| * convert to the jceks key store, then compare entries in the two key stores. | |
| * Read p12 key store and convert to the jks key store, then compare entries | |
| * in the two key stores. | |
| * Read p12 key store (contains only private key and a self-signed certificate) | |
| * and convert to the jks key store, then compare entries in the two key stores. | |
| * Read p12 key store (contains 2 entries) and convert to the jks key store, | |
| * then compare entries in the two key stores. | |
| * Read p12 key store (entry password and key store password are different) and | |
| * convert to the jks key store, then compare entries in the two key stores. | |
| */ | |
| public class ConvertP12Test { | |
| private static final String SUN_JSSE = "SunJSSE"; | |
| private static final String SUN_JCE = "SunJCE"; | |
| private static final String SUN = "SUN"; | |
| private static final String PKCS12 = "pkcs12"; | |
| private static final String JCE_KS = "JceKS"; | |
| private static final String JKS = "JKS"; | |
| public static void main(String args[]) throws Exception { | |
| ConvertP12Test jstest = new ConvertP12Test(); | |
| jstest.driver("JceksToP12", "keystoreCA.jceks.data", JCE_KS, SUN_JCE, | |
| "storepass", "keypass", PKCS12, SUN_JSSE); | |
| jstest.driver("P12ToJceks_Chain", "ie_jceks_chain.pfx.data", PKCS12, | |
| SUN_JSSE, "pass", "pass", JCE_KS, SUN_JCE); | |
| jstest.driver("P12ToJceks_SelfSigned", "jdk_jceks_selfsigned.p12.data", | |
| PKCS12, SUN_JSSE, "pass", "pass", JCE_KS, SUN_JCE); | |
| jstest.driver("P12ToJceks_TwoEntry", "jdk_jceks_twoentry.p12.data", | |
| PKCS12, SUN_JSSE, "pass", "pass", JCE_KS, SUN_JCE); | |
| jstest.driver("P12ToJceks_TwoPass", "jdk_jceks_twopass.p12.data", | |
| PKCS12, SUN_JSSE, "storepass", "keypass", JCE_KS, SUN_JCE); | |
| jstest.driver("P12ToJks_Chain", "ie_jks_chain.pfx.data", PKCS12, | |
| SUN_JSSE, "pass", "pass", JKS, SUN); | |
| jstest.driver("P12ToJks_SelfSigned", "jdk_jks_selfsigned.p12.data", | |
| PKCS12, SUN_JSSE, "pass", "pass", JKS, SUN); | |
| jstest.driver("P12ToJks_TwoEntry", "jdk_jks_twoentry.p12.data", PKCS12, | |
| SUN_JSSE, "pass", "pass", JKS, SUN); | |
| jstest.driver("P12ToJks_TwoPass", "jdk_jks_twopass.p12.data", PKCS12, | |
| SUN_JSSE, "storepass", "keypass", JKS, SUN); | |
| } | |
| private void driver(String testCase, String inKeyStore, | |
| String inKeyStoreType, String inKeyStoreTypePrv, | |
| String inStorePass, String inKeyPass, String outKeyStoreType, | |
| String outKeyStorePrv) throws Exception { | |
| String outStorePass = "pass"; | |
| String outKeyPass = "pass"; | |
| KeyStore inputKeyStore, outputKeyStore; | |
| out.println("Testing " + testCase); | |
| String keystorePath = System.getProperty("test.src", ".") | |
| + File.separator + "certs" + File.separator + "convertP12"; | |
| out.println("Output KeyStore : " + inKeyStore + ".out"); | |
| String outKeyStoreName = inKeyStore + ".out"; | |
| try (FileOutputStream fout = new FileOutputStream(outKeyStoreName);) { | |
| inputKeyStore = KeyStore.getInstance(inKeyStoreType, | |
| inKeyStoreTypePrv); | |
| // KeyStore have encoded by Base64.getMimeEncoder().encode(),need | |
| // decode first. | |
| byte[] input = Files.readAllBytes(Paths.get(keystorePath, | |
| inKeyStore)); | |
| ByteArrayInputStream arrayIn = new ByteArrayInputStream(Base64 | |
| .getMimeDecoder().decode(input)); | |
| out.println("Input KeyStore : " + inKeyStore); | |
| inputKeyStore.load(arrayIn, inStorePass.toCharArray()); | |
| outputKeyStore = KeyStore.getInstance(outKeyStoreType, | |
| outKeyStorePrv); | |
| outputKeyStore.load(null, null); | |
| run(inputKeyStore, outputKeyStore, inKeyPass, outKeyPass); | |
| outputKeyStore.store(fout, outStorePass.toCharArray()); | |
| // for P12ToJks_TwoEntry test case will test includes each other, | |
| // others just test compareKeystore | |
| if (testCase.contains("TwoEntry")) { | |
| compareKeyStore(inputKeyStore, outputKeyStore, inKeyPass, | |
| outKeyPass, 2); | |
| compareKeyStore(outputKeyStore, inputKeyStore, outKeyPass, | |
| inKeyPass, 2); | |
| } else { | |
| compareKeyStore(inputKeyStore, outputKeyStore, inKeyPass, | |
| outKeyPass, 1); | |
| } | |
| out.println("Test " + testCase + " STATUS: Pass!!"); | |
| } catch (Exception ex) { | |
| out.println("Test " + testCase + " STATUS: failed with exception: " | |
| + ex.getMessage()); | |
| throw ex; | |
| } | |
| } | |
| private void run(KeyStore inputKeyStore, KeyStore outputKeyStore, | |
| String inKeyPass, String outKeyPass) throws Exception { | |
| Enumeration<String> e = inputKeyStore.aliases(); | |
| String alias; | |
| while (e.hasMoreElements()) { | |
| alias = e.nextElement(); | |
| Certificate[] certs = inputKeyStore.getCertificateChain(alias); | |
| boolean isCertEntry = inputKeyStore.isCertificateEntry(alias); | |
| // Test KeyStore only contain key pair entries. | |
| if (isCertEntry == true) { | |
| throw new RuntimeException( | |
| "inputKeystore should not be certEntry because test" | |
| + " keystore only contain key pair entries" | |
| + " for alias:" + alias); | |
| } | |
| boolean isKeyEntry = inputKeyStore.isKeyEntry(alias); | |
| Key key = null; | |
| if (isKeyEntry) { | |
| key = inputKeyStore.getKey(alias, inKeyPass.toCharArray()); | |
| } else { | |
| throw new RuntimeException("Entry type unknown for alias:" | |
| + alias); | |
| } | |
| outputKeyStore.setKeyEntry(alias, key, outKeyPass.toCharArray(), | |
| certs); | |
| } | |
| } | |
| private void compareKeyStore(KeyStore a, KeyStore b, String inKeyPass, | |
| String outKeyPass, int keyStoreSize) throws Exception { | |
| if (a.size() != keyStoreSize || b.size() != keyStoreSize) { | |
| throw new RuntimeException("size not match or size not equal to " | |
| + keyStoreSize); | |
| } | |
| Enumeration<String> eA = a.aliases(); | |
| while (eA.hasMoreElements()) { | |
| String aliasA = eA.nextElement(); | |
| if (!b.containsAlias(aliasA)) { | |
| throw new RuntimeException("alias not match for alias:" | |
| + aliasA); | |
| } | |
| compareKeyEntry(a, b, inKeyPass, outKeyPass, aliasA); | |
| } | |
| } | |
| private void compareKeyEntry(KeyStore a, KeyStore b, String aPass, | |
| String bPass, String alias) throws KeyStoreException, | |
| UnrecoverableKeyException, NoSuchAlgorithmException { | |
| Certificate[] certsA = a.getCertificateChain(alias); | |
| Certificate[] certsB = b.getCertificateChain(alias); | |
| if (!Arrays.equals(certsA, certsB)) { | |
| throw new RuntimeException("Certs don't match for alias:" + alias); | |
| } | |
| Key keyA = a.getKey(alias, aPass.toCharArray()); | |
| Key keyB = b.getKey(alias, bPass.toCharArray()); | |
| if (!keyA.equals(keyB)) { | |
| throw new RuntimeException( | |
| "Key don't match for alias:" + alias); | |
| } | |
| } | |
| } |