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 GenericBlockCipher
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 javax.net.ssl.SSLServerSocket;
48import javax.net.ssl.SSLServerSocketFactory;
49import javax.net.ssl.SSLSocket;
50import javax.net.ssl.SSLSocketFactory;
51
52public class GenericBlockCipher {
53
54    /*
55     * =============================================================
56     * Set the various variables needed for the tests, then
57     * specify what tests to run on each side.
58     */
59
60    /*
61     * Should we run the client or server in a separate thread?
62     * Both sides can throw exceptions, but do you have a preference
63     * as to which side should be the main thread.
64     */
65    static boolean separateServerThread = false;
66
67    /*
68     * Where do we find the keystores?
69     */
70    static String pathToStores = "../etc";
71    static String keyStoreFile = "keystore";
72    static String trustStoreFile = "truststore";
73    static String passwd = "passphrase";
74
75    /*
76     * Is the server ready to serve?
77     */
78    volatile static boolean serverReady = false;
79
80    /*
81     * Turn on SSL debugging?
82     */
83    static boolean debug = false;
84
85    /*
86     * If the client or server is doing some kind of object creation
87     * that the other side depends on, and that thread prematurely
88     * exits, you may experience a hang.  The test harness will
89     * terminate all hung threads after its timeout has expired,
90     * currently 3 minutes by default, but you might try to be
91     * smart about it....
92     */
93
94    /*
95     * Define the server side of the test.
96     *
97     * If the server prematurely exits, serverReady will be set to true
98     * to avoid infinite hangs.
99     */
100    void doServerSide() throws Exception {
101        SSLServerSocketFactory sslssf =
102            (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
103        SSLServerSocket sslServerSocket =
104            (SSLServerSocket) sslssf.createServerSocket(serverPort);
105
106        serverPort = sslServerSocket.getLocalPort();
107
108        /*
109         * Signal Client, we're ready for his connect.
110         */
111        serverReady = true;
112
113        SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
114        InputStream sslIS = sslSocket.getInputStream();
115        OutputStream sslOS = sslSocket.getOutputStream();
116
117        sslIS.read();
118        sslOS.write('A');
119        sslOS.flush();
120
121        sslSocket.close();
122    }
123
124    /*
125     * Define the client side of the test.
126     *
127     * If the server prematurely exits, serverReady will be set to true
128     * to avoid infinite hangs.
129     */
130    void doClientSide() throws Exception {
131
132        /*
133         * Wait for server to get started.
134         */
135        while (!serverReady) {
136            Thread.sleep(50);
137        }
138
139        SSLSocketFactory sslsf =
140            (SSLSocketFactory) SSLSocketFactory.getDefault();
141        SSLSocket sslSocket = (SSLSocket)
142            sslsf.createSocket("localhost", serverPort);
143
144        // enable TLSv1.1 only
145        sslSocket.setEnabledProtocols(new String[] {"TLSv1.1"});
146
147        // enable a block cipher
148        sslSocket.setEnabledCipherSuites(
149            new String[] {"TLS_RSA_WITH_AES_128_CBC_SHA"});
150
151        InputStream sslIS = sslSocket.getInputStream();
152        OutputStream sslOS = sslSocket.getOutputStream();
153
154        sslOS.write('B');
155        sslOS.flush();
156        sslIS.read();
157
158        sslSocket.close();
159    }
160
161    /*
162     * =============================================================
163     * The remainder is just support stuff
164     */
165
166    // use any free port by default
167    volatile int serverPort = 0;
168
169    volatile Exception serverException = null;
170    volatile Exception clientException = null;
171
172    public static void main(String[] args) throws Exception {
173        String keyFilename =
174            System.getProperty("test.src", ".") + "/" + pathToStores +
175                "/" + keyStoreFile;
176        String trustFilename =
177            System.getProperty("test.src", ".") + "/" + pathToStores +
178                "/" + trustStoreFile;
179
180        System.setProperty("javax.net.ssl.keyStore", keyFilename);
181        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
182        System.setProperty("javax.net.ssl.trustStore", trustFilename);
183        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
184
185        if (debug)
186            System.setProperty("javax.net.debug", "all");
187
188        /*
189         * Start the tests.
190         */
191        new GenericBlockCipher();
192    }
193
194    Thread clientThread = null;
195    Thread serverThread = null;
196
197    /*
198     * Primary constructor, used to drive remainder of the test.
199     *
200     * Fork off the other side, then do your work.
201     */
202    GenericBlockCipher() throws Exception {
203        try {
204            if (separateServerThread) {
205                startServer(true);
206                startClient(false);
207            } else {
208                startClient(true);
209                startServer(false);
210            }
211        } catch (Exception e) {
212            // swallow for now.  Show later
213        }
214
215        /*
216         * Wait for other side to close down.
217         */
218        if (separateServerThread) {
219            serverThread.join();
220        } else {
221            clientThread.join();
222        }
223
224        /*
225         * When we get here, the test is pretty much over.
226         * Which side threw the error?
227         */
228        Exception local;
229        Exception remote;
230        String whichRemote;
231
232        if (separateServerThread) {
233            remote = serverException;
234            local = clientException;
235            whichRemote = "server";
236        } else {
237            remote = clientException;
238            local = serverException;
239            whichRemote = "client";
240        }
241
242        /*
243         * If both failed, return the curthread's exception, but also
244         * print the remote side Exception
245         */
246        if ((local != null) && (remote != null)) {
247            System.out.println(whichRemote + " also threw:");
248            remote.printStackTrace();
249            System.out.println();
250            throw local;
251        }
252
253        if (remote != null) {
254            throw remote;
255        }
256
257        if (local != null) {
258            throw local;
259        }
260    }
261
262    void startServer(boolean newThread) throws Exception {
263        if (newThread) {
264            serverThread = new Thread() {
265                public void run() {
266                    try {
267                        doServerSide();
268                    } catch (Exception e) {
269                        /*
270                         * Our server thread just died.
271                         *
272                         * Release the client, if not active already...
273                         */
274                        System.err.println("Server died...");
275                        serverReady = true;
276                        serverException = e;
277                    }
278                }
279            };
280            serverThread.start();
281        } else {
282            try {
283                doServerSide();
284            } catch (Exception e) {
285                serverException = e;
286            } finally {
287                serverReady = true;
288            }
289        }
290    }
291
292    void startClient(boolean newThread) throws Exception {
293        if (newThread) {
294            clientThread = new Thread() {
295                public void run() {
296                    try {
297                        doClientSide();
298                    } catch (Exception e) {
299                        /*
300                         * Our client thread just died.
301                         */
302                        System.err.println("Client died...");
303                        clientException = e;
304                    }
305                }
306            };
307            clientThread.start();
308        } else {
309            try {
310                doClientSide();
311            } catch (Exception e) {
312                clientException = e;
313            }
314        }
315    }
316}
317