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

Ela*_*ich 3 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();
Run Code Online (Sandbox Code Playgroud)

和一个简单的客户

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

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

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)
Run Code Online (Sandbox Code Playgroud)

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

查看完整示例.

Bru*_*uno 9

您不必将任何内容写入套接字,但如果您立即将其关闭,它将生成close_notify警报(尽管它被称为"警报",它是关闭TLS/SSL套接字的正常方式的一部分).

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

SSLSocket文档说:

可以通过以下三种方式之一启动此连接上的初始握手:

  • 调用startHandshake明确开始握手,或
  • 任何在此套接字上读取或写入应用程序数据的尝试都会导致隐式握手,或者
  • 将呼叫getSession尝试建立一个会话,如果当前没有有效的会话,并且隐式握手.

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

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

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

需要注意的是目的ServerSocket.accept(),它SSLServerSocket实现了,就是要创建一个SSLSocket,不一定用它做任何事情.该SSLServerSocket配置,但与握手继续超出范围.一方面,它可能听起来SSLSocket像一个普通的TCP套接字使行为更透明; 另一方面,它意味着从底层TCP流中读取,因此它会产生副作用.我没有试过,但SSLSocket由创造SSLServerSocket可能仍然是可配置成客户端套接字.毕竟,RFC 2246词汇表说: "客户端:启动到服务器的TLS连接的应用程序实体.这可能或可能不意味着客户端发起了底层传输连接." 这肯定会对透明度以及何时从API的角度进行握手产生影响.

(编写映射到普通TCP套接字API的SSL/TLS套接字的API是一项棘手的工作,而Java在这方面的工作并不算太糟糕.真正的"乐趣"始于异步TLS使用SSLEngine和NIO通道.考虑到任何一方都可以随时发起新的握手,它会变得更好:就TLS而言,对于上述级别的影响是不确定的,这可能导致尴尬的问题.)