8186057: TLS interoperability testing between different Java versions
authorjjiang
Tue, 28 Nov 2017 22:19:34 -0800
changeset 47955 0887e20e7173
parent 47954 3148be499e41
child 47956 72a474c85aee
8186057: TLS interoperability testing between different Java versions Summary: An interop test for checking the compatibility among different Java versions. Reviewed-by: asmotrak
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/JdkInfo.java
test/jdk/javax/net/ssl/compatibility/JdkRelease.java
test/jdk/javax/net/ssl/compatibility/JdkUtils.java
test/jdk/javax/net/ssl/compatibility/Parameter.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/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/jdk/javax/net/ssl/compatibility/java.security
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/compatibility/Cert.java	Tue Nov 28 22:19:34 2017 -0800
@@ -0,0 +1,265 @@
+/*
+ * 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.
+ */
+
+/*
+ * 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 req -x509 -newkey rsa:1024 -days 7300 \
+    //     -subj "/CN=RSA_SHA1_1024" -sha1 \
+    //     -keyout key.pem -out cert.pem
+    RSA_SHA1_1024(
+            SignatureAlgorithm.RSA,
+            "-----BEGIN CERTIFICATE-----\n" +
+            "MIIB/jCCAWegAwIBAgIJANPuKkD7/jxkMA0GCSqGSIb3DQEBBQUAMBgxFjAUBgNV\n" +
+            "BAMMDVJTQV9TSEExXzEwMjQwHhcNMTcwOTA3MDIwNTM0WhcNMzcwOTAyMDIwNTM0\n" +
+            "WjAYMRYwFAYDVQQDDA1SU0FfU0hBMV8xMDI0MIGfMA0GCSqGSIb3DQEBAQUAA4GN\n" +
+            "ADCBiQKBgQC3v7UeIxD5bdv4mqwcpah7sNxpI3IxUFzI2ao1g1jVzDPZt9Zawa3K\n" +
+            "H+m9al1Fg2X1dyNeRlbiXavcIZOQwZqNj08zJEwAdICP8iOnXQ2HUv5cpzArOPTu\n" +
+            "GY3flhf39xgiWsSdfb+cP0QsWNagNU8EtebbHndv8W+2K5JEdlpwQQIDAQABo1Aw\n" +
+            "TjAdBgNVHQ4EFgQU32KqdiGyzg39chNt/OwQzGOlUyAwHwYDVR0jBBgwFoAU32Kq\n" +
+            "diGyzg39chNt/OwQzGOlUyAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOB\n" +
+            "gQAWx8y45IIWWhy44cuQs0qcSDQihIvhXB3pvlpCNdfsSrVoaaH8lrOVjTC718ip\n" +
+            "fE1sF8I9niLHUg8WrAzdQRDsKyUhDUhEEJ7w1ffxwf8bcI9+NgWwEix0Dazzkub8\n" +
+            "2IRXuZ3dGwzoI54XtxvKMFH86nJEj4M/XQGrc9bnlhcn4g==\n" +
+            "-----END CERTIFICATE-----",
+            "30820278020100300d06092a864886f70d0101010500048202623082025e0201" +
+            "0002818100b7bfb51e2310f96ddbf89aac1ca5a87bb0dc69237231505cc8d9aa" +
+            "358358d5cc33d9b7d65ac1adca1fe9bd6a5d458365f577235e4656e25dabdc21" +
+            "9390c19a8d8f4f33244c0074808ff223a75d0d8752fe5ca7302b38f4ee198ddf" +
+            "9617f7f718225ac49d7dbf9c3f442c58d6a0354f04b5e6db1e776ff16fb62b92" +
+            "44765a7041020301000102818100b2c5afdf5c5a9d72c73b7eb0c9465b3fcc79" +
+            "0549d946255bc0861555ef2eb503f1c67757f400cfa7019996123020fb906d5b" +
+            "b66b789ffba90b16270cbd1fbfcf285a821dcdc78fd8f17f399eb231ce9724db" +
+            "af60f9dd20f3e57bb4c0f9fdc9069589b82d442dd868d48c031eb782e27f9e70" +
+            "8469f9b3d5b1b23cee5bf1b41781024100dec184ea77c2126c6bc0c01ba727b4" +
+            "642587d63811240932334dc80c7976e0f715f156e52b352a25e5c52542af2b5f" +
+            "68a29a9b68858f313c4375cc78ec03d859024100d32be8375f52cbe904002321" +
+            "6977aee83fa88bf536d4052d2ed578727d7b7e5aeef91fc52b34c1b6638c00f0" +
+            "4c6985fdaaa2d6e72adbcc7d10ed8bafff69da29024100ae8210acd6f13519b7" +
+            "38a3c7862636ce1610daa3c5d9e3526e9acad3eafc54b57d7d3a44029b7dcf7e" +
+            "b7f9beca1842806892929949b8aa2bb9f5b9202a55c0d1024100887dc0c2c9a2" +
+            "429a823374818c2207b3a631d304d443867505e884c9bbc1ae9228146e2c8b18" +
+            "b67ca52b411010d3c3ff89e366f454076dcd08bc01a5e8790ac102402321988a" +
+            "2003e19c878791d402a7c0acdd1b6dd27203ed88f86a0e3a390ee57c0cd277f3" +
+            "ea5df6440dbc8bdb4c8b3c28fc77e6991bc4ed3f4dc0619a5b953e8e"),
+
+    // This certificate is generated by the below command:
+    // openssl req -x509 -newkey rsa:1024 -days 7300 \
+    //     -subj "/CN=www.example.com" -sha1 \
+    //     -keyout key.pem -out cert.pem
+    RSA_EXAMPLE_SHA1_1024(
+            SignatureAlgorithm.RSA,
+            "-----BEGIN CERTIFICATE-----\n" +
+            "MIICAjCCAWugAwIBAgIJAK6TC9eDtZg4MA0GCSqGSIb3DQEBBQUAMBoxGDAWBgNV\n" +
+            "BAMMD3d3dy5leGFtcGxlLmNvbTAeFw0xNzExMDIwNTA5NDRaFw0zNzEwMjgwNTA5\n" +
+            "NDRaMBoxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNvbTCBnzANBgkqhkiG9w0BAQEF\n" +
+            "AAOBjQAwgYkCgYEAtt5kxFTzJuoxJR2UgeXUxCw7TfL3FeK3lCrU3vruBe3XKKvF\n" +
+            "oyCxf/B5ucm22gzMfOvJBWRg6KrNTrXGI1LtlmAYNDM5J0lK2N/neKOm3Qxe0d1W\n" +
+            "AZ1lwgrMNirsWu+r4UPNMq5UohL5nqVU9WwVa12t0GF3er3k32tMTBqSclcCAwEA\n" +
+            "AaNQME4wHQYDVR0OBBYEFNc8tKGfZdFyaY0ZslwGLt1kpRYAMB8GA1UdIwQYMBaA\n" +
+            "FNc8tKGfZdFyaY0ZslwGLt1kpRYAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEF\n" +
+            "BQADgYEAc71ZO83YEw9WvhxDEng9tMYUhJnNZJss6+gfWjZ487aiEGnS+VgKsHWz\n" +
+            "DBLBrYe9Ag5L9f1HtPNheUbnhhBbQ607jOG/wfmpi4VoU3myB5uxOfeAZdXDOB5x\n" +
+            "bv3t7KcEhgmPjB/e123jrBK8qnAYmDlQVlkZScctB3I1OuA2Po4=\n" +
+            "-----END CERTIFICATE-----",
+            "30820277020100300d06092a864886f70d0101010500048202613082025d0201" +
+            "0002818100b6de64c454f326ea31251d9481e5d4c42c3b4df2f715e2b7942ad4" +
+            "defaee05edd728abc5a320b17ff079b9c9b6da0ccc7cebc9056460e8aacd4eb5" +
+            "c62352ed96601834333927494ad8dfe778a3a6dd0c5ed1dd56019d65c20acc36" +
+            "2aec5aefabe143cd32ae54a212f99ea554f56c156b5dadd061777abde4df6b4c" +
+            "4c1a927257020301000102818048af52bc1acbdededd13d4930fa28b9441c47c" +
+            "b222f5c6fc92df07676db3a815a61c9b51de0a03a347b10a609bd6459a0dd926" +
+            "38877261686a5c6bb1ca9e8ea2373870af7685e7d6cebd66faba65af2ef04bd9" +
+            "1244ae56900fcd6ce11207d8c4040176e4ba9fef3d563741a1027b229134cfe1" +
+            "c0a90d9c8eba9ce6349835e769024100e82494b6f777c784ffc29298d033e11d" +
+            "af46f0d464c4dbd950d46bcd697d0f0b49a77699f0111d408e8748f2b461ab8f" +
+            "210071c9c20d8ecee3ae229cb9c3954b024100c9a976f0011fcdc0ca7fb2f679" +
+            "974fa85d420c604ca7ff64fe4667a44f73088eef290d22195474039760e99325" +
+            "3ca45ee444588b150467d14451d3c45dab0ba5024019df39d3ca70c703c39d63" +
+            "c9342b1403c2ed1d1a0ec101df8e6a9e391e7099a4a068d187068261c8381a4b" +
+            "bf00eb81bb49ea4ac439a4592e25a1daa9acea67510241008c4640007497bdd4" +
+            "94473da26b33d06a29ecae9531dd4e2edf1cf42cfc42e53a1fac2b8183a3164c" +
+            "053999600c6fe15a4c682a3b1cb482ceb33a4416fc9ce52d024100e4f08cd10a" +
+            "5c8face0b20db86443d0a42e34dfdde236dae4f042a06dd3aff7ca159f8aa3b7" +
+            "854df41d510148096155204f2bf46c4a96e271747a4126a66ade6c"),
+
+    // This certificate is generated by the below commands:
+    // openssl dsaparam -genkey 1024 -out key.pem
+    // openssl req -x509 -new -key key.pem -days 7300 \
+    //     -subj "/CN=DSA_SHA1_1024" -sha1 -out cert.pem
+    DSA_SHA1_1024(
+            SignatureAlgorithm.DSA,
+            "-----BEGIN CERTIFICATE-----\n" +
+            "MIICuzCCAnugAwIBAgIJAMAMLRrhQWQFMAkGByqGSM44BAMwGDEWMBQGA1UEAwwN\n" +
+            "RFNBX1NIQTFfMTAyNDAeFw0xNzExMDIwNjA4MDRaFw0zNzEwMjgwNjA4MDRaMBgx\n" +
+            "FjAUBgNVBAMMDURTQV9TSEExXzEwMjQwggG2MIIBKwYHKoZIzjgEATCCAR4CgYEA\n" +
+            "8CspE1sE84pJ4YxzVHFEDNJvBaIxsbax03pDwNHr/ogP9PVwF9z1jT6hpC5WluHG\n" +
+            "g5n5gqpF2XpBhX2fKm1qqZWRxNvHKo0+zzAhUqMrvRJqcjlL4ijXndHldt67/VKS\n" +
+            "0eTKi9m64c+yJx80YYphCO5b93d2sTM29z8QZOlrbD8CFQCmttKnPAOk4uz8Z8cV\n" +
+            "uPGeGOMB9wKBgCItgPpAjW0srIwCaDysDNpydX6hB+1NTy1gFYl24n8edLGbR0mZ\n" +
+            "isteBd6LjMtgicRmtKZzKxW7igxoVvR3WHpTucFjms5NRNjPaj5wt3DxoXn4hyWk\n" +
+            "LzMvDeBvi+jKJiO0jnQ3+1NDOlAQy6ukeH59/gxZ3UmcNxDlAQ/IYHcpA4GEAAKB\n" +
+            "gEgvi72gL+zax7Y2hg4PL1PqZx2jFp0XlTIugiTrcsGytrAnn+/s2+3xVyVyvVMn\n" +
+            "0z5yL5eP9cdGA7qV1+7n6KJ8jNAhLCBSiC6x5ekd88aTlqnmt5lstk4w0Q0zSa58\n" +
+            "Hp6dCFg2Irk6Z9ERKaXJJBBS6reaFeATVROhN/LEEzzvo1AwTjAdBgNVHQ4EFgQU\n" +
+            "jb+HHABclGNR4lpf19nHFZpfwPQwHwYDVR0jBBgwFoAUjb+HHABclGNR4lpf19nH\n" +
+            "FZpfwPQwDAYDVR0TBAUwAwEB/zAJBgcqhkjOOAQDAy8AMCwCFDB3F/m6jsZdHaoy\n" +
+            "1xTp2U8uHBO+AhQYzeJuJd8/qRSDVLs8mesE8TQg2g==\n" +
+            "-----END CERTIFICATE-----",
+            "3082014a0201003082012b06072a8648ce3804013082011e02818100f02b2913" +
+            "5b04f38a49e18c735471440cd26f05a231b1b6b1d37a43c0d1ebfe880ff4f570" +
+            "17dcf58d3ea1a42e5696e1c68399f982aa45d97a41857d9f2a6d6aa99591c4db" +
+            "c72a8d3ecf302152a32bbd126a72394be228d79dd1e576debbfd5292d1e4ca8b" +
+            "d9bae1cfb2271f34618a6108ee5bf77776b13336f73f1064e96b6c3f021500a6" +
+            "b6d2a73c03a4e2ecfc67c715b8f19e18e301f7028180222d80fa408d6d2cac8c" +
+            "02683cac0cda72757ea107ed4d4f2d60158976e27f1e74b19b4749998acb5e05" +
+            "de8b8ccb6089c466b4a6732b15bb8a0c6856f477587a53b9c1639ace4d44d8cf" +
+            "6a3e70b770f1a179f88725a42f332f0de06f8be8ca2623b48e7437fb53433a50" +
+            "10cbaba4787e7dfe0c59dd499c3710e5010fc8607729041602146ef9db36045f" +
+            "bcd8c7fd82ba29c5c5057ed11c7f"),
+
+    // This certificate is generated by the below commands:
+    // openssl dsaparam -genkey 1024 -out key.pem
+    // openssl req -x509 -new -key key.pem -days 7300 \
+    //     -subj "/CN=www.example.com" -sha1 -out cert.pem
+    DSA_EXAMPLE_SHA1_1024(
+            SignatureAlgorithm.DSA,
+            "-----BEGIN CERTIFICATE-----\n" +
+            "MIICwDCCAoCgAwIBAgIJAI5mKbdK5ZqyMAkGByqGSM44BAMwGjEYMBYGA1UEAwwP\n" +
+            "d3d3LmV4YW1wbGUuY29tMB4XDTE3MTEwMjA1NDczOVoXDTM3MTAyODA1NDczOVow\n" +
+            "GjEYMBYGA1UEAwwPd3d3LmV4YW1wbGUuY29tMIIBtzCCASwGByqGSM44BAEwggEf\n" +
+            "AoGBANVGWRSlxVZQKlVrTDcU/6Mr8QFlR3kGKmkvdbTHH1EhcP7YlZ7CJ30VBDbN\n" +
+            "LS2HvN3HHNooJ7hHBheL5Yz8EZIUa95TzPukZ1TmCo9fufR5i9HWj9Z8jLhyqx3l\n" +
+            "iUZOYN9H0MSn4ftK6dr5oTz2ZGYDblXDCq6R8qZfuw1URFqrAhUArx0nmGEI/1S/\n" +
+            "qyxnV4I6ItOntxMCgYEAxZKIZ/7aOGfzaQG2wRFdD/viHBZkkcxCsgmPUroQVUIw\n" +
+            "dqmUnfYk8cb02LCevhhSwcjfocQsA3y1jufIUdWaHuIB9W3EsFJQNd/Byh9j/pRD\n" +
+            "7zH/8lnBzJh2S7y10Vg840STVo5+ekZb4E+W7KK5gUaEQ6kAtUIIB0xjNz7RWs4D\n" +
+            "gYQAAoGAPVQKWqJSlMrbU4XEsx50Ur8P84CwMnS7WcQNLnih1ScaK2BijgVj5Fny\n" +
+            "9JZxITwj7XD7FWriq3kTjbydi3iAvrgVWij79x5Z7fTRCuoBVmtnAFkVGalwbGr2\n" +
+            "ghz70y6hep2Evb1pRCrHjRkMaJFE5Y2CA7VbpKoat+j47/LkXJ2jUDBOMB0GA1Ud\n" +
+            "DgQWBBSVjWy3SpaDfnFo+37mZJqX2aybzTAfBgNVHSMEGDAWgBSVjWy3SpaDfnFo\n" +
+            "+37mZJqX2aybzTAMBgNVHRMEBTADAQH/MAkGByqGSM44BAMDLwAwLAIUd5NOlcfX\n" +
+            "5rakT9H8UzlFcFQLr0MCFGrEYvlFUf/HJOH4FwXS2jEholBB\n" +
+            "-----END CERTIFICATE-----",
+            "3082014c0201003082012c06072a8648ce3804013082011f02818100d5465914" +
+            "a5c556502a556b4c3714ffa32bf101654779062a692f75b4c71f512170fed895" +
+            "9ec2277d150436cd2d2d87bcddc71cda2827b84706178be58cfc1192146bde53" +
+            "ccfba46754e60a8f5fb9f4798bd1d68fd67c8cb872ab1de589464e60df47d0c4" +
+            "a7e1fb4ae9daf9a13cf66466036e55c30aae91f2a65fbb0d54445aab021500af" +
+            "1d27986108ff54bfab2c6757823a22d3a7b71302818100c5928867feda3867f3" +
+            "6901b6c1115d0ffbe21c166491cc42b2098f52ba1055423076a9949df624f1c6" +
+            "f4d8b09ebe1852c1c8dfa1c42c037cb58ee7c851d59a1ee201f56dc4b0525035" +
+            "dfc1ca1f63fe9443ef31fff259c1cc98764bbcb5d1583ce34493568e7e7a465b" +
+            "e04f96eca2b981468443a900b54208074c63373ed15ace0417021500abf47692" +
+            "88c6ac41e2802e7eb7addba367339318"),
+
+    // This certificate is generated by the below commands:
+    // openssl ecparam -name prime256v1 -genkey -out key.pem
+    // openssl req -new -key key.pem -x509 -nodes -days 7300 \
+    //     -subj "/CN=ECDSA_SHA1_prime256v1" -sha1 -out cert.pem
+    ECDSA_SHA1_PRIME256V1(
+            SignatureAlgorithm.ECDSA,
+            "-----BEGIN CERTIFICATE-----\n" +
+            "MIIBhDCCASygAwIBAgIJAKW4wuujp9JbMAkGByqGSM49BAEwIDEeMBwGA1UEAwwV\n" +
+            "RUNEU0FfU0hBMV9wcmltZTI1NnYxMB4XDTE3MDkwNzAyMTA0MVoXDTM3MDkwMjAy\n" +
+            "MTA0MVowIDEeMBwGA1UEAwwVRUNEU0FfU0hBMV9wcmltZTI1NnYxMFkwEwYHKoZI\n" +
+            "zj0CAQYIKoZIzj0DAQcDQgAEdbE+AMwsFBf73YXRVwsvsx2dMt1xgDxj/4pN+BfY\n" +
+            "LWnO94beeZcrCJ1/N8CHmDOce7KRDR6/9kpi20wFAVXZ3KNQME4wHQYDVR0OBBYE\n" +
+            "FA/hB2ODDNdz1JF08u2uhknhlsVoMB8GA1UdIwQYMBaAFA/hB2ODDNdz1JF08u2u\n" +
+            "hknhlsVoMAwGA1UdEwQFMAMBAf8wCQYHKoZIzj0EAQNHADBEAiBNxv2L2FW+6+w/\n" +
+            "QtDe+YSUNRj3F8QrpLkfGk7rVaOiHQIgVF2pWJ5ytg0pbCuO8Bh+UZ7zfZUD03s8\n" +
+            "ZuIYW7RtMe0=\n" +
+            "-----END CERTIFICATE-----",
+            "308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02" +
+            "010104204d901d5efd0e3def78d5307788a4c760115effce4b9e2c31ae5860b6" +
+            "c11915aca1440342000475b13e00cc2c1417fbdd85d1570b2fb31d9d32dd7180" +
+            "3c63ff8a4df817d82d69cef786de79972b089d7f37c08798339c7bb2910d1ebf" +
+            "f64a62db4c050155d9dc"),
+
+    // This certificate is generated by the below commands:
+    // openssl ecparam -name prime256v1 -genkey -out key.pem
+    // openssl req -new -key key.pem -x509 -nodes -days 7300 \
+    //     -subj "/CN=www.example.com" -sha1 -out cert.pem
+    ECDSA_EXAMPLE_SHA1_PRIME256V1(
+            SignatureAlgorithm.ECDSA,
+            "-----BEGIN CERTIFICATE-----\n" +
+            "MIIBeDCCASCgAwIBAgIJAMxOXBpiJ5mDMAkGByqGSM49BAEwGjEYMBYGA1UEAwwP\n" +
+            "d3d3LmV4YW1wbGUuY29tMB4XDTE3MTEwMjA1MTg0MVoXDTM3MTAyODA1MTg0MVow\n" +
+            "GjEYMBYGA1UEAwwPd3d3LmV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0D\n" +
+            "AQcDQgAER9IyuwyrJ7X9DmIqGC3YNTlWBt4Fo/Y3RnlcxhTVxb/ZAYVNhqe4MbSM\n" +
+            "2nsVnYMjjXXDav1plNKvmgGDf9s/saNQME4wHQYDVR0OBBYEFHNUTaIIEA89uNKH\n" +
+            "OOUgJ981Qj5HMB8GA1UdIwQYMBaAFHNUTaIIEA89uNKHOOUgJ981Qj5HMAwGA1Ud\n" +
+            "EwQFMAMBAf8wCQYHKoZIzj0EAQNHADBEAiBCW59S1nE15j8euO6/q9bM6J9Ci5xJ\n" +
+            "WWAVznGGxnS/HgIgFaFKC31uxTXoBN7QN0yW/umQgJ0nsjwj7Pnxc0wNyw8=\n" +
+            "-----END CERTIFICATE-----",
+            "308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02" +
+            "010104209aa3784cd0c1fe0553e59b3c7b8f08c8fdaffd94f34e2c1683243a79" +
+            "7b64b673a1440342000447d232bb0cab27b5fd0e622a182dd835395606de05a3" +
+            "f63746795cc614d5c5bfd901854d86a7b831b48cda7b159d83238d75c36afd69" +
+            "94d2af9a01837fdb3fb1");
+
+    public final SignatureAlgorithm signatureAlgorithm;
+    public final String certMaterials;
+    public final String privKeyMaterials;
+
+    private Cert(
+            SignatureAlgorithm signatureAlgorithm,
+            String certMaterials,
+            String privKeyMaterials) {
+        this.signatureAlgorithm = signatureAlgorithm;
+        this.certMaterials = certMaterials;
+        this.privKeyMaterials = privKeyMaterials;
+    }
+
+    // Two certificates (mainCert and exampleCert) are selected to respect the
+    // specified cipher suite. SNI-associated cases specify exampleCert as desired.
+    public static Cert[] getCerts(String cipherSuite) {
+        Cert mainCert = Cert.DSA_SHA1_1024;
+        Cert exampleCert = Cert.DSA_EXAMPLE_SHA1_1024;
+        if (cipherSuite.contains("_ECDHE_RSA_")) {
+            mainCert = Cert.RSA_SHA1_1024;
+            exampleCert = Cert.RSA_EXAMPLE_SHA1_1024;
+        } else if (cipherSuite.contains("_EC")) {
+            mainCert = Cert.ECDSA_SHA1_PRIME256V1;
+            exampleCert = Cert.ECDSA_EXAMPLE_SHA1_PRIME256V1;
+        } else if (cipherSuite.contains("_RSA")) {
+            mainCert = Cert.RSA_SHA1_1024;
+            exampleCert = Cert.RSA_EXAMPLE_SHA1_1024;
+        }
+        System.out.printf("mainCert=%s, exampleCert=%s%n",
+                mainCert, exampleCert);
+        return new Cert[] { mainCert, exampleCert };
+    }
+}
+
+enum SignatureAlgorithm {
+
+    RSA, DSA, ECDSA;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/compatibility/Client.java	Tue Nov 28 22:19:34 2017 -0800
@@ -0,0 +1,206 @@
+/*
+ * 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.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
+                = Utils.getBoolProperty(Utils.PROP_SUPPORTS_SNI_ON_SERVER);
+        boolean supportsSNIOnClient
+                = Utils.getBoolProperty(Utils.PROP_SUPPORTS_SNI_ON_CLIENT);
+        boolean supportsALPNOnServer
+                = Utils.getBoolProperty(Utils.PROP_SUPPORTS_ALPN_ON_SERVER);
+        boolean supportsALPNOnClient
+                = Utils.getBoolProperty(Utils.PROP_SUPPORTS_ALPN_ON_CLIENT);
+        boolean negativeCase
+                = Utils.getBoolProperty(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));
+            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 -----");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/compatibility/Compatibility.java	Tue Nov 28 22:19:34 2017 -0800
@@ -0,0 +1,338 @@
+/*
+ * 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
+ * @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
+ * @compile -source 1.6 -target 1.6 JdkUtils.java Parameter.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 jdk.test.lib.process.OutputAnalyzer;
+
+public class Compatibility {
+
+    public static void main(String[] args) throws Throwable {
+        String javaSecurityFile
+                = System.getProperty("test.src") + "/java.security";
+        boolean debug = Utils.getBoolProperty("debug");
+
+        Set<JdkInfo> jdkInfos = jdkInfoList();
+
+        System.out.println("Test start");
+
+        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());
+
+            for (UseCase useCase : UseCase.getAllUseCases()) {
+                for (JdkInfo serverJdk : jdkInfos) {
+                    if (useCase.ignoredByJdk(serverJdk)) {
+                        continue;
+                    }
+
+                    Map<String, String> props = new LinkedHashMap<>();
+                    if (debug) {
+                        props.put("javax.net.debug", "ssl");
+                    }
+                    props.put("java.security.properties", javaSecurityFile);
+
+                    props.put(Utils.PROP_PROTOCOL, useCase.protocol.version);
+                    props.put(Utils.PROP_CIPHER_SUITE, useCase.cipherSuite.name());
+                    props.put(Utils.PROP_CLIENT_AUTH, useCase.clientAuth.name());
+                    if (useCase.appProtocol != 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 + "");
+
+                    for (JdkInfo clientJdk : jdkInfos) {
+                        if (useCase.ignoredByJdk(clientJdk)) {
+                            continue;
+                        }
+
+                        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_SUPPORTS_SNI_ON_CLIENT,
+                                clientJdk.supportsSNI + "");
+                        props.put(Utils.PROP_SUPPORTS_ALPN_ON_CLIENT,
+                                clientJdk.supportsALPN + "");
+                        if (useCase.serverName != 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));
+                        testCases.add(testCase);
+                        System.out.printf(
+                                "ServerStatus=%s, ClientStatus=%s, CaseStatus=%s%n",
+                                serverStatus, clientStatus, testCase.getStatus());
+
+                        // Confirm the server has stopped.
+                        if(new File(Utils.PORT_LOG).exists()) {
+                            throw new RuntimeException("Server doesn't stop.");
+                        }
+                        System.out.println("----- Case end -----");
+                    }
+                }
+            }
+
+            System.out.println(Utils.endPre());
+            System.out.println(Utils.endHtml());
+        }
+        System.setOut(origStdOut);
+        System.setErr(origStdErr);
+        executor.shutdown();
+
+        System.out.println("Test end");
+        System.out.println("Report is being generated...");
+        boolean failed = generateReport(testCases);
+        System.out.println("Report is generated.");
+        if (failed) {
+            throw new RuntimeException("At least one case failed. "
+                    + "Please check logs for more details.");
+        }
+    }
+
+    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) {
+        if (clientStatus == null || clientStatus == Status.TIMEOUT) {
+            return serverStatus == Status.EXPECTED_FAIL
+                   ? Status.EXPECTED_FAIL
+                   : Status.FAIL;
+        } else if (serverStatus == Status.TIMEOUT) {
+            return clientStatus == Status.EXPECTED_FAIL
+                   ? Status.EXPECTED_FAIL
+                   : Status.FAIL;
+        } else {
+            return serverStatus == clientStatus
+                   ? serverStatus
+                   : Status.FAIL;
+        }
+    }
+
+    // Retrieves JDK info from the file which is specified by jdkListFile.
+    // If no such file or no JDK is specified by the file, the current testing
+    // JDK will be used.
+    private static Set<JdkInfo> jdkInfoList() throws Throwable {
+        List<String> jdkList = jdkList("jdkListFile");
+        if (jdkList.size() == 0) {
+            jdkList.add(System.getProperty("test.jdk"));
+        }
+
+        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 listFileProp) throws IOException {
+        String listFile = System.getProperty(listFileProp);
+        System.out.println(listFileProp + "=" + listFile);
+        if (listFile != null && new File(listFile).exists()) {
+            return Files.lines(Paths.get(listFile))
+                        .filter(line -> { return !line.trim().isEmpty(); })
+                        .collect(Collectors.toList());
+        } 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 (!new File(Utils.PORT_LOG).exists()) {
+            return -1;
+        }
+
+        return Integer.valueOf(
+                Files.lines(Paths.get(Utils.PORT_LOG)).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);
+    }
+
+    // Generates the test result report.
+    private static 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.",
+                "ServerJDK",
+                "ClientJDK",
+                "Protocol",
+                "CipherSuite",
+                "ClientAuth",
+                "SNI",
+                "ALPN",
+                "Status"));
+        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.serverJdk.version,
+                    testCase.clientJdk.version,
+                    testCase.useCase.protocol.version,
+                    testCase.useCase.cipherSuite,
+                    Utils.boolToStr(
+                            testCase.useCase.clientAuth == ClientAuth.TRUE),
+                    Utils.boolToStr(
+                            testCase.useCase.serverName == ServerName.EXAMPLE),
+                    Utils.boolToStr(
+                            testCase.useCase.appProtocol == AppProtocol.EXAMPLE),
+                    testCase.getStatus()));
+            failed = failed
+                    || testCase.getStatus() == Status.FAIL
+                    || testCase.getStatus() == Status.UNEXPECTED_SUCCESS;
+        }
+        report.append(Utils.endTable());
+        report.append(Utils.endHtml());
+
+        generateFile("report.html", report.toString());
+        return failed;
+    }
+
+    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/JdkInfo.java	Tue Nov 28 22:19:34 2017 -0800
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+/*
+ * It represents a JDK with some specific attributes.
+ * If two JdkInfo instances have the same version value, the instances are
+ * regarded as equivalent.
+ */
+public class JdkInfo {
+
+    public final String jdkPath;
+
+    public final String version;
+    public final boolean supportsECKey;
+    public final boolean supportsSNI;
+    public final boolean supportsALPN;
+
+    public JdkInfo(String jdkPath) throws Throwable {
+        this.jdkPath = jdkPath;
+
+        String output = jdkAttributes(jdkPath);
+        if (output == null || output.trim().isEmpty()) {
+            throw new RuntimeException(
+                    "Cannot determine the JDK attributes: " + jdkPath);
+        }
+
+        String[] attributes = Utils.split(output, Utils.PARAM_DELIMITER);
+        version = attributes[0].replaceAll(".*=", "");
+        supportsECKey = Boolean.valueOf(attributes[1].replaceAll(".*=", ""));
+        supportsSNI = Boolean.valueOf(attributes[2].replaceAll(".*=", ""));
+        supportsALPN = Boolean.valueOf(attributes[3].replaceAll(".*=", ""));
+    }
+
+    // Determines the specific attributes for the specified JDK.
+    private static String jdkAttributes(String jdkPath) throws Throwable {
+        return ProcessUtils.java(jdkPath, null, JdkUtils.class).getOutput();
+    }
+
+    @Override
+    public int hashCode() {
+        return version == null ? 0 : version.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        JdkInfo other = (JdkInfo) obj;
+        if (version == null) {
+            if (other.version != null) {
+                return false;
+            }
+        } else if (!version.equals(other.version)) {
+            return false;
+        }
+        return true;
+    }
+
+    public boolean supportsCipherSuite(CipherSuite cipherSuite) {
+        JdkRelease jdkRelease = JdkRelease.getRelease(version);
+        return cipherSuite.startJdk.sequence <= jdkRelease.sequence
+                && (cipherSuite.endJdk == null
+                        || cipherSuite.endJdk.sequence >= jdkRelease.sequence);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/compatibility/JdkRelease.java	Tue Nov 28 22:19:34 2017 -0800
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+/*
+ * JDK major versions.
+ */
+public enum JdkRelease {
+
+    JDK6(6, "1.6"),
+    JDK7(7, "1.7"),
+    JDK8(8, "1.8"),
+    JDK9(9, "9"),
+    JDK10(10, "10");
+
+    public final int sequence;
+    public final String release;
+
+    private JdkRelease(int sequence, String release) {
+        this.sequence = sequence;
+        this.release = release;
+    }
+
+    public static JdkRelease getRelease(String jdkVersion) {
+        if (jdkVersion.startsWith(JDK6.release)) {
+            return JDK6;
+        } else if (jdkVersion.startsWith(JDK7.release)) {
+            return JDK7;
+        } else if (jdkVersion.startsWith(JDK8.release)) {
+            return JDK8;
+        } else if (jdkVersion.startsWith(JDK9.release)) {
+            return JDK9;
+        } else if (jdkVersion.startsWith(JDK10.release)) {
+            return JDK10;
+        }
+
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/compatibility/JdkUtils.java	Tue Nov 28 22:19:34 2017 -0800
@@ -0,0 +1,88 @@
+/*
+ * 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.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+
+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 SUPPORTS_EC_KEY = "supportsECKey";
+    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");
+    }
+
+    // Checks if EC key algorithm is supported by the JDK build.
+    private static boolean supportsECKey() {
+        boolean isSupported = true;
+        try {
+            KeyFactory.getInstance("EC");
+        } catch (NoSuchAlgorithmException e) {
+            isSupported = false;
+        }
+        return isSupported;
+    }
+
+    // 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) {
+        System.out.print(Utils.join(Utils.PARAM_DELIMITER,
+                attr(JAVA_RUNTIME_VERSION, javaRuntimeVersion()),
+                attr(SUPPORTS_EC_KEY, supportsECKey()),
+                attr(SUPPORTS_SNI, supportsSNI()),
+                attr(SUPPORTS_ALPN, supportsALPN())));
+    }
+
+    private static String attr(String name, Object value) {
+        return name + "=" + String.valueOf(value);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/compatibility/Parameter.java	Tue Nov 28 22:19:34 2017 -0800
@@ -0,0 +1,252 @@
+/*
+ * 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.
+ */
+
+/*
+ * A tagging interface that all TLS communication parameters must implement.
+ */
+public interface Parameter { }
+
+/* The followings are TLS communication parameters. */
+
+enum Protocol implements Parameter {
+
+    SSLV3_0(3, "SSLv3"),
+    TLSV1_0(4, "TLSv1"),
+    TLSV1_1(5, "TLSv1.1"),
+    TLSV1_2(6, "TLSv1.2");
+
+    public final int sequence;
+    public final String version;
+
+    private Protocol(int sequence, String version) {
+        this.sequence = sequence;
+        this.version = version;
+    }
+
+    static Protocol getProtocol(String version) {
+        for (Protocol protocol : values()) {
+            if (protocol.version.equals(version)) {
+                return protocol;
+            }
+        }
+
+        return null;
+    }
+
+    static Protocol[] getMandatoryValues() {
+        return new Protocol[] { TLSV1_0, TLSV1_1, TLSV1_2 };
+    }
+}
+
+enum CipherSuite implements Parameter {
+
+    TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384(
+            Protocol.TLSV1_2, JdkRelease.JDK7),
+    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384(
+            Protocol.TLSV1_2, JdkRelease.JDK7),
+    TLS_RSA_WITH_AES_256_CBC_SHA256(
+            Protocol.TLSV1_2, JdkRelease.JDK7),
+    TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384(
+            Protocol.TLSV1_2, JdkRelease.JDK7),
+    TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384(
+            Protocol.TLSV1_2, JdkRelease.JDK7),
+    TLS_DHE_RSA_WITH_AES_256_CBC_SHA256(
+            Protocol.TLSV1_2, JdkRelease.JDK7),
+    TLS_DHE_DSS_WITH_AES_256_CBC_SHA256(
+            Protocol.TLSV1_2, JdkRelease.JDK7),
+    TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA(),
+    TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA(),
+    TLS_RSA_WITH_AES_256_CBC_SHA(),
+    TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA(),
+    TLS_ECDH_RSA_WITH_AES_256_CBC_SHA(),
+    TLS_DHE_RSA_WITH_AES_256_CBC_SHA(),
+    TLS_DHE_DSS_WITH_AES_256_CBC_SHA(),
+    TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256(
+            Protocol.TLSV1_2, JdkRelease.JDK7),
+    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256(
+            Protocol.TLSV1_2, JdkRelease.JDK7),
+    TLS_RSA_WITH_AES_128_CBC_SHA256(
+            Protocol.TLSV1_2, JdkRelease.JDK7),
+    TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256(
+            Protocol.TLSV1_2, JdkRelease.JDK7),
+    TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256(
+            Protocol.TLSV1_2, JdkRelease.JDK7),
+    TLS_DHE_RSA_WITH_AES_128_CBC_SHA256(
+            Protocol.TLSV1_2, JdkRelease.JDK7),
+    TLS_DHE_DSS_WITH_AES_128_CBC_SHA256(
+            Protocol.TLSV1_2, JdkRelease.JDK7),
+    TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA(),
+    TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA(),
+    TLS_RSA_WITH_AES_128_CBC_SHA(),
+    TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA(),
+    TLS_ECDH_RSA_WITH_AES_128_CBC_SHA(
+            Protocol.SSLV3_0, JdkRelease.JDK7),
+    TLS_DHE_RSA_WITH_AES_128_CBC_SHA(),
+    TLS_DHE_DSS_WITH_AES_128_CBC_SHA(),
+    TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384(
+            Protocol.TLSV1_2, JdkRelease.JDK8),
+    TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256(
+            Protocol.TLSV1_2, JdkRelease.JDK8),
+    TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384(
+            Protocol.TLSV1_2, JdkRelease.JDK8),
+    TLS_RSA_WITH_AES_256_GCM_SHA384(
+            Protocol.TLSV1_2, JdkRelease.JDK8),
+    TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384(
+            Protocol.TLSV1_2, JdkRelease.JDK8),
+    TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384(
+            Protocol.TLSV1_2, JdkRelease.JDK8),
+    TLS_DHE_RSA_WITH_AES_256_GCM_SHA384(
+            Protocol.TLSV1_2, JdkRelease.JDK8),
+    TLS_DHE_DSS_WITH_AES_256_GCM_SHA384(
+            Protocol.TLSV1_2, JdkRelease.JDK8),
+    TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256(
+            Protocol.TLSV1_2, JdkRelease.JDK8),
+    TLS_RSA_WITH_AES_128_GCM_SHA256(
+            Protocol.TLSV1_2, JdkRelease.JDK8),
+    TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256(
+            Protocol.TLSV1_2, JdkRelease.JDK8),
+    TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256(
+            Protocol.TLSV1_2, JdkRelease.JDK8),
+    TLS_DHE_RSA_WITH_AES_128_GCM_SHA256(
+            Protocol.TLSV1_2, JdkRelease.JDK8),
+    TLS_DHE_DSS_WITH_AES_128_GCM_SHA256(
+            Protocol.TLSV1_2, JdkRelease.JDK8),
+    TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA(),
+    TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA(),
+    TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA(),
+    TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA(),
+    TLS_ECDHE_ECDSA_WITH_RC4_128_SHA(),
+    TLS_ECDHE_RSA_WITH_RC4_128_SHA(),
+    TLS_ECDH_ECDSA_WITH_RC4_128_SHA(),
+    TLS_ECDH_RSA_WITH_RC4_128_SHA(),
+    SSL_RSA_WITH_RC4_128_SHA(),
+    SSL_RSA_WITH_3DES_EDE_CBC_SHA(),
+    SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA(
+            Protocol.SSLV3_0, JdkRelease.JDK6),
+    SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA(
+            Protocol.SSLV3_0, JdkRelease.JDK6),
+    SSL_RSA_WITH_RC4_128_MD5(
+            Protocol.SSLV3_0, JdkRelease.JDK6);
+
+    private static final boolean FULL_CIPHER_SUITES
+            = Utils.getBoolProperty("fullCipherSuites");
+
+    final Protocol startProtocol;
+    final Protocol endProtocol;
+
+    final JdkRelease startJdk;
+    final JdkRelease endJdk;
+
+    private CipherSuite(
+            Protocol startProtocol, Protocol endProtocol,
+            JdkRelease startJdk, JdkRelease endJdk) {
+        this.startProtocol = startProtocol;
+        this.endProtocol = endProtocol;
+
+        this.startJdk = startJdk;
+        this.endJdk = endJdk;
+    }
+
+    private CipherSuite(Protocol startProtocol, JdkRelease startJdk) {
+        this(startProtocol, null, startJdk, null);
+    }
+
+    private CipherSuite() {
+        this(Protocol.TLSV1_0, null, JdkRelease.JDK6, null);
+    }
+
+    boolean supportedByProtocol(Protocol protocol) {
+        return startProtocol.sequence <= protocol.sequence
+                && (endProtocol == null || endProtocol.sequence >= protocol.sequence);
+    }
+
+    static CipherSuite[] getMandatoryValues() {
+        return FULL_CIPHER_SUITES
+               ? values()
+               : new CipherSuite[] {
+                       TLS_RSA_WITH_AES_128_CBC_SHA,
+                       TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
+                       TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+                       TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+                       TLS_RSA_WITH_AES_256_CBC_SHA256,
+                       TLS_DHE_DSS_WITH_AES_256_CBC_SHA256,
+                       TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
+                       TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 };
+    }
+
+    static CipherSuite getCipherSuite(String name) {
+        for (CipherSuite cipherSuite : values()) {
+            if (cipherSuite.name().equals(name)) {
+                return cipherSuite;
+            }
+        }
+
+        return null;
+    }
+}
+
+enum ClientAuth implements Parameter {
+
+    FALSE,
+    TRUE;
+
+    static ClientAuth[] getMandatoryValues() {
+        return new ClientAuth[] { TRUE };
+    }
+}
+
+enum ServerName implements Parameter {
+
+    NONE(null),
+    EXAMPLE("www.example.com");
+
+    final String name;
+
+    private ServerName(String name) {
+        this.name = name;
+    }
+
+    static ServerName[] getMandatoryValues() {
+        return new ServerName[] { EXAMPLE };
+    }
+}
+
+enum AppProtocol implements Parameter {
+
+    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;
+    }
+
+    static AppProtocol[] getMandatoryValues() {
+        return new AppProtocol[] { EXAMPLE };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/compatibility/ProcessUtils.java	Tue Nov 28 22:19:34 2017 -0800
@@ -0,0 +1,59 @@
+/*
+ * 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);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/compatibility/README	Tue Nov 28 22:19:34 2017 -0800
@@ -0,0 +1,130 @@
+# 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.
+
+##### 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 6. Some of Java
+source files, JdkUtils.java, Parameter.java, Server.java, and Client.java, use
+only JDK 6-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.
+
+##### Usage #####
+jtreg [-options] \
+    [-Ddebug=<true|false>] \
+    [-DfullCases=<true|false>] \
+    [-DfullCipherSuites=<true|false>] \
+    [-DjdkListFile=</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
+    It indicates if the test enable -Djavax.net.ssl=debug. 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
+    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/jdk6
+/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 \
+    $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 6 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/compatibility/Server.java	Tue Nov 28 22:19:34 2017 -0800
@@ -0,0 +1,171 @@
+/*
+ * 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.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 setEnabledCipherSuites(String... cipherSuites) {
+        serverSocket.setEnabledCipherSuites(cipherSuites);
+    }
+
+    private void setEnabledProtocols(String... protocols) {
+        serverSocket.setEnabledProtocols(protocols);
+    }
+
+    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 protocol = System.getProperty(Utils.PROP_PROTOCOL);
+        String cipherSuite = System.getProperty(Utils.PROP_CIPHER_SUITE);
+        boolean clientAuth
+                = Utils.getBoolProperty(Utils.PROP_CLIENT_AUTH);
+        String appProtocols = System.getProperty(Utils.PROP_APP_PROTOCOLS);
+        boolean supportsALPN
+                = Utils.getBoolProperty(Utils.PROP_SUPPORTS_ALPN_ON_SERVER);
+        boolean negativeCase
+                = Utils.getBoolProperty(Utils.PROP_NEGATIVE_CASE_ON_SERVER);
+
+        System.out.println(Utils.join(Utils.PARAM_DELIMITER,
+                "ServerJDK=" + System.getProperty(Utils.PROP_SERVER_JDK),
+                "Protocol=" + protocol,
+                "CipherSuite=" + cipherSuite,
+                "ClientAuth=" + clientAuth,
+                "AppProtocols=" + appProtocols));
+
+        Status status = Status.SUCCESS;
+        Server server = null;
+        try {
+            server = new Server(Cert.getCerts(cipherSuite));
+            System.out.println("port=" + server.getPort());
+            server.setNeedClientAuth(clientAuth);
+            server.setEnabledProtocols(protocol);
+            server.setEnabledCipherSuites(cipherSuite);
+            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();
+            }
+
+            // Cleanups port.log.
+            File file = new File(Utils.PORT_LOG);
+            if (file.exists()) {
+                file.delete();
+            }
+        }
+
+        System.out.println("STATUS: " + status);
+        System.out.println("----- Server end -----");
+    }
+
+    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/Status.java	Tue Nov 28 22:19:34 2017 -0800
@@ -0,0 +1,30 @@
+/*
+ * 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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/compatibility/TestCase.java	Tue Nov 28 22:19:34 2017 -0800
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+/*
+ * 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 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;
+
+        negativeCaseOnServer = useCase.negativeCase
+                || !serverJdk.supportsCipherSuite(useCase.cipherSuite);
+        negativeCaseOnClient = useCase.negativeCase
+                || !clientJdk.supportsCipherSuite(useCase.cipherSuite);
+    }
+
+    public Status getStatus() {
+        return status;
+    }
+
+    public void setStatus(Status status) {
+        this.status = status;
+    }
+
+    @Override
+    public String toString() {
+        return Utils.join(Utils.PARAM_DELIMITER,
+                "ServerJDK=" + serverJdk.version,
+                "ClientJDK=" + clientJdk.version,
+                useCase.toString());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/compatibility/UseCase.java	Tue Nov 28 22:19:34 2017 -0800
@@ -0,0 +1,107 @@
+/*
+ * 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;
+
+/*
+ * The TLS communication use case.
+ */
+public class UseCase {
+
+    private static final boolean FULL_CASES
+            = Utils.getBoolProperty("fullCases");
+
+    private static final Parameter[][] PARAMS = new Parameter[][] {
+            FULL_CASES ? Protocol.values() : Protocol.getMandatoryValues(),
+            FULL_CASES ? CipherSuite.values() : CipherSuite.getMandatoryValues(),
+            FULL_CASES ? ClientAuth.values() : ClientAuth.getMandatoryValues(),
+            FULL_CASES ? ServerName.values() : ServerName.getMandatoryValues(),
+            FULL_CASES ? AppProtocol.values() : AppProtocol.getMandatoryValues() };
+
+    public final Protocol protocol;
+    public final CipherSuite cipherSuite;
+    public final ClientAuth clientAuth;
+    public final ServerName serverName;
+    public final AppProtocol appProtocol;
+
+    public final boolean negativeCase;
+
+    public UseCase(
+            Protocol protocol,
+            CipherSuite cipherSuite,
+            ClientAuth clientAuth,
+            ServerName serverName,
+            AppProtocol appProtocol) {
+        this.protocol = protocol;
+        this.cipherSuite = cipherSuite;
+        this.clientAuth = clientAuth;
+        this.serverName = serverName;
+        this.appProtocol = appProtocol;
+
+        negativeCase = !cipherSuite.supportedByProtocol(protocol);
+    }
+
+    // JDK 6 doesn't support EC key algorithm.
+    public boolean ignoredByJdk(JdkInfo jdkInfo) {
+        return cipherSuite.name().contains("_EC") && !jdkInfo.supportsECKey;
+    }
+
+    @Override
+    public String toString() {
+        return Utils.join(Utils.PARAM_DELIMITER,
+                "Protocol=" + protocol.version,
+                "CipherSuite=" + cipherSuite,
+                "ClientAuth=" + clientAuth,
+                "ServerName=" + serverName,
+                "AppProtocols=" + appProtocol);
+    }
+
+    public static List<UseCase> getAllUseCases() {
+        List<UseCase> useCases = new ArrayList<>();
+        getUseCases(PARAMS, 0, new Parameter[PARAMS.length], useCases);
+        return useCases;
+    }
+
+    private static void getUseCases(Parameter[][] params, int index,
+            Parameter[] currentValues, List<UseCase> useCases) {
+        if (index == params.length) {
+            Protocol protocol = (Protocol) currentValues[0];
+            CipherSuite cipherSuite = (CipherSuite) currentValues[1];
+
+            UseCase useCase = new UseCase(
+                    protocol,
+                    cipherSuite,
+                    (ClientAuth) currentValues[2],
+                    (ServerName) currentValues[3],
+                    (AppProtocol) currentValues[4]);
+            useCases.add(useCase);
+        } else {
+            Parameter[] values = params[index];
+            for (int i = 0; i < values.length; i++) {
+                currentValues[index] = values[i];
+                getUseCases(params, index + 1, currentValues, useCases);
+            }
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/compatibility/Utils.java	Tue Nov 28 22:19:34 2017 -0800
@@ -0,0 +1,282 @@
+/*
+ * 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.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 javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.TrustManagerFactory;
+
+/*
+ * Utilities for testing.
+ */
+public class Utils {
+
+    /* ***** Properties ***** */
+    public static final String PROP_PORT = "test.port";
+    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 int TIMEOUT = 10000;
+    public static final char[] PASSWORD = "testpass".toCharArray();
+
+    public static final String TEST_LOG = "test.html";
+    public static final String PORT_LOG = "port";
+
+    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]));
+        }
+        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;
+    }
+
+    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 PrivateKey createKey(Cert cert)
+            throws NoSuchAlgorithmException, InvalidKeySpecException {
+        PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(
+                hexToBytes(cert.privKeyMaterials));
+        KeyFactory keyFactory = KeyFactory.getInstance(
+                getKeyAlgorithm(cert.signatureAlgorithm));
+        PrivateKey privKey = keyFactory.generatePrivate(privKeySpec);
+        return privKey;
+    }
+
+    private static String getKeyAlgorithm(
+            SignatureAlgorithm signatureAlgorithm) {
+        String signatureAlogrithmName = signatureAlgorithm.name();
+        return signatureAlogrithmName.equals(SignatureAlgorithm.ECDSA.name())
+               ? "EC"
+               : signatureAlogrithmName;
+    }
+
+    public static byte[] hexToBytes(String hex) {
+        if (hex == null) {
+            return null;
+        }
+
+        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;
+    }
+
+    public static String join(String delimiter, String... values) {
+        StringBuilder result = new StringBuilder();
+        if (values != null && values.length > 0) {
+            for (int i = 0; i < values.length - 1; i++) {
+                result.append(values[i]).append(delimiter);
+            }
+            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 boolean getBoolProperty(String prop) {
+        return Boolean.valueOf(System.getProperty(prop));
+    }
+
+    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 + ">";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/net/ssl/compatibility/java.security	Tue Nov 28 22:19:34 2017 -0800
@@ -0,0 +1,2 @@
+jdk.certpath.disabledAlgorithms=
+jdk.tls.disabledAlgorithms=
\ No newline at end of file