changeset 58968:b6b4506a7827

8243029: Rewrite javax/net/ssl/compatibility/Compatibility.java with a flexible interop test framework Reviewed-by: xuelei
author jjiang
date Fri, 24 Apr 2020 15:28:57 +0800
parents b1ad66e04b88
children 0c3459aec641
files test/jdk/javax/net/ssl/TLSCommon/Cert.java test/jdk/javax/net/ssl/TLSCommon/CipherSuite.java test/jdk/javax/net/ssl/TLSCommon/HashAlgorithm.java test/jdk/javax/net/ssl/TLSCommon/KeyUpdateRequest.java test/jdk/javax/net/ssl/TLSCommon/NamedGroup.java test/jdk/javax/net/ssl/TLSCommon/ResumptionMode.java test/jdk/javax/net/ssl/TLSCommon/SignatureAlgorithm.java test/jdk/javax/net/ssl/TLSCommon/interop/AbstractClient.java test/jdk/javax/net/ssl/TLSCommon/interop/AbstractPeer.java test/jdk/javax/net/ssl/TLSCommon/interop/AbstractProduct.java test/jdk/javax/net/ssl/TLSCommon/interop/AbstractServer.java test/jdk/javax/net/ssl/TLSCommon/interop/BaseInteropTest.java test/jdk/javax/net/ssl/TLSCommon/interop/CertTuple.java test/jdk/javax/net/ssl/TLSCommon/interop/Client.java test/jdk/javax/net/ssl/TLSCommon/interop/ConnectionInterceptor.java test/jdk/javax/net/ssl/TLSCommon/interop/ExtInteropTest.java test/jdk/javax/net/ssl/TLSCommon/interop/ExtUseCase.java test/jdk/javax/net/ssl/TLSCommon/interop/Jdk.java test/jdk/javax/net/ssl/TLSCommon/interop/JdkClient.java test/jdk/javax/net/ssl/TLSCommon/interop/JdkHttpsClient.java test/jdk/javax/net/ssl/TLSCommon/interop/JdkProcClient.java test/jdk/javax/net/ssl/TLSCommon/interop/JdkProcServer.java test/jdk/javax/net/ssl/TLSCommon/interop/JdkProcUtils.java test/jdk/javax/net/ssl/TLSCommon/interop/JdkServer.java test/jdk/javax/net/ssl/TLSCommon/interop/JdkUtils.java test/jdk/javax/net/ssl/TLSCommon/interop/KeyUpdateUseCase.java test/jdk/javax/net/ssl/TLSCommon/interop/Peer.java test/jdk/javax/net/ssl/TLSCommon/interop/ProcUtils.java test/jdk/javax/net/ssl/TLSCommon/interop/Product.java test/jdk/javax/net/ssl/TLSCommon/interop/ResumptionUseCase.java test/jdk/javax/net/ssl/TLSCommon/interop/SSLTestException.java test/jdk/javax/net/ssl/TLSCommon/interop/Server.java test/jdk/javax/net/ssl/TLSCommon/interop/Status.java test/jdk/javax/net/ssl/TLSCommon/interop/TestCase.java test/jdk/javax/net/ssl/TLSCommon/interop/UseCase.java test/jdk/javax/net/ssl/TLSCommon/interop/Utilities.java test/jdk/javax/net/ssl/compatibility/AlpnTest.java test/jdk/javax/net/ssl/compatibility/BasicConnectTest.java test/jdk/javax/net/ssl/compatibility/Cert.java test/jdk/javax/net/ssl/compatibility/Client.java test/jdk/javax/net/ssl/compatibility/Compatibility.java test/jdk/javax/net/ssl/compatibility/HrrTest.java test/jdk/javax/net/ssl/compatibility/JdkInfo.java test/jdk/javax/net/ssl/compatibility/JdkInfoUtils.java test/jdk/javax/net/ssl/compatibility/JdkUtils.java test/jdk/javax/net/ssl/compatibility/ProcessUtils.java test/jdk/javax/net/ssl/compatibility/README test/jdk/javax/net/ssl/compatibility/Server.java test/jdk/javax/net/ssl/compatibility/SniTest.java test/jdk/javax/net/ssl/compatibility/Status.java test/jdk/javax/net/ssl/compatibility/TestCase.java test/jdk/javax/net/ssl/compatibility/UseCase.java test/jdk/javax/net/ssl/compatibility/Utils.java test/lib/jdk/test/lib/security/CertUtils.java
diffstat 54 files changed, 4469 insertions(+), 1990 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/Cert.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+/*
+ * The certificates and corresponding private keys.
+ */
+public class Cert {
+
+    public final KeyAlgorithm keyAlgo;
+    public final SignatureAlgorithm sigAlgo;
+    public final HashAlgorithm hashAlgo;
+
+    public final String certMaterials;
+    public final String keyMaterials;
+
+    public Cert(
+            KeyAlgorithm keyAlgo,
+            SignatureAlgorithm sigAlgo,
+            HashAlgorithm hashAlgo,
+            String certMaterials,
+            String keyMaterials) {
+        this.keyAlgo = keyAlgo;
+        this.sigAlgo = sigAlgo;
+        this.hashAlgo = hashAlgo;
+
+        this.certMaterials = certMaterials;
+        this.keyMaterials = keyMaterials;
+    }
+
+    public Cert(
+            KeyAlgorithm keyAlgo,
+            SignatureAlgorithm sigAlgo,
+            HashAlgorithm hashAlgo,
+            String certMaterials) {
+        this(keyAlgo, sigAlgo, hashAlgo, certMaterials, null);
+    }
+
+    @Override
+    public String toString() {
+        return "keyAlgo=" + keyAlgo
+                + ",sigAlgo=" + sigAlgo
+                + ",hashAlg=" + hashAlgo;
+    }
+}
--- a/test/jdk/javax/net/ssl/TLSCommon/CipherSuite.java	Thu Apr 23 22:49:55 2020 -0700
+++ b/test/jdk/javax/net/ssl/TLSCommon/CipherSuite.java	Fri Apr 24 15:28:57 2020 +0800
@@ -161,7 +161,7 @@
     TLS_DHE_RSA_WITH_AES_256_CBC_SHA(
             0x0039, KeyExAlgorithm.DHE_RSA, Protocol.SSLV3, Protocol.TLSV1_2),
     TLS_DHE_DSS_WITH_AES_256_CBC_SHA(
-            0x0038, KeyExAlgorithm.DHE_DSS, Protocol.TLSV1_2, Protocol.TLSV1_2),
+            0x0038, KeyExAlgorithm.DHE_DSS, Protocol.SSLV3, Protocol.TLSV1_2),
     TLS_RSA_WITH_AES_256_CBC_SHA(
             0x0035, KeyExAlgorithm.RSA, Protocol.SSLV3, Protocol.TLSV1_2),
     TLS_DH_anon_WITH_AES_128_CBC_SHA(
@@ -169,7 +169,7 @@
     TLS_DHE_RSA_WITH_AES_128_CBC_SHA(
             0x0033, KeyExAlgorithm.DHE_RSA, Protocol.SSLV3, Protocol.TLSV1_2),
     TLS_DHE_DSS_WITH_AES_128_CBC_SHA(
-            0x0032, KeyExAlgorithm.DHE_DSS, Protocol.TLSV1_2, Protocol.TLSV1_2),
+            0x0032, KeyExAlgorithm.DHE_DSS, Protocol.SSLV3, Protocol.TLSV1_2),
     TLS_RSA_WITH_AES_128_CBC_SHA(
             0x002F, KeyExAlgorithm.RSA, Protocol.SSLV3, Protocol.TLSV1_2),
     TLS_KRB5_WITH_3DES_EDE_CBC_MD5(
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/HashAlgorithm.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+/*
+ * Hash algorithms.
+ */
+public enum HashAlgorithm {
+
+    SHA1("SHA-1"),
+    SHA256("SHA-256"),
+    SHA384("SHA-384"),
+    SHA512("SHA-512");
+
+    public final String name;
+
+    private HashAlgorithm(String name) {
+        this.name = name;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/KeyUpdateRequest.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+public enum KeyUpdateRequest {
+
+    NOT_REQUESTED("update_not_requested"),
+    REQUESTED("update_requested");
+
+    public String name;
+
+    KeyUpdateRequest(String name) {
+        this.name = name;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/NamedGroup.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+/*
+ * Named groups.
+ */
+public enum NamedGroup {
+
+    SECP256R1("secp256r1"),
+    SECP384R1("secp384r1"),
+    SECP521R1("secp521r1"),
+
+    X448("x448"),
+    X25519("x25519"),
+
+    FFDHE2048("ffdhe2048"),
+    FFDHE3072("ffdhe3072"),
+    FFDHE4096("ffdhe4096"),
+    FFDHE6144("ffdhe6144"),
+    FFDHE8192("ffdhe8192");
+
+    public final String name;
+
+    private NamedGroup(String name) {
+        this.name = name;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/ResumptionMode.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+/*
+ * The session resumption modes.
+ */
+public enum ResumptionMode {
+
+    ID,      // Resumed via session id
+    TICKET,  // Resumed via session ticket
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/SignatureAlgorithm.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+/*
+ * Signature algorithms.
+ */
+public enum SignatureAlgorithm {
+
+    RSA("RSA"),
+    DSA("DSA"),
+    ECDSA("ECDSA"),
+    RSASSAPSS("RSASSA-PSS");
+
+    public final String name;
+
+    private SignatureAlgorithm(String name) {
+        this.name = name;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/AbstractClient.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,54 @@
+/*
+ * 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.IOException;
+
+/*
+ * An abstract client.
+ */
+public abstract class AbstractClient extends AbstractPeer implements Client {
+
+    @Override
+    protected void printLog() throws IOException {
+        System.out.println("---------- Client log start ----------");
+        super.printLog();
+        System.out.println("---------- Client log end ----------");
+    }
+
+    public static abstract class Builder extends AbstractPeer.Builder {
+
+        // Indicate if try to read response.
+        private boolean readResponse = true;
+
+        public boolean isReadResponse() {
+            return readResponse;
+        }
+
+        public Builder setReadResponse(boolean readResponse) {
+            this.readResponse = readResponse;
+            return this;
+        }
+
+        public abstract AbstractClient build() throws Exception;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/AbstractPeer.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,213 @@
+/*
+ * 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.IOException;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/*
+ * Abstract peer implementation.
+ */
+public abstract class AbstractPeer implements Peer {
+
+    /*
+     * Peer's log path. The path could be null.
+     */
+    protected Path getLogPath() {
+        return null;
+    }
+
+    /*
+     * Prints the content of log file to stdout.
+     */
+    protected void printLog() throws IOException {
+        Path logPath = getLogPath();
+        Objects.requireNonNull(logPath, "Please specify log path.");
+        System.out.println(Utilities.readFile(logPath).orElse(""));
+    }
+
+    /*
+     * Deletes log file if exists.
+     */
+    protected void deleteLog() throws IOException {
+        Utilities.deleteFile(getLogPath());
+    }
+
+    /*
+     * The negotiated application protocol.
+     */
+    public String getNegoAppProtocol() throws SSLTestException {
+        throw new UnsupportedOperationException("getNegoAppProtocol");
+    }
+
+    @Override
+    public void close() throws IOException { }
+
+    public static abstract class Builder implements Peer.Builder {
+
+        // The supported SSL/TLS protocols.
+        private Protocol[] protocols;
+
+        // The supported cipher suites.
+        private CipherSuite[] cipherSuites;
+
+        // The trusted CAs and certificates.
+        private CertTuple certTuple;
+
+        // The server-acceptable SNI server name patterns;
+        // Or the client-desired SNI server names.
+        private String[] serverNames;
+
+        // The supported application protocols.
+        private String[] appProtocols;
+
+        // The supported named groups.
+        private NamedGroup[] namedGroups;
+
+        private String message = "M";
+
+        private int timeout = Utilities.TIMEOUT;
+
+        // System properties
+        private final Map<String, String> props = new HashMap<>();
+
+        public Protocol[] getProtocols() {
+            return protocols;
+        }
+
+        public Protocol getProtocol() {
+            return protocols != null && protocols.length > 0
+                    ? protocols[0]
+                    : null;
+        }
+
+        public Builder setProtocols(Protocol... protocols) {
+            this.protocols = protocols;
+            return this;
+        }
+
+        public CipherSuite[] getCipherSuites() {
+            return cipherSuites;
+        }
+
+        public CipherSuite getCipherSuite() {
+            return cipherSuites != null && cipherSuites.length > 0
+                    ? cipherSuites[0]
+                    : null;
+        }
+
+        public Builder setCipherSuites(CipherSuite... cipherSuites) {
+            this.cipherSuites = cipherSuites;
+            return this;
+        }
+
+        public CertTuple getCertTuple() {
+            return certTuple;
+        }
+
+        public Builder setCertTuple(CertTuple certTuple) {
+            this.certTuple = certTuple;
+            return this;
+        }
+
+        public String[] getServerNames() {
+            return serverNames;
+        }
+
+        public String getServerName() {
+            return serverNames != null && serverNames.length > 0
+                    ? serverNames[0]
+                    : null;
+        }
+
+        public Builder setServerNames(String... serverNames) {
+            this.serverNames = serverNames;
+            return this;
+        }
+
+        public String[] getAppProtocols() {
+            return appProtocols;
+        }
+
+        public String getAppProtocol() {
+            return appProtocols != null && appProtocols.length > 0
+                    ? appProtocols[0]
+                    : null;
+        }
+
+        public Builder setAppProtocols(String... appProtocols) {
+            this.appProtocols = appProtocols;
+            return this;
+        }
+
+        public NamedGroup[] getNamedGroups() {
+            return namedGroups;
+        }
+
+        public Builder setNamedGroups(NamedGroup... namedGroups) {
+            this.namedGroups = namedGroups;
+            return this;
+        }
+
+        public String getMessage() {
+            return message;
+        }
+
+        public Builder setMessage(String message) {
+            this.message = message;
+            return this;
+        }
+
+        public int getTimeout() {
+            return timeout;
+        }
+
+        public Builder setTimeout(int timeout) {
+            this.timeout = timeout;
+            return this;
+        }
+
+        public Builder addProp(String prop, String value) {
+            props.put(prop, value);
+            return this;
+        }
+
+        public String getProp(String prop) {
+            return props.get(prop);
+        }
+
+        public Builder addAllProps(Map<String, String> props) {
+            this.props.putAll(props);
+            return this;
+        }
+
+        public Map<String, String> getAllProps() {
+            return Collections.unmodifiableMap(props);
+        }
+
+        public abstract AbstractPeer build() throws Exception;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/AbstractProduct.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,65 @@
+/*
+ * 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.nio.file.Path;
+
+/*
+ * An abstract product definition.
+ */
+public abstract class AbstractProduct implements Product {
+
+    @Override
+    public Path getPath() {
+        return null;
+    }
+
+    @Override
+    public String toString() {
+        return getName();
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((getPath() == null) ? 0 : getPath().hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        Jdk other = (Jdk) obj;
+        if (getPath() == null) {
+            if (other.getPath() != null)
+                return false;
+        } else if (!getPath().equals(other.getPath()))
+            return false;
+        return true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/AbstractServer.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,80 @@
+/*
+ * 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.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/*
+ * An abstract server.
+ */
+public abstract class AbstractServer extends AbstractPeer implements Server {
+
+    @Override
+    protected void printLog() throws IOException {
+        System.out.println("---------- Server log start ----------");
+        super.printLog();
+        System.out.println("---------- Server log end ----------");
+    }
+
+    /*
+     * Generally, server outputs logs to a separated file.
+     * For some cases, this file could be used as a synchronizer between
+     * server and client.
+     */
+    @Override
+    public Path getLogPath() {
+        return Paths.get("server.log");
+    }
+
+    @Override
+    public void signalStop() throws Exception { }
+
+    public static abstract class Builder extends AbstractPeer.Builder {
+
+        private int port;
+
+        // Indicates if requires client authentication.
+        private boolean clientAuth = true;
+
+        public int getPort() {
+            return port;
+        }
+
+        public Builder setPort(int port) {
+            this.port = port;
+            return this;
+        }
+
+        public boolean getClientAuth() {
+            return clientAuth;
+        }
+
+        public Builder setClientAuth(boolean clientAuth) {
+            this.clientAuth = clientAuth;
+            return this;
+        }
+
+        public abstract AbstractServer build() throws Exception;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/BaseInteropTest.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,336 @@
+/*
+ * 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.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/*
+ * The base interop test on SSL/TLS communication.
+ */
+public abstract class BaseInteropTest<U extends UseCase> {
+
+    protected final Product serverProduct;
+    protected final Product clientProduct;
+
+    public BaseInteropTest(Product serverProduct, Product clientProduct) {
+        this.serverProduct = serverProduct;
+        this.clientProduct = clientProduct;
+    }
+
+    public boolean isJdkClient() {
+        return Jdk.DEFAULT.equals(clientProduct);
+    }
+
+    /*
+     * This main entrance of the test execution.
+     */
+    protected void execute() throws Exception {
+        System.out.printf("Server: %s%nClient: %s%n",
+                serverProduct, clientProduct);
+
+        if (skipExecute()) {
+            System.out.println("This execution was skipped.");
+            return;
+        }
+
+        List<TestCase<U>> testCases = null;
+
+        Path logPath = getLogPath();
+        if (logPath != null) {
+            System.out.println("Log: " + logPath);
+
+            PrintStream origStdOut = System.out;
+            PrintStream origStdErr = System.err;
+            try (PrintStream printStream = new PrintStream(
+                    new FileOutputStream(logPath.toFile()))) {
+                System.setOut(printStream);
+                System.setErr(printStream);
+
+                testCases = runTest();
+            } finally {
+                System.setOut(origStdOut);
+                System.setErr(origStdErr);
+            }
+        } else {
+            testCases = runTest();
+        }
+
+        boolean fail = false;
+        System.out.println("########## Failed Cases Start ##########");
+        for (TestCase<U> testCase : testCases) {
+            if (testCase.getStatus() == Status.FAIL) {
+                System.out.println("--------------------");
+                System.out.println(testCase);
+                System.out.println("--------------------");
+                fail = true;
+            }
+        }
+        System.out.println("########## Failed Cases End ##########");
+
+        if (fail) {
+            throw new RuntimeException(
+                    "At least one case failed! Please check log for details.");
+        } else {
+            System.out.println("This test passed!");
+        }
+    }
+
+    /*
+     * If either of server and client products is unavailable,
+     * just skip this test execution.
+     */
+    protected boolean skipExecute() {
+        return serverProduct.getPath() == null || clientProduct.getPath() == null;
+    }
+
+    /*
+     * Returns the log path.
+     * If null, no output will be redirected to local file.
+     */
+    protected Path getLogPath() {
+        return Utilities.LOG_PATH == null
+                ? null : Paths.get(Utilities.LOG_PATH);
+    }
+
+    /*
+     * Provides a default set of test cases for testing.
+     */
+    protected abstract List<TestCase<U>> getTestCases();
+
+    /*
+     * Checks if test case should be ignored.
+     */
+    protected boolean ignoreTestCase(TestCase<U> testCase) {
+        return false;
+    }
+
+    /*
+     * Runs all test cases with the specified products as server and client
+     * respectively.
+     */
+    protected List<TestCase<U>> runTest() throws Exception {
+        List<TestCase<U>> executedTestCases = new ArrayList<>();
+
+        List<TestCase<U>> testCases = getTestCases();
+        for (TestCase<U> testCase : testCases) {
+            System.out.println("========== Case Start ==========");
+            System.out.println(testCase);
+
+            if (!ignoreTestCase(testCase)) {
+                Status status = runTestCase(testCase);
+                testCase.setStatus(status);
+
+                executedTestCases.add(testCase);
+            } else {
+                System.out.println("Ignored");
+            }
+
+            System.out.println("========== Case End ==========");
+        }
+
+        return executedTestCases;
+    }
+
+    /*
+     * Runs a specific test case.
+     */
+    protected Status runTestCase(TestCase<U> testCase) throws Exception {
+        Status serverStatus = Status.UNSTARTED;
+        Status clientStatus = Status.UNSTARTED;
+
+        ExecutorService executor = Executors.newFixedThreadPool(1);
+        AbstractServer server = null;
+        try {
+            server = createServer(testCase.serverCase);
+            executor.submit(new ServerTask(server));
+            int port = server.getPort();
+            System.out.println("Server is listening " + port);
+            serverStatus = Status.PASS;
+
+            try (AbstractClient client = createClient(testCase.clientCase)) {
+                client.connect("localhost", port);
+                clientStatus = Status.PASS;
+
+                if (testCase.clientCase instanceof ExtUseCase) {
+                    ExtUseCase serverCase = (ExtUseCase) testCase.serverCase;
+                    ExtUseCase clientCase = (ExtUseCase) testCase.clientCase;
+
+                    String[] clientAppProtocols = clientCase.getAppProtocols();
+                        if (clientAppProtocols != null && clientAppProtocols.length > 0) {
+                        String expectedNegoAppProtocol = Utilities.expectedNegoAppProtocol(
+                                serverCase.getAppProtocols(),
+                                clientAppProtocols);
+                        System.out.println("Expected negotiated app protocol: "
+                                + expectedNegoAppProtocol);
+                        String negoAppProtocol = getNegoAppProtocol(server, client);
+                        System.out.println(
+                                "Actual negotiated app protocol: " + negoAppProtocol);
+                        if (!Utilities.trimStr(negoAppProtocol).equals(
+                                Utilities.trimStr(expectedNegoAppProtocol))) {
+                            System.out.println(
+                                    "Negotiated app protocol is unexpected");
+                            clientStatus = Status.FAIL;
+                        }
+                    }
+                }
+            } catch (Exception exception) {
+                clientStatus = handleClientException(exception);
+            }
+        } catch (Exception exception) {
+            serverStatus = handleServerException(exception);
+        } finally {
+            if (server != null) {
+                server.signalStop();
+                server.close();
+            }
+
+            executor.shutdown();
+        }
+
+        Status caseStatus
+                = serverStatus == Status.PASS && clientStatus == Status.PASS
+                  ? Status.PASS
+                  : Status.FAIL;
+        System.out.printf(
+                "ServerStatus=%s, ClientStatus=%s, CaseStatus=%s%n",
+                serverStatus, clientStatus, caseStatus);
+        return caseStatus;
+    }
+
+    /*
+     * Handles server side exception, and determines the status.
+     */
+    protected Status handleServerException(Exception exception) {
+        return handleException(exception);
+    }
+
+    /*
+     * Handles client side exception, and determines the status.
+     */
+    protected Status handleClientException(Exception exception) {
+        return handleException(exception);
+    }
+
+    private Status handleException(Exception exception) {
+        if (exception == null) {
+            return Status.PASS;
+        }
+
+        exception.printStackTrace(System.out);
+        return Status.FAIL;
+    }
+
+    /*
+     * Creates server.
+     */
+    protected AbstractServer createServer(U useCase) throws Exception {
+        return createServerBuilder(useCase).build();
+    }
+
+    protected AbstractServer.Builder createServerBuilder(U useCase)
+            throws Exception {
+        return (JdkServer.Builder) ((JdkServer.Builder) new JdkServer.Builder()
+                .setProtocols(useCase.getProtocols())
+                .setCipherSuites(useCase.getCipherSuites())
+                .setCertTuple(useCase.getCertTuple()))
+                .setClientAuth(useCase.isClientAuth());
+    }
+
+    /*
+     * Creates client.
+     */
+    protected AbstractClient createClient(U useCase) throws Exception {
+        return createClientBuilder(useCase).build();
+    }
+
+    protected AbstractClient.Builder createClientBuilder(U useCase)
+            throws Exception {
+        return (JdkClient.Builder) new JdkClient.Builder()
+                .setProtocols(useCase.getProtocols())
+                .setCipherSuites(useCase.getCipherSuites())
+                .setCertTuple(useCase.getCertTuple());
+    }
+
+    /*
+     * Determines the negotiated application protocol.
+     * Generally, using JDK client to get this value.
+     */
+    protected String getNegoAppProtocol(AbstractServer server,
+            AbstractClient client) throws SSLTestException {
+        return isJdkClient() ? client.getNegoAppProtocol()
+                             : server.getNegoAppProtocol();
+    }
+
+    protected static class ServerTask implements Callable<Void> {
+
+        private final AbstractServer server;
+
+        protected ServerTask(AbstractServer server) {
+            this.server = server;
+        }
+
+        @Override
+        public Void call() throws IOException {
+            server.accept();
+            return null;
+        }
+    }
+
+    protected static class ClientTask implements Callable<Exception> {
+
+        private final AbstractClient client;
+
+        private final String host;
+        private final int port;
+
+        protected ClientTask(AbstractClient client, String host, int port) {
+            this.client = client;
+
+            this.host = host;
+            this.port = port;
+        }
+
+        protected ClientTask(AbstractClient client, int port) {
+            this(client, "localhost", port);
+        }
+
+        @Override
+        public Exception call() {
+            try (AbstractClient c = client) {
+                c.connect(host, port);
+            } catch (Exception exception) {
+                return exception;
+            }
+
+            return null;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/CertTuple.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+/*
+ * A tuple for carrying certificates.
+ */
+public class CertTuple {
+
+    // Trusted CAs
+    public final Cert[] trustedCerts;
+
+    // End entity certificates
+    public final Cert[] endEntityCerts;
+
+    public CertTuple(Cert[] trustedCerts, Cert[] endEntityCerts) {
+        this.trustedCerts = trustedCerts;
+        this.endEntityCerts = endEntityCerts;
+    }
+
+    public CertTuple(Cert trustedCert, Cert endEntityCert) {
+        this.trustedCerts = new Cert[] { trustedCert };
+        this.endEntityCerts = new Cert[] { endEntityCert };
+    }
+
+    @Override
+    public String toString() {
+        return Utilities.join(Utilities.PARAM_DELIMITER,
+                "trustedCerts=" + Utilities.join(trustedCerts),
+                "endEntityCerts=" + Utilities.join(endEntityCerts));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/Client.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,35 @@
+/*
+ * 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.IOException;
+
+/*
+ * This interface defines functions for SSL/TLS client.
+ */
+public interface Client extends Peer {
+
+    /*
+     * Connect to the specified server.
+     */
+    public void connect(String host, int port) throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/ConnectionInterceptor.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,37 @@
+/*
+ * 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.IOException;
+
+import javax.net.ssl.SSLSocket;
+
+/*
+ * Some extension points in a SSL/TLS connection.
+ */
+public interface ConnectionInterceptor {
+
+    /*
+     * An extension point at the end of the current connection.
+     */
+    public void beforeExit(SSLSocket socket) throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/ExtInteropTest.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,59 @@
+/*
+ * 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.util.List;
+
+/*
+ * The extended base interop test on SSL/TLS communication.
+ */
+public abstract class ExtInteropTest extends BaseInteropTest<ExtUseCase> {
+
+    public ExtInteropTest(Product serverProduct, Product clientProduct) {
+        super(serverProduct, clientProduct);
+    }
+
+    @Override
+    protected abstract List<TestCase<ExtUseCase>> getTestCases();
+
+    @Override
+    protected AbstractServer.Builder createServerBuilder(ExtUseCase useCase)
+            throws Exception {
+        JdkServer.Builder builder
+                = (JdkServer.Builder) super.createServerBuilder(useCase);
+        builder.setServerNames(useCase.getServerNames());
+        builder.setAppProtocols(useCase.getAppProtocols());
+        builder.setNamedGroups(useCase.getNamedGroups());
+        return builder;
+    }
+
+    @Override
+    protected AbstractClient.Builder createClientBuilder(ExtUseCase useCase)
+            throws Exception {
+        JdkClient.Builder builder
+                = (JdkClient.Builder) super.createClientBuilder(useCase);
+        builder.setServerNames(useCase.getServerNames());
+        builder.setAppProtocols(useCase.getAppProtocols());
+        builder.setNamedGroups(useCase.getNamedGroups());
+        return builder;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/ExtUseCase.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+/*
+ * The extended SSL/TLS communication parameters.
+ */
+public class ExtUseCase extends UseCase {
+
+    // The server-acceptable SNI server name patterns;
+    // Or the client-desired SNI server names.
+    private String[] serverNames = null;
+
+    // The supported application protocols.
+    private String[] appProtocols = null;
+
+    // The supported named groups.
+    private NamedGroup[] namedGroups = null;
+
+    public static ExtUseCase newInstance() {
+        return new ExtUseCase();
+    }
+
+    public String[] getServerNames() {
+        return serverNames;
+    }
+
+    public String getServerName() {
+        return serverNames != null && serverNames.length > 0
+                ? serverNames[0]
+                : null;
+    }
+
+    public ExtUseCase setServerNames(String... serverNames) {
+        this.serverNames = serverNames;
+        return this;
+    }
+
+    public String[] getAppProtocols() {
+        return appProtocols;
+    }
+
+    public String getAppProtocol() {
+        return appProtocols != null && appProtocols.length > 0
+                ? appProtocols[0]
+                : null;
+    }
+
+    public ExtUseCase setAppProtocols(String... appProtocols) {
+        this.appProtocols = appProtocols;
+        return this;
+    }
+
+    public NamedGroup[] getNamedGroups() {
+        return namedGroups;
+    }
+
+    public String getNamedGroup() {
+        return namedGroups != null && namedGroups.length > 0
+                ? appProtocols[0]
+                : null;
+    }
+
+    public ExtUseCase setNamedGroups(NamedGroup... namedGroups) {
+        this.namedGroups = namedGroups;
+        return this;
+    }
+
+    @Override
+    public String toString() {
+        return Utilities.join(Utilities.PARAM_DELIMITER,
+                super.toString(),
+                Utilities.joinNameValue(
+                        "serverNames", Utilities.join(serverNames)),
+                Utilities.joinNameValue(
+                        "appProtocols", Utilities.join(appProtocols)),
+                Utilities.joinNameValue(
+                        "NamedGroups", Utilities.join(namedGroups)));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/Jdk.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,57 @@
+/*
+ * 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.nio.file.Path;
+import java.nio.file.Paths;
+
+/*
+ * JDK product.
+ */
+public class Jdk extends AbstractProduct {
+
+    // The default JDK build specified by jtreg option "-jdk".
+    public static final Jdk DEFAULT = new Jdk(
+            "Default JDK", Paths.get(Utilities.JAVA));
+
+    private String name;
+    private Path path;
+
+    public Jdk(String name, Path path) {
+        this.name = name;
+        this.path = path;
+    }
+
+    public Jdk(String name, String path) {
+        this(name, Paths.get(path));
+    }
+
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    @Override
+    public Path getPath() {
+        return path;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/JdkClient.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,158 @@
+/*
+ * 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.IOException;
+import java.net.InetSocketAddress;
+import java.net.SocketException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.net.ssl.SNIHostName;
+import javax.net.ssl.SNIServerName;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+
+/*
+ * A JDK client based on SSLSocket.
+ */
+public class JdkClient extends AbstractClient {
+
+    protected final int timeout;
+    protected final String request;
+    protected final boolean readResponse;
+
+    protected final ConnectionInterceptor interceptor;
+    protected final SSLContext context;
+    protected final SSLSocket socket;
+
+    public JdkClient(Builder builder) throws Exception {
+        timeout = builder.getTimeout() * 1000;
+        request = builder.getMessage();
+        readResponse = builder.isReadResponse();
+
+        interceptor = builder.getInterceptor();
+        context = getContext(builder);
+        socket = (SSLSocket) context.getSocketFactory().createSocket();
+        configClientSocket(builder);
+    }
+
+    protected SSLContext getContext(Builder builder) throws Exception {
+        return builder.getContext() == null
+                ? Utilities.createSSLContext(builder.getCertTuple())
+                : builder.getContext();
+    }
+
+    protected void configClientSocket(Builder builder) throws SocketException {
+        socket.setSoTimeout(timeout);
+        if (builder.getProtocols() != null) {
+            socket.setEnabledProtocols(Utilities.enumsToStrs(protocol -> {
+                return JdkUtils.protocol((Protocol) protocol);
+            }, builder.getProtocols()));
+        }
+        if (builder.getCipherSuites() != null) {
+            socket.setEnabledCipherSuites(
+                    Utilities.enumsToStrs(builder.getCipherSuites()));
+        }
+        SSLParameters sslParams = socket.getSSLParameters();
+        if (builder.getServerNames() != null) {
+            List<SNIServerName> serverNames = new ArrayList<>();
+            for(String bufServerName : builder.getServerNames()) {
+                serverNames.add(new SNIHostName(bufServerName));
+            }
+            sslParams.setServerNames(serverNames);
+        }
+        if (builder.getAppProtocols() != null) {
+            sslParams.setApplicationProtocols(builder.getAppProtocols());
+        }
+        socket.setSSLParameters(sslParams);
+    }
+
+    public static class Builder extends AbstractClient.Builder {
+
+        private ConnectionInterceptor interceptor;
+        private SSLContext context;
+
+        public ConnectionInterceptor getInterceptor() {
+            return interceptor;
+        }
+
+        public Builder setInterceptor(ConnectionInterceptor interceptor) {
+            this.interceptor = interceptor;
+            return this;
+        }
+
+        public SSLContext getContext() {
+            return context;
+        }
+
+        public Builder setContext(SSLContext context) {
+            this.context = context;
+            return this;
+        }
+
+        @Override
+        public JdkClient build() throws Exception {
+            return new JdkClient(this);
+        }
+    }
+
+    @Override
+    public Product getProduct() {
+        return Jdk.DEFAULT;
+    }
+
+    public SSLSession getSession() {
+        return socket.getSession();
+    }
+
+    @Override
+    public void connect(String host, int port) throws IOException {
+        socket.connect(new InetSocketAddress(host, port), timeout);
+        System.out.println("Client connected");
+
+        Utilities.writeOut(socket.getOutputStream(), request);
+        System.out.printf("Client sent request: [%s]%n", request);
+
+        if (readResponse) {
+            String response = Utilities.readIn(socket.getInputStream());
+            System.out.printf("Client received response: [%s]%n", response);
+        }
+
+        if (interceptor != null) {
+            interceptor.beforeExit(socket);
+        }
+    }
+
+    @Override
+    public String getNegoAppProtocol() throws SSLTestException {
+        return socket.getApplicationProtocol();
+    }
+
+    public void close() throws IOException {
+        if (!socket.isClosed()) {
+            socket.close();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/JdkHttpsClient.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,103 @@
+/*
+ * 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.IOException;
+import java.net.URL;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+
+/*
+ * A JDK client based on HttpsURLConnection.
+ */
+public class JdkHttpsClient extends AbstractClient {
+
+    protected final int timeout;
+    protected final String path;
+
+    protected final SSLContext context;
+
+    public JdkHttpsClient(Builder builder) throws Exception {
+        timeout = builder.getTimeout() * 1000;
+        path = builder.getPath();
+
+        context = getContext(builder);
+    }
+
+    protected SSLContext getContext(Builder builder) throws Exception {
+        return builder.getContext() == null
+                ? Utilities.createSSLContext(builder.getCertTuple())
+                : builder.getContext();
+    }
+
+    public static class Builder extends AbstractClient.Builder {
+
+        private String path = "";
+
+        private SSLContext context;
+
+        public String getPath() {
+            return path;
+        }
+
+        public Builder setPath(String path) {
+            this.path = path;
+            return this;
+        }
+
+        public SSLContext getContext() {
+            return context;
+        }
+
+        public Builder setContext(SSLContext context) {
+            this.context = context;
+            return this;
+        }
+
+        @Override
+        public JdkHttpsClient build() throws Exception {
+            return new JdkHttpsClient(this);
+        }
+    }
+
+    @Override
+    public Product getProduct() {
+        return Jdk.DEFAULT;
+    }
+
+    @Override
+    public void connect(String host, int port) throws IOException {
+        String urlStr = String.format("https://%s:%d/%s", host, port, path);
+        if (Utilities.DEBUG) {
+            System.out.println("URL: " + urlStr);
+        }
+
+        HttpsURLConnection conn
+                = (HttpsURLConnection) new URL(urlStr).openConnection();
+        conn.setConnectTimeout(timeout);
+        conn.setReadTimeout(timeout);
+        conn.setSSLSocketFactory(context.getSocketFactory());
+        conn.connect();
+        System.out.println(Utilities.readIn(conn.getInputStream()));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/JdkProcClient.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,186 @@
+/*
+ * 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.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.Map;
+
+/*
+ * A JDK client process.
+ */
+public class JdkProcClient extends AbstractClient {
+
+    private final Jdk jdk;
+    private final Map<String, String> props = new HashMap<>();
+
+    private Process process;
+
+    public JdkProcClient(Builder builder) {
+        this.jdk = builder.getJdk();
+
+        if (builder.getSecPropsFile() != null) {
+            props.put(JdkProcUtils.PROP_SEC_PROPS_FILE,
+                    builder.getSecPropsFile().toString());
+        }
+
+        if (builder.getCertTuple() != null) {
+            props.put(JdkProcUtils.PROP_TRUSTED_CERTS,
+                    JdkProcUtils.certsToStr(builder.getCertTuple().trustedCerts));
+            props.put(JdkProcUtils.PROP_EE_CERTS,
+                    JdkProcUtils.certsToStr(builder.getCertTuple().endEntityCerts));
+        }
+
+        if (builder.getProtocols() != null) {
+            props.put(JdkProcUtils.PROP_PROTOCOLS,
+                    Utilities.join(Utilities.enumsToStrs(builder.getProtocols())));
+        }
+
+        if (builder.getCipherSuites() != null) {
+            props.put(JdkProcUtils.PROP_CIPHER_SUITES,
+                    Utilities.join(Utilities.enumsToStrs(builder.getCipherSuites())));
+        }
+
+        if (builder.getServerNames() != null) {
+            props.put(JdkProcUtils.PROP_SERVER_NAMES,
+                    Utilities.join(builder.getServerNames()));
+        }
+
+        if (builder.getAppProtocols() != null) {
+            props.put(JdkProcUtils.PROP_APP_PROTOCOLS,
+                    Utilities.join(builder.getAppProtocols()));
+        }
+
+        if (builder.getNamedGroups() != null) {
+            props.put(JdkProcUtils.PROP_NAMED_GROUPS,
+                    Utilities.join(Utilities.namedGroupsToStrs(
+                            builder.getNamedGroups())));
+        }
+
+        props.put("test.src", Utilities.TEST_SRC);
+        if (Utilities.DEBUG) {
+            props.put("javax.net.debug", "all");
+        }
+    }
+
+    public static class Builder extends AbstractClient.Builder {
+
+        private Jdk jdk;
+
+        private Path secPropsFile;
+
+        public Jdk getJdk() {
+            return jdk;
+        }
+
+        public Builder setJdk(Jdk jdk) {
+            this.jdk = jdk;
+            return this;
+        }
+
+        public Path getSecPropsFile() {
+            return secPropsFile;
+        }
+
+        public Builder setSecPropsFile(Path secPropsFile) {
+            this.secPropsFile = secPropsFile;
+            return this;
+        }
+
+        @Override
+        public JdkProcClient build() {
+            return new JdkProcClient(this);
+        }
+    }
+
+    @Override
+    public Jdk getProduct() {
+        return jdk;
+    }
+
+    @Override
+    public void connect(String host, int port) throws IOException {
+        props.put(JdkProcUtils.PROP_HOST, host);
+        props.put(JdkProcUtils.PROP_PORT, port + "");
+
+        process = JdkProcUtils.java(getProduct().getPath(), getClass(), props,
+                getLogPath());
+        try {
+            process.waitFor();
+        } catch (InterruptedException e) {
+            throw new RuntimeException("Client was interrupted!", e);
+        }
+
+        if (process.exitValue() != 0) {
+            throw new SSLTestException("Client exited abnormally!");
+        }
+    }
+
+    @Override
+    protected Path getLogPath() {
+        return Paths.get("client.log");
+    }
+
+    @Override
+    public void close() throws IOException {
+        printLog();
+        deleteLog();
+    }
+
+    public static void main(String[] args) throws Exception {
+        String trustedCertsStr = System.getProperty(JdkProcUtils.PROP_TRUSTED_CERTS);
+        String eeCertsStr = System.getProperty(JdkProcUtils.PROP_EE_CERTS);
+
+        String protocolsStr = System.getProperty(JdkProcUtils.PROP_PROTOCOLS);
+        String cipherSuitesStr = System.getProperty(JdkProcUtils.PROP_CIPHER_SUITES);
+
+        String serverNamesStr = System.getProperty(JdkProcUtils.PROP_SERVER_NAMES);
+        String appProtocolsStr = System.getProperty(JdkProcUtils.PROP_APP_PROTOCOLS);
+
+        JdkClient.Builder builder = new JdkClient.Builder();
+        builder.setCertTuple(JdkProcUtils.createCertTuple(
+                trustedCertsStr, eeCertsStr));
+        if (!Utilities.isEmpty(protocolsStr)) {
+            builder.setProtocols(Utilities.strToEnums(
+                    Protocol.class, protocolsStr));
+        }
+        if (!Utilities.isEmpty(cipherSuitesStr)) {
+            builder.setCipherSuites(Utilities.strToEnums(
+                    CipherSuite.class, cipherSuitesStr));
+        }
+        if (!Utilities.isEmpty(serverNamesStr)) {
+            builder.setServerNames(Utilities.split(serverNamesStr));
+        }
+        if (!Utilities.isEmpty(appProtocolsStr)) {
+            builder.setAppProtocols(Utilities.split(appProtocolsStr));
+        }
+
+        String host = System.getProperty(JdkProcUtils.PROP_HOST);
+        int port = Integer.getInteger(JdkProcUtils.PROP_PORT);
+
+        try(JdkClient client = builder.build()) {
+            client.connect(host, port);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/JdkProcServer.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,225 @@
+/*
+ * 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.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.Map;
+
+/*
+ * A JDK server process.
+ */
+public class JdkProcServer extends AbstractServer {
+
+    public static final Path PORT_LOG = Paths.get("port.log");
+
+    private final Jdk jdk;
+    private final Map<String, String> props = new HashMap<>();
+
+    private Process process;
+
+    public JdkProcServer(Builder builder) throws Exception {
+        jdk = builder.getJdk();
+
+        if (builder.getSecPropsFile() != null) {
+            props.put(JdkProcUtils.PROP_SEC_PROPS_FILE,
+                    builder.getSecPropsFile().toString());
+        }
+
+        if (builder.getCertTuple() != null) {
+            props.put(JdkProcUtils.PROP_TRUSTED_CERTS,
+                    JdkProcUtils.certsToStr(builder.getCertTuple().trustedCerts));
+            props.put(JdkProcUtils.PROP_EE_CERTS,
+                    JdkProcUtils.certsToStr(builder.getCertTuple().endEntityCerts));
+        }
+
+        if (builder.getProtocols() != null) {
+            props.put(JdkProcUtils.PROP_PROTOCOLS,
+                    Utilities.join(Utilities.enumsToStrs(builder.getProtocols())));
+        }
+
+        if (builder.getCipherSuites() != null) {
+            props.put(JdkProcUtils.PROP_CIPHER_SUITES,
+                    Utilities.join(Utilities.enumsToStrs(builder.getCipherSuites())));
+        }
+
+        props.put(JdkProcUtils.PROP_CLIENT_AUTH,
+                String.valueOf(builder.getClientAuth()));
+
+        if (builder.getServerNames() != null) {
+            props.put(JdkProcUtils.PROP_SERVER_NAMES,
+                    Utilities.join(builder.getServerNames()));
+        }
+
+        if (builder.getAppProtocols() != null) {
+            props.put(JdkProcUtils.PROP_APP_PROTOCOLS,
+                    Utilities.join(builder.getAppProtocols()));
+        }
+
+        if (builder.getNamedGroups() != null) {
+            props.put(JdkProcUtils.PROP_NAMED_GROUPS,
+                    Utilities.join(Utilities.namedGroupsToStrs(
+                            builder.getNamedGroups())));
+        }
+
+        props.put("test.src", Utilities.TEST_SRC);
+        if (Utilities.DEBUG) {
+            props.put("javax.net.debug", "all");
+        }
+    }
+
+    public static class Builder extends AbstractServer.Builder {
+
+        private Jdk jdk;
+
+        private Path secPropsFile;
+
+        public Jdk getJdk() {
+            return jdk;
+        }
+
+        public Builder setJdk(Jdk jdk) {
+            this.jdk = jdk;
+            return this;
+        }
+
+        public Path getSecPropsFile() {
+            return secPropsFile;
+        }
+
+        public Builder setSecPropsFile(Path secPropsFile) {
+            this.secPropsFile = secPropsFile;
+            return this;
+        }
+
+        @Override
+        public JdkProcServer build() throws Exception {
+            return new JdkProcServer(this);
+        }
+    }
+
+    @Override
+    public Product getProduct() {
+        return jdk;
+    }
+
+    @Override
+    public int getPort() throws IOException {
+        System.out.println("Waiting for port log...");
+        if (!Utilities.waitFor(server -> server.isAlive() && readPort() > 0, this)) {
+            throw new RuntimeException("Server doesn't start in time.");
+        }
+
+        return readPort();
+    }
+
+    @Override
+    public boolean isAlive() {
+        return Utilities.isAliveProcess(process);
+    }
+
+    @Override
+    public void accept() throws IOException {
+        process = JdkProcUtils.java(getProduct().getPath(), getClass(), props,
+                getLogPath());
+        try {
+            process.waitFor();
+        } catch (InterruptedException e) {
+            throw new RuntimeException("Server was interrupted!", e);
+        }
+
+        if (process.exitValue() != 0) {
+            throw new SSLTestException("Server exited abnormally!");
+        }
+    }
+
+    @Override
+    public void signalStop() {
+        if (isAlive()) {
+            Utilities.destroyProcess(process);
+        }
+    }
+
+    @Override
+    public void close() throws IOException {
+        printLog();
+        deletePort();
+        deleteLog();
+    }
+
+    private static int readPort() {
+        try {
+            return Integer.valueOf(new String(Files.readAllBytes(PORT_LOG)));
+        } catch (Exception e) {
+            return 0;
+        }
+    }
+
+    private static void deletePort() throws IOException {
+        Utilities.deleteFile(PORT_LOG);
+    }
+
+    private static void savePort(int port) throws IOException {
+        Files.write(PORT_LOG, String.valueOf(port).getBytes(Utilities.CHARSET));
+    }
+
+    public static void main(String[] args) throws Exception {
+        String trustedCertsStr = System.getProperty(JdkProcUtils.PROP_TRUSTED_CERTS);
+        String eeCertsStr = System.getProperty(JdkProcUtils.PROP_EE_CERTS);
+
+        String protocolsStr = System.getProperty(JdkProcUtils.PROP_PROTOCOLS);
+        String cipherSuitesStr = System.getProperty(JdkProcUtils.PROP_CIPHER_SUITES);
+
+        boolean clientAuth = Boolean.getBoolean(JdkProcUtils.PROP_CLIENT_AUTH);
+        String serverNamesStr = System.getProperty(JdkProcUtils.PROP_SERVER_NAMES);
+        String appProtocolsStr = System.getProperty(JdkProcUtils.PROP_APP_PROTOCOLS);
+
+        JdkServer.Builder builder = new JdkServer.Builder();
+        builder.setCertTuple(JdkProcUtils.createCertTuple(
+                trustedCertsStr, eeCertsStr));
+        if (!Utilities.isEmpty(protocolsStr)) {
+            builder.setProtocols(Utilities.strToEnums(
+                    Protocol.class, protocolsStr));
+        }
+        if (!Utilities.isEmpty(cipherSuitesStr)) {
+            builder.setCipherSuites(Utilities.strToEnums(
+                    CipherSuite.class, cipherSuitesStr));
+        }
+        builder.setClientAuth(clientAuth);
+        if (!Utilities.isEmpty(serverNamesStr)) {
+            builder.setServerNames(Utilities.split(serverNamesStr));
+        }
+        if (!Utilities.isEmpty(appProtocolsStr)) {
+            builder.setAppProtocols(Utilities.split(appProtocolsStr));
+        }
+
+        try (JdkServer server = builder.build()) {
+            int port = server.getPort();
+            System.out.println("port=" + port);
+            savePort(port);
+            server.accept();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/JdkProcUtils.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,137 @@
+/*
+ * 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.IOException;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.StringJoiner;
+
+/*
+ * Utilities for JDK process peers.
+ */
+public class JdkProcUtils {
+
+    public static final String PROP_HOST = "test.host";
+    public static final String PROP_PORT = "test.port";
+
+    public static final String PROP_SEC_PROPS_FILE = "java.security.properties";
+    public static final String PROP_PROTOCOLS = "test.protocols";
+    public static final String PROP_CIPHER_SUITES = "test.cipher.suites";
+    public static final String PROP_TRUSTED_CERTS = "test.trusted.certs";
+    public static final String PROP_EE_CERTS = "test.ee.certs";
+    public static final String PROP_CLIENT_AUTH = "test.client.auth";
+    public static final String PROP_SERVER_NAMES = "test.server.names";
+    public static final String PROP_APP_PROTOCOLS = "test.app.protocols";
+    public static final String PROP_NAMED_GROUPS = "jdk.tls.namedGroups";
+
+    /*
+     * Converts a Cert instance to a string, which contains the field values of
+     * the Cert. The values are separated by comma.
+     */
+    public static String certToStr(Cert cert) {
+        return Utilities.join(cert.keyAlgo, cert.sigAlgo, cert.hashAlgo,
+                cert.certMaterials, cert.keyMaterials);
+    }
+
+    /*
+     * Converts multiple Certs to a string. The value strings of the Certs are
+     * separated by semicolon.
+     */
+    public static String certsToStr(Cert[] certs) {
+        StringJoiner joiner = new StringJoiner(Utilities.PARAM_DELIMITER);
+        for (Cert cert : certs) {
+            joiner.add(certToStr(cert));
+        }
+        return joiner.toString();
+    }
+
+    /*
+     * Converts a string, which contains the field values of a Cert,
+     * to a Cert instance.
+     */
+    public static Cert strToCert(String certStr) {
+        String[] values = Utilities.split(certStr);
+        String keyAlgo = values[0];
+        String sigAlgo = values[1];
+        String hashAlgo = values[2];
+        String certMaterials = values[3];
+        String keyMaterials = values.length == 5 ? values[4] : null;
+        return new Cert(KeyAlgorithm.valueOf(keyAlgo),
+                SignatureAlgorithm.valueOf(sigAlgo),
+                HashAlgorithm.valueOf(hashAlgo), certMaterials, keyMaterials);
+    }
+
+    /*
+     * Converts a string to multiple Certs.
+     */
+    public static Cert[] strToCerts(String certsStr) {
+        String[] certStrs = Utilities.split(certsStr, Utilities.PARAM_DELIMITER);
+        Cert[] certs = new Cert[certStrs.length];
+        for(int i = 0; i < certStrs.length; i++) {
+            certs[i] = strToCert(certStrs[i]);
+        }
+        return certs;
+    }
+
+    public static CertTuple createCertTuple(String trustedCertsStr,
+            String eeCertsStr) {
+        Cert[] trustedCerts = strToCerts(trustedCertsStr);
+        Cert[] eeCerts = strToCerts(eeCertsStr);
+        return new CertTuple(trustedCerts, eeCerts);
+    }
+
+    /*
+    * Executes java program.
+    * It can redirect the output to a local file if necessary,
+    * and will returns the process for later application.
+    */
+    public static Process java(Path javaPath, Class<?> clazz,
+            Map<String, String> props, Path outputPath) throws IOException {
+        ProcessBuilder pb = createProcessBuilder(javaPath, clazz, props);
+        if (outputPath != null) {
+            pb.redirectOutput(outputPath.toFile());
+        }
+        return pb.start();
+    }
+
+    private static ProcessBuilder createProcessBuilder(Path javaPath,
+            Class<?> clazz, Map<String, String> props) {
+        List<String> cmds = new ArrayList<>();
+        cmds.add(javaPath.toString());
+
+        if (props != null) {
+            for (Map.Entry<String, String> prop : props.entrySet()) {
+                cmds.add("-D" + prop.getKey() + "=" + prop.getValue());
+            }
+        }
+
+        cmds.add("-cp");
+        cmds.add(Utilities.TEST_CLASSPATH);
+        cmds.add(clazz.getName());
+        ProcessBuilder pb = new ProcessBuilder(cmds);
+        pb.redirectErrorStream(true);
+        return pb;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/JdkServer.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,149 @@
+/*
+ * 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.IOException;
+import java.net.SocketException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.net.ssl.SNIHostName;
+import javax.net.ssl.SNIMatcher;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+
+/*
+ * A JDK server based on SSLServerSocket.
+ */
+public class JdkServer extends AbstractServer {
+
+    protected final String response;
+
+    protected final SSLServerSocket serverSocket;
+
+    protected final SSLContext context;
+    private SSLSocket socket;
+
+    public JdkServer(Builder builder) throws Exception {
+        response = builder.getMessage();
+
+        context = Utilities.createSSLContext(builder.getCertTuple());
+        SSLServerSocketFactory serverFactory = context.getServerSocketFactory();
+        serverSocket
+                = (SSLServerSocket) serverFactory.createServerSocket(builder.getPort());
+        configServerSocket(builder);
+    }
+
+    protected void configServerSocket(Builder builder) throws SocketException {
+        serverSocket.setSoTimeout(builder.getTimeout() * 1000);
+        if (builder.getProtocols() != null) {
+            serverSocket.setEnabledProtocols(Utilities.enumsToStrs(protocol -> {
+                return JdkUtils.protocol((Protocol) protocol);
+            }, builder.getProtocols()));
+        }
+        if (builder.getCipherSuites() != null) {
+            serverSocket.setEnabledCipherSuites(
+                    Utilities.enumsToStrs(builder.getCipherSuites()));
+        }
+        serverSocket.setNeedClientAuth(builder.getClientAuth());
+        SSLParameters sslParams = serverSocket.getSSLParameters();
+        if (builder.getServerNames() != null) {
+            List<SNIMatcher> matchers = new ArrayList<>();
+            for(String bufServerName : builder.getServerNames()) {
+                matchers.add(SNIHostName.createSNIMatcher(bufServerName));
+            }
+            sslParams.setSNIMatchers(matchers);
+        }
+        if (builder.getAppProtocols() != null) {
+            sslParams.setApplicationProtocols(builder.getAppProtocols());
+            for (String appProtocol : sslParams.getApplicationProtocols()) {
+                System.out.println("appProtocol: " + appProtocol);
+            }
+        }
+        serverSocket.setSSLParameters(sslParams);
+    }
+
+    public static class Builder extends AbstractServer.Builder {
+
+        @Override
+        public JdkServer build() throws Exception {
+            return new JdkServer(this);
+        }
+    }
+
+    @Override
+    public Product getProduct() {
+        return Jdk.DEFAULT;
+    }
+
+    @Override
+    public int getPort() {
+        return serverSocket.getLocalPort();
+    }
+
+    @Override
+    public void accept() throws IOException {
+        while (true) {
+            try (SSLSocket socket = (SSLSocket) serverSocket.accept()) {
+                this.socket = socket;
+                System.out.println("Server accepted connection");
+
+                String request = Utilities.readIn(socket.getInputStream());
+                System.out.printf("Server received request: [%s]%n", request);
+
+                if (response != null) {
+                    Utilities.writeOut(socket.getOutputStream(), response);
+                    System.out.printf("Server sent response: [%s]%n", response);
+                }
+            }
+        }
+    }
+
+    private synchronized SSLSocket getSocket() {
+        return socket;
+    }
+
+    public SSLSession getSession() {
+        return getSocket().getSession();
+    }
+
+    @Override
+    public String getNegoAppProtocol() throws SSLTestException {
+        return getSocket().getApplicationProtocol();
+    }
+
+    @Override
+    public boolean isAlive() {
+        return !serverSocket.isClosed();
+    }
+
+    @Override
+    public void close() throws IOException {
+        if (isAlive()) {
+            serverSocket.close();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/JdkUtils.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+/*
+ * Utilities for JDK peers.
+ */
+public class JdkUtils {
+
+    public static String protocol(Protocol protocol) {
+        if (protocol == null) {
+            return null;
+        }
+
+        switch (protocol) {
+        case SSLV3:
+            return "SSLv3";
+
+        case TLSV1:
+            return "TLSv1";
+
+        case TLSV1_1:
+            return "TLSv1.1";
+
+        case TLSV1_2:
+            return "TLSv1.2";
+
+        case TLSV1_3:
+            return "TLSv1.3";
+
+        default:
+            throw new RuntimeException("Unsupported protocol: " + protocol);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/KeyUpdateUseCase.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+/*
+ * The SSL/TLS communication parameters on TLS 1.3 key update.
+ */
+public class KeyUpdateUseCase extends UseCase {
+
+    private KeyUpdateRequest keyUpdateRequest = KeyUpdateRequest.NOT_REQUESTED;
+
+    public static KeyUpdateUseCase newInstance() {
+        return new KeyUpdateUseCase();
+    }
+
+    public KeyUpdateRequest getKeyUpdateRequest() {
+        return keyUpdateRequest;
+    }
+
+    public KeyUpdateUseCase setKeyUpdateRequest(
+            KeyUpdateRequest keyUpdateRequest) {
+        this.keyUpdateRequest = keyUpdateRequest;
+        return this;
+    }
+
+    @Override
+    public String toString() {
+        return Utilities.join(Utilities.PARAM_DELIMITER,
+                super.toString(),
+                Utilities.joinNameValue("KeyUpdateRequest", keyUpdateRequest.name));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/Peer.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,52 @@
+/*
+ * 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.Closeable;
+import java.io.IOException;
+
+/*
+ * This interface defines common functions for SSL/TLS communication peers.
+ */
+public interface Peer extends Closeable {
+
+    /*
+     * Indicates which product the peer is.
+     */
+    public Product getProduct();
+
+    /*
+     * Closes resource if any.
+     */
+    public void close() throws IOException;
+
+    /*
+     * Peer builder.
+     */
+    public static interface Builder {
+
+        /*
+         * Builds peer.
+         */
+        public Peer build() throws Exception;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/ProcUtils.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,69 @@
+/*
+ * 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.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+/*
+ * Utilities for process operations.
+ */
+public class ProcUtils {
+
+    /*
+     * Executes java program.
+     * After the program finishes, it returns OutputAnalyzer.
+     */
+    public static OutputAnalyzer java(Path javaPath, Class<?> clazz,
+            Map<String, String> props) {
+        ProcessBuilder pb = createProcessBuilder(javaPath, clazz, props);
+        try {
+            return ProcessTools.executeCommand(pb);
+        } catch (Throwable e) {
+            throw new RuntimeException("Executes java program failed!", e);
+        }
+    }
+
+    private static ProcessBuilder createProcessBuilder(Path javaPath,
+            Class<?> clazz, Map<String, String> props) {
+        List<String> cmds = new ArrayList<>();
+        cmds.add(javaPath.toString());
+
+        if (props != null) {
+            for (Map.Entry<String, String> prop : props.entrySet()) {
+                cmds.add("-D" + prop.getKey() + "=" + prop.getValue());
+            }
+        }
+
+        cmds.add("-cp");
+        cmds.add(System.getProperty("test.class.path"));
+        cmds.add(clazz.getName());
+        ProcessBuilder pb = new ProcessBuilder(cmds);
+        pb.redirectErrorStream(true);
+        return pb;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/Product.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,33 @@
+/*
+ * 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.nio.file.Path;
+
+/*
+ * The basic definitions for a product on SSL/TLS implementation.
+ */
+public interface Product {
+
+    public String getName();
+    public Path getPath();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/ResumptionUseCase.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+/*
+ * The SSL/TLS communication parameters on session resumption.
+ */
+public class ResumptionUseCase extends ExtUseCase {
+
+    private boolean enableServerSessionTicket
+            = Boolean.getBoolean("jdk.tls.server.enableSessionTicketExtension");
+
+    private boolean enableClientSessionTicket
+            = Boolean.getBoolean("jdk.tls.client.enableSessionTicketExtension");
+
+    public static ResumptionUseCase newInstance() {
+        return new ResumptionUseCase();
+    }
+
+    public boolean isEnableServerSessionTicket() {
+        return enableServerSessionTicket;
+    }
+
+    public ResumptionUseCase setEnableServerSessionTicket(
+            boolean enableServerSessionTicket) {
+        this.enableServerSessionTicket = enableServerSessionTicket;
+        return this;
+    }
+
+    public boolean isEnableClientSessionTicket() {
+        return enableClientSessionTicket;
+    }
+
+    public ResumptionUseCase setEnableClientSessionTicket(
+            boolean enableClientSessionTicket) {
+        this.enableClientSessionTicket = enableClientSessionTicket;
+        return this;
+    }
+
+    /*
+     * For TLS 1.3, the session should always be resumed via session ticket.
+     * For TLS 1.2, if both of server and client support session ticket,
+     * the session should be resumed via session ticket; otherwise, the session
+     * should be resumed via session ID.
+     */
+    public ResumptionMode expectedResumptionMode() {
+        if (getProtocol() == Protocol.TLSV1_3
+                || (enableServerSessionTicket && enableClientSessionTicket)) {
+            return ResumptionMode.TICKET;
+        } else {
+            return ResumptionMode.ID;
+        }
+    }
+
+    @Override
+    public String toString() {
+        return Utilities.join(Utilities.PARAM_DELIMITER,
+                super.toString(),
+                Utilities.joinNameValue(
+                        "enableServerSessionTicket", enableServerSessionTicket),
+                Utilities.joinNameValue(
+                        "enableClientSessionTicket", enableClientSessionTicket));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/SSLTestException.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,40 @@
+/*
+ * 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.IOException;
+
+/*
+ * Exception on SSL/TLS communication testing.
+ */
+public class SSLTestException extends IOException {
+
+    private static final long serialVersionUID = -9198430167985282879L;
+
+    public SSLTestException(String reason, Throwable throwable) {
+        super(reason, throwable);
+    }
+
+    public SSLTestException(String reason) {
+        this(reason, null);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/Server.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,51 @@
+/*
+ * 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.IOException;
+
+/*
+ * This interface defines functions for SSL/TLS server.
+ */
+public interface Server extends Peer {
+
+    /*
+     * Returns the server port.
+     * When the port is available, the server must have been started.
+     */
+    public int getPort() throws IOException;
+
+    /*
+     * Accepts connection.
+     */
+    public void accept() throws IOException;
+
+    /*
+     * Checks if the peer is alive.
+     */
+    public boolean isAlive() throws IOException;
+
+    /*
+     * Signals the server to stop if necessary.
+     */
+    public void signalStop() throws Exception;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/Status.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+/*
+ * Test case status
+ */
+public enum Status {
+
+    UNSTARTED,
+    PASS,
+    FAIL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/TestCase.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,112 @@
+/*
+ * 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.util.Map;
+
+/*
+ * A specific SSL/TLS communication test case on two peers.
+ */
+public class TestCase<U extends UseCase> {
+
+    // The server side use case.
+    public final U serverCase;
+
+    // The client side use case.
+    public final U clientCase;
+
+    private Status status;
+
+    public TestCase(U serverCase, U clientCase) {
+        this.serverCase = serverCase;
+        this.clientCase = clientCase;
+    }
+
+    public TestCase<U> addServerProp(String prop, String value) {
+        serverCase.addProp(prop, value);
+        return this;
+    }
+
+    public String getServerProp(String prop) {
+        return serverCase.getProp(prop);
+    }
+
+    public TestCase<U> addAllServerProps(Map<String, String> props) {
+        serverCase.addAllProps(props);
+        return this;
+    }
+
+    public Map<String, String> getAllServerProps() {
+        return serverCase.getAllProps();
+    }
+
+    public TestCase<U> removeServerProp(String prop) {
+        serverCase.removeProp(prop);
+        return this;
+    }
+
+    public TestCase<U> removeAllServerProp() {
+        serverCase.removeAllProps();
+        return this;
+    }
+
+    public TestCase<U> addClientProp(String prop, String value) {
+        clientCase.addProp(prop, value);
+        return this;
+    }
+
+    public String getClientProp(String prop) {
+        return clientCase.getProp(prop);
+    }
+
+    public TestCase<U> addAllClientProps(Map<String, String> props) {
+        clientCase.addAllProps(props);
+        return this;
+    }
+
+    public Map<String, String> getAllClientProps() {
+        return clientCase.getAllProps();
+    }
+
+    public TestCase<U> removeClientProp(String prop) {
+        clientCase.removeProp(prop);
+        return this;
+    }
+
+    public TestCase<U> removeAllClientProp() {
+        clientCase.removeAllProps();
+        return this;
+    }
+
+    public Status getStatus() {
+        return status;
+    }
+
+    public void setStatus(Status status) {
+        this.status = status;
+    }
+
+    @Override
+    public String toString() {
+        return "Server: " + serverCase + "\n" + "Client: " + clientCase;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/UseCase.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,136 @@
+/*
+ * 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.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/*
+ * A set of specific SSL/TLS communication parameters on a peer.
+ */
+public class UseCase {
+
+ // The tuple for trusted CAs and certificates.
+    private CertTuple certTuple;
+
+    // The supported SSL/TLS protocols.
+    private Protocol[] protocols;
+
+    // The supported cipher suites.
+    private CipherSuite[] cipherSuites;
+
+    // If require client authentication.
+    private boolean clientAuth;
+
+    public static UseCase newInstance() {
+        return new UseCase();
+    }
+
+    public CertTuple getCertTuple() {
+        return certTuple;
+    }
+
+    public UseCase setCertTuple(CertTuple certTuple) {
+        this.certTuple = certTuple;
+        return this;
+    }
+
+    public Protocol[] getProtocols() {
+        return protocols;
+    }
+
+    public Protocol getProtocol() {
+        return protocols != null && protocols.length > 0
+                ? protocols[0]
+                : null;
+    }
+
+    public UseCase setProtocols(Protocol... protocols) {
+        this.protocols = protocols;
+        return this;
+    }
+
+    public CipherSuite[] getCipherSuites() {
+        return cipherSuites;
+    }
+
+    public CipherSuite getCipherSuite() {
+        return cipherSuites != null && cipherSuites.length > 0
+                ? cipherSuites[0]
+                : null;
+    }
+
+    public UseCase setCipherSuites(CipherSuite... cipherSuites) {
+        this.cipherSuites = cipherSuites;
+        return this;
+    }
+
+    public boolean isClientAuth() {
+        return clientAuth;
+    }
+
+    public UseCase setClientAuth(boolean clientAuth) {
+        this.clientAuth = clientAuth;
+        return this;
+    }
+
+    // The system properties used by a JDK peer.
+    private final Map<String, String> props = new HashMap<>();
+
+    public UseCase addProp(String prop, String value) {
+        props.put(prop, value);
+        return this;
+    }
+
+    public String getProp(String prop) {
+        return props.get(prop);
+    }
+
+    public UseCase addAllProps(Map<String, String> props) {
+        this.props.putAll(props);
+        return this;
+    }
+
+    public Map<String, String> getAllProps() {
+        return Collections.unmodifiableMap(props);
+    }
+
+    public UseCase removeProp(String prop) {
+        props.remove(prop);
+        return this;
+    }
+
+    public UseCase removeAllProps() {
+        props.clear();
+        return this;
+    }
+
+    @Override
+    public String toString() {
+        return Utilities.join(Utilities.PARAM_DELIMITER,
+                "certTuple=[" + certTuple + "]",
+                Utilities.joinNameValue("protocols", Utilities.join(protocols)),
+                Utilities.joinNameValue("cipherSuites", Utilities.join(cipherSuites)),
+                Utilities.joinNameValue("clientAuth", clientAuth ? "true" : ""));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/TLSCommon/interop/Utilities.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,511 @@
+/*
+ * 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
+            = Utilities.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;
+        while (!predicate.test(t) && System.currentTimeMillis() < deadline) {
+            try {
+                TimeUnit.SECONDS.sleep(1);
+            } catch (InterruptedException e) {
+                throw new RuntimeException("Sleep is interrupted.", e);
+            }
+        }
+
+        return predicate.test(t);
+    }
+
+    /*
+     * 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));
+    }
+
+    /*
+     * Executes shell command and return a OutputAnalyzer wrapping the process.
+     */
+    public static OutputAnalyzer shell(String command) throws IOException {
+        Process process = shellProc(command);
+        OutputAnalyzer oa = new OutputAnalyzer(process);
+        try {
+            process.waitFor();
+            return oa;
+        } catch (InterruptedException e) {
+            throw new RuntimeException("Shell process is interruptted!", e);
+        }
+    }
+
+    /*
+     * Executes shell command and redirect the output to a local file,
+     * and return the process.
+     */
+    public static Process shellProc(String command, Path outputPath)
+            throws IOException {
+        String[] cmds = new String[3];
+        cmds[0] = "sh";
+        cmds[1] = "-c";
+        cmds[2] = command;
+        if (DEBUG) {
+            System.out.println("[sh -c " + command + "]");
+        }
+        ProcessBuilder pb = new ProcessBuilder(cmds);
+        pb.redirectErrorStream(true);
+        if (outputPath != null) {
+            pb.redirectOutput(outputPath.toFile());
+        }
+        return pb.start();
+    }
+
+    /*
+     * Executes shell command and return the process.
+     */
+    public static Process shellProc(String command) throws IOException {
+        return shellProc(command, null);
+    }
+
+    /*
+     * 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 secondConnStartTime, long secondSessionCreationTime) {
+        System.out.println("ResumptionMode: " + mode);
+        System.out.println("firstSessionId: " + Arrays.toString(firstSessionId));
+        System.out.println("secondSessionId: " + Arrays.toString(secondSessionId));
+        System.out.println("secondConnStartTime: " + secondConnStartTime);
+        System.out.println("secondSessionCreationTime: " + secondSessionCreationTime);
+
+        boolean resumed = secondConnStartTime > 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];
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/compatibility/AlpnTest.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,181 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @summary This is an interop compatibility test on ALPN.
+ *
+ * @library /test/lib
+ *          ../TLSCommon
+ *          ../TLSCommon/interop
+ * @compile -source 1.8 -target 1.8
+ *          JdkInfoUtils.java
+ *          ../TLSCommon/interop/JdkProcServer.java
+ *          ../TLSCommon/interop/JdkProcClient.java
+ * @run main/manual AlpnTest true
+ * @run main/manual AlpnTest false
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+public class AlpnTest extends ExtInteropTest {
+
+    private JdkInfo serverJdkInfo;
+    private JdkInfo clientJdkInfo;
+
+    public AlpnTest(JdkInfo serverJdkInfo, JdkInfo clientJdkInfo) {
+        super(new Jdk(serverJdkInfo.version, serverJdkInfo.javaPath),
+              new Jdk(clientJdkInfo.version, clientJdkInfo.javaPath));
+
+        this.serverJdkInfo = serverJdkInfo;
+        this.clientJdkInfo = clientJdkInfo;
+    }
+
+    @Override
+    protected boolean skipExecute() {
+        return super.skipExecute() || !supportsALPN();
+    }
+
+    private boolean supportsALPN() {
+        boolean supported = true;
+
+        if (!serverJdkInfo.supportsALPN) {
+            System.out.println("The server doesn't support ALPN.");
+            supported = false;
+        }
+
+        if (!clientJdkInfo.supportsALPN) {
+            System.out.println("The client doesn't support ALPN.");
+            supported = false;
+        }
+
+        return supported;
+    }
+
+    @Override
+    protected List<TestCase<ExtUseCase>> getTestCases() {
+        List<TestCase<ExtUseCase>> testCases = new ArrayList<>();
+
+        for (Protocol protocol : new Protocol[] {
+                Protocol.TLSV1_2, Protocol.TLSV1_3 }) {
+            for (CipherSuite cipherSuite : Utilities.ALL_CIPHER_SUITES) {
+                if (!cipherSuite.supportedByProtocol(protocol)) {
+                    continue;
+                }
+
+                Cert cert = Utils.getCert(cipherSuite.keyExAlgorithm);
+                CertTuple certTuple = new CertTuple(cert, cert);
+
+                ExtUseCase serverCase = ExtUseCase.newInstance();
+                serverCase.setCertTuple(certTuple);
+                serverCase.setAppProtocols("http/1.1", "h2");
+
+                ExtUseCase clientCase = ExtUseCase.newInstance();
+                clientCase.setCertTuple(certTuple);
+                clientCase.setProtocols(protocol);
+                clientCase.setCipherSuites(cipherSuite);
+                clientCase.setAppProtocols("h2");
+
+                testCases.add(
+                        new TestCase<ExtUseCase>(serverCase, clientCase));
+            }
+        }
+
+        return testCases;
+    }
+
+    @Override
+    protected boolean ignoreTestCase(TestCase<ExtUseCase> testCase) {
+        CipherSuite cipherSuite = testCase.clientCase.getCipherSuite();
+        return !serverJdkInfo.enablesCipherSuite(cipherSuite)
+                || !clientJdkInfo.supportsCipherSuite(cipherSuite);
+    }
+
+    @Override
+    protected AbstractServer.Builder createServerBuilder(ExtUseCase useCase)
+            throws Exception {
+        return serverJdkInfo == JdkInfo.DEFAULT
+               ? createJdkServerBuilder(useCase)
+               : createAltJdkServerBuilder(useCase);
+    }
+
+    private JdkServer.Builder createJdkServerBuilder(ExtUseCase useCase) {
+        JdkServer.Builder builder = new JdkServer.Builder();
+        builder.setCertTuple(useCase.getCertTuple());
+        builder.setProtocols(useCase.getProtocols());
+        builder.setCipherSuites(useCase.getCipherSuites());
+        builder.setAppProtocols(useCase.getAppProtocols());
+        return builder;
+    }
+
+    private JdkProcServer.Builder createAltJdkServerBuilder(ExtUseCase useCase) {
+        JdkProcServer.Builder builder = new JdkProcServer.Builder();
+        builder.setJdk((Jdk) serverProduct);
+        builder.setCertTuple(useCase.getCertTuple());
+        builder.setProtocols(useCase.getProtocols());
+        builder.setCipherSuites(useCase.getCipherSuites());
+        builder.setAppProtocols(useCase.getAppProtocols());
+        return builder;
+    }
+
+    @Override
+    protected AbstractClient.Builder createClientBuilder(ExtUseCase useCase)
+            throws Exception {
+        return clientJdkInfo == JdkInfo.DEFAULT
+               ? createJdkClientBuilder(useCase)
+               : createAltJdkClientBuilder(useCase);
+    }
+
+    private JdkClient.Builder createJdkClientBuilder(ExtUseCase useCase) {
+        JdkClient.Builder builder = new JdkClient.Builder();
+        builder.setCertTuple(useCase.getCertTuple());
+        builder.setProtocols(useCase.getProtocols());
+        builder.setCipherSuites(useCase.getCipherSuites());
+        builder.setAppProtocols(useCase.getAppProtocols());
+        return builder;
+    }
+
+    private JdkProcClient.Builder createAltJdkClientBuilder(ExtUseCase useCase) {
+        JdkProcClient.Builder builder = new JdkProcClient.Builder();
+        builder.setJdk((Jdk) clientProduct);
+        builder.setCertTuple(useCase.getCertTuple());
+        builder.setProtocols(useCase.getProtocols());
+        builder.setCipherSuites(useCase.getCipherSuites());
+        builder.setAppProtocols(useCase.getAppProtocols());
+        return builder;
+    }
+
+    public static void main(String[] args) throws Exception {
+        Boolean defaultJdkAsServer = Boolean.valueOf(args[0]);
+
+        Set<JdkInfo> jdkInfos = Utils.jdkInfoList();
+        for (JdkInfo jdkInfo : jdkInfos) {
+            AlpnTest test = new AlpnTest(
+                    defaultJdkAsServer ? JdkInfo.DEFAULT : jdkInfo,
+                    defaultJdkAsServer ? jdkInfo : JdkInfo.DEFAULT);
+            test.execute();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/compatibility/BasicConnectTest.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,180 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @summary This is an interop compatibility test on basic handshaking and
+ *     client authentication against all SSL/TLS protocols.
+ *
+ * @library /test/lib
+ *          ../TLSCommon
+ *          ../TLSCommon/interop
+ * @compile -source 1.8 -target 1.8
+ *          JdkInfoUtils.java
+ *          ../TLSCommon/interop/JdkProcServer.java
+ *          ../TLSCommon/interop/JdkProcClient.java
+ * @run main/manual BasicConnectTest true
+ * @run main/manual BasicConnectTest false
+ */
+
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+public class BasicConnectTest extends BaseInteropTest<UseCase> {
+
+    private JdkInfo serverJdkInfo;
+    private JdkInfo clientJdkInfo;
+
+    public BasicConnectTest(JdkInfo serverJdkInfo, JdkInfo clientJdkInfo) {
+        super(new Jdk(serverJdkInfo.version, serverJdkInfo.javaPath),
+              new Jdk(clientJdkInfo.version, clientJdkInfo.javaPath));
+
+        this.serverJdkInfo = serverJdkInfo;
+        this.clientJdkInfo = clientJdkInfo;
+    }
+
+    @Override
+    protected List<TestCase<UseCase>> getTestCases() {
+        List<TestCase<UseCase>> useCases = new ArrayList<>();
+        for (Protocol protocol : new Protocol[] {
+                Protocol.SSLV3,
+                Protocol.TLSV1,
+                Protocol.TLSV1_1,
+                Protocol.TLSV1_2,
+                Protocol.TLSV1_3 }) {
+            for (CipherSuite cipherSuite : Utilities.ALL_CIPHER_SUITES) {
+                if (!cipherSuite.supportedByProtocol(protocol)) {
+                    continue;
+                }
+
+                Cert cert = Utils.getCert(cipherSuite.keyExAlgorithm);
+                CertTuple certTuple = new CertTuple(cert, cert);
+
+                UseCase serverCase = UseCase.newInstance()
+                        .setCertTuple(certTuple)
+                        .setClientAuth(true);
+
+                UseCase clientCase = UseCase.newInstance()
+                        .setCertTuple(certTuple)
+                        .setProtocols(protocol)
+                        .setCipherSuites(cipherSuite);
+
+                useCases.add(new TestCase<UseCase>(serverCase, clientCase));
+            }
+        }
+        return useCases;
+    }
+
+    @Override
+    protected boolean ignoreTestCase(TestCase<UseCase> testCase) {
+        Protocol protocol = testCase.clientCase.getProtocol();
+        CipherSuite cipherSuite = testCase.clientCase.getCipherSuite();
+        return !supportsProtocol(protocol)
+                || !supportsCipherSuite(cipherSuite)
+                // DHE_DSS cipher suites cannot work with pre-TLSv1.2 protocols,
+                // see JDK-8242928 for more details.
+                || (protocol.id < Protocol.TLSV1_2.id
+                        && (cipherSuite.keyExAlgorithm == KeyExAlgorithm.DHE_DSS
+                                || cipherSuite.keyExAlgorithm == KeyExAlgorithm.DHE_DSS_EXPORT));
+    }
+
+    private boolean supportsProtocol(Protocol protocol) {
+        return serverJdkInfo.enablesProtocol(protocol)
+                && clientJdkInfo.supportsProtocol(protocol);
+    }
+
+    private boolean supportsCipherSuite(CipherSuite cipherSuite) {
+        return serverJdkInfo.enablesCipherSuite(cipherSuite)
+                && clientJdkInfo.supportsCipherSuite(cipherSuite);
+    }
+
+    @Override
+    protected AbstractServer.Builder createServerBuilder(UseCase useCase)
+            throws Exception {
+        return serverJdkInfo == JdkInfo.DEFAULT
+               ? createJdkServerBuilder(useCase)
+               : createAltJdkServerBuilder(useCase);
+    }
+
+    private JdkServer.Builder createJdkServerBuilder(UseCase useCase) {
+        JdkServer.Builder builder = new JdkServer.Builder();
+        builder.setCertTuple(useCase.getCertTuple());
+        builder.setProtocols(useCase.getProtocols());
+        builder.setCipherSuites(useCase.getCipherSuites());
+        builder.setClientAuth(useCase.isClientAuth());
+        return builder;
+    }
+
+    private JdkProcServer.Builder createAltJdkServerBuilder(UseCase useCase) {
+        JdkProcServer.Builder builder = new JdkProcServer.Builder();
+        builder.setJdk((Jdk) serverProduct);
+        builder.setSecPropsFile(Paths.get(Utils.SEC_PROPS_FILE));
+        builder.setCertTuple(useCase.getCertTuple());
+        builder.setProtocols(useCase.getProtocols());
+        builder.setCipherSuites(useCase.getCipherSuites());
+        builder.setClientAuth(useCase.isClientAuth());
+        return builder;
+    }
+
+    @Override
+    protected AbstractClient.Builder createClientBuilder(UseCase useCase)
+            throws Exception {
+        return serverJdkInfo == JdkInfo.DEFAULT
+               ? createJdkClientBuilder(useCase)
+               : createAltJdkClientBuilder(useCase);
+    }
+
+    private JdkClient.Builder createJdkClientBuilder(UseCase useCase) {
+        JdkClient.Builder builder = new JdkClient.Builder();
+        builder.setCertTuple(useCase.getCertTuple());
+        builder.setProtocols(useCase.getProtocols());
+        builder.setCipherSuites(useCase.getCipherSuites());
+        return builder;
+    }
+
+    private JdkProcClient.Builder createAltJdkClientBuilder(UseCase useCase) {
+        JdkProcClient.Builder builder = new JdkProcClient.Builder();
+        builder.setJdk((Jdk) clientProduct);
+        builder.setSecPropsFile(Paths.get(Utils.SEC_PROPS_FILE));
+        builder.setCertTuple(useCase.getCertTuple());
+        builder.setProtocols(useCase.getProtocols());
+        builder.setCipherSuites(useCase.getCipherSuites());
+        return builder;
+    }
+
+    public static void main(String[] args) throws Exception {
+        Boolean defaultJdkAsServer = Boolean.valueOf(args[0]);
+
+        System.setProperty("java.security.properties", Utils.SEC_PROPS_FILE);
+
+        Set<JdkInfo> jdkInfos = Utils.jdkInfoList();
+        for (JdkInfo jdkInfo : jdkInfos) {
+            BasicConnectTest test = new BasicConnectTest(
+                    defaultJdkAsServer ? JdkInfo.DEFAULT : jdkInfo,
+                    defaultJdkAsServer ? jdkInfo : JdkInfo.DEFAULT);
+            test.execute();
+        }
+    }
+}
--- a/test/jdk/javax/net/ssl/compatibility/Cert.java	Thu Apr 23 22:49:55 2020 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,421 +0,0 @@
-/*
- * Copyright (c) 2017, 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.
- */
-
-/*
- * The certificates and corresponding private keys used by the test.
- * All of certificates uses relative weak key size and hash algorithm, then
- * all JDK releases can load them. Accordingly, a custom java.security file is
- * provided to make sure such weak key sizes and algorithms are not blocked by
- * any JDK build.
- */
-public enum Cert {
-
-    // This certificate is generated by the below command:
-    // openssl genpkey -algorithm rsa -pkeyopt rsa_keygen_bits:2048 \
-    //     -pkeyopt rsa_keygen_pubexp:65537 -out key.pem
-    // openssl req -x509 -new -days 7300 -key key.pem \
-    //     -subj "/CN=RSA-2048-SHA256" -sha256 -out cer.pem
-    RSA_2048_SHA256(
-            KeyAlgorithm.RSA,
-            "-----BEGIN CERTIFICATE-----\n" +
-            "MIIDFTCCAf2gAwIBAgIUe8nlNUPJa9Iy57Cy5JM49bCzWdkwDQYJKoZIhvcNAQEL\n" +
-            "BQAwGjEYMBYGA1UEAwwPUlNBLTIwNDgtU0hBMjU2MB4XDTE5MDIyNzA3NDkwMVoX\n" +
-            "DTM5MDIyMjA3NDkwMVowGjEYMBYGA1UEAwwPUlNBLTIwNDgtU0hBMjU2MIIBIjAN\n" +
-            "BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1Clo5Prh1AdHSdM7G85B6K20bjSn\n" +
-            "bydcWxa7vQDEgFid1Ne8XRbugv5i8I7kGv2sTl99fopHeJcXHJvQGg7KVPgZqH0Z\n" +
-            "S7ZImlT5f4FYFj8sKnM5wx2P2AxcbO8ktSox0qIgtsHsCd7SusczylqEvSUrcqEe\n" +
-            "V58LtoWH+trsWoSBDlHRew2eD6ZGyQTM8VFqbt9oF2XXW22JiuP+cSvb+p5qSCy5\n" +
-            "dGpdPCJpPB/9HpChZl/r+VsqpbHwUPEVu9/FG0SVjpcqvJojYrgglb1PvJxLqceN\n" +
-            "DPOirwxnnEdiu5j0xC6RhOkbcxTGtS0VgEEC1+HyY+KeauZJOrw2x1ZmxQIDAQAB\n" +
-            "o1MwUTAdBgNVHQ4EFgQUSSj0EFZWTSFr91nTUE2MrJdrJGowHwYDVR0jBBgwFoAU\n" +
-            "SSj0EFZWTSFr91nTUE2MrJdrJGowDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B\n" +
-            "AQsFAAOCAQEAW9uuS2ZpG1ytpNA0g20m29R/DVSnygdfp8r/xeaWgdol4H2syPzg\n" +
-            "xok3PLkxkSpBv6CgIPXBzy/iXSMlkX0mUKEO3aQnJ8MoZ5Tzu3Bkp2fTugRQuTRi\n" +
-            "iNWQjsMoupsrTXIZhJ64jkDCnlFADPAdvVqQV01yZcKW98sj3TyaT7TJuYX9mU+V\n" +
-            "OuICkS1LE5NssuyLodxpfqpjBMtVovSKZ57JvO36G6riftnjr3FBf8ukWFK2/UfP\n" +
-            "DaHyFQ+NewbjPy7N+taFlLHS7ELwZVQQ42t8JeHRuF5IVvlp1UjTgXC5NuhOBwQY\n" +
-            "2dXFFroT0vXetn7Fr51zENPP3/TGeaoQnw==\n" +
-            "-----END CERTIFICATE-----",
-            "308204be020100300d06092a864886f70d0101010500048204a8308204a40201" +
-            "000282010100d42968e4fae1d4074749d33b1bce41e8adb46e34a76f275c5b16" +
-            "bbbd00c480589dd4d7bc5d16ee82fe62f08ee41afdac4e5f7d7e8a477897171c" +
-            "9bd01a0eca54f819a87d194bb6489a54f97f8158163f2c2a7339c31d8fd80c5c" +
-            "6cef24b52a31d2a220b6c1ec09ded2bac733ca5a84bd252b72a11e579f0bb685" +
-            "87fadaec5a84810e51d17b0d9e0fa646c904ccf1516a6edf681765d75b6d898a" +
-            "e3fe712bdbfa9e6a482cb9746a5d3c22693c1ffd1e90a1665febf95b2aa5b1f0" +
-            "50f115bbdfc51b44958e972abc9a2362b82095bd4fbc9c4ba9c78d0cf3a2af0c" +
-            "679c4762bb98f4c42e9184e91b7314c6b52d15804102d7e1f263e29e6ae6493a" +
-            "bc36c75666c502030100010282010028f1f4f47c16a93cde5d390ee746df2170" +
-            "a4a9c02fb01c008ef3cc37a5b646aed387083baa1b8adc6d0bdb3138849d006b" +
-            "ffb1d0820f590e8fbf4db2d3d496e7df19d4929017348ebe7a37cc8bc1dc4944" +
-            "d4cc781157db32eeefc7763fb756f55699438701d5f3f1b4e9a7182fad5880c8" +
-            "73a223c61f52ea87c72d7f14511906af61d7fa190b02854471d4bdb77dac34ef" +
-            "46a3af3f39dff1c8844cad7f74f9936fbcc22bed6b139f47dc215048ddf02f60" +
-            "a24703b292be106ea4f01ec0839466666d9c3dc8488b353dccdd5f90bd4b5bb9" +
-            "4493b7da219ec4962fe6a427f6d69e2764065212c5accdbed3aa36a18d540e55" +
-            "192e63db9f6bdfc90ec52b89714d0102818100f7c35a70ee7d6aabd7feb590f6" +
-            "30ce9c28299f3431ebcd3c89ec9424cf68c626ee4f6ff0748ffc0ad810a9f6dd" +
-            "2b203c8fa7f516483545822e6c963b9f6a1687aca663be061aadcca920b09699" +
-            "bd7d2e8973bafe9ef11e19a27c10befe3e8919c141d04e5aab2990cc061c6798" +
-            "5d3da742a3c8c62b68a8ccb4af21c1c935bdcd02818100db37101251d805b8d6" +
-            "12749d8780cce9e4ff8fc58313e4192fbf9018dc2a8875beff70ea2ebaa24058" +
-            "d3de6eab4be66b0bb81c04f0fa29bad0f787776ed2e6ab7b7d9814ce7721cadd" +
-            "cc3f500ddfd73ae9def4d92a79e4a1662da16dbfc52d60507308286cf592ed8b" +
-            "9911089c4ec7dba3fcd64926b55d137d41f6de454694d902818100af6b582077" +
-            "2ac318d2401bcb7c13886555a64a7b09115be98df9bbd5e827d58c00d4ab7bc2" +
-            "fba2c706bd9da9146491596f98ca553160ce4ae295ad349fa4dc38c94bb178fc" +
-            "176d9066faa72ca9c358db572462741e92b6ee0d75ebe15e5f66709ebcfb404e" +
-            "bfbb1932eaecb7885013f3d5a1e2e83419d0d1c6e7ec6da9096ccd0281810099" +
-            "81fc922797f3a1d4dec5a4ce8fc66effba6aae7034cca54a8785dbb2c96217ba" +
-            "315c9bd12f469172e2a2bfb2da8ab769547ae286f157a987cddea2270c2f15e4" +
-            "7b35b554439e79564a4207c83f7893bbd43277a4c408f370ff012d3e7e506142" +
-            "d4dae09c3477b83aea6c40305d069d6b3f91bb560ce8e9cdec1478dfe0263902" +
-            "818002b66c71380142c3e606bfc598b4060f6833ac80e16d08aea40f4837191d" +
-            "34a3c85b91c3043c6ebb2c651a7fbb89539f5621820f792a5279a947c51f47b7" +
-            "1b6051c5a81d2d1c30dfa1f93cb57af1d7ee7862e8d90e33bd5c80f14aa9471b" +
-            "a2ea7aacddbb44d1a5e60f5fac437ca50cd56e237936fd3e9d034efc3e3c6710" +
-            "4c08"),
-
-    // This certificate is generated by the below command:
-    // openssl genpkey -algorithm rsa -pkeyopt rsa_keygen_bits:2048 \
-    //     -pkeyopt rsa_keygen_pubexp:65537 -out key.pem
-    // openssl req -x509 -new -days 7300 -key key.pem \
-    //     -subj "/CN=EXAMPLE" -sha256 -out cer.pem
-    EXAMPLE_RSA_2048_SHA256(
-            KeyAlgorithm.RSA,
-            "-----BEGIN CERTIFICATE-----\n" +
-            "MIIDBTCCAe2gAwIBAgIUD+8I14TmOfEfxtD6hgnhhK8ARCAwDQYJKoZIhvcNAQEL\n" +
-            "BQAwEjEQMA4GA1UEAwwHRVhBTVBMRTAeFw0xOTAyMjcwODAzNDhaFw0zOTAyMjIw\n" +
-            "ODAzNDhaMBIxEDAOBgNVBAMMB0VYQU1QTEUwggEiMA0GCSqGSIb3DQEBAQUAA4IB\n" +
-            "DwAwggEKAoIBAQChKYq85df7kUnf35qAfxW/OnqCgn/5FNwlWAwHLlEiHpK+k7jD\n" +
-            "8S6LVbw55I/4J3lehIHcIapGdmqh9ijUc2aNxTJ33z+/TTu2n+KlWmGj0G7ovTXk\n" +
-            "TbWptdgk5ro8DCr8I8YcvwdLekwH4AkRL6jSyiqsqlGZYLIxDd4l0CwSt5orbu/y\n" +
-            "+2UtM4DEOEswrxdP9UAd+W0On4AWaFIEbfuFaLZXHadvKxidnaCmudOJry6NjFWn\n" +
-            "+3PmIWNhZJitD0gq8FG3pvY502fLqHX95pigWCkDtrDNiqReXgVvZFWPaSMs065y\n" +
-            "n2ClShbzTs8pqJp8oBde9Iwi3RKwkew8I2iJAgMBAAGjUzBRMB0GA1UdDgQWBBTL\n" +
-            "3w5XucuEre5nQiaKnqi4s7ldBjAfBgNVHSMEGDAWgBTL3w5XucuEre5nQiaKnqi4\n" +
-            "s7ldBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBo51E5U5H7\n" +
-            "kXkI1LaGDs35dOOtrPQQQ7DzhQACUDfyYB8/BBUlYHPegS2ca/l1mkD2P/GNyZbN\n" +
-            "r4eRoOujfU59gOwH4+MEs/4zUKicajTGUPCbJ56heipHunHzj+2nj3ok5PI0MoI1\n" +
-            "soQfRV1FshfWAni7E49L1QI/PQrQ2cPR/1dvkB06JCIn0GoTxd8E76VCJz576xnd\n" +
-            "XgjiadVbjMYDH9XJEy6eQT6vY5WeGOQC2XwSE3mS6G+Z9jlwIswa8RrKGtKqFGK1\n" +
-            "6yse9zfJv64X8tQwnrkatCx4shJwDUet6wJQzm0/NMPfquoxz7QHF2NsLlNky+fY\n" +
-            "fZjMnoO3J1nV\n" +
-            "-----END CERTIFICATE-----",
-            "308204bd020100300d06092a864886f70d0101010500048204a7308204a30201" +
-            "000282010100a1298abce5d7fb9149dfdf9a807f15bf3a7a82827ff914dc2558" +
-            "0c072e51221e92be93b8c3f12e8b55bc39e48ff827795e8481dc21aa46766aa1" +
-            "f628d473668dc53277df3fbf4d3bb69fe2a55a61a3d06ee8bd35e44db5a9b5d8" +
-            "24e6ba3c0c2afc23c61cbf074b7a4c07e009112fa8d2ca2aacaa519960b2310d" +
-            "de25d02c12b79a2b6eeff2fb652d3380c4384b30af174ff5401df96d0e9f8016" +
-            "6852046dfb8568b6571da76f2b189d9da0a6b9d389af2e8d8c55a7fb73e62163" +
-            "616498ad0f482af051b7a6f639d367cba875fde698a0582903b6b0cd8aa45e5e" +
-            "056f64558f69232cd3ae729f60a54a16f34ecf29a89a7ca0175ef48c22dd12b0" +
-            "91ec3c236889020301000102820100655c9e60ce62b85b99ce0f71ba2db3fcd1" +
-            "07ea7baf8776823b8e940a142c7d3c23696fb97eab7b6db11fb07dbbbb0500c5" +
-            "dcab5c4b642feb1c87ff2d90e97fefdcbe303c9e7870580535ac33f9937d9783" +
-            "9a281ef41798114448cc74bd5f34fbf8177bebea8de8ffe33ff4bd5f2ccd8ebe" +
-            "0e7708ac47be54749bd7438b199d2f134b71efc513827f260c0f74f1fc32f45b" +
-            "e5d510844777fcd2a486bc02c080d120d1c32336000ece743ea755f79f60a44a" +
-            "5e619ceb1caa873d847715616874d13c2ff1fe9f9f81d8fc83e83fb035bce8d9" +
-            "ed8f5caa41626d323551311b1d8d8f06785e3700d45e4d771157b22826efe553" +
-            "7a5892ad3bf3f915ec25342a8c7a3d02818100d19c03d857442bbaedb41b741e" +
-            "8e93d295940fdfc455898463ad96b0089ee68d90b787848b7aed6bb735c7e4b9" +
-            "7b22e867000d8e4b4ede4b155c34fd88c10244917912c048d023757bd758a117" +
-            "764aa80434c5c9636ec125574667ffe01af856f4517d06b6831ad50f16b26bba" +
-            "67a7125e158988c98b817dbb0928efa00c3ed702818100c4d49f7f3bf36586aa" +
-            "519bf2841c459c1863e71c08a9111344e51fcf5ff4267420fd9ffc9f72288e44" +
-            "b56bdae4eaa669e5e350afe4b4402be4af54d5dbc8b5dc5f5b6bb79df4fd17a5" +
-            "225287947783b5327b5dedf02733fb534514cc05fde1dcfceb8b537ad3c163a8" +
-            "8f36a60e2fb17fa6d9a0f3fca444f349eed9f07823879f02818100a5e9eb753c" +
-            "261ec338d23e84dc8718e53036e195cacfb6294fc920a4b83e26da59799c5043" +
-            "238b789ead784b48b1fa40a0fefebbea4a44548454d730f4256a8921e906f9a2" +
-            "e8f59851ed741f16f63043ec0865a2720d41df2fc4f01f2ea1ca7ef1a6eae2fc" +
-            "66ac3f8750fceb9ec1db1203dce25f9ec0c93fdf6371beb31dde430281807852" +
-            "be59ea4d25504847f13c34948fdd176fe2f4d93a790cbd7e0f8f16ca4ac38cf3" +
-            "5e5cf11fb93917398c805896353ae164af8b8714c571cfaf7afded086a5c1812" +
-            "ebeb686d3e56b9051d4c726f091db8897fe7177aefa500c7672a3db370e245de" +
-            "bbe24160b784f3a2f0b65c4fbd831a7d498e3d70321243acf69fb0e18f630281" +
-            "8065f0a2f257f8bf1d57e3f1b72c9a664ca92630985ee5ba35438e57a1df67a6" +
-            "f6b380907f5b7f9bdd2ddc63385615c5ca3c0dcbedfdc3f18433160855824712" +
-            "eaaeb318774478427dfb58135715cf82730a743dd8448984450905c28a6a97a0" +
-            "5f4aaad616978c07c5957c4f1945073f333df4337557bd6b754953f71df7a03c" +
-            "ec"),
-
-    // This certificate is generated by the below commands:
-    // openssl genpkey -genparam -algorithm dsa -pkeyopt dsa_paramgen_bits:2048 \
-    //     -pkeyopt dsa_paramgen_q_bits:256 -out param.pem
-    // openssl genpkey -paramfile param.pem -out key.pem
-    // openssl req -x509 -new -key key.pem -days 7300 \
-    //     -subj "/CN=DSA-2048-SHA256" -sha256 -out cer.pem
-    DSA_2048_SHA256(
-            KeyAlgorithm.DSA,
-            "-----BEGIN CERTIFICATE-----\n" +
-            "MIIEezCCBCCgAwIBAgIUYbBHFrJkO9EokOROEScK0dr3aVowCwYJYIZIAWUDBAMC\n" +
-            "MBoxGDAWBgNVBAMMD0RTQS0yMDQ4LVNIQTI1NjAeFw0xOTAxMTYwNjA4NTJaFw0z\n" +
-            "OTAxMTEwNjA4NTJaMBoxGDAWBgNVBAMMD0RTQS0yMDQ4LVNIQTI1NjCCA0cwggI5\n" +
-            "BgcqhkjOOAQBMIICLAKCAQEAnGTeaC+MitQykXl2UcGtJhkelRhBalZuzR9fh8Xf\n" +
-            "swSj2auVzhjkQfns6E14X72XLYDwHPQilh4ZSiC1cX7bpvohJ7CjbouGnT78Gwf0\n" +
-            "pfVMRBRfbNiwBQzFtzehAqlLPXyHWCPxAzW0EgzZh8asIofBEGmGh6sxlpXbEcCS\n" +
-            "Ra5Q2vdDRVksm4APHKwbS1F6L/0QDvjDAudWyLFdFMSBuoyeFwCf7Gr5lcVi538h\n" +
-            "MliXSAhJ7SXe4B9K/5/VicuzAffE+EZsZZuJKeQ4oHz8xtycdMcW86Iag1i/POzD\n" +
-            "0Z7c5p9j1zDgms1ZRSz4fd7YgNGjmmf6dYJlZmCX4w9YiwIhALnVATHxZmk7G1kf\n" +
-            "LGX7SMeflAhA/D3EPA5QWdgTc0orAoIBAGYTWMnKHBF4oMKUsx6lF6KvSrqFQ0+j\n" +
-            "mWN1RNAGiVYm/Js9sc7jolZCbVTWM7GblO2DxiKed3FtcL3xw4P6l3GU7kFthsjh\n" +
-            "bHbMG58s5JVboLX50wZo1uBOb0kRcZYjYTfUwbBYpGNnl7xfQsZ/Bxq/wzyn4gxb\n" +
-            "+C0pu/vzmko+opKfFr9a2EL+ADvQhPd6y/L0YcpiTihvfXDWu+n3bNlwhUZYevux\n" +
-            "SPVkQH3h5YEqXePF7UeY506/2sr41/xCbCkuH+Ob77Cy1IjMqr4OpXzj6wCSjlFy\n" +
-            "Re66yqsjGpuBeTtsn9lKmlFVl4QUdw7XYbRubafNFEdd5IazMflCcgMDggEGAAKC\n" +
-            "AQEAnF3/TT0nYzfwY6/+lmoqoBtGU4of7RK4U3Jdhf6dj755GwgsPGAz3Rzh/hq/\n" +
-            "B3fuyrtnE/aU0EK1dtRNqnKeFsMCURBi3sWYYe7vamw5TukFMSUOuH76v75b26c+\n" +
-            "nTfZF30iDz+66Z5gcOSwhz9aLCnF/wYwijnzagnCF4m0Nhwsjtz4qECMPfL/Rkx8\n" +
-            "s83tUF53mx5o8WCYMNr4yJGcHEkautvZN05zwoxZTPKZNngWeCUAY07XwOYHTUvx\n" +
-            "C9Sxiom9k1pZPbHZnGpUx96at2dMoeTeHR6xF/0QpiIb4wLpOg/CRxsopBmhEl0S\n" +
-            "BEXYNIcrXLwVBLvJD6H44DxRiqNTMFEwHQYDVR0OBBYEFCr6C8Bl7wjz5L3cYMG3\n" +
-            "/ZFe7Ee0MB8GA1UdIwQYMBaAFCr6C8Bl7wjz5L3cYMG3/ZFe7Ee0MA8GA1UdEwEB\n" +
-            "/wQFMAMBAf8wCwYJYIZIAWUDBAMCA0gAMEUCIArByiqjCG1ZuOVY91OPa9g8q60y\n" +
-            "/BSRWRgikEuq3AbgAiEAoZoKXW80FTMxv/9tFy0N7OrUV4rc9+AUBSTuRCuTAk4=\n" +
-            "-----END CERTIFICATE-----",
-            "308202640201003082023906072a8648ce3804013082022c02820101009c64de" +
-            "682f8c8ad43291797651c1ad26191e9518416a566ecd1f5f87c5dfb304a3d9ab" +
-            "95ce18e441f9ece84d785fbd972d80f01cf422961e194a20b5717edba6fa2127" +
-            "b0a36e8b869d3efc1b07f4a5f54c44145f6cd8b0050cc5b737a102a94b3d7c87" +
-            "5823f10335b4120cd987c6ac2287c110698687ab319695db11c09245ae50daf7" +
-            "4345592c9b800f1cac1b4b517a2ffd100ef8c302e756c8b15d14c481ba8c9e17" +
-            "009fec6af995c562e77f21325897480849ed25dee01f4aff9fd589cbb301f7c4" +
-            "f8466c659b8929e438a07cfcc6dc9c74c716f3a21a8358bf3cecc3d19edce69f" +
-            "63d730e09acd59452cf87dded880d1a39a67fa758265666097e30f588b022100" +
-            "b9d50131f166693b1b591f2c65fb48c79f940840fc3dc43c0e5059d813734a2b" +
-            "02820100661358c9ca1c1178a0c294b31ea517a2af4aba85434fa399637544d0" +
-            "06895626fc9b3db1cee3a256426d54d633b19b94ed83c6229e77716d70bdf1c3" +
-            "83fa977194ee416d86c8e16c76cc1b9f2ce4955ba0b5f9d30668d6e04e6f4911" +
-            "7196236137d4c1b058a4636797bc5f42c67f071abfc33ca7e20c5bf82d29bbfb" +
-            "f39a4a3ea2929f16bf5ad842fe003bd084f77acbf2f461ca624e286f7d70d6bb" +
-            "e9f76cd9708546587afbb148f564407de1e5812a5de3c5ed4798e74ebfdacaf8" +
-            "d7fc426c292e1fe39befb0b2d488ccaabe0ea57ce3eb00928e517245eebacaab" +
-            "231a9b81793b6c9fd94a9a5155978414770ed761b46e6da7cd14475de486b331" +
-            "f942720304220220509dd213cc9769e93825063a4a60500f67c4b979f6504b2f" +
-            "ccdbefb3ab8fe6da"),
-
-    // This certificate is generated by the below commands:
-    // openssl genpkey -genparam -algorithm dsa -pkeyopt dsa_paramgen_bits:2048 \
-    //     -pkeyopt dsa_paramgen_q_bits:256 -out param.pem
-    // openssl genpkey -paramfile param.pem -out key.pem
-    // openssl req -x509 -new -key key.pem -days 7300 \
-    //     -subj "/CN=EXAMPLE" -sha256 -out cer.pem
-    EXAMPLE_DSA_2048_SHA256(
-            KeyAlgorithm.DSA,
-            "-----BEGIN CERTIFICATE-----\n" +
-            "MIIEaTCCBA+gAwIBAgIUckU2myqkWak+Svv0FFJX91vv1jMwCwYJYIZIAWUDBAMC\n" +
-            "MBIxEDAOBgNVBAMMB0VYQU1QTEUwHhcNMTkwMTE2MDYwODUzWhcNMzkwMTExMDYw\n" +
-            "ODUzWjASMRAwDgYDVQQDDAdFWEFNUExFMIIDRjCCAjkGByqGSM44BAEwggIsAoIB\n" +
-            "AQDGmXUxMKzLIVUQUy4lu4fbnv8fRXtWIbv1jxWATCNFiFt4cUxrr7GVC16MGrgm\n" +
-            "FtMIHXWwFlq2wTL0RhVp2WPIPQzxCwQFivQjpdewVCB1BoJ1ozlvQjU4hri5Ymdt\n" +
-            "ebe90uT8NsvrQrSKYCl+/pPNiZKT8oX1aKzRYPQLn0bVXUicWlACoLfHGM4irjEC\n" +
-            "4JezC/tdLleeNYNpy2/dKYu/atyN/u0d+dPRLWBCw6/qCRn1yRAv04GC3WYBlSXz\n" +
-            "f9OKlCH5kfm9sLyatz/RWDqOb/YWW2Rk7UTKAnoTAyB+I9yUXg6Gad2csNkxXv55\n" +
-            "9oJAhdhsOS5cdBoqlZEahIFBAiEAjiMCVBGpnAxjb2dXM/Eec7EfThflQXbl33Zn\n" +
-            "Uq3AAsUCggEAaBNP9Uttfs1eV/38aurLd3T1OiM0CF7DPxE0qpSM9dQz9cKZajIE\n" +
-            "lsVTGOLBC5/+VSat9t1VG+JoyvSspkvk97/mxx0WCz/QAYTdwCXVuMuSv+EqeOMP\n" +
-            "lCxEdbOS8pfD8shOK+pnDSHMJvURYxB+fJkHHeXfwesH3632Vq0GlJ8PgXH5NLHM\n" +
-            "MWv7oZjyZMnGWDq2taJcZZG5ETNda2fATNCF9Al430MUxie2Sp50vA1KEtyUqMu+\n" +
-            "CLpyOynPHi96TWHNfD23TmKFVN9Uh2nUNIpUk8NMKBwg2O7FvvNnKfbl44ikuCnc\n" +
-            "06U7SdF3y8NRdwyayMI3BkOsV8mkoMwUgAOCAQUAAoIBADK2c1Gl3+6zrFU8Uhro\n" +
-            "5lFnDy3UYXINpdtWR/8T0FJ6YMax70VCkyxucq3AUnmq9AQtFijjmXDnxzD5g7IS\n" +
-            "zOU/28Kg1Mmw26uzrpUZPiixNU7v/xzE37M0Ig3VCEQ9mw57/yv8gwZurHtsokGt\n" +
-            "k0lzH/krhYPCOpskg6NulGq5lGsnNVdPkSkiAWZFHTysgKgxvMUxXj0bUm4ZyNw6\n" +
-            "Lp2bFHKbmSeTy3OLo/Kvd7BIjhV+Bi5LFh7h8spf6SC7qyEm0X7Keu+61xkFHU8a\n" +
-            "aghnGQYwuzpTp+hsbAJdHwVLw9ElqEoaVp3rAmxtsdzqhZSxcMZoypbjEJpiZ1/v\n" +
-            "fQCjUzBRMB0GA1UdDgQWBBRTPXqHl7VKr5U94p9c882ge9DOXzAfBgNVHSMEGDAW\n" +
-            "gBRTPXqHl7VKr5U94p9c882ge9DOXzAPBgNVHRMBAf8EBTADAQH/MAsGCWCGSAFl\n" +
-            "AwQDAgNHADBEAiAOQxtKiMImXKWQvUKZxoUc+chXRxAj3UD3Zj7RksPF2AIgf8HG\n" +
-            "hOnr3hzIej3Da2Ty9RTittcgZ14boraO/Vlx9Jo=\n" +
-            "-----END CERTIFICATE-----",
-            "308202640201003082023906072a8648ce3804013082022c0282010100c69975" +
-            "3130accb215510532e25bb87db9eff1f457b5621bbf58f15804c2345885b7871" +
-            "4c6bafb1950b5e8c1ab82616d3081d75b0165ab6c132f4461569d963c83d0cf1" +
-            "0b04058af423a5d7b0542075068275a3396f42353886b8b962676d79b7bdd2e4" +
-            "fc36cbeb42b48a60297efe93cd899293f285f568acd160f40b9f46d55d489c5a" +
-            "5002a0b7c718ce22ae3102e097b30bfb5d2e579e358369cb6fdd298bbf6adc8d" +
-            "feed1df9d3d12d6042c3afea0919f5c9102fd38182dd66019525f37fd38a9421" +
-            "f991f9bdb0bc9ab73fd1583a8e6ff6165b6464ed44ca027a1303207e23dc945e" +
-            "0e8669dd9cb0d9315efe79f6824085d86c392e5c741a2a95911a848141022100" +
-            "8e23025411a99c0c636f675733f11e73b11f4e17e54176e5df766752adc002c5" +
-            "0282010068134ff54b6d7ecd5e57fdfc6aeacb7774f53a2334085ec33f1134aa" +
-            "948cf5d433f5c2996a320496c55318e2c10b9ffe5526adf6dd551be268caf4ac" +
-            "a64be4f7bfe6c71d160b3fd00184ddc025d5b8cb92bfe12a78e30f942c4475b3" +
-            "92f297c3f2c84e2bea670d21cc26f51163107e7c99071de5dfc1eb07dfadf656" +
-            "ad06949f0f8171f934b1cc316bfba198f264c9c6583ab6b5a25c6591b911335d" +
-            "6b67c04cd085f40978df4314c627b64a9e74bc0d4a12dc94a8cbbe08ba723b29" +
-            "cf1e2f7a4d61cd7c3db74e628554df548769d4348a5493c34c281c20d8eec5be" +
-            "f36729f6e5e388a4b829dcd3a53b49d177cbc351770c9ac8c2370643ac57c9a4" +
-            "a0cc1480042202201ba738489c54dddd5ffbf0009ef9d11851182235a251a410" +
-            "4a6354181ecd0348"),
-
-    // This certificate is generated by the below commands:
-    // openssl genpkey -algorithm ec -pkeyopt ec_paramgen_curve:P-256 \
-    //     -pkeyopt ec_param_enc:named_curve -out key.pem
-    // openssl req -x509 -new -days 7300 -key key.pem \
-    //     -subj "/CN=ECDSA-SECP256-SHA256" -sha256 -out cer.pem
-    ECDSA_PRIME256V1_SHA256(
-            KeyAlgorithm.EC,
-            "-----BEGIN CERTIFICATE-----\n" +
-            "MIIBkzCCATmgAwIBAgIUVW+Rj8muf1DO8yUB9NSEDkD8oYowCgYIKoZIzj0EAwIw\n" +
-            "HzEdMBsGA1UEAwwURUNEU0EtU0VDUDI1Ni1TSEEyNTYwHhcNMTkwMjI3MTEwNzA0\n" +
-            "WhcNMzkwMjIyMTEwNzA0WjAfMR0wGwYDVQQDDBRFQ0RTQS1TRUNQMjU2LVNIQTI1\n" +
-            "NjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJPHqflVA59hR/sBM64OOY2/PTTx\n" +
-            "kZZhKcVV8vEkWRWvDV2u2F+lbRQoEoe8bwfGgQgGJIdc+dz9/TVAaYlitaKjUzBR\n" +
-            "MB0GA1UdDgQWBBRS9gbMeeA7j7QdipPufKn3jI3hKTAfBgNVHSMEGDAWgBRS9gbM\n" +
-            "eeA7j7QdipPufKn3jI3hKTAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0gA\n" +
-            "MEUCIDH0b3EewcoZUeSo0c2pNSWGCeRlZI49dASDbZ3A0jdTAiEAy/dM9LwYvyLl\n" +
-            "yuWq4yTouCdzfQwR9QXg3ohRMhnASlg=\n" +
-            "-----END CERTIFICATE-----",
-            "308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02" +
-            "01010420ae670b91bae99a9752f2b7e26ab9c0e98636f0b0040d78f2ea4081f8" +
-            "e57c72e0a1440342000493c7a9f955039f6147fb0133ae0e398dbf3d34f19196" +
-            "6129c555f2f1245915af0d5daed85fa56d14281287bc6f07c681080624875cf9" +
-            "dcfdfd3540698962b5a2"),
-
-    // This certificate is generated by the below commands:
-    // openssl genpkey -algorithm ec -pkeyopt ec_paramgen_curve:P-256 \
-    //     -pkeyopt ec_param_enc:named_curve -out key.pem
-    // openssl req -x509 -new -days 7300 -key key.pem \
-    //     -subj "/CN=EXAMPLE" -sha256 -out cer.pem
-    EXAMPLE_ECDSA_PRIME256V1_SHA256(
-            KeyAlgorithm.EC,
-            "-----BEGIN CERTIFICATE-----\n" +
-            "MIIBeTCCAR+gAwIBAgIUH6kQ0NfopvszxUwZ58KhMicqgCwwCgYIKoZIzj0EAwIw\n" +
-            "EjEQMA4GA1UEAwwHRVhBTVBMRTAeFw0xOTAyMjcxMTA5MTJaFw0zOTAyMjIxMTA5\n" +
-            "MTJaMBIxEDAOBgNVBAMMB0VYQU1QTEUwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC\n" +
-            "AASbW2bDwNxTHAzN7aW/OD/ywfa0A4bPKF3Qw4U4nLFBHhbbEmDrIkRWqU56UUDt\n" +
-            "fnTZnBCJtm4sH8o9D1D9UZVFo1MwUTAdBgNVHQ4EFgQUEEpzWKgPritmUQNEcQhz\n" +
-            "bB+5KuUwHwYDVR0jBBgwFoAUEEpzWKgPritmUQNEcQhzbB+5KuUwDwYDVR0TAQH/\n" +
-            "BAUwAwEB/zAKBggqhkjOPQQDAgNIADBFAiBjeGB0oc6t2fWOaviIMfqRqta64nl6\n" +
-            "Gj8I/JfDH97P1wIhAJ5IC9cxVTiPL/QTxUxRRlTYUboL/+ck1XR9JbZjd/ar\n" +
-            "-----END CERTIFICATE-----",
-            "308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02" +
-            "010104205dfd6695d259d4047433c0b4520bedcf95130c5c08ba149caddad70d" +
-            "b3b66c1ba144034200049b5b66c3c0dc531c0ccdeda5bf383ff2c1f6b40386cf" +
-            "285dd0c385389cb1411e16db1260eb224456a94e7a5140ed7e74d99c1089b66e" +
-            "2c1fca3d0f50fd519545"),
-
-    // This certificate is generated by the below commands:
-    // openssl genpkey -algorithm ec -pkeyopt ec_paramgen_curve:P-256 \
-    //     -pkeyopt ec_param_enc:named_curve -out key.pem
-    // openssl req -new -key key.pem \
-    //     -subj "/CN=EC-RSA-SECP256-SHA256" -sha256 -out csr.pem
-    // openssl x509 -req -CAcreateserial -days 7300 -in csr.pem -sha256 \
-    //     -CA CA.cer -CAkey CA.key -out cer.pem
-    // Actually the CA is RSA_2048_SHA256
-    EC_RSA_PRIME256V1_SHA256(
-            KeyAlgorithm.EC,
-            "-----BEGIN CERTIFICATE-----\n" +
-            "MIIB9TCB3gIUeM/cp7ZB4C1Gi/elzfbpdCrNPtAwDQYJKoZIhvcNAQELBQAwGjEY\n" +
-            "MBYGA1UEAwwPUlNBLTIwNDgtU0hBMjU2MB4XDTE5MTIxNTEzMDQxMFoXDTM5MTIx\n" +
-            "MDEzMDQxMFowIDEeMBwGA1UEAwwVRUMtUlNBLVNFQ1AyNTYtU0hBMjU2MFkwEwYH\n" +
-            "KoZIzj0CAQYIKoZIzj0DAQcDQgAE/kcsoE9AIKIjGv0IlkSSQvSwRpoO97UJlUks\n" +
-            "F0+MLaw66yOxFvVT7182/oKdJ8HiwZfxmiGEswSumT8yDdMnFzANBgkqhkiG9w0B\n" +
-            "AQsFAAOCAQEAuBUW4HsZ0ICYW6KtKLr9LlZfQdhv9Bc/nU836ASd8cV+PQHH3NSM\n" +
-            "1sUFWqq7ivVxvlNTcXThOrTleK8QN6388K4NRUFEXzROZk9Qo3q6lLpnfWiCIqOF\n" +
-            "DzQerjcUH9L/TgEtAm83tDq0ZgO7G59X8thTE9GjhXJ6bITK7TMh/VtsGzE7cW8r\n" +
-            "kXBNwflorhsR7rywKsASz5snYPYoTM0NZL9T093sxtO86B5sMlfX2rR+/BDQPDsX\n" +
-            "bCnXQNvn3tPuFuUZV1IAmrxG+xLxEaH0vi8eU7N2xMvPQKHGrprk4TvxM/d1Z7xY\n" +
-            "lWJXWvlhmPI3hb2ngLHEFa/gElpcdWi8Tw==\n" +
-            "-----END CERTIFICATE-----",
-            "308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02" +
-            "010104207ce96cbc7fe72e987c6f194afab1b219d26eed446e6b462ed51a8f2a" +
-            "c0619c53a14403420004fe472ca04f4020a2231afd0896449242f4b0469a0ef7" +
-            "b50995492c174f8c2dac3aeb23b116f553ef5f36fe829d27c1e2c197f19a2184" +
-            "b304ae993f320dd32717"),
-
-    // This certificate is generated by the below commands:
-    // openssl genpkey -algorithm ec -pkeyopt ec_paramgen_curve:P-256 \
-    //     -pkeyopt ec_param_enc:named_curve -out key.pem
-    // openssl req -new -key key.pem -subj "/CN=EXAMPLE" -sha256 -out csr.pem
-    // openssl x509 -req -CAcreateserial -days 7300 -in csr.pem -sha256 \
-    //     -CA CA.cer -CAkey CA.key -out cer.pem
-    // Actually the CA is EXAMPLE_RSA_2048_SHA256
-    EXAMPLE_EC_RSA_PRIME256V1_SHA256(
-            KeyAlgorithm.EC,
-            "-----BEGIN CERTIFICATE-----\n" +
-            "MIIB3zCByAIUWm9wgVB1TgdT5lpGNNkWBzuclKQwDQYJKoZIhvcNAQELBQAwEjEQ\n" +
-            "MA4GA1UEAwwHRVhBTVBMRTAeFw0xOTAyMjcwODA0MTNaFw0zOTAyMjIwODA0MTNa\n" +
-            "MBIxEDAOBgNVBAMMB0VYQU1QTEUwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASp\n" +
-            "6YAqTEEjuMlG+vKl8XPo2T2wgqY6t+j1R5ySC0YiGesfrwVLTM4V+Ey9PKHoEIVK\n" +
-            "kWNUF5Sb2JdrYIuzb5WdMA0GCSqGSIb3DQEBCwUAA4IBAQBPrIScxw5Nx4DhT5GL\n" +
-            "ngyNBOun0yAwqrxQ3LPheMuN7CH4qehFPDx8MHhmFFjEIDKVRbEEgxiCJAgca7qD\n" +
-            "uLCfESM8KU4bkV4Pjx7/OEQZ3AkQ0UwDvDr/DypPg7TLLyF979OQo+fEaqWKH8Q4\n" +
-            "8Ot8+VUFuwpYhHQlkoPnwFKIuCfDGwYmmHP2btlZ5qBuDDzdo1JVGF8pJ943cfA8\n" +
-            "zRBJGKw8MMJXlfk3yiDSKMji0106SFuGwFJfkrdUnZ+hpeJ7rrrqW7jwLIil8PKf\n" +
-            "Z41UjYM4Ut/6O5SFqueBsC6yxfzrJbd8UZ7ZkfagWMr/AXLK1Sm3ICSPHsQW30mH\n" +
-            "uX+T\n" +
-            "-----END CERTIFICATE-----",
-            "308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02" +
-            "01010420f1f944e1fc4bd7013b157db5fed23b84a4a1cd3d1a22f40746353185" +
-            "c0d8684da14403420004a9e9802a4c4123b8c946faf2a5f173e8d93db082a63a" +
-            "b7e8f5479c920b462219eb1faf054b4cce15f84cbd3ca1e810854a9163541794" +
-            "9bd8976b608bb36f959d");
-
-    public final KeyAlgorithm keyAlgorithm;
-    public final String certMaterials;
-    public final String privKeyMaterials;
-
-    private Cert(
-            KeyAlgorithm keyAlgorithm,
-            String certMaterials,
-            String privKeyMaterials) {
-        this.keyAlgorithm = keyAlgorithm;
-        this.certMaterials = certMaterials;
-        this.privKeyMaterials = privKeyMaterials;
-    }
-
-    public static Cert[] getCerts(String... certNames) {
-        Cert[] certs = new Cert[certNames.length];
-        for(int i = 0; i < certNames.length; i++) {
-            certs[i] = Cert.valueOf(certNames[i]);
-        }
-        return certs;
-    }
-
-    // Two certificates (mainCert and exampleCert) are selected to respect the
-    // specified cipher suite. SNI-associated cases specify exampleCert as desired.
-    public static Cert[] getCerts(CipherSuite cipherSuite) {
-        Cert mainCert = Cert.ECDSA_PRIME256V1_SHA256;
-        Cert exampleCert = Cert.EXAMPLE_ECDSA_PRIME256V1_SHA256;
-        if (cipherSuite.keyExAlgorithm == KeyExAlgorithm.ECDHE_RSA
-                || cipherSuite.keyExAlgorithm == KeyExAlgorithm.DHE_RSA
-                || cipherSuite.keyExAlgorithm == KeyExAlgorithm.RSA) {
-            mainCert = Cert.RSA_2048_SHA256;
-            exampleCert = Cert.EXAMPLE_RSA_2048_SHA256;
-        } else if (cipherSuite.keyExAlgorithm == KeyExAlgorithm.ECDH_RSA) {
-            mainCert = Cert.EC_RSA_PRIME256V1_SHA256;
-            exampleCert = Cert.EXAMPLE_EC_RSA_PRIME256V1_SHA256;
-        } else if (cipherSuite.keyExAlgorithm == KeyExAlgorithm.DHE_DSS) {
-            mainCert = Cert.DSA_2048_SHA256;
-            exampleCert = Cert.EXAMPLE_DSA_2048_SHA256;
-        }
-        System.out.printf("mainCert=%s, exampleCert=%s%n",
-                mainCert, exampleCert);
-        return new Cert[] { mainCert, exampleCert };
-    }
-}
--- a/test/jdk/javax/net/ssl/compatibility/Client.java	Thu Apr 23 22:49:55 2020 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,206 +0,0 @@
-/*
- * Copyright (c) 2017, 2019, 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.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.InetSocketAddress;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLParameters;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.SSLSocket;
-import javax.net.ssl.SSLSocketFactory;
-
-/*
- * A simple SSL socket client.
- */
-public class Client {
-
-    private final SSLSocket socket;
-
-    public Client(SSLContext context) throws Exception {
-        SSLSocketFactory socketFactory = context.getSocketFactory();
-        socket = (SSLSocket) socketFactory.createSocket();
-        socket.setSoTimeout(Utils.TIMEOUT);
-    }
-
-    public Client(Cert... certs) throws Exception {
-        this(Utils.createSSLContext(certs));
-    }
-
-    private SSLSession getSession() {
-        return socket.getSession();
-    }
-
-    private void setEnabledCipherSuites(String... cipherSuites) {
-        socket.setEnabledCipherSuites(cipherSuites);
-    }
-
-    private void setEnabledProtocols(String... protocols) {
-        socket.setEnabledProtocols(protocols);
-    }
-
-    @SuppressWarnings(value = { "unchecked", "rawtypes" })
-    private void setServerName(String hostname) {
-        List serverNames = new ArrayList();
-        serverNames.add(createSNIHostName(hostname));
-        SSLParameters params = socket.getSSLParameters();
-        params.setServerNames(serverNames);
-        socket.setSSLParameters(params);
-    }
-
-    // Create SNIHostName via reflection due to pre-8 JDK builds don't support
-    // SNI. Those JDK builds cannot find classes SNIServerName and SNIHostName.
-    private Object createSNIHostName(String hostname) {
-        try {
-            Class<?> clazz = Class.forName("javax.net.ssl.SNIHostName");
-            return clazz.getConstructor(String.class).newInstance(hostname);
-        } catch (Exception e) {
-            throw new RuntimeException("Creates SNIHostName failed!", e);
-        }
-    }
-
-    private void setApplicationProtocols(String... protocols) {
-        SSLParameters params = socket.getSSLParameters();
-        params.setApplicationProtocols(protocols);
-        socket.setSSLParameters(params);
-    }
-
-    private String getNegotiatedApplicationProtocol() {
-        return socket.getApplicationProtocol();
-    }
-
-    private void oneTimeConnect(String host, int port) throws IOException {
-        socket.connect(new InetSocketAddress(host, port));
-
-        OutputStream out = socket.getOutputStream();
-        out.write('C');
-        out.flush();
-
-        InputStream in = socket.getInputStream();
-        in.read();
-    }
-
-    public void close() throws IOException {
-        socket.close();
-    }
-
-    public static void main(String[] args) throws IOException {
-        System.out.println("----- Client start -----");
-        int port = Integer.valueOf(System.getProperty(Utils.PROP_PORT));
-
-        String protocol = System.getProperty(Utils.PROP_PROTOCOL);
-        String cipherSuite = System.getProperty(Utils.PROP_CIPHER_SUITE);
-        String serverName = System.getProperty(Utils.PROP_SERVER_NAME);
-        String appProtocols = System.getProperty(Utils.PROP_APP_PROTOCOLS);
-        boolean supportsSNIOnServer
-                = Boolean.getBoolean(Utils.PROP_SUPPORTS_SNI_ON_SERVER);
-        boolean supportsSNIOnClient
-                = Boolean.getBoolean(Utils.PROP_SUPPORTS_SNI_ON_CLIENT);
-        boolean supportsALPNOnServer
-                = Boolean.getBoolean(Utils.PROP_SUPPORTS_ALPN_ON_SERVER);
-        boolean supportsALPNOnClient
-                = Boolean.getBoolean(Utils.PROP_SUPPORTS_ALPN_ON_CLIENT);
-        boolean negativeCase
-                = Boolean.getBoolean(Utils.PROP_NEGATIVE_CASE_ON_CLIENT);
-        System.out.println(Utils.join(Utils.PARAM_DELIMITER,
-                "ClientJDK=" + System.getProperty(Utils.PROP_CLIENT_JDK),
-                "Protocol=" + protocol,
-                "CipherSuite=" + cipherSuite,
-                "ServerName=" + serverName,
-                "AppProtocols=" + appProtocols));
-
-        Status status = Status.SUCCESS;
-        Client client = null;
-        try {
-            client = new Client(Cert.getCerts(CipherSuite.cipherSuite(cipherSuite)));
-            client.setEnabledProtocols(protocol);
-            client.setEnabledCipherSuites(cipherSuite);
-
-            if (serverName != null) {
-                if (supportsSNIOnClient) {
-                    client.setServerName(serverName);
-                } else {
-                    System.out.println(
-                            "Ignored due to client doesn't support SNI.");
-                }
-            }
-
-            if (appProtocols != null) {
-                if (supportsALPNOnClient) {
-                    client.setApplicationProtocols(
-                            Utils.split(appProtocols, Utils.VALUE_DELIMITER));
-                } else {
-                    System.out.println(
-                            "Ignored due to client doesn't support ALPN.");
-                }
-            }
-
-            client.oneTimeConnect("localhost", port);
-
-            if (serverName != null && supportsSNIOnServer
-                    && supportsSNIOnClient) {
-                X509Certificate cert
-                        = (X509Certificate) client.getSession().getPeerCertificates()[0];
-                String subject
-                        = cert.getSubjectX500Principal().getName();
-                if (!subject.contains(serverName)) {
-                    System.out.println("Unexpected server: " + subject);
-                    status = Status.FAIL;
-                }
-            }
-
-            if (appProtocols != null && supportsALPNOnServer
-                    && supportsALPNOnClient) {
-                String negoAppProtocol
-                        = client.getNegotiatedApplicationProtocol();
-                String expectedNegoAppProtocol
-                        = System.getProperty(Utils.PROP_NEGO_APP_PROTOCOL);
-                if (!expectedNegoAppProtocol.equals(negoAppProtocol)) {
-                    System.out.println("Unexpected negotiated app protocol: "
-                            + negoAppProtocol);
-                    status = Status.FAIL;
-                }
-            }
-
-            if (status != Status.FAIL) {
-                status = negativeCase
-                       ? Status.UNEXPECTED_SUCCESS
-                       : Status.SUCCESS;
-            }
-        } catch (Exception exception) {
-            status = Utils.handleException(exception, negativeCase);
-        } finally {
-            if (client != null) {
-                client.close();
-            }
-        }
-
-        System.out.println("STATUS: " + status);
-        System.out.println("----- Client end -----");
-    }
-}
--- a/test/jdk/javax/net/ssl/compatibility/Compatibility.java	Thu Apr 23 22:49:55 2020 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,341 +0,0 @@
-/*
- * Copyright (c) 2017, 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.
- */
-
-/*
- * @test
- * @summary This test is used to check the interop compatibility on JSSE among
- *     different JDK releases.
- *     Note that, this is a manual test. For more details about the test and
- *     its usages, please look through README.
- *
- * @library /test/lib ../TLSCommon
- * @compile -source 1.7 -target 1.7 JdkUtils.java Server.java Client.java
- * @run main/manual Compatibility
- */
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.PrintStream;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import jdk.test.lib.process.OutputAnalyzer;
-
-public class Compatibility {
-
-    protected List<UseCase> getUseCases() {
-        return UseCase.getAllUseCases();
-    }
-
-    protected Set<JdkInfo> getJdkInfos() {
-        return jdkInfoList();
-    }
-
-    protected List<TestCase> runTest() throws Exception {
-        Set<JdkInfo> jdkInfos = getJdkInfos();
-
-        List<TestCase> testCases = new ArrayList<>();
-        ExecutorService executor = Executors.newCachedThreadPool();
-        PrintStream origStdOut = System.out;
-        PrintStream origStdErr = System.err;
-
-        try (PrintStream printStream = new PrintStream(
-                new FileOutputStream(Utils.TEST_LOG, true))) {
-            System.setOut(printStream);
-            System.setErr(printStream);
-
-            System.out.println(Utils.startHtml());
-            System.out.println(Utils.startPre());
-
-            JdkInfo targetJdkInfo = new JdkInfo(System.getProperty("test.jdk"));
-            for (UseCase useCase : getUseCases()) {
-                for (JdkInfo jdkInfo : jdkInfos) {
-                    testCases.add(
-                            runCase(targetJdkInfo, jdkInfo, useCase, executor));
-                    testCases.add(
-                            runCase(jdkInfo, targetJdkInfo, useCase, executor));
-                }
-            }
-
-            System.out.println(Utils.endPre());
-            System.out.println(Utils.endHtml());
-        }
-        System.setOut(origStdOut);
-        System.setErr(origStdErr);
-        executor.shutdown();
-
-        return testCases;
-    }
-
-    private TestCase runCase(JdkInfo serverJdk, JdkInfo clientJdk,
-            UseCase useCase, ExecutorService executor) throws Exception {
-        Map<String, String> props = new LinkedHashMap<>();
-        if (Utils.DEBUG) {
-            props.put("javax.net.debug", "all");
-        }
-
-        props.put("java.security.properties", Utils.SECURITY_PROPERTIES_FILE);
-
-        props.put(Utils.PROP_CERTS, Utils.join(Utils.VALUE_DELIMITER,
-                Cert.getCerts(useCase.cipherSuite)));
-        props.put(Utils.PROP_CLIENT_AUTH, String.valueOf(useCase.clientAuth));
-        if (useCase.appProtocol != UseCase.AppProtocol.NONE) {
-            props.put(Utils.PROP_APP_PROTOCOLS,
-                    Utils.join(Utils.VALUE_DELIMITER,
-                            useCase.appProtocol.appProtocols));
-            props.put(Utils.PROP_NEGO_APP_PROTOCOL,
-                    useCase.appProtocol.negoAppProtocol);
-        }
-        props.put(Utils.PROP_SERVER_JDK, serverJdk.version);
-
-        props.put(Utils.PROP_SUPPORTS_SNI_ON_SERVER,
-                serverJdk.supportsSNI + "");
-        props.put(Utils.PROP_SUPPORTS_ALPN_ON_SERVER,
-                serverJdk.supportsALPN + "");
-
-        TestCase testCase = new TestCase(serverJdk, clientJdk, useCase);
-        System.out.println(Utils.anchorName(testCase.toString(),
-                "===== Case start ====="));
-        System.out.println(testCase.toString());
-
-        props.put(Utils.PROP_NEGATIVE_CASE_ON_SERVER,
-                testCase.negativeCaseOnServer + "");
-        props.put(Utils.PROP_NEGATIVE_CASE_ON_CLIENT,
-                testCase.negativeCaseOnClient + "");
-
-        Future<OutputAnalyzer> serverFuture = executor.submit(() -> {
-            return runServer(serverJdk.jdkPath, props);
-        });
-        int port = waitForServerStarted();
-        System.out.println("port=" + port);
-
-        props.put(Utils.PROP_PORT, port + "");
-
-        props.put(Utils.PROP_CLIENT_JDK, clientJdk.version);
-
-        props.put(Utils.PROP_PROTOCOL, useCase.protocol.name);
-        props.put(Utils.PROP_CIPHER_SUITE, useCase.cipherSuite.name());
-        props.put(Utils.PROP_SUPPORTS_SNI_ON_CLIENT,
-                clientJdk.supportsSNI + "");
-        props.put(Utils.PROP_SUPPORTS_ALPN_ON_CLIENT,
-                clientJdk.supportsALPN + "");
-        if (useCase.serverName != UseCase.ServerName.NONE) {
-            props.put(Utils.PROP_SERVER_NAME,
-                    useCase.serverName.name);
-        }
-
-        Status clientStatus = null;
-        if (port != -1) {
-            String clientOutput = runClient(clientJdk.jdkPath,
-                    props).getOutput();
-            clientStatus = getStatus(clientOutput);
-        }
-
-        String serverOutput = serverFuture.get().getOutput();
-        Status serverStatus = getStatus(serverOutput);
-        testCase.setStatus(caseStatus(serverStatus, clientStatus));
-        System.out.printf(
-                "ServerStatus=%s, ClientStatus=%s, CaseStatus=%s%n",
-                serverStatus, clientStatus, testCase.getStatus());
-
-        System.out.println("===== Case end =====");
-        return testCase;
-    }
-
-    // Generates the test result report.
-    protected boolean generateReport(List<TestCase> testCases)
-            throws IOException {
-        boolean failed = false;
-        StringBuilder report = new StringBuilder();
-        report.append(Utils.startHtml());
-        report.append(Utils.tableStyle());
-        report.append(Utils.startTable());
-        report.append(Utils.row(
-                "No.",
-                "Client",
-                "Server",
-                "Protocol",
-                "Cipher suite",
-                "Client auth",
-                "SNI",
-                "ALPN",
-                "Status",
-                "Reason"));
-        for (int i = 0, size = testCases.size(); i < size; i++) {
-            TestCase testCase = testCases.get(i);
-
-            report.append(Utils.row(
-                    Utils.anchorLink(
-                            Utils.TEST_LOG,
-                            testCase.toString(),
-                            i + ""),
-                    testCase.clientJdk.version,
-                    testCase.serverJdk.version,
-                    testCase.useCase.protocol.name,
-                    testCase.useCase.cipherSuite,
-                    Utils.boolToStr(
-                            testCase.useCase.clientAuth),
-                    Utils.boolToStr(
-                            testCase.useCase.serverName == UseCase.ServerName.EXAMPLE),
-                    Utils.boolToStr(
-                            testCase.useCase.appProtocol == UseCase.AppProtocol.EXAMPLE),
-                    testCase.getStatus(),
-                    testCase.reason()));
-
-            failed = failed || testCase.isFailed();
-        }
-        report.append(Utils.endTable());
-        report.append(Utils.endHtml());
-
-        generateFile("report.html", report.toString());
-        return failed;
-    }
-
-    protected void run() throws Exception {
-        System.out.println("Test start");
-        List<TestCase> testCases= runTest();
-        System.out.println("Test end");
-
-        boolean failed = generateReport(testCases);
-        System.out.println("Report was generated.");
-
-        if (failed) {
-            throw new RuntimeException("At least one case failed. "
-                    + "Please check logs for more details.");
-        }
-    }
-
-    public static void main(String[] args) throws Throwable {
-        new Compatibility().run();;
-    }
-
-    private static Status getStatus(String log) {
-        if (log.contains(Status.UNEXPECTED_SUCCESS.name())) {
-            return Status.UNEXPECTED_SUCCESS;
-        } else if (log.contains(Status.SUCCESS.name())) {
-            return Status.SUCCESS;
-        } else if (log.contains(Status.EXPECTED_FAIL.name())) {
-            return Status.EXPECTED_FAIL;
-        } else if (log.contains(Status.TIMEOUT.name())) {
-            return Status.TIMEOUT;
-        } else {
-            return Status.FAIL;
-        }
-    }
-
-    private static Status caseStatus(Status serverStatus, Status clientStatus) {
-        return (serverStatus == Status.EXPECTED_FAIL && clientStatus != Status.SUCCESS)
-                || (clientStatus == Status.EXPECTED_FAIL && serverStatus != Status.SUCCESS)
-                ? Status.EXPECTED_FAIL
-                : (serverStatus == clientStatus ? serverStatus : Status.FAIL);
-    }
-
-    // Retrieves JDK info from the file which is specified by jdkListFile.
-    private static Set<JdkInfo> jdkInfoList() {
-        List<String> jdkList = jdkList();
-
-        Set<JdkInfo> jdkInfoList = new LinkedHashSet<>();
-        for (String jdkPath : jdkList) {
-            JdkInfo jdkInfo = new JdkInfo(jdkPath);
-            // JDK version must be unique.
-            if (!jdkInfoList.add(jdkInfo)) {
-                System.out.println("The JDK version is duplicate: " + jdkPath);
-            }
-        }
-        return jdkInfoList;
-    }
-
-    private static List<String> jdkList() {
-        String listFile = System.getProperty("jdkListFile");
-        System.out.println("jdk list file: " + listFile);
-        if (listFile != null && Files.exists(Paths.get(listFile))) {
-            try (Stream<String> lines = Files.lines(Paths.get(listFile))) {
-                return lines.filter(line -> {
-                    return !line.trim().isEmpty();
-                }).collect(Collectors.toList());
-            } catch (IOException e) {
-                throw new RuntimeException("Cannot get jdk list", e);
-            }
-        } else {
-            return new ArrayList<>();
-        }
-    }
-
-    // Checks if server is already launched, and returns server port.
-    private static int waitForServerStarted()
-            throws IOException, InterruptedException {
-        System.out.print("Waiting for server");
-        long deadline = System.currentTimeMillis() + Utils.TIMEOUT;
-        int port;
-        while ((port = getServerPort()) == -1
-                && System.currentTimeMillis() < deadline) {
-            System.out.print(".");
-            TimeUnit.SECONDS.sleep(1);
-        }
-        System.out.println();
-
-        return port;
-    }
-
-    // Retrieves the latest server port from port.log.
-    private static int getServerPort() throws IOException {
-        if (!Files.exists(Paths.get(Utils.PORT_LOG))) {
-            return -1;
-        }
-
-        try (Stream<String> lines = Files.lines(Paths.get(Utils.PORT_LOG))) {
-            return Integer.valueOf(lines.findFirst().get());
-        }
-    }
-
-    private static OutputAnalyzer runServer(String jdkPath,
-            Map<String, String> props) {
-        return ProcessUtils.java(jdkPath, props, Server.class);
-    }
-
-    private static OutputAnalyzer runClient(String jdkPath,
-            Map<String, String> props) {
-        return ProcessUtils.java(jdkPath, props, Client.class);
-    }
-
-    private static void generateFile(String path, String content)
-            throws IOException {
-        try(FileWriter writer = new FileWriter(new File(path))) {
-            writer.write(content);
-        }
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/compatibility/HrrTest.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,163 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @summary This is an interop compatibility test on TLSv1.3 hello retry request.
+ *
+ * @library /test/lib
+ *          ../TLSCommon
+ *          ../TLSCommon/interop
+ * @compile -source 1.8 -target 1.8
+ *          JdkInfoUtils.java
+ *          ../TLSCommon/interop/JdkProcServer.java
+ *          ../TLSCommon/interop/JdkProcClient.java
+ * @run main/manual HrrTest true
+ * @run main/manual HrrTest false
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import jdk.test.lib.security.CertUtils;
+
+public class HrrTest extends ExtInteropTest {
+
+    private JdkInfo serverJdkInfo;
+    private JdkInfo clientJdkInfo;
+
+    public HrrTest(JdkInfo serverJdkInfo, JdkInfo clientJdkInfo) {
+        super(new Jdk(serverJdkInfo.version, serverJdkInfo.javaPath),
+              new Jdk(clientJdkInfo.version, clientJdkInfo.javaPath));
+
+        this.serverJdkInfo = serverJdkInfo;
+        this.clientJdkInfo = clientJdkInfo;
+    }
+
+    @Override
+    protected boolean skipExecute() {
+        return super.skipExecute() || !supportsTLSv1_3();
+    }
+
+    private boolean supportsTLSv1_3() {
+        boolean supported = true;
+
+        if (!serverJdkInfo.enablesProtocol(Protocol.TLSV1_3)) {
+            System.out.println("The server doesn't support TLSv1.3.");
+            supported = false;
+        }
+
+        if (!clientJdkInfo.enablesProtocol(Protocol.TLSV1_3)) {
+            System.out.println("The client doesn't support TLSv1.3.");
+            supported = false;
+        }
+
+        return supported;
+    }
+
+    /*
+     * It takes the server to support secp384r1 only, and the client to support
+     * secp256r1 and secp384r1 in order, the server should respond hello retry
+     * request message.
+     * Please note that it has to specify the supported groups via property
+     * jdk.tls.namedGroups for JSSE peers.
+     */
+    @Override
+    protected List<TestCase<ExtUseCase>> getTestCases() {
+        List<TestCase<ExtUseCase>> testCases = new ArrayList<>();
+        for (CipherSuite cipherSuite : new CipherSuite[] {
+                CipherSuite.TLS_AES_128_GCM_SHA256,
+                CipherSuite.TLS_AES_256_GCM_SHA384,
+                CipherSuite.TLS_CHACHA20_POLY1305_SHA256}) {
+            testCases.add(createTestCase(cipherSuite));
+        }
+        return testCases;
+    }
+
+    private TestCase<ExtUseCase> createTestCase(CipherSuite cipherSuite) {
+        Cert cert = new Cert(KeyAlgorithm.RSA, SignatureAlgorithm.RSA,
+                HashAlgorithm.SHA256, CertUtils.RSA_CERT, CertUtils.RSA_KEY);
+        CertTuple certTuple = new CertTuple(cert, cert);
+
+        ExtUseCase serverCase = ExtUseCase.newInstance();
+        serverCase.setCertTuple(certTuple);
+        serverCase.setNamedGroups(NamedGroup.SECP384R1);
+
+        ExtUseCase clientCase = ExtUseCase.newInstance();
+        clientCase.setCertTuple(certTuple);
+        clientCase.setProtocols(Protocol.TLSV1_3);
+        clientCase.setCipherSuites(cipherSuite);
+        clientCase.setNamedGroups(NamedGroup.SECP256R1, NamedGroup.SECP384R1);
+
+        return new TestCase<ExtUseCase>(serverCase, clientCase);
+    }
+
+    @Override
+    protected boolean ignoreTestCase(TestCase<ExtUseCase> testCase) {
+        CipherSuite cipherSuite = testCase.clientCase.getCipherSuite();
+        return !serverJdkInfo.enablesCipherSuite(cipherSuite)
+                || !clientJdkInfo.supportsCipherSuite(cipherSuite);
+    }
+
+    @Override
+    protected JdkProcServer.Builder createServerBuilder(ExtUseCase useCase)
+            throws Exception {
+        JdkProcServer.Builder builder = new JdkProcServer.Builder();
+        builder.setJdk((Jdk) serverProduct);
+        builder.setCertTuple(useCase.getCertTuple());
+        builder.setProtocols(useCase.getProtocols());
+        builder.setCipherSuites(useCase.getCipherSuites());
+        builder.setClientAuth(useCase.isClientAuth());
+        builder.setServerNames(useCase.getServerNames());
+        builder.setAppProtocols(useCase.getAppProtocols());
+        builder.setNamedGroups(useCase.getNamedGroups());
+        return builder;
+    }
+
+    @Override
+    protected JdkProcClient.Builder createClientBuilder(ExtUseCase useCase)
+            throws Exception {
+        JdkProcClient.Builder builder = new JdkProcClient.Builder();
+        builder.setJdk((Jdk) clientProduct);
+        builder.setCertTuple(useCase.getCertTuple());
+        builder.setProtocols(useCase.getProtocols());
+        builder.setCipherSuites(useCase.getCipherSuites());
+        builder.setServerNames(useCase.getServerNames());
+        builder.setAppProtocols(useCase.getAppProtocols());
+        builder.setNamedGroups(useCase.getNamedGroups());
+        return builder;
+    }
+
+    public static void main(String[] args) throws Exception {
+        Boolean defaultJdkAsServer = Boolean.valueOf(args[0]);
+
+        Set<JdkInfo> jdkInfos = Utils.jdkInfoList();
+        for (JdkInfo jdkInfo : jdkInfos) {
+            HrrTest test = new HrrTest(
+                    defaultJdkAsServer ? JdkInfo.DEFAULT : jdkInfo,
+                    defaultJdkAsServer ? jdkInfo : JdkInfo.DEFAULT);
+            test.execute();
+        }
+    }
+}
--- a/test/jdk/javax/net/ssl/compatibility/JdkInfo.java	Thu Apr 23 22:49:55 2020 -0700
+++ b/test/jdk/javax/net/ssl/compatibility/JdkInfo.java	Fri Apr 24 15:28:57 2020 +0800
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -22,6 +21,7 @@
  * questions.
  */
 
+import java.nio.file.Path;
 import java.util.LinkedHashMap;
 import java.util.Map;
 
@@ -32,7 +32,9 @@
  */
 public class JdkInfo {
 
-    public final String jdkPath;
+    public static final JdkInfo DEFAULT = new JdkInfo(Jdk.DEFAULT.getPath());
+
+    public final Path javaPath;
 
     public final String version;
     public final String supportedProtocols;
@@ -42,16 +44,16 @@
     public final boolean supportsSNI;
     public final boolean supportsALPN;
 
-    public JdkInfo(String jdkPath) {
-        this.jdkPath = jdkPath;
+    public JdkInfo(Path javaPath) {
+        this.javaPath = javaPath;
 
-        String output = jdkAttributes(jdkPath);
+        String output = jdkAttributes(javaPath);
         if (output == null || output.trim().isEmpty()) {
             throw new RuntimeException(
-                    "Cannot determine the JDK attributes: " + jdkPath);
+                    "Cannot determine the JDK attributes: " + javaPath);
         }
 
-        String[] attributes = Utils.split(output, Utils.PARAM_DELIMITER);
+        String[] attributes = Utilities.split(output, Utilities.PARAM_DELIMITER);
         version = attributes[0].replaceAll(".*=", "");
         supportedProtocols = attributes[1].replaceAll(".*=", "");
         enabledProtocols = attributes[2].replaceAll(".*=", "");
@@ -62,10 +64,10 @@
     }
 
     // Determines the specific attributes for the specified JDK.
-    private static String jdkAttributes(String jdkPath) {
+    private static String jdkAttributes(Path javaPath) {
         Map<String, String> props = new LinkedHashMap<>();
-        props.put("java.security.properties", Utils.SECURITY_PROPERTIES_FILE);
-        return ProcessUtils.java(jdkPath, props, JdkUtils.class).getOutput();
+        props.put("java.security.properties", Utils.SEC_PROPS_FILE);
+        return ProcUtils.java(javaPath, JdkInfoUtils.class, props).getOutput();
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/compatibility/JdkInfoUtils.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,113 @@
+/*
+ * 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.security.NoSuchAlgorithmException;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLParameters;
+
+/*
+ * This class is used for returning some specific JDK information.
+ */
+public class JdkInfoUtils {
+
+    public static final String JAVA_RUNTIME_VERSION = "javaRuntimeVersion";
+    public static final String SUPPORTED_PROTOCOLS = "supportedProtocols";
+    public static final String ENABLED_PROTOCOLS = "enabledProtocols";
+    public static final String SUPPORTED_CIPHER_SUITES = "supportedCipherSuites";
+    public static final String ENABLED_CIPHER_SUITES = "enabledCipherSuites";
+    public static final String SUPPORTS_SNI = "supportsSNI";
+    public static final String SUPPORTS_ALPN = "supportsALPN";
+
+    // Returns the JDK build version.
+    public static String javaRuntimeVersion() {
+        return System.getProperty("java.runtime.version");
+    }
+
+    private static String supportedProtocols()
+            throws NoSuchAlgorithmException {
+        String[] protocols = SSLContext.getDefault()
+                .createSSLEngine().getSupportedProtocols();
+        return Utilities.join(Utilities.VALUE_DELIMITER, protocols).toString();
+    }
+
+    private static String enabledProtocols()
+            throws NoSuchAlgorithmException {
+        String[] protocols = SSLContext.getDefault()
+                .createSSLEngine().getEnabledProtocols();
+        return Utilities.join(Utilities.VALUE_DELIMITER, protocols).toString();
+    }
+
+    private static String supportedCipherSuites()
+            throws NoSuchAlgorithmException {
+        String[] supportedCipherSuites = SSLContext.getDefault()
+                .createSSLEngine().getSupportedCipherSuites();
+        return Utilities.join(Utilities.VALUE_DELIMITER, supportedCipherSuites)
+                .toString();
+    }
+
+    private static String enabledCipherSuites()
+            throws NoSuchAlgorithmException {
+        String[] enabledCipherSuites = SSLContext.getDefault()
+                .createSSLEngine().getEnabledCipherSuites();
+        return Utilities.join(Utilities.VALUE_DELIMITER, enabledCipherSuites)
+                .toString();
+    }
+
+    // Checks if SNI is supported by the JDK build.
+    private static boolean supportsSNI() {
+        boolean isSupported = true;
+        try {
+            SSLParameters.class.getMethod("getServerNames");
+        } catch (NoSuchMethodException e) {
+            isSupported = false;
+        }
+        return isSupported;
+    }
+
+    // Checks if ALPN is supported by the JDK build.
+    private static boolean supportsALPN() {
+        boolean isSupported = true;
+        try {
+            SSLParameters.class.getMethod("getApplicationProtocols");
+        } catch (NoSuchMethodException e) {
+            isSupported = false;
+        }
+        return isSupported;
+    }
+
+    public static void main(String[] args) throws NoSuchAlgorithmException {
+        System.out.print(Utilities.join(Utilities.PARAM_DELIMITER,
+                attr(JAVA_RUNTIME_VERSION, javaRuntimeVersion()),
+                attr(SUPPORTED_PROTOCOLS, supportedProtocols()),
+                attr(ENABLED_PROTOCOLS, enabledProtocols()),
+                attr(SUPPORTED_CIPHER_SUITES, supportedCipherSuites()),
+                attr(ENABLED_CIPHER_SUITES, enabledCipherSuites()),
+                attr(SUPPORTS_SNI, supportsSNI()),
+                attr(SUPPORTS_ALPN, supportsALPN())));
+    }
+
+    private static String attr(String name, Object value) {
+        return name + "=" + String.valueOf(value);
+    }
+}
--- a/test/jdk/javax/net/ssl/compatibility/JdkUtils.java	Thu Apr 23 22:49:55 2020 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,113 +0,0 @@
-/*
- * Copyright (c) 2017, 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.security.NoSuchAlgorithmException;
-
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLParameters;
-
-/*
- * This class is used for returning some specific JDK information.
- */
-public class JdkUtils {
-
-    public static final String JAVA_RUNTIME_VERSION = "javaRuntimeVersion";
-    public static final String SUPPORTED_PROTOCOLS = "supportedProtocols";
-    public static final String ENABLED_PROTOCOLS = "enabledProtocols";
-    public static final String SUPPORTED_CIPHER_SUITES = "supportedCipherSuites";
-    public static final String ENABLED_CIPHER_SUITES = "enabledCipherSuites";
-    public static final String SUPPORTS_SNI = "supportsSNI";
-    public static final String SUPPORTS_ALPN = "supportsALPN";
-
-    // Returns the JDK build version.
-    public static String javaRuntimeVersion() {
-        return System.getProperty("java.runtime.version");
-    }
-
-    private static String supportedProtocols()
-            throws NoSuchAlgorithmException {
-        String[] protocols = SSLContext.getDefault()
-                .createSSLEngine().getSupportedProtocols();
-        return Utils.join(Utils.VALUE_DELIMITER, protocols).toString();
-    }
-
-    private static String enabledProtocols()
-            throws NoSuchAlgorithmException {
-        String[] protocols = SSLContext.getDefault()
-                .createSSLEngine().getEnabledProtocols();
-        return Utils.join(Utils.VALUE_DELIMITER, protocols).toString();
-    }
-
-    private static String supportedCipherSuites()
-            throws NoSuchAlgorithmException {
-        String[] supportedCipherSuites = SSLContext.getDefault()
-                .createSSLEngine().getSupportedCipherSuites();
-        return Utils.join(Utils.VALUE_DELIMITER, supportedCipherSuites)
-                .toString();
-    }
-
-    private static String enabledCipherSuites()
-            throws NoSuchAlgorithmException {
-        String[] enabledCipherSuites = SSLContext.getDefault()
-                .createSSLEngine().getEnabledCipherSuites();
-        return Utils.join(Utils.VALUE_DELIMITER, enabledCipherSuites)
-                .toString();
-    }
-
-    // Checks if SNI is supported by the JDK build.
-    private static boolean supportsSNI() {
-        boolean isSupported = true;
-        try {
-            SSLParameters.class.getMethod("getServerNames");
-        } catch (NoSuchMethodException e) {
-            isSupported = false;
-        }
-        return isSupported;
-    }
-
-    // Checks if ALPN is supported by the JDK build.
-    private static boolean supportsALPN() {
-        boolean isSupported = true;
-        try {
-            SSLParameters.class.getMethod("getApplicationProtocols");
-        } catch (NoSuchMethodException e) {
-            isSupported = false;
-        }
-        return isSupported;
-    }
-
-    public static void main(String[] args) throws NoSuchAlgorithmException {
-        System.out.print(Utils.join(Utils.PARAM_DELIMITER,
-                attr(JAVA_RUNTIME_VERSION, javaRuntimeVersion()),
-                attr(SUPPORTED_PROTOCOLS, supportedProtocols()),
-                attr(ENABLED_PROTOCOLS, enabledProtocols()),
-                attr(SUPPORTED_CIPHER_SUITES, supportedCipherSuites()),
-                attr(ENABLED_CIPHER_SUITES, enabledCipherSuites()),
-                attr(SUPPORTS_SNI, supportsSNI()),
-                attr(SUPPORTS_ALPN, supportsALPN())));
-    }
-
-    private static String attr(String name, Object value) {
-        return name + "=" + String.valueOf(value);
-    }
-}
--- a/test/jdk/javax/net/ssl/compatibility/ProcessUtils.java	Thu Apr 23 22:49:55 2020 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2017, 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.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-import jdk.test.lib.process.OutputAnalyzer;
-import jdk.test.lib.process.ProcessTools;
-
-/*
- * Utilities for executing java process.
- */
-public class ProcessUtils {
-
-    private static final String TEST_CLASSES = System.getProperty("test.classes");
-
-    public static OutputAnalyzer java(String jdkPath, Map<String, String> props,
-            Class<?> clazz) {
-        List<String> cmds = new ArrayList<>();
-        cmds.add(jdkPath + "/bin/java");
-
-        if (props != null) {
-            for (Map.Entry<String, String> prop : props.entrySet()) {
-                cmds.add("-D" + prop.getKey() + "=" + prop.getValue());
-            }
-        }
-
-        cmds.add("-cp");
-        cmds.add(TEST_CLASSES);
-        cmds.add(clazz.getName());
-        try {
-            return ProcessTools.executeCommand(
-                    cmds.toArray(new String[cmds.size()]));
-        } catch (Throwable e) {
-            throw new RuntimeException("Execute command failed: " + cmds, e);
-        }
-    }
-}
--- a/test/jdk/javax/net/ssl/compatibility/README	Thu Apr 23 22:49:55 2020 -0700
+++ b/test/jdk/javax/net/ssl/compatibility/README	Fri Apr 24 15:28:57 2020 +0800
@@ -1,4 +1,4 @@
-# Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2017, 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
@@ -21,109 +21,41 @@
 
 ##### Summary #####
 This test is used to check the interop compatibility on JSSE among different
-JDK releases. The oldest version supported by the test is JDK 7. Some of Java
-source files, JdkUtils.java, Server.java, and Client.java, use only JDK 7-compliant
-language features and APIs, in order to allowing different JDK releases can load
-and run associated classes.
-
-##### Output #####
-The test can generate a report at $JTREG_WORKDIR/scratch/report.html to display
-the key information for each case. It also outputs all of details on both of
-server and client sides to a separated file at $JTREG_WORKDIR/scratch/test.html.
-
-##### Report Columns #####
-No.
-    A sequence number. It contains a hyper link to the corresponding details
-    in $JTREG_WORKDIR/scratch/test.html.
-
-ServerJDK
-    The version of the JDK that acts as server.
-
-ClientJDK
-    The version of the JDK that acts as client.
-
-Protocol
-    The TLS protocol version.
-
-CipherSuite
-    The only enabled cipher suite on both of server and client.
-
-ClientAuth
-    If the client authentication is checked, the value is "Y"; otherwise, "N".
-
-SNI
-    If the SNI is checked, the value is "Y"; otherwise, "N".
-
-ALPN
-    If the ALPN is checked, the value is "Y"; otherwise, "N".
-
-Status
-    It indicates the communication status for a test case.
-    There are three status:
-    SUCCESS: Communication succeed as expected.
-    UNEXPECTED_SUCCESS: Communication succeed as unexpected.
-    FAIL: Communication fails with unexpected failure.
-    EXPECTED_FAIL: Communication fails with expected failure.
-    Please note that, if a case finishes as status UNEXPECTED_SUCCESS or FAIL,
-    that means the case fails. Any failed case results in the test goes to fail.
+JDK releases. The oldest version supported by the test is JDK 8. Some of Java
+source files, like JdkInfoUtils.java, JdkProcServer.java and JdkProcClient.java,
+use only JDK 8-compliant language features and APIs, in order to allowing
+different JDK releases can load and run associated classes.
 
 ##### Usage #####
 jtreg [-options] \
-    [-Ddebug=<true|false>] \
-    [-DfullCases=<true|false>] \
-    [-DfullCipherSuites=<true|false>] \
-    [-DjdkListFile=</path/to/jdkListFile>] \
+    [-Dtest.debug=<true|false>] \
+    [-Dtest.jdk.list.file=</path/to/jdkListFile>] \
     $JDK_WORKSPACE/test/jdk/javax/net/ssl/compatibility/Compatibility.java
 
 Besides the common jtreg options, like -jdk, this test introduces some more
 properties:
-debug
+test.debug
     It indicates if the test enable -Djavax.net.debug=all. This is a boolean
     property, and the default value is false.
     It is not mandatory.
 
-fullCases
-    It indicates if testing the full or mandatory set of parameter values.
-    Every parameter provides a mandatory value set that must be covered.
-    For more details about the parameter value sets, please see Parameter.java.
-    This is a boolean property, and the default value is false.
-    It is not mandatory.
-
-fullCipherSuites
-    It indicates if testing the full or mandatory set of cipher suites.
-    For more details about the specific cipher suite sets, see CipherSuite in
-    Parameter.java.
-    This is a boolean property, and the default value is false.
-    It is not mandatory.
-
-jdkListFile
+test.jdk.list.file
     It indicate the path of a file, which lists the absolute paths of different
     JDK builds. If no this property, the current testing JDK, specified by JTREG
     option -jdk, is used as the testing JDK.
     It is not mandatory.
 
 ##### Usage Examples #####
-Example 1
-$ jtreg -jdk:/path/to/latest/jdk \
-    $JDK_WS/jdk/test/javax/net/ssl/compatibility/Compatibility.java
-This example doesn't specify any property introduced by the test. That means
-it uses the current testing JDK, namely /path/to/latest/jdk, as server and
-client. It doesn't output any debug log, and tests only mandatory parameter
-value sets.
-
-Example 2
 $ cat /path/to/jdkList
-/path/to/jdk7
 /path/to/jdk8
 /path/to/jdk9
 /path/to/jdk10
 
 $ jtreg -jdk:/path/to/latest/jdk \
     -Ddebug=true \
-    -DfullCipherSuites=true \
-    -DjdkListFile=/path/to/jdkList \
+    -Dtest.jdk.list.file=/path/to/jdkList \
     $JDK_WS/jdk/test/javax/net/ssl/compatibility/Compatibility.java
 The above example uses a file "/path/to/jdkList" to contain the paths of local
-different JDK builds through 7 to 10. The execution uses each of JDK builds as
+different JDK builds through 8 to 10. The execution uses each of JDK builds as
 server and client respectively. And it enables SSL debug flag, and tests the
-full parameter value set.
\ No newline at end of file
+full parameter value set.
--- a/test/jdk/javax/net/ssl/compatibility/Server.java	Thu Apr 23 22:49:55 2020 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,162 +0,0 @@
-/*
- * Copyright (c) 2017, 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.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLParameters;
-import javax.net.ssl.SSLServerSocket;
-import javax.net.ssl.SSLServerSocketFactory;
-import javax.net.ssl.SSLSocket;
-
-/*
- * A simple SSL socket server.
- */
-public class Server {
-
-    private final SSLServerSocket serverSocket;
-
-    public Server(SSLContext context, int port) throws Exception {
-        SSLServerSocketFactory serverFactory = context.getServerSocketFactory();
-        serverSocket = (SSLServerSocket) serverFactory.createServerSocket(port);
-        serverSocket.setSoTimeout(Utils.TIMEOUT);
-    }
-
-    public Server(Cert[] certs, int port) throws Exception {
-        this(Utils.createSSLContext(certs), port);
-    }
-
-    public Server(Cert[] certs) throws Exception {
-        this(certs, 0);
-    }
-
-    private void setNeedClientAuth(boolean needClientAuth) {
-        serverSocket.setNeedClientAuth(needClientAuth);
-    }
-
-    private void setApplicationProtocols(String... protocols) {
-        SSLParameters params = serverSocket.getSSLParameters();
-        params.setApplicationProtocols(protocols);
-        serverSocket.setSSLParameters(params);
-    }
-
-    public int getPort() {
-        return serverSocket.getLocalPort();
-    }
-
-    private void accept() throws IOException {
-        SSLSocket socket = null;
-        try {
-            socket = (SSLSocket) serverSocket.accept();
-
-            InputStream in = socket.getInputStream();
-            in.read();
-
-            OutputStream out = socket.getOutputStream();
-            out.write('S');
-            out.flush();
-        } finally {
-            if (socket != null) {
-                socket.close();
-            }
-        }
-    }
-
-    public void close() throws IOException {
-        serverSocket.close();
-    }
-
-    public static void main(String[] args) throws IOException {
-        System.out.println("----- Server start -----");
-        String certs = System.getProperty(Utils.PROP_CERTS);
-        boolean clientAuth
-                = Boolean.getBoolean(Utils.PROP_CLIENT_AUTH);
-        String appProtocols = System.getProperty(Utils.PROP_APP_PROTOCOLS);
-        boolean supportsALPN
-                = Boolean.getBoolean(Utils.PROP_SUPPORTS_ALPN_ON_SERVER);
-        boolean negativeCase
-                = Boolean.getBoolean(Utils.PROP_NEGATIVE_CASE_ON_SERVER);
-
-        System.out.println(Utils.join(Utils.PARAM_DELIMITER,
-                "ServerJDK=" + System.getProperty(Utils.PROP_SERVER_JDK),
-                "ClientAuth=" + clientAuth,
-                "AppProtocols=" + appProtocols));
-
-        Status status = Status.SUCCESS;
-        Server server = null;
-        try {
-            server = new Server(
-                    Cert.getCerts(Utils.split(certs, Utils.VALUE_DELIMITER)));
-            System.out.println("port=" + server.getPort());
-            server.setNeedClientAuth(clientAuth);
-            if (appProtocols != null) {
-                if (supportsALPN) {
-                    server.setApplicationProtocols(
-                            Utils.split(appProtocols, Utils.VALUE_DELIMITER));
-                } else {
-                    System.out.println(
-                            "Ignored due to server doesn't support ALPN.");
-                }
-            }
-
-            savePort(server.getPort());
-            server.accept();
-
-            status = negativeCase ? Status.UNEXPECTED_SUCCESS : Status.SUCCESS;
-        } catch (Exception exception) {
-            status = Utils.handleException(exception, negativeCase);
-        } finally {
-            if (server != null) {
-                server.close();
-            }
-
-            deletePortFile();
-        }
-
-        System.out.println("STATUS: " + status);
-        System.out.println("----- Server end -----");
-    }
-
-    private static void deletePortFile() {
-        File portFile = new File(Utils.PORT_LOG);
-        if (portFile.exists() && !portFile.delete()) {
-            throw new RuntimeException("Cannot delete port log");
-        }
-    }
-
-    private static void savePort(int port) throws IOException {
-        FileWriter writer = null;
-        try {
-            writer = new FileWriter(new File(Utils.PORT_LOG));
-            writer.write(port + "");
-        } finally {
-            if (writer != null) {
-                writer.close();
-            }
-        }
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/compatibility/SniTest.java	Fri Apr 24 15:28:57 2020 +0800
@@ -0,0 +1,181 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @summary This is an interop compatibility test on SNI.
+ *
+ * @library /test/lib
+ *          ../TLSCommon
+ *          ../TLSCommon/interop
+ * @compile -source 1.8 -target 1.8
+ *          JdkInfoUtils.java
+ *          ../TLSCommon/interop/JdkProcServer.java
+ *          ../TLSCommon/interop/JdkProcClient.java
+ * @run main/manual SniTest true
+ * @run main/manual SniTest false
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+public class SniTest extends ExtInteropTest {
+
+    private JdkInfo serverJdkInfo;
+    private JdkInfo clientJdkInfo;
+
+    public SniTest(JdkInfo serverJdkInfo, JdkInfo clientJdkInfo) {
+        super(new Jdk(serverJdkInfo.version, serverJdkInfo.javaPath),
+              new Jdk(clientJdkInfo.version, clientJdkInfo.javaPath));
+
+        this.serverJdkInfo = serverJdkInfo;
+        this.clientJdkInfo = clientJdkInfo;
+    }
+
+    @Override
+    protected boolean skipExecute() {
+        return super.skipExecute() || !supportsSNI();
+    }
+
+    private boolean supportsSNI() {
+        boolean supported = true;
+
+        if (!serverJdkInfo.supportsSNI) {
+            System.out.println("The server doesn't support SNI.");
+            supported = false;
+        }
+
+        if (!clientJdkInfo.supportsSNI) {
+            System.out.println("The client doesn't support SNI.");
+            supported = false;
+        }
+
+        return supported;
+    }
+
+    @Override
+    protected List<TestCase<ExtUseCase>> getTestCases() {
+        List<TestCase<ExtUseCase>> testCases = new ArrayList<>();
+
+        for (Protocol protocol : new Protocol[] {
+                Protocol.TLSV1_2, Protocol.TLSV1_3 }) {
+            for (CipherSuite cipherSuite : Utilities.ALL_CIPHER_SUITES) {
+                if (!cipherSuite.supportedByProtocol(protocol)) {
+                    continue;
+                }
+
+                Cert cert = Utils.getCert(cipherSuite.keyExAlgorithm);
+                CertTuple certTuple = new CertTuple(cert, cert);
+
+                ExtUseCase serverCase = ExtUseCase.newInstance();
+                serverCase.setCertTuple(certTuple);
+                serverCase.setServerNames("SNI");
+
+                ExtUseCase clientCase = ExtUseCase.newInstance();
+                clientCase.setCertTuple(certTuple);
+                clientCase.setProtocols(protocol);
+                clientCase.setCipherSuites(cipherSuite);
+                clientCase.setServerNames(serverCase.getServerNames());
+
+                testCases.add(
+                        new TestCase<ExtUseCase>(serverCase, clientCase));
+            }
+        }
+
+        return testCases;
+    }
+
+    @Override
+    protected boolean ignoreTestCase(TestCase<ExtUseCase> testCase) {
+        CipherSuite cipherSuite = testCase.clientCase.getCipherSuite();
+        return !serverJdkInfo.enablesCipherSuite(cipherSuite)
+                || !clientJdkInfo.supportsCipherSuite(cipherSuite);
+    }
+
+    @Override
+    protected AbstractServer.Builder createServerBuilder(ExtUseCase useCase)
+            throws Exception {
+        return serverJdkInfo == JdkInfo.DEFAULT
+               ? createJdkServerBuilder(useCase)
+               : createAltJdkServerBuilder(useCase);
+    }
+
+    private JdkServer.Builder createJdkServerBuilder(ExtUseCase useCase) {
+        JdkServer.Builder builder = new JdkServer.Builder();
+        builder.setCertTuple(useCase.getCertTuple());
+        builder.setProtocols(useCase.getProtocols());
+        builder.setCipherSuites(useCase.getCipherSuites());
+        builder.setServerNames(useCase.getServerNames());
+        return builder;
+    }
+
+    private JdkProcServer.Builder createAltJdkServerBuilder(ExtUseCase useCase) {
+        JdkProcServer.Builder builder = new JdkProcServer.Builder();
+        builder.setJdk((Jdk) serverProduct);
+        builder.setCertTuple(useCase.getCertTuple());
+        builder.setProtocols(useCase.getProtocols());
+        builder.setCipherSuites(useCase.getCipherSuites());
+        builder.setServerNames(useCase.getServerNames());
+        return builder;
+    }
+
+    @Override
+    protected AbstractClient.Builder createClientBuilder(ExtUseCase useCase)
+            throws Exception {
+        return clientJdkInfo == JdkInfo.DEFAULT
+               ? createJdkClientBuilder(useCase)
+               : createAltJdkClientBuilder(useCase);
+    }
+
+    private JdkClient.Builder createJdkClientBuilder(ExtUseCase useCase) {
+        JdkClient.Builder builder = new JdkClient.Builder();
+        builder.setCertTuple(useCase.getCertTuple());
+        builder.setProtocols(useCase.getProtocols());
+        builder.setCipherSuites(useCase.getCipherSuites());
+        builder.setServerNames(useCase.getServerNames());
+        return builder;
+    }
+
+    private JdkProcClient.Builder createAltJdkClientBuilder(ExtUseCase useCase) {
+        JdkProcClient.Builder builder = new JdkProcClient.Builder();
+        builder.setJdk((Jdk) clientProduct);
+        builder.setCertTuple(useCase.getCertTuple());
+        builder.setProtocols(useCase.getProtocols());
+        builder.setCipherSuites(useCase.getCipherSuites());
+        builder.setServerNames(useCase.getServerNames());
+        return builder;
+    }
+
+    public static void main(String[] args) throws Exception {
+        Boolean defaultJdkAsServer = Boolean.valueOf(args[0]);
+
+        Set<JdkInfo> jdkInfos = Utils.jdkInfoList();
+        for (JdkInfo jdkInfo : jdkInfos) {
+            SniTest test = new SniTest(
+                    defaultJdkAsServer ? JdkInfo.DEFAULT : jdkInfo,
+                    defaultJdkAsServer ? jdkInfo : JdkInfo.DEFAULT);
+            test.execute();
+        }
+    }
+}
--- a/test/jdk/javax/net/ssl/compatibility/Status.java	Thu Apr 23 22:49:55 2020 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-/*
- * Copyright (c) 2017, 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.
- */
-
-/*
- * Test case result status.
- */
-public enum Status {
-
-    SUCCESS, UNEXPECTED_SUCCESS, FAIL, EXPECTED_FAIL, TIMEOUT;
-}
--- a/test/jdk/javax/net/ssl/compatibility/TestCase.java	Thu Apr 23 22:49:55 2020 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,121 +0,0 @@
-/*
- * Copyright (c) 2017, 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.
- */
-
-/*
- * A test case for a specific TLS communication use case between two JDKs.
- */
-public class TestCase {
-
-    public final JdkInfo serverJdk;
-    public final JdkInfo clientJdk;
-    public final UseCase useCase;
-
-    public final boolean protocolSupportsCipherSuite;
-
-    public final boolean serverEnablesProtocol;
-    public final boolean serverEnablesCipherSuite;
-
-    public final boolean clientSupportsProtocol;
-    public final boolean clientSupportsCipherSuite;
-
-    public final boolean negativeCaseOnServer;
-    public final boolean negativeCaseOnClient;
-
-    private Status status;
-
-    public TestCase(JdkInfo serverJdk, JdkInfo clientJdk, UseCase useCase) {
-        this.serverJdk = serverJdk;
-        this.clientJdk = clientJdk;
-        this.useCase = useCase;
-
-        serverEnablesProtocol = serverJdk.enablesProtocol(useCase.protocol);
-        serverEnablesCipherSuite = serverJdk.enablesCipherSuite(useCase.cipherSuite);
-
-        clientSupportsProtocol = clientJdk.supportsProtocol(useCase.protocol);
-        clientSupportsCipherSuite = clientJdk.supportsCipherSuite(useCase.cipherSuite);
-
-        protocolSupportsCipherSuite = useCase.protocolSupportsCipherSuite;
-
-        negativeCaseOnServer = !protocolSupportsCipherSuite
-                || !serverEnablesProtocol
-                || !serverEnablesCipherSuite;
-        negativeCaseOnClient = !protocolSupportsCipherSuite
-                || !clientSupportsProtocol
-                || !clientSupportsCipherSuite;
-    }
-
-    public Status getStatus() {
-        return status;
-    }
-
-    public void setStatus(Status status) {
-        this.status = status;
-    }
-
-    public boolean isNegative() {
-        return negativeCaseOnServer || negativeCaseOnClient;
-    }
-
-    public boolean isFailed() {
-        return status == Status.FAIL || status == Status.UNEXPECTED_SUCCESS;
-    }
-
-    public String negativeCaseReason() {
-        return Utils.join(". ",
-                !protocolSupportsCipherSuite
-                        ? "Protocol doesn't support cipher suite"
-                        : "",
-                !serverEnablesProtocol
-                        ? "Server doesn't enable protocol"
-                        : "",
-                !serverEnablesCipherSuite
-                        ? "Server doesn't enable cipher suite"
-                        : "",
-                !clientSupportsProtocol
-                        ? "Client doesn't support protocol"
-                        : "",
-                !clientSupportsCipherSuite
-                        ? "Client doesn't support cipher suite"
-                        : "");
-    }
-
-    public String reason() {
-        if (status == Status.SUCCESS) {
-            return "";
-        }
-
-        if (status == Status.EXPECTED_FAIL && isNegative()) {
-            return negativeCaseReason();
-        }
-
-        return "Refer to log at case hyperlink for details...";
-    }
-
-    @Override
-    public String toString() {
-        return Utils.join(Utils.PARAM_DELIMITER,
-                "ServerJDK=" + serverJdk.version,
-                "ClientJDK=" + clientJdk.version,
-                useCase.toString());
-    }
-}
--- a/test/jdk/javax/net/ssl/compatibility/UseCase.java	Thu Apr 23 22:49:55 2020 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,206 +0,0 @@
-/*
- * Copyright (c) 2017, 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.util.ArrayList;
-import java.util.List;
-
-/*
- * The TLS communication use case.
- */
-public class UseCase {
-
-    private static final boolean FULL_CASES
-            = Boolean.getBoolean("fullCases");
-
-    public static final boolean FULL_CIPHER_SUITES
-            = Boolean.getBoolean("fullCipherSuites");
-
-    public static final Protocol[] PROTOCOLS = new Protocol[] {
-            Protocol.SSLV3,
-            Protocol.TLSV1,
-            Protocol.TLSV1_1,
-            Protocol.TLSV1_2,
-            Protocol.TLSV1_3 };
-
-    public static final CipherSuite[] CIPHER_SUITES = new CipherSuite[] {
-            CipherSuite.TLS_AES_128_GCM_SHA256,
-            CipherSuite.TLS_AES_256_GCM_SHA384,
-            CipherSuite.TLS_CHACHA20_POLY1305_SHA256,
-            CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
-            CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
-            CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
-            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
-            CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
-            CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256,
-            CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
-            CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
-            CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
-            CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
-            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
-            CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
-            CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA,
-            CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
-            CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
-            CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
-            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
-            CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
-            CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256,
-            CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
-            CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
-            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
-            CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
-            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
-            CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
-            CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
-            CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
-            CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
-            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
-            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
-            CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
-            CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384,
-            CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,
-            CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,
-            CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
-            CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384,
-            CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
-            CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256,
-            CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
-            CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
-            CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
-            CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 };
-
-    public static final CipherSuite[] MANDATORY_CIPHER_SUITES = new CipherSuite[] {
-            CipherSuite.TLS_AES_128_GCM_SHA256,
-            CipherSuite.TLS_CHACHA20_POLY1305_SHA256,
-            CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
-            CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA,
-            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
-            CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
-            CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256,
-            CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
-            CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
-            CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 };
-
-    enum ServerName {
-
-        NONE(null),
-        EXAMPLE("EXAMPLE");
-
-        final String name;
-
-        private ServerName(String name) {
-            this.name = name;
-        }
-    }
-
-    enum AppProtocol {
-
-        NONE(null, null),
-        EXAMPLE(new String[] { Utils.HTTP_2, Utils.HTTP_1_1 }, Utils.HTTP_2);
-
-        final String[] appProtocols;
-
-        // Expected negotiated application protocol
-        final String negoAppProtocol;
-
-        private AppProtocol(String[] appProtocols, String negoAppProtocol) {
-            this.appProtocols = appProtocols;
-            this.negoAppProtocol = negoAppProtocol;
-        }
-    }
-
-    private static final Object[][] PARAMS = new Object[][] {
-            PROTOCOLS,
-            FULL_CASES || FULL_CIPHER_SUITES ? CIPHER_SUITES : MANDATORY_CIPHER_SUITES,
-            FULL_CASES ? new Boolean[] { false, true } : new Boolean[] { true },
-            FULL_CASES
-                    ? new ServerName[] { ServerName.NONE, ServerName.EXAMPLE }
-                    : new ServerName[] { ServerName.EXAMPLE },
-            FULL_CASES
-                    ? new AppProtocol[] {
-                            AppProtocol.NONE,
-                            AppProtocol.EXAMPLE }
-                    : new AppProtocol[] {
-                            AppProtocol.EXAMPLE } };
-
-    public final Protocol protocol;
-    public final CipherSuite cipherSuite;
-    public final Boolean clientAuth;
-    public final ServerName serverName;
-    public final AppProtocol appProtocol;
-
-    public final boolean protocolSupportsCipherSuite;
-
-    public UseCase(
-            Protocol protocol,
-            CipherSuite cipherSuite,
-            boolean clientAuth,
-            ServerName serverName,
-            AppProtocol appProtocol) {
-        this.protocol = protocol;
-        this.cipherSuite = cipherSuite;
-        this.clientAuth = clientAuth;
-        this.serverName = serverName;
-        this.appProtocol = appProtocol;
-
-        protocolSupportsCipherSuite = cipherSuite.supportedByProtocol(protocol);
-    }
-
-    @Override
-    public String toString() {
-        return Utils.join(Utils.PARAM_DELIMITER,
-                "Protocol=" + protocol.name,
-                "CipherSuite=" + cipherSuite,
-                "ClientAuth=" + clientAuth,
-                "ServerName=" + serverName,
-                "AppProtocols=" + appProtocol);
-    }
-
-    public static List<UseCase> getAllUseCases() {
-        List<UseCase> useCases = new ArrayList<>();
-        getUseCases(PARAMS, 0, new Object[PARAMS.length], useCases);
-        return useCases;
-    }
-
-    private static void getUseCases(Object[][] params, int index,
-            Object[] currentValues, List<UseCase> useCases) {
-        if (index == params.length) {
-            Protocol protocol = (Protocol) currentValues[0];
-            CipherSuite cipherSuite = (CipherSuite) currentValues[1];
-
-            UseCase useCase = new UseCase(
-                    protocol,
-                    cipherSuite,
-                    (Boolean) currentValues[2],
-                    (ServerName) currentValues[3],
-                    (AppProtocol) currentValues[4]);
-            useCases.add(useCase);
-        } else {
-            Object[] values = params[index];
-            for (int i = 0; i < values.length; i++) {
-                currentValues[index] = values[i];
-                getUseCases(params, index + 1, currentValues, useCases);
-            }
-        }
-    }
-}
--- a/test/jdk/javax/net/ssl/compatibility/Utils.java	Thu Apr 23 22:49:55 2020 -0700
+++ b/test/jdk/javax/net/ssl/compatibility/Utils.java	Fri Apr 24 15:28:57 2020 +0800
@@ -21,263 +21,94 @@
  * questions.
  */
 
-import java.io.ByteArrayInputStream;
 import java.io.IOException;
-import java.net.SocketTimeoutException;
-import java.security.KeyFactory;
-import java.security.KeyStore;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateFactory;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.PKCS8EncodedKeySpec;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLHandshakeException;
-import javax.net.ssl.TrustManagerFactory;
+import jdk.test.lib.security.CertUtils;
 
 /*
  * Utilities for testing.
  */
 public class Utils {
 
-    /* ***** Properties ***** */
-    public static final String PROP_PORT = "test.port";
-    public static final String PROP_CERTS = "test.certs";
-    public static final String PROP_PROTOCOL = "test.protocol";
-    public static final String PROP_CIPHER_SUITE = "test.cipher.suite";
-    public static final String PROP_CLIENT_AUTH = "test.client.auth";
-    public static final String PROP_SERVER_JDK = "test.server.jdk";
-    public static final String PROP_CLIENT_JDK = "test.client.jdk";
-    public static final String PROP_SERVER_NAME = "test.server.name";
-    public static final String PROP_APP_PROTOCOLS
-            = "test.app.protocols";
-    public static final String PROP_NEGO_APP_PROTOCOL
-            = "test.negotiated.app.protocol";
-    public static final String PROP_SUPPORTS_SNI_ON_SERVER
-            = "test.supports.sni.on.server";
-    public static final String PROP_SUPPORTS_SNI_ON_CLIENT
-            = "test.supports.sni.on.client";
-    public static final String PROP_SUPPORTS_ALPN_ON_SERVER
-            = "test.supports.alpn.on.server";
-    public static final String PROP_SUPPORTS_ALPN_ON_CLIENT
-            = "test.supports.alpn.on.client";
-    public static final String PROP_NEGATIVE_CASE_ON_SERVER
-            = "test.negative.case.on.server";
-    public static final String PROP_NEGATIVE_CASE_ON_CLIENT
-            = "test.negative.case.on.client";
+    public static final String PROP_JDK_LIST_FILE = "test.jdk.list.file";
 
-    public static final boolean DEBUG = Boolean.getBoolean("debug");
-    public static final String SECURITY_PROPERTIES_FILE = System.getProperty(
-            "test.security.properties",
+    public static final String PROP_SEC_PROPS_FILE = "test.sec.props.file";
+    public static final String SEC_PROPS_FILE = System.getProperty(
+            PROP_SEC_PROPS_FILE,
             System.getProperty("test.src") + "/java.security");
 
-    public static final int TIMEOUT = 10000;
-    public static final char[] PASSWORD = "testpass".toCharArray();
+    public static final Cert RSA_CERT = new Cert(
+            KeyAlgorithm.RSA,
+            SignatureAlgorithm.RSA,
+            HashAlgorithm.SHA256,
+            CertUtils.RSA_CERT, CertUtils.RSA_KEY);
+    public static final Cert ECDSA_CERT = new Cert(
+            KeyAlgorithm.EC,
+            SignatureAlgorithm.ECDSA,
+            HashAlgorithm.SHA256,
+            CertUtils.ECDSA_CERT, CertUtils.ECDSA_KEY);
+    public static final Cert ECRSA_CERT = new Cert(
+            KeyAlgorithm.EC,
+            SignatureAlgorithm.RSA,
+            HashAlgorithm.SHA256,
+            CertUtils.ECRSA_CERT, CertUtils.ECRSA_KEY);
+    public static final Cert DSA_CERT = new Cert(
+            KeyAlgorithm.DSA,
+            SignatureAlgorithm.DSA,
+            HashAlgorithm.SHA256,
+            CertUtils.DSA_CERT, CertUtils.DSA_KEY);
 
-    public static final String TEST_LOG = "test.html";
-    public static final String PORT_LOG = "port";
+    // Retrieves JDK info from the file which is specified by system property
+    // test.jdk.list.file.
+    public static Set<JdkInfo> jdkInfoList() {
+        List<String> jdkList = jdkList();
 
-    public static final String HTTP_2 = "h2";
-    public static final String HTTP_1_1 = "http/1.1";
-
-    public static final String PARAM_DELIMITER = ";";
-    public static final String VALUE_DELIMITER = ",";
-
-    /*
-     * Creates SSL context with the specified certificate.
-     */
-    public static SSLContext createSSLContext(Cert... certs) throws Exception {
-        KeyStore trustStore = KeyStore.getInstance("JKS");
-        trustStore.load(null, null);
-        for (int i = 0; i < certs.length; i++) {
-            trustStore.setCertificateEntry("trust-" + certs[i].name(),
-                    createCert(certs[i]));
+        Set<JdkInfo> jdkInfoList = new LinkedHashSet<>();
+        for (String jdkPath : jdkList) {
+            JdkInfo jdkInfo = new JdkInfo(Paths.get(jdkPath, "bin", "java"));
+            // JDK version must be unique.
+            if (!jdkInfoList.add(jdkInfo)) {
+                System.out.println("The JDK version is duplicate: " + jdkPath);
+            }
         }
-        TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
-        tmf.init(trustStore);
-
-        KeyStore keyStore = KeyStore.getInstance("JKS");
-        keyStore.load(null, null);
-        for (int i = 0; i < certs.length; i++) {
-            PrivateKey privKey = createKey(certs[i]);
-            keyStore.setKeyEntry("cert-" + certs[i].name(), privKey, PASSWORD,
-                    new Certificate[] { createCert(certs[i]) });
-        }
-        KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
-        kmf.init(keyStore, PASSWORD);
-
-        SSLContext context = SSLContext.getInstance("TLS");
-        context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
-        return context;
+        return jdkInfoList;
     }
 
-    private static Certificate createCert(Cert cert) throws IOException {
-        try {
-            CertificateFactory certFactory
-                    = CertificateFactory.getInstance("X.509");
-            return certFactory.generateCertificate(
-                    new ByteArrayInputStream(cert.certMaterials.getBytes()));
-        } catch (Exception e) {
-            throw new RuntimeException("Create key failed: " + cert, e);
+    private static List<String> jdkList() {
+        String listFile = System.getProperty(PROP_JDK_LIST_FILE);
+        System.out.println("jdk list file: " + listFile);
+        if (listFile != null && Files.exists(Paths.get(listFile))) {
+            try (Stream<String> lines = Files.lines(Paths.get(listFile))) {
+                return lines.filter(line -> {
+                    return !line.trim().isEmpty();
+                }).collect(Collectors.toList());
+            } catch (IOException e) {
+                throw new RuntimeException("Cannot get jdk list", e);
+            }
+        } else {
+            return new ArrayList<>();
         }
     }
 
-    private static PrivateKey createKey(Cert cert)
-            throws NoSuchAlgorithmException, InvalidKeySpecException {
-        PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(
-                hexToBytes(cert.privKeyMaterials));
-        KeyFactory keyFactory = KeyFactory.getInstance(
-                cert.keyAlgorithm.name);
-        PrivateKey privKey = keyFactory.generatePrivate(privKeySpec);
-        return privKey;
-    }
-
-    public static byte[] hexToBytes(String hex) {
-        if (hex == null) {
-            return null;
+    public static Cert getCert(KeyExAlgorithm keyExAlgorithm) {
+        if (keyExAlgorithm == KeyExAlgorithm.RSA
+                || keyExAlgorithm == KeyExAlgorithm.DHE_RSA
+                || keyExAlgorithm == KeyExAlgorithm.ECDHE_RSA) {
+            return RSA_CERT;
+        } else if (keyExAlgorithm == KeyExAlgorithm.DHE_DSS) {
+            return DSA_CERT;
+        } else if (keyExAlgorithm == KeyExAlgorithm.ECDH_RSA) {
+            return ECRSA_CERT;
+        } else {
+            return ECDSA_CERT;
         }
-
-        int length = hex.length();
-        if (length % 2 != 0) {
-            throw new IllegalArgumentException("Hex format is wrong.");
-        }
-
-        byte[] bytes = new byte[length / 2];
-        for (int i = 0; i < length; i += 2) {
-            bytes[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
-                    + Character.digit(hex.charAt(i + 1), 16));
-        }
-        return bytes;
-    }
-
-    @SuppressWarnings("unchecked")
-    public static <T> String join(String delimiter, T... values) {
-        StringBuilder result = new StringBuilder();
-        if (values != null && values.length > 0) {
-            for (int i = 0; i < values.length - 1; i++) {
-                if (values[i] != null && !values[i].toString().isEmpty()) {
-                    result.append(values[i]).append(delimiter);
-                }
-            }
-
-            if (values[values.length - 1] != null
-                    && !values[values.length - 1].toString().isEmpty()) {
-                result.append(values[values.length - 1]);
-            }
-        }
-        return result.toString();
-    }
-
-    public static String[] split(String str, String delimiter) {
-        return str == null ? new String[0] : str.split(delimiter);
-    }
-
-    public static String boolToStr(boolean bool) {
-        return bool ? "Y" : "N";
-    }
-
-    public static Status handleException(Exception exception,
-            boolean negativeCase) {
-        Status status;
-        if ((exception instanceof SSLHandshakeException
-                || exception instanceof IllegalArgumentException)
-                && negativeCase) {
-            System.out.println("Expected exception: " + exception);
-            status = Status.EXPECTED_FAIL;
-        } else if (exception instanceof SocketTimeoutException) {
-            status = Status.TIMEOUT;
-        } else {
-            exception.printStackTrace(System.out);
-            status = Status.FAIL;
-        }
-        return status;
-    }
-
-    /* The HTML-related constants and methods. */
-
-    private static final String STYLE
-            = "style=\"font-family: Courier New; "
-            + "font-size: 12px; "
-            + "white-space: pre-wrap\"";
-
-    private static final String TABLE_STYLE
-            = "#test { font-family: \"Courier New\"; font-size: 12px; border-collapse: collapse; }\n"
-            + "#test td { border: 1px solid #ddd; padding: 4px; }\n"
-            + "#test tr:nth-child(odd) { background-color: #f2f2f2; }";
-
-    public static String row(Object... values) {
-        StringBuilder row = new StringBuilder();
-        row.append(startTr());
-        for (Object value : values) {
-            row.append(startTd());
-            row.append(value);
-            row.append(endTd());
-        }
-        row.append(endTr());
-        return row.toString();
-    }
-
-    public static String startHtml() {
-        return startTag("html");
-    }
-
-    public static String endHtml() {
-        return endTag("html");
-    }
-
-    public static String startPre() {
-        return startTag("pre " + STYLE);
-    }
-
-    public static String endPre() {
-        return endTag("pre");
-    }
-
-    public static String anchorName(String name, String text) {
-        return "<a name=" + name + ">" + text + "</a>";
-    }
-
-    public static String anchorLink(String file, String anchorName,
-            String text) {
-        return "<a href=" + file + "#" + anchorName + ">" + text + "</a>";
-    }
-
-    public static String tableStyle() {
-        return startTag("style") + TABLE_STYLE  +endTag("style");
-    }
-
-    public static String startTable() {
-        return startTag("table id=\"test\"");
-    }
-
-    public static String endTable() {
-        return endTag("table");
-    }
-
-    private static String startTr() {
-        return startTag("tr");
-    }
-
-    private static String endTr() {
-        return endTag("tr");
-    }
-
-    private static String startTd() {
-        return startTag("td");
-    }
-
-    private static String endTd() {
-        return endTag("td");
-    }
-
-    private static String startTag(String tag) {
-        return "<" + tag + ">";
-    }
-
-    private static String endTag(String tag) {
-        return "</" + tag + ">";
     }
 }
--- a/test/lib/jdk/test/lib/security/CertUtils.java	Thu Apr 23 22:49:55 2020 -0700
+++ b/test/lib/jdk/test/lib/security/CertUtils.java	Fri Apr 24 15:28:57 2020 +0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 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
@@ -161,6 +161,39 @@
             "00gfgiJFKZsHuOaAIfes/nSLM1G9rh8ohlQnS88JL3MGvispVyj1nqpX";
 
     /*
+     * This EC-key certificate is singed by the above RSA CA, namely RSA_CERT.
+     *
+     * Version: 3 (0x2)
+     * Serial Number:
+     *     6a:5e:bb:97:3c:f8:0a:0d:ef:0a:ca:72:0b:6d:7f:b5:e0:af:b2:86
+     * Signature Algorithm: sha256WithRSAEncryption
+     * Issuer: CN = localhost
+     * Validity
+     *      Not Before: Apr 14 08:14:04 2020 GMT
+     *      Not After : Apr 12 08:14:04 2030 GMT
+     * Subject: CN = localhost
+     */
+    public static final String ECRSA_CERT =
+            "-----BEGIN CERTIFICATE-----\n" +
+            "MIICLTCCARWgAwIBAgIUal67lzz4Cg3vCspyC21/teCvsoYwDQYJKoZIhvcNAQEL\n" +
+            "BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIwMDQxNDA4MTQwNFoXDTMwMDQx\n" +
+            "MjA4MTQwNFowFDESMBAGA1UEAwwJbG9jYWxob3N0MFkwEwYHKoZIzj0CAQYIKoZI\n" +
+            "zj0DAQcDQgAEZOIGqyJHpWFhyiRbZACdNBYHvXTzWVWMC10RW8vfxiOPAZBlPzqn\n" +
+            "d2X6/bGhSN1EkrMl8YlJTAKvZcGaaKFUHKNCMEAwHQYDVR0OBBYEFCl9FR9xeNjc\n" +
+            "5+Zkg/Rrk7JpTKnFMB8GA1UdIwQYMBaAFG2c8J0rzOu1Agd54OX0xnC9uLqlMA0G\n" +
+            "CSqGSIb3DQEBCwUAA4IBAQCPcwr88n/vjsHPByiF28P2cEZ02JdQH0FQVe+6Xw7t\n" +
+            "Rn62aTAmS3kaHovXXrFpDpwgz+BMtGSNVTeR7zFttAZLyYb6w6rD8tCfZqHqOTC8\n" +
+            "ctCHz7D2QnsH3tdSV1J7A8N3+P8t4cmCs1AED92yLhy9sumXBvZ2ZskpUtcA5nZB\n" +
+            "djTvyJ3F74835w0s2FzWPnTULvBmit2Z94b22QyZLkFhThUpMBlu2LmXosLrdfji\n" +
+            "xVcV68tpQ1nk1o9tE4V7h4/SjYVaDM1fmlaY+eM3XcbK30mVyktty5ScuOMhLpb6\n" +
+            "RFP/QKvmQ/2l4+rj/epV84ImDuEAhkBGOU6vo4X4l1Du\n" +
+            "-----END CERTIFICATE-----";
+    public static final String ECRSA_KEY =
+            "MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgldlJrkmEDVtzh4r9\n" +
+            "NO8Yn/89mZuBhKPasVgpRjKQxRyhRANCAARk4garIkelYWHKJFtkAJ00Fge9dPNZ\n" +
+            "VYwLXRFby9/GI48BkGU/Oqd3Zfr9saFI3USSsyXxiUlMAq9lwZpooVQc";
+
+    /*
      * Version: 3 (0x2)
         Serial Number:
             76:07:da:cb:0f:8a:89:26:72:cb:db:20:ec:df:b2:52:50:01:6a:56