【发布时间】: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