Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4453053

If a server shuts down correctly during handshaking, the client doesn't see it.

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P2 P2
    • 1.4.0
    • unknown
    • security-libs
    • beta2
    • generic
    • generic

      This is generic to our impelemtnation, however it is most easily reproduced
      with a bad client chain.

      The server requires client auth, but the client
      doesn't provide any, the server sends a bad cert fatal error,
      but the client never sees it. The client is too busy
      trying to write a change cipher suite, or something similar.
      The result is a broken pipe error.

      See the attachments for the test output.

      Exception in thread "main" java.io.IOException: Broken pipe
      at java.net.SocketOutputStream.socketWrite0(Native Method)
      at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:95)
      at java.net.SocketOutputStream.write(SocketOutputStream.java:129)
      at com.sun.net.ssl.internal.ssl.OutputRecord.a([DashoPro-V1.2-120198])
      at com.sun.net.ssl.internal.ssl.SSLSocketImpl.a([DashoPro-V1.2-120198])
      at com.sun.net.ssl.internal.ssl.HandshakeOutStream.flush([DashoPro-V1.2-120198])
      at com.sun.net.ssl.internal.ssl.Handshaker.sendChangeCipherSpec([DashoPro-V1.2-120198])
      at com.sun.net.ssl.internal.ssl.ClientHandshaker.e([DashoPro-V1.2-120198])
      at com.sun.net.ssl.internal.ssl.ClientHandshaker.a([DashoPro-V1.2-120198])
      at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage([DashoPro-V1.2-120198])
      at com.sun.net.ssl.internal.ssl.Handshaker.process_record([DashoPro-V1.2-120198])
      at com.sun.net.ssl.internal.ssl.SSLSocketImpl.a([DashoPro-V1.2-120198])
      at com.sun.net.ssl.internal.ssl.SSLSocketImpl.a([DashoPro-V1.2-120198])
      at com.sun.net.ssl.internal.ssl.AppOutputStream.flush([DashoPro-V1.2-120198])
      at foo.doClientSide(foo.java:132)
      at foo.startClient(foo.java:258)
      at foo.<init>(foo.java:185)
      at foo.main(foo.java:171)

      This is a race condition, I did it on a U60 (bongos).

      Brad


      /*
       * @test %I% %E%
       * @bug 1234567
       * @summary Use this template to help speed your client/server tests.
       * @author Brad Wetmore
       */

      import java.io.*;
      import java.net.*;
      import java.security.*;
      import javax.net.ssl.*;

      public class foo {

          /*
           * =============================================================
           * Set the various variables needed for the tests, then
           * specify what tests to run on each side.
           */

          /*
           * Should we run the client or server in a separate thread?
           * Both sides can throw exceptions, but do you have a preference
           * as to which side should be the main thread.
           */
          static boolean separateServerThread = true;

          /*
           * Where do we find the keystores?
           */
          final static String pathToStores = "../etc";
          final static String keyStoreFile = "keystore";
          final static String trustStoreFile = "truststore";
          final static String passwd = "passphrase";
          final static char[] cpasswd = "passphrase".toCharArray();

          /*
           * Is the server ready to serve?
           */
          volatile static boolean serverReady = false;

          /*
           * Turn on SSL debugging?
           */
          final static boolean debug = false;

          /*
           * If the client or server is doing some kind of object creation
           * that the other side depends on, and that thread prematurely
           * exits, you may experience a hang. The test harness will
           * terminate all hung threads after its timeout has expired,
           * currently 3 minutes by default, but you might try to be
           * smart about it....
           */

          /*
           * Define the server side of the test.
           *
           * If the server prematurely exits, serverReady will be set to true
           * to avoid infinite hangs.
           */
          void doServerSide() throws Exception {
      SSLServerSocketFactory sslssf =
      (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
      SSLServerSocket sslServerSocket =
      (SSLServerSocket) sslssf.createServerSocket(serverPort, 3);
      sslServerSocket.setNeedClientAuth(true);

      /*
      * Signal Client, we're ready for his connect.
      */
      serverReady = true;

      SSLSocket sslSocket = (SSLSocket) sslServerSocket.accept();
      InputStream sslIS = sslSocket.getInputStream();
      OutputStream sslOS = sslSocket.getOutputStream();

      try {
      sslIS.read();
      sslOS.write(85);
      sslOS.flush();
      } catch (SSLException e) {
      System.out.println("Should see a null cert chain exception"
      + e.toString());
      }

      sslSocket.close();
      System.out.println("Server exiting!");
          }

          /*
           * Define the client side of the test.
           *
           * If the server prematurely exits, serverReady will be set to true
           * to avoid infinite hangs.
           */
          void doClientSide() throws Exception {

      /*
      * Wait for server to get started.
      */
      while (!serverReady) {
      Thread.sleep(5000);
      }

      System.out.println("Starting test");
      System.out.println("Should *NOT* see a broken pipe exception");

      KeyStore ks = KeyStore.getInstance("JKS");
      KeyStore uks = KeyStore.getInstance("JKS");
      SSLContext ctx = SSLContext.getInstance("TLS");
      KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
      TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");

      uks.load(new FileInputStream(unknownFilename), cpasswd);
      kmf.init(uks, cpasswd);

      ks.load(new FileInputStream(trustFilename), cpasswd);
      tmf.init(ks);

      ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

      SSLSocketFactory sslsf =
      (SSLSocketFactory) ctx.getSocketFactory();
      SSLSocket sslSocket = (SSLSocket)
      sslsf.createSocket("localhost", serverPort);

      InputStream sslIS = sslSocket.getInputStream();
      OutputStream sslOS = sslSocket.getOutputStream();

      sslOS.write(280);
      sslOS.flush();
      sslIS.read();

      sslSocket.close();
          }

          /*
           * =============================================================
           * The remainder is just support stuff
           */

          int serverPort = 2001;

          volatile Exception serverException = null;
          volatile Exception clientException = null;

          final static String keyFilename =
      System.getProperty("test.src", "./") + "/" + pathToStores +
      "/" + keyStoreFile;
          final static String trustFilename =
      System.getProperty("test.src", "./") + "/" + pathToStores +
      "/" + trustStoreFile;
          final static String unknownFilename =
      System.getProperty("test.src", "./") + "/" + pathToStores +
      "/" + "unknown_keystore";

          public static void main(String[] args) throws Exception {

      System.setProperty("javax.net.ssl.keyStore", keyFilename);
      System.setProperty("javax.net.ssl.keyStorePassword", passwd);
      System.setProperty("javax.net.ssl.trustStore", trustFilename);
      System.setProperty("javax.net.ssl.trustStorePassword", passwd);

      if (debug)
      System.setProperty("javax.net.debug", "all");

      /*
      * Start the tests.
      */
              new foo();
          }

          Thread clientThread = null;
          Thread serverThread = null;

          /*
           * Primary constructor, used to drive remainder of the test.
           *
           * Fork off the other side, then do your work.
           */
          foo() throws Exception {
      if (separateServerThread) {
      startServer(true);
      startClient(false);
      } else {
      startClient(true);
      startServer(false);
      }

      /*
      * Wait for other side to close down.
      */
      if (separateServerThread) {
      serverThread.join();
      } else {
      clientThread.join();
      }

      /*
      * When we get here, the test is pretty much over.
      *
      * If the main thread excepted, that propagates back
      * immediately. If the other thread threw an exception, we
      * should report back.
      */
      if (serverException != null) {
      System.out.print("Server Exception:");
      throw serverException;
      }
      if (clientException != null) {
      System.out.print("Client Exception:");
      throw clientException;
      }
          }

          void startServer(boolean newThread) throws Exception {
      if (newThread) {
      serverThread = new Thread() {
      public void run() {
      try {
      doServerSide();
      } catch (Exception e) {
      /*
      * Our server thread just died.
      *
      * Release the client, if not active already...
      */
      System.err.println("Server died...");
      serverReady = true;
      serverException = e;
      }
      }
      };
      serverThread.start();
      } else {
      doServerSide();
      }
          }

          void startClient(boolean newThread) throws Exception {
      if (newThread) {
      clientThread = new Thread() {
      public void run() {
      try {
      doClientSide();
      } catch (Exception e) {
      /*
      * Our client thread just died.
      */
      System.err.println("Client died...");
      clientException = e;
      }
      }
      };
      clientThread.start();
      } else {
      doClientSide();
      }
          }
      }

            rleesunw Rosanna Lee (Inactive)
            wetmore Bradford Wetmore
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: