首页 > 解决方案 > 来自时间戳服务器的签名 pdf 缺少时间戳

问题描述

我尝试使用外部网络服务对 pdf 进行数字签名。此 Web 服务包含用户证书,用户可以使用其凭据和一次性密码生成代码访问该证书。

旁注:Web 服务应该期待 pdf 摘要(散列),但奇怪的是它接受了整个文件。

无论如何,实现如下:

using iTextSharp.text.pdf;
using iTextSharp.text.pdf.security;

// OTP = One Time Password code
public void SignPdf(string username, string password, string otp)
{
    byte[] file = GetFileFromPath("D:\test.pdf");
    var fieldName = "signatureField";
    string tempFilePath = "D:\test1temp.pdf");

    using (var pdfReader = new PdfReader(file))
    {
        using (var signedPdf = new FileStream(tempFilePath, FileMode.Create))
        {
            using (var pdfStamper = PdfStamper.CreateSignature(pdfReader, signedPdf, '\0', null, true);
            {
                // Prepare signature
                PdfDate date = new PdfDate();
                var fullSignDate = date.GetW3CDate();
                var signDate = fullSignDate.Substring(0, fullSignDate.IndexOf("T"));
                var signTime = fullSignDate.Substring(fullSignDate.IndexOf("T") + 1);
                var signatureAppearance = pdfStamper.SignatureAppearance;
                signatureAppearance.SetVisibleSignature(fieldName);
                signatureAppearance.Layer2Text=($"Digitally signed by: Test User");

                // Get font
                signatureAppearance.SignatureRenderingMode = PdfSignatureAppearance.RenderingMode.DESCRIPTION;
                signatureAppearance.CryptoDictionary = GetPdfSignature(signatureAppearance);
                signatureAppearance.PreClose(new Dictionary<PdfName, int> { [PdfName.CONTENTS] = 8192 * 2 + 2 });

                // Get file content as base64 string
                var ms = new MemoryStream();
                signatureAppearance.GetRangeStream().CopyTo(ms);
                fileAsBase64 = ms.ToArray();

                // Sign hash (the "hash" is the whole document)
                signature = GetSignedHash(Convert.ToBase64String(fileAsBase64), username, password, otp);

                if (signature != null)
                {
                    EmbedSignatureToPdf(signatureAppearance, signatureWithTimeStamp);
                    success = true;
                }
            }
        }
    }
}

private static PdfDictionary GetPdfSignature(PdfSignatureAppearance sa)
{
    return new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED)
    {
        Reason = sa.Reason,
        Location = sa.Location,
        SignatureCreator = sa.SignatureCreator,
        Contact = sa.Contact,
        Date = new PdfDate(sa.SignDate)
    };
}

private byte[] GetSignedHash(string hash, string username, string password, string otp)
{
    // Call external web service and get a the signed hash
}

private void EmbedSignatureToPdf(PdfSignatureAppearance signatureAppearance, byte[] signature)
{
    var array = new byte[8192];
    Array.Copy(signature, 0, array, 0, signature.Length);
    var pdfDictionary = new PdfDictionary();
    pdfDictionary.Put(PdfName.CONTENTS, new PdfString(array).SetHexWriting(true));
    signatureAppearance.Close(pdfDictionary);
}

pdf 已成功签名,但使用 Adob​​e Reader 并检查签名字段似乎缺少受信任的时间戳,如图所示:

无时间戳的数字签名

来自远程服务的响应似乎是一个签名对象,我只需将其嵌入到 PDF 文件中。

我的问题是:由于我收到的签名不包含来自时间戳服务器的时间戳,我是否可以在此时嵌入这样的时间戳,或者远程 Web 服务是否应该在将签名发送给我之前添加它?

谢谢!

标签: c#pdfitextdigital-signaturetrusted-timestamp

解决方案


由于我收到的签名不包含来自时间戳服务器的时间戳,我是否可以在此时嵌入这样的时间戳,或者远程 Web 服务是否应该在将签名发送给我之前添加它?

这样的时间戳作为未签名属性添加到签名容器中。因为它们没有签名,签名容器中的未签名属性可以在应用签名后更改,例如可以添加额外的属性。

因此,您自己可以特别为从您的服务中检索到的签名容器添加时间戳。

但是,根据签名的性质,您可能必须增加在 pdf 中创建的占位符的大小,以便为额外的时间戳留出足够的空间。


推荐阅读