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

我发现了一些有关如何实现此目的的不同解决方案。

选项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"),但ojit_code仍然与SSL紧密相关)。

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

最佳答案

在阅读了David Hook的《使用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安全类/算法。

09-30 15:44
查看更多