Podpis nałożony na PDF nie zabrania późniejszych zmian. Fiksuje zakres bajtów, a aktualizacja przyrostowa dokleja nowe bajty po nim, więc podpis pozostaje matematycznie ważny, podczas gdy dokument nabywa nową treść. To, czy ta treść jest akceptowalna, jest pytaniem o politykę, a DocMDP jest miejscem, gdzie autor tę politykę zapisuje: żadnych zmian w ogóle, tylko wypełnianie formularzy i podpisywanie, albo to plus adnotacje. Egzekwowanie jej oznacza klasyfikowanie tego, co faktycznie się zmieniło, i to robi AnalyzeModifications. Skieruj ją na wcześniejszą rewizję, a potem odczytaj GetModificationLevel dla werdyktu ogólnego oraz akcesory per znalezisko dla poziomu, numeru obiektu i opisu każdej różnicy
Gdy to jest na miejscu, egzekwowanie DocMDP zapada się do porównania: czy obliczony poziom jest równy poziomowi dozwolonemu przez politykę albo poniżej niego
Dlaczego podpisany PDF ma prawo się zmieniać
Trzy legalne przypadki i pokrywają większość tego, co zobaczysz. Drugi podpisujący dokłada swój podpis. Odbiorca wypełnia pola formularza, które autor zostawił otwarte. I doklejany jest materiał walidacji długoterminowej: odpowiedzi OCSP i listy CRL zapisywane do magazynu zabezpieczeń dokumentu, żeby podpis pozostał weryfikowalny, gdy respondenci już nie istnieją. Ten ostatni nie tylko jest dozwolony — to dokładnie to, co dobrze prowadzone archiwum celowo robi z podpisanymi dokumentami
Więc „plik urośł po podpisaniu” nie niesie żadnej informacji. Pytanie zawsze brzmi, co zostało dodane, a odpowiedź musi pochodzić z porównania stanów dokumentu, a nie z obserwowania bajtów. Mechanikę doklejania samej w sobie opisuje artykuł o aktualizacji przyrostowej
Klasyfikuj po kształcie obiektu, nie po ścieżce, która go stworzyła
Klasyfikator patrzy na to, czym obiekt jest po zmianie, a nie na to, które wywołanie biblioteki go stworzyło. To zamierzone, bo analiza działa na plikach wyprodukowanych przez inne oprogramowanie, gdzie żadna ścieżka wywołań nie jest dostępna do zbadania
Rozpoznawane są cztery kształty. Słowniki informacji magazynu zabezpieczeń dokumentu i danych walidacyjnych, obiekty strumienia odwołań krzyżowych, wpis metadanych katalogu oraz słowniki podpisów niosące zakres bajtów to materiał archiwum długoterminowego. Obiekt niosący jednocześnie typ pola i wartość pola to wypełnianie formularza. Obiekt, którego typem jest adnotacja albo którego podtyp jest jednym z wymienionych w tabeli 168 ISO 32000-2, to zmiana adnotacyjna. Wszystko inne jest niesklasyfikowane
Usunięcia traktuje się surowiej niż dodatki. Usunięty obiekt trafia na białą listę tylko wtedy, gdy obiekt po starej stronie był sam w sobie materiałem archiwalnym, co obejmuje normalny przypadek wymiany magazynu zabezpieczeń na nowszy. Każde inne usunięcie jest niesklasyfikowane, bo usuwanie treści z podpisanego dokumentu to nie jest coś, co poziom uprawnień autoryzuje. Różnice na poziomie dokumentu są surowsze jeszcze: zmiana liczby stron idzie od razu do niesklasyfikowanych bez badania pojedynczych obiektów, skoro żaden poziom DocMDP nie zezwala na dodawanie ani usuwanie stron
Biała lista myli się w stronę odmowy
To jest reguła projektowa rządząca każdą decyzją na granicy. Zmiana błędnie sklasyfikowana jako dozwolona to podpis, który waliduje się nad treścią, której autor nigdy nie autoryzował. Zmiana błędnie sklasyfikowana jako niesklasyfikowana to dokument, który zostaje oflagowany i przejrzany przez człowieka. Te dwa błędy nie są symetryczne, więc biała lista pozostaje wąska, a nierozpoznane kształty spadają do niesklasyfikowanych, zamiast być zgadywane
Ma to praktyczną konsekwencję wartą przewidzenia: pliki od nietypowych producentów będą czasem zgłaszać niesklasyfikowane zmiany, które po zbadaniu są łagodne. Właściwą reakcją jest spojrzenie na szczegół znaleziska i numer obiektu, a nie poszerzanie białej listy, bo biała lista rosnąca po to, by uciszać pojedyncze zgłoszenia, przestaje być zabezpieczeniem
uses
PDFlibrary, PDFlibCompare;
var
Pdf: TPDFlib;
I, Level: Integer;
begin
Pdf := TPDFlib.Create(nil);
try
Pdf.LoadFromFile('contract-countersigned.pdf', '');
if Pdf.AnalyzeModifications('contract-as-signed.pdf', '') < 0 then
raise Exception.Create('the earlier revision could not be loaded');
// TPLModificationLevel w kolejności mlNone, mlLTAUpdates, mlFormFilling,
// mlAnnotations, mlUnclassified; getter zwraca jej wartość porządkową
Level := Pdf.GetModificationLevel;
// Egzekwowanie DocMDP to teraz jedno porównanie z polityką
if Level > Ord(mlFormFilling) then
for I := 0 to Pdf.GetModificationFindingCount - 1 do
Report.Add(Format('object %d, level %d: %s',
[Pdf.GetModificationFindingObjNum(I),
Pdf.GetModificationFindingLevel(I),
Pdf.GetModificationFindingDetail(I)]));
finally
Pdf.Free;
end;
end;
Poziom ogólny to maksimum po wszystkich znaleziskach, i to jedyne dające się obronić agregowanie: dokument zawierający dziewięćdziesiąt dziewięć archiwalnych dodatków i jedną niesklasyfikowaną zmianę jest dokumentem z niesklasyfikowaną zmianą
Pod spodem: odciski, nie kryptograficzne skróty
Silnik porównawczy, który wystawia CompareWith i na którym zbudowana jest analiza modyfikacji, identyfikuje obiekty po odcisku ich znormalizowanego ciała, używając niekryptograficznego 64-bitowego hasza zamiast SHA-256. To przemyślany wybór. Strukturalne porównanie potrzebuje determinizmu: to samo ciało obiektu musi zawsze produkować ten sam odcisk w ramach jednego uruchomienia. Nie potrzebuje odporności na kolizje, bo atakujący kontrolujący obie strony porównania już wygrał innymi środkami, a płacenie pełnym kryptograficznym haszem za każdy obiekt w dokumencie o milionie obiektów to realny koszt bez żadnej korzyści
Dwie reguły normalizacji znaczą więcej niż wybór hasza. Referencje pośrednie zwijają się do tokenu zastępczego zamiast być rozwijane do wskazywanej treści: rozwijanie kopiowałoby ciało współdzielonego obiektu do każdego odwołującego, więc drobna edycja współdzielonego deskryptora fontu unieważniłaby odcisk każdego obiektu, który do niego sięga, a raport byłby nieczytelny. Numery obiektów same są wyłączone z odcisku, bo przepisanie może przenumerować obiekty, nie zmieniając niczego semantycznie
Dopasowywanie biegnie potem w dwóch przebiegach, najpierw wyrównując po odcisku, a resztę parując po numerze obiektu, żeby rozpoznać zmiany, a nie dodatek plus usunięcie. Tanich sprawdzeń używa się najpierw na całej linii: różnica liczby stron jest zgłaszana, zanim jakiekolwiek przechodzenie po obiektach się zacznie
Pułapka: porównanie ze sobą nie musi dać identyczności
Naturalnym pierwszym testem dla silnika diff jest porównanie pliku z nim samym i asercja, że wynik jest identyczny. Ta asercja tutaj nie obowiązuje, a powód jest pouczający. Publiczna ścieżka wczytywania i ścieżka wczytywania dokumentu niższego poziomu nie konfigurują dekodowania identycznie, więc ten sam plik wczytany dwiema drogami może dać odciski różniące się dla niektórych obiektów. Silnik się nie myli; dwa wczytania naprawdę wyprodukowały różne stany w pamięci
Zamiast zmuszać obie ścieżki do zguły, semantyka porównania jest sformułowana wąsko: analiza porównuje bieżący stan dokumentu z wcześniejszą rewizją i zgłasza identyczność tylko wtedy, gdy oba zbiory odcisków pokrywają się dokładnie. To jest pytanie, które użytkownicy faktycznie zadają, i nie wymaga, by oba wczytywania były wymienne. Projektując funkcję porównywania, zdefiniowanie, co znaczy „to samo”, to większa część roboty niż jej obliczenie
Gdzie tego używać
Dwa miejsca. W raporcie walidacji, obok sprawdzania podpisów, żeby recenzent widział nie tylko to, czy podpis jest kryptograficznie nietknięty, ale i to, co stało się z dokumentem potem; stronę podpisową omawia podpisywanie i walidacja PAdES. I w bramce przyjęcia, gdzie dokument przychodzący z zewnątrz jest sprawdzany względem wysłanej kopii, więc zwrócony kontrakt z dodaną adnotacją jest traktowany inaczej niż taki z zedytowaną stroną
Jedno zastrzeżenie co do zakresu. Ta analiza mówi ci, co zmieniło się między dwiema rewizjami tego samego rodowodu dokumentu. Nie mówi, czy widoczna treść jest myląca, czy strumień wyglądu pola formularza zgadza się z jego wartością ani czy tekst schowany pod nakładką wciąż jest obecny w strumieniu zawartości. To wymaga osobnego traktowania, a stronę usuwania treści omawia artykuł o prawdziwej redakcji. Punkty wejścia analizy i porównywania są udokumentowane na stronie produktu losLab PDF Developer Library