【问题标题】:Client certificate missing: How to recover it客户端证书丢失:如何恢复它
【发布时间】:2019-03-31 14:51:17
【问题描述】:

我所在的团队正在尝试使用证书将 Java J2SE 应用程序连接到安全的公司 Web 服务站点。团队成员之前都没有为此类连接创建证书和编码的经验。

我们准备并提交了一份 CSR,并收到了来自 Web 服务站点的 .p7b 证书。 .p7b 包含两个证书:一个由 Web 服务站点颁发给我们,另一个由公司所有者自己的 CA 颁发给 Web 服务站点。两者都出现在下面的密钥库列表中。密钥库在自定义 SSLContext 中被引用,Java 代码使用该 SSLContext 创建一个 Apache HttpClient 而不会出错。

当 Java 代码尝试执行 HttpGet 时,Web 服务站点拒绝 SSLHandshake 并终止连接并出现错误:

javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake

在握手调试跟踪中,在握手的第 13 步中,消息是:

ServerHelloDone
Warning: no suitable certificate found - continuing without client authentication
Certificate chain
Empty

Keytool 将密钥库的内容列为: (公司身份已编辑)

Keystore type: PKCS12
Keystore provider: SUN

Your keystore contains 1 entry

Alias name: server
Creation date: Mar 28, 2019
Entry type: PrivateKeyEntry
Certificate chain length: 2
Certificate[1]:
Owner: ...
Issuer: ...
Serial number: ...
Valid from: Mon Mar 11 19:00:00 CDT 2019 until: Wed Mar 11 18:59:59 CDT 2020
Certificate fingerprints:
     SHA1: ...
     SHA256: ...
Signature algorithm name: SHA1withRSA
Subject Public Key Algorithm: 2048-bit RSA key
Version: 3

Extensions: 

#1: ObjectId: 2.16.840.1.113733.1.6.9 Criticality=false
0000: 01 01 FF                                           ...


#2: ObjectId: 2.5.29.19 Criticality=false
BasicConstraints:[
  CA:false
  PathLen: undefined
]

#3: ObjectId: 2.5.29.31 Criticality=false
CRLDistributionPoints [
  [DistributionPoint:
     [URIName: http://onsite-crl.pki.digicert.com/ATTServicesIncApplicationCertificates/LatestCRL.crl]
]]

#4: ObjectId: 2.5.29.15 Criticality=false
KeyUsage [
  DigitalSignature
  Key_Encipherment
]

#5: ObjectId: 2.16.840.1.113730.1.1 Criticality=false
NetscapeCertType [
   SSL client
]

Certificate[2]:
Owner: ...
Issuer: ...
Serial number: ...
Valid from: Wed Feb 23 18:00:00 CST 2011 until: Tue Feb 23 17:59:59 CST 2021
Certificate fingerprints:
     SHA1: ...
     SHA256: ...
Signature algorithm name: SHA1withRSA
Subject Public Key Algorithm: 2048-bit RSA key
Version: 3

Extensions: 

#1: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: 97 20 99 C2 73 2A 45 EB   E0 02 7F 47 DA 7B AB 7C  . ..s*E....G....
0010: EB 1F AF 6E                                        ...n
]
]

#2: ObjectId: 2.5.29.19 Criticality=true
BasicConstraints:[
  CA:true
  PathLen:0
]

#3: ObjectId: 2.5.29.31 Criticality=false
CRLDistributionPoints [
  [DistributionPoint:
     [URIName: http://onsitecrl.verisign.com/offlineca/ATTServicesIncATTServicesIncRootCA.crl]
]]

#4: ObjectId: 2.5.29.15 Criticality=true
KeyUsage [
  Key_CertSign
  Crl_Sign
]

#5: ObjectId: 2.5.29.17 Criticality=false
SubjectAlternativeName [
  CN=VeriSignMPKI-2-51
]

#6: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 25 64 37 69 DB DC 57 99   43 80 79 29 90 6C B8 13  %d7i..W.C.y).l..
0010: 58 EE B6 D0                                        X...
]
]



*******************************************
*******************************************

]
}

似乎密钥库包含我们的私钥条目,但不包含客户端证书;仅列出来自 Web 服务站点的 .p7b 的两个证书。

