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 4395238 4354003 4387961 4395266
27 * @summary A test of many of the new functionality to go into JSSE 1.1
28 *      Fixed 4395238: The new certificate chains APIs should really be
29 *          returning certs, not x509 certs
30 *      Fixed 4354003: Need API to get client certificate chain
31 *      Fixed 4387961: HostnameVerifier needs to pass various hostnames
32 *      Fixed 4395266: HttpsURLConnection should be made protected
33 * @run main/othervm HttpsURLConnectionLocalCertificateChain
34 *
35 *     SunJSSE does not support dynamic system properties, no way to re-use
36 *     system properties in samevm/agentvm mode.
37 * @author Brad Wetmore
38 */
39
40import java.io.*;
41import java.net.*;
42import javax.net.ssl.*;
43import java.security.cert.*;
44
45public class HttpsURLConnectionLocalCertificateChain
46        implements HandshakeCompletedListener,
47        HostnameVerifier {
48
49    /*
50     * =============================================================
51     * Set the various variables needed for the tests, then
52     * specify what tests to run on each side.
53     */
54
55    /*
56     * Should we run the client or server in a separate thread?
57     * Both sides can throw exceptions, but do you have a preference
58     * as to which side should be the main thread.
59     */
60    static boolean separateServerThread = false;
61
62    /*
63     * Where do we find the keystores?
64     */
65    static String pathToStores = "../etc";
66    static String keyStoreFile = "keystore";
67    static String trustStoreFile = "truststore";
68    static String passwd = "passphrase";
69
70    /*
71     * Is the server ready to serve?
72     */
73    volatile static boolean serverReady = false;
74
75    /*
76     * Default Verifier
77     */
78    public boolean verify(String hostname, SSLSession session) {
79        try {
80            Certificate [] certs = session.getPeerCertificates();
81
82            for (int i = 0; i< certs.length; i++) {
83                if (certs[i] instanceof X509Certificate) {
84                    System.out.println("Hostname Verification cert #1: ");
85                    // System.out.println(certs[i].toString());
86                }
87            }
88        } catch (Exception e) {
89            serverException = e;
90        }
91        return true;
92    }
93
94    /*
95     * The event sent by the app.
96     */
97    HandshakeCompletedEvent event;
98
99    /*
100     * Provide the Listener for the HandshakeCompletedEvent
101     * Store the event now, we'll examine it later as we're
102     * finishing the test...
103     */
104    public void handshakeCompleted(HandshakeCompletedEvent theEvent) {
105        event = theEvent;
106    }
107
108    void examineHandshakeCompletedEvent() throws Exception {
109        /*
110         * Also check the types during compile.  We changed
111         * from cert.x509 to certs.
112         */
113        dumpCerts("examineHandshakeCompletedEvent received",
114            event.getPeerCertificates());
115        dumpCerts("examineHandshakeCompletedEvent sent",
116            event.getLocalCertificates());
117    }
118
119    synchronized void dumpCerts(String where, Certificate [] certs)
120            throws Exception {
121
122        System.out.println("");
123        System.out.println(where + ":");
124
125        if (certs == null) {
126            throw new Exception("certs == null");
127        }
128
129        for (int i = 0; i< certs.length; i++) {
130            if (certs[i] instanceof X509Certificate) {
131                System.out.println("cert #1: " +
132                    ((X509Certificate) certs[i]).getSubjectDN());
133            }
134        }
135    }
136
137    void doServerSide() throws Exception {
138
139        SSLServerSocketFactory sslssf;
140        SSLServerSocket sslServerSocket;
141
142        System.out.println("Starting Server...");
143        sslssf =
144            (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
145        sslServerSocket =
146            (SSLServerSocket) sslssf.createServerSocket(serverPort);
147        serverPort = sslServerSocket.getLocalPort();
148        System.out.println("Kicking off Client...");
149
150        serverReady = true;
151
152        SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
153        sslSocket.setNeedClientAuth(true);
154        sslSocket.addHandshakeCompletedListener(this);
155
156        InputStream sslIS = sslSocket.getInputStream();
157        OutputStream sslOS = sslSocket.getOutputStream();
158        DataOutputStream out = new DataOutputStream(sslOS);
159
160        System.out.println("Server reading request...");
161        sslIS.read();
162
163        System.out.println("Server replying...");
164        try {
165            out.writeBytes("HTTP/1.0 200 OK\r\n");
166            out.writeBytes("Content-Length: " + 1 + "\r\n");
167            out.writeBytes("Content-Type: text/html\r\n\r\n");
168            out.write(57);
169            out.flush();
170        } catch (IOException ie) {
171            serverException = ie;
172        }
173
174        System.out.println("Server getting certs...");
175        SSLSession sslSession = sslSocket.getSession();
176        dumpCerts("ServerSide sent", sslSession.getLocalCertificates());
177        dumpCerts("ServerSide received", sslSession.getPeerCertificates());
178
179        /*
180         * Won't bother closing IS/sockets this time, we're exiting...
181         */
182
183        /*
184         * We'll eventually get this event, wait for it.
185         */
186        while (event == null) {
187            Thread.sleep(1000);
188        }
189
190        System.out.println("Server examining Event...");
191        examineHandshakeCompletedEvent();
192    }
193
194    void doClientSide() throws Exception {
195
196        /*
197         * Wait for server to get started.
198         */
199        while (!serverReady) {
200            Thread.sleep(50);
201        }
202
203        System.out.println("Starting Client...");
204
205        String url = "https://localhost:" + serverPort;
206        System.out.println("connecting to: " + url);
207        URL myURL = new URL(url);
208        HttpsURLConnection myURLc;
209
210        System.out.println("Client setting up URL/connecting...");
211        myURLc = (HttpsURLConnection) myURL.openConnection();
212        myURLc.setHostnameVerifier(this);
213        myURLc.connect();
214
215        InputStream sslIS = myURLc.getInputStream();
216
217        System.out.println("Client reading...");
218        sslIS.read();
219
220        System.out.println("Client dumping certs...");
221
222        dumpCerts("ClientSide received", myURLc.getServerCertificates());
223        dumpCerts("ClientSide sent", myURLc.getLocalCertificates());
224
225        /*
226         * Won't bother closing IS/sockets this time, we're exiting...
227         */
228    }
229    /*
230     * =============================================================
231     * The remainder is just support stuff
232     */
233
234    // use any free port by default
235    volatile int serverPort = 0;
236
237    volatile Exception serverException = null;
238    volatile Exception clientException = null;
239
240    public static void main(String[] args) throws Exception {
241        String keyFilename =
242            System.getProperty("test.src", "./") + "/" + pathToStores +
243                "/" + keyStoreFile;
244        String trustFilename =
245            System.getProperty("test.src", "./") + "/" + pathToStores +
246                "/" + trustStoreFile;
247
248        System.setProperty("javax.net.ssl.keyStore", keyFilename);
249        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
250        System.setProperty("javax.net.ssl.trustStore", trustFilename);
251        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
252
253        /*
254         * Start the tests.
255         */
256        new HttpsURLConnectionLocalCertificateChain();
257    }
258
259    Thread clientThread = null;
260    Thread serverThread = null;
261
262    HttpsURLConnectionLocalCertificateChain () throws Exception {
263        if (separateServerThread) {
264            startServer(true);
265            startClient(false);
266        } else {
267            startClient(true);
268            startServer(false);
269        }
270
271        /*
272         * Wait for other side to close down.
273         */
274        if (separateServerThread) {
275            serverThread.join();
276        } else {
277            clientThread.join();
278        }
279
280        /*
281         * When we get here, the test is pretty much over.
282         *
283         * If the main thread excepted, that propagates back
284         * immediately.  If the other thread threw an exception, we
285         * should report back.
286         */
287        if (serverException != null)
288            throw serverException;
289        if (clientException != null)
290            throw clientException;
291    }
292
293    void startServer(boolean newThread) throws Exception {
294        if (newThread) {
295            serverThread = new Thread() {
296                public void run() {
297                    try {
298                        doServerSide();
299                    } catch (Exception e) {
300                        /*
301                         * Our server thread just died.
302                         *
303                         * Release the client, if not active already...
304                         */
305                        System.out.println("Server died...");
306                        serverReady = true;
307                        serverException = e;
308                    }
309                }
310            };
311            serverThread.start();
312        } else {
313            doServerSide();
314        }
315    }
316
317    void startClient(boolean newThread) throws Exception {
318        if (newThread) {
319            clientThread = new Thread() {
320                public void run() {
321                    try {
322                        doClientSide();
323                    } catch (Exception e) {
324                        /*
325                         * Our client thread just died.
326                         */
327                        System.out.println("Client died...");
328                        clientException = e;
329                    }
330                }
331            };
332            clientThread.start();
333        } else {
334            doClientSide();
335        }
336    }
337}
338