【问题标题】:iTextSharp 5 multiple signatures - last signature renders previous signatures invalid - Document has been altered or corruptediTextSharp 5 多重签名 - 最后一个签名使以前的签名无效 - 文档已被更改或损坏
【发布时间】:2020-05-15 18:17:35
【问题描述】:

我正在尝试使用 iTextSharp 5.5.13.1 添加多个签名。
只有最后一个签名有效。
并且所有以前的签名都对消息无效: “文档自签署以来已被更改或损坏” - 1 页已修改

我不一定需要经过认证的签名。

我使用签名附加模式,但仍然无法弄清楚是什么修改了文档。 在记事本中,文档的第一部分直到第二个签名似乎没有变化。

我使用的代码是:

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;
}

感谢任何帮助。谢谢

【问题讨论】:

  • 您的代码将图像添加到页面。禁止对签名文件执行此操作。但是,根据您的 cmets,您还尝试将图像添加到签名外观中。这本身并没有被禁止。请专注于该方法并基于该方法共享问题文件。
  • 我已经添加了带有签名外观的 pdf 文件。
  • 你还是换个页面吧,至少还有额外的页面内容流。可能你仍然打电话给var pdfContentByte = pdfStamper.GetOverContent(page);。该调用已经通过为过度内容添加内容流来更改页面。
  • 我明白了。我需要获取页面宽度和高度来定位图像。我不知道一个简单的 Get 会创建额外的内容流。我来检查一下。谢谢
  • “我需要获取页面宽度和高度来定位图像” - 您可以从PdfReader 中检索这些信息。 “我不知道一个简单的 Get 会创建额外的内容流。” - 严格来说应该是CreateOrGetOverContent。但至少它是幂等的,一旦一个压模有一个页面的内容过多,它就会一次又一次地使用它。

标签: c# pdf itext signing


【解决方案1】:

您的代码将图像添加到页面的静态内容中。禁止对签名文件执行此操作。有关允许和不允许更改已签名 PDF 的详细信息,请阅读 this answer

但是,根据您的代码 cmets,您还尝试将图像添加到签名外观中。这本身并没有被禁止。但是分析提供的示例 PDF 很明显,在此尝试中,已将其他内容流添加到页面中。即使它们本质上是空的,这也被视为不允许更改页面内容。

事实证明,您在这次尝试中没有将图像添加到页面内容中,但您仍然检索到页面的 OverContent

var pdfContentByte = pdfStamper.GetOverContent(page);

此操作已经为页面添加了额外的内容流,以便 OverContent 到来。因此,严格来说,该方法应该改名为CreateOrGetOverContent...

删除GetOverContent后调用签名不再损坏之前的签名。

【讨论】:

    猜你喜欢
    • 2021-11-06
    • 1970-01-01
    • 1970-01-01
    • 2023-04-03
    • 2016-09-16
    • 2018-12-04
    • 2021-05-11
    • 2021-06-20
    • 2016-01-20
    相关资源
    最近更新 更多