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 ExportableBlockCipher 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.IOException; 47import java.io.InputStream; 48import java.io.OutputStream; 49import javax.net.ssl.SSLException; 50import javax.net.ssl.SSLHandshakeException; 51import javax.net.ssl.SSLServerSocket; 52import javax.net.ssl.SSLServerSocketFactory; 53import javax.net.ssl.SSLSocket; 54import javax.net.ssl.SSLSocketFactory; 55 56public class ExportableBlockCipher { 57 58 /* 59 * ============================================================= 60 * Set the various variables needed for the tests, then 61 * specify what tests to run on each side. 62 */ 63 64 /* 65 * Should we run the client or server in a separate thread? 66 * Both sides can throw exceptions, but do you have a preference 67 * as to which side should be the main thread. 68 */ 69 static boolean separateServerThread = false; 70 71 /* 72 * Where do we find the keystores? 73 */ 74 static String pathToStores = "../etc"; 75 static String keyStoreFile = "keystore"; 76 static String trustStoreFile = "truststore"; 77 static String passwd = "passphrase"; 78 79 /* 80 * Is the server ready to serve? 81 */ 82 volatile static boolean serverReady = false; 83 84 /* 85 * Turn on SSL debugging? 86 */ 87 static boolean debug = false; 88 89 /* 90 * If the client or server is doing some kind of object creation 91 * that the other side depends on, and that thread prematurely 92 * exits, you may experience a hang. The test harness will 93 * terminate all hung threads after its timeout has expired, 94 * currently 3 minutes by default, but you might try to be 95 * smart about it.... 96 */ 97 98 /* 99 * Define the server side of the test. 100 * 101 * If the server prematurely exits, serverReady will be set to true 102 * to avoid infinite hangs. 103 */ 104 void doServerSide() throws Exception { 105 SSLServerSocketFactory sslssf = 106 (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); 107 SSLServerSocket sslServerSocket = 108 (SSLServerSocket) sslssf.createServerSocket(serverPort); 109 110 serverPort = sslServerSocket.getLocalPort(); 111 112 /* 113 * Signal Client, we're ready for his connect. 114 */ 115 serverReady = true; 116 117 SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept(); 118 InputStream sslIS = sslSocket.getInputStream(); 119 OutputStream sslOS = sslSocket.getOutputStream(); 120 121 boolean interrupted = false; 122 try { 123 sslIS.read(); 124 sslOS.write('A'); 125 sslOS.flush(); 126 } catch (IOException ioe) { 127 // get the expected exception 128 interrupted = true; 129 } finally { 130 sslSocket.close(); 131 } 132 133 if (!interrupted) { 134 throw new SSLHandshakeException( 135 "A weak cipher suite is negotiated, " + 136 "TLSv1.1 must not negotiate the exportable cipher suites."); 137 } 138 } 139 140 /* 141 * Define the client side of the test. 142 * 143 * If the server prematurely exits, serverReady will be set to true 144 * to avoid infinite hangs. 145 */ 146 void doClientSide() throws Exception { 147 148 /* 149 * Wait for server to get started. 150 */ 151 while (!serverReady) { 152 Thread.sleep(50); 153 } 154 155 SSLSocketFactory sslsf = 156 (SSLSocketFactory) SSLSocketFactory.getDefault(); 157 SSLSocket sslSocket = (SSLSocket) 158 sslsf.createSocket("localhost", serverPort); 159 160 // enable TLSv1.1 only 161 sslSocket.setEnabledProtocols(new String[] {"TLSv1.1"}); 162 163 // enable a exportable block cipher 164 sslSocket.setEnabledCipherSuites( 165 new String[] {"SSL_RSA_EXPORT_WITH_DES40_CBC_SHA"}); 166 167 InputStream sslIS = sslSocket.getInputStream(); 168 OutputStream sslOS = sslSocket.getOutputStream(); 169 170 boolean interrupted = false; 171 try { 172 sslOS.write('B'); 173 sslOS.flush(); 174 sslIS.read(); 175 } catch (SSLException ssle) { 176 // get the expected exception 177 interrupted = true; 178 } finally { 179 sslSocket.close(); 180 } 181 182 if (!interrupted) { 183 throw new SSLHandshakeException( 184 "A weak cipher suite is negotiated, " + 185 "TLSv1.1 must not negotiate the exportable cipher suites."); 186 } 187 } 188 189 /* 190 * ============================================================= 191 * The remainder is just support stuff 192 */ 193 194 // use any free port by default 195 volatile int serverPort = 0; 196 197 volatile Exception serverException = null; 198 volatile Exception clientException = null; 199 200 public static void main(String[] args) throws Exception { 201 String keyFilename = 202 System.getProperty("test.src", ".") + "/" + pathToStores + 203 "/" + keyStoreFile; 204 String trustFilename = 205 System.getProperty("test.src", ".") + "/" + pathToStores + 206 "/" + trustStoreFile; 207 208 System.setProperty("javax.net.ssl.keyStore", keyFilename); 209 System.setProperty("javax.net.ssl.keyStorePassword", passwd); 210 System.setProperty("javax.net.ssl.trustStore", trustFilename); 211 System.setProperty("javax.net.ssl.trustStorePassword", passwd); 212 213 if (debug) 214 System.setProperty("javax.net.debug", "all"); 215 216 /* 217 * Start the tests. 218 */ 219 new ExportableBlockCipher(); 220 } 221 222 Thread clientThread = null; 223 Thread serverThread = null; 224 225 /* 226 * Primary constructor, used to drive remainder of the test. 227 * 228 * Fork off the other side, then do your work. 229 */ 230 ExportableBlockCipher() throws Exception { 231 try { 232 if (separateServerThread) { 233 startServer(true); 234 startClient(false); 235 } else { 236 startClient(true); 237 startServer(false); 238 } 239 } catch (Exception e) { 240 // swallow for now. Show later 241 } 242 243 /* 244 * Wait for other side to close down. 245 */ 246 if (separateServerThread) { 247 serverThread.join(); 248 } else { 249 clientThread.join(); 250 } 251 252 /* 253 * When we get here, the test is pretty much over. 254 * Which side threw the error? 255 */ 256 Exception local; 257 Exception remote; 258 String whichRemote; 259 260 if (separateServerThread) { 261 remote = serverException; 262 local = clientException; 263 whichRemote = "server"; 264 } else { 265 remote = clientException; 266 local = serverException; 267 whichRemote = "client"; 268 } 269 270 /* 271 * If both failed, return the curthread's exception, but also 272 * print the remote side Exception 273 */ 274 if ((local != null) && (remote != null)) { 275 System.out.println(whichRemote + " also threw:"); 276 remote.printStackTrace(); 277 System.out.println(); 278 throw local; 279 } 280 281 if (remote != null) { 282 throw remote; 283 } 284 285 if (local != null) { 286 throw local; 287 } 288 } 289 290 void startServer(boolean newThread) throws Exception { 291 if (newThread) { 292 serverThread = new Thread() { 293 public void run() { 294 try { 295 doServerSide(); 296 } catch (Exception e) { 297 /* 298 * Our server thread just died. 299 * 300 * Release the client, if not active already... 301 */ 302 System.err.println("Server died..."); 303 serverReady = true; 304 serverException = e; 305 } 306 } 307 }; 308 serverThread.start(); 309 } else { 310 try { 311 doServerSide(); 312 } catch (Exception e) { 313 serverException = e; 314 } finally { 315 serverReady = true; 316 } 317 } 318 } 319 320 void startClient(boolean newThread) throws Exception { 321 if (newThread) { 322 clientThread = new Thread() { 323 public void run() { 324 try { 325 doClientSide(); 326 } catch (Exception e) { 327 /* 328 * Our client thread just died. 329 */ 330 System.err.println("Client died..."); 331 clientException = e; 332 } 333 } 334 }; 335 clientThread.start(); 336 } else { 337 try { 338 doClientSide(); 339 } catch (Exception e) { 340 clientException = e; 341 } 342 } 343 } 344} 345