/* * Copyright (c) 2003, 2015, 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.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; 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.NoSuchProviderException; import java.security.UnrecoverableKeyException; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.Base64; import java.util.Enumeration; /* * @test * @bug 8048618 * @summary Write different types p12 key store to Check the write related * APIs. * @run main WriteP12Test */ public class WriteP12Test { private static final String IN_KEYSTORE_TYPE = "jks"; private static final String IN_KEYSTORE_PRV = "SUN"; private static final String IN_KEYSTORE_ENDUSER = "keystoreEU.jks.data"; private static final String IN_KEYSTORE_CA = "keystoreCA.jks.data"; private static final String OUT_KEYSTORE = "outKeyStore.p12"; private static final String IN_STORE_PASS = "storepass"; private static final String IN_KEY_PASS = "keypass"; private static final String CERT_PATH = System.getProperty("test.src", ".") + File.separator + "certs" + File.separator + "writeP12" + File.separator; private static final String CA_CERT_STR = "-----BEGIN CERTIFICATE-----\n" + "MIIDFzCCAf8CBD8+0nAwDQYJKoZIhvcNAQEFBQAwUDELMAkGA1UEBhMCV\n" + "VMxETAPBgNVBAoTCEphdmFTb2Z0MRUwEwYDVQQLEwxTZWN1cml0eSBTUU\n" + "UxFzAVBgNVBAMTDlBLQ1MxMiBUZXN0IENBMB4XDTAzMDgxNzAwNTUxMlo\n" + "XDTEzMDgxNDAwNTUxMlowUDELMAkGA1UEBhMCVVMxETAPBgNVBAoTCEph\n" + "dmFTb2Z0MRUwEwYDVQQLEwxTZWN1cml0eSBTUUUxFzAVBgNVBAMTDlBLQ\n" + "1MxMiBUZXN0IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQ\n" + "EAk7Sh+K/yGsmJacZnjfkZfuWxGNJCPW0q69exwoRP+eBHMQwG00yi9aL\n" + "SsZAqNpJSCDvpgySOAUmBd+f8WFhHqJfRVREVfv3mradDKZCjhqtsUI7I\n" + "wRTYYy9clFkeeK4dHaxbuFMPpUu7yQfwSTXgvOA/UJ4kJuGtaYAdTJI4e\n" + "f1mUASo6+dea0UZA/FHCuV7O6z3hr5VHlyhJL2/o/8M5tGBTBISODJSnn\n" + "GNBvtQLNHnWYvs470UAE2BtuCGYh1V/3HAH1tRirS3MBBcb1XnIkiiXR3\n" + "tjaBSB+XhoCfuG8KtInXXFaAnvKfY9mYFw6VJt9JYQpY2VDC7281/Pbz0\n" + "dQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQBzXZ8zHWrnC8/E+N/n2Czhx\n" + "i18YQc2LPWBDLYTTxoFEazWmYLv1k/JT7Nta1qu1quvxXJ4uV1XHbd9NF\n" + "AJWKwtFQEpfv4o6I7qWUPoxnfA+jyqKXxv27z25tzt+Y4xOEhqvO03G0Q\n" + "imhkiNt9MF7L69y2U0/U73+uFNGzdAEDiI9EibvICiOnr1TeQ5GekK3Yb\n" + "k5qe3lviMZPkkSXepTJI8m0AiXCji+eXj97jVLeH+RxeBchBY+uELrqUr\n" + "sVOVWh7IBCqC/V7FqUTkmD1IFlzkkinatpl42s1MbhJId2yQkzaeBRc\n" + "suE63bDEtuRWp9ynMO3QA4Yu85uBRWGzQ1Di\n" + "-----END CERTIFICATE-----"; private static final String LEAD_CERT = "-----BEGIN CERTIFICATE-----\n" + "MIICwDCCAaigAwIBAgIEPz7S1jANBgkqhkiG9w0BAQQFADBQMQswCQYDV\n" + "QQGEwJVUzERMA8GA1UEChMISmF2YVNvZnQxFTATBgNVBAsTDFNlY3VyaX\n" + "R5IFNRRTEXMBUGA1UEAxMOUEtDUzEyIFRlc3QgQ0EwHhcNMDAwODA5MDc\n" + "wMDAwWhcNMTAwODA3MDcwMDAwWjBSMQswCQYDVQQGEwJVUzERMA8GA1UE\n" + "ChMISmF2YVNvZnQxFTATBgNVBAsTDFNlY3VyaXR5IFNRRTEZMBcGA1UEA\n" + "xMQUEtDUzEyIFRlc3QgTGVhZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgY\n" + "kCgYEAzq9X2USz/WjDhT+jUyZWqB5h4A33tS11YqH5qYvqjTXjcUI6gOp\n" + "moXMafDG9RHRlIccvp51xLp7Ap3WMrv411lWBttqtZi5c1/DEC1cEM/Sl\n" + "PCk1r2zFbkJu7QKieXeMcrjZEo6LcBHMwQjIpI+up9cr3VjuyqG/olQkU\n" + "mXVuS0CAwEAAaMkMCIwDwYDVR0PAQH/BAUDAweAADAPBgNVHRMBAf8EBT\n" + "ADAQH/MA0GCSqGSIb3DQEBBAUAA4IBAQBhbuim98TWmtv9vSldRE7RvQ8\n" + "FlS0TyZVO7kcSNtfCUE4R76J1ElN74Koc5pQnUtduLeQJs2ao/mEcCZsE\n" + "zVcwI3mSZrSzPhc8s7w5gOQA4TUwVLSSjKgBCaZ7R3+qJ3QeqPJ5O6sFz\n" + "pvBYkgSa4MWptK41jbmT8cwZQJXFCi8WxFFJ+p97F1Ppm3LgmYmtiUP4M\n" + "ZQwOBvpTZWXU0WrqFXpzWQx0mg4SX19fZm4nLcJAerCEUphf8ILagtpQM\n" + "EErT3/jg6mfCdT3Rj055QXPfF4OiRFevPF5a1fZgrCePCukRQZcd7s8K5\n" + "OBIaryuM0MdFtlzxi6XWeUNpVFFHURcy\n" + "-----END CERTIFICATE-----"; private static final String END_CERT = "-----BEGIN CERTIFICATE-----\n" + "MIICNjCCAZ+gAwIBAgIEPz7WtzANBgkqhkiG9w0BAQQFADBSMQswCQYDV\n" + "QQGEwJVUzERMA8GA1UEChMISmF2YVNvZnQxFTATBgNVBAsTDFNlY3VyaX\n" + "R5IFNRRTEZMBcGA1UEAxMQUEtDUzEyIFRlc3QgTGVhZDAeFw0wMDA4MDk\n" + "wNzAwMDBaFw0xMDA4MDcwNzAwMDBaMFgxCzAJBgNVBAYTAlVTMREwDwYD\n" + "VQQKEwhKYXZhU29mdDEVMBMGA1UECxMMU2VjdXJpdHkgU1FFMR8wHQYDV\n" + "QQDExZQS0NTMTIgVGVzdCBFbmQgVXNlciAxMIGfMA0GCSqGSIb3DQEBAQ\n" + "UAA4GNADCBiQKBgQDIKomSYomDzH/V63eDQEG7od0DLcnnVZ81pbWhDss\n" + "8gHV2m8pADdRqdihBmnSQEaMW4D3uZ4sFE1LtkQls6hjd7SdOsG5Y24L8\n" + "15jot9a2JcB73H8H0VKirrObL5BZdt7BtASPDnYtW4Spt++YjDoJFxyF0\n" + "HchkavzXaVTlexakwIDAQABoxMwETAPBgNVHQ8BAf8EBQMDB4AAMA0GCS\n" + "qGSIb3DQEBBAUAA4GBAIFA3JXEmb9AXn3RD7t+Mn6DoyVDIy5jsn6xOKT\n" + "JV25I0obpDUzgw4QaAMmM0ZvusOmZ2wZNS8MtyTUgdANyakbzn5SdxbTy\n" + "TLEqQsFbX8UVC38fx5ZM6ExA5YSAvgmXudZpOVC0ATccoZS3JFU8CxSfW\n" + "+Q3IC2MLh+QTg3hUJ5b\n-----END CERTIFICATE-----"; private final Certificate testerCert; private final Certificate testLeadCert; private final Certificate caCert; WriteP12Test() throws CertificateException { CertificateFactory cf = CertificateFactory.getInstance("X.509"); caCert = cf.generateCertificate(new ByteArrayInputStream(CA_CERT_STR .getBytes())); testLeadCert = cf.generateCertificate(new ByteArrayInputStream( LEAD_CERT.getBytes())); testerCert = cf.generateCertificate(new ByteArrayInputStream(END_CERT .getBytes())); } public static void main(String[] args) throws CertificateException, UnrecoverableKeyException, KeyStoreException, NoSuchProviderException, NoSuchAlgorithmException, IOException { WriteP12Test jstest = new WriteP12Test(); out.println("test WriteP12CertChain"); /* * WriteP12CertChain: This test creates a p12 keystore contains one * entry with private key and a certificate chains contains three * certificates in the order of user->lead->ca. This case expects to * pass. */ jstest.test(new Certificate[] { jstest.testerCert, jstest.testLeadCert, jstest.caCert }, IN_KEYSTORE_ENDUSER, "pkcs12testenduser1", "pass", "pass"); /* * WriteP12CertChainBad: same as WriteP12CertChain but chains order is * user-ca-lead, the order is wrong so expects to fail. */ out.println("test WriteP12CertChainBad"); try { jstest.test(new Certificate[] { jstest.testerCert, jstest.caCert, jstest.testLeadCert }, IN_KEYSTORE_ENDUSER, "pkcs12testenduser1", "pass", "pass"); throw new RuntimeException( " Certificate chain is not valid, test should not pass." + " Test failed."); } catch (KeyStoreException e) { e.printStackTrace(); out.println(" Certificate chain is not valid,exception is" + " expected. Test passed."); } /* * WriteP12PrivateKey:This test creates a p12 contains a self-signed * cert and private key,expects no exception */ out.println("test WriteP12PrivateKey"); jstest.test(null, IN_KEYSTORE_ENDUSER, "pkcs12testenduser1", "pass", "pass"); /* * WriteP12TwoEntry: This test creates a p12 keystore with different * storepass and keypass, and contains two entries. */ out.println("test WriteP12TwoEntry"); jstest.testTwoEntry(IN_KEYSTORE_ENDUSER, IN_KEYSTORE_CA, "pkcs12testenduser1", "pass", "pass"); /* * WriteP12TwoPass: This test creates a p12 keystore with different * storepass and keypass, and contains one entry with private key and a * certificate */ out.println("test WriteP12TwoPass"); jstest.test(null, IN_KEYSTORE_CA, "pkcs12testCA", "storepass", "keypass"); } private void test(Certificate certs[], String inKeyStorePath, String userAlias, String outStorePass, String outKeyPass) throws KeyStoreException, NoSuchProviderException, IOException, CertificateException, UnrecoverableKeyException, NoSuchAlgorithmException { // init output key store KeyStore outputKeyStore = KeyStore.getInstance("pkcs12", "SunJSSE"); outputKeyStore.load(null, null); try (FileOutputStream fout = new FileOutputStream(OUT_KEYSTORE)) { // KeyStore have encoded by Base64.getMimeEncoder().encode(),need // decode first. byte[] input = Files.readAllBytes(Paths.get(CERT_PATH, inKeyStorePath)); ByteArrayInputStream arrayIn = new ByteArrayInputStream(Base64 .getMimeDecoder().decode(input)); // input key store KeyStore inputKeyStore = KeyStore.getInstance(IN_KEYSTORE_TYPE, IN_KEYSTORE_PRV); inputKeyStore.load(arrayIn, IN_STORE_PASS.toCharArray()); // add key/certificate to output key store Key key = inputKeyStore .getKey(userAlias, IN_KEY_PASS.toCharArray()); out.println("Input Key Algorithm " + key.getAlgorithm()); out.println("====Input Certs====="); if (certs == null) { certs = new Certificate[] { inputKeyStore .getCertificate(userAlias) }; } for (Certificate cert : certs) { out.println(((X509Certificate) cert).getSubjectDN()); } outputKeyStore.setKeyEntry(userAlias, key, outKeyPass.toCharArray(), certs); Certificate retCerts[] = outputKeyStore .getCertificateChain(userAlias); out.println("====Output Certs====="); for (Certificate retCert : retCerts) { out.println(((X509Certificate) retCert).getSubjectDN()); } out.println("====Output Key Algorithm====="); Key outKey = outputKeyStore.getKey(userAlias, outKeyPass.toCharArray()); out.println(outKey.getAlgorithm()); if (!key.equals(outKey)) { throw new RuntimeException("key don't match"); } if (!Arrays.equals(certs, retCerts)) { throw new RuntimeException("certs don't match"); } // save output outputKeyStore.store(fout, outStorePass.toCharArray()); // test output testKeyStore(outputKeyStore, outKeyPass.toCharArray()); } } private void testTwoEntry(String inKeyStoreOnePath, String inKeyStoreTwoPath, String userAlias, String outStorePass, String outKeyPass) throws KeyStoreException, NoSuchProviderException, NoSuchAlgorithmException, CertificateException, IOException, UnrecoverableKeyException { // initial KeyStore KeyStore outputKeyStore = KeyStore.getInstance("pkcs12", "SunJSSE"); try (FileOutputStream fout = new FileOutputStream(OUT_KEYSTORE);) { outputKeyStore.load(null, null); KeyStore inputKeyStoreOne, inputKeyStoreTwo; inputKeyStoreOne = KeyStore.getInstance(IN_KEYSTORE_TYPE, IN_KEYSTORE_PRV); // KeyStore have encoded by Base64.getMimeEncoder().encode(),need // decode first. byte[] inputBytes = Files.readAllBytes(Paths.get(CERT_PATH, inKeyStoreOnePath)); ByteArrayInputStream arrayIn = new ByteArrayInputStream(Base64 .getMimeDecoder().decode(inputBytes)); // input key store inputKeyStoreOne.load(arrayIn, IN_STORE_PASS.toCharArray()); inputBytes = Files.readAllBytes(Paths.get(CERT_PATH, inKeyStoreTwoPath)); arrayIn = new ByteArrayInputStream(Base64.getMimeDecoder().decode( inputBytes)); inputKeyStoreTwo = KeyStore.getInstance(IN_KEYSTORE_TYPE, IN_KEYSTORE_PRV); inputKeyStoreTwo.load(arrayIn, IN_STORE_PASS.toCharArray()); // add key/certificate to output key store out.println("====First Entry====="); Key inputKey = inputKeyStoreOne.getKey(userAlias, IN_KEY_PASS.toCharArray()); Certificate cert = inputKeyStoreOne.getCertificate(userAlias); Certificate certs[] = new Certificate[1]; certs[0] = cert; out.println("====Input1 Key====="); out.println(inputKey.getAlgorithm()); out.println("====Input1 Certs====="); out.println("Certificate :"); out.println(((X509Certificate) cert).getSubjectDN()); outputKeyStore.setKeyEntry("USER", inputKey, outKeyPass.toCharArray(), certs); out.println("====Second Entry====="); String caAlias = "pkcs12testca"; inputKey = inputKeyStoreTwo.getKey(caAlias, IN_KEY_PASS.toCharArray()); cert = inputKeyStoreTwo.getCertificate(caAlias); certs[0] = cert; out.println("====Input2 Key====="); out.println(inputKey.getAlgorithm()); out.println("====Input2 Certs====="); out.println("Certificate :"); out.println(((X509Certificate) cert).getSubjectDN()); outputKeyStore.setKeyEntry("CA", inputKey, outKeyPass.toCharArray(), certs); // save output outputKeyStore.store(fout, outStorePass.toCharArray()); // test output testKeyStore(outputKeyStore, outKeyPass.toCharArray()); } } private void testKeyStore(KeyStore inputKeyStore, char[] keypass) throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException { out.println("========== Key Store =========="); out.println("getProvider : " + inputKeyStore.getProvider()); out.println("getType : " + inputKeyStore.getType()); out.println("getDefaultType : " + KeyStore.getDefaultType()); int idx = 0; Enumeration<String> e = inputKeyStore.aliases(); String alias; while (e.hasMoreElements()) { alias = e.nextElement(); if (!inputKeyStore.containsAlias(alias)) { throw new RuntimeException("Alias not found"); } out.println("Alias " + idx + " : " + alias); out.println("getCreationDate : " + inputKeyStore.getCreationDate(alias)); X509Certificate cert = (X509Certificate) inputKeyStore .getCertificate(alias); out.println("getCertificate : " + cert.getSubjectDN()); String retAlias = inputKeyStore.getCertificateAlias(cert); if (!retAlias.equals(alias)) { throw new RuntimeException("Alias mismatch, actually " + retAlias + ", expected " + alias); } out.println("getCertificateAlias : " + retAlias); Certificate[] certs = inputKeyStore.getCertificateChain(alias); int i = 0; for (Certificate certification : certs) { out.println("getCertificateChain " + i + ((X509Certificate) certification).getSubjectDN()); i++; } if (inputKeyStore.isCertificateEntry(alias)) { throw new RuntimeException( "inputKeystore should not be certEntry because this" + " keystore only contain key pair entries."); } if (!inputKeyStore.isKeyEntry(alias)) { throw new RuntimeException("Entry type unknown."); } idx++; } int size = inputKeyStore.size(); if (idx != size) { throw new RuntimeException("Size not match, actually " + idx + ", expected " + size); } } }