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
--- 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) {