Java和Bouncycastle的X.509证书验证

25
通过Bouncycastle维基页面,我能够理解如何创建X.509根证书和认证请求,但是在概念和编程方面我还不太明白接下来该怎么做。
假设A方发出证书请求并从CA获得客户端证书,那么B方如何验证A的证书?A需要什么样的证书?根证书?'普通'客户端证书?
如果我们假设A已成功将他的证书以DER或PEM格式发送给B,那么验证在编程层面上是如何工作的?
非常感谢任何帮助。
最好的问候, 罗布
2个回答

41

从程序员的角度来看,验证X.509证书需要以下几个要素:

  1. 一组“信任锚点”——你依赖的CA根证书。这些证书应该受到保护,以防攻击者替换CA证书为自己的伪造证书。这些证书中的公钥用于验证其他证书上的数字签名。
  2. 一组中间证书。应用程序可能会保存这些证书的集合,但大多数使用证书的协议(如SSL和S/MIME)都有提供额外证书的标准方式。存储这些证书不需要特别注意;它们的完整性受根CA的签名保护。
  3. 吊销信息。即使证书由CA颁发,也可能因为私钥泄漏或最终实体更改身份而被过早地吊销。(例如,人们换工作并吊销具有旧公司名称的证书。)CRL或类似OCSP的Web服务可用于获取有关证书状态的更新信息。

有了这些输入,你可以使用内置PKIX支持来构建和验证证书路径。

/* Givens. */
InputStream trustStoreInput = ...
char[] password = ...
List<X509Certificate> chain = ...
Collection<X509CRL> crls = ...

/* Construct a valid path. */
KeyStore anchors = KeyStore.getInstance(KeyStore.getDefaultType());
anchors.load(trustStoreInput, password);
X509CertSelector target = new X509CertSelector();
target.setCertificate(chain.get(0));
PKIXBuilderParameters params = new PKIXBuilderParameters(anchors, target);
CertStoreParameters intermediates = new CollectionCertStoreParameters(chain)
params.addCertStore(CertStore.getInstance("Collection", intermediates));
CertStoreParameters revoked = new CollectionCertStoreParameters(crls);
params.addCertStore(CertStore.getInstance("Collection", revoked));
CertPathBuilder builder = CertPathBuilder.getInstance("PKIX");
/* 
 * If build() returns successfully, the certificate is valid. More details 
 * about the valid path can be obtained through the PKIXBuilderResult.
 * If no valid path can be found, a CertPathBuilderException is thrown.
 */
PKIXBuilderResult r = (PKIXBuilderResult) builder.build(params);

需要注意的重要一点是,如果找不到路径,你得不到关于原因的太多信息。这可能很令人沮丧,但是这样设计是有原因的。总的来说,有许多潜在的路径。如果它们都因为不同的原因失败了,那么路径生成器将如何决定报告什么作为原因呢?


这很清楚,但我找不到任何方法从XMLSignature中获取List<X509Certificate>链,即使在xmldsig xml文档中,我可以看到所有的证书。 - Jaime Hablutzel
@jaime - 通过从KeyInfo元素生成的X509Data,它们可以被访问。我对XML签名支持不太熟悉,所以不确定如何从文档中生成这个对象。 - erickson
进一步观察,我可以看到您可以从XML结构中取消编组 KeyInfo。如果存在,其内容将包括X509Data - erickson
@erickson: 请查看此链接 - https://dev59.com/5WPVa4cB1Zd3GeqP41zz - Ashwin
@erickson 我尝试了你的代码,但是我得到了“路径与任何锚点链不匹配”的错误,尽管我已经正确地提供了所有输入:( - suraj
显示剩余2条评论

9

好的,CA背后的想法如下:

  • CA是每个人都信任的人。为此,在您的浏览器/电子邮件客户端/甚至是我的手机上都提供了一些可信的CA选择。在您的情况下,您的公共根密钥(证书)应该在您的应用程序中。
  • 用户向CA发送PEM格式的带有公钥的证书请求。 CA对最终用户进行某种形式的验证(我故意保持模糊),例如向他们收取费用或在增强验证(绿色)证书的情况下进行背景检查。
  • 如果CA认为用户的请求无效,则以某种方式进行通信。
  • 如果他们确实这样做,则签署公钥并生成包含此信息的证书。这是您处理证书请求并将其转换为X.509证书的地方。
  • 其他用户遇到我们虚构的用户,并想知道他们是否可以信任他们。因此,他们查看证书并发现它由他们信任列表中的某个人数字签名。因此,他们信任根CA,只有根CA可以通过其私钥签署(通过)此用户的公钥,而CA信任用户,我们推断出新用户可以信任mr fictitious。

在编程层面上,您通过阅读X.509证书并确定CA应该是谁来实现这一点。鉴于CA的指纹,您在数据库中找到它并验证签名。如果匹配,则您就有了信任链。

这起作用是因为,正如我所说,只有CA可以创建数字签名,但任何人都可以验证它。它恰好与加密概念相反。您所做的是使用私钥“加密”要签名的数据,并验证“使用公钥解密”的数据是否等于您拥有的数据。


感谢您对CA概念的详细解释。我现在明白了。现在我只需要弄清楚编程层面的细节。 - Rob

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接