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// SunJSSE does not support dynamic system properties, no way to re-use
28// system properties in samevm/agentvm mode.
29//
30
31/*
32 * @test
33 * @bug 4873188
34 * @summary Support TLS 1.1
35 * @run main/othervm EmptyCertificateAuthorities
36 * @modules java.security.jgss
37 *          java.security.jgss/sun.security.krb5:+open
38 *          java.security.jgss/sun.security.krb5.internal:+open
39 *          java.security.jgss/sun.security.krb5.internal.ccache
40 *          java.security.jgss/sun.security.krb5.internal.crypto
41 *          java.security.jgss/sun.security.krb5.internal.ktab
42 *          java.base/sun.security.util
43 * @author Xuelei Fan
44 */
45
46import java.io.FileInputStream;
47import java.io.InputStream;
48import java.io.OutputStream;
49import java.security.KeyStore;
50import java.security.Security;
51import java.security.cert.CertificateException;
52import java.security.cert.X509Certificate;
53import javax.net.ssl.KeyManager;
54import javax.net.ssl.KeyManagerFactory;
55import javax.net.ssl.SSLContext;
56import javax.net.ssl.SSLServerSocket;
57import javax.net.ssl.SSLServerSocketFactory;
58import javax.net.ssl.SSLSocket;
59import javax.net.ssl.SSLSocketFactory;
60import javax.net.ssl.TrustManager;
61import javax.net.ssl.TrustManagerFactory;
62import javax.net.ssl.X509TrustManager;
63
64public class EmptyCertificateAuthorities {
65
66    /*
67     * =============================================================
68     * Set the various variables needed for the tests, then
69     * specify what tests to run on each side.
70     */
71
72    /*
73     * Should we run the client or server in a separate thread?
74     * Both sides can throw exceptions, but do you have a preference
75     * as to which side should be the main thread.
76     */
77    static boolean separateServerThread = false;
78
79    /*
80     * Where do we find the keystores?
81     */
82    static String pathToStores = "../etc";
83    static String keyStoreFile = "keystore";
84    static String trustStoreFile = "truststore";
85    static String passwd = "passphrase";
86
87    /*
88     * Is the server ready to serve?
89     */
90    volatile static boolean serverReady = false;
91
92    /*
93     * Turn on SSL debugging?
94     */
95    static boolean debug = false;
96
97    /*
98     * If the client or server is doing some kind of object creation
99     * that the other side depends on, and that thread prematurely
100     * exits, you may experience a hang.  The test harness will
101     * terminate all hung threads after its timeout has expired,
102     * currently 3 minutes by default, but you might try to be
103     * smart about it....
104     */
105
106    /*
107     * Define the server side of the test.
108     *
109     * If the server prematurely exits, serverReady will be set to true
110     * to avoid infinite hangs.
111     */
112    void doServerSide() throws Exception {
113        SSLServerSocketFactory sslssf = getSSLServerSF();
114        SSLServerSocket sslServerSocket =
115            (SSLServerSocket) sslssf.createServerSocket(serverPort);
116
117        // require client authentication.
118        sslServerSocket.setNeedClientAuth(true);
119
120        serverPort = sslServerSocket.getLocalPort();
121
122        /*
123         * Signal Client, we're ready for his connect.
124         */
125        serverReady = true;
126
127        SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
128        InputStream sslIS = sslSocket.getInputStream();
129        OutputStream sslOS = sslSocket.getOutputStream();
130
131        sslIS.read();
132        sslOS.write('A');
133        sslOS.flush();
134
135        sslSocket.close();
136    }
137
138    /*
139     * Define the client side of the test.
140     *
141     * If the server prematurely exits, serverReady will be set to true
142     * to avoid infinite hangs.
143     */
144    void doClientSide() throws Exception {
145
146        /*
147         * Wait for server to get started.
148         */
149        while (!serverReady) {
150            Thread.sleep(50);
151        }
152
153        SSLSocketFactory sslsf =
154            (SSLSocketFactory) SSLSocketFactory.getDefault();
155        SSLSocket sslSocket = (SSLSocket)
156            sslsf.createSocket("localhost", serverPort);
157
158        // enable TLSv1.1 only
159        sslSocket.setEnabledProtocols(new String[] {"TLSv1.1"});
160
161        InputStream sslIS = sslSocket.getInputStream();
162        OutputStream sslOS = sslSocket.getOutputStream();
163
164        sslOS.write('B');
165        sslOS.flush();
166        sslIS.read();
167
168        sslSocket.close();
169    }
170
171    private SSLServerSocketFactory getSSLServerSF() throws Exception {
172
173        char [] password =
174            System.getProperty("javax.net.ssl.keyStorePassword").toCharArray();
175        String keyFilename = System.getProperty("javax.net.ssl.keyStore");
176
177        KeyStore ks = KeyStore.getInstance("JKS");
178        ks.load(new FileInputStream(keyFilename), password);
179
180        KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
181        kmf.init(ks, password);
182
183        KeyManager[] kms = kmf.getKeyManagers();
184        TrustManager[] tms = new MyX509TM[] {new MyX509TM()};
185
186        SSLContext ctx = SSLContext.getInstance("TLS");
187        ctx.init(kms, tms, null);
188
189        return ctx.getServerSocketFactory();
190    }
191
192
193    static class MyX509TM implements X509TrustManager {
194        X509TrustManager tm;
195
196        public void checkClientTrusted(X509Certificate[] chain,
197            String authType) throws CertificateException {
198            if (tm == null) {
199                initialize();
200            }
201            tm.checkClientTrusted(chain, authType);
202        }
203
204        public void checkServerTrusted(X509Certificate[] chain,
205            String authType) throws CertificateException {
206            if (tm == null) {
207                initialize();
208            }
209            tm.checkServerTrusted(chain, authType);
210        }
211
212        public X509Certificate[] getAcceptedIssuers() {
213            // always return empty array
214            return new X509Certificate[0];
215        }
216
217        private void initialize() throws CertificateException {
218            String passwd =
219                System.getProperty("javax.net.ssl.trustStorePassword");
220            char [] password = passwd.toCharArray();
221            String trustFilename =
222                System.getProperty("javax.net.ssl.trustStore");
223
224            try {
225                KeyStore ks = KeyStore.getInstance("JKS");
226                ks.load(new FileInputStream(trustFilename), password);
227
228                TrustManagerFactory tmf =
229                        TrustManagerFactory.getInstance("PKIX");
230                tmf.init(ks);
231                tm = (X509TrustManager)tmf.getTrustManagers()[0];
232            } catch (Exception e) {
233                throw new CertificateException("Unable to initialize TM");
234            }
235
236        }
237    }
238
239    /*
240     * =============================================================
241     * The remainder is just support stuff
242     */
243
244    // use any free port by default
245    volatile int serverPort = 0;
246
247    volatile Exception serverException = null;
248    volatile Exception clientException = null;
249
250    public static void main(String[] args) throws Exception {
251        // MD5 is used in this test case, don't disable MD5 algorithm.
252        Security.setProperty("jdk.certpath.disabledAlgorithms",
253                "MD2, RSA keySize < 1024");
254        Security.setProperty("jdk.tls.disabledAlgorithms",
255                "SSLv3, RC4, DH keySize < 768");
256
257        String keyFilename =
258            System.getProperty("test.src", ".") + "/" + pathToStores +
259                "/" + keyStoreFile;
260        String trustFilename =
261            System.getProperty("test.src", ".") + "/" + pathToStores +
262                "/" + trustStoreFile;
263
264        System.setProperty("javax.net.ssl.keyStore", keyFilename);
265        System.setProperty("javax.net.ssl.keyStorePassword", passwd);
266        System.setProperty("javax.net.ssl.trustStore", trustFilename);
267        System.setProperty("javax.net.ssl.trustStorePassword", passwd);
268
269        if (debug)
270            System.setProperty("javax.net.debug", "all");
271
272        /*
273         * Start the tests.
274         */
275        new EmptyCertificateAuthorities();
276    }
277
278    Thread clientThread = null;
279    Thread serverThread = null;
280
281    /*
282     * Primary constructor, used to drive remainder of the test.
283     *
284     * Fork off the other side, then do your work.
285     */
286    EmptyCertificateAuthorities() throws Exception {
287        try {
288            if (separateServerThread) {
289                startServer(true);
290                startClient(false);
291            } else {
292                startClient(true);
293                startServer(false);
294            }
295        } catch (Exception e) {
296            // swallow for now.  Show later
297        }
298
299        /*
300         * Wait for other side to close down.
301         */
302        if (separateServerThread) {
303            serverThread.join();
304        } else {
305            clientThread.join();
306        }
307
308        /*
309         * When we get here, the test is pretty much over.
310         * Which side threw the error?
311         */
312        Exception local;
313        Exception remote;
314        String whichRemote;
315
316        if (separateServerThread) {
317            remote = serverException;
318            local = clientException;
319            whichRemote = "server";
320        } else {
321            remote = clientException;
322            local = serverException;
323            whichRemote = "client";
324        }
325
326        /*
327         * If both failed, return the curthread's exception, but also
328         * print the remote side Exception
329         */
330        if ((local != null) && (remote != null)) {
331            System.out.println(whichRemote + " also threw:");
332            remote.printStackTrace();
333            System.out.println();
334            throw local;
335        }
336
337        if (remote != null) {
338            throw remote;
339        }
340
341        if (local != null) {
342            throw local;
343        }
344    }
345
346    void startServer(boolean newThread) throws Exception {
347        if (newThread) {
348            serverThread = new Thread() {
349                public void run() {
350                    try {
351                        doServerSide();
352                    } catch (Exception e) {
353                        /*
354                         * Our server thread just died.
355                         *
356                         * Release the client, if not active already...
357                         */
358                        System.err.println("Server died...");
359                        serverReady = true;
360                        serverException = e;
361                    }
362                }
363            };
364            serverThread.start();
365        } else {
366            try {
367                doServerSide();
368            } catch (Exception e) {
369                serverException = e;
370            } finally {
371                serverReady = true;
372            }
373        }
374    }
375
376    void startClient(boolean newThread) throws Exception {
377        if (newThread) {
378            clientThread = new Thread() {
379                public void run() {
380                    try {
381                        doClientSide();
382                    } catch (Exception e) {
383                        /*
384                         * Our client thread just died.
385                         */
386                        System.err.println("Client died...");
387                        clientException = e;
388                    }
389                }
390            };
391            clientThread.start();
392        } else {
393            try {
394                doClientSide();
395            } catch (Exception e) {
396                clientException = e;
397            }
398        }
399    }
400}
401