打开和关闭SSLSocket没有写入任何数据时出错

时间:2011-06-30 11:38:26

标签: java sockets ssl

一个简单的服务器

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

和一个简单的客户

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

如果我没有向SSL套接字写任何内容,则会在客户端抛出异常:

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)

我不明白为什么会这样。 SSL / TLS规范是否要求您将内容写入套接字?

请参阅full example

2 个答案:

答案 0 :(得分:9)

你不必在套接字中写任何东西,但是如果你马上关闭它,它会产生一个close_notify警报(尽管它被称为“警报”,它是正常方式的一部分)关闭TLS / SSL套接字)。

此外,SSL / TLS套接字被设计为“几乎”像普通的TCP套接字一样,但由于SSL / TLS的工作方式,它们没有(也不能)。 特别是,在SSL / TLS连接开始时,会发送SSL / TLS握手,这会在发送任何应用程序数据之前从每一侧进行大量读/写操作。

documentation for SSLSocket说:

  

对此的初步握手   连接可以在其中一个中启动   三种方式:

     
      
  • 调用明确开始握手的startHandshake,或
  •   
  • 在此套接字上读取或写入应用程序数据的任何尝试都会导致隐式握手,或
  •   
  • 如果当前没有,getSession的调用会尝试设置会话   有效会话和隐含   握手完成。
  •   

实际上,示例中客户端的getInputStream().read()会启动握手,这会导致服务器继续进行accept() 并在其侧面执行握手。但是,由于您在服务器端关闭它(通常,但是立即),您甚至不会让握手完成任何时间。因此,在握手期间发送close_notify,这会导致您获得异常。如果你试图从服务器端读取或写入,那么握手至少会完成。

编辑:关注@ EJP的评论,我应该澄清一下我的意思:

    客户端的
  • createSocket("localhost", 1443)建立连接,服务器通过accept()接受。
  • 客户端的
  • getInputStream().read()使其启动握手。因此,它会向服务器发送ClientHello TLS消息。
  • 由于服务器在接受套接字后直接使用close(),因此会发送close_notify警报。由于服务器尚未开始读/写,因此尚未启动握手(因此无法完成)。

请注意,SSLServerSocket实现的ServerSocket.accept()的目的是创建SSLSocket,而不一定要对其进行任何操作。 SSLServerSocket配置它,但继续握手超出范围。一方面,它可能听起来像SSLSocket表现得更像普通的TCP套接字;另一方面,它意味着从底层TCP流中读取,因此它会产生副作用。 我还没有尝试过,但SSLSocket创建的SSLServerSocket仍可配置为客户端套接字。毕竟RFC 2246 glossary说: “client:启动与服务器的TLS连接的应用程序实体。这可能会或可能不会暗示客户端启动了基础传输连接。”这肯定会对透明度产生影响,何时会产生影响从API的角度来看握手。

(编写映射到普通TCP套接字API的SSL / TLS套接字的API是一项棘手的工作,而Java在这方面的工作并不算太糟糕。真正的“乐趣”始于异步TLS使用{ {1}}和NIO频道。考虑到任何一方都可以随时发起新的握手,情况会更好:就TLS而言,对上述级别的影响是不确定的,这可能导致awkward problems。 )

答案 1 :(得分:1)

情况无效。您正在尝试读取未发送的数据。这是应用程序协议错误。布鲁诺的答案中的所有陈述也适用。客户正在尝试握手;服务器正在尝试关闭连接。可以说服务器关闭可以在尚未完成握手的情况下发起握手,但事实并非如此。

正如您所指出的,另一种解决方法是在任一端调用startHandshake()。