1/*
2 * Copyright (c) 2001, 2011, 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// SunJSSE does not support dynamic system properties, no way to re-use
26// system properties in samevm/agentvm mode.
27//
28
29/*
30 * @test
31 * @bug 4514971
32 * @summary Verify applications do not read handshake data after failure
33 * @run main/othervm ReadHandshake
34 */
35
36import java.io.*;
37import java.net.*;
38import javax.net.ssl.*;
39import java.security.Security;
40
41public class ReadHandshake {
42
43    /*
44     * =============================================================
45     * Set the various variables needed for the tests, then
46     * specify what tests to run on each side.
47     */
48
49    /*
50     * Should we run the client or server in a separate thread?
51     * Both sides can throw exceptions, but do you have a preference
52     * as to which side should be the main thread.
53     */
54    static boolean separateServerThread = true;
55
56    // Note: we use anonymous ciphersuites only, no keys/ trusted certs needed
57
58    private final static String[] CLIENT_SUITES = new String[] {
59        "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA",
60    };
61
62    private final static String[] SERVER_SUITES = new String[] {
63        "SSL_DH_anon_WITH_RC4_128_MD5",
64    };
65
66    /*
67     * Is the server ready to serve?
68     */
69    volatile static boolean serverReady = false;
70
71    /*
72     * Turn on SSL debugging?
73     */
74    static boolean debug = false;
75
76    /*
77     * If the client or server is doing some kind of object creation
78     * that the other side depends on, and that thread prematurely
79     * exits, you may experience a hang.  The test harness will
80     * terminate all hung threads after its timeout has expired,
81     * currently 3 minutes by default, but you might try to be
82     * smart about it....
83     */
84
85    /*
86     * Define the server side of the test.
87     *
88     * If the server prematurely exits, serverReady will be set to true
89     * to avoid infinite hangs.
90     */
91    void doServerSide() throws Exception {
92        SSLSocket sslSocket = null;
93        SSLServerSocket sslServerSocket = null;
94        try {
95            SSLServerSocketFactory sslssf =
96                (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
97            sslServerSocket =
98                (SSLServerSocket) sslssf.createServerSocket(serverPort);
99            serverPort = sslServerSocket.getLocalPort();
100
101            sslServerSocket.setEnabledCipherSuites(SERVER_SUITES);
102
103            /*
104             * Signal Client, we're ready for his connect.
105             */
106            serverReady = true;
107
108            System.out.println("Server waiting for connection");
109
110            sslSocket = (SSLSocket) sslServerSocket.accept();
111            InputStream sslIS = sslSocket.getInputStream();
112            OutputStream sslOS = sslSocket.getOutputStream();
113
114            System.out.println("Server starting handshake...");
115
116
117            try {
118                sslIS.read();
119                throw new Exception("No handshake exception on server side");
120            } catch (IOException e) {
121                System.out.println("Handshake failed on server side, OK");
122            }
123
124            for (int i = 0; i < 3; i++) {
125                try {
126                    int ch;
127                    if ((ch = sslIS.read()) != -1) {
128                        throw new Exception("Read succeeded server side: "
129                            + ch);
130                    }
131                } catch (IOException e) {
132                    System.out.println("Exception for read() on server, OK");
133                }
134            }
135
136        } finally {
137            closeSocket(sslSocket);
138            closeSocket(sslServerSocket);
139        }
140    }
141
142    private static void closeSocket(Socket s) {
143        try {
144            if (s != null) {
145                s.close();
146            }
147        } catch (Exception e) {
148            // ignore
149        }
150    }
151
152    private static void closeSocket(ServerSocket s) {
153        try {
154            if (s != null) {
155                s.close();
156            }
157        } catch (Exception e) {
158            // ignore
159        }
160    }
161
162    /*
163     * Define the client side of the test.
164     *
165     * If the server prematurely exits, serverReady will be set to true
166     * to avoid infinite hangs.
167     */
168    void doClientSide() throws Exception {
169
170        /*
171         * Wait for server to get started.
172         */
173        while (!serverReady) {
174            Thread.sleep(80);
175        }
176
177        SSLSocket sslSocket = null;
178        try {
179
180            SSLSocketFactory sslsf =
181                (SSLSocketFactory) SSLSocketFactory.getDefault();
182            sslSocket = (SSLSocket)
183                sslsf.createSocket("localhost", serverPort);
184            sslSocket.setEnabledCipherSuites(CLIENT_SUITES);
185
186            InputStream sslIS = sslSocket.getInputStream();
187            OutputStream sslOS = sslSocket.getOutputStream();
188
189            System.out.println("Client starting handshake...");
190
191            try {
192                sslIS.read();
193                throw new Exception("No handshake exception on client side");
194            } catch (IOException e) {
195                System.out.println("Handshake failed on client side, OK");
196            }
197
198            for (int i = 0; i < 3; i++) {
199                try {
200                    int ch;
201                    if ((ch = sslIS.read()) != -1) {
202                        throw new Exception("Read succeeded on client side: "
203                            + ch);
204                    }
205                } catch (IOException e) {
206                    System.out.println("Exception for read() on client, OK");
207                }
208            }
209        } finally {
210            sslSocket.close();
211        }
212    }
213
214    /*
215     * =============================================================
216     * The remainder is just support stuff
217     */
218
219    volatile int serverPort = 0;
220
221    volatile Exception serverException = null;
222    volatile Exception clientException = null;
223
224    public static void main(String[] args) throws Exception {
225        // reset security properties to make sure that the algorithms
226        // and keys used in this test are not disabled.
227        Security.setProperty("jdk.tls.disabledAlgorithms", "");
228        Security.setProperty("jdk.certpath.disabledAlgorithms", "");
229
230        if (debug)
231            System.setProperty("javax.net.debug", "all");
232
233        /*
234         * Start the tests.
235         */
236        new ReadHandshake();
237    }
238
239    Thread clientThread = null;
240    Thread serverThread = null;
241
242    /*
243     * Primary constructor, used to drive remainder of the test.
244     *
245     * Fork off the other side, then do your work.
246     */
247    ReadHandshake() throws Exception {
248        startServer(true);
249        startClient(true);
250
251        serverThread.join();
252        clientThread.join();
253
254        /*
255         * When we get here, the test is pretty much over.
256         *
257         * If the main thread excepted, that propagates back
258         * immediately.  If the other thread threw an exception, we
259         * should report back.
260         */
261        if (serverException != null) {
262            if (clientException != null) {
263                System.out.println("Client exception:");
264                clientException.printStackTrace(System.out);
265            }
266            throw serverException;
267        }
268        if (clientException != null) {
269            throw clientException;
270        }
271    }
272
273    void startServer(boolean newThread) throws Exception {
274        if (newThread) {
275            serverThread = new Thread() {
276                public void run() {
277                    try {
278                        doServerSide();
279                    } catch (Exception e) {
280                        /*
281                         * Our server thread just died.
282                         *
283                         * Release the client, if not active already...
284                         */
285                        System.err.println("Server died...");
286                        serverReady = true;
287                        serverException = e;
288                    }
289                }
290            };
291            serverThread.start();
292        } else {
293            doServerSide();
294        }
295    }
296
297    void startClient(boolean newThread) throws Exception {
298        if (newThread) {
299            clientThread = new Thread() {
300                public void run() {
301                    try {
302                        doClientSide();
303                    } catch (Exception e) {
304                        /*
305                         * Our client thread just died.
306                         */
307                        System.err.println("Client died...");
308                        clientException = e;
309                    }
310                }
311            };
312            clientThread.start();
313        } else {
314            doClientSide();
315        }
316    }
317}
318