Java中带时间戳的数字签名

Java中带时间戳的数字签名,java,pdf,pdf-generation,bouncycastle,trusted-timestamp,Java,Pdf,Pdf Generation,Bouncycastle,Trusted Timestamp,我在使用可信时间戳创建具有Bouncy Castle的有效CMS签名时遇到问题。签名创建工作正常(我想将签名包含到PDF文件中),签名有效。但是在我将可信时间戳包括到签名的unsigned属性表中之后,签名仍然保持有效,但是读取器报告签名包括嵌入的时间戳,但它无效。这让我相信,hash I时间戳不是正确的,但我似乎无法找出它的问题所在 签署代码: 时间戳数据: TimeStampRequestGenerator reqgen = new TimeStampRequestGenerator();

我在使用可信时间戳创建具有Bouncy Castle的有效CMS签名时遇到问题。签名创建工作正常(我想将签名包含到PDF文件中),签名有效。但是在我将可信时间戳包括到签名的unsigned属性表中之后,签名仍然保持有效,但是读取器报告签名包括嵌入的时间戳,但它无效。这让我相信,hash I时间戳不是正确的,但我似乎无法找出它的问题所在

签署代码:

时间戳数据

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_lipsum.pdf,第一版 时间戳令牌引用为某些签名者

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

已由

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

序列号是7

但是,它本身并不提供此证书,它也不是由封装签名CMS容器提供的,也不是在一些与验证相关的信息PDF文档部分中提供的

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

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

您可能希望增强时间戳令牌本身,以便在将其包含到签名中之前包含该证书

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

就像在第一个版本中一样,时间戳引用具有

  • 受试者CN=e-Szigno测试TSA2,OU=e-Szigno CA,O=Microsec有限公司,L=布达佩斯,C=HU
  • 发行人CN=Microsec e-Szigno测试根CA 2008,OU=e-Szigno CA,O=Microsec Ltd.,L=布达佩斯,C=HU
  • 序列号7。
另一方面,包含的证书已

  • 受试者CN=e-Szigno测试TSA2,OU=e-Szigno CA,O=Microsec有限公司,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);
TimeStampRequestGenerator reqgen=new TimeStampRequestGenerator();

请求根setCertReq(真);//你确定你的
timestamdata
方法吗?你能提供一个由你的代码签名和时间戳的PDF样本吗?老实说,我再也不确定了我已经添加了timestamdata方法,并上传了一个有符号和无符号的PDF示例。我稍后将对此进行研究,但读者不应该说时间戳无法验证,而不是说它无效吗?看看-直到时间戳的一些看似次要的细节得到修复,Adobe Reader声称文档已被更改。此外,我还看到其他软件在验证过程中未找到签名者证书时抛出
NullPointerException
,也就是说,我不能保证这就是原因;它本质上就是我被卡住的地方,Adobe Reader可能也被卡住了。我明白了,我应该如何增强TimeStampToken?我得到它的
CMSSignedData
结构,并使用
replaceCertificates和crls
方法替换(添加)从TSP下载得到的证书。我理解正确吗?我不是BC专家,但乍一看,这似乎就是我的意思。
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;
TimeStampRequestGenerator reqgen = new TimeStampRequestGenerator();
reqgen.setCertReq(true); // <<<<<<<<<<<<<<<<<<<<<<<<<<
TimeStampRequest req = reqgen.generate(TSPAlgorithms.SHA1, data);