问题
I'm trying to do the following setup for signing pdfs, broken down into asynchronous steps between a client and a server:
- A server receives a pdf and computes it's digest.
- Server sends the digest to a client.
- Client signs the hash at a later time.
- Client sends the signature to server.
- Server embeds the signature into the pdf.
I'm basing myself mainly in PDF Signature digest and Create pkcs7 signature from file digest
The second question allowed me to write most of the code, however I'm getting that the integrity of the file has been compromised. I can't seem to serialize the intermediary pdf for embedding the signature later (to make sure no timestamps are altered, etc). But from the first SO question, it seems to be a harder problem than I thought. Can it actually be done?
I'm using pdfbox.
Server code:
PDDocument document = PDDocument.load(documentFile);
PDSignature signature = new PDSignature();
signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
signature.setName("Example User");
signature.setLocation("Los Angeles, CA");
signature.setReason("Testing");
Calendar date = Calendar.getInstance();
signature.setSignDate(date);
document.addSignature(signature);
ExternalSigningSupport externalSigningSupport = document.saveIncrementalForExternalSigning(null);
byte[] content = IOUtils.toByteArray(externalSigningSupport.getContent());
MessageDigest md = MessageDigest.getInstance("SHA256", new BouncyCastleProvider());
byte[] digest = md.digest(content); // this is sent to client
What I'm basically doing is sending that digest to the client to sign and then on the server redoing the above steps and setting the client signature:
ExternalSigningSupport externalSigning = document.saveIncrementalForExternalSigning(fos);
externalSigning.setSignature(encodedSignature); // encodedSignature is received from client and computed based on the digest sent by the server
This setup ends up with the integrity of the file being corrupted, since I'm creating a new PDSignature once I have the encodedSignature
on the server to embed it. Is there a way to serialize the PDDocument created after calling addSignature, so I can later deserialize it on the server and add the client's signature?
回答1:
What I'm basically doing is sending that digest to the client to sign and then on the server redoing the above steps and setting the client signature
If you want those above steps to generate identical documents, you need to
- make sure the inputs to those steps are identical and
- provide the same revision id seed value.
If you do so, the outputs of the above steps are identical as is required for your task.
Making sure the inputs are identical
One step of your above steps is prone to result in different inputs:
Calendar date = Calendar.getInstance();
signature.setSignDate(date);
To guarantee identical inputs, you have to determine date
only once and use that single value every time you execute those steps for the same signing transaction.
Providing the same revision id seed value
As recommended by the specification, PDFBox attempts to give each PDF revision its unique ID. In the case at hand, though, we need the same revision ID both times the above steps are executed.
Fortunately, PDFBox allows us to provide the seed value it uses to make the revision ID unique enough.
As we don't want to same revision ID all the time we sign the same document but merely during the current signing transaction, we should use the same seed value only in the same transaction. As the seed value is a long, we can simply use the time in milliseconds corresponding to the date
already discussed above, i.e.:
pdDocument.setDocumentId(date.getTimeInMillis());
来源:https://stackoverflow.com/questions/46689478/sign-pdf-asynchronously-using-digest