Assinatura múltipla de PDFBox fornecendo assinatura inválida Java

Nov 26 2020

Eu tinha alguns requisitos de fluxo de trabalho de multi-assinatura em PDF Neste pdf será assinado várias vezes sem alterações no documento, digamos que 2 ou mais pessoas podem assinar o mesmo documento. Estou tentando adicionar as assinaturas em pdf duas vezes, mas depois de assinar o pdf pela segunda vez, a primeira assinatura fica inválida. Usei o PDFBox Java API para a criação de assinaturas em PDF.

Etapas de criação de PDF:

  1. PDF criado adicionando nomes de campos de assinatura vazios: [email protected] e [email protected] usando hello.pdf original out put nome de arquivo hello_tag.pdf run program> TagPDFSignatureFields.java
  2. Assinatura pela primeira vez buscando o campo de assinatura [email protected] do arquivo hello_tag.pdf, o nome do arquivo de saída é hello_signed.pdf execute o programa> SignAndIdentifySignatureFields.java
  3. Assinatura pela segunda vez obtendo o campo de assinatura [email protected] do arquivo hello_signed.pdf, o nome do arquivo de saída é hello_singed2.pdf run program> Sign2.java

Na 2ª etapa, o pdf é assinado corretamente, mas após a 3ª etapa, a versão assinada da 2ª etapa é invalidada e a assinatura da 3ª etapa mostra tudo certo no acrobat reader.

Encontre o código-fonte Java do link e um exemplo de pdf para referência. Link do Google Drive pdf_multi_signs_pdfbox_java

Qualquer ajuda seria apreciada.

Respostas

3 mkl Nov 27 2020 at 01:26

Resumindo, há uma série de problemas em seu código. O problema que faz com que o Adobe Reader marque sua primeira assinatura como inválida após adicionar uma segunda assinatura, na verdade, já está na etapa de preparação, TagPDFSignatureFieldsonde você cria uma entrada inválida na árvore de páginas duplicadas. Os outros problemas também devem ser corrigidos, embora o Adobe Reader atualmente não reclame.

Os problemas em detalhes ...

Entrada de página duplicada

Em TagPDFSignatureFieldsseu método addEmptySignFieldcomeça assim:

private void addEmptySignField(String[] args) throws Exception, IOException {
    // Create a new document with an empty page.
    try (PDDocument document = PDDocument.load(new File(args[0]));)
    {
        PDPage page = document.getPage(0);
        document.addPage(page);

Aqui você recupera a primeira página de documente imediatamente adiciona essa página documentnovamente. Isso faz com que o nó da árvore raiz das páginas em seu arquivo hello_tag.pdffique assim:

2 0 obj
<<
/Type /Pages
/Count 2
/Kids [6 0 R 6 0 R]
>>
endobj 

Ou seja, a árvore de páginas contém o mesmo objeto de página duas vezes que o Adobe Reader não aceita, mas repara nos bastidores. Para os documentos assinados, o Adobe Reader avisa sobre isso de forma vaga:

E nas versões atuais (por exemplo, 2020.013.20066) Adobe Reader no arquivo assinado duas vezes até marca a primeira assinatura como quebrada. Em versões anteriores (por exemplo, 2019.012.20040), isso não acontecia. Provavelmente, isso é um efeito do endurecimento do código de validação após a publicação dos Shadow Attacks.

À parte: se você tiver uma situação em que manipular um documento assinado (preenchimento de formulário, assinar novamente, ...) quebra as assinaturas antigas, sempre verifique também se o documento original já pode ter problemas. A verificação se alterações aplicadas a um documento assinado são permitidas, são bastante sensíveis a erros que de outra forma são corrigidos sob o capô e, portanto, não visíveis.

Nomes de campos parciais inválidos

Você usa endereços de e-mail como nomes de campo [email protected]e , [email protected]no caso do seu exemplo:

signatureField.setPartialName("[email protected]");
...
signatureField1.setPartialName("[email protected]");

( TagPDFSignatureFieldsmétodo addEmptySignField)

Esses nomes de campos parciais são inválidos, os nomes de campos parciais não devem conter caracteres de ponto ('.').

O PDFBox em versões futuras tentará evitar isso, consulte PDFBOX-5028 .

Definindo os recursos padrão e as aparências padrão na assinatura

Durante a assinatura, você define os recursos padrão e a aparência padrão do dicionário AcroForm :

acroForm.setDefaultResources(resources);
...
acroForm.setDefaultAppearance(defaultAppearanceString);

( SignAndIdentifySignatureFieldse Sign2método addEmptySignField)

Por si só, isso não é uma coisa ruim, mas cuidado, se você fizer isso com um arquivo assinado anteriormente que já contém essas entradas e configurá-los com valores diferentes dos anteriores, isso pode invalidar a assinatura anterior , consulte o problema respondido aqui .

Configurando a versão PDF sem necessidade

Você tenta alterar a versão PDF reivindicada do documento:

document.setVersion(1.0f);

( SignAndIdentifySignatureFieldsmétodo addEmptySignField)

document.setVersion(2.0f);

( Sign2método addEmptySignField)

A primeira instrução é ignorada porque o próprio documento já requer uma versão de pelo menos 1.5, mas a segunda instrução realmente define a versão do PDF do documento para 2.0, o que pode causar problemas com visualizadores mais antigos.

...

É bem provável que haja mais problemas. Eu simplesmente identifiquei esses problemas pela primeira vez antes de reconhecer que já consertando o único primeiro, a entrada de página duplicada, foi suficiente para curar a primeira assinatura ...