使用 PDFBox 2.0.17 签署带有多个签名字段的 PDF [英] Signing PDF with multiple signature fields using PDFBox 2.0.17

查看:94
本文介绍了使用 PDFBox 2.0.17 签署带有多个签名字段的 PDF的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 PDFBox 提供的示例代码(https://svn.apache.org/repos/asf/pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java).但签名后的 PDF 显示 此文档已发生更改,使签名无效.

I am trying to sign a PDF with 2 signature fields using the example code provided by PDFBox (https://svn.apache.org/repos/asf/pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/signature/CreateVisibleSignature.java). But the signed PDF shows There have been changes made to this document that invalidate the signature.

我已将我的示例项目上传到 GitHub,请在此处找到它.

I have uploaded my sample project to GitHub please find it here.

该项目可以使用 IntelliJ 或 Eclipse 打开.

The project can be opened using IntelliJ or Eclipse.

程序参数应设置为以下以模拟问题.

The program argument should be set to the following to simulate the problem.

keystore/lawrence.p12 12345678 pdfs/Fillable-2.pdf images/image.jpg

如果有 PDFBox 专家可以帮助我,将不胜感激.谢谢.

Grateful if any PDFBox expert can help me. Thank you.

推荐答案

这个答案对问题签名字段中的Lock"字典是签名后签名损坏的原因已经包含了尊重签名的签名代码Lock 字典并在签名时创建匹配的 FieldMDP 转换.

This answer to the question "Lock" dictionary in signature field is the reason of broken signature after signing already contains code for signing that respects the signature Lock dictionary and creates a matching FieldMDP transformations while signing.

不过,正如评论中所澄清的,OP 很奇怪

As clarified in a comment, though, the OP wonders

有没有办法在签名后锁定对应的textfield

is there any way to lock the corresponding textfield after signing

因此,不仅对受保护的表单字段进行更改会使相关签名无效,而且在签署这些受保护的字段的过程中,这些受保护的字段本身也应被锁定.

Thus, not only shall changes to protected form fields invalidate the signature in question but in the course of signing these protected fields shall themselves be locked.

确实,您也可以改进参考答案中的代码来做到这一点:

Indeed, one can improve the code from the referenced answer to do that, too:

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

COSBase lock = signatureField.getCOSObject().getDictionaryObject(COS_NAME_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);

    final Predicate<PDField> shallBeLocked;
    final COSArray fields = lockDict.getCOSArray(COSName.FIELDS);
    final List<String> fieldNames = fields == null ? Collections.emptyList() :
        fields.toList().stream().filter(c -> (c instanceof COSString)).map(s -> ((COSString)s).getString()).collect(Collectors.toList());
    final COSName action = lockDict.getCOSName(COSName.getPDFName("Action"));
    if (action.equals(COSName.getPDFName("Include"))) {
        shallBeLocked = f -> fieldNames.contains(f.getFullyQualifiedName());
    } else if (action.equals(COSName.getPDFName("Exclude"))) {
        shallBeLocked = f -> !fieldNames.contains(f.getFullyQualifiedName());
    } else if (action.equals(COSName.getPDFName("All"))) {
        shallBeLocked = f -> true;
    } else { // unknown action, lock nothing
        shallBeLocked = f -> false;
    }
    lockFields(document.getDocumentCatalog().getAcroForm().getFields(), shallBeLocked);
}

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 辅助方法 signAndLockExistingFieldWithLock)

(CreateSignature helper method signAndLockExistingFieldWithLock)

使用 lockFields 实现如下:

boolean lockFields(List<PDField> fields, Predicate<PDField> shallBeLocked) {
    boolean isUpdated = false;
    if (fields != null) {
        for (PDField field : fields) {
            boolean isUpdatedField = false;
            if (shallBeLocked.test(field)) {
                field.setFieldFlags(field.getFieldFlags() | 1);
                if (field instanceof PDTerminalField) {
                    for (PDAnnotationWidget widget : ((PDTerminalField)field).getWidgets())
                        widget.setLocked(true);
                }
                isUpdatedField = true;
            }
            if (field instanceof PDNonTerminalField) {
                if (lockFields(((PDNonTerminalField)field).getChildren(), shallBeLocked))
                    isUpdatedField = true;
            }
            if (isUpdatedField) {
                field.getCOSObject().setNeedToBeUpdated(true);
                isUpdated = true;
            }
        }
    }
    return isUpdated;
}

(CreateSignature 辅助方法 lockFields)

(CreateSignature helper method lockFields)

这篇关于使用 PDFBox 2.0.17 签署带有多个签名字段的 PDF的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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