我想从TLS Client Hello Message
找到主机名。我希望在java完成对透明ssl proxy
的握手之前找到主机名。
有没有办法在不编写整个SNI extension
逻辑的情况下找到ssl handshake
值?
Java是否支持ssl handshake
初始内存缓冲区?
我的想法是:
sslSocket.startHandshake(initialBuffer)
初始缓冲区将包含TLS客户端hello数据包数据。所以Java可以做握手。第二个想法是使用SSLEngine class
。但它似乎比需求更多的实现。我假设SSLEngine
在我不需要的情况下使用大部分异步。
第三个想法是实施完整的TLS protocol
。
哪种想法更好?
答案 0 :(得分:1)
SSLSocket和SSLEngine都缺乏(非常难以理解)对服务器连接的正确SNI支持。
我自己遇到了同样的问题,最后写了一个库:TLS Channel。它不仅如此,它实际上是SSLEngine的完全抽象,暴露为ByteChannel。关于SNI,库在创建SSLEngine之前解析第一个字节。然后,用户可以向服务器通道提供功能,根据收到的域名选择SSLContexts。
答案 1 :(得分:1)
该问题的公认答案有些陈旧,并不能真正提供该问题的答案。
初始化KeyManager
时应使用自定义SSLContext
,诀窍是使用javax.net.ssl.X509ExtendedKeyManager
(请注意扩展术语)。这将提供在密钥别名选择过程中公开SSLEngine
而不是普通(无用)套接字的可能性。
在SSL握手过程中将调用方法chooseEngineServerAlias(...)
,以便从KeyStore中选择适当的别名(证书/密钥)。并且SNI信息已已填充,并在SSLEngine
中可用。此处的技巧是将SSLSession
转换为ExtendedSSLSession
(请注意扩展术语),然后转换为getRequestedServerNames()
。
KeyManager[] km = new KeyManager[]
{
new X509ExtendedKeyManager()
{
public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine)
{
if( engine.getHandshakeSession() instanceof ExtendedSSLSession )
{
List<SNIServerName> sni = ((ExtendedSSLSession)engine.getHandshakeSession()).getRequestedServerNames();
// select the proper certificate alias based on SNI here
}
}
}
}
SSLContext context = SSLContext.getInstance("TLS");
context.init(km, null, null);