该页面可以包含自动翻译的文本。

使用 C# 和 VB.NET 为 PDF 签名添加长期验证 (PAdES-LTV) 信息

PDF 签名的长期验证 (LTV) 信息有助于在数字签名创建后很长时间内对其进行验证。如果没有 LTV,一旦签名者的证书过期或吊销数据不再可用,数字签名将无法验证。这对于必须保持多年可信度的法律和财务 PDF 文档来说通常是不可接受的。

本文包含两部分:理论和实践。首先,您将学习有关 PAdES-LTV 签名的基本信息。然后,您将探索如何使用 Docotic.Pdf 库 使用 C# 为 PDF 签名添加 LTV 信息。您可以在 下载 C# .NET PDF 库 页面获取该库和免费的限时许可证密钥。

Docotic.Pdf 库 9.7.18373 回归测试 15,244 通过 NuGet 总下载量 5,976,723

长期验证 (LTV)

PAdES - PDF 高级电子签名

欧洲电信标准协会 (ETSI) 已发布多项电子签名标准。特别是,该协会在 ETSI EN 319 142 规范中定义了 PDF 高级电子签名 (PAdES) 标准。PAdES 概述了如何使 PDF 签名符合欧洲 eIDAS 法规。

LTV 签名的核心概念是将验证相关信息 (VRI) 嵌入 PDF 文件中。这些信息使得即使在签名环境不再可用的情况下,也能在长时间后验证 PDF 签名。

ETSI EN 319 142-1 规范定义了四个级别的 PAdES 基线签名:B-B、B-T、B-LT 和 B-LTA。在本文中,我将重点介绍 B-LT 和 B-LTA 级别,因为它们与 PDF 中支持 LTV 的签名相关。

PAdES-B-B

ETSI.CAdES.detached 格式的短期数字 PDF 签名对应于此级别。使用 C# 和 VB.NET 签署 PDF 文档 文章解释了如何创建此类签名。

PAdES-B-T

B-T 签名必须满足 B-B 级别的要求,并且 包含时间戳

PAdES-B-LT

B-LT 签名必须符合 B-T 级别。此外,PDF 文件必须包含文档安全存储 (DSS) 字典,其中包含以下数据:

  • 信任链中的所有证书
  • 在线证书状态协议(OCSP)响应
  • 证书吊销列表 (CRLs)

高级电子签名对应于此级别。

PAdES-B-LTA

B-LTA 签名必须符合 B-LT 级别。此外,PDF 文件必须包含文档时间戳签名和文档时间戳证书的 VRI

合格的电子签名对应此级别。

PAdES 验证

一种选择是使用 Adob​​e Acrobat Pro 或 Adob​​e Reader。打开“签名面板”,展开数字签名以检查其状态。如果签名有效,您将看到“签名已启用 LTV”或“签名未启用 LTV,且将在之后过期”。

Adobe Reader 中的签名已启用 LTV

另一种选择是使用欧盟委员会的 PAdES 验证器。此方法在验证符合欧盟 (eIDAS) 标准的文档时效果最佳。

此外,还有ETSI 的签名一致性检查器。此服务主要面向从事签名或验证工具开发的开发人员。

请记住,这些验证器可能会对同一 PDF 文档提供不同的结果。

空谈误事,放码过来。

使用 C# 和 VB.NET 创建支持 LTV 的 PDF 签名

现在开始编写代码吧!Docotic.Pdf 提供了 PdfDocument.AddLtvInfo 方法 来将 LTV 信息添加到 PDF 签名中。要生成 B-LTA 签名,您还需要 PdfDocument.TimestampAndSave 方法 来保存带有文档时间戳签名的 PDF。

如何在 C# 中创建 PAdES-B-LT 签名

创建 B-LT 签名的过程包含三个步骤:

  1. 创建 B-T 签名并保存文档。
  2. 打开已签名的文档并添加 LTV 信息。
  3. 增量保存最终文档。

以下是创建 B-LT 签名的 C# 代码。您也可以从 GitHub 下载完整的 创建支持 LTV 的 PDF 签名 示例项目:

