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 }
--- EOF ---