如何在不修改Java应用程序源代码的情况下发送没有证书链的TLS客户端证书?

如何在不修改Java应用程序源代码的情况下发送没有证书链的TLS客户端证书?,java,ssl,artifactory,gradle-plugin,client-certificates,Java,Ssl,Artifactory,Gradle Plugin,Client Certificates,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 Cert

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>
***认证请求
证书类型:RSA、DSS、ECDSA
支持的签名算法:SHA256withRSA、SHA256withDSA、SHA256withECDSA、SHA384withRSA、未知(哈希:0x5,签名:0x2)、SHA384withECDSA、SHA512withRSA、未知(哈希:0x6,签名:0x2)、SHA512withECDSA、SHA1 WithRSA、SHA1 WithDSA、SHA1 WithECDSA
核证机关:
池-1-线程-1,读取:TLSv1.2握手,长度=4
***海龙石
警告:找不到合适的证书-在没有客户端身份验证的情况下继续
***证书链
在Linux和Windows上的Java8和Java11中都可以观察到这种行为

我试图通过修改密钥管理器实现来访问带有测试应用程序的服务器,以便它始终选择“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();
//使用Artifactory客户端库:
// https://github.com/jfrog/artifactory-client-java
PrivateKeyStrategy aliasStrategy=新PrivateKeyStrategy(){
@凌驾
公共字符串选择器(映射别名、套接字){
返回“myalias”;
}
};
char[]password=“keystrepassword”.toCharArray();
Artifactory-Artifactory=ArtifactoryClientBuilder.create()
.setUrl(“https://theserver/artifactory")
.setUsername(“myuser”)
.setPassword(“我的密码”)
.setSslContextBuilder(SSLContexts.custom().loadKeyMaterial(新文件(“mykeystore.pfx”)、密码、密码、别名策略)
.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
...
***认证请求
证书类型:RSA、DSS、ECDSA
支持的签名算法:SHA256withRSA、SHA256withDSA、SHA256withECDSA、SHA384withRSA、未知(哈希:0x5,签名:0x2)、SHA384withECDSA、SHA512withRSA、未知(哈希:0x6,签名:0x2)、SHA512withECDSA、SHA1 WithRSA、SHA1 WithDSA、SHA1 WithECDSA
核证机关:
main,读取:TLSv1.2握手,长度=4
***海龙石
匹配别名:myalias
***证书链
链[0]=[
[
版本:V3
主题:CN=myuser,O=Sharaga Inc,C=Far Far away
签名算法:SHA256withRSA,OID=1.2.840.113549.1.1.11
...
(此处链长为1,但握手成功。)


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

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


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

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