// 1. 创建 PAdES-B-T 签名
using var step1 = new MemoryStream();
using (var pdf = new PdfDocument())
{
    var options = new PdfSigningOptions(..)
    {
        DigestAlgorithm = PdfDigestAlgorithm.Sha256,
        Format = PdfSignatureFormat.CadesDetached,
    };
    options.Timestamp.AuthorityUrl = new Uri("http://timestamp.digicert.com");

    pdf.SignAndSave(options, step1);
}

// 2. 打开已签名的文档并添加 LTV 信息
using (var pdf = new PdfDocument(step1))
{
    pdf.AddLtvInfo();

    // 3. 增量保存最终文档
    var incrementalOptions = new PdfSaveOptions()
    {
        WriteIncrementally = true,
    };
    pdf.Save("b-lt.pdf", incrementalOptions);
}

有几个关键点需要考虑。首先,您可以使用 PKCS#12 证书(.pfx 或 .p12 文件)或 外部签名者 创建 PdfSigningOptions。无论使用哪种方法,为了符合 PAdES 规范,Format 选项必须设置为 PdfSignatureFormat.CadesDetached

此代码段使用了 http://timestamp.digicert.com,但您可以使用任何其他时间戳颁发机构 (TSA)。以下是一些常用的替代方案:

http://timestamp.comodoca.com/rfc3161
http://timestamp.sectigo.com
http://timestamp.entrust.net/TSS/RFC3161sha2TS
http://rfc3161timestamp.globalsign.com/advanced

为了符合 ETSI 规范,您应该使用经 eIDAS 批准的 TSA。您可以使用 EU/EEA 可信列表浏览器 选择一个。

完成第一步后,必须保存中间文档。在附加 LTV 信息之前,您必须对文档进行签名并保存。但是,此规则有一个例外,我将在下面的使用 LTV 认证 PDF部分中进行解释。

第三步中的 WriteIncrementally = true 行启用增量保存。增量更新不会使数字签名失效。添加 LTV 信息时,您应该始终以增量方式保存 PDF 文件。

如何在 C# 中创建 PAdES-B-LTA 签名

生成 B-LTA 签名的步骤类似,除了第三步。您应该:

  1. 创建 B-T 签名并保存文档。
  2. 打开已签名的文档并添加 LTV 信息。
  3. 附带文档时间戳签名地增量保存最终文档。

以下代码示例展示了如何在 C# 中创建 B-LTA 签名:

var timestampAuthorityUrl = new Uri("http://timestamp.digicert.com");

// 1. 创建 PAdES-B-T 签名
using var step1 = new MemoryStream();
using (var pdf = new PdfDocument())
{
    var options = new PdfSigningOptions(..)
    {
        DigestAlgorithm = PdfDigestAlgorithm.Sha256,
        Format = PdfSignatureFormat.CadesDetached,
    };
    options.Timestamp.AuthorityUrl = timestampAuthorityUrl;

    pdf.SignAndSave(options, step1);
}

// 2. 打开已签名的文档并添加 LTV 信息
using (var pdf = new PdfDocument(step1))
{
    pdf.AddLtvInfo();

    // 3. **附带文档时间戳签名**地增量保存最终文档
    var timestampOptions = new PdfSignatureTimestampOptions
    {
        AuthorityUrl = timestampAuthorityUrl,
    };
    var incrementalOptions = new PdfSaveOptions()
    {
        WriteIncrementally = true,
    };
    pdf.TimestampAndSave(timestampOptions, "b-lta.pdf", incrementalOptions);
}

最终的 b-lta.pdf 文档包含两个签名——第一步中的主签名和第三步中的文档时间戳签名。您可能会注意到,Adobe Acrobat 会为两个签名显示“签名已启用 LTV”的消息。文档时间戳签名是在调用 AddLtvInfo 之后创建的,怎么可能启用了 LTV?

关键在于对签名时间戳和文档时间戳使用相同的 TSAAddLtvInfo 方法会为时间戳证书添加 VRI 。然后,文档时间戳会使用相同的证书并重用相关数据。

