You don't have to write anything into the socket as such, but if you close it straight away, it will generate a close_notify
alert (although it's called "alert", it's part of the normal way of closing a TLS/SSL socket).
In addition, SSL/TLS sockets are designed to behave "almost" like normal TCP sockets, but there are details where they don't (and can't) because of the way SSL/TLS works.
In particular, at the beginning of an SSL/TLS connection, the SSL/TLS handshake takes place, which involves a number of read/writes from each side, before sending any application data.
The documentation for SSLSocket says:
The initial handshake on this
connection can be initiated in one of
three ways:
- calling
startHandshake
which explicitly begins handshakes, or
- any attempt to read or write application data on this socket causes an implicit handshake, or
- a call to
getSession
tries to set up a session if there is no currently
valid session, and an implicit
handshake is done.
Essentially, the getInputStream().read()
by the client in your example initiates the handshake, which causes the server to proceed with accept()
and perform the handshake on its side. However, since you close it (normally, but immediately) on the server side, you don't even let any time for the handshake to complete. Hence the close_notify
is sent during the handshake, which causes the exception you get. Had you tried to read or write from the server side, the handshake would have at least completed.
EDIT: Following @EJP's comment, I should clarify what I meant:
createSocket("localhost", 1443)
on the client side establishes a connection and the server accepts it via accept()
.
getInputStream().read()
on the client side makes it initiate the handshake. Thus, it sends a ClientHello
TLS message to the server.
- Because the server uses
close()
straight after accepting the socket, it sends a close_notify
alert. Because the server hasn't started to read/write, it hasn't started the handshake (and thus doesn't complete it).
Note that the purpose of ServerSocket.accept()
, which SSLServerSocket
implements, is to create an SSLSocket
, not necessarily to do anything with it. The SSLServerSocket
configures it, but proceeding with the handshake is out of scope. On the one hand, it might sound as making the SSLSocket
behave more transparently like a normal TCP socket; on the other hand, it would imply reading from the underlying TCP stream, so it would have side-effects.
I haven't tried, but the SSLSocket
created by the SSLServerSocket
might still be configurable into a client socket. After all as the RFC 2246 glossary says:
"client: The application entity that initiates a TLS connection to a server. This may or may not imply that the client initiated the underlying transport connection." This would definitely have consequences regarding the transparency and when to do the handshake from the API point of view.
(Writing an API for SSL/TLS sockets that maps to the API of normal TCP sockets is a tricky exercise, and Java doesn't do too bad a job at it. The real "fun" starts with asynchronous TLS using SSLEngine
and NIO channels. It gets even better considering that either side can initiate a new handshake at any time: the implications for the level above are undefined as far as TLS is concerned, which can lead to awkward problems.)