How can I lock a PDF document after signing it?

前端 未结 1 1206
青春惊慌失措
青春惊慌失措 2021-01-25 16:31

Adobe Acrobat has the option to lock the PDF document after signing it. This changes the document permissions so that Acrobat does not offer signing the document again or modify

相关标签:
1条回答
  • 2021-01-25 17:22

    If your use case only required signing unsigned PDFs, locking would be easy: You simply would have set CertificationLevel = CERTIFIED_NO_CHANGES_ALLOWED for your PdfSignatureAppearance object. But as your use case is to

    add a new signature in a new signature field to an existing PDF which may or may not be signed,

    the solution is somewhat more difficult: Instead of the DocMDP transform method (used for certification) the FieldMDP transform method has to be used. For details read ISO 32000-1, especially section 12.8.

    I tried to do this in one step but, unfortunately, iText in its current state (version 5.4.4) only properly supports lock dictionaries in already existing fields.

    @Bruno It should not be too difficult to add a lock dictionary support for fields created on the run while signing, too.

    Thus, here a two-step solution first adding an empty signature field with locking information and then signing this field. I did it in Java (I'm more at home there) but this should not be too difficult to port to C#.

    // STEP 1 --- prepare a signature field with locking information
    //
    // Creating the reader and the stamper for adding the field
    PdfReader reader = new PdfReader(SRC);
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    PdfStamper stamper = new PdfStamper(reader, baos, (char)0, true);
    
    // adding the empty signature field
    PdfFormField field = PdfFormField.createSignature(stamper.getWriter());
    field.setFieldName("Signature");
    field.put(PdfName.LOCK, stamper.getWriter().addToBody(new PdfSigLockDictionary(LockPermissions.NO_CHANGES_ALLOWED)).getIndirectReference());
    field.setFlags(PdfAnnotation.FLAGS_PRINT);
    field.setPage(1);
    field.setWidget(new Rectangle(150, 250, 300, 401), PdfAnnotation.HIGHLIGHT_INVERT);
    stamper.addAnnotation(field, 1);
    
    // finishing the intermediate PDF
    stamper.close();
    reader.close();
    
    // STEP 2 --- sign the prepared signature field, nothing special
    //
    // Creating the reader and the stamper for signing
    reader = new PdfReader(baos.toByteArray());
    FileOutputStream os = new FileOutputStream("target/test-outputs/test_signed-with-lock-field-2step.pdf");
    stamper = PdfStamper.createSignature(reader, os, '\0', null, true);
    
    // Creating the appearance
    PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
    appearance.setReason("reason");
    appearance.setLocation("location");
    appearance.setVisibleSignature("Signature");
    
    // Creating the signature
    ExternalDigest digest = new BouncyCastleDigest();
    ExternalSignature signature = new PrivateKeySignature(pk, DigestAlgorithms.SHA256, "BC");
    MakeSignature.signDetached(appearance, digest, signature, chain, null, null, null, 0, CryptoStandard.CMS);
    

    As you see, there is nothing special to do in the second step when signing the prepared empty signature field, iText applies the lock under the hood.

    This feature, though, has only been available since iText 5.3.2, and I have not checked when it was completely ported to iTextSharp.

    For a test run (using self-signed test certificates, thus the warnings) I got:

    The input file signed once:

    enter image description here

    The output file signed twice and locked:

    enter image description here

    0 讨论(0)
提交回复
热议问题