1/*
2 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24/*
25 * @test
26 * @bug 8173783
27 * @summary 6u141 IllegalArgumentException: jdk.tls.namedGroups
28 * run main/othervm HelloExtensionsTest
29 * run main/othervm HelloExtensionsTest -Djdk.tls.namedGroups="bug, bug"
30 * run main/othervm HelloExtensionsTest -Djdk.tls.namedGroups="secp521r1"
31 *
32 */
33import javax.crypto.*;
34import javax.net.ssl.*;
35import javax.net.ssl.SSLEngineResult.*;
36import java.io.*;
37import java.nio.*;
38import java.security.*;
39
40public class HelloExtensionsTest {
41
42    private static boolean debug = false;
43    private static boolean proceed = true;
44    private static boolean EcAvailable = isEcAvailable();
45
46    static String pathToStores = "../../../../javax/net/ssl/etc";
47    private static String keyStoreFile = "keystore";
48    private static String trustStoreFile = "truststore";
49    private static String passwd = "passphrase";
50
51    private static String keyFilename =
52            System.getProperty("test.src", "./") + "/" + pathToStores +
53                "/" + keyStoreFile;
54    private static String trustFilename =
55            System.getProperty("test.src", "./") + "/" + pathToStores +
56                "/" + trustStoreFile;
57
58    private static void checkDone(SSLEngine ssle) throws Exception {
59        if (!ssle.isInboundDone()) {
60            throw new Exception("isInboundDone isn't done");
61        }
62        if (!ssle.isOutboundDone()) {
63            throw new Exception("isOutboundDone isn't done");
64        }
65    }
66
67    private static void runTest(SSLEngine ssle) throws Exception {
68
69         /*
70
71         A client hello message captured via wireshark by selecting
72         a TLSv1.2 Client Hello record and clicking through to the
73         TLSv1.2 Record Layer line and then selecting the hex stream
74         via "copy -> bytes -> hex stream".
75
76         For Record purposes, here's the ClientHello :
77
78         *** ClientHello, TLSv1.2
79         RandomCookie:  GMT: 1469560450 bytes = { 108, 140, 12, 202,
80         2, 213, 10, 236, 143, 223, 58, 162, 228, 155, 239, 3, 98,
81         232, 89, 41, 116, 120, 13, 37, 105, 153, 97, 241 }
82         Session ID:  {}
83         Cipher Suites: [TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
84         TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA256,
85         TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
86         TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
87         TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
88         TLS_DHE_DSS_WITH_AES_128_CBC_SHA256,
89         TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
90         TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
91         TLS_RSA_WITH_AES_128_CBC_SHA,
92         TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
93         TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
94         TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
95         TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
96         TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
97         TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
98         TLS_RSA_WITH_AES_128_GCM_SHA256,
99         TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
100         TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
101         TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
102         TLS_DHE_DSS_WITH_AES_128_GCM_SHA256,
103         TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
104         TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
105         SSL_RSA_WITH_3DES_EDE_CBC_SHA,
106         TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
107         TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
108         SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
109         SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
110         TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
111         Compression Methods:  { 0 }
112         Extension elliptic_curves, curve names: {secp256r1,
113         sect163k1, sect163r2, secp192r1, secp224r1, sect233k1, sect233r1,
114         sect283k1, sect283r1, secp384r1, sect409k1, sect409r1, secp521r1,
115         sect571k1, sect571r1, secp160k1, secp160r1, secp160r2, sect163r1,
116         secp192k1, sect193r1, sect193r2, secp224k1, sect239k1, secp256k1}
117         Extension ec_point_formats, formats: [uncompressed]
118         Extension signature_algorithms, signature_algorithms:
119         SHA512withECDSA, SHA512withRSA, SHA384withECDSA, SHA384withRSA,
120         SHA256withECDSA, SHA256withRSA, Unknown (hash:0x3, signature:0x3),
121         Unknown (hash:0x3, signature:0x1), SHA1withECDSA,
122         SHA1withRSA, SHA1withDSA
123         Extension server_name, server_name:
124         [host_name: bugs.openjdk.java.net]
125         */
126
127        String hello = "16030300df010000db03035898b7826c8c0cc" +
128            "a02d50aec8fdf3aa2e49bef0362e8592974780d25699961f" +
129            "100003ac023c027003cc025c02900670040c009c013002fc" +
130            "004c00e00330032c02bc02f009cc02dc031009e00a2c008c" +
131            "012000ac003c00d0016001300ff01000078000a003400320" +
132            "0170001000300130015000600070009000a0018000b000c0" +
133            "019000d000e000f001000110002001200040005001400080" +
134            "016000b00020100000d00180016060306010503050104030" +
135            "401030303010203020102020000001a00180000156275677" +
136            "32e6f70656e6a646b2e6a6176612e6e6574";
137
138        byte[] msg_clihello = hexStringToByteArray(hello);
139        ByteBuffer bf_clihello = ByteBuffer.wrap(msg_clihello);
140
141        SSLSession session = ssle.getSession();
142        int appBufferMax = session.getApplicationBufferSize();
143        int netBufferMax = session.getPacketBufferSize();
144
145        ByteBuffer serverIn = ByteBuffer.allocate(appBufferMax + 50);
146        ByteBuffer serverOut = ByteBuffer.wrap("I'm Server".getBytes());
147        ByteBuffer sTOc = ByteBuffer.allocate(netBufferMax);
148
149        ssle.beginHandshake();
150
151        // unwrap the clientHello message.
152        SSLEngineResult result = ssle.unwrap(bf_clihello, serverIn);
153        System.out.println("server unwrap " + result);
154        runDelegatedTasks(result, ssle);
155
156        if (!proceed) {
157            //expected exception occurred. Don't process anymore
158            return;
159        }
160
161        // one more step, ensure the clientHello message is parsed.
162        SSLEngineResult.HandshakeStatus status = ssle.getHandshakeStatus();
163        if ( status == HandshakeStatus.NEED_UNWRAP) {
164            result = ssle.unwrap(bf_clihello, serverIn);
165            System.out.println("server unwrap " + result);
166            runDelegatedTasks(result, ssle);
167        } else if ( status == HandshakeStatus.NEED_WRAP) {
168            result = ssle.wrap(serverOut, sTOc);
169            System.out.println("server wrap " + result);
170            runDelegatedTasks(result, ssle);
171        } else {
172            throw new Exception("unexpected handshake status " + status);
173        }
174
175        // enough, stop
176    }
177
178    /*
179     * If the result indicates that we have outstanding tasks to do,
180     * go ahead and run them in this thread.
181     */
182    private static void runDelegatedTasks(SSLEngineResult result,
183            SSLEngine engine) throws Exception {
184
185        if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
186            Runnable runnable;
187            try {
188                while ((runnable = engine.getDelegatedTask()) != null) {
189                    log("\trunning delegated task...");
190                    runnable.run();
191                }
192            } catch (ExceptionInInitializerError e) {
193                String v = System.getProperty("jdk.tls.namedGroups");
194                if (!EcAvailable || v == null) {
195                    // we weren't expecting this if no EC providers
196                    throw new RuntimeException("Unexpected Error :" + e);
197                }
198                if (v != null && v.contains("bug")) {
199                    // OK - we were expecting this Error
200                    log("got expected error for bad jdk.tls.namedGroups");
201                    proceed = false;
202                    return;
203                } else {
204                    System.out.println("Unexpected error. " +
205                        "jdk.tls.namedGroups value: " + v);
206                    throw e;
207                }
208            }
209            HandshakeStatus hsStatus = engine.getHandshakeStatus();
210            if (hsStatus == HandshakeStatus.NEED_TASK) {
211                throw new Exception(
212                    "handshake shouldn't need additional tasks");
213            }
214            log("\tnew HandshakeStatus: " + hsStatus);
215        }
216    }
217
218    private static byte[] hexStringToByteArray(String s) {
219        int len = s.length();
220        byte[] data = new byte[len / 2];
221        for (int i = 0; i < len; i += 2) {
222            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
223                + Character.digit(s.charAt(i+1), 16));
224        }
225        return data;
226    }
227
228    private static boolean isEcAvailable() {
229        try {
230            Signature.getInstance("SHA1withECDSA");
231            Signature.getInstance("NONEwithECDSA");
232            KeyAgreement.getInstance("ECDH");
233            KeyFactory.getInstance("EC");
234            KeyPairGenerator.getInstance("EC");
235            AlgorithmParameters.getInstance("EC");
236        } catch (Exception e) {
237            log("EC not available. Received: " + e);
238            return false;
239        }
240        return true;
241    }
242
243    public static void main(String args[]) throws Exception {
244        SSLEngine ssle = createSSLEngine(keyFilename, trustFilename);
245        runTest(ssle);
246        System.out.println("Test Passed.");
247    }
248
249    /*
250     * Create an initialized SSLContext to use for this test.
251     */
252    static private SSLEngine createSSLEngine(String keyFile, String trustFile)
253            throws Exception {
254
255        SSLEngine ssle;
256
257        KeyStore ks = KeyStore.getInstance("JKS");
258        KeyStore ts = KeyStore.getInstance("JKS");
259
260        char[] passphrase = "passphrase".toCharArray();
261
262        ks.load(new FileInputStream(keyFile), passphrase);
263        ts.load(new FileInputStream(trustFile), passphrase);
264
265        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
266        kmf.init(ks, passphrase);
267
268        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
269        tmf.init(ts);
270
271        SSLContext sslCtx = SSLContext.getInstance("TLS");
272
273        sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
274
275        ssle = sslCtx.createSSLEngine();
276        ssle.setUseClientMode(false);
277
278        return ssle;
279    }
280
281
282    private static void log(String str) {
283        if (debug) {
284            System.out.println(str);
285        }
286    }
287}
288