使用SSLEngine(JSSE)与旧客户端进行SSL握手

时间:2012-04-17 17:57:24

标签: java ssl jsse sslengine

这是“SSL Handshaking Using Self-Signed Certs and SSLEngine (JSSE)”的后续问题。

我已经实现了一个NIO Web服务器,可以在同一个端口上处理SSL和非SSL消息。为了区分SSL和非SSL消息,我检查入站请求的第一个字节以查看它是否是SSL / TLS消息。例如:

byte a = read(buf);
if (totalBytesRead==1 && (a>19 && a<25)){
    parseTLS(buf);
}

在parseTLS()方法中,我实例化SSLEngine,启动握手,包装/解包消息等。对于大多数现代Web浏览器(Firefox 10,IE 9,Safari 5等),一切似乎都能正常工作。

问题是像IE 6这样的老式网络浏览器和像Java的URLConnection类这样的库似乎以不同方式启动SSL / TLS握手。例如,IE 6中的前几个字节看起来像这样(十六进制值):

80 4F 01 03 00 ...

如果我将消息传递给SSLEngine,它似乎无法识别该消息并抛出异常。

javax.net.ssl.SSLException: Unsupported record version Unknown-0.0

那么IE 6和Java的URLConnection类究竟发送了什么?这是JSSE SSLEngine可以支持的有效SSL / TLS消息吗?我是否必须进行一些预处理或与客户协商以发送不同的消息?

提前致谢!

更新

感谢Bruno和EJP以及一些进一步的调试,我对正在发生的事情有了更好的理解。正如Bruno正确指出的那样,IE6和Java 6客户端通过SSLv2 ClientHello发送。与我之前的一条评论相反,Java 1.6中的SSLEngine实际上可以解包SSLv2消息并生成有效的响应以发送回客户端。我之前报告的SSLException是我的错误,与SSLEngine无关(我错误地认为客户端已完成发送数据,当SSLEngine期望更多数据打开时,我最终得到一个空的ByteBuffer)。

1 个答案:

答案 0 :(得分:4)

这看起来像an SSLv2 Client Hello (see TLS specification)

  

支持SSL 2.0版服务器的TLS 1.1客户端必须发送SSL   2.0版客户端问候消息[SSL2]。 TLS服务器应该接受   如果客户端希望支持SSL 2.0客户端,请使用客户端问候语格式   相同的连接端口。与2.0版本的唯一偏差   规范是指定值为的版本的能力   三,并且在CipherSpec中支持更多的加密类型。

  • 80 4F是长度,高位必须设置为1(参见msg_length description)。
  • 01是消息类型(Client Hello)
  • 03 00是支持的最高版本(此处为SSLv3)

自Java 7以来,this is now disabled by default

修改

为了澄清,这不是SSLv2客户端Hello,这是SSLv2格式的SSLv3客户端Hello。在这种情况下,服务器将使用(正确的)SSLv3服务器Hello(对应于03 00请求的版本号)进行回复。这同样适用于TLS 1.0,1.1和1.2,尽管这种格式的使用逐渐被弃用。

JSSE 7 SSLServerSocket仍然会理解这样的客户端Hello并使用SSLv3 / TLS1.x服务器Hello进行适当的回复。