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