Przejdź do głównej zawartości

Sprawdzanie istniejącego podpisu i zrozumienie granicy zaufania

Użyj inspektora edycji Core, aby wykryć, czy plik PDF zawiera słownik podpisu. Inspektor działa offline i nie korzysta z modułu pomocniczego Spectrum. Ten przepis wyjaśnia również granicę zaufania: wykrycie podpisu nie jest tym samym co jego weryfikacja. Weryfikacja kryptograficzna, walidacja ścieżki zaufania oraz sprawdzanie unieważnień są dostępne w edycji Premium albo po stronie zewnętrznego walidatora.

Okno terminala
composer require nextpdf/core:^3

Podpis PDF to pole podpisu, którego wartością jest słownik podpisu (ISO 32000-2 §12.7.4). Wpis Contents w słowniku przechowuje strukturę SignedData formatu Cryptographic Message Syntax (CMS), zakodowaną w DER (ISO 32000-2 §12.8.1). Tryb awaryjny Quick klasy Inspector wykrywa obecność tej struktury, skanując plik w poszukiwaniu znaczników podpisu. Nie analizuje struktury CMS, nie przelicza skrótu dla zakresu bajtów (który wyklucza wartość podpisu — ISO 32000-2 §12.8.1), nie weryfikuje łańcucha certyfikatów ani nie sprawdza unieważnień.

Wywołaj new Inspector(), a następnie ->inspect(string $pdfData, InspectConfig $config). Dla działającego offline awaryjnego trybu PHP użyj InspectConfig::quick(). InspectDepth::Standard/Full wymagają modułu pomocniczego Spectrum, a przy jego braku kończą się bezpiecznym niepowodzeniem (INSPECT-SIDECAR-001). Wynikiem jest obiekt wartości InspectResult. W tym przepływie pracy obecność podpisu sprawdzaj za pomocą $hasSigned; przydatne są też $isEncrypted oraz $pdfVersion.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Inspect\InspectConfig;
use NextPDF\Inspect\Inspector;
$pdfData = file_get_contents(__DIR__ . '/incoming.pdf');
if ($pdfData === false || $pdfData === '') {
fwrite(STDERR, "Cannot read incoming.pdf\n");
exit(1);
}
$result = (new Inspector())->inspect($pdfData, InspectConfig::quick());
// hasSigned reports the PRESENCE of a signature dictionary.
// It does NOT mean the signature verifies.
echo $result->hasSigned
? "A signature is present — NOT verified.\n"
: "No signature found.\n";

Ten samodzielny program działa w środowisku uruchomieniowym przepisów. Odzwierciedla examples/37-inspect-existing-signature.php. Sprawdza znaną podpisaną próbkę z korpusu oraz świeżo utworzony niepodpisany dokument, co pozwala zobaczyć obie gałęzie flagi obecności. Następnie przekazuje werdykt dalej. Informacja o obecności służy do kierowania przepływem, ale nigdy nie jest werdyktem zaufania. Plik trafia do weryfikatora kryptograficznego (Pro lub zewnętrznego). Na tym etapie nie uznaje się go jeszcze za zaufany.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
use NextPDF\Inspect\InspectConfig;
use NextPDF\Inspect\Inspector;
$inspector = new Inspector();
// --- A known-signed input ---
// The repository corpus carries synthetic PAdES samples. In your
// application this is simply the incoming PDF you received.
$signedPath = __DIR__ . '/tests/Corpus/pades/pades-b-b-bytepattern-synthetic.pdf';
if (is_file($signedPath)) {
$signed = (string) file_get_contents($signedPath);
$r = $inspector->inspect($signed, InspectConfig::quick());
echo "Signed sample:\n";
echo ' Signature present : ' . ($r->hasSigned ? 'yes' : 'no') . "\n";
echo ' Encrypted : ' . ($r->isEncrypted ? 'yes' : 'no') . "\n";
echo ' PDF version : ' . ($r->pdfVersion ?? 'unknown') . "\n";
echo " Verdict : presence detected — NOT verified.\n";
if ($r->hasSigned) {
// Presence detected. This is routing input, not a trust verdict.
// Hand the file to a cryptographic verifier (Pro or external)
// before relying on it. (Pseudo-queue shown; wire your own.)
// $verifierQueue->enqueue($signed);
echo " Next step : run a cryptographic verifier before trusting it.\n";
}
} else {
echo "Signed corpus sample absent; skipping the signed branch.\n";
}
// --- A known-unsigned input ---
$unsigned = Document::createStandalone();
$unsigned->setTitle('Unsigned sample');
$unsigned->addPage();
$unsigned->setFont('helvetica', '', 12);
$unsigned->cell(0, 10, 'This document carries no signature.', newLine: true);
$unsignedBytes = $unsigned->getPdfData();
$ru = $inspector->inspect($unsignedBytes, InspectConfig::quick());
echo "Unsigned sample:\n";
echo ' Signature present : ' . ($ru->hasSigned ? 'yes' : 'no') . "\n";
// The harness sets NEXTPDF_COOKBOOK_OUTPUT and runs this script under the
// semantic profile; emit the unsigned document to the side-channel.
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT');
file_put_contents($out !== false && $out !== '' ? $out : __DIR__ . '/inspected.pdf', $unsignedBytes);

Oczekiwane wyjście STDOUT (gałąź podpisana jest pomijana, jeśli próbka z korpusu nie jest dostępna):

