代码之家  ›  专栏  ›  技术社区  ›  hudolejev

用Java验证PKCS#7证书

  •  7
  • hudolejev  · 技术社区  · 15 年前

    需要一些Java加密例程的帮助。

    给定一个PKCS#7签名,我想根据可信存储验证它包含的所有证书。我假设签名中包含的所有证书都以正确的顺序形成有效的证书路径(或链,无论什么),以便

    • 最上面的(#0)是签名证书;
    • 下一个(#1)是中间证书,用于签署#0;
    • 下一个(#2)是另一个中间证书,用于签署#1;

    // Exception handling skipped for readability
    
    //byte[] signature = ...
    pkcs7 = new PKCS7(signature); // `sun.security.pkcs.PKCS7;`
    
    // *** Checking some PKCS#7 parameters here
    
    X509Certificate prevCert = null; // Previous certificate we've found
    X509Certificate[] certs = pkcs7.getCertificates(); // `java.security.cert.X509Certificate`
    for (int i = 0; i < certs.length; i++) {
        // *** Checking certificate validity period here
    
        if (cert != null) {
            // Verify previous certificate in chain against this one
            prevCert.verify(certs[i].getPublicKey());
        }
        prevCert = certs[i];
    }
    
    //String keyStorePath = ...
    KeyStore keyStore = KeyStore.getInstance("JKS"); // `java.security.KeyStore`
    keyStore.load(new FileInputStream(keyStorePath), null);
    
    // Get trusted VeriSign class 1 certificate
    Certificate caCert = keyStore.getCertificate("verisignclass1ca"); // `java.security.cert.Certificate`
    
    // Verify last certificate against trusted certificate
    cert.verify(caCert.getPublicKey());
    

    所以问题是——如何使用像 CertPath 朋友呢?我有一种强烈的感觉,我正在重新发明一辆自行车。或者,如果有人有一个BouncyCastle库的例子,也可以。

    附加问题:如何根据受信任的存储验证证书,以便自动选择根证书?

    2 回复  |  直到 15 年前
        1
  •  14
  •   Community CDub    8 年前

    我自己找到了解决办法。因此,下面介绍如何针对受信任的存储提取和验证证书链(为了可读性,跳过了异常处理):

    CertificateFactory cf = CertificateFactory.getInstance("X.509");
    
    // Get ContentInfo
    //byte[] signature = ... // PKCS#7 signature bytes
    InputStream signatureIn = new ByteArrayInputStream(signature);
    DERObject obj = new ASN1InputStream(signatureIn).readObject();
    ContentInfo contentInfo = ContentInfo.getInstance(obj);
    
    // Extract certificates
    SignedData signedData = SignedData.getInstance(contentInfo.getContent());
    Enumeration certificates = signedData.getCertificates().getObjects();
    
    // Build certificate path
    List certList = new ArrayList();
    while (certificates.hasMoreElements()) {
        DERObject certObj = (DERObject) certificates.nextElement();
        InputStream in = new ByteArrayInputStream(certObj.getDEREncoded());
        certList.add(cf.generateCertificate(in));
    }
    CertPath certPath = cf.generateCertPath(certList);
    
    // Load key store
    //String keyStorePath = ...
    KeyStore keyStore = KeyStore.getInstance("JKS");
    keyStore.load(new FileInputStream(keyStorePath), null);
    
    // Set validation parameters
    PKIXParameters params = new PKIXParameters(keyStore);
    params.setRevocationEnabled(false); // to avoid exception on empty CRL
    
    // Validate certificate path
    CertPathValidator validator = CertPathValidator.getInstance("PKIX");
    CertPathValidatorResult result = validator.validate(certPath, params);
    

    validate() 如果验证失败,将引发异常。

    文件: ASN1Set ContentInfo , SignedData java.security.cert

    这里没有太阳,只有 BouncyCastle provider library

    This 问题(尤其是答案)也会有帮助。

        2
  •  2
  •   President James K. Polk    15 年前

    你想要什么 CertificateFactory