Java中带有时间戳的数字签名



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

签名代码:

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

签名PDF与LTV-编辑

signed_lipsum.pdf,第一版

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

CN=e-Szigno测试TSA2,OU=e-Szygno CA,O=Microsec有限公司,L=布达佩斯,C=HU

已由发布

CN=Microsec e-Szigno Test Root CA 2008,OU=e-Szinio CA,O=Microsec有限公司,L=布达佩斯,C=HU

序列号为7。

不过,它本身并不提供此证书,封装签名CMS容器也不提供该证书,某些验证相关信息PDF文档部分也不提供此证书。

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

您是否以适合您的Adobe Reader的方式在您的计算机上提供了有问题的证书?如果你有,但仍然不起作用,请提供它进行进一步的测试。如果没有,请尝试检索并提供它们。

在将证书包含到签名中之前,您可能需要增强时间戳令牌本身以包含该证书。

signed_lipsum.pdf,第二版

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

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

  • 受试者CN=e-Szigno测试TSA2,OU=e-Szygno CA,O=Microsec有限公司,L=布达佩斯,C=HU
  • 发行人CN=Microsec e-Szigno Test Root CA 2008,OU=e-Szinio CA,O=Microsec有限公司,L=布达佩斯,C=HU
  • 序列号7。

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

  • 受试者CN=e-Szigno测试TSA2,OU=e-Szygno CA,O=Microsec有限公司,L=布达佩斯,C=HU
  • 发行人CN=Microsec e-Szigno Test Root CA 2008,OU=e-Szinio CA,O=Microsec有限公司,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?

引用LeonardRosenthol(Adobe的PDF大师)的话:

启用LTV意味着验证文件所需的所有信息(减去根证书)都包含在内。所以这个说法[…]是正确的。

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

(2013年1月10日;7:07pm;LeonardRosenthol on itext general)

相关内容

  • 没有找到相关文章

最新更新