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 4474255 27 * @test 1.1 01/06/27 28 * @bug 4484246 29 * @summary When an application enables anonymous SSL cipher suite, 30 * Hostname verification is not required 31 * @run main/othervm ComHostnameVerifier 32 * 33 * SunJSSE does not support dynamic system properties, no way to re-use 34 * system properties in samevm/agentvm mode. 35 */ 36 37 import java.io.*; 38 import java.net.*; 39 import javax.net.ssl.*; 40 import javax.security.cert.*; 41 import com.sun.net.ssl.HostnameVerifier; 42 import com.sun.net.ssl.HttpsURLConnection; 43 44 /** 45 * Use com.net.net.ssl.HostnameVerifier 46 */ 47 public class ComHostnameVerifier { 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 = true; 61 62 /* 63 * Is the server ready to serve? 64 */ 65 volatile static boolean serverReady = false; 66 67 /* 68 * Turn on SSL debugging? 69 */ 70 static boolean debug = false; 71 72 /* 73 * If the client or server is doing some kind of object creation 74 * that the other side depends on, and that thread prematurely 75 * exits, you may experience a hang. The test harness will 76 * terminate all hung threads after its timeout has expired, 77 * currently 3 minutes by default, but you might try to be 78 * smart about it.... 79 */ 80 81 /** 82 * Returns the path to the file obtained from 83 * parsing the HTML header. 84 */ 85 private static String getPath(DataInputStream in) 86 throws IOException 87 { 88 String line = in.readLine(); 89 if (line == null) 90 return null; 91 String path = ""; 92 // extract class from GET line 93 if (line.startsWith("GET /")) { 94 line = line.substring(5, line.length()-1).trim(); 95 int index = line.indexOf(' '); 96 if (index != -1) { 97 path = line.substring(0, index); 98 } 99 } 100 101 // eat the rest of header 102 do { 103 line = in.readLine(); 104 } while ((line.length() != 0) && 105 (line.charAt(0) != '\r') && (line.charAt(0) != '\n')); 106 107 if (path.length() != 0) { 108 return path; 109 } else { 110 throw new IOException("Malformed Header"); 111 } 112 } 113 114 /** 115 * Returns an array of bytes containing the bytes for 116 * the file represented by the argument <b>path</b>. 117 * 118 * In our case, we just pretend to send something back. 119 * 120 * @return the bytes for the file 121 * @exception FileNotFoundException if the file corresponding 122 * to <b>path</b> could not be loaded. 123 */ 124 private byte[] getBytes(String path) 125 throws IOException 126 { 127 return "Hello world, I am here".getBytes(); 128 } 129 130 /* 131 * Define the server side of the test. 132 * 133 * If the server prematurely exits, serverReady will be set to true 134 * to avoid infinite hangs. 135 */ 136 void doServerSide() throws Exception { 137 138 SSLServerSocketFactory sslssf = 139 (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); 140 SSLServerSocket sslServerSocket = 141 (SSLServerSocket) sslssf.createServerSocket(serverPort); 142 serverPort = sslServerSocket.getLocalPort(); 143 144 String ciphers[]= { "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA" }; 145 sslServerSocket.setEnabledCipherSuites(ciphers); 146 147 /* 148 * Signal Client, we're ready for his connect. 149 */ 150 serverReady = true; 151 152 SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept(); 153 DataOutputStream out = 154 new DataOutputStream(sslSocket.getOutputStream()); 155 156 try { 157 // get path to class file from header 158 DataInputStream in = 159 new DataInputStream(sslSocket.getInputStream()); 160 String path = getPath(in); 161 // retrieve bytecodes 162 byte[] bytecodes = getBytes(path); 163 // send bytecodes in response (assumes HTTP/1.0 or later) 164 try { 165 out.writeBytes("HTTP/1.0 200 OK\r\n"); 166 out.writeBytes("Content-Length: " + bytecodes.length + "\r\n"); 167 out.writeBytes("Content-Type: text/html\r\n\r\n"); 168 out.write(bytecodes); 169 out.flush(); 170 } catch (IOException ie) { 171 ie.printStackTrace(); 172 return; 173 } 174 175 } catch (Exception e) { 176 e.printStackTrace(); 177 // write out error response 178 out.writeBytes("HTTP/1.0 400 " + e.getMessage() + "\r\n"); 179 out.writeBytes("Content-Type: text/html\r\n\r\n"); 180 out.flush(); 181 } finally { 182 // close the socket 183 System.out.println("Server closing socket"); 184 sslSocket.close(); 185 serverReady = false; 186 } 187 } 188 189 /* 190 * Define the client side of the test. 191 * 192 * If the server prematurely exits, serverReady will be set to true 193 * to avoid infinite hangs. 194 */ 195 void doClientSide() throws Exception { 196 /* 197 * Wait for server to get started. 198 */ 199 while (!serverReady) { 200 Thread.sleep(50); 201 } 202 203 System.setProperty("java.protocol.handler.pkgs", 204 "com.sun.net.ssl.internal.www.protocol"); 205 206 System.setProperty("https.cipherSuites", 207 "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA"); 208 209 // use the default hostname verifier 210 211 URL url = new URL("https://" + "localhost:" + serverPort + 212 "/etc/hosts"); 213 URLConnection urlc = url.openConnection(); 214 215 if (!(urlc instanceof com.sun.net.ssl.HttpsURLConnection)) { 216 throw new Exception( 217 "URLConnection ! instanceof " + 218 "com.sun.net.ssl.HttpsURLConnection"); 219 } 220 221 BufferedReader in = null; 222 try { 223 in = new BufferedReader(new InputStreamReader( 224 urlc.getInputStream())); 225 String inputLine; 226 System.out.print("Client reading... "); 227 while ((inputLine = in.readLine()) != null) 228 System.out.println(inputLine); 229 System.out.println("Cipher Suite: " + 230 ((HttpsURLConnection)urlc).getCipherSuite()); 231 in.close(); 232 } catch (SSLException e) { 233 if (in != null) 234 in.close(); 235 throw e; 236 } 237 System.out.println("Client reports: SUCCESS"); 238 } 239 240 /* 241 * ============================================================= 242 * The remainder is just support stuff 243 */ 244 245 // use any free port by default 246 volatile int serverPort = 0; 247 248 volatile Exception serverException = null; 249 volatile Exception clientException = null; 250 251 public static void main(String[] args) throws Exception { 252 253 if (debug) 254 System.setProperty("javax.net.debug", "all"); 255 256 /* 257 * Start the tests. 258 */ 259 new ComHostnameVerifier(); 260 } 261 262 Thread clientThread = null; 263 Thread serverThread = null; 264 265 /* 266 * Primary constructor, used to drive remainder of the test. 267 * 268 * Fork off the other side, then do your work. 269 */ 270 ComHostnameVerifier() throws Exception { 271 if (separateServerThread) { 272 startServer(true); 273 startClient(false); 274 } else { 275 startClient(true); 276 startServer(false); 277 } 278 279 /* 280 * Wait for other side to close down. 281 */ 282 if (separateServerThread) { 283 serverThread.join(); 284 } else { 285 clientThread.join(); 286 } 287 288 /* 289 * When we get here, the test is pretty much over. 290 * 291 * If the main thread excepted, that propagates back 292 * immediately. If the other thread threw an exception, we 293 * should report back. 294 */ 295 if (serverException != null) { 296 System.out.print("Server Exception:"); 297 throw serverException; 298 } 299 if (clientException != null) { 300 System.out.print("Client Exception:"); 301 throw clientException; 302 } 303 } 304 305 void startServer(boolean newThread) throws Exception { 306 if (newThread) { 307 serverThread = new Thread() { 308 public void run() { 309 try { 310 doServerSide(); 311 } catch (Exception e) { 312 /* 313 * Our server thread just died. 314 * 315 * Release the client, if not active already... 316 */ 317 System.err.println("Server died..."); 318 serverReady = true; 319 serverException = e; 320 } 321 } 322 }; 323 serverThread.start(); 324 } else { 325 doServerSide(); 326 } 327 } 328 329 void startClient(boolean newThread) throws Exception { 330 if (newThread) { 331 clientThread = new Thread() { 332 public void run() { 333 try { 334 doClientSide(); 335 } catch (Exception e) { 336 /* 337 * Our client thread just died. 338 */ 339 System.err.println("Client died..."); 340 clientException = e; 341 } 342 } 343 }; 344 clientThread.start(); 345 } else { 346 doClientSide(); 347 } 348 } 349 }