1 /* 2 * Copyright (c) 2018, 2021, 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 * @test 26 * @bug 8076190 8242151 8153005 8266182 27 * @summary This is java keytool <-> openssl interop test. This test generates 28 * some openssl keystores on the fly, java operates on it and 29 * vice versa. 30 * 31 * Note: This test executes some openssl command, so need to set 32 * openssl path using system property "test.openssl.path" or it should 33 * be available in /usr/bin or /usr/local/bin 34 * Required OpenSSL version : OpenSSL 1.1.* 35 * 36 * @modules java.base/sun.security.pkcs 37 * java.base/sun.security.util 38 * @library /test/lib 39 * @library /sun/security/pkcs11/ 40 * @run main/othervm/timeout=600 KeytoolOpensslInteropTest 41 */ 42 43 import jdk.test.lib.Asserts; 44 import jdk.test.lib.SecurityTools; 45 import jdk.test.lib.process.ProcessTools; 46 import jdk.test.lib.process.OutputAnalyzer; 47 import jdk.test.lib.security.OpensslArtifactFetcher; 48 49 import java.io.File; 50 import java.io.FileInputStream; 51 import java.io.FileOutputStream; 52 import java.io.IOException; 53 import java.io.InputStream; 54 import java.io.OutputStream; 55 import java.io.UncheckedIOException; 56 import java.nio.file.DirectoryStream; 57 import java.nio.file.Files; 58 import java.nio.file.Path; 59 import java.security.KeyStore; 60 import java.util.Base64; 61 import java.util.Objects; 62 63 import static jdk.test.lib.security.DerUtils.*; 64 import static sun.security.util.KnownOIDs.*; 65 import static sun.security.pkcs.ContentInfo.*; 66 67 public class KeytoolOpensslInteropTest { 68 main(String[] args)69 public static void main(String[] args) throws Throwable { 70 String opensslPath = OpensslArtifactFetcher.getOpenssl1dot1dotStar(); 71 if (opensslPath != null) { 72 // if preferred version of openssl is available perform all 73 // keytool <-> openssl interop tests 74 generateInitialKeystores(opensslPath); 75 testWithJavaCommands(); 76 testWithOpensslCommands(opensslPath); 77 } else { 78 // since preferred version of openssl is not available skip all 79 // openssl command dependent tests with a warning 80 System.out.println("\n\u001B[31mWarning: Can't find openssl " 81 + "(version 1.1.*) binary on this machine, please install" 82 + " and set openssl path with property " 83 + "'test.openssl.path'. Now running only half portion of " 84 + "the test, skipping all tests which depends on openssl " 85 + "commands.\u001B[0m\n"); 86 // De-BASE64 textual files in ./params to `pwd` 87 try (DirectoryStream<Path> stream = Files.newDirectoryStream( 88 Path.of(System.getProperty("test.src"), "params"), 89 p -> !p.getFileName().toString().equals("README"))) { 90 stream.forEach(p -> { 91 try (InputStream is = Files.newInputStream(p); 92 OutputStream os = Files.newOutputStream( 93 p.getFileName())) { 94 Base64.getMimeDecoder().wrap(is).transferTo(os); 95 } catch (IOException e) { 96 throw new UncheckedIOException(e); 97 } 98 }); 99 } 100 testWithJavaCommands(); 101 } 102 } 103 generateInitialKeystores(String opensslPath)104 private static void generateInitialKeystores(String opensslPath) 105 throws Throwable { 106 keytool("-keystore ks -keyalg ec -genkeypair -storepass" 107 + " changeit -alias a -dname CN=A").shouldHaveExitValue(0); 108 109 ProcessTools.executeCommand(opensslPath, "pkcs12", "-in", "ks", 110 "-nodes", "-out", "kandc", "-passin", "pass:changeit") 111 .shouldHaveExitValue(0); 112 113 ProcessTools.executeCommand(opensslPath, "pkcs12", "-export", "-in", 114 "kandc", "-out", "os2", "-name", "a", "-passout", 115 "pass:changeit", "-certpbe", "NONE", "-nomac") 116 .shouldHaveExitValue(0); 117 118 ProcessTools.executeCommand(opensslPath, "pkcs12", "-export", "-in", 119 "kandc", "-out", "os3", "-name", "a", "-passout", 120 "pass:changeit", "-certpbe", "NONE") 121 .shouldHaveExitValue(0); 122 123 ProcessTools.executeCommand(opensslPath, "pkcs12", "-export", "-in", 124 "kandc", "-out", "os4", "-name", "a", "-passout", 125 "pass:changeit", "-certpbe", "PBE-SHA1-RC4-128", "-keypbe", 126 "PBE-SHA1-RC4-128", "-macalg", "SHA224") 127 .shouldHaveExitValue(0); 128 129 ProcessTools.executeCommand(opensslPath, "pkcs12", "-export", "-in", 130 "kandc", "-out", "os5", "-name", "a", "-passout", 131 "pass:changeit", "-certpbe", "AES-256-CBC", "-keypbe", 132 "AES-256-CBC", "-macalg", "SHA512") 133 .shouldHaveExitValue(0); 134 } 135 testWithJavaCommands()136 private static void testWithJavaCommands() throws Throwable { 137 byte[] data; 138 139 // openssl -> keytool interop check 140 // os2. no cert pbe, no mac. 141 check("os2", "a", null, "changeit", true, true, true); 142 check("os2", "a", "changeit", "changeit", true, true, true); 143 // You can even load it with a wrong storepass, controversial 144 check("os2", "a", "wrongpass", "changeit", true, true, true); 145 146 // os3. no cert pbe, has mac. just like JKS 147 check("os3", "a", null, "changeit", true, true, true); 148 check("os3", "a", "changeit", "changeit", true, true, true); 149 // Cannot load with a wrong storepass, same as JKS 150 check("os3", "a", "wrongpass", "-", IOException.class, "-", "-"); 151 152 // os4. non default algs 153 check("os4", "a", "changeit", "changeit", true, true, true); 154 check("os4", "a", "wrongpass", "-", IOException.class, "-", "-"); 155 // no storepass no cert 156 check("os4", "a", null, "changeit", true, false, true); 157 158 // os5. strong non default algs 159 check("os5", "a", "changeit", "changeit", true, true, true); 160 check("os5", "a", "wrongpass", "-", IOException.class, "-", "-"); 161 // no storepass no cert 162 check("os5", "a", null, "changeit", true, false, true); 163 164 // keytool 165 166 // Current default pkcs12 setting 167 keytool("-importkeystore -srckeystore ks -srcstorepass changeit " 168 + "-destkeystore ksnormal -deststorepass changeit"); 169 170 data = Files.readAllBytes(Path.of("ksnormal")); 171 checkInt(data, "22", 10000); // Mac ic 172 checkAlg(data, "2000", SHA_256); // Mac alg 173 checkAlg(data, "110c010c01000", PBES2); // key alg 174 checkInt(data, "110c010c01001011", 10000); // key ic 175 checkAlg(data, "110c10", ENCRYPTED_DATA_OID); 176 checkAlg(data, "110c110110", PBES2); // cert alg 177 check("ksnormal", "a", "changeit", "changeit", true, true, true); 178 check("ksnormal", "a", null, "changeit", true, false, true); 179 check("ksnormal", "a", "wrongpass", "-", IOException.class, "-", "-"); 180 181 // Import it into a new keystore with legacy algorithms 182 keytool("-importkeystore -srckeystore ksnormal -srcstorepass changeit " 183 + "-destkeystore kslegacyimp -deststorepass changeit " 184 + "-J-Dkeystore.pkcs12.legacy"); 185 data = Files.readAllBytes(Path.of("kslegacyimp")); 186 checkInt(data, "22", 100000); // Mac ic 187 checkAlg(data, "2000", SHA_1); // Mac alg 188 checkAlg(data, "110c010c01000", PBEWithSHA1AndDESede); // key alg 189 checkInt(data, "110c010c010011", 50000); // key ic 190 checkAlg(data, "110c110110", PBEWithSHA1AndRC2_40); // cert alg 191 checkInt(data, "110c1101111", 50000); // cert ic 192 193 // Add a new entry with password-less settings, still has a storepass 194 keytool("-keystore ksnormal -genkeypair -keyalg DSA " 195 + "-storepass changeit -alias b -dname CN=b " 196 + "-J-Dkeystore.pkcs12.certProtectionAlgorithm=NONE " 197 + "-J-Dkeystore.pkcs12.macAlgorithm=NONE"); 198 data = Files.readAllBytes(Path.of("ksnormal")); 199 checkInt(data, "22", 10000); // Mac ic 200 checkAlg(data, "2000", SHA_256); // Mac alg 201 checkAlg(data, "110c010c01000", PBES2); // key alg 202 checkInt(data, "110c010c01001011", 10000); // key ic 203 checkAlg(data, "110c010c11000", PBES2); // new key alg 204 checkInt(data, "110c010c11001011", 10000); // new key ic 205 checkAlg(data, "110c10", ENCRYPTED_DATA_OID); 206 checkAlg(data, "110c110110", PBES2); // cert alg 207 check("ksnormal", "b", null, "changeit", true, false, true); 208 check("ksnormal", "b", "changeit", "changeit", true, true, true); 209 210 // Different keypbe alg, no cert pbe and no mac 211 keytool("-importkeystore -srckeystore ks -srcstorepass changeit " 212 + "-destkeystore ksnopass -deststorepass changeit " 213 + "-J-Dkeystore.pkcs12.keyProtectionAlgorithm=PBEWithSHA1AndRC4_128 " 214 + "-J-Dkeystore.pkcs12.certProtectionAlgorithm=NONE " 215 + "-J-Dkeystore.pkcs12.macAlgorithm=NONE"); 216 data = Files.readAllBytes(Path.of("ksnopass")); 217 shouldNotExist(data, "2"); // no Mac 218 checkAlg(data, "110c010c01000", PBEWithSHA1AndRC4_128); 219 checkInt(data, "110c010c010011", 10000); 220 checkAlg(data, "110c10", DATA_OID); 221 check("ksnopass", "a", null, "changeit", true, true, true); 222 check("ksnopass", "a", "changeit", "changeit", true, true, true); 223 check("ksnopass", "a", "wrongpass", "changeit", true, true, true); 224 225 // Add a new entry with normal settings, still password-less 226 keytool("-keystore ksnopass -genkeypair -keyalg DSA " 227 + "-storepass changeit -alias b -dname CN=B"); 228 data = Files.readAllBytes(Path.of("ksnopass")); 229 shouldNotExist(data, "2"); // no Mac 230 checkAlg(data, "110c010c01000", PBEWithSHA1AndRC4_128); 231 checkInt(data, "110c010c010011", 10000); 232 checkAlg(data, "110c010c11000", PBES2); 233 checkInt(data, "110c010c11001011", 10000); 234 checkAlg(data, "110c10", DATA_OID); 235 check("ksnopass", "a", null, "changeit", true, true, true); 236 check("ksnopass", "b", null, "changeit", true, true, true); 237 238 keytool("-importkeystore -srckeystore ks -srcstorepass changeit " 239 + "-destkeystore ksnewic -deststorepass changeit " 240 + "-J-Dkeystore.pkcs12.macIterationCount=5555 " 241 + "-J-Dkeystore.pkcs12.certPbeIterationCount=6666 " 242 + "-J-Dkeystore.pkcs12.keyPbeIterationCount=7777"); 243 data = Files.readAllBytes(Path.of("ksnewic")); 244 checkInt(data, "22", 5555); // Mac ic 245 checkAlg(data, "2000", SHA_256); // Mac alg 246 checkAlg(data, "110c010c01000", PBES2); // key alg 247 checkInt(data, "110c010c01001011", 7777); // key ic 248 checkAlg(data, "110c110110", PBES2); // cert alg 249 checkInt(data, "110c110111011", 6666); // cert ic 250 251 // keypbe alg cannot be NONE 252 keytool("-keystore ksnewic -genkeypair -keyalg DSA " 253 + "-storepass changeit -alias b -dname CN=B " 254 + "-J-Dkeystore.pkcs12.keyProtectionAlgorithm=NONE") 255 .shouldContain("NONE AlgorithmParameters not available") 256 .shouldHaveExitValue(1); 257 258 // new entry new keypbe alg (and default ic), else unchanged 259 keytool("-keystore ksnewic -genkeypair -keyalg DSA " 260 + "-storepass changeit -alias b -dname CN=B " 261 + "-J-Dkeystore.pkcs12.keyProtectionAlgorithm=PBEWithSHA1AndRC4_128"); 262 data = Files.readAllBytes(Path.of("ksnewic")); 263 checkInt(data, "22", 5555); // Mac ic 264 checkAlg(data, "2000", SHA_256); // Mac alg 265 checkAlg(data, "110c010c01000", PBES2); // key alg 266 checkInt(data, "110c010c01001011", 7777); // key ic 267 checkAlg(data, "110c010c11000", PBEWithSHA1AndRC4_128); // new key alg 268 checkInt(data, "110c010c110011", 10000); // new key ic 269 checkAlg(data, "110c110110", PBES2); // cert alg 270 checkInt(data, "110c110111011", 6666); // cert ic 271 272 // Check KeyStore loading multiple keystores 273 KeyStore ks = KeyStore.getInstance("pkcs12"); 274 try (FileInputStream fis = new FileInputStream("ksnormal"); 275 FileOutputStream fos = new FileOutputStream("ksnormaldup")) { 276 ks.load(fis, "changeit".toCharArray()); 277 ks.store(fos, "changeit".toCharArray()); 278 } 279 data = Files.readAllBytes(Path.of("ksnormaldup")); 280 checkInt(data, "22", 10000); // Mac ic 281 checkAlg(data, "2000", SHA_256); // Mac alg 282 checkAlg(data, "110c010c01000", PBES2); // key alg 283 checkInt(data, "110c010c01001011", 10000); // key ic 284 checkAlg(data, "110c010c11000", PBES2); // new key alg 285 checkInt(data, "110c010c11001011", 10000); // new key ic 286 checkAlg(data, "110c10", ENCRYPTED_DATA_OID); 287 checkAlg(data, "110c110110", PBES2); // cert alg 288 checkInt(data, "110c110111011", 10000); // cert ic 289 290 try (FileInputStream fis = new FileInputStream("ksnopass"); 291 FileOutputStream fos = new FileOutputStream("ksnopassdup")) { 292 ks.load(fis, "changeit".toCharArray()); 293 ks.store(fos, "changeit".toCharArray()); 294 } 295 data = Files.readAllBytes(Path.of("ksnopassdup")); 296 shouldNotExist(data, "2"); // no Mac 297 checkAlg(data, "110c010c01000", PBEWithSHA1AndRC4_128); 298 checkInt(data, "110c010c010011", 10000); 299 checkAlg(data, "110c010c11000", PBES2); 300 checkInt(data, "110c010c11001011", 10000); 301 checkAlg(data, "110c10", DATA_OID); 302 303 try (FileInputStream fis = new FileInputStream("ksnewic"); 304 FileOutputStream fos = new FileOutputStream("ksnewicdup")) { 305 ks.load(fis, "changeit".toCharArray()); 306 ks.store(fos, "changeit".toCharArray()); 307 } 308 data = Files.readAllBytes(Path.of("ksnewicdup")); 309 checkInt(data, "22", 5555); // Mac ic 310 checkAlg(data, "2000", SHA_256); // Mac alg 311 checkAlg(data, "110c010c01000", PBES2); // key alg 312 checkInt(data, "110c010c01001011", 7777); // key ic 313 checkAlg(data, "110c010c11000", PBEWithSHA1AndRC4_128); // new key alg 314 checkInt(data, "110c010c110011", 10000); // new key ic 315 checkAlg(data, "110c110110", PBES2); // cert alg 316 checkInt(data, "110c110111011", 6666); // cert ic 317 318 // Check keytool behavior 319 320 // ksnormal has password 321 322 keytool("-list -keystore ksnormal") 323 .shouldContain("WARNING WARNING WARNING") 324 .shouldContain("Certificate chain length: 0"); 325 326 SecurityTools.setResponse("changeit"); 327 keytool("-list -keystore ksnormal") 328 .shouldNotContain("WARNING WARNING WARNING") 329 .shouldContain("Certificate fingerprint"); 330 331 // ksnopass is password-less 332 333 keytool("-list -keystore ksnopass") 334 .shouldNotContain("WARNING WARNING WARNING") 335 .shouldContain("Certificate fingerprint"); 336 337 // -certreq prompts for keypass 338 SecurityTools.setResponse("changeit"); 339 keytool("-certreq -alias a -keystore ksnopass") 340 .shouldContain("Enter key password for <a>") 341 .shouldContain("-----BEGIN NEW CERTIFICATE REQUEST-----") 342 .shouldHaveExitValue(0); 343 344 // -certreq -storepass works fine 345 keytool("-certreq -alias a -keystore ksnopass -storepass changeit") 346 .shouldNotContain("Enter key password for <a>") 347 .shouldContain("-----BEGIN NEW CERTIFICATE REQUEST-----") 348 .shouldHaveExitValue(0); 349 350 // -certreq -keypass also works fine 351 keytool("-certreq -alias a -keystore ksnopass -keypass changeit") 352 .shouldNotContain("Enter key password for <a>") 353 .shouldContain("-----BEGIN NEW CERTIFICATE REQUEST-----") 354 .shouldHaveExitValue(0); 355 356 // -importkeystore prompts for srckeypass 357 SecurityTools.setResponse("changeit", "changeit"); 358 keytool("-importkeystore -srckeystore ksnopass " 359 + "-destkeystore jks3 -deststorepass changeit") 360 .shouldContain("Enter key password for <a>") 361 .shouldContain("Enter key password for <b>") 362 .shouldContain("2 entries successfully imported"); 363 364 // ksnopass2 is ksnopass + 2 cert entries 365 366 ks = KeyStore.getInstance(new File("ksnopass"), (char[])null); 367 ks.setCertificateEntry("aa", ks.getCertificate("a")); 368 ks.setCertificateEntry("bb", ks.getCertificate("b")); 369 try (FileOutputStream fos = new FileOutputStream("ksnopass2")) { 370 ks.store(fos, null); 371 } 372 373 // -importkeystore prompts for srckeypass for private keys 374 // and no prompt for certs 375 SecurityTools.setResponse("changeit", "changeit"); 376 keytool("-importkeystore -srckeystore ksnopass2 " 377 + "-destkeystore jks5 -deststorepass changeit") 378 .shouldContain("Enter key password for <a>") 379 .shouldContain("Enter key password for <b>") 380 .shouldNotContain("Enter key password for <aa>") 381 .shouldNotContain("Enter key password for <bb>") 382 .shouldContain("4 entries successfully imported"); 383 384 // ksonlycert has only cert entries 385 386 ks.deleteEntry("a"); 387 ks.deleteEntry("b"); 388 try (FileOutputStream fos = new FileOutputStream("ksonlycert")) { 389 ks.store(fos, null); 390 } 391 392 // -importkeystore does not prompt at all 393 keytool("-importkeystore -srckeystore ksonlycert " 394 + "-destkeystore jks6 -deststorepass changeit") 395 .shouldNotContain("Enter key password for <aa>") 396 .shouldNotContain("Enter key password for <bb>") 397 .shouldContain("2 entries successfully imported"); 398 399 // create a new password-less keystore 400 keytool("-keystore ksnopass -exportcert -alias a -file a.cert -rfc"); 401 402 // Normally storepass is prompted for 403 keytool("-keystore kscert1 -importcert -alias a -file a.cert -noprompt") 404 .shouldContain("Enter keystore password:"); 405 keytool("-keystore kscert2 -importcert -alias a -file a.cert -noprompt " 406 + "-J-Dkeystore.pkcs12.certProtectionAlgorithm=NONE") 407 .shouldContain("Enter keystore password:"); 408 keytool("-keystore kscert3 -importcert -alias a -file a.cert -noprompt " 409 + "-J-Dkeystore.pkcs12.macAlgorithm=NONE") 410 .shouldContain("Enter keystore password:"); 411 // ... but not if it's password-less 412 keytool("-keystore kscert4 -importcert -alias a -file a.cert -noprompt " 413 + "-J-Dkeystore.pkcs12.certProtectionAlgorithm=NONE " 414 + "-J-Dkeystore.pkcs12.macAlgorithm=NONE") 415 .shouldNotContain("Enter keystore password:"); 416 417 // still prompt for keypass for genkeypair and certreq 418 SecurityTools.setResponse("changeit", "changeit"); 419 keytool("-keystore ksnopassnew -genkeypair -keyalg DSA " 420 + "-alias a -dname CN=A " 421 + "-J-Dkeystore.pkcs12.certProtectionAlgorithm=NONE " 422 + "-J-Dkeystore.pkcs12.macAlgorithm=NONE") 423 .shouldNotContain("Enter keystore password:") 424 .shouldContain("Enter key password for <a>"); 425 keytool("-keystore ksnopassnew -certreq -alias a") 426 .shouldNotContain("Enter keystore password:") 427 .shouldContain("Enter key password for <a>"); 428 keytool("-keystore ksnopassnew -list -v -alias a") 429 .shouldNotContain("Enter keystore password:") 430 .shouldNotContain("Enter key password for <a>"); 431 432 // params only read on demand 433 434 // keyPbeIterationCount is used by -genkeypair 435 keytool("-keystore ksgenbadkeyic -genkeypair -keyalg DSA " 436 + "-alias a -dname CN=A " 437 + "-storepass changeit " 438 + "-J-Dkeystore.pkcs12.keyPbeIterationCount=abc") 439 .shouldContain("keyPbeIterationCount is not a number: abc") 440 .shouldHaveExitValue(1); 441 442 keytool("-keystore ksnopassnew -exportcert -alias a -file a.cert"); 443 444 // but not used by -importcert 445 keytool("-keystore ksimpbadkeyic -importcert -alias a -file a.cert " 446 + "-noprompt -storepass changeit " 447 + "-J-Dkeystore.pkcs12.keyPbeIterationCount=abc") 448 .shouldHaveExitValue(0); 449 450 // None is used by -list 451 keytool("-keystore ksnormal -storepass changeit -list " 452 + "-J-Dkeystore.pkcs12.keyPbeIterationCount=abc " 453 + "-J-Dkeystore.pkcs12.certPbeIterationCount=abc " 454 + "-J-Dkeystore.pkcs12.macIterationCount=abc") 455 .shouldHaveExitValue(0); 456 } 457 testWithOpensslCommands(String opensslPath)458 private static void testWithOpensslCommands(String opensslPath) 459 throws Throwable { 460 461 OutputAnalyzer output1 = ProcessTools.executeCommand(opensslPath, 462 "pkcs12", "-in", "ksnormal", "-passin", "pass:changeit", 463 "-info", "-nokeys", "-nocerts"); 464 output1.shouldHaveExitValue(0) 465 .shouldContain("MAC: sha256, Iteration 10000") 466 .shouldContain("Shrouded Keybag: PBES2, PBKDF2, AES-256-CBC," 467 + " Iteration 10000, PRF hmacWithSHA256") 468 .shouldContain("PKCS7 Encrypted data: PBES2, PBKDF2, AES-256-CBC," 469 + " Iteration 10000, PRF hmacWithSHA256"); 470 471 OutputAnalyzer output2 = ProcessTools.executeCommand(opensslPath, 472 "pkcs12", "-in", "ksnormaldup", "-passin", "pass:changeit", 473 "-info", "-nokeys", "-nocerts"); 474 output2.shouldHaveExitValue(0); 475 if(!output1.getStderr().equals(output2.getStderr())) { 476 throw new RuntimeException("Duplicate pkcs12 keystores" 477 + " ksnormal & ksnormaldup show different info"); 478 } 479 480 output1 = ProcessTools.executeCommand(opensslPath, "pkcs12", "-in", 481 "ksnopass", "-passin", "pass:changeit", "-info", "-nokeys", 482 "-nocerts"); 483 output1.shouldNotHaveExitValue(0); 484 485 output1 = ProcessTools.executeCommand(opensslPath, "pkcs12", "-in", 486 "ksnopass", "-passin", "pass:changeit", "-info", "-nokeys", 487 "-nocerts", "-nomacver"); 488 output1.shouldHaveExitValue(0) 489 .shouldNotContain("PKCS7 Encrypted data:") 490 .shouldContain("Shrouded Keybag: PBES2, PBKDF2, AES-256-CBC," 491 + " Iteration 10000, PRF hmacWithSHA256") 492 .shouldContain("Shrouded Keybag: pbeWithSHA1And128BitRC4," 493 + " Iteration 10000"); 494 495 output2 = ProcessTools.executeCommand(opensslPath, "pkcs12", "-in", 496 "ksnopassdup", "-passin", "pass:changeit", "-info", "-nokeys", 497 "-nocerts", "-nomacver"); 498 output2.shouldHaveExitValue(0); 499 if(!output1.getStderr().equals(output2.getStderr())) { 500 throw new RuntimeException("Duplicate pkcs12 keystores" 501 + " ksnopass & ksnopassdup show different info"); 502 } 503 504 output1 = ProcessTools.executeCommand(opensslPath, "pkcs12", "-in", 505 "ksnewic", "-passin", "pass:changeit", "-info", "-nokeys", 506 "-nocerts"); 507 output1.shouldHaveExitValue(0) 508 .shouldContain("MAC: sha256, Iteration 5555") 509 .shouldContain("Shrouded Keybag: PBES2, PBKDF2, AES-256-CBC," 510 + " Iteration 7777, PRF hmacWithSHA256") 511 .shouldContain("Shrouded Keybag: pbeWithSHA1And128BitRC4," 512 + " Iteration 10000") 513 .shouldContain("PKCS7 Encrypted data: PBES2, PBKDF2, AES-256-CBC," 514 + " Iteration 6666, PRF hmacWithSHA256"); 515 516 output2 = ProcessTools.executeCommand(opensslPath, "pkcs12", "-in", 517 "ksnewicdup", "-passin", "pass:changeit", "-info", "-nokeys", 518 "-nocerts"); 519 output2.shouldHaveExitValue(0); 520 if(!output1.getStderr().equals(output2.getStderr())) { 521 throw new RuntimeException("Duplicate pkcs12 keystores" 522 + " ksnewic & ksnewicdup show different info"); 523 } 524 } 525 526 /** 527 * Check keystore loading and key/cert reading. 528 * 529 * @param keystore the file name of keystore 530 * @param alias the key/cert to read 531 * @param storePass store pass to try out, can be null 532 * @param keypass key pass to try, can not be null 533 * @param expectedLoad expected result of keystore loading, true if non 534 * null, false if null, exception class if exception 535 * @param expectedCert expected result of cert reading 536 * @param expectedKey expected result of key reading 537 */ check( String keystore, String alias, String storePass, String keypass, Object expectedLoad, Object expectedCert, Object expectedKey)538 private static void check( 539 String keystore, 540 String alias, 541 String storePass, 542 String keypass, 543 Object expectedLoad, 544 Object expectedCert, 545 Object expectedKey) { 546 KeyStore ks = null; 547 Object actualLoad, actualCert, actualKey; 548 String label = keystore + "-" + alias + "-" + storePass + "-" + keypass; 549 try { 550 ks = KeyStore.getInstance(new File(keystore), 551 storePass == null ? null : storePass.toCharArray()); 552 actualLoad = ks != null; 553 } catch (Exception e) { 554 e.printStackTrace(System.out); 555 actualLoad = e.getClass(); 556 } 557 Asserts.assertEQ(expectedLoad, actualLoad, label + "-load"); 558 559 // If not loaded correctly, skip cert/key reading 560 if (!Objects.equals(actualLoad, true)) { 561 return; 562 } 563 564 try { 565 actualCert = (ks.getCertificate(alias) != null); 566 } catch (Exception e) { 567 e.printStackTrace(System.out); 568 actualCert = e.getClass(); 569 } 570 Asserts.assertEQ(expectedCert, actualCert, label + "-cert"); 571 572 try { 573 actualKey = (ks.getKey(alias, keypass.toCharArray()) != null); 574 } catch (Exception e) { 575 e.printStackTrace(System.out); 576 actualKey = e.getClass(); 577 } 578 Asserts.assertEQ(expectedKey, actualKey, label + "-key"); 579 } 580 keytool(String s)581 private static OutputAnalyzer keytool(String s) throws Throwable { 582 return SecurityTools.keytool(s); 583 } 584 } 585