【问题标题】:Digital signature with timestamp in JavaJava中带有时间戳的数字签名
【发布时间】:2014-02-18 09:24:16
【问题描述】:

我在使用受信任的时间戳通过 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;

感谢您的帮助!

示例文件:

Signed PDF

Unsigned PDF

Signed PDF with iText

Signed PDF with LTV - 已编辑

【问题讨论】:

  • 您确定您的timestampData 方法吗?您能否进一步提供由您的代码签名并加盖时间戳的示例 PDF?
  • 说实话,我什么都不确定了。 :) 我添加了 timestampData 方法,并上传了一个签名和一个未签名的 PDF 示例。
  • 我稍后会调查这个

标签: java pdf pdf-generation bouncycastle trusted-timestamp


【解决方案1】:

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 证书,但它是错误的!

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

  • Subject CN=e-Szigno Test TSA2,OU=e-Szigno CA,O=Microsec Ltd.,L=Budapest,C=HU
  • 发行人 CN=Microsec e-Szigno Test Root CA 2008,OU=e-Szigno CA,O=Microsec Ltd.,L=Budapest,C=HU
  • 序列号 7。

另一方面,包含的证书有

  • Subject CN=e-Szigno Test TSA2,OU=e-Szigno CA,O=Microsec Ltd.,L=Budapest,C=HU
  • 发行人 CN=Microsec e-Szigno Test Root CA 2008,OU=e-Szigno CA,O=Microsec Ltd.,L=Budapest,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

来自cmets:

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

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

启用 LTV 意味着验证文件所需的所有信息(减去根证书)都包含在其中。所以这个陈述 [...] 是正确的。

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

(Jan 10, 2013; 7:07pm;Leonard Rosenthol on itext-general)

【讨论】:

  • 但是读者不应该说时间戳无法验证而不是说它无效吗?
  • 看看this answer - 直到一些看似次要的时间戳细节得到修复,Adobe Reader 声称文档已被更改。此外,我还看到其他软件在验证期间找不到签名者证书时抛出NullPointerExceptions...
  • 话虽如此,我不能保证是这个原因;它本质上是我卡住的地方,Adobe Reader 也可能卡在那里。
  • 我明白了,我应该如何加强 TimeStampToken?我得到它的CMSSignedData 结构并使用replaceCertificatesAndCRLs 方法来替换(添加)我通过从TSP 下载获得的证书。我理解正确吗?
  • 我不是 BC 专家,但乍一看这似乎是我的意思。
猜你喜欢
  • 2013-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-21
  • 2022-07-08
  • 2016-08-21
  • 2018-01-18
  • 1970-01-01
相关资源
最近更新 更多