在PDFBox 2.x中,我将/Lock字典放入签名字段:
/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),用于指定应为该用户锁定的表单字段。 当接收者在字段上签名时,应创建签名,签名参考和转换参数字典。应当从签名字段锁定字典中的相应字段复制变换参数字典中的“ 动作” 和“ 字段” 条目。
的 FieldMDP 应使用变换的方法检测的变化形式的字段列表的值。表256中列出了其转换参数字典中的条目。
[…]
* 作者还可以指定在特定收件人签名文档后,对特定表单字段的任何修改都将使该收件人签名无效。对于每个指定的接收者,应该有一个单独的签名字段,每个签名接收者都有一个相关的签名字段锁定字典(参见表233),用于指定应为该用户锁定的表单字段。
因此,签名 锁 字典的预期处理包括将匹配的 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 [, ...]);
( CreateSignature辅助方法signExistingFieldWithLock)
signExistingFieldWithLock
关于注释中讨论的签名 锁* 字典中的 P 条目:此条目已在Adobe补充ISO 32000,扩展级别3中引入。 *