1 /*
2  * Copyright (c) 2012, 2018, 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 // SunJSSE does not support dynamic system properties, no way to re-use
26 // system properties in samevm/agentvm mode.
27 //
28 
29 /*
30  * @test
31  * @bug 7200295
32  * @summary CertificateRequest message is wrapping when using large
33  *          numbers of Certs
34  * @run main/othervm CertRequestOverflow
35  */
36 
37 import java.io.*;
38 import java.net.*;
39 import java.util.*;
40 import javax.net.ssl.*;
41 import java.security.cert.*;
42 import java.security.*;
43 
44 public class CertRequestOverflow {
45 
46     /*
47      * =============================================================
48      * Set the various variables needed for the tests, then
49      * specify what tests to run on each side.
50      */
51 
52     /*
53      * Should we run the client or server in a separate thread?
54      * Both sides can throw exceptions, but do you have a preference
55      * as to which side should be the main thread.
56      */
57     static boolean separateServerThread = false;
58 
59     /*
60      * Where do we find the keystores?
61      */
62     static String pathToStores = "../../../../javax/net/ssl/etc";
63     static String keyStoreFile = "keystore";
64     static String trustStoreFile = "truststore";
65     static String passwd = "passphrase";
66     private final static char[] cpasswd = "passphrase".toCharArray();
67 
68     /*
69      * Is the server ready to serve?
70      */
71     volatile static boolean serverReady = false;
72 
73     /*
74      * Turn on SSL debugging?
75      */
76     static boolean debug = false;
77 
78     /*
79      * If the client or server is doing some kind of object creation
80      * that the other side depends on, and that thread prematurely
81      * exits, you may experience a hang.  The test harness will
82      * terminate all hung threads after its timeout has expired,
83      * currently 3 minutes by default, but you might try to be
84      * smart about it....
85      */
86 
87     /*
88      * Define the server side of the test.
89      *
90      * If the server prematurely exits, serverReady will be set to true
91      * to avoid infinite hangs.
92      */
doServerSide()93     void doServerSide() throws Exception {
94         SSLServerSocketFactory sslssf =
95                                 getContext(true).getServerSocketFactory();
96         SSLServerSocket sslServerSocket =
97             (SSLServerSocket) sslssf.createServerSocket(serverPort);
98         serverPort = sslServerSocket.getLocalPort();
99         if (debug) {
100             System.out.println("Server port is " + serverPort);
101         }
102 
103         // enable endpoint identification
104         // ignore, we may test the feature when known how to parse client
105         // hostname
106         //SSLParameters params = sslServerSocket.getSSLParameters();
107         //params.setEndpointIdentificationAlgorithm("HTTPS");
108         //sslServerSocket.setSSLParameters(params);
109 
110         /*
111          * Signal Client, we're ready for his connect.
112          */
113         serverReady = true;
114 
115         SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
116         sslSocket.setNeedClientAuth(true);
117         InputStream sslIS = sslSocket.getInputStream();
118         OutputStream sslOS = sslSocket.getOutputStream();
119 
120         try {
121             sslIS.read();
122             sslOS.write(85);
123             sslOS.flush();
124 
125             throw new Exception("SERVER TEST FAILED!  " +
126                         "It is expected to fail with field length overflow");
127         } catch (SSLException ssle) {
128             Throwable cause = ssle.getCause();
129             if (!(cause instanceof RuntimeException)) {
130                 System.out.println("We are expecting a RuntimeException!");
131                 throw ssle;
132             }
133             System.out.println("The expected exception!  " + ssle);
134         } finally {
135             sslSocket.close();
136         }
137 
138         System.out.println("SERVER TEST PASSED!");
139     }
140 
141     /*
142      * Define the client side of the test.
143      *
144      * If the server prematurely exits, serverReady will be set to true
145      * to avoid infinite hangs.
146      */
doClientSide()147     void doClientSide() throws Exception {
148 
149         /*
150          * Wait for server to get started.
151          */
152         while (!serverReady) {
153             Thread.sleep(50);
154         }
155 
156         SSLSocketFactory sslsf = getContext(false).getSocketFactory();
157         SSLSocket sslSocket = (SSLSocket)
158             sslsf.createSocket("localhost", serverPort);
159         if (debug) {
160             System.out.println("Connected to: " +
161                     sslSocket.getRemoteSocketAddress());
162         }
163 
164         // enable endpoint identification
165         SSLParameters params = sslSocket.getSSLParameters();
166         params.setEndpointIdentificationAlgorithm("HTTPS");
167         sslSocket.setSSLParameters(params);
168 
169         InputStream sslIS = sslSocket.getInputStream();
170         OutputStream sslOS = sslSocket.getOutputStream();
171 
172         try {
173             sslOS.write(280);
174             sslOS.flush();
175             sslIS.read();
176         } catch (SSLException ssle) {
177             System.out.println("An expected exception!");
178         } finally {
179             sslSocket.close();
180         }
181     }
182 
183     MyExtendedX509TM serverTM;
184     MyExtendedX509TM clientTM;
185 
getContext(boolean server)186     private SSLContext getContext(boolean server) throws Exception {
187         String keyFilename =
188             System.getProperty("test.src", "./") + "/" + pathToStores +
189                 "/" + keyStoreFile;
190         String trustFilename =
191             System.getProperty("test.src", "./") + "/" + pathToStores +
192                 "/" + trustStoreFile;
193 
194         KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
195         KeyStore ks = KeyStore.getInstance("JKS");
196         ks.load(new FileInputStream(keyFilename), cpasswd);
197         kmf.init(ks, cpasswd);
198 
199         TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
200         KeyStore ts = KeyStore.getInstance("JKS");
201         ts.load(new FileInputStream(trustFilename), cpasswd);
202         tmf.init(ts);
203 
204         TrustManager tms[] = tmf.getTrustManagers();
205         if (tms == null || tms.length == 0) {
206             throw new Exception("unexpected trust manager implementation");
207         } else {
208            if (!(tms[0] instanceof X509TrustManager)) {
209             throw new Exception("unexpected trust manager implementation: "
210                                 + tms[0].getClass().getCanonicalName());
211            }
212         }
213 
214         if (server) {
215             serverTM = new MyExtendedX509TM((X509TrustManager)tms[0]);
216 
217             tms = new TrustManager[] {serverTM};
218         } else {
219             clientTM = new MyExtendedX509TM((X509TrustManager)tms[0]);
220 
221             tms = new TrustManager[] {clientTM};
222         }
223 
224         SSLContext ctx = SSLContext.getInstance("TLSv1.2");
225         ctx.init(kmf.getKeyManagers(), tms, null);
226 
227         return ctx;
228     }
229 
230     static class MyExtendedX509TM extends X509ExtendedTrustManager
231             implements X509TrustManager {
232 
233         X509TrustManager tm;
234 
235         boolean clientChecked;
236         boolean serverChecked;
237 
MyExtendedX509TM(X509TrustManager tm)238         MyExtendedX509TM(X509TrustManager tm) {
239             clientChecked = false;
240             serverChecked = false;
241 
242             this.tm = tm;
243         }
244 
wasClientChecked()245         public boolean wasClientChecked() {
246             return clientChecked;
247         }
248 
wasServerChecked()249         public boolean wasServerChecked() {
250             return serverChecked;
251         }
252 
253         @Override
checkClientTrusted(X509Certificate chain[], String authType)254         public void checkClientTrusted(X509Certificate chain[], String authType)
255                 throws CertificateException {
256             tm.checkClientTrusted(chain, authType);
257         }
258 
259         @Override
checkServerTrusted(X509Certificate chain[], String authType)260         public void checkServerTrusted(X509Certificate chain[], String authType)
261                 throws CertificateException {
262             tm.checkServerTrusted(chain, authType);
263         }
264 
265         @Override
getAcceptedIssuers()266         public X509Certificate[] getAcceptedIssuers() {
267             // (hack code) increase the size of the returned array to make a
268             // overflow CertificateRequest.
269             List<X509Certificate> issuersList = new LinkedList<>();
270             X509Certificate[] issuers = tm.getAcceptedIssuers();
271             for (int i = 0; i < 800; i += issuers.length) {
272                 for (X509Certificate issuer : issuers) {
273                     issuersList.add(issuer);
274                 }
275             }
276 
277             return issuersList.toArray(issuers);
278         }
279 
280         @Override
checkClientTrusted(X509Certificate[] chain, String authType, Socket socket)281         public void checkClientTrusted(X509Certificate[] chain, String authType,
282                 Socket socket) throws CertificateException {
283             clientChecked = true;
284             tm.checkClientTrusted(chain, authType);
285         }
286 
287         @Override
checkServerTrusted(X509Certificate[] chain, String authType, Socket socket)288         public void checkServerTrusted(X509Certificate[] chain, String authType,
289                 Socket socket) throws CertificateException {
290             serverChecked = true;
291             tm.checkServerTrusted(chain, authType);
292         }
293 
294         @Override
checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine engine)295         public void checkClientTrusted(X509Certificate[] chain, String authType,
296             SSLEngine engine) throws CertificateException {
297             clientChecked = true;
298             tm.checkClientTrusted(chain, authType);
299         }
300 
301         @Override
checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine engine)302         public void checkServerTrusted(X509Certificate[] chain, String authType,
303             SSLEngine engine) throws CertificateException {
304             serverChecked = true;
305             tm.checkServerTrusted(chain, authType);
306         }
307     }
308 
309     /*
310      * =============================================================
311      * The remainder is just support stuff
312      */
313 
314     // use any free port by default
315     volatile int serverPort = 0;
316 
317     volatile Exception serverException = null;
318     volatile Exception clientException = null;
319 
main(String[] args)320     public static void main(String[] args) throws Exception {
321 
322         if (debug)
323             System.setProperty("javax.net.debug", "all");
324 
325         /*
326          * Start the tests.
327          */
328         new CertRequestOverflow();
329     }
330 
331     Thread clientThread = null;
332     Thread serverThread = null;
333 
334     /*
335      * Primary constructor, used to drive remainder of the test.
336      *
337      * Fork off the other side, then do your work.
338      */
CertRequestOverflow()339     CertRequestOverflow() throws Exception {
340         if (separateServerThread) {
341             startServer(true);
342             startClient(false);
343         } else {
344             startClient(true);
345             startServer(false);
346         }
347 
348         /*
349          * Wait for other side to close down.
350          */
351         if (separateServerThread) {
352             serverThread.join();
353         } else {
354             clientThread.join();
355         }
356 
357         /*
358          * When we get here, the test is pretty much over.
359          *
360          * If the main thread excepted, that propagates back
361          * immediately.  If the other thread threw an exception, we
362          * should report back.
363          */
364         if (serverException != null)
365             throw serverException;
366         if (clientException != null)
367             throw clientException;
368     }
369 
startServer(boolean newThread)370     void startServer(boolean newThread) throws Exception {
371         if (newThread) {
372             serverThread = new Thread() {
373                 @Override
374                 public void run() {
375                     try {
376                         doServerSide();
377                     } catch (Exception e) {
378                         /*
379                          * Our server thread just died.
380                          *
381                          * Release the client, if not active already...
382                          */
383                         System.err.println("Server died...");
384                         serverReady = true;
385                         serverException = e;
386                     }
387                 }
388             };
389             serverThread.start();
390         } else {
391             doServerSide();
392         }
393     }
394 
startClient(boolean newThread)395     void startClient(boolean newThread) throws Exception {
396         if (newThread) {
397             clientThread = new Thread() {
398                 @Override
399                 public void run() {
400                     try {
401                         doClientSide();
402                     } catch (Exception e) {
403                         /*
404               * Our client thread just died.
405                          */
406                         System.err.println("Client died...");
407                         clientException = e;
408                     }
409                 }
410             };
411             clientThread.start();
412         } else {
413             doClientSide();
414         }
415     }
416 }
417 
418