Path: blob/master/test/jdk/javax/net/ssl/TLSCommon/interop/Utilities.java
41154 views
/*1* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223import java.io.ByteArrayInputStream;24import java.io.File;25import java.io.IOException;26import java.io.InputStream;27import java.io.OutputStream;28import java.lang.reflect.Array;29import java.nio.charset.Charset;30import java.nio.charset.StandardCharsets;31import java.nio.file.Files;32import java.nio.file.Path;33import java.security.KeyFactory;34import java.security.KeyStore;35import java.security.KeyStoreException;36import java.security.NoSuchAlgorithmException;37import java.security.PrivateKey;38import java.security.cert.Certificate;39import java.security.cert.CertificateException;40import java.security.cert.CertificateFactory;41import java.security.spec.InvalidKeySpecException;42import java.security.spec.PKCS8EncodedKeySpec;43import java.util.Arrays;44import java.util.Base64;45import java.util.Optional;46import java.util.StringJoiner;47import java.util.concurrent.TimeUnit;48import java.util.function.Function;49import java.util.function.Predicate;50import java.util.stream.Collectors;5152import javax.net.ssl.KeyManagerFactory;53import javax.net.ssl.SSLContext;54import javax.net.ssl.TrustManagerFactory;5556import jdk.test.lib.process.OutputAnalyzer;5758/*59* Utilities for interop testing.60*/61public class Utilities {6263public static final String JAVA_HOME = System.getProperty("java.home");64public static final String JAVA65= String.join(File.separator, JAVA_HOME, "bin", "java");66public static final String JAVAC67= String.join(File.separator, JAVA_HOME, "bin", "javac");6869public static final String TEST_SRC = System.getProperty("test.src");70public static final String TEST_CLASSES = System.getProperty("test.classes");71public static final String TEST_CLASSPATH = System.getProperty("test.class.path");7273public static final Charset CHARSET = StandardCharsets.UTF_8;7475public static final boolean DEBUG = Boolean.getBoolean("test.debug");76public static final int TIMEOUT = Integer.getInteger("test.timeout", 20);77public static final String LOG_PATH = System.getProperty("test.log.path");7879public static final String PARAM_DELIMITER = ";";80public static final String VALUE_DELIMITER = ",";8182public static final CipherSuite[] ALL_CIPHER_SUITES = getAllCipherSuites();8384/*85* Gets all supported cipher suites.86*/87private static CipherSuite[] getAllCipherSuites() {88String[] supportedCipherSuites;89try {90supportedCipherSuites = SSLContext.getDefault()91.createSSLEngine()92.getSupportedCipherSuites();93} catch (NoSuchAlgorithmException e) {94throw new RuntimeException(95"Failed to get supported cipher suites", e);96}9798CipherSuite[] cipherSuites = Arrays.stream(supportedCipherSuites)99.map(cipherSuite -> {100return CipherSuite.cipherSuite(cipherSuite);})101.filter(cipherSuite -> {102return cipherSuite != CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV; })103.toArray(CipherSuite[]::new);104105return cipherSuites;106}107108/*109* Creates SSL context with the specified certificates.110*/111public static SSLContext createSSLContext(CertTuple certTuple)112throws Exception {113KeyStore trustStore = createTrustStore(certTuple.trustedCerts);114TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");115tmf.init(trustStore);116117KeyStore keyStore = createKeyStore(certTuple.endEntityCerts);118KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");119kmf.init(keyStore, null);120121SSLContext context = SSLContext.getInstance("TLS");122context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);123return context;124}125126/*127* Creates trust store with the specified certificates.128*/129public static KeyStore createTrustStore(Cert... certs)130throws KeyStoreException, IOException, NoSuchAlgorithmException,131CertificateException {132KeyStore trustStore = KeyStore.getInstance("PKCS12");133trustStore.load(null, null);134135if (certs != null) {136for (int i = 0; i < certs.length; i++) {137if (certs[i] != null) {138trustStore.setCertificateEntry("trust-" + i,139createCert(certs[i]));140}141}142}143144return trustStore;145}146147/*148* Creates key store with the specified certificates.149*/150public static KeyStore createKeyStore(Cert... certs)151throws KeyStoreException, IOException, NoSuchAlgorithmException,152CertificateException, InvalidKeySpecException {153KeyStore keyStore = KeyStore.getInstance("PKCS12");154keyStore.load(null, null);155156if (certs != null) {157for (int i = 0; i < certs.length; i++) {158if (certs[i] != null) {159keyStore.setKeyEntry("cert-" + i, createKey(certs[i]), null,160new Certificate[] { createCert(certs[i]) });161}162}163}164165return keyStore;166}167168/*169* Creates Certificate instance with the specified certificate.170*/171public static Certificate createCert(Cert cert) {172try {173CertificateFactory certFactory = CertificateFactory.getInstance("X.509");174return certFactory.generateCertificate(175new ByteArrayInputStream(cert.certMaterials.getBytes()));176} catch (CertificateException e) {177throw new RuntimeException("Create cert failed: " + cert, e);178}179}180181/*182* Creates PrivateKey instance with the specified certificate.183*/184public static PrivateKey createKey(Cert cert)185throws NoSuchAlgorithmException, InvalidKeySpecException {186PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(187Base64.getMimeDecoder().decode(cert.keyMaterials));188KeyFactory keyFactory = KeyFactory.getInstance(189cert.keyAlgo.name);190PrivateKey privKey = keyFactory.generatePrivate(privKeySpec);191return privKey;192}193194/*195* Reads an input stream, in which the content length isn't more than 1024.196*/197public static String readIn(InputStream input) throws IOException {198byte[] buf = new byte[1024];199int length = input.read(buf);200if (length > 0) {201return new String(buf, 0, length);202} else {203return "";204}205}206207/*208* Writes the specified content to an output stream.209*/210public static void writeOut(OutputStream output, String content)211throws IOException {212output.write(content.getBytes(Utilities.CHARSET));213output.flush();214}215216/*217* Sleeps until the condition is true or getting timeout.218*/219public static <T> boolean waitFor(Predicate<T> predicate, T t) {220long deadline = System.currentTimeMillis() + Utilities.TIMEOUT * 1000;221boolean predicateResult = predicate.test(t);222while (!predicateResult && System.currentTimeMillis() < deadline) {223try {224TimeUnit.SECONDS.sleep(1);225predicateResult = predicate.test(t);226} catch (InterruptedException e) {227throw new RuntimeException("Sleep is interrupted.", e);228}229}230231return predicateResult;232}233234/*235* Converts Enum array to string array.236* The string elements are the Enum names.237*/238public static String[] enumsToStrs(Enum<?>... elements) {239return enumsToStrs(element -> {240return element.name();241}, elements);242}243244/*245* Converts NamedGroup array to string array.246* The string elements are the NameGroups' names.247*/248public static String[] namedGroupsToStrs(NamedGroup... namedGroups) {249return enumsToStrs(namedGroup -> {250return ((NamedGroup) namedGroup).name;251}, namedGroups);252}253254/*255* Converts Enum array to string array.256* The string elements are determined by the specified Function.257*/258public static String[] enumsToStrs(Function<Enum<?>, String> function,259Enum<?>... elements) {260return elements == null261? null262: Arrays.stream(elements).map(function).toArray(String[]::new);263}264265/*266* Converts string array to Enum array.267*/268@SuppressWarnings("unchecked")269public static <T extends Enum<T>> T[] strToEnums(Class<T> enumType,270String namesStr) {271if (namesStr == null) {272return null;273}274275return Arrays.stream(namesStr.split(VALUE_DELIMITER)).map(name -> {276return Enum.valueOf(enumType, name);277}).collect(Collectors.toList()).toArray(278(T[]) Array.newInstance(enumType, 0));279}280281/*282* Determines if the specified process is alive.283*/284public static boolean isAliveProcess(Process process) {285return process != null && process.isAlive();286}287288/*289* Destroys the specified process and the associated child processes.290*/291public static void destroyProcess(Process process) {292process.children().forEach(ProcessHandle::destroy);293process.destroy();294}295296/*297* Reads the content for the specified file.298*/299public static Optional<String> readFile(Path path) throws IOException {300if (!Files.exists(path)) {301return Optional.empty();302} else {303return Optional.of(new String(Files.readAllBytes(path)));304}305}306307/*308* Tries to delete the specified file before getting timeout,309* in case that the file is not released by some process in time.310*/311public static void deleteFile(Path filePath) throws IOException {312if (filePath == null) {313return;314}315316waitFor(path -> delete(path), filePath);317if (Files.exists(filePath)) {318throw new IOException(319"File is not deleted in time: " + filePath.toAbsolutePath());320}321}322323private static boolean delete(Path filePath) {324boolean deleted = false;325try {326deleted = Files.deleteIfExists(filePath);327} catch (IOException e) {328e.printStackTrace(System.out);329}330331return deleted;332}333334/*335* Determines if the TLS session is resumed.336*/337public static boolean isSessionResumed(ResumptionMode mode,338byte[] firstSessionId, byte[] secondSessionId,339long firstSessionCreationTime, long secondSessionCreationTime) {340System.out.println("ResumptionMode: " + mode);341System.out.println("firstSessionId: " + Arrays.toString(firstSessionId));342System.out.println("secondSessionId: " + Arrays.toString(secondSessionId));343System.out.println("firstSessionCreationTime: " + firstSessionCreationTime);344System.out.println("secondSessionCreationTime: " + secondSessionCreationTime);345346boolean resumed = firstSessionCreationTime == secondSessionCreationTime;347if (mode == ResumptionMode.ID) {348resumed = resumed && firstSessionId.length > 0349&& Arrays.equals(firstSessionId, secondSessionId);350}351return resumed;352}353354@SuppressWarnings("unchecked")355public static <T> String join(String delimiter, Function<T, String> toStr,356T... elements) {357if (elements == null) {358return "";359}360361StringJoiner joiner = new StringJoiner(delimiter);362for (T element : elements) {363if (element != null) {364String str = toStr.apply(element);365if (str != null && !str.isEmpty()) {366joiner.add(str);367}368}369}370return joiner.toString();371}372373@SuppressWarnings("unchecked")374public static <T> String join(String delimiter, T... elements) {375return join(delimiter, elem -> {376return elem.toString();377}, elements);378}379380@SuppressWarnings("unchecked")381public static <T> String join(T... elements) {382return join(VALUE_DELIMITER, elements);383}384385@SuppressWarnings("unchecked")386public static <T> String join(Function<T, String> toStr, T... elements) {387return join(VALUE_DELIMITER, toStr, elements);388}389390public static String joinOptValue(String delimiter, String option,391Object value) {392return value == null || value.toString().isEmpty()393? ""394: option + delimiter + value;395}396397public static String joinOptValue(String option, Object value) {398return joinOptValue(" ", option, value);399}400401public static String joinNameValue(String option, Object value) {402return joinOptValue("=", option, value);403}404405public static String[] split(String str, String delimiter) {406if (str == null) {407return null;408}409410return str.split(delimiter);411}412413public static String[] split(String str) {414return split(str, VALUE_DELIMITER);415}416417public static String trimStr(String str) {418return str == null ? "" : str.trim();419}420421public static boolean isEmpty(String str) {422return str == null || str.isEmpty();423}424425/*426* Determines the expected negotiated application protocol from the server427* and client application protocols.428*/429public static String expectedNegoAppProtocol(String[] serverAppProtocols,430String[] clientAppProtocols) {431if (serverAppProtocols != null && clientAppProtocols != null) {432for(String clientAppProtocol : clientAppProtocols) {433for(String serverAppProtocol : serverAppProtocols) {434if (clientAppProtocol.equals(serverAppProtocol)) {435return clientAppProtocol;436}437}438}439}440441return null;442}443444/*445* Finds the minimum protocol in the specified protocols.446*/447public static Protocol minProtocol(Protocol[] protocols) {448return findProtocol(protocols, true);449}450451/*452* Finds the maximum protocol in the specified protocols.453*/454public static Protocol maxProtocol(Protocol[] protocols) {455return findProtocol(protocols, false);456}457458private static Protocol findProtocol(Protocol[] protocols, boolean findMin) {459if (protocols == null) {460return null;461}462463Arrays.sort(protocols, (p1, p2) -> {464return (p1.id - p2.id) * (findMin ? 1 : -1);465});466return protocols[0];467}468}469470471