1/*
2 * Copyright (c) 2003, 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
24import java.io.*;
25import java.net.*;
26import java.util.*;
27import java.security.*;
28import javax.net.*;
29import javax.net.ssl.*;
30
31public class ClientAuth extends PKCS11Test {
32
33    /*
34     * =============================================================
35     * Set the various variables needed for the tests, then
36     * specify what tests to run on each side.
37     */
38
39    private static Provider provider;
40    private static final String NSS_PWD = "test12";
41    private static final String JKS_PWD = "passphrase";
42    private static final String SERVER_KS = "server.keystore";
43    private static final String TS = "truststore";
44    private static String p11config;
45
46    private static String DIR = System.getProperty("DIR");
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     * Is the server ready to serve?
57     */
58    volatile static boolean serverReady = false;
59
60    /*
61     * Turn on SSL debugging?
62     */
63    static boolean debug = false;
64
65    /*
66     * If the client or server is doing some kind of object creation
67     * that the other side depends on, and that thread prematurely
68     * exits, you may experience a hang.  The test harness will
69     * terminate all hung threads after its timeout has expired,
70     * currently 3 minutes by default, but you might try to be
71     * smart about it....
72     */
73
74    /*
75     * Define the server side of the test.
76     *
77     * If the server prematurely exits, serverReady will be set to true
78     * to avoid infinite hangs.
79     */
80    void doServerSide() throws Exception {
81
82        SSLContext ctx = SSLContext.getInstance("TLS");
83        char[] passphrase = JKS_PWD.toCharArray();
84
85        // server gets KeyStore from JKS keystore
86        KeyStore ks = KeyStore.getInstance("JKS");
87        ks.load(new FileInputStream(new File(DIR, SERVER_KS)), passphrase);
88        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
89        kmf.init(ks, passphrase);
90
91        // server gets TrustStore from PKCS#11 token
92/*
93        passphrase = NSS_PWD.toCharArray();
94        KeyStore ts = KeyStore.getInstance("PKCS11", "SunPKCS11-nss");
95        ts.load(null, passphrase);
96        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
97        tmf.init(ts);
98*/
99
100        //ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
101        ctx.init(kmf.getKeyManagers(), null, null);
102        ServerSocketFactory ssf = ctx.getServerSocketFactory();
103        SSLServerSocket sslServerSocket = (SSLServerSocket)
104                                ssf.createServerSocket(serverPort);
105        sslServerSocket.setNeedClientAuth(true);
106        serverPort = sslServerSocket.getLocalPort();
107        System.out.println("serverPort = " + serverPort);
108
109        /*
110         * Signal Client, we're ready for his connect.
111         */
112        serverReady = true;
113
114        SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
115        InputStream sslIS = sslSocket.getInputStream();
116        OutputStream sslOS = sslSocket.getOutputStream();
117
118        sslIS.read();
119        sslOS.write(85);
120        sslOS.flush();
121
122        sslSocket.close();
123    }
124
125    /*
126     * Define the client side of the test.
127     *
128     * If the server prematurely exits, serverReady will be set to true
129     * to avoid infinite hangs.
130     */
131    void doClientSide() throws Exception {
132
133        /*
134         * Wait for server to get started.
135         */
136        while (!serverReady) {
137            Thread.sleep(50);
138        }
139
140        SSLContext ctx = SSLContext.getInstance("TLS");
141        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
142
143        // client gets KeyStore from PKCS#11 token,
144        // and gets TrustStore from JKS KeyStore (using system properties)
145        char[] passphrase = NSS_PWD.toCharArray();
146        KeyStore ks = KeyStore.getInstance("PKCS11", "SunPKCS11-nss");
147        ks.load(null, passphrase);
148
149        kmf = KeyManagerFactory.getInstance("SunX509");
150        kmf.init(ks, passphrase);
151        ctx.init(kmf.getKeyManagers(), null, null);
152
153        SSLSocketFactory sslsf = ctx.getSocketFactory();
154        SSLSocket sslSocket = (SSLSocket)
155            sslsf.createSocket("localhost", serverPort);
156
157        if (clientProtocol != null) {
158            sslSocket.setEnabledProtocols(new String[] {clientProtocol});
159        }
160
161        if (clientCiperSuite != null) {
162            sslSocket.setEnabledCipherSuites(new String[] {clientCiperSuite});
163        }
164
165        InputStream sslIS = sslSocket.getInputStream();
166        OutputStream sslOS = sslSocket.getOutputStream();
167
168        sslOS.write(280);
169        sslOS.flush();
170        sslIS.read();
171
172        sslSocket.close();
173    }
174
175    /*
176     * =============================================================
177     * The remainder is just support stuff
178     */
179
180    // use any free port by default
181    volatile int serverPort = 0;
182
183    volatile Exception serverException = null;
184    volatile Exception clientException = null;
185
186    private static String clientProtocol = null;
187    private static String clientCiperSuite = null;
188
189    private static void parseArguments(String[] args) {
190        if (args.length > 0) {
191            clientProtocol = args[0];
192        }
193
194        if (args.length > 1) {
195            clientCiperSuite = args[1];
196        }
197    }
198
199    public static void main(String[] args) throws Exception {
200        // Get the customized arguments.
201        parseArguments(args);
202        main(new ClientAuth());
203    }
204
205    public void main(Provider p) throws Exception {
206        // SSL RSA client auth currently needs an RSA cipher
207        // (cf. NONEwithRSA hack), which is currently not available in
208        // open builds.
209        try {
210            javax.crypto.Cipher.getInstance("RSA/ECB/PKCS1Padding", p);
211        } catch (GeneralSecurityException e) {
212            System.out.println("Not supported by provider, skipping");
213            return;
214        }
215
216        this.provider = p;
217
218        System.setProperty("javax.net.ssl.trustStore",
219                                        new File(DIR, TS).toString());
220        System.setProperty("javax.net.ssl.trustStoreType", "JKS");
221        System.setProperty("javax.net.ssl.trustStoreProvider", "SUN");
222        System.setProperty("javax.net.ssl.trustStorePassword", JKS_PWD);
223
224        // perform Security.addProvider of P11 provider
225        Security.addProvider(getSunPKCS11(System.getProperty("CUSTOM_P11_CONFIG")));
226
227        if (debug) {
228            System.setProperty("javax.net.debug", "all");
229        }
230
231        /*
232         * Start the tests.
233         */
234        go();
235    }
236
237    Thread clientThread = null;
238    Thread serverThread = null;
239
240    /*
241     * Fork off the other side, then do your work.
242     */
243    private void go() throws Exception {
244        try {
245            if (separateServerThread) {
246                startServer(true);
247                startClient(false);
248            } else {
249                startClient(true);
250                startServer(false);
251            }
252        } catch (Exception e) {
253            //swallow for now.  Show later
254        }
255
256        /*
257         * Wait for other side to close down.
258         */
259        if (separateServerThread) {
260            serverThread.join();
261        } else {
262            clientThread.join();
263        }
264
265        /*
266         * When we get here, the test is pretty much over.
267         * Which side threw the error?
268         */
269        Exception local;
270        Exception remote;
271        String whichRemote;
272
273        if (separateServerThread) {
274            remote = serverException;
275            local = clientException;
276            whichRemote = "server";
277        } else {
278            remote = clientException;
279            local = serverException;
280            whichRemote = "client";
281        }
282
283        /*
284         * If both failed, return the curthread's exception, but also
285         * print the remote side Exception
286         */
287        if ((local != null) && (remote != null)) {
288            System.out.println(whichRemote + " also threw:");
289            remote.printStackTrace();
290            System.out.println();
291            throw local;
292        }
293
294        if (remote != null) {
295            throw remote;
296        }
297
298        if (local != null) {
299            throw local;
300        }
301    }
302
303    void startServer(boolean newThread) throws Exception {
304        if (newThread) {
305            serverThread = new Thread() {
306                public void run() {
307                    try {
308                        doServerSide();
309                    } catch (Exception e) {
310                        /*
311                         * Our server thread just died.
312                         *
313                         * Release the client, if not active already...
314                         */
315                        System.err.println("Server died...");
316                        serverReady = true;
317                        serverException = e;
318                    }
319                }
320            };
321            serverThread.start();
322        } else {
323            try {
324                doServerSide();
325            } catch (Exception e) {
326                serverException = e;
327            } finally {
328                serverReady = true;
329            }
330        }
331    }
332
333    void startClient(boolean newThread) throws Exception {
334        if (newThread) {
335            clientThread = new Thread() {
336                public void run() {
337                    try {
338                        doClientSide();
339                    } catch (Exception e) {
340                        /*
341                         * Our client thread just died.
342                         */
343                        System.err.println("Client died...");
344                        clientException = e;
345                    }
346                }
347            };
348            clientThread.start();
349        } else {
350            try {
351                doClientSide();
352            } catch (Exception e) {
353                clientException = e;
354            }
355        }
356    }
357}
358