如何为时间戳签名启用 LTV 并设置不允许更改 pdf?

How to enable LTV for a timestamp signature and set the pdf change not allowed?

我正在使用 iText 签署带有数字证书的 pdf。现在我可以签名并添加 LTV,但 CertificateLevel 只能是:

signatureAppearance.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_FORM_FILLING_AND_ANNOTATIONS);

我只想设置PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED。最终结果应如下所示:

sap.setCertificationLevel(PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED);
MakeSignature.signDetached(signatureAppearance, privateKey, "SHA-512", chain, null, ocspClient, tsaClient, 0, MakeSignature.CryptoStandard.CADES);

如果我使用上面的代码签名,那么使用AdobeLtvEnabling.java添加LTV会在使用ACROBAT校验时提示签名无效,因为添加LTV时文件正在修改不可修改的PDF文件。那么,我该怎么做才能接近最终效果呢

要获得像您的快照中那样的结果,即 "No changes are allowed" 和 "Signature is LTV enabled" 都没有任何后来的签名或文档时间戳,您必须

  • 要么已经将 Adob​​e 验证器要求的所有 LTV material 包含到您的原始签名修订中
  • 或使用允许您附加 LTV material 的签名模式,尽管不允许进行任何更改。

不幸的是,Adobe Acrobat 似乎尚未正确支持后一种变体 Reader。

有关详细信息,请参阅以下部分。

将所有 LTV material 包含到原始签名修订中

首先,这并不总是可能的。如果你想在原始签名版本中有 LTV material,它必须是签名数据的一部分,所以你必须在签名之前收集它。但是,在许多使用远程签名服务的设置中,您在实际请求签名之前并不知道将使用哪个签名证书。

不过,如果可能的话,即如果您事先知道签名证书,您可以使用 中的 class AdobeLtvEnabling 来包含如下信息:

PdfStamper stamper = PdfStamper.createSignature(...);

AdobeLtvEnabling adobeLtvEnabling = new AdobeLtvEnabling(stamper);
OcspClient ocsp = new OcspClientBouncyCastle();
CrlClient crl = new CrlClientOnline();
adobeLtvEnabling.addLtvForChain(YOUR_SIGNER_CERTIFICATE, ocsp, crl, PdfName.A);
adobeLtvEnabling.outputDss();

[...preparing your signature...]
MakeSignature.signDetached(...);

(CreateSignatureComodo 测试 testCreateLtvNoChangesAllowedCertification)

您可能必须为此制作 AdobeLtvEnabling 方法 addLtvForChainoutputDss public,因为 AdobeLtvEnabling 最初不打算像这样使用这个。

结果:

使用允许附加 LTV material 但不能附加其他任何东西的签名模式

或者,尽管有 "no changes allowed" 认证,您也可以采用允许稍后添加 LTV material 的方式签署 PDF。

首先,如果您想在应用签名后将 LTV material 添加到 PDF,则必须使用首先为 PAdES 签名指定的机制。虽然此机制同时包含在 ISO 32000-2 中,但它在普通 ISO 32000-1 上下文中不可用。不过,由于您的屏幕截图是 Adob​​e Acrobat 的,所以这对您来说应该不是问题。

此机制是文档安全存储。来自 的 iText class LtvVerification 和 class AdobeLtvEnabling 都在 PDF 中填写了这些商店。

尽管有 "no changes allowed" 认证,是否允许添加这些文档安全存储? — 这取决于...

如果您的 PDF 是 PDF-2.0:是的。 ISO 32000-2 描述了某些认证允许或不允许的更改,例如:

Changes to a PDF that are incremental updates which include only the data necessary to add DSS’s 12.8.4.3, "Document Security Store (DSS)" and/or document timestamps 12.8.5, "Document timestamp (DTS) dictionary" to the document shall not be considered as changes to the document as defined in the choices below.

(ISO 32000-2,Table 257 — DocMDP 转换参数字典中的条目)

如果您的 PDF-1.x 启用了 PAdES 扩展:是。 ETSI EN 319 142-1 要求

DocMDP restrictions (see ISO 32000-1 , clause 12.8.2.2) shall not apply to incremental updates to a PDF document containing a DSS dictionary and associated VRI, Certs, CRLs and OCSPs.

...

When evaluating the DocMDP restrictions (see ISO 32000-1 , clause 12.8.2.2) the presence of a Document Time-stamp dictionary item shall be ignored.

(ETSI EN 319 142-1 V1.1.1,第 5.4 节验证数据和存档验证数据属性)

如果您的 PDF 是普通 PDF-1.x,但是:不!

因此,如果您想使用此选项并在签名后添加 LTV 信息,请确保您最初认证的 PDF 是 PDF-2 或至少启用了 PAdES 扩展。

虽然 iText 5 不支持 PDF-2,但使用它创建 PAdES 样式签名会添加 PAdES 扩展。

因此,如果您认证 PAdES 样式,即使认证是 "no changes allowed".

,您也应该能够启用 LTV 签名

Adobe Acrobat 支持 Reader DC 2019.008.20080

完成了一些测试,扩展了仅包含 LTV 信息的不允许更改的认证 PDF,该 PDF 被标记为具有适当的 ETSI 和 Adob​​e 扩展名的 PDF-1.7 或标记为 PDF-2.0,Adobe Acrobat 似乎支持ETSI EN 319 142-1 和 ISO 32000-2 均未完全通过:在所有测试中,它认为认证已失效,参见。 CreateSignatureComodo 测试 testCreateNoChangesAllowedCertificationAndLtv.

因此,目前要获得 LTV 启用的不允许更改认证的文档并让 Adob​​e Acrobat 识别这一点,只有上面的第一个选项,即包括所有 LTV material进入原始签名修订版。

一种解决方法可能是创建允许填写表格的证书,然后添加 LTV 信息,然后使用另一个(批准)签名签名,通过其字段锁定将文档更改为不允许更改字典及其 FieldMDP 变换,参见。 CreateSignatureComodo 测试 testCreateCertificationAndLtvAndNoChangesAllowed。但是,由于知识渊博的人可以删除该签名的增量更新,因此这远非完美。

解决方法的结果:

我正在使用 itextsharp,我想以下内容对您的 Java 代码也很有用。

如果您使用 CrlClientOcspClient 调用 MakeSignature.SignDetached(而不是将 null 作为参数传递),您将在第一个之后获得启用 LTV 的签名步。然后你不需要做第二步后添加文档时间戳。

var stamper = PdfStamper.CreateSignature(reader, stream, '[=10=]', null, true);
var appearance = stamper.SignatureAppearance;
appearance.CertificationLevel = PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED;
...
var privateKey = ...
var chain = ...
var crlClient = new CrlClientOnline(chain);
var ocspClient = new OcspClientBouncyCastle();
var tsaClient = new TSAClientBouncyCastle("http://....");

MakeSignature.SignDetached(appearance, privateKey, chain, 
    new[] { crlClient }, 
    ocspClient,
    tsaClient, 
    0, 
    CryptoStandard.CMS);
stamper.Close();

希望这对你有用。