I\'m trying to build an application where the following happens:
It seems that you have overlooked the DeferredSigning example.
In this example, we first create a PDF with an empty signature:
public void emptySignature(String src, String dest, String fieldname, Certificate[] chain) throws IOException, DocumentException, GeneralSecurityException {
PdfReader reader = new PdfReader(src);
FileOutputStream os = new FileOutputStream(dest);
PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0');
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
appearance.setVisibleSignature(new Rectangle(36, 748, 144, 780), 1, fieldname);
appearance.setCertificate(chain[0]);
ExternalSignatureContainer external = new ExternalBlankSignatureContainer(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
MakeSignature.signExternalContainer(appearance, external, 8192);
}
Granted, the public certificate chain[0]
is passed to the appearance
in this example, it is used to create the visual appearance and to create the PdfPKCS7
object.
Once you have a PDF with an empty signature, you can create a PdfSignatureAppearance
on the server and get the hash that can be sent to the client for signing. This can be done using the getRangeStream()
method to get the ranges of PDF bytes that need to be hashed. This method returns an InputStream
, that can be used like this:
BouncyCastleDigest digest = new BouncyCastleDigest();
PdfPKCS7 sgn = new PdfPKCS7(null, chain, hashAlgorithm, null, digest, false);
byte[] hash = DigestAlgorithms.digest(is, digest.getMessageDigest(hashAlgorithm));
Calendar cal = Calendar.getInstance();
byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, cal, null, null, CryptoStandard.CMS);
Now you can send this sh
to the client for signing. You will receive another byte[]
which is the actual signature that needs to be added to the PDF, let's say the byte[]
is called sig
.
Your external signature container can be kept very simple: it just needs to return the signature bytes:
class MyExternalSignatureContainer implements ExternalSignatureContainer {
protected byte[] sig;
public MyExternalSignatureContainer(byte[] sig) {
this.sig = sig;
}
public byte[] sign(InputStream is) throws Exception {
return sig;
}
public void modifySigningDictionary(PdfDictionary signDic) {
}
}
You can now use the createSignature()
method on the server:
public void createSignature(String src, String dest, String fieldname, PrivateKey pk, Certificate[] chain) throws IOException, DocumentException, GeneralSecurityException {
PdfReader reader = new PdfReader(src);
FileOutputStream os = new FileOutputStream(dest);
ExternalSignatureContainer external = new MyExternalSignatureContainer(sig);
MakeSignature.signDeferred(reader, fieldname, os, external);
}