【问题标题】:How to send TLS client certificate with no certification chain without modifying Java application source?如何在不修改 Java 应用程序源的情况下发送没有证书链的 TLS 客户端证书?
【发布时间】:2020-12-26 15:50:14
【问题描述】:

Gradle 项目需要将构建结果部署到私有 Artifactory 服务器。后者需要客户端 TLS 身份验证。用户证书由服务器所有者作为具有 1 个私钥条目的密钥库提供,并且该条目具有大小为 1 的证书链:

Keystore type: JKS
Keystore provider: SUN

Your keystore contains 1 entry

Alias name: myalias
Creation date: 08.09.2020
Entry type: PrivateKeyEntry
Certificate chain length: 1
Certificate[1]:
Owner: CN=myuser, O=Sharaga Inc, C=Far far away
Issuer: CN=CA, O=Sharaga Inc, C=Far far away
...

Gradle 尝试连接服务器时,Java TLS 实现拒绝发送客户端证书:

*** CertificateRequest
Cert Types: RSA, DSS, ECDSA
Supported Signature Algorithms: SHA256withRSA, SHA256withDSA, SHA256withECDSA, SHA384withRSA, Unknown (hash:0x5, signature:0x2), SHA384withECDSA, SHA512withRSA, Unknown (hash:0x6, signature:0x2), SHA512withECDSA, SHA1withRSA, SHA1withDSA, SHA1withECDSA
Cert Authorities:
<CN=CA, O=Sharaga Inc, C=Far far away>
pool-1-thread-1, READ: TLSv1.2 Handshake, length = 4
*** ServerHelloDone
Warning: no suitable certificate found - continuing without client authentication
*** Certificate chain
<Empty>

在 Java 8 和 Java 11 下,Linux 和 Windows 上都可以观察到这种行为。

我尝试通过修改密钥管理器实现来使用测试应用程序访问服务器,以便它始终选择“myalias”发送到服务器,并且成功了:

// Uses Artifactory client library:
// https://github.com/jfrog/artifactory-client-java

            PrivateKeyStrategy aliasStrategy = new PrivateKeyStrategy() {
                @Override
                public String chooseAlias(Map<String,PrivateKeyDetails> aliases, Socket socket) {
                    return "myalias";
                }
            };
    
            char[] password = "keystorepassword".toCharArray();
    
            Artifactory artifactory = ArtifactoryClientBuilder.create()
                .setUrl("https://theserver/artifactory")
                .setUsername("myuser")
                .setPassword("mypassword")
                .setSslContextBuilder(SSLContexts.custom().loadKeyMaterial(new File("mykeystore.pfx"), password, password, aliasStrategy))
                .build();

TLS 调试输出:

*** CertificateRequest
Cert Types: RSA, DSS, ECDSA
Supported Signature Algorithms: SHA256withRSA, SHA256withDSA, SHA256withECDSA, SHA384withRSA, Unknown (hash:0x5, signature:0x2), SHA384withECDSA, SHA512withRSA, Unknown (hash:0x6, signature:0x2), SHA512withECDSA, SHA1withRSA, SHA1withDSA, SHA1withECDSA
Cert Authorities:
<CN=CA, O=Sharaga Inc, C=Far far away>
main, READ: TLSv1.2 Handshake, length = 4
*** ServerHelloDone
matching alias: myalias
*** Certificate chain
chain [0] = [
[
  Version: V3
  Subject:CN=myuser, O=Sharaga Inc, C=Far far away
  Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11
...

(此处链长为1,但握手成功。)

有没有办法在现有 Java 应用程序中强制发送没有证书链的客户端证书而不更改/重新编译它?也许有一些系统属性可以调整这种行为?

【问题讨论】:

  • 为什么?您发送的证书链的范围由 JSSE 根据服务器在CertificateRequest 消息中请求的内容确定。这与应用程序无关。
  • 你看到这个问题和答案了吗? stackoverflow.com/questions/36202894/…
  • @Guillaume 明白为什么?不同的问题,不同的解决方案。很难看出这里有什么问题,如果有的话。链长与“找不到合适的证书”无关,当然也与您链接中的任何内容无关。
  • @MarquisofLorne,您的意思是我的证书与证书请求不匹配吗?我怎样才能了解/调试不匹配的原因?
  • @Guillaume,信任库不是我的情况:服务器链以众所周知的根 CA 结束。

标签: java ssl artifactory gradle-plugin client-certificates


【解决方案1】:

经过一番调试,我找到了原因。 javax.net.ssl.keyStore*系统属性不影响Gradle Artifactory Plugin,它对客户端证书一无所知,证书链实际上是空的(零长度)。

如果链中至少有一个证书,则将其成功发送到服务器。

【讨论】:

    猜你喜欢
    • 2012-03-15
    • 2019-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-10
    • 2015-09-27
    • 1970-01-01
    • 2016-10-22
    相关资源
    最近更新 更多