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