文档时间戳无法使用相同的 TSA?我将在 PAdES-B-T 到 B-LTA 的转换 部分讨论这种情况。

使用 C# 和 VB.NET 向现有 PDF 签名添加 LTV 信息

到目前为止,我已经从头创建了启用 LTV 的签名。但是,通常需要修改现有的 PAdES-B-T 签名。例如,将它们转换为 B-LT 或 B-LTA,或者刷新 LTV 信息。

与前面的示例一样,您需要:

  1. 打开已签名的文档并添加 LTV 信息。
  2. 逐步保存最终文档,无论是否包含文档时间戳签名。

以下是相应的代码片段。

如何在 C# 中将 PAdES-B-T 签名转换为 B-LT

using var pdf = new PdfDocument("b-t.pdf");
pdf.AddLtvInfo();

var incrementalOptions = new PdfSaveOptions()
{
    WriteIncrementally = true,
};
pdf.Save("b-lt.pdf", incrementalOptions);

如何在 C# 中将 PAdES-B-T 签名转换为 B-LTA

using var pdf = new PdfDocument("b-t.pdf");
pdf.AddLtvInfo();

var timestampOptions = new PdfSignatureTimestampOptions
{
    AuthorityUrl = new Uri("http://timestamp.digicert.com"),
};
var incrementalOptions = new PdfSaveOptions()
{
    WriteIncrementally = true,
};
pdf.TimestampAndSave(timestampOptions, "b-lta.pdf", incrementalOptions);

在 GitHub 上下载完整的 将 LTV 信息添加到现有签名 示例项目。

将 LTV 信息添加到文档时间戳签名

现有的 B-T 签名可能使用与本示例不同的任意 TSA 。在这种情况下,Adobe Acrobat 会在文档时间戳签名中显示“签名未启用 LTV”消息。

如何启用 LTV?您需要将 LTV 信息添加到文档时间戳签名中:

var timestampOptions = new PdfSignatureTimestampOptions
{
    AuthorityUrl = new Uri("http://timestamp.digicert.com"),
};
var incrementalOptions = new PdfSaveOptions()
{
    WriteIncrementally = true,
};

using var intermediate = new MemoryStream();
using (var pdf = new PdfDocument("b-t.pdf"))
{
    pdf.AddLtvInfo();
    pdf.TimestampAndSave(timestampOptions, intermediate, incrementalOptions);
}

// 将 LTV 信息添加到文档时间戳签名中
using (var pdf = new PdfDocument(intermediate))
{
    pdf.AddLtvInfo();
    pdf.TimestampAndSave(timestampOptions, "b-lta.pdf", incrementalOptions);
}

使用 C# 和 VB.NET 为 PDF 添加 LTV 认证签名

已验证 PDF 文档中的数字签名不允许任何修改。PDF 阅读器应用程序会使用特殊图标和以“已验证”开头的标题显示此类签名。

Adobe Acrobat 中显示的已验证 PDF 签名

对已验证 PDF 文档的任何更改都将使签名无效,这意味着您无法在不破坏验证的情况下添加 LTV 信息。

Docotic.Pdf 提供了生成包含 LTV 信息的已验证 PDF 文档的功能。使用 AddLtvInfo(PdfSigningOptions) 重载 在签名过程中添加 LTV 信息。以下代码示例演示了如何使用 C# 使用 B-LT 签名验证 PDF:

using var pdf = new PdfDocument();

var options = new PdfSigningOptions(..)
{
    DigestAlgorithm = PdfDigestAlgorithm.Sha256,
    Format = PdfSignatureFormat.CadesDetached,
    Type = PdfSignatureType.AuthorNoChanges,
};
options.Timestamp.AuthorityUrl = new Uri("http://timestamp.digicert.com");

pdf.AddLtvInfo(options);

pdf.SignAndSave(options, "certified-b-lt.pdf");

探索 GitHub 上的 使用 LTV 签名认证 PDF 代码示例。

