Skip to content

Commit

Permalink
8266182: Automate manual steps listed in the test jdk/sun/security/pk…
Browse files Browse the repository at this point in the history
…cs12/ParamsTest.java

Reviewed-by: hchao, ssahoo, xuelei, weijun
  • Loading branch information
Abdul Kolarkunnu committed Aug 17, 2021
1 parent 0e3fde6 commit ed57cf1
Show file tree
Hide file tree
Showing 2 changed files with 299 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2021, 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
Expand All @@ -23,16 +23,28 @@

/*
* @test
* @bug 8076190 8242151 8153005
* @library /test/lib
* @bug 8076190 8242151 8153005 8266182
* @summary This is java keytool <-> openssl interop test. This test generates
* some openssl keystores on the fly, java operates on it and
* vice versa.
*
* Note: This test executes some openssl command, so need to set
* openssl path using system property "test.openssl.path" or it should
* be available in /usr/bin or /usr/local/bin
* Required OpenSSL version : OpenSSL 1.1.*
*
* @modules java.base/sun.security.pkcs
* java.base/sun.security.util
* @summary Customizing the generation of a PKCS12 keystore
* @library /test/lib
* @library /sun/security/pkcs11/
* @run main/othervm/timeout=600 KeytoolOpensslInteropTest
*/

import jdk.test.lib.Asserts;
import jdk.test.lib.SecurityTools;
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.artifacts.OpensslArtifactFetcher;

import java.io.File;
import java.io.FileInputStream;
Expand All @@ -52,28 +64,79 @@
import static sun.security.util.KnownOIDs.*;
import static sun.security.pkcs.ContentInfo.*;

