I've been working on a digital signature function for some days, now that I have everything working it is time to try to print the stamp in all pages but I'm not doing great...
Trying to give a quick resume, to show the stamp what I do is creating PdfStamper, PdfSignatureAppearance and a Rectangle, then call the
appearance.setVisibleSignature(rectangle, 1, "SIGNATURE")
The second parameter "1" above is the page number that I want to show the stamp, it is okay to be 1 by now, as I tried to do in order to show stamp in other page was creating other instances of PdfStamper, PdfSignatureAppearance and a Rectangle but set it to page 2. If it had worked I would have put it within a loop and keep changing the page parameter.
But why didn't it work??? Well, near the end I call a method of MakeSignature and among the parameters I have to pass one of the appearences I created, if I call it more than once the signature appears only on the page related to the last appearence I pass to it.
For example:
MakeSignature.signDetached(appearance2, digest, pks, chain, null, null, null, 0, CryptoStandard.CMS);
MakeSignature.signDetached(appearance, digest, pks, chain, null, null, null, 0, CryptoStandard.CMS);
The stamp will be showed on the first page only.
Maybe I could get some help here???
Here it goes the whole thing:
public String signPdfFirstTime(String src, String dest, PrivateKey pk, Certificate[] chain, String providerName, String conteudoBase64, X509Certificate cert, String alias) throws IOException, DocumentException, GeneralSecurityException
{
byte[] conteudoBinario = Base64.decode(conteudoBase64);
FileOutputStream fos = new FileOutputStream(path + File.separator + src);
fos.write(conteudoBinario);
fos.close();
File f = new File(path + File.separator + src);
FileInputStream in = new FileInputStream(f);
PdfReader reader = new PdfReader(in);
int qtypages = reader.getNumberOfPages();
FileOutputStream os = new FileOutputStream(path + File.separator + dest);
PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0');
// Creating the appearance
PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
Rectangle rectangle = new Rectangle(550, 50, 610, 500);// funciona vertical
appearance.setVisibleSignature(rectangle, 1, "SIGNATURE");
//Here I build a custom message...nothing relevant
StringBuilder stampMessage = new StringBuilder();
stampMessage.append("...");
stampMessage.append(alias);
stampMessage.append(" - ");
// customize appearance layer 2 to display text vertically
PdfTemplate layer2 = appearance.getLayer(2);
layer2.transform(new AffineTransform(0, 1, -1, 0, rectangle.getWidth(), 0));
Font font = new Font();
font.setColor(BaseColor.BLACK);
ColumnText ct2 = new ColumnText(layer2);
ct2.setRunDirection(PdfWriter.RUN_DIRECTION_NO_BIDI);
ct2.setSimpleColumn(new Phrase(stampMessage.toString(), font), 0, 0, rectangle.getHeight(), rectangle.getWidth(), 15, Element.ALIGN_LEFT);
ct2.go();
appearance.setCertificate(cert);
//Here starts where I tried to make a second stamp to show in the page 2
FileOutputStream fos2 = new FileOutputStream(path + File.separator + src);
fos2.write(conteudoBinario);
fos2.close();
File f2 = new File(path + File.separator + src);
FileInputStream in2 = new FileInputStream(f2);
PdfReader reader2 = new PdfReader(in2);
FileOutputStream os2 = new FileOutputStream(path + File.separator + dest);
PdfStamper stamper2 = PdfStamper.createSignature(reader2, os2, '\0');
// Creating the appearance
PdfSignatureAppearance appearance2 = stamper2.getSignatureAppearance();
Rectangle rectangle2 = new Rectangle(550, 50, 610, 500);// funciona vertical
appearance2.setVisibleSignature(rectangle2, 3, "ASSINATURA2");
//Cria a msg que aparece na estampa
StringBuilder stampMessage2 = new StringBuilder();
stampMessage2.append(" - ");
PdfTemplate layer22 = appearance.getLayer(2);
layer22.transform(new AffineTransform(0, 1, -1, 0, rectangle2.getWidth(), 0));
Font font2 = new Font();
font2.setColor(BaseColor.BLACK);
ColumnText ct22 = new ColumnText(layer22);
ct22.setRunDirection(PdfWriter.RUN_DIRECTION_NO_BIDI);
ct22.setSimpleColumn(new Phrase(stampMessage2.toString(), font2), 0, 0, rectangle2.getHeight(), rectangle2.getWidth(), 15, Element.ALIGN_LEFT);
ct22.go();
appearance2.setCertificate(cert);
// Creating the signature
ExternalSignature pks = new PrivateKeySignature(pk, DigestAlgorithms.SHA256, providerName);
ExternalDigest digest = new BouncyCastleDigest();
List<CrlClient> crlList = new ArrayList<CrlClient>();
crlList.add(new CrlClientOnline());
LtvVerification v = stamper.getLtvVerification();
LtvVerification v2 = stamper2.getLtvVerification();
OcspClient ocspClient = new OcspClientBouncyCastle();
String url = CertificateUtil.getCRLURL(cert);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509CRL crl = (X509CRL) cf.generateCRL(new URL(url).openStream());
System.out.println("CRL valid until: " + crl.getNextUpdate());
System.out.println("Certificate revoked: " + crl.isRevoked(chain[0]));
if (crl.isRevoked(chain[0])) {
throw new GeneralSecurityException("CERTIFICADO REVOGADO!");
}
else {
MakeSignature.processCrl(cert, crlList);
MakeSignature.signDetached(appearance2, digest, pks, chain, null, null, null, 0, CryptoStandard.CMS);
MakeSignature.signDetached(appearance, digest, pks, chain, null, null, null, 0, CryptoStandard.CMS);
os.close();
byte[] b = this.read(f);
return Base64.encodeBytes(b);
}
}
This actually is a discussion of the available options...
There are fundamentally different ways to print the signature stamp in all pages:
"Visualizations" of a PDF signature field are widgets directly associated with the field; in particular they can be clicked to have a signature validation dialog open up. In contrast to these widgets the "images" in the second option are mere images without such an associated action.
This most likely is the option the OP has on his mind. In particular this is the preferable option, at least at first glance:
There are a number of disadvantages, though:
Multiple visualizations of the same signature may have a negative impact on the legal value of that signature.
Adobe, therefore, decided years ago not to create signature fields with multiple visualizations in their software, cf. for example
The location of a signature within a document can have a bearing on its legal meaning. For this reason, signature fields never refer to more than one annotation. If more than one location is associated with a signature, the meaning may become ambiguous.
(Digital Signature Appearances whitepaper for Adobe Acrobat version 9 dated May 5, 2008)
E.g. in Germany jurisdiction concerning written signatures vertically confines the part of the document the signer has legally signed, he generally is not legally bound by anything written below the signature. Similar jurisdiction may exist in other legal systems, too.
In case of electronic signatures with visualizations in the signed documents, such jurisdiction might hold analogously (or one at least has to make quite an effort to explain the differences). In case of multiple visualization of the same signature this might mean that only everything up to the first visualization is considered signed.
(I am not a lawyer, so please do not consider this legal consultation.)
Because of such potential legal issues signature fields in the upcoming PDF 2.0 standard will only be allowed to have a single widget. Thus, signatures with multiple widgets likely will be considered invalid according to that standard.
Already now the signature panel of Adobe Reader contains "the page the signature is on", cf. the last line of this screen shot:
Active signature fields without an associated entry (with the correct page number) on that panel might be doubted outright.
In case of using this option, the disadvantages of the prior option do not apply or at least only to a lesser degree. In particular if the mere images slightly differ from the visualization by a hint indicating that they are copies, the final, true visualization will likely be considered the binding signature location.
The major disadvantage of this option, though, is that adding mere images to the content is not allowed for already signed documents. Thus, this option cannot be used for the second or third signer of a document, but the OP has indicated that the solution will eventually have to allow the documents to be signed to more than one person.
One can consider adding those images as annotations, not as content; for certain types of integrated PDF signatures adding and removing annotations after signing is an allowed operation. But if adding those annotations was allowed, usually removing them again after signing is allowed, too, making those signature images quite volatile.
This option does not have the disadvantages of the other options as each visualization corresponds to a different digital signature. Thus, the final one guarantees that the signer is legally bound by the whole document.
It does have disadvantages of its own, though:
iText allows implementing the second and third option in a fairly straight-forward manner out-of-the-box.
Implementing the first option is possible with iText but requires the use of low-level APIs and Java reflection or alternatively patching iText a bit.
Considering the problems of each option, though, I'd advice against doing this at all, one signature right at the end of the content to sign is the least ambiguous way to sign.
@mkl points on legal issue are very much considerable. But if you still want to sign all the pages with Itext api (version 5.5.*) , they you should do a little hack in preClose(HashMap<PdfName, Integer> exclusionSizes)
method of PdfSignatureAppearance
class which where the signature appearance is included in the pages.
search for writer.addAnnotation(sigField, pagen);
line inside PdfSignatureAppearance
class and replace with
for (int p = 1; p <= writer.reader.getNumberOfPages(); p++) {
writer.addAnnotation(sigField, p);
}
It add the reference of the signature to all the pages.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With