我已经实现了一个接受SSL / TLS连接的(Netty 3.6.6,Java 6)服务器,并且需要对客户端的证书链进行身份验证。我在我的信任库中有共同的CA.除非此处描述的情况,服务器的SSL实现基本上有效。鉴于有效的签名证书(适用于连接到其他服务器),我可以使用以下命令成功连接到我的服务器:
openssl s_client -connect 127.0.0.1 -key test.key -cert test.pem -CAfile capath.pem
但是,如果证书和中间体连接在一起并且我连接到:
openssl s_client -connect 127.0.0.1 -key test.key -cert all.pem
然后我被unable to find valid certification path to requested target
抛出;我希望这种方法有效。
我的代码是(缩写):
public class MySslConnectionHandler extends FrameDecoder {
// this class is added into the netty ChannelPipeline (not shown)
private SSLContext sslContext;
public MySslConnectionHandler() {
KeyStore clientKeyStore = KeyStore.getInstance('JKS');
clientKeyStore.load(new FileInputStream(trustStoreFilename), trustStorePassword);
PKIXSSLContextFactory contextFactory = new PKIXSSLContextFactory(serverKeyStore, keyStorePassword, clientKeyStore, true);
this.sslContext = contextFactory.buildSSLContext();
}
@Override
protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception {
SSLEngine engine = sslContext.createSSLEngine();
engine.setUseClientMode(false);
engine.setNeedClientAuth(true);
engine.setEnabledProtocols(new String[] {"TLSv1","SSLv3"});
SslHandler sslHandler = new SslHandler(engine);
sslHandler.setEnableRenegotiation(false);
ChannelFuture handshakeFuture = sslHandler.handshake();
handshakeFuture.addListener(new MySslHandshakeListener(engine));
return buffer.readBytes(buffer.readableBytes());
}
}
我做错了什么?我们的客户报告此行为与他们使用的其他服务器不同,因此我不希望这会导致问题;这个合理吗? (广泛的谷歌搜索没有帮助...)
谢谢: - )
答案 0 :(得分:1)
你的期望是错误的。 openssl s_client -cert file
仅使用第一个证书,该证书必须是客户端证书。在该文件中放入其他证书,链或其他证书将被忽略。结果s_client
(通过libssl客户端)发送一个不完整的链。通常,服务器无法对此进行验证。
虽然-CAfile
和/或-CAdir
被记录为为s_client
提供验证 peer (服务器)证书的根,但libssl 也< / em>使用信任库来填写它在必要和可能时发送的链;显然你在cacert.pem
中有你的链证书,而且发生了这种情况。
我认为您的客户没有使用s_client
,因为它发送和接收合适数据的能力非常有限。
如果您或某人使用libssl编写或编写实际应用程序,您可以通过调用SSL_CTX_use_certificate_chain_file
而不是SSL_CTX_use_certificate_file
来设置(整个)链,或者您可以使用SSL_CTX_add_extra_chain_cert
从单个证书构建链。 (如果你只有一个中级,这些实际上是等价的。)更不用说你可以用Java,perl和dotNET等其他语言做什么了。 s_client
被设计为测试和调试工具,但不执行这些操作;只有use_certificate
只使用第一个证书。
警告:这是OpenSSL到1.0.1的全部内容。现在处于测试阶段的1.0.2已宣布在证书和链验证方面有所变化我还没有进行过检查。虽然基于过去的做法,我自信地希望默认将继续像早期版本一样。
如果您确实需要Java服务器来接受发送不完整链的客户端(根据RFC不应该这样),您可以在服务器信任库中放置第一个未发送的中间件(这是第一个中间周期)。但我相信(不能轻易测试)在这种情况下,Java将完全忽略链的其余部分,因此您必须手动或通过其他方式进行监控。撤销。