| /* | |
| * Copyright (c) 2017, 2023, 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 | |
| * @bug 8173783 | |
| * @summary 6u141 IllegalArgumentException: jdk.tls.namedGroups | |
| * run main/othervm HelloExtensionsTest | |
| * run main/othervm HelloExtensionsTest -Djdk.tls.namedGroups="bug, bug" | |
| * run main/othervm HelloExtensionsTest -Djdk.tls.namedGroups="secp521r1" | |
| * | |
| */ | |
| import javax.crypto.*; | |
| import javax.net.ssl.*; | |
| import javax.net.ssl.SSLEngineResult.*; | |
| import java.io.*; | |
| import java.nio.*; | |
| import java.security.*; | |
| public class HelloExtensionsTest { | |
| private static boolean debug = false; | |
| private static boolean proceed = true; | |
| private static boolean EcAvailable = isEcAvailable(); | |
| static String pathToStores = "../../../../javax/net/ssl/etc"; | |
| private static String keyStoreFile = "keystore"; | |
| private static String trustStoreFile = "truststore"; | |
| private static String passwd = "passphrase"; | |
| private static String keyFilename = | |
| System.getProperty("test.src", "./") + "/" + pathToStores + | |
| "/" + keyStoreFile; | |
| private static String trustFilename = | |
| System.getProperty("test.src", "./") + "/" + pathToStores + | |
| "/" + trustStoreFile; | |
| private static void checkDone(SSLEngine ssle) throws Exception { | |
| if (!ssle.isInboundDone()) { | |
| throw new Exception("isInboundDone isn't done"); | |
| } | |
| if (!ssle.isOutboundDone()) { | |
| throw new Exception("isOutboundDone isn't done"); | |
| } | |
| } | |
| private static void runTest(SSLEngine ssle) throws Exception { | |
| /* | |
| A client hello message captured via wireshark by selecting | |
| a TLSv1.2 Client Hello record and clicking through to the | |
| TLSv1.2 Record Layer line and then selecting the hex stream | |
| via "copy -> bytes -> hex stream". | |
| For Record purposes, here's the ClientHello : | |
| *** ClientHello, TLSv1.2 | |
| RandomCookie: GMT: 1469560450 bytes = { 108, 140, 12, 202, | |
| 2, 213, 10, 236, 143, 223, 58, 162, 228, 155, 239, 3, 98, | |
| 232, 89, 41, 116, 120, 13, 37, 105, 153, 97, 241 } | |
| Session ID: {} | |
| Cipher Suites: [TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, | |
| TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA256, | |
| TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, | |
| TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, | |
| TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, | |
| TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, | |
| 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, | |
| TLS_DHE_RSA_WITH_AES_128_CBC_SHA, | |
| TLS_DHE_DSS_WITH_AES_128_CBC_SHA, | |
| TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, | |
| TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, | |
| TLS_RSA_WITH_AES_128_GCM_SHA256, | |
| TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, | |
| TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, | |
| TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, | |
| TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, | |
| TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, | |
| TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, | |
| SSL_RSA_WITH_3DES_EDE_CBC_SHA, | |
| TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, | |
| TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, | |
| SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, | |
| SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, | |
| TLS_EMPTY_RENEGOTIATION_INFO_SCSV] | |
| Compression Methods: { 0 } | |
| Extension elliptic_curves, curve names: {secp256r1, | |
| sect163k1, sect163r2, secp192r1, secp224r1, sect233k1, sect233r1, | |
| sect283k1, sect283r1, secp384r1, sect409k1, sect409r1, secp521r1, | |
| sect571k1, sect571r1, secp160k1, secp160r1, secp160r2, sect163r1, | |
| secp192k1, sect193r1, sect193r2, secp224k1, sect239k1, secp256k1} | |
| Extension ec_point_formats, formats: [uncompressed] | |
| Extension signature_algorithms, signature_algorithms: | |
| SHA512withECDSA, SHA512withRSA, SHA384withECDSA, SHA384withRSA, | |
| SHA256withECDSA, SHA256withRSA, Unknown (hash:0x3, signature:0x3), | |
| Unknown (hash:0x3, signature:0x1), SHA1withECDSA, | |
| SHA1withRSA, SHA1withDSA | |
| Extension server_name, server_name: | |
| [host_name: bugs.openjdk.org] | |
| */ | |
| String hello = "16030300df010000db03035898b7826c8c0cc" + | |
| "a02d50aec8fdf3aa2e49bef0362e8592974780d25699961f" + | |
| "100003ac023c027003cc025c02900670040c009c013002fc" + | |
| "004c00e00330032c02bc02f009cc02dc031009e00a2c008c" + | |
| "012000ac003c00d0016001300ff01000078000a003400320" + | |
| "0170001000300130015000600070009000a0018000b000c0" + | |
| "019000d000e000f001000110002001200040005001400080" + | |
| "016000b00020100000d00180016060306010503050104030" + | |
| "401030303010203020102020000001a00180000156275677" + | |
| "32e6f70656e6a646b2e6a6176612e6e6574"; | |
| byte[] msg_clihello = hexStringToByteArray(hello); | |
| ByteBuffer bf_clihello = ByteBuffer.wrap(msg_clihello); | |
| SSLSession session = ssle.getSession(); | |
| int appBufferMax = session.getApplicationBufferSize(); | |
| int netBufferMax = session.getPacketBufferSize(); | |
| ByteBuffer serverIn = ByteBuffer.allocate(appBufferMax + 50); | |
| ByteBuffer serverOut = ByteBuffer.wrap("I'm Server".getBytes()); | |
| ByteBuffer sTOc = ByteBuffer.allocate(netBufferMax); | |
| ssle.beginHandshake(); | |
| // unwrap the clientHello message. | |
| SSLEngineResult result = ssle.unwrap(bf_clihello, serverIn); | |
| System.out.println("server unwrap " + result); | |
| runDelegatedTasks(result, ssle); | |
| if (!proceed) { | |
| //expected exception occurred. Don't process anymore | |
| return; | |
| } | |
| // one more step, ensure the clientHello message is parsed. | |
| SSLEngineResult.HandshakeStatus status = ssle.getHandshakeStatus(); | |
| if ( status == HandshakeStatus.NEED_UNWRAP) { | |
| result = ssle.unwrap(bf_clihello, serverIn); | |
| System.out.println("server unwrap " + result); | |
| runDelegatedTasks(result, ssle); | |
| } else if ( status == HandshakeStatus.NEED_WRAP) { | |
| result = ssle.wrap(serverOut, sTOc); | |
| System.out.println("server wrap " + result); | |
| runDelegatedTasks(result, ssle); | |
| } else { | |
| throw new Exception("unexpected handshake status " + status); | |
| } | |
| // enough, stop | |
| } | |
| /* | |
| * If the result indicates that we have outstanding tasks to do, | |
| * go ahead and run them in this thread. | |
| */ | |
| private static void runDelegatedTasks(SSLEngineResult result, | |
| SSLEngine engine) throws Exception { | |
| if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { | |
| Runnable runnable; | |
| try { | |
| while ((runnable = engine.getDelegatedTask()) != null) { | |
| log("\trunning delegated task..."); | |
| runnable.run(); | |
| } | |
| } catch (ExceptionInInitializerError e) { | |
| String v = System.getProperty("jdk.tls.namedGroups"); | |
| if (!EcAvailable || v == null) { | |
| // we weren't expecting this if no EC providers | |
| throw new RuntimeException("Unexpected Error :" + e); | |
| } | |
| if (v != null && v.contains("bug")) { | |
| // OK - we were expecting this Error | |
| log("got expected error for bad jdk.tls.namedGroups"); | |
| proceed = false; | |
| return; | |
| } else { | |
| System.out.println("Unexpected error. " + | |
| "jdk.tls.namedGroups value: " + v); | |
| throw e; | |
| } | |
| } | |
| HandshakeStatus hsStatus = engine.getHandshakeStatus(); | |
| if (hsStatus == HandshakeStatus.NEED_TASK) { | |
| throw new Exception( | |
| "handshake shouldn't need additional tasks"); | |
| } | |
| log("\tnew HandshakeStatus: " + hsStatus); | |
| } | |
| } | |
| private static byte[] hexStringToByteArray(String s) { | |
| int len = s.length(); | |
| byte[] data = new byte[len / 2]; | |
| for (int i = 0; i < len; i += 2) { | |
| data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) | |
| + Character.digit(s.charAt(i+1), 16)); | |
| } | |
| return data; | |
| } | |
| private static boolean isEcAvailable() { | |
| try { | |
| Signature.getInstance("SHA1withECDSA"); | |
| Signature.getInstance("NONEwithECDSA"); | |
| KeyAgreement.getInstance("ECDH"); | |
| KeyFactory.getInstance("EC"); | |
| KeyPairGenerator.getInstance("EC"); | |
| AlgorithmParameters.getInstance("EC"); | |
| } catch (Exception e) { | |
| log("EC not available. Received: " + e); | |
| return false; | |
| } | |
| return true; | |
| } | |
| public static void main(String args[]) throws Exception { | |
| SSLEngine ssle = createSSLEngine(keyFilename, trustFilename); | |
| runTest(ssle); | |
| System.out.println("Test Passed."); | |
| } | |
| /* | |
| * Create an initialized SSLContext to use for this test. | |
| */ | |
| static private SSLEngine createSSLEngine(String keyFile, String trustFile) | |
| throws Exception { | |
| SSLEngine ssle; | |
| char[] passphrase = "passphrase".toCharArray(); | |
| KeyStore ks = KeyStore.getInstance(new File(keyFile), passphrase); | |
| KeyStore ts = KeyStore.getInstance(new File(trustFile), passphrase); | |
| KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); | |
| kmf.init(ks, passphrase); | |
| TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); | |
| tmf.init(ts); | |
| SSLContext sslCtx = SSLContext.getInstance("TLS"); | |
| sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); | |
| ssle = sslCtx.createSSLEngine(); | |
| ssle.setUseClientMode(false); | |
| return ssle; | |
| } | |
| private static void log(String str) { | |
| if (debug) { | |
| System.out.println(str); | |
| } | |
| } | |
| } |