1/*
2 * Copyright (c) 2010, 2016, 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.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26/*
27 * @test
28 * @bug 4873188
29 * @summary Support TLS 1.1
30 * @modules java.security.jgss
31 *          java.security.jgss/sun.security.krb5:+open
32 *          java.security.jgss/sun.security.krb5.internal:+open
33 *          java.security.jgss/sun.security.krb5.internal.ccache
34 *          java.security.jgss/sun.security.krb5.internal.crypto
35 *          java.security.jgss/sun.security.krb5.internal.ktab
36 *          java.base/sun.security.util
37 * @run main/othervm GenericStreamCipher
38 *
39 *     SunJSSE does not support dynamic system properties, no way to re-use
40 *     system properties in samevm/agentvm mode.
41 *
42 * @author Xuelei Fan
43 */
44
45import java.io.InputStream;
46import java.io.OutputStream;
47import java.security.Security;
48import javax.net.ssl.SSLServerSocket;
49import javax.net.ssl.SSLServerSocketFactory;
50import javax.net.ssl.SSLSocket;
51import javax.net.ssl.SSLSocketFactory;
52
53public class GenericStreamCipher {
54
55    /*
56     * =============================================================
57     * Set the various variables needed for the tests, then
58     * specify what tests to run on each side.
59     */
60
61    /*
62     * Should we run the client or server in a separate thread?
63     * Both sides can throw exceptions, but do you have a preference
64     * as to which side should be the main thread.
65     */
66    static boolean separateServerThread = false;
67
68    /*
69     * Where do we find the keystores?
70     */
71    static String pathToStores = "../etc";
72    static String keyStoreFile = "keystore";
73    static String trustStoreFile = "truststore";
74    static String passwd = "passphrase";
75
76    /*
77     * Is the server ready to serve?
78     */
79    volatile static boolean serverReady = false;
80
81    /*
82     * Turn on SSL debugging?
83     */
84    static boolean debug = false;
85
86    /*
87     * If the client or server is doing some kind of object creation
88     * that the other side depends on, and that thread prematurely
89     * exits, you may experience a hang.  The test harness will
90     * terminate all hung threads after its timeout has expired,
91     * currently 3 minutes by default, but you might try to be
92     * smart about it....
93     */
94
95    /*
96     * Define the server side of the test.
97     *
98     * If the server prematurely exits, serverReady will be set to true
99     * to avoid infinite hangs.
100     */
101    void doServerSide() throws Exception {
102        SSLServerSocketFactory sslssf =
103            (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
104        SSLServerSocket sslServerSocket =
105            (SSLServerSocket) sslssf.createServerSocket(serverPort);
106
107        // enable a stream cipher
108        sslServerSocket.setEnabledCipherSuites(
109            new String[] {"SSL_RSA_WITH_RC4_128_MD5"});
110
111        serverPort = sslServerSocket.getLocalPort();
112
113        /*
114         * Signal Client, we're ready for his connect.
115         */
116        serverReady = true;
117
118        SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
119        InputStream sslIS = sslSocket.getInputStream();
120        OutputStream sslOS = sslSocket.getOutputStream();
121
122        sslIS.read();
123        sslOS.write('A');
124        sslOS.flush();
125
126        sslSocket.close();
127    }
128
129    /*
130     * Define the client side of the test.
131     *
132     * If the server prematurely exits, serverReady will be set to true
133     * to avoid infinite hangs.
134     */
135    void doClientSide() throws Exception {
136
137        /*
138         * Wait for server to get started.
139         */
140        while (!serverReady) {
141            Thread.sleep(50);
142        }
143
144        SSLSocketFactory sslsf =
145            (SSLSocketFactory) SSLSocketFactory.getDefault();
146        SSLSocket sslSocket = (SSLSocket)
147            sslsf.createSocket("localhost", serverPort);
148
149        // enable TLSv1.1 only
150        sslSocket.setEnabledProtocols(new String[] {"TLSv1.1"});
151
152        // enable a stream cipher
153        sslSocket.setEnabledCipherSuites(
154            new String[] {"SSL_RSA_WITH_RC4_128_MD5"});
155
156        InputStream sslIS = sslSocket.getInputStream();
157        OutputStream sslOS = sslSocket.getOutputStream();
158
159        sslOS.write('B');
160        sslOS.flush();
161        sslIS.read();
162
163        sslSocket.close();
164    }
165
166    /*
167     * =============================================================
168     * The remainder is just support stuff
169     */
170
171    // use any free port by default
172    volatile int serverPort = 0;
173
174    volatile Exception serverException = null;
175    volatile Exception clientException = null;
176
177    public static void main(String[] args) throws Exception {
178        // reset the security property to make sure that the algorithms
179        // and keys used in this test are not disabled.
180        Security.setProperty("jdk.tls.disabledAlgorithms", "");
181
182        String keyFilename =
183            System.getProperty("test.src", ".") + "/" + pathToStores +
184                "/" + keyStoreFile;
185        String trustFilename =
186            System.getProperty("test.src", ".") + "/" + pathToStores +
187                "/" + trustStoreFile;
188
189        System.setProperty("javax.net.ssl.keyStore", keyFilename);
190        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
191        System.setProperty("javax.net.ssl.trustStore", trustFilename);
192        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
193
194        if (debug)
195            System.setProperty("javax.net.debug", "all");
196
197        /*
198         * Start the tests.
199         */
200        new GenericStreamCipher();
201    }
202
203    Thread clientThread = null;
204    Thread serverThread = null;
205
206    /*
207     * Primary constructor, used to drive remainder of the test.
208     *
209     * Fork off the other side, then do your work.
210     */
211    GenericStreamCipher() throws Exception {
212        try {
213            if (separateServerThread) {
214                startServer(true);
215                startClient(false);
216            } else {
217                startClient(true);
218                startServer(false);
219            }
220        } catch (Exception e) {
221            // swallow for now.  Show later
222        }
223
224        /*
225         * Wait for other side to close down.
226         */
227        if (separateServerThread) {
228            serverThread.join();
229        } else {
230            clientThread.join();
231        }
232
233        /*
234         * When we get here, the test is pretty much over.
235         * Which side threw the error?
236         */
237        Exception local;
238        Exception remote;
239        String whichRemote;
240
241        if (separateServerThread) {
242            remote = serverException;
243            local = clientException;
244            whichRemote = "server";
245        } else {
246            remote = clientException;
247            local = serverException;
248            whichRemote = "client";
249        }
250
251        /*
252         * If both failed, return the curthread's exception, but also
253         * print the remote side Exception
254         */
255        if ((local != null) && (remote != null)) {
256            System.out.println(whichRemote + " also threw:");
257            remote.printStackTrace();
258            System.out.println();
259            throw local;
260        }
261
262        if (remote != null) {
263            throw remote;
264        }
265
266        if (local != null) {
267            throw local;
268        }
269    }
270
271    void startServer(boolean newThread) throws Exception {
272        if (newThread) {
273            serverThread = new Thread() {
274                public void run() {
275                    try {
276                        doServerSide();
277                    } catch (Exception e) {
278                        /*
279                         * Our server thread just died.
280                         *
281                         * Release the client, if not active already...
282                         */
283                        System.err.println("Server died...");
284                        serverReady = true;
285                        serverException = e;
286                    }
287                }
288            };
289            serverThread.start();
290        } else {
291            try {
292                doServerSide();
293            } catch (Exception e) {
294                serverException = e;
295            } finally {
296                serverReady = true;
297            }
298        }
299    }
300
301    void startClient(boolean newThread) throws Exception {
302        if (newThread) {
303            clientThread = new Thread() {
304                public void run() {
305                    try {
306                        doClientSide();
307                    } catch (Exception e) {
308                        /*
309                         * Our client thread just died.
310                         */
311                        System.err.println("Client died...");
312                        clientException = e;
313                    }
314                }
315            };
316            clientThread.start();
317        } else {
318            try {
319                doClientSide();
320            } catch (Exception e) {
321                clientException = e;
322            }
323        }
324    }
325}
326