使用Bouncy Castle在Java中签署文件

10
我希望在Java中使用证书对文件内容进行签名。
通过终端和openssl,我可以这样做:
openssl smime -sign -in nosign.mobileconfig -out signed.mobileconfig -signer server.crt -inkey server.key -certfile cacert.crt -outform der -nodetach

server.crt和.key是要签名的文件,我认为cacert.crt嵌入了输出内容中。

最终,我有一个被签名和信任的文件。

在Java中,我无法使用openssl(不想启动openssl命令),所以我必须使用库进行签名。

为此,我使用Bouncy Castle(版本1.53)。

这是我的代码:

    byte[] profile = ...; // I can have it also in String

    // the certificate in -certfile
    FileInputStream inputStream = new FileInputStream("src/main/resources/cacert.crt"); 

    byte[] caCertificate = ByteStreams.toByteArray(inputStream);

    // the certificate to sign : server.crt, embedded in p12
    X509Certificate serverCertificate = (X509Certificate) this.keyStore.getCertificate("1");

    // Private key is the server.key
    ContentSigner sha1Signer = new JcaContentSignerBuilder("SHA1withRSA").setProvider("BC").build(this.privateKey);

    CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
    generator.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(
            new JcaDigestCalculatorProviderBuilder().setProvider("BC").build()).build(sha1Signer, serverCertificate));

    // the embedded certificate : cacert.crt, but  I don't know if it is good to do that this way
    X509CertificateHolder holder = new X509CertificateHolder(caCertificate);

    generator.addCertificate(holder);

    CMSProcessableByteArray bytes = new CMSProcessableByteArray(profile);
    CMSSignedData signedData = generator.generate(bytes, true);

    System.out.println("signedData : \n" + signedData.getEncoded());

你能帮我得到正确的签名数据吗?谢谢!

编辑: 我在这里遇到了一个错误。

    X509CertificateHolder holder = new X509CertificateHolder(caCertificate);

java.io.IOException: 遇到未知标记13


你有读过这篇教程吗?https://docs.oracle.com/javase/tutorial/security/apisign/step3.html - Mr_Thorynque
你有什么问题或疑问吗?你是否收到任何错误信息或其他提示? - JimmyB
我在以下代码处遇到了错误:X509CertificateHolder holder = new X509CertificateHolder(caCertificate);java.io.IOException: 遇到未知标签13 我检查了cacert并且它是格式良好的。 - zarghol
1个回答

8

CA证书文件显然是以PEM(ASCII)格式存储的。X509CertificateHolder的构造函数需要证书的BER / DER(二进制)编码。

您可以通过添加以下内容进行转换:

PEMParser pemParser = new PEMParser(new FileReader("src/main/resources/cacert.crt"));
X509CertificateHolder caCertificate = (X509CertificateHolder) pemParser.readObject();

您应该将签名证书添加到CMS结构中:

generator.addCertificate(new X509CertificateHolder(serverCertificate.getEncoded()));

谢谢!这有助于我嵌入cacert.crt,现在不再出错了。记录一下,PEMReader不再存在,但我可以使用PEMParser parser = new PEMParser(fileReader); parser.readObject();我的配置文件已生成,但仍未被我的操作系统识别为已签名。 - zarghol
@zarghol 我已经更新了我的回答。除了没有添加签名证书外,你的代码看起来非常好。然而,你留下了很多东西,并且如果p12文件不是用Java生成的话,通常会出现问题。如果你仍然遇到问题,请创建一个MCVE - Omikron
我使用了 generator.addCertificate((X509CertificateHolder) parser.readObject()); 这段代码,自从我3小时前留言以来它就一直在工作。现在它被识别为已签名!我会尝试一些更改,但它在全局范围内都能正常工作。感谢您的帮助! - zarghol

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接