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.
There are multiple issues in the OP's code:
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
stamper.Close() and 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.
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
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.
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)
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