Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
370 views
in Technique[技术] by (71.8m points)

java - Error when opening and closing an SSLSocket w/o writing any data

A simple server

listen = getServer();
Logger.getAnonymousLogger().info("Listening to "+listen.toString());
SSLSocket client = (SSLSocket)listen.accept();
// adding this line fixes everything - client.write(42);
client.close();

and a simple client

SocketFactory sockMaker = SSLSocketFactory.getDefault();
Socket server = sockMaker.createSocket("localhost", 1443);
int retval = server.getInputStream().read();
assert retval == -1;
server.close();

If I don't write anything to the SSL Socket, an exception is thrown in the client side:

Exception in thread "main" javax.net.ssl.SSLException:
  Received close_notify during handshake
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:190)

I don't see why is that. Does the SSL/TLS specification requires you to write things into the socket?

See the full example.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...