src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java

Print this page
8144566 Custom HostnameVerifier disables SNI extension

@@ -208,10 +208,16 @@
     List<SNIServerName>         serverNames =
                                     Collections.<SNIServerName>emptyList();
     Collection<SNIMatcher>      sniMatchers =
                                     Collections.<SNIMatcher>emptyList();
 
+    // Is the serverNames set to empty with SSLParameters.setServerNames()?
+    private boolean             noSniExtension = false;
+
+    // Is the sniMatchers set to empty with SSLParameters.setSNIMatchers()?
+    private boolean             noSniMatcher = false;
+
     // Configured application protocol values
     String[] applicationProtocols = new String[0];
 
     // Negotiated application protocol value.
     //

@@ -652,10 +658,15 @@
             throw new SocketException(
                                   "Cannot handle non-Inet socket addresses.");
         }
 
         super.connect(endpoint, timeout);
+
+        if (host == null || host.length() == 0) {
+            useImplicitHost(false);
+        }
+
         doneConnect();
     }
 
     /**
      * Initialize the handshaker and socket streams.

@@ -2083,57 +2094,85 @@
     synchronized void setVersion(ProtocolVersion protocolVersion) {
         this.protocolVersion = protocolVersion;
         outputRecord.setVersion(protocolVersion);
     }
 
+    //
+    // ONLY used by ClientHandshaker for the server hostname during handshaling
+    //
     synchronized String getHost() {
         // Note that the host may be null or empty for localhost.
         if (host == null || host.length() == 0) {
-            if (!trustNameService) {
-                // If the local name service is not trustworthy, reverse host
-                // name resolution should not be performed for endpoint
-                // identification.  Use the application original specified
-                // hostname or IP address instead.
-                host = getOriginalHostname(getInetAddress());
-            } else {
-                host = getInetAddress().getHostName();
+            useImplicitHost(true);
             }
-        }
 
         return host;
     }
 
     /*
-     * Get the original application specified hostname.
+     * Try to set and use the implicit specified hostname
      */
-    private static String getOriginalHostname(InetAddress inetAddress) {
-        /*
-         * Get the original hostname via jdk.internal.misc.SharedSecrets.
-         */
-        JavaNetInetAddressAccess jna = SharedSecrets.getJavaNetInetAddressAccess();
+    synchronized private void useImplicitHost(boolean noSniUpdate) {
+        if ((host != null) && (host.length() != 0)) {
+            return;
+        }
+
+        // Note: If the local name service is not trustworthy, reverse
+        // host name resolution should not be performed for endpoint
+        // identification.  Use the application original specified
+        // hostname or IP address instead.
+
+        // Get the original hostname via jdk.internal.misc.SharedSecrets
+        InetAddress inetAddress = getInetAddress();
+        if (inetAddress == null) {      // not connected
+            return;
+        }
+
+        JavaNetInetAddressAccess jna =
+                SharedSecrets.getJavaNetInetAddressAccess();
         String originalHostname = jna.getOriginalHostName(inetAddress);
+        if ((originalHostname != null) &&
+                (originalHostname.length() != 0)) {
 
-        /*
-         * If no application specified hostname, use the IP address.
-         */
-        if (originalHostname == null || originalHostname.length() == 0) {
-            originalHostname = inetAddress.getHostAddress();
+            host = originalHostname;
+            if (!noSniUpdate && serverNames.isEmpty() && !noSniExtension) {
+                serverNames =
+                        Utilities.addToSNIServerNameList(serverNames, host);
+
+                if (!roleIsServer &&
+                        (handshaker != null) && !handshaker.started()) {
+                    handshaker.setSNIServerNames(serverNames);
         }
+            }
 
-        return originalHostname;
+            return;
     }
 
+        // No explicitly specified hostname, no sserver name indication.
+        if (!trustNameService) {
+            // The local name service is not trustworthy, use IP address.
+            host = inetAddress.getHostAddress();
+        } else {
+            // Use the underlying reverse host name resolution service.
+            host = getInetAddress().getHostName();
+        }
+    }
+
     // ONLY used by HttpsClient to setup the URI specified hostname
     //
     // Please NOTE that this method MUST be called before calling to
     // SSLSocket.setSSLParameters(). Otherwise, the {@code host} parameter
     // may override SNIHostName in the customized server name indication.
     public synchronized void setHost(String host) {
         this.host = host;
         this.serverNames =
             Utilities.addToSNIServerNameList(this.serverNames, this.host);
+
+        if (!roleIsServer && (handshaker != null) && !handshaker.started()) {
+            handshaker.setSNIServerNames(serverNames);
     }
+    }
 
     /**
      * Gets an input stream to read from the peer on the other side.
      * Data read from this stream was always integrity protected in
      * transit, and will usually have been confidentiality protected.

@@ -2518,12 +2557,25 @@
         SSLParameters params = super.getSSLParameters();
 
         // the super implementation does not handle the following parameters
         params.setEndpointIdentificationAlgorithm(identificationProtocol);
         params.setAlgorithmConstraints(algorithmConstraints);
+
+        if (sniMatchers.isEmpty() && !noSniMatcher) {
+            // 'null' indicates none has been set
+            params.setSNIMatchers(null);
+        } else {
         params.setSNIMatchers(sniMatchers);
+        }
+
+        if (serverNames.isEmpty() && !noSniExtension) {
+            // 'null' indicates none has been set
+            params.setServerNames(null);
+        } else {
         params.setServerNames(serverNames);
+        }
+
         params.setUseCipherSuitesOrder(preferLocalCipherSuites);
         params.setMaximumPacketSize(maximumPacketSize);
         params.setApplicationProtocols(applicationProtocols);
 
         // DTLS handshake retransmissions parameter does not apply here.

@@ -2553,15 +2605,25 @@
             maximumPacketSize = outputRecord.getMaxPacketSize();
         }
 
         List<SNIServerName> sniNames = params.getServerNames();
         if (sniNames != null) {
+            if (sniNames.isEmpty()) {
+                // need no SNI extension
+                noSniExtension = true;
+            }   // Otherwise, need not to set noSniExtension
+
             serverNames = sniNames;
         }
 
         Collection<SNIMatcher> matchers = params.getSNIMatchers();
         if (matchers != null) {
+            if (matchers.isEmpty()) {
+                // need no SNI matcher
+                noSniMatcher = true;
+            }   // Otherwise, need not to set noSniMatcher
+
             sniMatchers = matchers;
         }
 
         applicationProtocols = params.getApplicationProtocols();