StackOverflow 帖子位于:

why doesn't java send the client certificate during SSL handshake?

建议从密钥库中导出客户端证书并编辑证书链。这并不能解决问题,显然是因为密钥库包含我们的私钥但不包含我们的签名证书。

我没有标识为客户端证书的工件。 Oracle 程序在:

https://docs.oracle.com/cd/E19509-01/820-3503/ggezu/index.html

建议应该在准备原始 CSR 的过程中创建签名的客户端证书(过程的第 3 步),但是我们似乎没有将该证书文件作为单独的工件。

我认为我们需要重建客户端证书并将其导入到密钥库中证书链的正确位置。由于我们在创建 CSR 时似乎没有创建原始文件,现在是否可以从头开始重新创建客户端证书(Oracle 过程的第 3-5 步)并将其重新编辑到链中?有没有办法从原始 CSR 中提取或重构客户端证书?

非常感谢任何问题、见解或建议。谢谢。

【问题讨论】:

  • 我想几年前我看到了一个类似的问题,并且由于 JVM 中的 PKCS12 密钥库代码出现了奇怪的行为,其中链不会被正确处理,而是放置每个单独的证书in 会正常工作。 JKS 商店没有发生这种情况。我的记忆很模糊,所以我会检查我的笔记,看看我是否有任何有用的东西可以作为答案。

标签: java ssl ssl-certificate keystore apache-httpclient-4.x


【解决方案1】:

似乎密钥库包含我们的私钥条目,但不包含客户端证书;仅列出来自 Web 服务站点的 .p7b 的两个证书。

您显示的由 keytool 列出的 PrivateKeyEntry 确实包含一个客户端证书(由 BC、KU 和 NCT 提供)和一个可能是该客户端证书的颁发(父)证书的 CA 证书。 (如果您使用 keytool 将这些证书导入此密钥库,则 CA 证书肯定是颁发者,因为 keytool 会验证这一点;如果您使用其他工具,它应该强制执行相同的要求,但可能不会。)您描述p7b 包含“公司所有者自己的 CA 发布的 Web 服务站点的第二个”,但是(1)如果是这种情况,keytool 不会将其作为同一链的一部分导入,并且(2)没有任何意义,因为客户端在其密钥库 信任库中不需要 CA 颁发(即非自签名)的服务器证书,在其信任库中只需要服务器的 CA 证书,并且作为一个单独的条目不在客户端的 PrivateKeyEntry 中,即使它是一个共享文件。

根据您的描述,您将获得 javax.net.debug=ssl 跟踪,因此请查看该跟踪的加载密钥库的部分并确保 此条目 正在加载,并查看服务器的 @ 987654322@ 在Cert Authorities 下查看它要求的CA(立即之前 *** ServerHelloDone)并将(那些)与您的密钥库中链的实际CA(未编辑)进行比较.由于您使用的是 Apache HttpClient,如果您使用的是指定 PrivateKeyStrategy 的重载之一,请确保它正确选择别名。

【讨论】:

  • 跟踪的证书请求部分列出了四个证书颁发机构,两个众所周知的公共证书颁发机构,颁发 .p7b 的公司中间机构,以及拥有公司中介机构的公司根 CA,两者都是存在于密钥库中。客户端证书似乎存在,但我没有从提供的 .p7b 正确组装密钥库。您能否准确解释我需要遵循哪些步骤才能将 .p7b 正确加载和配置到密钥库中?
  • 如果 keystore 条目中链中的任何证书是由服务器请求的任何 CA 颁发的,并且用于正确的算法(我之前忘了说),则 keystore 条目是正确的,并且您说两者都是(假设“在密钥库中”是指“在特定私钥条目的链中,而不是密钥库中的其他位置”)。正如我所说,确保跟踪显示此密钥库条目(包括链)由会话(或更确切地说是密钥管理器,应该基于密钥库)加载 ,并且您的代码不会阻止 AHC 选择它。
猜你喜欢
  • 1970-01-01
  • 2013-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-20
  • 1970-01-01
  • 2011-11-21
  • 2015-09-06
相关资源
最近更新 更多