3

我在使用受信任的时间戳使用 Bouncy Castle 创建有效的 CMS 签名时遇到问题。签名创建效果很好(我想将签名包含在 PDF 文件中),签名有效。但是在我在签名的未签名属性表中包含受信任的时间戳后,签名仍然保持有效,但阅读器报告签名包含嵌入的时间戳但它是无效的。这让我相信,我时间戳的哈希值不是正确的,但我似乎无法弄清楚它有什么问题。

签名代码:

Store store = new JcaCertStore(Arrays.asList(certContainer.getChain()));

CMSSignedDataGenerator signedDataGenerator = new CMSSignedDataGenerator();
JcaSignerInfoGeneratorBuilder infoGeneratorBuilder = new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider("BC").build());
JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder("SHA1withRSA");
signedDataGenerator.addSignerInfoGenerator(
                       infoGeneratorBuilder.build(contentSignerBuilder.build(certContainer.getPrivateKey()), (X509Certificate)certContainer.getSignatureCertificate()));
signedDataGenerator.addCertificates(store);
CMSTypedData cmsData = new CMSProcessableByteArray(data);
signedData = signedDataGenerator.generate(cmsData, false);
Collection<SignerInformation> ss = signedData.getSignerInfos().getSigners();
SignerInformation si = ss.iterator().next(); // get first signer (should be only one)
ASN1EncodableVector timestampVector = new ASN1EncodableVector();
Attribute token = createTSToken(si.getSignature());
timestampVector.add(token);
AttributeTable at = new AttributeTable(timestampVector);
si = SignerInformation.replaceUnsignedAttributes(si, at);
ss.clear();
ss.add(si);
SignerInformationStore newSignerStore = new SignerInformationStore(ss);
CMSSignedData newSignedData = CMSSignedData.replaceSigners(signedData, newSignerStore);

createTSToken代码:

public Attribute createTSToken(byte[] data) throws NoSuchProviderException, NoSuchAlgorithmException, IOException {
    // Generate timestamp
    MessageDigest digest = MessageDigest.getInstance("SHA1", "BC");
    TimeStampResponse response = timestampData(digest.digest(data));
    TimeStampToken timestampToken = response.getTimeStampToken();
    // Create timestamp attribute

    Attribute a = new Attribute(PKCSObjectIdentifiers.id_aa_signatureTimeStampToken, new DERSet(ASN1Primitive.fromByteArray(timestampToken.getEncoded())));
    return a;
}

timestampData

TimeStampRequestGenerator reqgen = new TimeStampRequestGenerator();
TimeStampRequest req = reqgen.generate(TSPAlgorithms.SHA1, data);
byte request[] = req.getEncoded();

URL url = new URL("http://time.certum.pl");
HttpURLConnection con = (HttpURLConnection) url.openConnection();

con.setDoOutput(true);
con.setDoInput(true);
con.setRequestMethod("POST");
con.setRequestProperty("Content-type", "application/timestamp-query");
con.setRequestProperty("Content-length", String.valueOf(request.length));

OutputStream out = con.getOutputStream();
out.write(request);
out.flush();

if (con.getResponseCode() != HttpURLConnection.HTTP_OK) {
    throw new IOException("Received HTTP error: " + con.getResponseCode() + " - " +                 con.getResponseMessage());
}
InputStream in = con.getInputStream();
TimeStampResp resp = TimeStampResp.getInstance(new ASN1InputStream(in).readObject());
response = new TimeStampResponse(resp);
response.validate(req);
if(response.getStatus() != 0) {
    System.out.println(response.getStatusString());
    return null;
}
return response;

谢谢你的帮助!

示例文件:

签名 PDF

未签名的 PDF

使用 iText 签名的 PDF

使用 LTV 签名的 PDF - 已编辑

4

1 回答 1

2

signed_lipsum.pdf,第一版

时间戳令牌引用为签名者一些

CN=e-Szigno Test TSA2,OU=e-Szigno CA,O=Microsec Ltd.,L=布达佩斯,C=HU

CN=Microsec e-Szigno 测试根 CA 2008,OU=e-Szigno CA,O=Microsec Ltd.,L=布达佩斯,C=HU

序列号为 7。

但是,它本身不提供此证书,封装签名 CMS 容器或某些验证相关信息 PDF 文档部分也没有提供此证书。

因此,至少在我的计算机上没有机会以任何方式验证时间戳令牌,Adobe Reader 完全正确不接受时间戳。

您是否以适合您的 Adob​​e Reader 的方式在您的计算机上提供了相关证书?如果您有,但仍然无法正常工作,请提供它以进行进一步测试。如果还没有,请尝试检索并提供它们。

您可能希望增强时间戳令牌本身以包含该证书,然后再将其包含到签名中。

signed_lipsum.pdf,第二版

在更新的文件 signed_lipsum.pdf 中,签名时间戳包含 TSA 证书,但它是错误的!

就像在第一个版本中一样,时间戳引用签名者证书

  • 主题 CN=e-Szigno Test TSA2,OU=e-Szigno CA,O=Microsec Ltd.,L=布达佩斯,C=HU
  • 发行人 CN=Microsec e-Szigno 测试根 CA 2008,OU=e-Szigno CA,O=Microsec Ltd.,L=布达佩斯,C=HU
  • 序列号 7。

另一方面,包含的证书具有

  • 主题 CN=e-Szigno Test TSA2,OU=e-Szigno CA,O=Microsec Ltd.,L=布达佩斯,C=HU
  • 发行人 CN=Microsec e-Szigno 测试根 CA 2008,OU=e-Szigno CA,O=Microsec Ltd.,L=布达佩斯,C=HU
  • 序列号 5。

我假设测试 TSA 使用多个带有单独证书的签名设备/软令牌,并且 OP 包含了错误的。

因此,您可能希望包含正确的证书。

顺便说一句,由 iText 签名的 PDF 中的时间戳包含与戳中的引用匹配的证书......

RFC 3161 时间戳请求可以要求 TSA 自动包含签名者证书。Bouncy Castle 允许像这样设置这个标志:

TimeStampRequestGenerator reqgen = new TimeStampRequestGenerator();
reqgen.setCertReq(true); // <<<<<<<<<<<<<<<<<<<<<<<<<<
TimeStampRequest req = reqgen.generate(TSPAlgorithms.SHA1, data);

您可以尝试这个,而不是自己包含证书。

启用 LTV

从评论:

只是出于好奇,需要添加哪些额外内容才能启用 PDF LTV?

引用 Leonard Rosenthol(Adobe 的 PDF 专家)的话:

启用 LTV 意味着验证文件所需的所有信息(减去根证书)都包含在其中。因此,这种说法 [...] 将是正确的。

PDF 已正确签名并包含所有必要的证书、每个证书的有效 CRL 或 OSCP 响应

2013 年 1 月 10 日;晚上 7:07;Leonard Rosenthol 在 itext-general 上

于 2014-02-19T08:59:30.573 回答