“锁定"签名字段中的词典是签名后签名损坏的原因 [英] "Lock" dictionary in signature field is the reason of broken signature after signing

查看:160
本文介绍了“锁定"签名字段中的词典是签名后签名损坏的原因的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在PDFBox 2.x中,我将/Lock字典放入签名字段:

import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField;

public class SigningUtils {
    public static final COSName COS_NAME_LOCK = COSName.getPDFName("Lock");
    public static final COSName COS_NAME_ACTION = COSName.getPDFName("Action");
    public static final COSName COS_NAME_ALL = COSName.getPDFName("All");
    public static final COSName COS_NAME_SIG_FIELD_LOCK = COSName.getPDFName("SigFieldLock");

    public static void setLock(PDSignatureField pdSignatureField, PDAcroForm acroForm) {
        COSDictionary lockDict = new COSDictionary();
        lockDict.setItem(COS_NAME_ACTION, COS_NAME_ALL);
        lockDict.setItem(COSName.TYPE, COS_NAME_SIG_FIELD_LOCK);
        pdSignatureField.getCOSObject().setItem(COS_NAME_LOCK, lockDict);
    }
}

然后我在签名字段签名:

PDSignature signature = findExistingSignature(document, signatureFieldName); //This is some method to find signature field and create PDSignature dictionary

signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);

signature.setName("blablabla");
signature.setLocation("blablabla");
signature.setReason("blablabla");
signature.setSignDate(Calendar.getInstance());
document.addSignature(signature, this);

除了我在Adobe Acrobat中打开签名的文档时,一切都看起来还不错,它抱怨文档的内容已更改.如果我不添加/Lock词典,一切都很好.

有人知道哪里出了问题吗?

解决方案

问题是PDFBox签名没有考虑 Lock 字典.

根据ISO 32000-1(以及类似的ISO 32000-2):

12.8.2.4 FieldMDP

FieldMDP 转换方法应用于检测对表单字段列表值的更改.表256中列出了其转换参数字典中的条目.

[...]

  • 作者还可以指定特定收件人在文档上签名后,对特定表单字段的任何修改都将使该收件人的签名无效.对于每个指定的收件人,应该有一个单独的签名域,每个签名域都有一个关联的签名域锁定字典(请参见表233),用于指定应为该用户锁定的表单域.

  • 当接收者在字段上签名时,应创建签名,签名参考和转换参数字典.应当从签名字段锁定字典中的相应字段复制变换参数字典中的 Action Fields 条目.

因此,对签名 Lock 词典的预期处理包括将匹配的 FieldMDP 转换数据添加到签名字段值.默认情况下,PDFBox签名不这样做.

您可以在签名期间手动执行以下操作:

PDSignatureField signatureField = FIND_YOUR_SIGNATURE_FIELD_TO_SIGN;
PDSignature signature = new PDSignature();
signatureField.setValue(signature);

COSBase lock = signatureField.getCOSObject().getDictionaryObject(COSName.getPDFName("Lock"));
if (lock instanceof COSDictionary)
{
    COSDictionary lockDict = (COSDictionary) lock;
    COSDictionary transformParams = new COSDictionary(lockDict);
    transformParams.setItem(COSName.TYPE, COSName.getPDFName("TransformParams"));
    transformParams.setItem(COSName.V, COSName.getPDFName("1.2"));
    transformParams.setDirect(true);
    COSDictionary sigRef = new COSDictionary();
    sigRef.setItem(COSName.TYPE, COSName.getPDFName("SigRef"));
    sigRef.setItem(COSName.getPDFName("TransformParams"), transformParams);
    sigRef.setItem(COSName.getPDFName("TransformMethod"), COSName.getPDFName("FieldMDP"));
    sigRef.setItem(COSName.getPDFName("Data"), document.getDocumentCatalog());
    sigRef.setDirect(true);
    COSArray referenceArray = new COSArray();
    referenceArray.add(sigRef);
    signature.getCOSObject().setItem(COSName.getPDFName("Reference"), referenceArray);
}

signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
signature.setName("blablabla");
signature.setLocation("blablabla");
signature.setReason("blablabla");
signature.setSignDate(Calendar.getInstance());
document.addSignature(signature [, ...]);

((

Then I sign the signature field:

PDSignature signature = findExistingSignature(document, signatureFieldName); //This is some method to find signature field and create PDSignature dictionary

signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);

signature.setName("blablabla");
signature.setLocation("blablabla");
signature.setReason("blablabla");
signature.setSignDate(Calendar.getInstance());
document.addSignature(signature, this);

Everything looks allright except that when I open signed document in Adobe Acrobat it complains the content of the document was changed. If I don't add the /Lock dictionary the everything is fine.

Anyone has any idea what is wrong?

解决方案

The problem is that PDFBox signing does not take the Lock dictionary into account.

According to ISO 32000-1 (and also similarly ISO 32000-2):

12.8.2.4 FieldMDP

The FieldMDP transform method shall be used to detect changes to the values of a list of form fields. The entries in its transform parameters dictionary are listed in Table 256.

[...]

  • The author can also specify that after a specific recipient has signed the document, any modifications to specific form fields shall invalidate that recipient’s signature. There shall be a separate signature field for each designated recipient, each having an associated signature field lock dictionary (see Table 233) specifying the form fields that shall be locked for that user.

  • When the recipient signs the field, the signature, signature reference, and transform parameters dictionaries shall be created. The Action and Fields entries in the transform parameters dictionary shall be copied from the corresponding fields in the signature field lock dictionary.

Thus, the expected handling of a signature Lock dictionary includes the addition of matching FieldMDP transform data to the signature field value. PDFBox signing does not do so by default.

You can manually do it like this during signing:

PDSignatureField signatureField = FIND_YOUR_SIGNATURE_FIELD_TO_SIGN;
PDSignature signature = new PDSignature();
signatureField.setValue(signature);

COSBase lock = signatureField.getCOSObject().getDictionaryObject(COSName.getPDFName("Lock"));
if (lock instanceof COSDictionary)
{
    COSDictionary lockDict = (COSDictionary) lock;
    COSDictionary transformParams = new COSDictionary(lockDict);
    transformParams.setItem(COSName.TYPE, COSName.getPDFName("TransformParams"));
    transformParams.setItem(COSName.V, COSName.getPDFName("1.2"));
    transformParams.setDirect(true);
    COSDictionary sigRef = new COSDictionary();
    sigRef.setItem(COSName.TYPE, COSName.getPDFName("SigRef"));
    sigRef.setItem(COSName.getPDFName("TransformParams"), transformParams);
    sigRef.setItem(COSName.getPDFName("TransformMethod"), COSName.getPDFName("FieldMDP"));
    sigRef.setItem(COSName.getPDFName("Data"), document.getDocumentCatalog());
    sigRef.setDirect(true);
    COSArray referenceArray = new COSArray();
    referenceArray.add(sigRef);
    signature.getCOSObject().setItem(COSName.getPDFName("Reference"), referenceArray);
}

signature.setFilter(PDSignature.FILTER_ADOBE_PPKLITE);
signature.setSubFilter(PDSignature.SUBFILTER_ADBE_PKCS7_DETACHED);
signature.setName("blablabla");
signature.setLocation("blablabla");
signature.setReason("blablabla");
signature.setSignDate(Calendar.getInstance());
document.addSignature(signature [, ...]);

(CreateSignature helper method signExistingFieldWithLock)


Concerning the P entry in the signature Lock dictionary discussed in the comments: This entry has been introduced in the Adobe supplement to ISO 32000, extension level 3.

这篇关于“锁定"签名字段中的词典是签名后签名损坏的原因的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