Java SSL服务器不接受中间证书链

时间:2014-09-09 08:17:53

标签: java ssl netty

我已经实现了一个接受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());
    }
}

我做错了什么?我们的客户报告此行为与他们使用的其他服务器不同,因此我不希望这会导致问题;这个合理吗? (广泛的谷歌搜索没有帮助...)

谢谢: - )

1 个答案:

答案 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将完全忽略链的其余部分,因此您必须手动或通过其他方式进行监控。撤销。