简体   繁体   English

Java - 使用系统TrustStore验证证书

[英]Java - verifying certificate with system TrustStore

Premise: I have a certificate and I want to verify that the system 'trusts' this certificate (signed by a trusted root CA by Java / Operating System) 前提:我有一个证书,我想验证系统 “信任”此证书(由Java /操作系统的受信任的根CA签名)

I have found some varying solutions on how to accomplish this. 我找到了一些关于如何实现这一目标的不同解决方案。

Option 1: 选项1:

Use SSL classes to derive trust. 使用SSL类来获取信任。

TrustManagerFactory tmfactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmfactory.init((KeyStore) null);
for (TrustManager trustManager : tmfactory.getTrustManagers()) {
    if (trustManager instanceof X509TrustManager) {
        try {
            ((X509TrustManager) trustManager).checkClientTrusted(new X509Certificate[] {new JcaX509CertificateConverter().getCertificate(holder)}, "RSA");
            System.out.println("This certificate is trusted by a Root CA");
        } catch (CertificateException e) {
            e.printStackTrace();
        }
    }
}

Since this approach relies heavily on SSL classes (which are not needed by the current project) we are looking for alternatives. 由于这种方法在很大程度上依赖于SSL类(当前项目不需要),我们正在寻找替代方案。

Option 2: Load Java's cacerts file into a keystore and check each 'most-trusted' certificate against my certificate for equality. 选项2:将Java的cacerts文件加载到密钥库中,并根据我的证书检查每个“最受信任”的证书是否相等。

String filename = System.getProperty("java.home") + "/lib/security/cacerts".replace('/', File.separatorChar);
FileInputStream is = new FileInputStream(filename);
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
String password = "changeit";
keystore.load(is, password.toCharArray());

// This class retrieves the most-trusted CAs from the keystore
PKIXParameters params = new PKIXParameters(keystore);
// Get the set of trust anchors, which contain the most-trusted CA certificates
Set<X509Certificate> rootCertificates = params.getTrustAnchors().parallelStream().map(TrustAnchor::getTrustedCert).collect(Collectors.toSet());
return rootCertificates.contains(holderX509);

The problem with this approach is that it requires a password to verify integrity of the JKS encoded file. 这种方法的问题是它需要密码来验证JKS编码文件的完整性。 While the SSL one seemingly does not (or rather uses System.getProperty("javax.net.ssl.trustStorePassword") which again is heavily tied to SSL. 虽然SSL看起来没有(或者更确切地说使用System.getProperty("javax.net.ssl.trustStorePassword") ,而这又与SSL密切相关。

Question: Does there exist a solution that is in between manually loading certificates from a file and pure SSL? 问题:是否存在从文件和纯SSL手动加载证书之间的解决方案? I feel as if there should be some class that I can call to simply verify the system trust of a certificate without having to jump through a couple hoops. 我觉得好像应该有一些课程,我可以打电话来简单地验证系统对证书的信任,而不必跳过几个环节。

Short of downloading a third-party library, there probably isn't another alternative. 如果没有下载第三方库,可能没有其他选择。

Why are you trying to avoid the "SSL" library? 你为什么要试图避开“SSL”库? It's part of the standard library and so puts no burden on your program. 它是标准库的一部分,因此不会给您的程序带来负担。

In any case, certificate verification is a big part of SSL. 无论如何,证书验证是SSL的重要组成部分。 I doubt anyone's gone to the trouble of creating a library that does so without also implementing some substantial subset of the SSL protocol. 我怀疑是否有人在创建一个没有实现SSL协议的实质性子集的库的情况下遇到了麻烦。 There's just no real reason to do so. 没有真正的理由这样做。

After reading Beginning Cryptography With Java by David Hook I have produced the following example to verify a certificate chain (which accomplishes the original goal of using the system truststore to verify Root CA's) 在阅读David Hook的Beginning Cryptography With Java之后,我制作了以下示例来验证证书链(它实现了使用系统信任库来验证根CA的原始目标)

CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509", new BouncyCastleProvider());
InputStream is = new ByteArrayInputStream(some bytes in an array);
CertPath certPath = certificateFactory.generateCertPath(is, "PKCS7"); // Throws Certificate Exception when a cert path cannot be generated
CertPathValidator certPathValidator = CertPathValidator.getInstance("PKIX", new BouncyCastleProvider());
PKIXParameters parameters = new PKIXParameters(KeyTool.getCacertsKeyStore());

PKIXCertPathValidatorResult validatorResult = (PKIXCertPathValidatorResult) certPathValidator.validate(certPath, parameters); // This will throw a CertPathValidatorException if validation fails

This also accomplishes the goal of not having to use SSL classes - instead Java security classes / algorithms are used. 这也实现了不必使用SSL类的目标 - 而是使用Java安全类/算法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM