My signature structure disturbs on embedding signature using itext7

前端 未结 1 436
一整个雨季
一整个雨季 2021-01-28 00:32

I am using itext7 version 7.1.5 in my application. My scenario is as following: - Take the hash of the document - Sign the hash from external signing server and get Pkcs7 - Embe

1条回答
  •  北海茫月
    2021-01-28 00:54

    To sign a PDF with iText 7 using a remote server to create the actual cryptographic signature, you can simply implement an iText signature interface which executes the call of the remote service in its Sign method for the given data.

    Furthermore, you clarified in a comment that your

    external signing server returns PKCS7 signature signed data.

    Thus, the interface to use is an IExternalSignatureContainer (and not a IExternalSignature which one would have used if the server returned merely the primitive signature bytes).

    I don't know how you communicate with your server; in particular I don't know whether the API you use requires you to provide the complete signed data or merely the hash thereof; and in the former case, whether to provide them as stream or array. Thus, I put hints into the Sign method for each case:

    public class ExternalServiceSignatureContainer : IExternalSignatureContainer
    {
        public void ModifySigningDictionary(PdfDictionary signDic)
        {
            signDic.Put(PdfName.Filter, PdfName.Adobe_PPKLite);
            signDic.Put(PdfName.SubFilter, PdfName.Adbe_pkcs7_detached);
        }
    
        public byte[] Sign(Stream data)
        {
            // Call your external signing service to create a CMS signature container
            // for the data in the InputStream
    
            // Depending on your API to access that service you may either be able to
            // directly call it with the stream
         // return YOUR_SIGNING_API_CALL_FOR_STREAM(data);
            // (or a byte[] generated from the stream contents)
         // return YOUR_SIGNING_API_CALL_FOR_ARRAY(StreamUtil.InputStreamToArray(data));
            // as parameter, or you may first have to hash the data yourself
            // (e.g. as follows) and send your hash to the service.
         // byte[] hash = DigestAlgorithms.Digest(data, DigestAlgorithms.SHA256);
         // return YOUR_SIGNING_API_CALL_FOR_HASH(hash)
    
            // dummy
            return new byte[0];
        }
    }
    

    You can then use this class as follows:

    PdfReader pdfReader = new PdfReader(DOCUMENT_TO_SIGN);
    PdfSigner pdfSigner = new PdfSigner(pdfReader, RESULT_STREAM, new StampingProperties().UseAppendMode());
    
    pdfSigner.SetFieldName("Signature1");
    
    ImageData imageData = ImageDataFactory.Create(SIGNATURE_IMAGE);
    
    PdfSignatureAppearance sigAppearance = pdfSigner.GetSignatureAppearance();
    sigAppearance.SetContact("ContactInfo");
    sigAppearance.SetLocation("Location");
    sigAppearance.SetPageNumber(1);
    sigAppearance.SetPageRect(new Rectangle(100, 500, imageData.GetWidth() / 2, imageData.GetHeight() / 2));
    sigAppearance.SetReason("SigningReason");
    sigAppearance.SetSignatureGraphic(imageData);
    sigAppearance.SetRenderingMode(RenderingMode.GRAPHIC);
    sigAppearance.SetSignatureCreator("Malik");
    
    pdfSigner.GetDocument().GetCatalog().SetModified();
    
    int estimatedSize = 12000;
    pdfSigner.SignExternalContainer(new ExternalServiceSignatureContainer(), estimatedSize);
    

    Some remarks:

    I added

    sigAppearance.SetPageRect(new Rectangle(100, 500, imageData.GetWidth() / 2, imageData.GetHeight() / 2));
    

    because I also used a different document to test. As that other document does not originally contain a signature field named Signature1, I needed to set the rectangle to get a visible signature. In case of your document which already has such a signature field, that line can be dropped but is ignored anyways.

    The line

    pdfSigner.GetDocument().GetCatalog().SetModified();
    

    needs to be added because of a small bug in iText: When signing an existing field (not a new field), the AcroForm dictionary (in particular if contained directly in the Catalog like in your document), is not marked as modified and, therefore, not updated in the incremental update. This prevents the SigFlags in your document from being set which causes Adobe Reader not display the top signature bar.

    You might want to change the estimate

    int estimatedSize = 12000;
    

    of the signature container size, in particular if the signature containers you retrieve always are much smaller or sometimes larger than 12000 bytes.

    0 讨论(0)
提交回复
热议问题