自 2025 年 6 月起,Adobe Acrobat 支持包含 B-LT 签名的已验证 PDF 文档,但将已验证文档中的 B-LTA 签名视为无效。

结论

您可以为 PDF 签名添加长期验证 (LTV) 信息,以确保法律合规性和长期信任。PAdES 标准定义了 PDF 签名的规则和一致性级别。

建议至少使用 PAdES-B-T 签名进行签名。B-T 签名可以转换为高级电子签名 (B-LT) 或合格电子签名 (B-LTA),而不会破坏现有的验证机制。

使用 Docotic.Pdf 库 在 .NET 应用程序中为 PDF 签名添加 LTV 信息。您甚至可以使用 LTV 认证 PDF 文档。

探索 GitHub 上的 PDF 数字签名代码示例。查看相关文章了解更多信息:

常见问题

如何避免在 Adobe Acrobat 中出现“签名有效性未知”的提示?

当 Adobe Acrobat 无法验证签名者的证书时,会显示“签名有效性未知”的警告。通常这是由于证书缺失、不受信任、自签名、已被吊销、已过期或尚未生效所导致的。

获取正确的证书 以避免出现警告或创建符合欧盟 (eIDAS) 标准的文档。

或者,你可以手动将证书添加到 Adobe Acrobat 的“受信任的证书”中。此选项位于:菜单 > 首选项 > 签名 > 身份与受信任的证书

如果您需要信任已认证文档的证书,请确保授予相应的权限:

在 Adobe Acrobat 中配置信任设置

如何检查 PDF 签名是否启用了 LTV?

你可以使用 Adobe Reader 或欧盟委员会的 PAdES 验证工具。有关更多详细信息,请参阅 PAdES 验证 部分。

为什么 Adobe Acrobat 会显示“签名未启用 LTV”?

Adobe Acrobat 在验证签名的过程中会检查证书的撤销信息。如果需要联网下载任何数据,说明相应签名未启用 LTV功能。

如何使 PDF 签名符合 ETSI 规范?

请遵循 PDF 高级电子签名 的要求。您需要使用 欧盟信任列表 (EUTL) 中列出的提供商颁发的证书。

如何在 Adobe Reader 中实现“签名已启用 LTV”的指示?

首先,签名必须至少符合 PAdES-B-T 级别。然后,你需要添加 LTV 信息,包括信任链中的所有证书、 OCSP 响应以及 CRL 列表。

创建启用 LTV 的 PDF 签名将 LTV 信息添加到现有 PDF 签名 部分介绍了如何在 C# 和 VB.NET 中添加 LTV 信息。

如何为文档时间戳签名启用 LTV?

该过程与常规 PDF 签名类似。您需要将文档时间戳签名的 LTV 信息添加到 DSS 字典中。

请参阅将 LTV 信息添加到文档时间戳签名部分中的代码示例。

是否可以在同一操作中执行 LTV 和时间戳?

可以!请查看如何将 PAdES-B-T 签名转换为 B-LTA部分中的代码示例。

如何在 C# 中使用 LTV 创建数字签名?

使用 Docotic.Pdf 库。要生成高级电子签名,请查看如何创建 PAdES-B-LT 签名部分中的代码示例。要创建合格电子签名,请查看如何创建 PAdES-B-LTA 签名部分。

当“不允许更改”时,如何为签名启用 LTV?

对于已认证的文档,Adobe Acrobat 要求所有 LTV 数据都包含在原始签名文档中。阅读使用 LTV 认证 PDF部分了解更多详情。

如何在外部签名 PDF 文档时启用长期验证 (LTV)?

使用 Docotic.Pdf 库,通过 USB 令牌、智能卡或云端硬件安全模块 (HSM) 为 PDF 文档启用 LTV 签名。请参阅 如何在 C# 和 VB.NET 中使用 USB 令牌和 HSM 设备对 PDF 进行签名 文章和 如何创建 PAdES-B-LT 签名 部分。

如何为 PDF 文档启用多重签名和 LTV?

结合使用 由多人签署 PDF 表单将 LTV 信息添加到现有签名 代码示例。