I'm trying to migrate my application from iText 5.5.9 to iText 7 and I have a problem with signing a document on the server using a signature created on the client (described in the Digital Signatures for PDF documents).
As the getRangeStream()
method isn't public anymore as it was in iText 5.5.9, how can I obtain a reference to the range stream?
getRangeStream
is not the only method that was refactored fromPdfSignatureAppearance
toPdfSigner
and madeprotected
on that way. The same problem exists for other methods, too, likepreClose
andclose
which are also methods used in thePreSign
andPostSign
servlets from Digital Signatures for PDF documents which you seem to use or at least borrow code from.This, as I presume, has been done to make iText 7 users use the
signDeferred
,signDetached
, andsignExternalContainer
methods which usually are sufficient for signing applications and "do it correctly", i.e. use the other, now not anymore public methods in a way that creates valid signatures.The
PreSign
andPostSign
servlets as they are unfortunately cannot use those three methods, they actually are like thesignDetached
code ripped in two halves with the relevant local variables stored in the HTTP session.Thus, you essentially have two choices:
Use the protected methods nonetheless
Unless I overlooked something, this can even be done by deriving your own signer class from
PdfSigner
and making those methods and probably member variables publicly accessibly again; using reflection magic at first sight doesn't seem necessary.Change the
PreSign
andPostSign
servlet architectureIf you could switch from keeping those signing related objects in memory (referenced via the HTTP session) to merely keeping an intermediary PDF file in memory or even on disk and probably the half-baked signature container in memory, you could proceed like this:
Replace the
PreSign
servlet by a servlet that "signs" the PDF usingPdfSigner.signExternalContainer
with aIExternalSignatureContainer
implementation that merely provides a dummy signature, e.g.new byte[0]
.This
IExternalSignatureContainer
retrieves the sought-for range stream as parameter of itssign
method, so it can calculate the range stream hash.Now the PDF with the dummy signature can be saved to disk or held in memory. And based on the range stream hash you can continue constructing and feeding the
PdfPKCS7
instance as before. And hold that in memory, e.g. referenced from the HTTP session.Replace the
PostSign
servlet by a servlet that as before finishes feeding thePdfPKCS7
instance and generates a CMS signature container. Then inject this container into the saved PDF using thePdfSigner.signDeferred
method.Alternatively you could even move the whole CMS signature container creation to the client. In that case all the session has to remember is where the intermediary PDF is stored...
Some inspiration may come from the C4_09_DeferredSigning.java iText 7 example.