public class ParamsTest {
public class KeytoolOpensslInteropTest {

public static void main(String[] args) throws Throwable {

// De-BASE64 textual files in ./params to `pwd`
try (DirectoryStream<Path> stream = Files.newDirectoryStream(
Path.of(System.getProperty("test.src"), "params"),
p -> !p.getFileName().toString().equals("README"))) {
stream.forEach(p -> {
try (InputStream is = Files.newInputStream(p);
OutputStream os = Files.newOutputStream(p.getFileName())) {
Base64.getMimeDecoder().wrap(is).transferTo(os);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
});
String opensslPath = OpensslArtifactFetcher.getOpenssl1dot1dotStar();
if (opensslPath != null) {
// if preferred version of openssl is available perform all
// keytool <-> openssl interop tests
generateInitialKeystores(opensslPath);
testWithJavaCommands();
testWithOpensslCommands(opensslPath);
} else {
// since preferred version of openssl is not available skip all
// openssl command dependent tests with a warning
System.out.println("\n\u001B[31mWarning: Can't find openssl "
+ "(version 1.1.*) binary on this machine, please install"
+ " and set openssl path with property "
+ "'test.openssl.path'. Now running only half portion of "
+ "the test, skipping all tests which depends on openssl "
+ "commands.\u001B[0m\n");
// De-BASE64 textual files in ./params to `pwd`
try (DirectoryStream<Path> stream = Files.newDirectoryStream(
Path.of(System.getProperty("test.src"), "params"),
p -> !p.getFileName().toString().equals("README"))) {
stream.forEach(p -> {
try (InputStream is = Files.newInputStream(p);
OutputStream os = Files.newOutputStream(
p.getFileName())) {
Base64.getMimeDecoder().wrap(is).transferTo(os);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
});
}
testWithJavaCommands();
}
}

private static void generateInitialKeystores(String opensslPath)
throws Throwable {
keytool("-keystore ks -keyalg ec -genkeypair -storepass"
+ " changeit -alias a -dname CN=A").shouldHaveExitValue(0);

ProcessTools.executeCommand(opensslPath, "pkcs12", "-in", "ks",
"-nodes", "-out", "kandc", "-passin", "pass:changeit")
.shouldHaveExitValue(0);

ProcessTools.executeCommand(opensslPath, "pkcs12", "-export", "-in",
"kandc", "-out", "os2", "-name", "a", "-passout",
"pass:changeit", "-certpbe", "NONE", "-nomac")
.shouldHaveExitValue(0);

ProcessTools.executeCommand(opensslPath, "pkcs12", "-export", "-in",
"kandc", "-out", "os3", "-name", "a", "-passout",
"pass:changeit", "-certpbe", "NONE")
.shouldHaveExitValue(0);

ProcessTools.executeCommand(opensslPath, "pkcs12", "-export", "-in",
"kandc", "-out", "os4", "-name", "a", "-passout",
"pass:changeit", "-certpbe", "PBE-SHA1-RC4-128", "-keypbe",
"PBE-SHA1-RC4-128", "-macalg", "SHA224")
.shouldHaveExitValue(0);

ProcessTools.executeCommand(opensslPath, "pkcs12", "-export", "-in",
"kandc", "-out", "os5", "-name", "a", "-passout",
"pass:changeit", "-certpbe", "AES-256-CBC", "-keypbe",
"AES-256-CBC", "-macalg", "SHA512")
.shouldHaveExitValue(0);
}

private static void testWithJavaCommands() throws Throwable {
byte[] data;

// openssl -> keytool interop check

// os2. no cert pbe, no mac.
check("os2", "a", null, "changeit", true, true, true);
check("os2", "a", "changeit", "changeit", true, true, true);
Expand Down Expand Up @@ -392,6 +455,74 @@ public static void main(String[] args) throws Throwable {
.shouldHaveExitValue(0);
}

private static void testWithOpensslCommands(String opensslPath)
throws Throwable {

OutputAnalyzer output1 = ProcessTools.executeCommand(opensslPath,
"pkcs12", "-in", "ksnormal", "-passin", "pass:changeit",
"-info", "-nokeys", "-nocerts");
output1.shouldHaveExitValue(0)
.shouldContain("MAC: sha256, Iteration 10000")
.shouldContain("Shrouded Keybag: PBES2, PBKDF2, AES-256-CBC,"
+ " Iteration 10000, PRF hmacWithSHA256")
.shouldContain("PKCS7 Encrypted data: PBES2, PBKDF2, AES-256-CBC,"
+ " Iteration 10000, PRF hmacWithSHA256");

OutputAnalyzer output2 = ProcessTools.executeCommand(opensslPath,
"pkcs12", "-in", "ksnormaldup", "-passin", "pass:changeit",
"-info", "-nokeys", "-nocerts");
output2.shouldHaveExitValue(0);
if(!output1.getStderr().equals(output2.getStderr())) {
throw new RuntimeException("Duplicate pkcs12 keystores"
+ " ksnormal & ksnormaldup show different info");
}

output1 = ProcessTools.executeCommand(opensslPath, "pkcs12", "-in",
"ksnopass", "-passin", "pass:changeit", "-info", "-nokeys",
"-nocerts");
output1.shouldNotHaveExitValue(0);

output1 = ProcessTools.executeCommand(opensslPath, "pkcs12", "-in",
"ksnopass", "-passin", "pass:changeit", "-info", "-nokeys",
"-nocerts", "-nomacver");
output1.shouldHaveExitValue(0)
.shouldNotContain("PKCS7 Encrypted data:")
.shouldContain("Shrouded Keybag: PBES2, PBKDF2, AES-256-CBC,"
+ " Iteration 10000, PRF hmacWithSHA256")
.shouldContain("Shrouded Keybag: pbeWithSHA1And128BitRC4,"
+ " Iteration 10000");

output2 = ProcessTools.executeCommand(opensslPath, "pkcs12", "-in",
"ksnopassdup", "-passin", "pass:changeit", "-info", "-nokeys",
"-nocerts", "-nomacver");
output2.shouldHaveExitValue(0);
if(!output1.getStderr().equals(output2.getStderr())) {
throw new RuntimeException("Duplicate pkcs12 keystores"
+ " ksnopass & ksnopassdup show different info");
}

output1 = ProcessTools.executeCommand(opensslPath, "pkcs12", "-in",
"ksnewic", "-passin", "pass:changeit", "-info", "-nokeys",
"-nocerts");
output1.shouldHaveExitValue(0)
.shouldContain("MAC: sha256, Iteration 5555")
.shouldContain("Shrouded Keybag: PBES2, PBKDF2, AES-256-CBC,"
+ " Iteration 7777, PRF hmacWithSHA256")
.shouldContain("Shrouded Keybag: pbeWithSHA1And128BitRC4,"
+ " Iteration 10000")
.shouldContain("PKCS7 Encrypted data: PBES2, PBKDF2, AES-256-CBC,"
+ " Iteration 6666, PRF hmacWithSHA256");

output2 = ProcessTools.executeCommand(opensslPath, "pkcs12", "-in",
"ksnewicdup", "-passin", "pass:changeit", "-info", "-nokeys",
"-nocerts");
output2.shouldHaveExitValue(0);
if(!output1.getStderr().equals(output2.getStderr())) {
throw new RuntimeException("Duplicate pkcs12 keystores"
+ " ksnewic & ksnewicdup show different info");
}
}

/**
* Check keystore loading and key/cert reading.
*
Expand Down Expand Up @@ -447,7 +578,7 @@ private static void check(
Asserts.assertEQ(expectedKey, actualKey, label + "-key");
}

static OutputAnalyzer keytool(String s) throws Throwable {
private static OutputAnalyzer keytool(String s) throws Throwable {
return SecurityTools.keytool(s);
}
}
}
147 changes: 147 additions & 0 deletions test/lib/jdk/test/lib/artifacts/OpensslArtifactFetcher.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/*
* Copyright (c) 2021, 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.
*/

package jdk.test.lib.artifacts;

import java.io.File;

import jdk.test.lib.Platform;
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.artifacts.Artifact;
import jdk.test.lib.artifacts.ArtifactResolver;
import jdk.test.lib.artifacts.ArtifactResolverException;

public class OpensslArtifactFetcher {

/**
* Gets the openssl binary path of version 1.1.*
*
* Openssl selection flow:
1. Check whether property test.openssl.path is set and it's the
preferred version(1.1.*) of openssl, then return that path.
2. Else look for already installed openssl (version 1.1.*) in system
path /usr/bin/openssl or /usr/local/bin/openssl, then return that
path.
3. Else try to download openssl (version 1.1.*) from the artifactory
and return that path, if download fails then return null.
*
* @return openssl binary path of version 1.1.*
*/
public static String getOpenssl1dot1dotStar() {
String version = "1.1.";
String path = getOpensslFromSystemProp(version);
if (path != null) {
return path;
} else {
path = getDefaultSystemOpensslPath(version);
if (path != null) {
return path;
} else if (Platform.is64bit()) {
if (Platform.isLinux()) {
path = fetchOpenssl(LINUX_X64.class);
} else if (Platform.isOSX()) {
path = fetchOpenssl(MACOSX_X64.class);
} else if (Platform.isWindows()) {
path = fetchOpenssl(WINDOWS_X64.class);
}
if (verifyOpensslVersion(path, version)) {
return path;
}
}
}
return null;
}

private static String getOpensslFromSystemProp(String version) {
String path = System.getProperty("test.openssl.path");
System.out.println("System Property - test.openssl.path: " + path);
if (!verifyOpensslVersion(path, version)) {
path = null;
}
return path;
}

private static String getDefaultSystemOpensslPath(String version) {
if (verifyOpensslVersion("/usr/bin/openssl", version)) {
return "/usr/bin/openssl";
} else if (verifyOpensslVersion("/usr/local/bin/openssl", version)) {
return "/usr/local/bin/openssl";
}
return null;
}

private static boolean verifyOpensslVersion(String path, String version) {
if (path != null) {
try {
ProcessTools.executeCommand(path, "version")
.shouldHaveExitValue(0)
.shouldContain(version);
return true;
} catch (Throwable t) {
t.printStackTrace();
}
}
return false;
}

private static String fetchOpenssl(Class<?> clazz) {
String path = null;
try {
path = ArtifactResolver.resolve(clazz).entrySet().stream()
.findAny().get().getValue() + File.separator + "openssl"
+ File.separator + "bin" + File.separator + "openssl";
System.out.println("path: " + path);
} catch (ArtifactResolverException e) {
Throwable cause = e.getCause();
if (cause == null) {
System.out.println("Cannot resolve artifact, "
+ "please check if JIB jar is present in classpath.");
} else {
throw new RuntimeException("Fetch artifact failed: " + clazz
+ "\nPlease make sure the artifact is available.", e);
}
}
return path;
}

@Artifact(
organization = "jpg.tests.jdk.openssl",
name = "openssl-linux_x64",
revision = "1.1.1g",
extension = "zip")
private static class LINUX_X64 { }

@Artifact(
organization = "jpg.tests.jdk.openssl",
name = "openssl-macosx_x64",
revision = "1.1.1g",
extension = "zip")
private static class MACOSX_X64 { }

@Artifact(
organization = "jpg.tests.jdk.openssl",
name = "openssl-windows_x64",
revision = "1.1.1g",
extension = "zip")
private static class WINDOWS_X64 { }
}

1 comment on commit ed57cf1

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.