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 * @test
26 * @bug 4390659
27 * @summary setNeedClientAuth() isn't working after a handshaker is established
28 * @run main/othervm ClientModeClientAuth
29 *
30 *     SunJSSE does not support dynamic system properties, no way to re-use
31 *     system properties in samevm/agentvm mode.
32 * @author Brad Wetmore
33 */
34
35import java.io.*;
36import java.net.*;
37import javax.net.ssl.*;
38import java.security.cert.*;
39
40public class ClientModeClientAuth {
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 = false;
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     * Define the server side of the test.
70     */
71    void doServerSide() throws Exception {
72
73        ServerSocket serverSocket = null;
74        serverSocket = new ServerSocket(serverPort);
75        serverPort = serverSocket.getLocalPort();
76
77        /*
78         * Signal Client, we're ready for his connect.
79         */
80        serverReady = true;
81
82        Socket socket = serverSocket.accept();
83        OutputStream out = socket.getOutputStream();
84        InputStream in = socket.getInputStream();
85
86        /*
87         * send data to make sure we are ok.
88         */
89        out.write(85);
90        out.flush();
91        in.read();
92
93        SSLSocketFactory sslsf =
94            (SSLSocketFactory) SSLSocketFactory.getDefault();
95        SSLSocket sslSocket =
96            (SSLSocket) sslsf.createSocket(
97                socket, socket.getInetAddress().getHostName(),
98                socket.getPort(), true);
99
100        sslSocket.setUseClientMode(false);
101        sslSocket.setNeedClientAuth(true);
102
103        InputStream sslIS = sslSocket.getInputStream();
104        OutputStream sslOS = sslSocket.getOutputStream();
105
106        sslOS.write(85);
107        sslOS.flush();
108        sslIS.read();
109
110        System.out.println("About to get PeerCertificates");
111        Certificate[] certs =
112            sslSocket.getSession().getPeerCertificates();
113        if (certs[0] instanceof X509Certificate) {
114            System.out.println("Peer: " +
115                ((X509Certificate)certs[0]).getSubjectDN());
116        }
117
118        sslIS.close();
119        sslOS.close();
120        sslSocket.close();
121    }
122
123    /*
124     * Define the client side of the test.
125     */
126    void doClientSide() throws Exception {
127
128        /*
129         * Wait for host to set up his port.
130         */
131        while (!serverReady) {
132            Thread.sleep(50);
133        }
134
135        Socket socket = new Socket("localhost", serverPort);
136        InputStream in = socket.getInputStream();
137        OutputStream out = socket.getOutputStream();
138
139        in.read();
140        out.write(280);
141        out.flush();
142
143        SSLSocketFactory sslsf =
144            (SSLSocketFactory) SSLSocketFactory.getDefault();
145
146        SSLSocket sslSocket = (SSLSocket)
147            sslsf.createSocket(socket, socket.getInetAddress().getHostName(),
148                socket.getPort(), true);
149
150        sslSocket.setUseClientMode(true);
151
152        InputStream sslIS = sslSocket.getInputStream();
153        OutputStream sslOS = sslSocket.getOutputStream();
154
155        sslIS.read();
156        sslOS.write(280);
157        sslOS.flush();
158
159        sslIS.close();
160        sslOS.close();
161        sslSocket.close();
162    }
163
164    /*
165     * =============================================================
166     * The remainder is just support stuff
167     */
168
169    // use any free port by default
170    volatile int serverPort = 0;
171
172    volatile Exception serverException = null;
173    volatile Exception clientException = null;
174
175    public static void main(String[] args) throws Exception {
176        String keyFilename =
177            System.getProperty("test.src", "./") + "/" + pathToStores +
178                "/" + keyStoreFile;
179        String trustFilename =
180            System.getProperty("test.src", "./") + "/" + pathToStores +
181                "/" + trustStoreFile;
182
183        System.setProperty("javax.net.ssl.keyStore", keyFilename);
184        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
185        System.setProperty("javax.net.ssl.trustStore", trustFilename);
186        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
187
188        /*
189         * Start the tests.
190         */
191        new ClientModeClientAuth();
192    }
193
194    Thread clientThread = null;
195    Thread serverThread = null;
196
197    ClientModeClientAuth() throws Exception {
198        if (separateServerThread) {
199            startServer(true);
200            startClient(false);
201        } else {
202            startClient(true);
203            startServer(false);
204        }
205
206        /*
207         * Wait for other side to close down.
208         */
209        if (separateServerThread) {
210            serverThread.join();
211        } else {
212            clientThread.join();
213        }
214
215        /*
216         * When we get here, the test is pretty much over.
217         *
218         * If the main thread excepted, that propagates back
219         * immediately.  If the other thread threw an exception, we
220         * should report back.
221         */
222        if (serverException != null)
223            throw serverException;
224        if (clientException != null)
225            throw clientException;
226    }
227
228    void startServer(boolean newThread) throws Exception {
229        if (newThread) {
230            serverThread = new Thread() {
231                public void run() {
232                    try {
233                        doServerSide();
234                    } catch (Exception e) {
235                        /*
236                         * Our server thread just died.
237                         *
238                         * Release the client, if not active already...
239                         */
240                        System.out.println("Server died...");
241                        serverReady = true;
242                        serverException = e;
243                    }
244                }
245            };
246            serverThread.start();
247        } else {
248            doServerSide();
249        }
250    }
251
252    void startClient(boolean newThread) throws Exception {
253        if (newThread) {
254            clientThread = new Thread() {
255                public void run() {
256                    try {
257                        doClientSide();
258                    } catch (Exception e) {
259                        /*
260                         * Our client thread just died.
261                         */
262                        System.out.println("Client died...");
263                        clientException = e;
264                    }
265                }
266            };
267            clientThread.start();
268        } else {
269            doClientSide();
270        }
271    }
272}
273