Signed sample:
Signature present : yes
Encrypted : no
PDF version : <version>
Verdict : presence detected — NOT verified.
Next step : run a cryptographic verifier before trusting it.
Unsigned sample:
Signature present : no
  • Obecność nie oznacza ważności. $hasSigned sygnalizuje istnienie słownika podpisu. Nie sprawdza struktury CMS, skrótu dla zakresu bajtów, certyfikatu podpisującego, łańcucha ani unieważnienia. Sfałszowany plik nadal może zwracać hasSigned = true. Nigdy nie traktuj obecności jako dowodu integralności ani autorstwa.
  • Czego wymaga pełna weryfikacja. Pełna decyzja weryfikacyjna obejmuje przeliczenie skrótu dla zakresu bajtów (ISO 32000-2 §12.8.1), walidację struktury SignedData formatu CMS, zbudowanie i sprawdzenie ścieżki X.509 do kotwicy zaufania oraz sprawdzenie statusu unieważnienia za pomocą protokołu Online Certificate Status Protocol (OCSP) lub listy unieważnionych certyfikatów (CRL). Jeśli znacznik czasu podpisu jest obecny, weryfikuje się go osobno względem własnego odcisku obliczonego z oktetów wartości podpisu (ETSI EN 319 122-1 §5.3). Te operacje są udostępniane przez kontrakty podpisywania. Implementacje produkcyjne są dostarczane w wersjach Pro i Enterprise. Alternatywną obsługiwaną ścieżką jest zewnętrzny walidator.
  • Głębokość inspekcji. InspectConfig::quick() to jedyna głębokość, która działa bez modułu pomocniczego Spectrum. Standard/Full zgłaszają INSPECT-SIDECAR-001, gdy moduł pomocniczy jest niedostępny.
  • Puste dane wejściowe. Pusty ciąg znaków sprawia, że inspekcja zgłasza wyjątek z komunikatem „PDF data must not be empty”. Zabezpiecz operację odczytu.
  • Wiele podpisów / znaczników czasu. Flaga obecności nie zlicza podpisów ani nie odróżnia podpisu certyfikującego od znacznika czasu dokumentu (który również jest przenoszony w unsignedAttrs zgodnie z RFC 5652 §5.3). Użyj dedykowanego weryfikatora, gdy znaczenie ma liczba podpisów lub werdykt dla każdego z nich.

Tryb awaryjny Quick wykonuje ograniczone skanowanie bajtów dokumentu. Nie analizuje pełnego grafu obiektów. Używaj go do szybkiej selekcji wstępnej napływających plików, zanim skierujesz je do cięższego weryfikatora.

Inspektor to narzędzie do wstępnej selekcji, a nie granica zaufania. Pozytywna wartość hasSigned nigdy nie może samodzielnie warunkować decyzji o zaufaniu.

Lokalizacja danych i środki ograniczające ryzyko związane z PII

Dział zatytułowany „Lokalizacja danych i środki ograniczające ryzyko związane z PII”

Sprawdzanie odbywa się w całości w procesie. Żadne bajty dokumentu nie opuszczają hosta. Tryb awaryjny Quick odczytuje wyłącznie znaczniki strukturalne, a nie tekst dokumentu, dlatego nie wyodrębnia ani nie przesyła informacji umożliwiających identyfikację osób (PII).

Inspector przyjmuje opcjonalny rejestrator zgodny z PSR-3. Rejestruje wybraną ścieżkę („Spectrum unavailable, using PHP fallback”), nie treść dokumentu. Nie zapisuj w dziennikach dosłownych bajtów sprawdzanego pliku PDF ani obiektu InspectResult, jeśli dokument jest poufny.

Uwzględniono: sfałszowany plik zawierający składniowo poprawny słownik podpisu (inspektor zgłasza obecność; jawnie nie potwierdza integralności) oraz plik bez podpisu (poprawnie zgłaszany jako nieobecny). Nie potwierdza się: że jakikolwiek wykryty podpis jest kryptograficznie ważny, zaufany lub nieunieważniony — to zadanie weryfikatora.

Tryb awaryjny Quick nie wykonuje żadnych operacji kryptograficznych, dlatego tryb Federal Information Processing Standards (FIPS) nie ma znaczenia w tym przepisie. To weryfikacja kryptograficzna (Premium/zewnętrzna) jest miejscem, w którym znaczenie ma łańcuch dostawców FIPS.

StwierdzenieSpecyfikacjaKlauzulareference_id
Wartością pola podpisu jest słownik podpisu.ISO 32000-2§12.7.4
Contents przechowuje strukturę SignedData formatu CMS w DER; Contents znacznika czasu dokumentu przechowuje TimeStampToken.ISO 32000-2§12.8.1
Weryfikacja przelicza skrót z zakresu bajtów, wykluczając wartość podpisu.ISO 32000-2§12.8.1
Odcisk znacznika czasu podpisu jest obliczany z oktetów wartości podpisu SignerInfo.ETSI EN 319 122-1§5.3
Znacznik czasu jest przenoszony w unsignedAttrs struktury SignerInfo.RFC 5652§5.3

Ten przepis wykrywa podpis. Nie potwierdza, że jakikolwiek podpis jest ważny, zaufany lub nieunieważniony. Tę decyzję podejmuje weryfikator kryptograficzny.

Kryptograficzna weryfikacja CMS, walidacja ścieżki X.509 oraz sprawdzanie unieważnień OCSP/CRL są udostępniane przez kontrakty podpisywania w edycjach Pro i Enterprise. Inspektor edycji Core obejmuje wyłącznie wykrywanie obecności.