8229481: sun/net/www/protocol/https/ChunkedOutputStream.java failed with a SSLException
authordfuchs
Fri, 16 Aug 2019 15:01:58 +0100
changeset 57778 6768b0f490df
parent 57777 90ead0febf56
child 57779 0a8407a78a2f
8229481: sun/net/www/protocol/https/ChunkedOutputStream.java failed with a SSLException Summary: The test is updated to ignore plain text connections Reviewed-by: chegar, michaelm
test/jdk/sun/net/www/protocol/https/ChunkedOutputStream.java
test/jdk/sun/net/www/protocol/https/HttpCallback.java
test/jdk/sun/net/www/protocol/https/TestHttpsServer.java
--- a/test/jdk/sun/net/www/protocol/https/ChunkedOutputStream.java	Tue Aug 06 10:48:21 2019 +0200
+++ b/test/jdk/sun/net/www/protocol/https/ChunkedOutputStream.java	Fri Aug 16 15:01:58 2019 +0100
@@ -37,6 +37,7 @@
 import java.io.*;
 import java.net.*;
 import javax.net.ssl.*;
+import java.util.concurrent.atomic.AtomicInteger;
 
 public class ChunkedOutputStream implements HttpCallback {
     /*
@@ -47,6 +48,7 @@
     static String trustStoreFile = "truststore";
     static String passwd = "passphrase";
     static int count = 0;
+    static final AtomicInteger rogueCount = new AtomicInteger();
 
     static final String str1 = "Helloworld1234567890abcdefghijklmnopqrstuvwxyz"+
                                 "1234567890abcdefkjsdlkjflkjsldkfjlsdkjflkj"+
@@ -132,12 +134,23 @@
                 req.sendResponse(200, "OK");
                 req.orderlyClose();
                 break;
+            default:
+                req.sendResponse(404, "Not Found");
+                req.orderlyClose();
+                break;
             }
         } catch (IOException e) {
             e.printStackTrace();
         }
     }
 
+    public boolean dropPlainTextConnections() {
+        System.out.println("Unrecognized SSL message, plaintext connection?");
+        System.out.println("TestHttpsServer receveived rogue connection: ignoring it.");
+        rogueCount.incrementAndGet();
+        return true;
+    }
+
     static void readAndCompare(InputStream is, String cmp) throws IOException {
         int c;
         byte buf[] = new byte[1024];
@@ -153,6 +166,26 @@
         }
     }
 
+    /* basic smoke test: verify that server drops plain connections */
+    static void testPlainText(String authority) throws Exception {
+        URL url = new URL("http://" + authority + "/Donauschiffsgesellschaftskapitaenskajuete");
+        System.out.println("client opening connection to: " + url);
+        HttpURLConnection urlc = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
+        int rogue = rogueCount.get();
+        try {
+            int code  = urlc.getResponseCode();
+            System.out.println("Unexpected response: " + code);
+            throw new AssertionError("Unexpected response: " + code);
+        } catch (SocketException x) {
+            // we expect that the server will drop the connection and
+            // close the accepted socket, so we should get a SocketException
+            // on the client side, and confirm that this::dropPlainTextConnections
+            // has ben called.
+            if (rogueCount.get() == rogue) throw x;
+            System.out.println("Got expected exception: " + x);
+        }
+    }
+
     /* basic chunked test (runs twice) */
 
     static void test1(String u) throws Exception {
@@ -303,6 +336,7 @@
                 server = new TestHttpsServer(
                         new ChunkedOutputStream(), 1, 10, loopback, 0);
                 System.out.println("Server started: listening on: " + server.getAuthority());
+                testPlainText(server.getAuthority());
                 // the test server doesn't support keep-alive yet
                 // test1("http://" + server.getAuthority() + "/d0");
                 test1("https://" + server.getAuthority() + "/d01");
--- a/test/jdk/sun/net/www/protocol/https/HttpCallback.java	Tue Aug 06 10:48:21 2019 +0200
+++ b/test/jdk/sun/net/www/protocol/https/HttpCallback.java	Fri Aug 16 15:01:58 2019 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -36,4 +36,15 @@
      *        client and used to send the response
      */
     void request (HttpTransaction msg);
+
+    /**
+     * Tells whether the server should simply close the
+     * connection and ignore the request when the first
+     * byte received by the server looks like a plain
+     * text connection.
+     * @return true if the request should be ignored.
+     **/
+    default boolean dropPlainTextConnections() {
+        return false;
+    }
 }
--- a/test/jdk/sun/net/www/protocol/https/TestHttpsServer.java	Tue Aug 06 10:48:21 2019 +0200
+++ b/test/jdk/sun/net/www/protocol/https/TestHttpsServer.java	Fri Aug 16 15:01:58 2019 +0100
@@ -316,6 +316,7 @@
         HttpCallback cb;
         HandshakeStatus currentHSStatus;
         boolean initialHSComplete;
+        boolean handshakeStarted;
         /*
          * All inbound data goes through this buffer.
          *
@@ -364,6 +365,25 @@
 
                     case NEED_UNWRAP:
                         int bytes = schan.read(inNetBB);
+                        if (!handshakeStarted && bytes > 0) {
+                            handshakeStarted = true;
+                            int byte0 = inNetBB.get(0);
+                            if (byte0 != 0x16) {
+                                // first byte of a TLS connection is supposed to be
+                                // 0x16. If not it may be a plain text connection.
+                                //
+                                // Sometime a rogue client may try to open a plain
+                                // connection with our server. Calling this method
+                                // gives a chance to the test logic to ignore such
+                                // rogue connections.
+                                //
+                                if (cb.dropPlainTextConnections()) {
+                                    try { schan.close(); } catch (IOException x) { };
+                                    return;
+                                }
+                                // else sslEng.unwrap will throw later on...
+                            }
+                        }
 
 needIO:
                         while (currentHSStatus == HandshakeStatus.NEED_UNWRAP) {