强制发送客户端证书

force-sending client certificate

我正在使用 Java SE Jersey 客户端连接到使用双向 SSL 的 HTTPS 资源。

我的 SSLContext 看起来像这样:

private SSLContext getSSLContext() {
    SslConfigurator sslConfig = SslConfigurator.newInstance()
        .keyStoreFile("src/main/certificates/testcert.p12")
        .keyPassword("mypassword");

   return sslConfig.createSSLContext();
}

问题是从未发送过客户端证书。

我收到错误 "Warning: no suitable certificate found - continuing without client authentication" 并且我已经追踪到客户端证书未颁发给服务器 CertificateRequest[=43 中列出的证书颁发机构之一这一事实的原因=] 消息给客户。我从 cURL 的测试中知道服务器无论如何都会接受证书。端点是 public 测试系统。

我的问题:如何强制发送我的客户端证书?(即我的 Java SE 客户端应该忽略 testcert.p12 证书的事实发行人不是服务器表示会接受的发行人列表)

请不要向我指出有关禁用服务器证书检查或有关使用自签名证书的答案。服务器的证书就好了

更新

原来我的问题是另一个问题。我通过设置系统 属性 javax.net.debug=all 进行调试。在检查了结果输出之后,在我看来,即使在执行了上述操作之后,密钥库仍然是空的。所以难怪为什么 "no suitable certificate found"。

泽西岛有这个 'clever' SslConfigurator class 可以帮助您建立 SSLContext。也许对我来说太聪明了,因为我无法让它与上面的代码一起工作。因此,我现在配置 SSLContext 如下所示:

    KeyStore ks = KeyStore.getInstance("PKCS12");
    FileInputStream fis = new FileInputStream("src/main/certificates/testcert.p12");
    ks.load(fis, "mypassword".toCharArray());
    KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
    kmf.init(ks, "mypassword".toCharArray());
    SSLContext sc = SSLContext.getInstance("TLS");
    sc.init(kmf.getKeyManagers(), null, null);
    // now use 'sc' in Jersey

这对我有用,而 Jersey 的助手 class 却没有。我完全赞同 Jersey 的 SSLContext 助手 class 的想法,因为对于这样一个简单的用例,JSSE 在这里似乎过于复杂。好吧好吧

你不能。这将违反 TLS 协议,因此没有 API 支持它。各种 TLS APIs 只会在以下情况下发送客户端证书:

  1. 已请求,并且
  2. 可以找到符合 CertificateRequest 消息中指定内容的客户端证书。

您必须安排您的服务器信任您的客户端证书,无论是通过 CA 签名还是将其导出到服务器的受信任证书存储区,无论服务器采用何种形式。