gabrielgeo
gabrielgeo

Reputation: 536

iTextSharp 5 multiple signatures - last signature renders previous signatures invalid - Document has been altered or corrupted

I am trying to add multiple signatures with iTextSharp 5.5.13.1.
Only the last signature is valid.
And all previous signatures are invalid with the message: "Document has been altered or corrupted since it was signed" - 1 Page(s) Modified

I don't necessarily need certified signatures.

I use signature append mode but still can't figure out what modifies the document. In notepad the first part of document till the second signature seems unchanged.

The code I used is:

private string SignFile(string fileToSign, string certname, float xPercent, float yPercent, int page)
{
    string signedFile = fileToSign.Replace(".pdf", ".signed.pdf");

    using (PdfReader pdfReader = new PdfReader(fileToSign))
    {
        int pages = pdfReader.NumberOfPages;
        var currentSignaturesCount = pdfReader.AcroFields.GetSignatureNames().Count();

        using (FileStream signedPdf = new FileStream(signedFile, FileMode.Create, FileAccess.ReadWrite))
        {
            string tempDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), ".tempfiles");
            Directory.CreateDirectory(tempDir);
            string tempFileName = Path.Combine(tempDir, Guid.NewGuid().ToString("N") + ".pdf");
            if (!File.Exists(tempFileName))
                File.Create(tempFileName).Close();

            using (PdfStamper pdfStamper = PdfStamper.CreateSignature(pdfReader, signedPdf, '\0', tempFileName, true))  // Append mode
            {
                // Add signature image
                if (page <= pages && page > 0)
                {
                    var pdfContentByte = pdfStamper.GetOverContent(page);

                    var pageSize = pdfReader.GetPageSize(i);
                    float pageWidth = pageSize.Width;
                    float pageHeight = pageSize.Height;

                    // GenerateStamp() = simplified function that will get a custom bitmap (code not included here)
                    System.Drawing.Bitmap img = GenerateStamp();

                    var image = iTextSharp.text.Image.GetInstance(img, true);

                    image.SetAbsolutePosition(xPercent * pageWidth, pageHeight - yPercent * pageHeight - image.ScaledHeight);

                    pdfContentByte.AddImage(image);
                }
                //Also tried adding the image directly to signatureAppearance
                //signatureAppearance.SignatureGraphic = image;
                //signatureAppearance.SetVisibleSignature(rectangle, page, signatureFieldName);
                // and getting the error "Document has been altered or corrupted since it was signed"


                PdfSignatureAppearance signatureAppearance = pdfStamper.SignatureAppearance;

                signatureAppearance.Reason = "Test";
                signatureAppearance.SignDate = DateTime.Now;
                signatureAppearance.SignatureRenderingMode = PdfSignatureAppearance.RenderingMode.GRAPHIC;
                signatureAppearance.Acro6Layers = false;

                //Also tried like this:
                //signatureAppearance.CertificationLevel = currentSignaturesCount == 0 ? PdfSignatureAppearance.CERTIFIED_FORM_FILLING_AND_ANNOTATIONS : PdfSignatureAppearance.NOT_CERTIFIED;
                // with message: "There have been changes made to this document that invalidate the signature"

                // sign document
                try
                {
                    X509Certificate2 cert = GetCertificateByName(certname);
                    Org.BouncyCastle.X509.X509CertificateParser cp = new Org.BouncyCastle.X509.X509CertificateParser();
                    Org.BouncyCastle.X509.X509Certificate[] chain = new Org.BouncyCastle.X509.X509Certificate[] { cp.ReadCertificate(cert.RawData) };
                    IExternalSignature externalSignature = new X509Certificate2Signature(cert, "SHA-256");

                    MakeSignature.SignDetached(signatureAppearance, externalSignature, chain, null, null, null, 0, CryptoStandard.CMS);
                }
                catch (Exception ex)
                {
                    throw;
                }

            }
        }
    }

    return signedFile;
}

Any help is appreciated. Thanks

Upvotes: 3

Views: 979

Answers (1)

mkl
mkl

Reputation: 95898

Your code as is adds an image to the static content of a page. That is forbidden to do to a signed file. For details on allowed and disallowed changes to a signed PDF read this answer.

According to your code comments, though, you also tried to alternatively add the image to the signature appearance. That is not forbidden as such. But analyzing the provided example PDFs it becomes apparent that in this attempt additional content streams have been added to the page. Even though they essentially are empty, this is considered a change of page content which is disallowed.

As it turned out, you didn't add the image to the page content in this attempt but you still retrieved the OverContent of the page:

var pdfContentByte = pdfStamper.GetOverContent(page);

This operation already adds extra content streams to the page for the OverContent to come. Strictly speaking, therefore, the method should be named CreateOrGetOverContent instead...

After removing the GetOverContent call signing does not damage the previous signatures anymore.

Upvotes: 1

Related Questions