In Itext 7, how to sign a pdf with 2 steps?

匿名 (未验证) 提交于 2019-12-03 01:25:01

问题:

Following the answers given in this previous question : In Itext 7, how to get the range stream to sign a pdf?, i've tried to reimplement the two steps signing method working in Itext 5 but i encounter an issue when trying to reopen the document result of the first step (with the PdfReader or a pdf reader).(invalid document)

Here is the presigning part for a document already containing an empty signature field named certification ... why is the result of this step invalid ?

PdfReader reader = new PdfReader(fis); Path signfile = Files.createTempFile("sign", ".pdf"); FileOutputStream os = new FileOutputStream(signfile.toFile()); PdfSigner signer = new PdfSigner(reader, os, false); signer.setFieldName("certification"); // this field already exists signer.setCertificationLevel(PdfSigner.CERTIFIED_FORM_FILLING); PdfSignatureAppearance sap = signer.getSignatureAppearance(); sap.setReason("Certification of the document"); sap.setLocation("On server"); sap.setCertificate(maincertificate); BouncyCastleDigest digest = new BouncyCastleDigest(); PdfPKCS7 sgn = new PdfPKCS7(null, chain, hashAlgorithm, null, digest,false);  //IExternalSignatureContainer like BlankContainer PreSignatureContainer external = new    PreSignatureContainer(PdfName.Adobe_PPKLite,PdfName.Adbe_pkcs7_detached); signer.signExternalContainer(external, 8192); byte[] hash=external.getHash(); byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, null, null,PdfSigner.CryptoStandard.CMS);// sh will be sent for signature

And here is the PreSignatureContainer class :

public class PreSignatureContainer implements IExternalSignatureContainer {  private PdfDictionary sigDic; private byte hash[];   public PreSignatureContainer(PdfName filter, PdfName subFilter) {      sigDic = new PdfDictionary();     sigDic.put(PdfName.Filter, filter);     sigDic.put(PdfName.SubFilter, subFilter); }  @Override public byte[] sign(InputStream data) throws GeneralSecurityException {     String hashAlgorithm = "SHA256";     BouncyCastleDigest digest = new BouncyCastleDigest();      try {     this.hash= DigestAlgorithms.digest(data, digest.getMessageDigest(hashAlgorithm));     } catch (IOException e) {         throw new GeneralSecurityException("PreSignatureContainer signing exception",e);     }      return new byte[0]; }  @Override public void modifySigningDictionary(PdfDictionary signDic) {     signDic.putAll(sigDic);  }  public byte[] getHash() {     return hash; }  public void setHash(byte hash[]) {     this.hash = hash; }

}

回答1:

why is the result of this step invalid

Because you essentially discovered a bug... ;)

Your sample input file has one feature which triggers the bug: It is compressed using object streams.

When iText manipulates such a file, it also tries to put as many objects as possible into object streams. Unfortunately it also does so with the signature dictionary. This is unfortunate because after writing the whole file it tries to enter some information (which are not available before) into this dictionary which damages the compressed object stream.


What you can do...

You can either

  • wait for iText development to fix this issue - I assume this won't take too long but probably you don't have the time to wait; or
  • convert the file to sign into a form which does not use object streams - this can be done using iText itself but probably you cannot accept the file growth this means, or probably the files already are signed which forbids any such transformation; or
  • patch iText 7 to force the signature dictionary not to be added to an object stream - it is a trivial patch but yo
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!