Friday, November 09, 2007 6:00 AM
Today we're going to talk about SSL Closure Alerts in Internet Explorer. This is usually manifested as the user getting the "Page Cannot Be Displayed" error when connecting to a secure website hosted on a non-Microsoft Web Server. Before we get too deep into the analysis though, it is important to note that this issue cannot be accurately diagnosed without collecting a trace of the behavior.
So what exactly is the SSL Closure Alert? The SSL3 Closure Alert is a 23 byte packet that is sent by several kinds of servers to indicate that the SSL Session is being closed at the server even though the Keep-Alive headers indicate that the socket can be left open. Keep in mind that a "Connection: Keep-alive" header is read and handled at the HTTP protocol level, and not at the TCP level.
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. This is where the close_notify message comes into play. This message notifies the recipient that the sender will not send any more messages on this connection. The session cannot be resumed 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.
This is significant in the case of the close_notify packet because Internet Explorer will read the keep-alive header within the initial server response to keep the socket alive. Unfortunately, when the Server sends the close_notify packet to inform the client that the server is about the close the socket, the packet arrives but does not contain any TCP level flag informing Internet Explorer that the port is being closed (ACK FIN, RESET). Since Internet Explorer is unable to determine that close_notify data is not program data, the port is left open on the client.
The socket being left open can cause problems because, by default, Internet Explorer will have two Keep-Alive ports open to the server and the socket Retry count will be equal to 2. When the Socket receive occurs after the first attempt to send data, the SSL 3.0 closure alert (close_notify) is processed and the TCP closure is processed causing the first Keep-Alive port to be closed and the Retry count to be decremented. Since the retry count is not 0, there is another client request attempt to use the second Keep-Alive port. However, this too does not work because it has already been closed on the server and the retry count is decremented once again. At this point the retry count is now 0 and the error message is generated that indicates that the request could not be honored and the user receives the "Page cannot be displayed" error.
Here is the sequence of packets that you see in a Network trace:
Client Sends Request to Server on port.
Server Responds with the Data and contains Keep-Alive Header
Server Responds with the SSL3 Close Notify Message
Server Responds with TCP Flags A...F
Client Re-uses Port for next Request because the Keep-Alive Header was present.
Client Immediate Sends A...F
Server Sends TCP RESET for the re-use of the port.
Server Sends TCP RESET for the A...F
Here is the Sequence of data as seen through WININET (the HTTP protocol handler for Internet Explorer):
Client Sends Request to Server
Client Calls Socket_Receive and reads a certain number of bytes from the socket based on the Content-Length header field
This leaves the Close_Notify Message and the A...F in the Winsock Buffer.
Client processes the response and attempts to re-use the socket because of the Keep-Alive Header.
Client Calls Socket_Receive and does not understand the Close_Notify packet but does see the A...F and aborts the request.
Client Sends A...F and shuts down the socket
Since the Client Aborted, it checks the retry count and if the number of retries > 0 then it tries again.
The close_notify response from the Server can be identified as 15 03 00 within the data frame as it is decrypted using a debug version of wininet.dll:
000004c4:<app> 017 About to decrypt this data:
000004c4:<app> 017 23 (0x17) bytes @ 0x1dd9c0
000004c4:<app> 017 001dd9c0 15 03 00 00 12 3b c0 cc-b1 e6 51 59 93 cc 28 b9 .....;....QY..(.
000004c4:<app> 017 001dd9d0 70 7d 61 b5 2f dc fd p}a./..
For Internet Explorer 7, discarding this extra data is the default behavior, removing the condition that can cause the "Page cannot be displayed" behavior. Today, however, the only way to resolve this issue for Internet Explorer 6.0 is to install a hotfix and corresponding registry key (see Microsoft KB Article 921090 for the details). The good news is that this about to change. An upcoming IE cumulative update, slated to release before the end of this year, will include changes so that Internet Explorer 6.0 (Windows XP/SP2, 2003 Server/SP1, 2003 Server/SP2) matches the default behavior seen with Internet Explorer 7.0 when receiving a close_notify from a Server.