2

当我使用过期的公共证书验证 Java 中的数字签名 (PKCS#7) 时遇到问题。更详细地说,在 .NET 中签名数据然后在 Java 中验证的情况下是可以的,但在 Java中签署数据并在 Java 中验证的情况下会出现 Certificate Expired 错误。在这两种情况下,我都使用了相同的验证方法、相同的私钥和公共证书。

请告诉我为什么?如果我想在验证数字签名时绕过Certificate Expired验证该怎么办?

谢谢,

C#.NET 中的签名方法

private static string SignData(byte[] data, string pkcs12FileUrl, string pkcs12Password)
    {
        X509Certificate2 signerCert = new X509Certificate2(pkcs12FileUrl, pkcs12Password);
        ContentInfo content = new ContentInfo(data);
        SignedCms signed = new SignedCms(content, true);
        CmsSigner signer = new CmsSigner(signerCert);
        signer.IncludeOption = X509IncludeOption.None;
        signed.ComputeSignature(signer);

        return Convert.ToBase64String(signed.Encode());
    }

Java中的签名方法

public static String SignData(byte[] data, String pkcs12File, String pkcs12Password)
    throws Exception
{
        if(Security.getProvider("BC")==null)
        {
            Security.addProvider(new BouncyCastleProvider());
        }
        KeyStore keyStore = getPkcs12Info(pkcs12File, pkcs12Password);

        Enumeration<String> aliasesList = keyStore.aliases();
        String aliasName = "";
        while (aliasesList.hasMoreElements())
        {
            aliasName = aliasesList.nextElement().toString();
        }

        X509Certificate signerCert = (X509Certificate) keyStore.getCertificate(aliasName);
        PrivateKey privateKey = (PrivateKey) keyStore.getKey(aliasName,pkcs12Password.toCharArray());

        CMSSignedDataGenerator Signer = new CMSSignedDataGenerator();
        Signer.addSigner(privateKey, signerCert, CMSSignedDataGenerator.DIGEST_SHA1);

        CMSProcessableByteArray digestContent = new CMSProcessableByteArray(data);

        CMSSignedData Signed = Signer.generate(digestContent, false, "BC");
        return Base64.encode(Signed.getEncoded());

}

private static  KeyStore getPkcs12Info(String pkcs12File, String pkcs12Password) throws Exception
{
    //KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC");
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        keyStore.load(new FileInputStream(pkcs12File), pkcs12Password.toCharArray());
        return keyStore;
}

Java中的验证方法

public static boolean VerifySignature(byte[] data, String digitalSignature, InputStream publicCertFile) throws Exception
{
    if(Security.getProvider("BC")==null)
    {
        Security.addProvider(new BouncyCastleProvider());
    }
    CertificateFactory factory = CertificateFactory.getInstance("X509","BC");
    X509Certificate publicCert = (X509Certificate)factory.generateCertificate(publicCertFile);
    CMSProcessableByteArray digestContent = new CMSProcessableByteArray(data);
    CMSSignedData Signed = new CMSSignedData(digestContent,Base64.decode(digitalSignature));
    SignerInformation Signer=(SignerInformation)Signed.getSignerInfos().getSigners().iterator().next();
    return Signer.verify(publicCert, "BC");
}
4

2 回答 2

1

我找到了 C# SignedCms 的这个主题Java 实现,并尝试在 Java 中更改我的 Sign 方法的代码。最后,它工作得很好。这是我在Java中更新的代码

public static String SignData(byte[] data, String pkcs12File, String pkcs12Password)
    throws Exception
{
        ByteArrayOutputStream byteArrOut = new ByteArrayOutputStream();
        DEROutputStream derOut = new DEROutputStream(byteArrOut);
        try
        {
            if(Security.getProvider("BC")==null)
            {
                Security.addProvider(new BouncyCastleProvider());
            }
            KeyStore keyStore = getPkcs12Info(pkcs12File, pkcs12Password);

            Enumeration<String> aliasesList = keyStore.aliases();
            String aliasName = "";
            while (aliasesList.hasMoreElements())
            {
                aliasName = aliasesList.nextElement().toString();
            }

            X509Certificate signerCert = (X509Certificate) keyStore.getCertificate(aliasName);
            PrivateKey privateKey = (PrivateKey) keyStore.getKey(aliasName, pkcs12Password.toCharArray());

            List certList = new ArrayList();
            Store certs = new JcaCertStore(certList);

            JcaSimpleSignerInfoGeneratorBuilder builder = new JcaSimpleSignerInfoGeneratorBuilder().setProvider("BC").setDirectSignature(true);


            CMSSignedDataGenerator signer = new CMSSignedDataGenerator();
            signer.addSignerInfoGenerator(builder.build("SHA1withRSA", privateKey, signerCert));
            signer.addCertificates(certs);

            CMSTypedData msg = new CMSProcessableByteArray(data);
            CMSSignedData signed = signer.generate(msg, false);

            derOut.writeObject(signed.toASN1Structure().toASN1Primitive());
            return Base64.encode(byteArrOut.toByteArray());
        }
        catch(Exception ex)
        {
            throw ex;
        }
        finally
        {
            derOut.close();
            byteArrOut.close();
        }

}
于 2012-10-17T02:34:31.797 回答
1

如果您使用已过期的证书签署文件,那已经毫无意义。证书已过期,不应再用于新用途。验证签名证书已过期的文档是有意义的,因为至少您知道在文档签名时证书是有效的。除非它显然是由 .NET 签名的。对我来说,这听起来像是 .NET 中的一个错误。

于 2012-10-16T09:51:04.670 回答