使用 Java 和 Bouncycastle 进行 X.509 证书验证

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2457795/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 07:58:22  来源:igfitidea点击:

X.509 Certificate validation with Java and Bouncycastle

javavalidationcertificatebouncycastlex509

提问by Rob

through the bouncycastle wiki pageI was able to understand how to create a X.509 root certificate and a certification request, but I do not quite understand how to proceed concept- and programming wise after that.

通过bouncycastle wiki 页面,我能够了解如何创建 X.509 根证书和认证请求,但我不太明白此后如何进行概念和编程。

Lets assume party A does a cert request and gets his client certificate from the CA. How can some party B validate A's certificate? What kind of certificate does A need? A root certificate? A 'normal' client certificate?

让我们假设 A 方做了一个证书请求并从 CA 获取他的客户端证书。B 方如何验证 A 的证书?A需要什么样的证书?根证书?“普通”客户端证书?

And how does the validation work on programming level, if we assume that A has successfully send his certificate in DER or PEM format to B?

如果我们假设 A 已成功将 DER 或 PEM 格式的证书发送给 B,则验证在编程级别如何工作?

Any help is much appreciated.

任何帮助深表感谢。

Best Regards, Rob

最好的问候,罗布

回答by Rob

Ok, the idea behind CAs is as follows:

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

  • CAs are people everyone trusts. To this end, a selection of Trusted CAs is available in your browser/email client/even on my mobile. In your case, your public root key (certificate) should be in your application.
  • Users send requests to the CA for a certificate in PEM format with the public key. CAs do some (I leave this ambiguous deliberately) form of verification of the end user, such as charging them money or in the case of enhanced verification (green) certs, background checks.
  • If the CA doesn't think the user's request is valid, they communicate this somehow.
  • If they do, they sign the public key and produce a certificate containing this information. This is where you process the cert-req and turn it into an X.509 cert.
  • Other users come across our fictitious user and want to know if they can trust them. So, they take a look at the certificate and find it is digitally signed by someone they have in their trust list. So, the fact that they trust the root CA and only the root CA could sign (via their private key) this user's public key and the CA trusts the user, we deduce that the new user can trust mr fictitious.
  • CA 是每个人都信任的人。为此,您的浏览器/电子邮件客户端/甚至我的手机上都提供了一系列受信任的 CA。在您的情况下,您的公共根密钥(证书)应该在您的应用程序中。
  • 用户使用公钥向 CA 发送 PEM 格式的证书请求。CA 对最终用户进行一些(我故意保留这种模棱两可的)形式的验证,例如向他们收费,或者在增强验证(绿色)证书的情况下,进行背景调查。
  • 如果 CA 认为用户的请求无效,他们会以某种方式传达这一信息。
  • 如果他们这样做,他们会签署公钥并生成包含此信息的证书。这是您处理 cert-req 并将其转换为 X.509 证书的地方。
  • 其他用户遇到我们虚构的用户,想知道他们是否可以信任他们。因此,他们查看证书并发现它是由他们信任列表中的某个人进行数字签名的。因此,事实上,他们信任根 CA 并且只有根 CA 可以(通过他们的私钥)签署此用户的公钥并且 CA 信任用户,我们推断新用户可以信任虚构的先生。

On a programmatic level, you implement this by reading the X.509 certificate and working out who the CA is supposed to be. Given that CA's fingerprint, you find it in your database and verify the signature. If it matches, you have your chain of trust.

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

This works because, as I've said, only the CA can create the digital signature but anyone can verify it. It is exactly the reverse of the encryption concept. What you do is "encrypt with the private key" the data you wish to sign and verify that the "decrypt with the public key" equals the data you've got.

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

回答by erickson

From a programmer's perspective, you need a few things to validate an X.509 certificate.

从程序员的角度来看,您需要做一些事情来验证 X.509 证书。

  1. A set of "trust anchors"—the root certificates of CAs that you rely on. These should be protected from tampering, so that an attacker doesn't replace a CA certificate with his own fake. The public keys in these certificates are used to verify the digital signatures on other certificates.
  2. A collection of Intermediate certificates. The application might keep a collection of these, but most protocols, like SSL and S/MIME, that use certificates have a standard way to provide extra certificates. Storing these doesn't require any special care; their integrity is protected by the signature of a root CA.
  3. Revocation information. Even if a certificate was issued by a CA, it might have been revoked prematurely because the private key was disclosed, or the end entity changed their identity. (For example, a person switches jobs and a certificate with their old company's name in it is revoked.) CRLs or a web-service like OCSP can be used to get an update about the status of a certificate.
  1. 一组“信任锚”——您所依赖的 CA 的根证书。这些应该受到保护以免被篡改,这样攻击者就不会用他自己的伪造证书替换 CA 证书。这些证书中的公钥用于验证其他证书上的数字签名。
  2. 中级证书的集合。应用程序可能会保留这些的集合,但大多数使用证书的协议(如 SSL 和 S/MIME)都有提供额外证书的标准方法。存储这些不需要任何特殊照顾;它们的完整性受根 CA 的签名保护。
  3. 撤销信息。即使证书是由 CA 颁发的,它也可能因为私钥被泄露或最终实体更改了他们的身份而被提前撤销。(例如,一个人换了工作,其中包含其旧公司名称的证书将被撤销。)CRL 或像 OCSP 之类的 Web 服务可用于获取有关证书状态的更新。

With these inputs available, you can use the built-in PKIX supportto construct and validate a certificate path.

有了这些输入,您就可以使用内置的 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);

An important thing to note is that if a path cannot be found, you don't get much information about the reason. This can be frustrating, but it is that way by design. In general, there are many potential paths. If they all fail for different reasons, how would the path builder decide what to report as the reason?

需要注意的重要一点是,如果找不到路径,您将无法获得有关原因的太多信息。这可能令人沮丧,但它就是这样设计的。一般来说,有很多潜在的路径。如果它们都因不同的原因而失败,路径构建器将如何决定报告什么原因?