blob: 34cccb5356c62b9d658a7edcbe9f4ec87157bc20 [file] [log] [blame]
/*
* Copyright (c) 2020, 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 java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Array;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.KeyFactory;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Arrays;
import java.util.Base64;
import java.util.Optional;
import java.util.StringJoiner;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import jdk.test.lib.process.OutputAnalyzer;
/*
* Utilities for interop testing.
*/
public class Utilities {
public static final String JAVA_HOME = System.getProperty("java.home");
public static final String JAVA
= String.join(File.separator, JAVA_HOME, "bin", "java");
public static final String JAVAC
= String.join(File.separator, JAVA_HOME, "bin", "javac");
public static final String TEST_SRC = System.getProperty("test.src");
public static final String TEST_CLASSES = System.getProperty("test.classes");
public static final String TEST_CLASSPATH = System.getProperty("test.class.path");
public static final Charset CHARSET = StandardCharsets.UTF_8;
public static final boolean DEBUG = Boolean.getBoolean("test.debug");
public static final int TIMEOUT = Integer.getInteger("test.timeout", 20);
public static final String LOG_PATH = System.getProperty("test.log.path");
public static final String PARAM_DELIMITER = ";";
public static final String VALUE_DELIMITER = ",";
public static final CipherSuite[] ALL_CIPHER_SUITES = getAllCipherSuites();
/*
* Gets all supported cipher suites.
*/
private static CipherSuite[] getAllCipherSuites() {
String[] supportedCipherSuites;
try {
supportedCipherSuites = SSLContext.getDefault()
.createSSLEngine()
.getSupportedCipherSuites();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(
"Failed to get supported cipher suites", e);
}
CipherSuite[] cipherSuites = Arrays.stream(supportedCipherSuites)
.map(cipherSuite -> {
return CipherSuite.cipherSuite(cipherSuite);})
.filter(cipherSuite -> {
return cipherSuite != CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV; })
.toArray(CipherSuite[]::new);
return cipherSuites;
}
/*
* Creates SSL context with the specified certificates.
*/
public static SSLContext createSSLContext(CertTuple certTuple)
throws Exception {
KeyStore trustStore = createTrustStore(certTuple.trustedCerts);
TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
tmf.init(trustStore);
KeyStore keyStore = createKeyStore(certTuple.endEntityCerts);
KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
kmf.init(keyStore, null);
SSLContext context = SSLContext.getInstance("TLS");
context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
return context;
}
/*
* Creates trust store with the specified certificates.
*/
public static KeyStore createTrustStore(Cert... certs)
throws KeyStoreException, IOException, NoSuchAlgorithmException,
CertificateException {
KeyStore trustStore = KeyStore.getInstance("PKCS12");
trustStore.load(null, null);
if (certs != null) {
for (int i = 0; i < certs.length; i++) {
if (certs[i] != null) {
trustStore.setCertificateEntry("trust-" + i,
createCert(certs[i]));
}
}
}
return trustStore;
}
/*
* Creates key store with the specified certificates.
*/
public static KeyStore createKeyStore(Cert... certs)
throws KeyStoreException, IOException, NoSuchAlgorithmException,
CertificateException, InvalidKeySpecException {
KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(null, null);
if (certs != null) {
for (int i = 0; i < certs.length; i++) {
if (certs[i] != null) {
keyStore.setKeyEntry("cert-" + i, createKey(certs[i]), null,
new Certificate[] { createCert(certs[i]) });
}
}
}
return keyStore;
}
/*
* Creates Certificate instance with the specified certificate.
*/
public static Certificate createCert(Cert cert) {
try {
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
return certFactory.generateCertificate(
new ByteArrayInputStream(cert.certMaterials.getBytes()));
} catch (CertificateException e) {
throw new RuntimeException("Create cert failed: " + cert, e);
}
}
/*
* Creates PrivateKey instance with the specified certificate.
*/
public static PrivateKey createKey(Cert cert)
throws NoSuchAlgorithmException, InvalidKeySpecException {
PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(
Base64.getMimeDecoder().decode(cert.keyMaterials));
KeyFactory keyFactory = KeyFactory.getInstance(
cert.keyAlgo.name);
PrivateKey privKey = keyFactory.generatePrivate(privKeySpec);
return privKey;
}
/*
* Reads an input stream, in which the content length isn't more than 1024.
*/
public static String readIn(InputStream input) throws IOException {
byte[] buf = new byte[1024];
int length = input.read(buf);
if (length > 0) {
return new String(buf, 0, length);
} else {
return "";
}
}
/*
* Writes the specified content to an output stream.
*/
public static void writeOut(OutputStream output, String content)
throws IOException {
output.write(content.getBytes(Utilities.CHARSET));
output.flush();
}
/*
* Sleeps until the condition is true or getting timeout.
*/
public static <T> boolean waitFor(Predicate<T> predicate, T t) {
long deadline = System.currentTimeMillis() + Utilities.TIMEOUT * 1000;
boolean predicateResult = predicate.test(t);
while (!predicateResult && System.currentTimeMillis() < deadline) {
try {
TimeUnit.SECONDS.sleep(1);
predicateResult = predicate.test(t);
} catch (InterruptedException e) {
throw new RuntimeException("Sleep is interrupted.", e);
}
}
return predicateResult;
}
/*
* Converts Enum array to string array.
* The string elements are the Enum names.
*/
public static String[] enumsToStrs(Enum<?>... elements) {
return enumsToStrs(element -> {
return element.name();
}, elements);
}
/*
* Converts NamedGroup array to string array.
* The string elements are the NameGroups' names.
*/
public static String[] namedGroupsToStrs(NamedGroup... namedGroups) {
return enumsToStrs(namedGroup -> {
return ((NamedGroup) namedGroup).name;
}, namedGroups);
}
/*
* Converts Enum array to string array.
* The string elements are determined by the specified Function.
*/
public static String[] enumsToStrs(Function<Enum<?>, String> function,
Enum<?>... elements) {
return elements == null
? null
: Arrays.stream(elements).map(function).toArray(String[]::new);
}
/*
* Converts string array to Enum array.
*/
@SuppressWarnings("unchecked")
public static <T extends Enum<T>> T[] strToEnums(Class<T> enumType,
String namesStr) {
if (namesStr == null) {
return null;
}
return Arrays.stream(namesStr.split(VALUE_DELIMITER)).map(name -> {
return Enum.valueOf(enumType, name);
}).collect(Collectors.toList()).toArray(
(T[]) Array.newInstance(enumType, 0));
}
/*
* Determines if the specified process is alive.
*/
public static boolean isAliveProcess(Process process) {
return process != null && process.isAlive();
}
/*
* Destroys the specified process and the associated child processes.
*/
public static void destroyProcess(Process process) {
process.children().forEach(ProcessHandle::destroy);
process.destroy();
}
/*
* Reads the content for the specified file.
*/
public static Optional<String> readFile(Path path) throws IOException {
if (!Files.exists(path)) {
return Optional.empty();
} else {
return Optional.of(new String(Files.readAllBytes(path)));
}
}
/*
* Tries to delete the specified file before getting timeout,
* in case that the file is not released by some process in time.
*/
public static void deleteFile(Path filePath) throws IOException {
if (filePath == null) {
return;
}
waitFor(path -> delete(path), filePath);
if (Files.exists(filePath)) {
throw new IOException(
"File is not deleted in time: " + filePath.toAbsolutePath());
}
}
private static boolean delete(Path filePath) {
boolean deleted = false;
try {
deleted = Files.deleteIfExists(filePath);
} catch (IOException e) {
e.printStackTrace(System.out);
}
return deleted;
}
/*
* Determines if the TLS session is resumed.
*/
public static boolean isSessionResumed(ResumptionMode mode,
byte[] firstSessionId, byte[] secondSessionId,
long firstSessionCreationTime, long secondSessionCreationTime) {
System.out.println("ResumptionMode: " + mode);
System.out.println("firstSessionId: " + Arrays.toString(firstSessionId));
System.out.println("secondSessionId: " + Arrays.toString(secondSessionId));
System.out.println("firstSessionCreationTime: " + firstSessionCreationTime);
System.out.println("secondSessionCreationTime: " + secondSessionCreationTime);
boolean resumed = firstSessionCreationTime == secondSessionCreationTime;
if (mode == ResumptionMode.ID) {
resumed = resumed && firstSessionId.length > 0
&& Arrays.equals(firstSessionId, secondSessionId);
}
return resumed;
}
@SuppressWarnings("unchecked")
public static <T> String join(String delimiter, Function<T, String> toStr,
T... elements) {
if (elements == null) {
return "";
}
StringJoiner joiner = new StringJoiner(delimiter);
for (T element : elements) {
if (element != null) {
String str = toStr.apply(element);
if (str != null && !str.isEmpty()) {
joiner.add(str);
}
}
}
return joiner.toString();
}
@SuppressWarnings("unchecked")
public static <T> String join(String delimiter, T... elements) {
return join(delimiter, elem -> {
return elem.toString();
}, elements);
}
@SuppressWarnings("unchecked")
public static <T> String join(T... elements) {
return join(VALUE_DELIMITER, elements);
}
@SuppressWarnings("unchecked")
public static <T> String join(Function<T, String> toStr, T... elements) {
return join(VALUE_DELIMITER, toStr, elements);
}
public static String joinOptValue(String delimiter, String option,
Object value) {
return value == null || value.toString().isEmpty()
? ""
: option + delimiter + value;
}
public static String joinOptValue(String option, Object value) {
return joinOptValue(" ", option, value);
}
public static String joinNameValue(String option, Object value) {
return joinOptValue("=", option, value);
}
public static String[] split(String str, String delimiter) {
if (str == null) {
return null;
}
return str.split(delimiter);
}
public static String[] split(String str) {
return split(str, VALUE_DELIMITER);
}
public static String trimStr(String str) {
return str == null ? "" : str.trim();
}
public static boolean isEmpty(String str) {
return str == null || str.isEmpty();
}
/*
* Determines the expected negotiated application protocol from the server
* and client application protocols.
*/
public static String expectedNegoAppProtocol(String[] serverAppProtocols,
String[] clientAppProtocols) {
if (serverAppProtocols != null && clientAppProtocols != null) {
for(String clientAppProtocol : clientAppProtocols) {
for(String serverAppProtocol : serverAppProtocols) {
if (clientAppProtocol.equals(serverAppProtocol)) {
return clientAppProtocol;
}
}
}
}
return null;
}
/*
* Finds the minimum protocol in the specified protocols.
*/
public static Protocol minProtocol(Protocol[] protocols) {
return findProtocol(protocols, true);
}
/*
* Finds the maximum protocol in the specified protocols.
*/
public static Protocol maxProtocol(Protocol[] protocols) {
return findProtocol(protocols, false);
}
private static Protocol findProtocol(Protocol[] protocols, boolean findMin) {
if (protocols == null) {
return null;
}
Arrays.sort(protocols, (p1, p2) -> {
return (p1.id - p2.id) * (findMin ? 1 : -1);
});
return protocols[0];
}
}