【问题标题】:Java - verifying certificate with system TrustStoreJava - 使用系统 TrustStore 验证证书
【发布时间】:2016-08-05 06:03:19
【问题描述】:

前提:我有一个证书,我想验证系统“信任”这个证书(由 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 的 cacertsfile 加载到密钥库中,并根据我的证书检查每个“最受信任”证书是否相等。

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 之间的解决方案?我觉得好像应该有一些类我可以调用来简单地验证证书的系统信任,而不必跳过几个环节。

【问题讨论】:

  • 这里使用 TrustManager 没有任何问题。这就是它的用途。克服你的厌恶。

标签: java security x509certificate pki truststore


【解决方案1】:

在阅读了 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 安全类/算法。

【讨论】:

    【解决方案2】:

    没有下载第三方库,估计没有别的选择了。

    您为什么要避免使用“SSL”库?它是标准库的一部分,因此不会给您的程序带来负担。

    无论如何,证书验证都是 SSL 的重要组成部分。我怀疑是否有人会在创建一个库而没有实现 SSL 协议的一些实质性子集的情况下遇到麻烦。没有真正的理由这样做。

    【讨论】:

      猜你喜欢
      • 2014-09-24
      • 2010-09-25
      • 1970-01-01
      • 2015-08-15
      • 2011-09-02
      • 2021-01-08
      • 1970-01-01
      • 2020-05-27
      • 2021-04-13
      相关资源
      最近更新 更多