根据我目前的理解,在签署 PDF 时不允许为时间戳证书添加
DSS
(如果是签名时间戳)。因此,我尝试首先签署 PDF,保存它,然后将其重新加载为 PDDocument
,为时间戳证书添加 DSS
。
下面是我的源代码:
//This saves the signed file to responseStream
ByteArrayInputStream responseStream = new ByteArrayInputStream(outputStream.toByteArray());
//Reloads output PDF as PDDocument to embed DSS for TSA Certificates
PDDocument documentForLTV = PDDocument.load(responseStream);
//New response stream with DSS
ByteArrayOutputStream outputStreamLTV = new ByteArrayOutputStream();
//Adds revocation info and certs for TSA into DSS of PDDocument
addValidationInformation(documentForLTV, TSACertificates);
documentForLTV.saveIncremental(outputStreamLTV);
//Checking updated DSS. Updated DSS shows TSA certs which are expected to be added.
PDDocumentCatalog docCatalog = documentForLTV.getDocumentCatalog();
COSDictionary catalog = docCatalog.getCOSObject();
COSDictionary dss = validationService.getOrCreateDictionaryEntry(COSDictionary.class, catalog, "DSS");
COSArray certs = validationService.getOrCreateDictionaryEntry(COSArray.class, dss, "Certs");
//final output response. This outputStreamLTV does not contain the TSA Certs and revocation info.
ByteArrayInputStream responseStreamLTV = new ByteArrayInputStream(outputStreamLTV.toByteArray());
documentForLTV.close();
return responseStreamLTV;
在这里,我使用我的方法
addValidationInformation
将时间戳证书和吊销信息添加到DSS。这是相同的方法,我用它来将签名证书的验证信息添加到DSS
。在调试时,我可以看到它成功地将时间戳证书添加到 DSS。但我在最终输出的 PDF 中找不到它们。
outputStreamLTV
仅包含签名证书的验证信息。
addValidationInformation方法如下:
public void addValidationInformation(PDDocument document, Certificate[] certificateChain) {
List<String> ocspResponse = getOcspData(certificateChain);
List<String> crlResponse = getClrData(certificateChain);
List<String> certificates = getCertificates(certificateChain);
PDDocumentCatalog docCatalog = document.getDocumentCatalog();
COSDictionary catalog = docCatalog.getCOSObject();
catalog.setNeedsTobeUpdated(true);
// As mentioned in PDFBox Samples
COSDictionary dss = getOrCreateDictionaryEntry(COSDictionary.class, catalog, "DSS");
dss.setNeedsTobeUpdated(true);
COSDictionary vri = getOrCreateDictionaryEntry(COSDictionary.class, dss, "VRI");
vri.setNeedsTobeUpdated(true);
COSArray ocsps = getOrCreateDictionaryEntry(COSArray.class, dss, "OCSPs");
ocsps.setNeedsTobeUpdated(true);
COSArray crls = getOrCreateDictionaryEntry(COSArray.class, dss, "CRLs");
crls.setNeedsTobeUpdated(true);
COSArray certs = getOrCreateDictionaryEntry(COSArray.class, dss, "Certs");
certs.setNeedsTobeUpdated(true);
if (ocspResponse != null) {
ocspResponse.forEach(ocsp -> {
byte[] ocspData = b64Decoder.decode(ocsp);
try {
ocsps.add(writeDataToStream(ocspData, document));
} catch (IOException e) {
e.printStackTrace();
}
});
}
if (!ocspResponse.isEmpty()) {
vri.setItem("OCSP", ocsps);
}
//Same for CRL and Certs...
}
我的其他一些发现是:
AddValidationInformation
和 this 方法以类似的方式添加时间戳证书和吊销信息。但我更喜欢使用我当前的实现,因为该示例并不完全符合我的要求。此外,他们还会为相同的功能添加重复的代码。PDDocument.save(outputStreamLTV)
代替PDDocument.saveIncremental(outputStreamLTV)
。输出 PDF 显示所需的 DSS,但签名无效。请建议我如何使现有代码正常工作以及我缺少什么?将 PDDocument 保存到流中时似乎存在一些问题。 或者这是
PDFBox
一侧的错误,因为我可以在签名之前使用相同的方法 addValidationInformation
添加 DSS,使用对 TSA 的一个虚拟调用来获取证书。