3

I am getting the below error when signing a pdf. The error is “Signature defined. Must be closed in PdfSignatureAppearance.”

I am able to sign the pdf for the first time. It creates a pdf file in output folder with the signature in the first page. So far the code works fine. Now when I give the recently generated file as input to sign in a second page I get the error “Signature defined. Must be closed in PdfSignatureAppearance.”

I am getting the error in the below line

appearance.SetVisibleSignature(new iTextSharp.text.Rectangle(300, 40, 530, 120), pageNo, "Icsi-Vendor");

Please find the code below

if (File.Exists(fName))
{
    PdfReader.unethicalreading = true;
    using (PdfReader pdfReader = new PdfReader(fName))
    {
        //file name
       fName = fName.Substring(fName.LastIndexOf("\\") + 1);
        outputFile = outputFolder + fName + ".pdf";
        if (!File.Exists(outputFile))
        {
            using (FileStream fout = new FileStream(outputFile, FileMode.Create, FileAccess.ReadWrite))
            {
                using (PdfStamper stamper = PdfStamper.CreateSignature(pdfReader, fout, '\0'))
                {
                    PdfSignatureAppearance appearance = stamper.SignatureAppearance;
                    string imagePath = txtImage.Text;
                    iTextSharp.text.Image signatureFieldImage = iTextSharp.text.Image.GetInstance(imagePath);
                    appearance.SignatureGraphic = signatureFieldImage;

                    signatureFieldImage.SetAbsolutePosition(250, 50);
                    stamper.GetOverContent(pageNo).AddImage(signatureFieldImage);

                    appearance.SetVisibleSignature(new iTextSharp.text.Rectangle(300, 40, 530, 120), pageNo, "Icsi-Vendor");
                    appearance.Reason = txtReason.Text;

                    IExternalSignature es = new PrivateKeySignature(pk, "SHA-256");
                    MakeSignature.SignDetached(appearance, es, new X509Certificate[] { pk12.GetCertificate(alias).Certificate }, null, null, null, 0, CryptoStandard.CMS);
                    stamper.Close();
                }
            }
        }
    }
    this.Invoke(new BarDelegate(UpdateBar), fName);
}

Can some one help me please and let me know in case more details are required.

jtate
  • 2,612
  • 7
  • 25
  • 35
Venu
  • 43
  • 1
  • 1
  • 4
  • 1
    You get the error during `stamper.Close()`, and the error message tells you what to do instead: don't close the `stamper`, close the `appearance`. – mkl Mar 18 '15 at 06:54

1 Answers1

8

There are multiple issues in the OP's code:

The correct Close call

When applying signatures, one must not close the stamper object itself but instead the signature appearance object. And if one uses helper methods like MakeSignature.SignDetached, one does not even have to code that closing because SignDetached implicitly already closes the appearance in its last line.

Thus, please

  • remove stamper.Close() and
  • don't put PdfStamper stamper = PdfStamper.CreateSignature(pdfReader, fout, '\0') into a using directive as this causes a call of the stamper's Dispose method which in turn calls Close.

Usually you are not hurt by those lines because after the implicit appearance close in MakeSignature.SignDetached, further close calls are ignored.

If you don't get that far, though, e.g. due to some error situation before, such close calls cause the error you observe, in your case the close call caused by the using directive.

The issue in SetVisibleSignature

You are getting the error in

appearance.SetVisibleSignature(new iTextSharp.text.Rectangle(300, 40, 530, 120), pageNo, "Icsi-Vendor");

Unfortunately the actual error occurring in this line is replaced by the error caused by the Close call during the Dispose call due to the using directive.

Considering the message code:

/**
 * Sets the signature to be visible. It creates a new visible signature field.
 * @param pageRect the position and dimension of the field in the page
 * @param page the page to place the field. The fist page is 1
 * @param fieldName the field name or <CODE>null</CODE> to generate automatically a new field name
 */
virtual public void SetVisibleSignature(Rectangle pageRect, int page, String fieldName) {
    if (fieldName != null) {
        if (fieldName.IndexOf('.') >= 0)
            throw new ArgumentException(MessageLocalization.GetComposedMessage("field.names.cannot.contain.a.dot"));
        AcroFields af = writer.GetAcroFields();
        AcroFields.Item item = af.GetFieldItem(fieldName);
        if (item != null)
            throw new ArgumentException(MessageLocalization.GetComposedMessage("the.field.1.already.exists", fieldName));
        this.fieldName = fieldName;
    }
    if (page < 1 || page > writer.reader.NumberOfPages)
        throw new ArgumentException(MessageLocalization.GetComposedMessage("invalid.page.number.1", page));
    this.pageRect = new Rectangle(pageRect);
    this.pageRect.Normalize();
    rect = new Rectangle(this.pageRect.Width, this.pageRect.Height);
    this.page = page;
}

the obvious causes would be

  • the field name containing a dot,
  • the named field already existing in the document, or
  • an invalid page number.

As you describe your situation as

I am able to sign the pdf for the first time. It creates a pdf file in output folder with the signature in the first page. So far the code works fine. Now when I give the recently generated file as input to sign in a second page I get the error

I assume the second item to be the most probable cause: If you want to add multiple signatures to the same document, their field names must differ.

Append mode

As you indicate that you apply multiple signatures to the same file, you must use the append mode. If you don't, you'll invalidate the earlier signatures:

PdfStamper stamper = PdfStamper.CreateSignature(pdfReader, fout, '\0', true);

Cf. that CreateSignature method overload comment

/**
 * Applies a digital signature to a document, possibly as a new revision, making
 * possible multiple signatures. The returned PdfStamper
 * can be used normally as the signature is only applied when closing.
 * <p>
... (outdated Java example code) ...
 * @param reader the original document
 * @param os the output stream or <CODE>null</CODE> to keep the document in the temporary file
 * @param pdfVersion the new pdf version or '\0' to keep the same version as the original
 * document
 * @param tempFile location of the temporary file. If it's a directory a temporary file will be created there.
 *     If it's a file it will be used directly. The file will be deleted on exit unless <CODE>os</CODE> is null.
 *     In that case the document can be retrieved directly from the temporary file. If it's <CODE>null</CODE>
 *     no temporary file will be created and memory will be used
 * @param append if <CODE>true</CODE> the signature and all the other content will be added as a
 * new revision thus not invalidating existing signatures
 * @return a <CODE>PdfStamper</CODE>
 * @throws DocumentException on error
 * @throws IOException on error
 */
public static PdfStamper CreateSignature(PdfReader reader, Stream os, char pdfVersion, string tempFile, bool append)
mkl
  • 90,588
  • 15
  • 125
  • 265
  • Thank you so much, your help is great. the way you had provided the code is awesome. The issue got resolved. – Venu Apr 15 '15 at 03:48