Wielokrotny podpis PDFBox z nieprawidłowym podpisem Java

Nov 26 2020

Miałem wymagania dotyczące przepływu pracy z wieloma podpisami PDF. W tym pliku PDF zostanie podpisany wiele razy bez zmian w dokumencie, powiedzmy, że 2 lub więcej osób może podpisać ten sam dokument. Próbuję dwukrotnie dodać podpisy w pdf, ale po drugim podpisaniu pdf pierwszy podpis jest nieważny. Użyłem API PDFBox Java do tworzenia podpisów PDF.

Kroki tworzenia PDF:

  1. Utworzono plik PDF przez dodanie nazw pustych pól podpisu: [email protected] i [email protected] przy użyciu oryginalnego pliku hello.pdf, wyślij nazwę pliku hello_tag.pdf uruchom program> TagPDFSignatureFields.java
  2. Pierwsze podpisywanie przez pobranie pola podpisu [email protected] z pliku hello_tag.pdf, nazwa pliku to hello_signed.pdf uruchom program> SignAndIdentifySignatureFields.java
  3. Podpisywanie po raz drugi przez pobranie pola podpisu [email protected] z pliku hello_signed.pdf, nazwa pliku to hello_singed2.pdf uruchom program> Sign2.java

W drugim kroku plik PDF jest poprawnie podpisywany, ale po trzecim kroku podpisana wersja w drugim kroku zostaje unieważniona, a podpis w trzecim kroku jest w porządku w programie Acrobat Reader.

Proszę znaleźć link do kodu źródłowego Java i przykładowego pliku PDF w celach informacyjnych. Link do dysku Google pdf_multi_signs_pdfbox_java

Każda pomoc będzie mile widziana.

Odpowiedzi

3 mkl Nov 27 2020 at 01:26

Krótko mówiąc, w kodzie występuje wiele problemów. Problem powodujący, że program Adobe Reader oznaczył Twój pierwszy podpis jako nieważny po dodaniu drugiego podpisu, w rzeczywistości jest już na etapie przygotowań, TagPDFSignatureFieldspodczas którego tworzysz nieprawidłowy wpis w drzewie zduplikowanych stron. Pozostałe problemy również powinny zostać naprawione, mimo że Adobe Reader obecnie nie narzeka.

Szczegółowe zagadnienia ...

Duplikat wpisu strony

W TagPDFSignatureFieldstwojej metodzie addEmptySignFieldzaczyna się tak:

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);

Tutaj pobierasz pierwszą stronę documenti natychmiast dodajesz tę stronę documentponownie. To powoduje, że węzeł drzewa głównego stron w pliku hello_tag.pdfwygląda następująco:

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

To znaczy drzewo stron zawiera dwa razy ten sam obiekt strony, którego Adobe Reader nie akceptuje, ale naprawia pod maską. W przypadku podpisanych dokumentów Adobe Reader ostrzega o tym w sposób niejasny:

A w aktualnych wersjach (np. 2020.013.20066) Adobe Reader w dwukrotnie podpisanym pliku oznacza nawet pierwszy podpis jako uszkodzony. We wcześniejszych wersjach (np. 2019.012.20040) tak się nie stało. Prawdopodobnie jest to efekt utwardzenia kodu walidacyjnego po opublikowaniu Shadow Attacks.

Na marginesie: jeśli masz sytuację, w której manipulowanie podpisanym dokumentem (wypełnianie formularzy, ponowne podpisywanie ...) zrywa stare podpisy, zawsze sprawdź również, czy oryginalny dokument może już mieć problemy. Sprawdzenie, czy zmiany zastosowane w podpisanym dokumencie są dozwolone, są dość wrażliwe na błędy, które w przeciwnym razie są naprawiane pod maską, a zatem niewidoczne.

Nieprawidłowe częściowe nazwy pól

Używasz adresów e-mail jako nazw pól, [email protected]a [email protected]na przykład:

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

( TagPDFSignatureFieldsmetoda addEmptySignField)

Te częściowe nazwy pól są nieprawidłowe, częściowe nazwy pól nie mogą zawierać znaków kropki („.”).

PDFBox w przyszłych wersjach będzie próbował temu zapobiec, patrz PDFBOX-5028 .

Ustawianie domyślnych zasobów i domyślnych wyglądów po podpisaniu

Podczas podpisywania ustawiasz domyślne zasoby i domyślny wygląd słownika AcroForm :

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

( SignAndIdentifySignatureFieldsi Sign2metoda addEmptySignField)

Samo w sobie nie jest to złe, ale uważaj, jeśli zrobisz to na wcześniej podpisanym pliku, który ma już takie wpisy i ustawisz je na inne wartości niż wcześniej, może to unieważnić poprzedni podpis , zobacz odpowiedź tutaj .

Ustawianie wersji PDF bez potrzeby

Próbujesz zmienić zgłoszoną wersję PDF dokumentu:

document.setVersion(1.0f);

( SignAndIdentifySignatureFieldsmetoda addEmptySignField)

document.setVersion(2.0f);

( Sign2metoda addEmptySignField)

Pierwsza instrukcja jest ignorowana, ponieważ sam dokument wymaga już wersji co najmniej 1.5, ale druga instrukcja rzeczywiście ustawia wersję dokumentu PDF na 2.0, co może powodować problemy w starszych przeglądarkach.

...

Prawdopodobnie jest więcej problemów. Po raz pierwszy zauważyłem te problemy, zanim zdałem sobie sprawę, że już naprawienie jedynego pierwszego, Duplicate Page Entry, wystarczyło, aby naprawić pierwszy podpis ...