8186057: TLS interoperability testing between different Java versions

An interop test for checking the compatibility among different Java versions.

Reviewed-by: asmotrak
This commit is contained in:
John Jiang 2017-11-28 22:19:34 -08:00
parent 6912165887
commit f8aaf97179
15 changed files with 2144 additions and 0 deletions

View File

@ -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;
}

View File

@ -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 -----");
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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 };
}
}

View File

@ -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);
}
}
}

View File

@ -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.

View File

@ -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();
}
}
}
}

View File

@ -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;
}

View File

@ -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());
}
}

View File

@ -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);
}
}
}
}

View File

@ -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 + ">";
}
}

View File

@ -0,0 +1,2 @@
jdk.certpath.disabledAlgorithms=
jdk.tls.disabledAlgorithms=