http-client-branch: Fixed 8200351: problem verifying certificate of literal IP address connection http-client-branch
authormichaelm
Thu, 29 Mar 2018 17:14:17 +0100
branchhttp-client-branch
changeset 56368 c10279a27b41
parent 56367 875d85699981
child 56369 24a8fafec3ff
http-client-branch: Fixed 8200351: problem verifying certificate of literal IP address connection
src/java.net.http/share/classes/jdk/internal/net/http/AbstractAsyncSSLConnection.java
src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java
test/jdk/java/net/httpclient/ssltest/CertificateTest.java
test/jdk/java/net/httpclient/ssltest/loopback.keystore
--- a/src/java.net.http/share/classes/jdk/internal/net/http/AbstractAsyncSSLConnection.java	Thu Mar 29 15:32:18 2018 +0100
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/AbstractAsyncSSLConnection.java	Thu Mar 29 17:14:17 2018 +0100
@@ -37,6 +37,7 @@
 import jdk.internal.net.http.common.SSLTube;
 import jdk.internal.net.http.common.Log;
 import jdk.internal.net.http.common.Utils;
+import static jdk.internal.net.http.common.Utils.ServerName;
 
 
 /**
@@ -69,14 +70,14 @@
 
     AbstractAsyncSSLConnection(InetSocketAddress addr,
                                HttpClientImpl client,
-                               String serverName, int port,
+                               ServerName serverName, int port,
                                String[] alpn) {
         super(addr, client);
-        this.serverName = serverName;
+        this.serverName = serverName.getName();
         SSLContext context = client.theSSLContext();
         sslParameters = createSSLParameters(client, serverName, alpn);
         Log.logParams(sslParameters);
-        engine = createEngine(context, serverName, port, sslParameters);
+        engine = createEngine(context, serverName.getName(), port, sslParameters);
     }
 
     abstract HttpConnection plainConnection();
@@ -90,7 +91,7 @@
     final SSLEngine getEngine() { return engine; }
 
     private static SSLParameters createSSLParameters(HttpClientImpl client,
-                                                     String serverName,
+                                                     ServerName serverName,
                                                      String[] alpn) {
         SSLParameters sslp = client.sslParameters();
         SSLParameters sslParameters = Utils.copySSLParameters(sslp);
@@ -103,8 +104,11 @@
         } else {
             Log.logSSL("AbstractAsyncSSLConnection: no applications set!");
         }
-        if (serverName != null) {
-            sslParameters.setServerNames(List.of(new SNIHostName(serverName)));
+        if (!serverName.isLiteral()) {
+            String name = serverName.getName();
+            if (name != null && name.length() > 0) {
+                sslParameters.setServerNames(List.of(new SNIHostName(name)));
+            }
         }
         return sslParameters;
     }
--- a/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java	Thu Mar 29 15:32:18 2018 +0100
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java	Thu Mar 29 17:14:17 2018 +0100
@@ -322,36 +322,37 @@
         return !token.isEmpty();
     }
 
+    public static class ServerName {
+        ServerName(String name, boolean isLiteral) {
+            this.name = name;
+            this.isLiteral = isLiteral;
+        }
+
+        final String name;
+        final boolean isLiteral;
+
+        public String getName() {
+            return name;
+        }
+
+        public boolean isLiteral() {
+            return isLiteral;
+        }
+    }
+
     /**
-     * If the address was created with a domain name, then return
-     * the domain name string. If created with a literal IP address
-     * then return null except if the literal is loopback.
-     * We do this to avoid doing a reverse lookup
-     * Used to populate the TLS SNI parameter. So, SNI is only set
-     * when a domain name was supplied except in case of loopback
-     * where we return "localhost".
+     * Analyse the given address and determine if it is literal or not,
+     * returning the address in String form.
      */
-    public static String getServerName(InetSocketAddress addr) {
+    public static ServerName getServerName(InetSocketAddress addr) {
         String host = addr.getHostString();
         byte[] literal = IPAddressUtil.textToNumericFormatV4(host);
         if (literal == null) {
-            // not IPv4 literal
+            // not IPv4 literal. Check IPv6
             literal = IPAddressUtil.textToNumericFormatV6(host);
-            if (literal == null) {
-                // not IPv6 literal. Must be domain name
-                return host;
-            } else { // check if loopback
-                if (isLoopbackLiteral(literal))
-                    return "localhost";
-                else
-                    return null;
-            }
+            return new ServerName(host, literal != null);
         } else {
-            // check if IPv4 loopback
-            if (isLoopbackLiteral(literal))
-                    return "localhost";
-                else
-                    return null;
+            return new ServerName(host, true);
         }
     }
 
--- a/test/jdk/java/net/httpclient/ssltest/CertificateTest.java	Thu Mar 29 15:32:18 2018 +0100
+++ b/test/jdk/java/net/httpclient/ssltest/CertificateTest.java	Thu Mar 29 17:14:17 2018 +0100
@@ -48,6 +48,7 @@
  * @run main/othervm
  *      -Djdk.internal.httpclient.disableHostnameVerification=xxyyzz
  *       CertificateTest bad.keystore expectFailure
+ * @run main/othervm CertificateTest loopback.keystore expectSuccess
  */
 
 /**
@@ -102,7 +103,11 @@
 
     static void test(String[] args) throws Exception
     {
-        String uri_s = "https://localhost:" + Integer.toString(port) + "/foo";
+        String uri_s;
+        if (args[0].equals("loopback.keystore"))
+            uri_s = "https://127.0.0.1:" + Integer.toString(port) + "/foo";
+        else
+            uri_s = "https://localhost:" + Integer.toString(port) + "/foo";
         String error = null;
         Exception exception = null;
         System.out.println("Making request to " + uri_s);
Binary file test/jdk/java/net/httpclient/ssltest/loopback.keystore has changed