0

I'm using iText's methods to sign a PDF with digital certificate, generating a signature visible in the document with PdfSignatureAppearance, but I'd like the visible signature not to come out in print. I saw that there is something similar in the PdfAnnotation class, where you can add a flag for this. Is there any way to do this with the digital signature? My code:

PdfStamper stp = null;
try {
    PdfReader reader = new PdfReader(pdfInputFileName);

    stp = PdfStamper.createSignature(reader, fout, '\0');
    PdfSignatureAppearance sap = stp.getSignatureAppearance();

    sap.setCrypto(privateKey, certificateChain, null, PdfSignatureAppearance.WINCER_SIGNED);

    sap.setReason(reason);
    sap.setLocation(location);
    sap.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED);
    sap.setVisibleSignature(new Rectangle(30, 830, 170, 770), 1, null);

    stp.close();

} catch (DocumentException | IOException e) {

    logger.error("An unknown error accoured while signing the PDF file: " + e.getMessage());
}

This is the link to a PDF signed by this code, when I print it, the signature stamp always comes out in the print: https://s3.amazonaws.com/gxzadminlocal/anexo_28276.pdf

  • If iText creates a signature field during signing (and not fills an pre-existing one), it sets the PRINT flag automatically. Thus, can you please share an example PDF signed by your code for analysis. – mkl Nov 07 '18 at 16:03
  • @mkl, i attached the pdf for analysis. – Jonathan Rodrigues Carvalho Nov 07 '18 at 19:14
  • By the way, your signature is not state-of-the-art: It uses the subfilter **adbe.pkcs7.sha1** which implicitly uses SHA1 to hash the document data; but SHA1 is considered insecure nowadays. Furthermore it uses all the signature appearance layers **n0** through **n4** which is a deprecated, legacy method to make Adobe Reader display the signature validation status in the signature visualization itself. This is forbidden according to the current PDF specification, cf. [this answer](https://stackoverflow.com/a/40391641/1729265). – mkl Nov 08 '18 at 10:54
  • @mkl, I think I did not express myself well, I would like the signature NOT to come out in print. I got this with the annotations (PdfAnnotation), visible on the screen but not printed, but I could not do the same with the signature. I am using Adobe Acrobat Reader DC Version 2019.008.20080 also, even just marking "Document" in "Form and Comments" in the print window. – Jonathan Rodrigues Carvalho Nov 08 '18 at 10:57
  • I just realized that you want it "NOT to come out in print", I seem to have ignored the **NOT** before. Ok, as mentioned in my first comment, current iText 5 versions automatically set the PRINT flag if the signature field does not yet exist and they have to create it. But if you fill an existing signature field, that flag is untouched. Thus, you might want to add an empty signature field without PRINT in a first step and in a second step sign using that field. – mkl Nov 08 '18 at 11:06

1 Answers1

1

Current iText 5 versions automatically set the PRINT flag if the signature field does not yet exist and they have to create it. But if you fill an existing signature field, that flag is untouched. Thus, you might want to add an empty signature field without that PRINT flag in a first step and in a second step sign using that field, e.g. with the following code:

Preparing the PDF

You can prepare a PDF with an empty signature field without setting the PRINT flag like this:

try (   InputStream resource = SOURCE_STREAM;
        OutputStream os = INTERMEDIATE_OUTPUT_STREAM) {
    PdfReader reader = new PdfReader(resource);
    PdfStamper stamper = new PdfStamper(reader, os);
    PdfFormField field = PdfFormField.createSignature(stamper.getWriter());
    field.setFieldName("Signature");
    field.setWidget(new Rectangle(30, 830, 170, 770), PdfAnnotation.HIGHLIGHT_NONE);
    stamper.addAnnotation(field, 1);
    stamper.close();
}

(CreateSignature test signWidgetNoPrint pass 1)

In particular you don't do

field.setFlags(PdfAnnotation.FLAGS_PRINT);

here!

Signing the prepared PDF

Having created that intermediate PDF, you can sign it like this:

try (   InputStream resource = INTERMEDIATE_INPUT_STREAM;
        OutputStream os = RESULT_STREAM) {
    PdfReader reader = new PdfReader(resource);
    PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0');

    PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
    appearance.setReason("reason");
    appearance.setLocation("location");
    appearance.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED);
    appearance.setVisibleSignature("Signature");

    ExternalSignature pks = new PrivateKeySignature(pk, "SHA512", "BC");
    ExternalDigest digest = new BouncyCastleDigest();
    MakeSignature.signDetached(appearance, digest, pks, chain, null, null, null, 0, CryptoStandard.CMS);
}

(CreateSignature test signWidgetNoPrint pass 2)

assuming you have prepared your private key in pk and your certificate chain in chain; and assuming you have registered Bouncy Castle as security provider.

In the result PDF the signature visualization appears on screen but not in print.

Community
  • 1
  • 1
mkl
  • 90,588
  • 15
  • 125
  • 265
  • The code is breaking in this line without exceptions: `ExternalDigest digest = new BouncyCastleDigest();` I update iText and registered BouncyCastle: `BouncyCastleProvider providerBC = new BouncyCastleProvider(); Security.insertProviderAt(providerBC, 1);` What I am missing? – Jonathan Rodrigues Carvalho Nov 08 '18 at 14:11
  • *"The code is breaking in this line without exceptions"* - `BouncyCastleDigest` has only the default constructor, so if the program fails in that line on your setup, there must be something seriously screwed up in that setup, e.g. missing jars or jars with incompatible versions. – mkl Nov 08 '18 at 14:38
  • Which iText version exactly do you use? You are using the old API. Thus, the current version to use should be a 5.5.1x. And which BouncyCastle version do you use? iText 5.5.1x requires bcprov-jdk15on and bcpkix-jdk15on version 1.49. – mkl Nov 08 '18 at 14:42
  • Thank you, it worked. There are still some doubts, signing a signed document delete the previous signature and the new one is valid? By testing signing with a PKCS11 USB token, if I put the correct certificate password the first time, I can pass it incorrect on the others that the code signs anyway (`ks.load (null, PIN.toCharArray ()`). And finally, can you manage multiple signatures in the same document with iText? Again, thank you. – Jonathan Rodrigues Carvalho Nov 08 '18 at 18:48
  • *"signing a signed document delete the previous signature"* - in your code you set a `CertificationLevel`. Thus, you create a certification signature. As a certification signature must be the first signature in a pdf, there cannot be any previous signatures. Or the other way around: if you want to sign pdfs that already are signed, don't set the verification level! Furthermore sign in append mode to not invalidate earlier signatures hashes. – mkl Nov 08 '18 at 21:23
  • *"By testing signing with a PKCS11 USB token, if I put the correct certificate password the first time, I can pass it incorrect on the others that the code signs anyway"* - that appears to be an issue either of the USB token or your way of communicating with it, not of itext. – mkl Nov 08 '18 at 21:26
  • *"can you manage multiple signatures in the same document with iText?"* - yes. As mentioned two comments before, you have to sign in append mode and must not use a certification level for later signatures. Furthermore, the signature field names obviously must differ. – mkl Nov 08 '18 at 21:28