我正在使用pdfBox完成一个包含撤销信息的pades文档。目标是文档变为启用了LTV。
我使用的文档有一个签名和一个时间戳。我已经获得了必要的crl/ocsp令牌。
我的问题是,我如何构造一个具有来自CRL和OCSP的响应的COSDictionary?
InMemoryDocument doc = new InMemoryDocument(getFile());
PDDocument document = PDDocument.loadNonSeq(doc.openStream(), null);
COSDictionary cosDictionary = document.getDocumentCatalog().getCOSDictionary();
...
cosDictionary.setNeedToBeUpdate(true);谢谢
发布于 2015-06-10 19:29:45
假设您拥有以字节数组形式提供的必要证书、CRL和OCSP响应,您可以使用PDFBox将它们添加到文档安全性存储中:
COSDictionary dss = createDssDictionary(certificates, crls, ocspResponses);使用这些辅助方法:
COSDictionary createDssDictionary(Iterable<byte[]> certificates, Iterable<byte[]> crls, Iterable<byte[]> ocspResponses) throws IOException
{
final COSDictionary dssDictionary = new COSDictionary();
dssDictionary.setNeedToBeUpdate(true);
dssDictionary.setName(COSName.TYPE, "DSS");
if (certificates != null)
dssDictionary.setItem(COSName.getPDFName("Certs"), createArray(certificates));
if (crls != null)
dssDictionary.setItem(COSName.getPDFName("CRLs"), createArray(crls));
if (ocspResponses != null)
dssDictionary.setItem(COSName.getPDFName("OCSPs"), createArray(ocspResponses));
return dssDictionary;
}
COSArray createArray(Iterable<byte[]> datas) throws IOException
{
COSArray array = new COSArray();
array.setNeedToBeUpdate(true);
if (datas != null)
{
for (byte[] data: datas)
array.add(createStream(data));
}
return array;
}
COSStream createStream(byte[] data) throws IOException
{
RandomAccessBuffer storage = new RandomAccessBuffer();
COSStream stream = new COSStream(storage);
stream.setNeedToBeUpdate(true);
final OutputStream unfilteredStream = stream.createUnfilteredStream();
unfilteredStream.write(data);
unfilteredStream.flush();
return stream;
}您可以将这样的DSS字典作为增量更新添加到源文档中,如下所示:
try ( InputStream source = ...;
FileOutputStream fos = new FileOutputStream(resultFile);
FileInputStream fis = new FileInputStream(resultFile);
)
{
byte[] inputBytes = IOUtils.toByteArray(source);
PDDocument pdDocument = PDDocument.load(new ByteArrayInputStream(inputBytes));
PDDocumentCatalog catalog = pdDocument.getDocumentCatalog();
catalog.getCOSObject().setNeedToBeUpdate(true);
catalog.getCOSDictionary().setItem(COSName.getPDFName("DSS"), dss);
fos.write(inputBytes);
pdDocument.saveIncremental(fis, fos);
pdDocument.close();
}发布于 2015-07-28 22:11:52
再次分析代码后,我在证书编码中发现了一些错误。我认为这就是文件损坏的原因。下面是我用来将链式证书添加到DSS字典的代码。我已经重用了你的代码。再次感谢。
private byte[] addCertificates(byte[] pdfFile) throws IOException, PDFLTVEnablerException {
ByteArrayInputStream stream = new ByteArrayInputStream(pdfFile);
PDDocument document = PDDocument.load(stream);
PDDocumentCatalog catalog = document.getDocumentCatalog();
COSDictionary catalogDictionary = catalog.getCOSDictionary();
COSDictionary dssDictionary = (COSDictionary) catalogDictionary.getDictionaryObject("DSS");
dssDictionary.setNeedToBeUpdate(true);
COSArray certDSS = getTrustedCertificatesChain();
dssDictionary.setItem(COSName.getPDFName("Certs"), certDSS);
catalog.getCOSObject().setNeedToBeUpdate(true);
catalogDictionary.setItem(COSName.getPDFName("DSS"), dssDictionary);
File resultFile = File.createTempFile("dss", null);
FileOutputStream fos = new FileOutputStream(resultFile);
FileInputStream fis = new FileInputStream(resultFile);
fos.write(pdfFile);
try {
document.saveIncremental(fis, fos);
} catch (COSVisitorException e) {
logger.debug(e.getMessage());
throw new PDFLTVEnablerException("Couldn't access PDF DSS dictionary");
}
FileInputStream out = new FileInputStream(resultFile);
byte[] byteArray = IOUtils.toByteArray(out);
resultFile.delete();
document.close();
return byteArray;
}
private byte[] addRevocationInfo(byte[] pdfFile) throws IOException, PDFLTVEnablerException {
ByteArrayInputStream stream = new ByteArrayInputStream(pdfFile);
PDDocument document = PDDocument.load(stream);
PDDocumentCatalog catalog = document.getDocumentCatalog();
COSDictionary catalogDictionary = catalog.getCOSDictionary();
COSDictionary dssDictionary = (COSDictionary) catalogDictionary.getDictionaryObject("DSS");
dssDictionary.setNeedToBeUpdate(true);
COSArray crlsDss = loadCrlsForCerts(pdfFile);
dssDictionary.setItem(COSName.getPDFName("CRLs"), crlsDss);
dssDictionary.setItem(COSName.getPDFName("OCSPs"), new COSArray());
catalog.getCOSObject().setNeedToBeUpdate(true);
catalogDictionary.setItem(COSName.getPDFName("DSS"), dssDictionary);
File resultFile = File.createTempFile("dss", null);
FileOutputStream fos = new FileOutputStream(resultFile);
FileInputStream fis = new FileInputStream(resultFile);
fos.write(pdfFile);
try {
document.saveIncremental(fis, fos);
} catch (COSVisitorException e) {
logger.debug(e.getMessage());
throw new PDFLTVEnablerException("Couldn't access PDF DSS dictionary");
}
FileInputStream out = new FileInputStream(resultFile);
byte[] byteArray = IOUtils.toByteArray(out);
resultFile.delete();
document.close();
return byteArray;
}
private COSArray getTrustedCertificatesChain() throws IOException {
COSArray certs = new COSArray();
certs.setNeedToBeUpdate(true);
List < X509Certificate > trustedCerts = trustedCertsStore.getTrustedCerts();
for (X509Certificate cert: trustedCerts) {
try {
COSStream certStream = createStream(cert.getEncoded());
certs.add(certStream);
} catch (CertificateException e) {
logger.error("Could not import trusted certificate: " + e.getMessage());
throw new IOException("The certificate in the truststore is invalid");
}
}
return certs;
}
private COSArray loadCrlsForCerts(byte[] pdfFile) throws IOException, PDFLTVEnablerException {
COSArray crls = new COSArray();
crls.setNeedToBeUpdate(true);
List < X509Certificate > trustedCerts = trustedCertsStore.getTrustedCerts();
for (X509Certificate cert: trustedCerts) {
try {
X509CRL crl = crlDownloader.verifyCertificateCRLs(cert);
if (crl != null) {
COSStream crlStream = createStream(crl.getEncoded());
crls.add(crlStream);
}
} catch (CertificateException e) {
logger.error("Could not import trusted certificate: " + e.getMessage());
throw new IOException("The certificate in the truststore is invalid");
} catch (CertificateVerificationException e) {
logger.error("Could not import trusted certificate: " + e.getMessage());
throw new IOException("The certificate in the truststore is invalid");
} catch (CRLException e) {
logger.debug("Error downloading crl " + e.getMessage());
throw new Exception("Couldn't retrive CRL");
} catch (NamingException e) {
logger.debug(e.getMessage());
throw new Exception("Couldn't retrive CRL");
}
}
return crls;
}
public COSStream createStream(byte[] data) throws IOException {
RandomAccessBuffer storage = new RandomAccessBuffer();
COSStream stream = new COSStream(storage);
stream.setNeedToBeUpdate(true);
final OutputStream unfilteredStream = stream.createUnfilteredStream();
unfilteredStream.write(data);
unfilteredStream.flush();
return stream;
}发布于 2015-06-09 22:21:56
实际上,我并没有直接使用PDFbox。
我从一个PAdESService类型的对象开始,我的目标是将时间戳添加到PDF中。
我已经像这样构建了DSS字典:
private PdfDict createDSSDictionary() throws IOException, CertificateEncodingException {
final PdfDict dssDictionary = factory.newDict("DSS");
for (X509Certificate x509Certificate : certs) {
PdfStream stream = factory.newStream(x509Certificate.getEncoded());
certArray.add(stream);
}
if (certArray.size() > 0) {
dssDictionary.add("Certs", certArray);
}
if (crlArray.size() > 0) {
dssDictionary.add("CRLs", crlArray);
}
if (ocspArray.size() > 0) {
dssDictionary.add("OCSPs", ocspArray);
}
return dssDictionary;
}此方法仅显示Certs流的构造,OCSP和CRL的过程类似。
接下来就是丑陋的部分了。
我已经更改了类eu.europa.ec.markt.dss.parameter.SignatureParameters.我已经添加了参数PdfDict,它包含我想要插入到PDF中的DSS字典( DSS是从上一个函数返回的)。
然后,在eu.europa.ec.markt.dss.signature.pades.PAdESLevelBaselineLT类中,我从signatureParameters中获取决策支持系统字典,并将其用作参数来扩展timsetamp(..)类eu.europa.ec.markt.dss.signature.pdf.PDFTimestampService的函数。
https://stackoverflow.com/questions/30617875
复制相似问题