1 /* 2 * Copyright (c) 2012, 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 */ 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 100 // enable endpoint identification 101 // ignore, we may test the feature when known how to parse client 102 // hostname 103 //SSLParameters params = sslServerSocket.getSSLParameters(); 104 //params.setEndpointIdentificationAlgorithm("HTTPS"); 105 //sslServerSocket.setSSLParameters(params); 106 107 /* 108 * Signal Client, we're ready for his connect. 109 */ 110 serverReady = true; 111 112 SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept(); 113 sslSocket.setNeedClientAuth(true); 114 InputStream sslIS = sslSocket.getInputStream(); 115 OutputStream sslOS = sslSocket.getOutputStream(); 116 117 try { 118 sslIS.read(); 119 sslOS.write(85); 120 sslOS.flush(); 121 122 throw new Exception("SERVER TEST FAILED! " + 123 "It is expected to fail with field length overflow"); 124 } catch (SSLException ssle) { 125 Throwable cause = ssle.getCause(); 126 if (!(cause instanceof RuntimeException)) { 127 System.out.println("We are expecting a RuntimeException!"); 128 throw ssle; 129 } 130 System.out.println("The expected exception! " + ssle); 131 } finally { 132 sslSocket.close(); 133 } 134 135 System.out.println("SERVER TEST PASSED!"); 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 = getContext(false).getSocketFactory(); 154 SSLSocket sslSocket = (SSLSocket) 155 sslsf.createSocket("localhost", serverPort); 156 157 // enable endpoint identification 158 SSLParameters params = sslSocket.getSSLParameters(); 159 params.setEndpointIdentificationAlgorithm("HTTPS"); 160 sslSocket.setSSLParameters(params); 161 162 InputStream sslIS = sslSocket.getInputStream(); 163 OutputStream sslOS = sslSocket.getOutputStream(); 164 165 try { 166 sslOS.write(280); 167 sslOS.flush(); 168 sslIS.read(); 169 } catch (SSLException ssle) { 170 System.out.println("An expected exception!"); 171 } finally { 172 sslSocket.close(); 173 } 174 } 175 176 MyExtendedX509TM serverTM; 177 MyExtendedX509TM clientTM; 178 179 private SSLContext getContext(boolean server) throws Exception { 180 String keyFilename = 181 System.getProperty("test.src", "./") + "/" + pathToStores + 182 "/" + keyStoreFile; 183 String trustFilename = 184 System.getProperty("test.src", "./") + "/" + pathToStores + 185 "/" + trustStoreFile; 186 187 KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); 188 KeyStore ks = KeyStore.getInstance("JKS"); 189 ks.load(new FileInputStream(keyFilename), cpasswd); 190 kmf.init(ks, cpasswd); 191 192 TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); 193 KeyStore ts = KeyStore.getInstance("JKS"); 194 ts.load(new FileInputStream(trustFilename), cpasswd); 195 tmf.init(ts); 196 197 TrustManager tms[] = tmf.getTrustManagers(); 198 if (tms == null || tms.length == 0) { 199 throw new Exception("unexpected trust manager implementation"); 200 } else { 201 if (!(tms[0] instanceof X509TrustManager)) { 202 throw new Exception("unexpected trust manager implementation: " 203 + tms[0].getClass().getCanonicalName()); 204 } 205 } 206 207 if (server) { 208 serverTM = new MyExtendedX509TM((X509TrustManager)tms[0]); 209 210 tms = new TrustManager[] {serverTM}; 211 } else { 212 clientTM = new MyExtendedX509TM((X509TrustManager)tms[0]); 213 214 tms = new TrustManager[] {clientTM}; 215 } 216 217 SSLContext ctx = SSLContext.getInstance("TLS"); 218 ctx.init(kmf.getKeyManagers(), tms, null); 219 220 return ctx; 221 } 222 223 static class MyExtendedX509TM extends X509ExtendedTrustManager 224 implements X509TrustManager { 225 226 X509TrustManager tm; 227 228 boolean clientChecked; 229 boolean serverChecked; 230 231 MyExtendedX509TM(X509TrustManager tm) { 232 clientChecked = false; 233 serverChecked = false; 234 235 this.tm = tm; 236 } 237 238 public boolean wasClientChecked() { 239 return clientChecked; 240 } 241 242 public boolean wasServerChecked() { 243 return serverChecked; 244 } 245 246 247 public void checkClientTrusted(X509Certificate chain[], String authType) 248 throws CertificateException { 249 tm.checkClientTrusted(chain, authType); 250 } 251 252 public void checkServerTrusted(X509Certificate chain[], String authType) 253 throws CertificateException { 254 tm.checkServerTrusted(chain, authType); 255 } 256 257 public X509Certificate[] getAcceptedIssuers() { 258 // (hack code) increase the size of the returned array to make a 259 // overflow CertificateRequest. 260 List<X509Certificate> issuersList = new LinkedList<>(); 261 X509Certificate[] issuers = tm.getAcceptedIssuers(); 262 for (int i = 0; i < 800; i += issuers.length) { 263 for (X509Certificate issuer : issuers) { 264 issuersList.add(issuer); 265 } 266 } 267 268 return issuersList.toArray(issuers); 269 } 270 271 public void checkClientTrusted(X509Certificate[] chain, String authType, 272 Socket socket) throws CertificateException { 273 clientChecked = true; 274 tm.checkClientTrusted(chain, authType); 275 } 276 277 public void checkServerTrusted(X509Certificate[] chain, String authType, 278 Socket socket) throws CertificateException { 279 serverChecked = true; 280 tm.checkServerTrusted(chain, authType); 281 } 282 283 public void checkClientTrusted(X509Certificate[] chain, String authType, 284 SSLEngine engine) throws CertificateException { 285 clientChecked = true; 286 tm.checkClientTrusted(chain, authType); 287 } 288 289 public void checkServerTrusted(X509Certificate[] chain, String authType, 290 SSLEngine engine) throws CertificateException { 291 serverChecked = true; 292 tm.checkServerTrusted(chain, authType); 293 } 294 } 295 296 /* 297 * ============================================================= 298 * The remainder is just support stuff 299 */ 300 301 // use any free port by default 302 volatile int serverPort = 0; 303 304 volatile Exception serverException = null; 305 volatile Exception clientException = null; 306 307 public static void main(String[] args) throws Exception { 308 309 if (debug) 310 System.setProperty("javax.net.debug", "all"); 311 312 /* 313 * Start the tests. 314 */ 315 new CertRequestOverflow(); 316 } 317 318 Thread clientThread = null; 319 Thread serverThread = null; 320 321 /* 322 * Primary constructor, used to drive remainder of the test. 323 * 324 * Fork off the other side, then do your work. 325 */ 326 CertRequestOverflow() throws Exception { 327 if (separateServerThread) { 328 startServer(true); 329 startClient(false); 330 } else { 331 startClient(true); 332 startServer(false); 333 } 334 335 /* 336 * Wait for other side to close down. 337 */ 338 if (separateServerThread) { 339 serverThread.join(); 340 } else { 341 clientThread.join(); 342 } 343 344 /* 345 * When we get here, the test is pretty much over. 346 * 347 * If the main thread excepted, that propagates back 348 * immediately. If the other thread threw an exception, we 349 * should report back. 350 */ 351 if (serverException != null) 352 throw serverException; 353 if (clientException != null) 354 throw clientException; 355 } 356 357 void startServer(boolean newThread) throws Exception { 358 if (newThread) { 359 serverThread = new Thread() { 360 public void run() { 361 try { 362 doServerSide(); 363 } catch (Exception e) { 364 /* 365 * Our server thread just died. 366 * 367 * Release the client, if not active already... 368 */ 369 System.err.println("Server died..."); 370 serverReady = true; 371 serverException = e; 372 } 373 } 374 }; 375 serverThread.start(); 376 } else { 377 doServerSide(); 378 } 379 } 380 381 void startClient(boolean newThread) throws Exception { 382 if (newThread) { 383 clientThread = new Thread() { 384 public void run() { 385 try { 386 doClientSide(); 387 } catch (Exception e) { 388 /* 389 * Our client thread just died. 390 */ 391 System.err.println("Client died..."); 392 clientException = e; 393 } 394 } 395 }; 396 clientThread.start(); 397 } else { 398 doClientSide(); 399 } 400 } 401 } 402