JDK-6618387 : SSL client sessions do not close cleanly. A TCP reset occurs instead of a close_notify alert.
  • Type: Bug
  • Component: security-libs
  • Sub-Component: javax.net.ssl
  • Affected Version: 5.0u15
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: solaris_7
  • CPU: sparc
  • Submitted: 2007-10-18
  • Updated: 2011-03-07
  • Resolved: 2011-03-07
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other JDK 6 JDK 7
1.4.2_18-revFixed 6u10Fixed 7 b25Fixed
Description
Note, this bug is being reported agains 1.5.

We are trying to make a connection to a web server using httpsURLConnection.
However when we close the SSL session. A close_notify message is not generated.
[
SSL 3.0 specification
5.4.1 Closure alerts

   The client and the server must share knowledge that the connection
   is ending in order to avoid a truncation attack.  Either party may
   initiate the exchange of closing messages.

     close_notify      This message notifies the recipient that the
                       sender will not send any more messages on this
                       connection.  The session becomes unresumable if
                       any connection is terminated without proper
                       close_notify messages with level equal to
                       warning.

   Either party may initiate a close by sending a close_notify alert.
   Any data received after a closure alert is ignored.

   Each party is required to send a close_notify alert before closing
   the write side of the connection.  It is required that the other
   party respond with a close_notify alert of its own and close down
   the connection immediately, discarding any pending writes.  It is
   not required for the initiator of the close to wait for the
   responding close_notify alert before closing the read side of the
   connection.

   NB: It is assumed that closing a connection reliably delivers
   pending data before destroying the transport.

http://java.sun.com/j2se/1.5.0/docs/guide/security/jsse/JSSERefGuide.html#SSLOverview
< http://java.sun.com/j2se/1.5.0/docs/guide/security/jsse/JSSERefGuide.html>

For an orderly shutdown of an SSL/TLS connection, the SSL/TLS protocols require
transmission of close messages. Therefore, when an application is done with
the SSL/TLS connection, it should first obtain the close messages from the SSLEngine,
then transmit them to the peer using its transport mechanism, and finally shut
down the transport mechanism.


JavaTM Secure Socket Extension (JSSE)Reference Guidefor the JavaTM 2 Platform Standard Edition 5
Close Messages - At the end of the connection, each side will send a close_notify message to inform the peer that the connection is closed.

Analysis

During the close,if the KeepAliveConnections(maxRequest) is 0  or if the value of the Connection is close, close_notify message is generated.However when we try to close, with the KeepAliveConnections >0. Then there is no close_notify message

Looking into the KeepAliveStream.java file and HttpClient.java, and have observed that while closing this stream if the KeepAliveConnections>0 . The value is stored in the cache.

KeepAliveConnection.java
if (closed) {
            return;
        }

        // Skip past the data that's left in the Inputstream because
        // some sort of error may have occurred.
        // Do this ONLY if the skip won't block. The stream may have
        // been closed at the beginning of a big file and we don't want
        // to hang around for nothing. So if we can't skip without blocking
        // we just close the socket and, therefore, terminate the keepAlive
        // NOTE: Don't close super class
        try {
               
            if (expected > count) {
                long nskip = (long) (expected - count);
                if (nskip <= available()) {
                    long n = 0;
                    while (n < nskip) {
                        nskip = nskip - n;
                        n = skip(nskip);
                    }
                } else {
                    hc.closeServer();
                }
            }         
            if (!closed && !hurried) {
                hc.finished();
            }
        } finally {        
            if (pi != null)
                pi.finishTracking();
       
            // nulling out the underlying inputstream as well as
            // httpClient to let gc collect the memories faster
                in = null;
                hc = null;
                closed = true;
        }


HttpClient.java
if (keepAliveConnections > 0 && isKeepingAlive() &&
               !(serverOutput.checkError())) {
            /* This connection is keepingAlive && still valid.
             * Return it to the cache.
             */
            putInKeepAliveCache();
        } else {
                    closeServer();
        }
 

Looking into the code of sun.net.www.protocol.http.HttpURLConnection.java for the disconnect method to find whether it had any code which could do a proper SSL shutdown.  It has code for the purpose mentioned in it���s comment

if (http != null) {
            /*
             * If we have an input stream this means we received a response
             * from the server. That stream may have been read to EOF and
             * dependening on the stream type may already be closed or the
             * the http client may be returned to the keep-alive cache.
             * If the http client has been returned to the keep-alive cache
             * it may be closed (idle timeout) or may be allocated to
             * another request.
             *
             * In other to avoid timing issues we close the input stream
             * which will either close the underlying connection or return
             * the client to the cache. If there's a possibility that the
             * client has been returned to the cache (ie: stream is a keep
             * alive stream or a chunked input stream) then we remove an
             * idle connection to the server. Note that this approach
             * can be considered an approximation in that we may close a
             * different idle connection to that used by the request.
             * Additionally it's possible that we close two connections
             * - the first becuase it wasn't an EOF (and couldn't be
             * hurried) - the second, another idle connection to the
             * same server. The is okay because "disconnect" is an
             * indication that the application doesn't intend to access
             * this http server for a while.
             */

In our case the value of http is null. As a result of which it does not enter the loop. Hence no code is executed to do the proper SSL Shutdown.

We require a close_notify alert to have a orderly shutdown of an SSL/TLS connection, which is not observed in the above case.

Comments
EVALUATION The closeIdleConnection() failed to query the correct cached connections from keep-alive cache, so disconnet() will not be able to close the underlying cached connections. Override the method in HttpsClient, and make the query by the way it cached.
16-03-2008

EVALUATION Re-opening this bug: It was fixed by Andrew for JDK 7, he is working on backport to 6.0: (Comments from Andrew) I just got the response this morning, it's accepted as a bug. I will fix it as soon as possible. By the fix, the httpsURLConnection.disconnect() will close the underlying socket. You can get the updates from webrev: http://sceri.prc.sun.com/~xf138604/bugbios/6618387/webrev/ But in order to close the cached connection with httpURLConnection.disconnect(), the application should not call inputstream.close() explicitly, refer to the comment in the webrev test CloseKeepAliveCached.doClientSide(). I think we need to tell HP in order to avoid the close() calling before disconnection(). Andrew
18-01-2008

EVALUATION the close_notify will be send after a few seconds if keep alive, it is not a bug.
05-12-2007