Java - 使用系统 TrustStore 验证证书

标签 java security x509certificate pki truststore

前提:我有一个证书,我想验证系统是否“信任”这个证书(由受信任的根 CA 通过 Java/操作系统签名)

我找到了一些不同的解决方案来实现这一点。

选项 1:

使用 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();
        }
    }
}

由于这种方法严重依赖 SSL 类(当前项目不需要),我们正在寻找替代方案。

选项 2: 将 Java 的 cacerts 文件加载到 keystore 中,并根据我的证书检查每个“最受信任”的证书是否相等。

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);

此方法的问题在于它需要密码来验证 JKS 编码文件的完整性。虽然 SSL 似乎没有(或者更确切地说使用 System.getProperty("javax.net.ssl.trustStorePassword"),这又一次与 SSL 密切相关。

问题:是否存在介于从文件手动加载证书和纯 SSL 之间的解决方案?我觉得好像应该有一些我可以调用的类来简单地验证证书的系统信任,而不必跳过几个环节。

最佳答案

在阅读了 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

这也实现了不必使用 SSL 类的目标 - 而是使用 Java 安全类/算法。

关于Java - 使用系统 TrustStore 验证证书,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36610312/

相关文章:

java - JADE 中的 ACLMessages 问题

java - POM.xml 中的 tomcat 资源错误

java - 数组和嵌套循环

wix - 如何从 Wix 安装程序将自签名 SSL 证书安装到商店中?

java - java.lang.Math.PI 等于 GCC 的 M_PI 吗?

c# - 使用 System.Net.Http 避免 TRUSTWORTHY ON 和 PERMISSION_SET = UNSAFE

oauth-2.0 - 作为 OAuth 服务器,我应该如何生成和存储 OAuth 2.0 token ?

php - 为什么连接失败时 PDO 会打印我的密码?

c++ - x509 证书主题备用名称

java - 如何在 TrustManager 的 checkServerTrusted() 中获取 CertPathValidatorResult?