Enterprise edycja
Powiązanie zaufania ASiC
W skrócie
Dział zatytułowany „W skrócie”Kontener ASiC łączy podpisane pliki z podpisami, które je chronią. Trudne pytanie nie brzmi „czy podpis się przelicza?”, lecz „kto stoi za podpisującym?”. NextPDF\Enterprise\Security\Asic\AsicTrustBinder odpowiada dokładnie na to pytanie. Przekazujesz mu certyfikat podpisujący z podpisu kontenera, zaufaną listę oraz czas walidacji. Odpowiada obiektem AsicTrustBindingResult: werdyktem zaufany/niezaufany, wersją pakietu kotwic, względem której podjął decyzję, oraz maszynowo czytelnymi powodami. Każde odrzucenie nazywa swoją przyczynę, więc dowód audytowy zapisuje się sam.
Jedna granica jest celowa i warto zaznaczyć ją na wstępie. To API nie parsuje kontenerów ASiC. Twoje narzędzia otwierają kontener i wyodrębniają certyfikat podpisujący; NextPDF jest właścicielem decyzji o zaufaniu.
Dostępność i licencjonowanie
Dział zatytułowany „Dostępność i licencjonowanie”Ta funkcja dostarczana jest w NextPDF Enterprise (nextpdf/enterprise) i aktywuje się kopertą licencyjną poziomu Enterprise. Wdrożenie bez tego uprawnienia nie ładuje klas tej funkcji. Porównaj edycje i uzyskaj licencję.
Instalacja
Dział zatytułowany „Instalacja”composer require nextpdf/enterpriseAktywacja wymaga koperty licencyjnej Enterprise. Zobacz Instalacja i uwierzytelnianie. Klasy z tej strony znajdują się w przestrzeniach NextPDF\Enterprise\Security\Asic oraz NextPDF\Enterprise\Security\Tsl.
Przegląd koncepcyjny
Dział zatytułowany „Przegląd koncepcyjny”ASiC (Associated Signature Containers, ETSI EN 319 162-1) pakuje pliki danych i podpisy w jednym archiwum. Bazowy kontener ASiC osadza wyłącznie bazowe podpisy CAdES lub XAdES. Bazowy podpis CAdES niesie swój certyfikat podpisujący wewnątrz SignedData.certificates, więc oczekuje się, że weryfikator wyodrębni go, gdy podpis jest poprawnie sformowany i obsługiwany przez narzędzia kontenera, z podpisu kontenera. Ten wyodrębniony certyfikat jest wejściem tego API.
Źródłem zaufania jest zaufana lista (TSL) ETSI TS 119 612: podpisany dokument XML, który wylicza dostawców usług zaufania oraz ich certyfikaty usługowe. NextPDF\Enterprise\Security\Tsl\TslTrustAnchorProvider przekształca sparsowany TslDocument w pakiet kotwic. Tylko usługi, które są jednocześnie w statusie granted i typu usługi CA/QC, zasilają zbiór kotwic. Pakiet niesie ciąg wersji wyprowadzony z numeru sekwencji TSL i terytorium, plus skrót integralności SHA-256.
Przed jakimkolwiek porównaniem kotwic uruchamiane są dwie bramki fail-closed:
- Świeżość TSL. Zaufana lista, której moment
NextUpdatejuż minął, musi zostać odrzucona jako wygasła.AsicTrustBinder::verify()sprawdza świeżość w podanym czasie walidacji, zanim wyprowadzi choćby jedną kotwicę. Nieaktualna lista lub wartośćNextUpdatebez jawnego oznaczenia UTC rzucaTslParseException. - Okres ważności podpisującego. Walidacja ścieżki RFC 5280 wymaga, aby okres ważności certyfikatu obejmował czas walidacji. Kryptograficznie nienaruszony podpis, którego certyfikat był w tym czasie wygasły lub jeszcze nieważny, jest odrzucany z precyzyjnym kodem powodu.
Dopiero wtedy binder testuje certyfikat podpisujący względem każdej kotwicy. Dopasowanie daje trusted: true z powodem anchor_signature_match. Brak dopasowania daje trusted: false z powodem no_anchor_chain.
Dlaczego działa to w ten sposób
Dział zatytułowany „Dlaczego działa to w ten sposób”Nośną decyzją projektową jest ścisłe oddzielenie mechaniki kontenera od decyzji o zaufaniu, przy wymuszeniu, aby decyzja o zaufaniu była jawna co do czasu. Formaty kontenerów różnią się (ASiC-S, ASiC-E, ładunki CAdES lub XAdES), ale pytanie o zaufanie jest jednym niezmiennym jądrem: czy ten certyfikat łączy się z kotwicą ze świeżej zaufanej listy w podanym momencie? Utrzymanie tego jądra wolnym od parsowania ZIP i XML sprawia, że jest ono na tyle małe, by testować je wyczerpująco i by zamykać się bezpiecznie przy każdej bramce. To samo rozumowanie zakazuje cichej wartości domyślnej now: czas walidacji zmienia werdykt, więc musi być własnością wywołującego. Świeżość sprawdzana jest wewnątrz samej ścieżki wyprowadzania kotwic, a nie w opcjonalnym współpracowniku, więc żadna ścieżka producenta nie może jej pominąć.
Tło projektowe: Jak podpis cyfrowy dowodzi, kto podpisał.
Powierzchnia API
Dział zatytułowany „Powierzchnia API”AsicTrustBinder
Dział zatytułowany „AsicTrustBinder”Konstrukcja przyjmuje dostawcę kotwic, który zamienia zaufane listy w pakiety kotwic.
public function __construct( private readonly TslTrustAnchorProvider $anchorProvider,) {}Główny punkt wejścia weryfikuje certyfikat podpisującego względem zaufanej listy:
public function verify( string $signerCertPem, TslDocument $tsl, DateTimeInterface $validationTime,): AsicTrustBindingResult$signerCertPem— niepusty ciąg PEM: certyfikat podpisujący z podpisu ASiC.$tsl— sparsowana, uwierzytelniona zaufana lista.$validationTime— moment, który musi obejmować okres ważności certyfikatu podpisującego. Nie ma wartości domyślnej.
Rzuca lub kończy się niepowodzeniem z: NextPDF\Enterprise\Security\Tsl\TslParseException, gdy TSL jest nieaktualny (NextUpdate minął), gdy NextUpdate nie jest kanoniczną wartością UTC lub gdy lista nie zawiera aktywnych usług CA/QC. Niezaufani podpisujący nie rzucają wyjątku; zwracają wynik z trusted: false i kodem powodu.
Dla obciążeń wsadowych weryfikuj względem wcześniej zbudowanego pakietu:
public function verifyAgainstBundle( string $signerCertPem, EnterpriseCaTrustAnchorBundle $bundle, DateTimeInterface $validationTime,): AsicTrustBindingResultRzuca lub kończy się niepowodzeniem z: brak własnych wyjątków; każdy wynik jest obiektem AsicTrustBindingResult. Pakiet uzyskaj z TslTrustAnchorProvider::buildBundle() — nie konstruuj go ręcznie.
TslTrustAnchorProvider
Dział zatytułowany „TslTrustAnchorProvider”public function buildBundle(TslDocument $tsl, DateTimeImmutable $now): EnterpriseCaTrustAnchorBundleRzuca lub kończy się niepowodzeniem z: TslParseException, jeśli TSL jest nieaktualny, jego NextUpdate nie jest kanoniczną wartością UTC lub nie ma aktywnych usług CA/QC.
AsicTrustBindingResult
Dział zatytułowany „AsicTrustBindingResult”public function __construct( public bool $trusted, public string $anchorBundleVersion, public array $reasons,) {}$reasons to list<non-empty-string> maszynowo czytelnych kodów. $anchorBundleVersion zapisuje użyty zbiór kotwic w postaci tsl-<territory>-seq<N> (na przykład tsl-eu-seq42).
| Kod powodu | Znaczenie |
|---|---|
anchor_signature_match | Certyfikat podpisujący weryfikuje się względem kotwicy wyprowadzonej z TSL. Zaufany. |
no_anchor_chain | Żadna kotwica w pakiecie nie weryfikuje certyfikatu podpisującego. Niezaufany. |
signer_cert_expired | Czas walidacji przypada po notAfter certyfikatu. Niezaufany. |
signer_cert_not_yet_valid | Czas walidacji przypada przed notBefore certyfikatu. Niezaufany. |
cannot_parse_signer_cert | Dostarczony PEM nie parsuje się jako certyfikat X.509. Niezaufany. |
Przykład kodu — Szybki start
Dział zatytułowany „Przykład kodu — Szybki start”Twoje narzędzia kontenera już wyodrębniły certyfikat podpisujący. Powiąż go z zaufaną listą państwa członkowskiego, którą pobrałeś i uwierzytelniłeś (zobacz Trusted lists).
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Enterprise\Security\Asic\AsicTrustBinder;use NextPDF\Enterprise\Security\Tsl\TslParseException;use NextPDF\Enterprise\Security\Tsl\TslTrustAnchorProvider;use NextPDF\Enterprise\Security\Tsl\TslXmlParser;
// Extracted by YOUR tooling from META-INF/signature.p7s or signatures.xml.$signerCertPem = (string) file_get_contents(__DIR__ . '/asic-signer.pem');
// A trusted list you have already fetched and authenticated.$tslXml = (string) file_get_contents(__DIR__ . '/member-state-tsl.xml');
$binder = new AsicTrustBinder(new TslTrustAnchorProvider());
try { $tsl = (new TslXmlParser())->parse($tslXml);
$result = $binder->verify( signerCertPem: $signerCertPem, tsl: $tsl, validationTime: new DateTimeImmutable('2026-07-03T12:00:00Z'), );} catch (TslParseException $e) { // Fail closed: stale TSL, malformed NextUpdate, or no active CA/QC services. fwrite(STDERR, 'Trusted list rejected: ' . $e->getMessage() . PHP_EOL); exit(1);}
echo $result->trusted ? "TRUSTED\n" : "NOT TRUSTED\n";echo 'Anchors: ' . $result->anchorBundleVersion . "\n";echo 'Reasons: ' . implode(', ', $result->reasons) . "\n";Oczekiwany wynik dla podpisującego wystawionego przez wymienioną usługę CA/QC:
TRUSTEDAnchors: tsl-eu-seq42Reasons: anchor_signature_matchPrzykład kodu — Produkcja
Dział zatytułowany „Przykład kodu — Produkcja”Wyprowadź pakiet kotwic raz na zaufaną listę, a następnie weryfikuj wiele podpisujących z kontenerów względem niego. Jeden nieaktualny lub nieużyteczny TSL zamyka bezpiecznie całą partię; indywidualne problemy podpisujących ujawniają się per kontener.
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Enterprise\Security\Asic\AsicTrustBinder;use NextPDF\Enterprise\Security\Asic\AsicTrustBindingResult;use NextPDF\Enterprise\Security\Tsl\TslDocument;use NextPDF\Enterprise\Security\Tsl\TslParseException;use NextPDF\Enterprise\Security\Tsl\TslTrustAnchorProvider;use NextPDF\Enterprise\Security\Tsl\TslXmlParser;
/** * @param array<string, non-empty-string> $signerPemsByContainer PEM per container path. * @return array<string, AsicTrustBindingResult> * @throws TslParseException When no anchor set can be derived from the TSL. */function bindBatch( TslDocument $tsl, array $signerPemsByContainer, DateTimeImmutable $validationTime,): array { $provider = new TslTrustAnchorProvider();
// Derive the anchor set ONCE; a throw here means the trusted list itself // is unusable at this validation time. $bundle = $provider->buildBundle($tsl, $validationTime);
$binder = new AsicTrustBinder($provider);
$results = []; foreach ($signerPemsByContainer as $container => $signerPem) { $results[$container] = $binder->verifyAgainstBundle( signerCertPem: $signerPem, bundle: $bundle, validationTime: $validationTime, ); }
return $results;}
$tsl = (new TslXmlParser())->parse( (string) file_get_contents(__DIR__ . '/member-state-tsl.xml'),);
$signerPems = [ 'invoice-2026-06.asice' => (string) file_get_contents(__DIR__ . '/signer-a.pem'), 'tender-2019.asice' => (string) file_get_contents(__DIR__ . '/signer-b.pem'),];
try { $results = bindBatch( tsl: $tsl, signerPemsByContainer: $signerPems, validationTime: new DateTimeImmutable('now', new DateTimeZone('UTC')), );} catch (TslParseException $e) { // Fail closed for the WHOLE batch: no trustworthy anchor set exists. fwrite(STDERR, 'Anchor derivation failed: ' . $e->getMessage() . PHP_EOL); exit(1);}
foreach ($results as $container => $result) { printf( "%s => %s (%s; anchors %s)\n", $container, $result->trusted ? 'trusted' : 'rejected', implode(',', $result->reasons), $result->anchorBundleVersion, );}Oczekiwany wynik, gdy jeden certyfikat podpisujący wygasł:
invoice-2026-06.asice => trusted (anchor_signature_match; anchors tsl-eu-seq42)tender-2019.asice => rejected (signer_cert_expired; anchors tsl-eu-seq42)Przypadki brzegowe i pułapki
Dział zatytułowany „Przypadki brzegowe i pułapki”- Czas walidacji jest obowiązkowy i rozstrzygający. Nie ma cichej wartości domyślnej
now. Podpis, który zweryfikował się w 2019, zgłaszasigner_cert_expired, gdy walidujesz w momencie z 2026 ponotAfter. Dla materiałów historycznych przekaż czas, który wspiera Twój dowód (na przykład czas dowodu istnienia), a nie zegar ścienny. - Nieaktualny TSL rzuca wyjątek; to nie jest werdykt „niezaufany”.
TslParseExceptionzverify()lubbuildBundle()oznacza, że źródło zaufania jest nieużyteczne. Traktuj to jako awarię operacyjną: odśwież listę, nie zapisuj tego jako odrzucenia podpisującego. - Kotwice testowane są jako bezpośredni wystawcy. Każda kotwica jest próbowana jako certyfikat, który podpisał certyfikat podpisujący. TSL państw członkowskich UE wymieniają certyfikaty usług CA/QC wystawiających, więc certyfikaty kwalifikowane podmiotu końcowego zwykle dopasowują się bezpośrednio. Podpisujący wystawiony przez pośredni urząd CA, który sam nie jest wymienioną aktywną usługą CA/QC, daje
no_anchor_chain. - Wyprowadzanie kotwic filtruje ostro. Usługi wycofane lub jakiegokolwiek typu innego niż CA/QC nigdy nie stają się kotwicami. Lista, której aktywny zbiór CA/QC jest pusty, rzuca wyjątek, zamiast wytwarzać pusty pakiet.
NextUpdatemusi być kanonicznym UTC. Wartość bez jawnegoZlub liczbowego oznaczenia przesunięcia jest odrzucana fail-closed, nigdy nie reinterpretowana w lokalnej strefie czasowej serwera.- Zniekształcone wejście degraduje precyzyjnie. PEM, który się nie parsuje, zwraca
cannot_parse_signer_cert; certyfikat jeszcze nieważny jest odróżniany od wygasłego. - Zapisz
anchorBundleVersion. Nazywa dokładny zbiór kotwic (tsl-<territory>-seq<N>) stojący za każdym werdyktem, o co właśnie zapyta audytor.
Uwagi dotyczące bezpieczeństwa
Dział zatytułowany „Uwagi dotyczące bezpieczeństwa”- Fail-closed z założenia konstrukcyjnego. Świeżość sprawdzana jest przed wyprowadzeniem jakiejkolwiek kotwicy. Bramka ważności podpisującego uruchamiana jest przed jakimkolwiek porównaniem kotwic. Nieużyteczny materiał zaufania rzuca wyjątek; wątpliwi podpisujący są odrzucani z podaniem powodów. Żadna ścieżka nie degraduje do cichego przejścia.
- Powiązanie zaufania to jedna warstwa, a nie cała walidacja. To API nie weryfikuje wartości podpisu CAdES nad zawartością kontenera, nie sprawdza unieważnienia (brak zapytań CRL ani OCSP) i nie uwierzytelnia samego dokumentu TSL. Najpierw uwierzytelnij listę przez potok zaufanych list (zobacz Trusted lists), zweryfikuj podpis kryptograficznie swoimi narzędziami do podpisów i dodaj sprawdzanie unieważnienia zgodnie ze swoją polityką.
- Wybieraj czas walidacji rozważnie. Werdykt jest funkcją czasu, który przekazujesz. Wyprowadź go z wiarygodnego dowodu (kwalifikowanego znacznika czasu, zapisu archiwalnego), a nie z zegara, na który może wpłynąć atakujący.
- Wyjścia dowodowe są deterministyczne.
trusted,anchorBundleVersionireasonsto stabilne, maszynowo czytelne wartości nadające się do podpisanych dzienników audytowych.
Zgodność
Dział zatytułowany „Zgodność”AsicTrustBinder wspiera procesy zgodne z ETSI EN 319 162-1 (bazowe kontenery ASiC), ETSI EN 319 122-1 (bazowe podpisy CAdES) oraz ETSI TS 119 612 (zaufane listy) i stosuje bramkę okresu ważności RFC 5280 w podanym czasie walidacji.
Wsparcie to nie zgodność, a zgodność to nie certyfikacja. NextPDF implementuje kontrole opisane na tej stronie; nie został certyfikowany względem tych norm przez żadną jednostkę, a użycie tego API samo w sobie nie czyni Twojego wyniku „kwalifikowanym” ani prawnie skutecznym w świetle eIDAS lub jakiegokolwiek innego reżimu. NextPDF nie posiada żadnej certyfikacji i żadnej nie udziela. To, czy kompletny proces walidacji spełnia dany wymóg prawny lub przetargowy, jest ustaleniem należącym do Twoich audytorów.
Zachowanie w trybie FIPS
Dział zatytułowany „Zachowanie w trybie FIPS”Powiązanie zaufania wykonuje kontrole podpisu certyfikatu X.509 w procesie; nie jest kierowane przez strażnika środowiska uruchomieniowego trybu FIPS Enterprise, a włączenie trybu FIPS nie zmienia jego zachowania. Nie jest to usługa kryptograficzna walidowana pod FIPS i nie jest deklarowana żadna certyfikacja FIPS 140. Wdrożenia z obowiązkami FIPS powinny odpowiednio ograniczyć zakres tego API i zobaczyć Polityka kryptograficzna FIPS 140-2/3.
Kontrakt zachowania
Dział zatytułowany „Kontrakt zachowania”verify()wyprowadza kotwice wyłącznie z TSL, który jest świeży w podanym czasie walidacji; nieaktualna lub zniekształcona lista rzucaTslParseException, zanim istnieje jakakolwiek kotwica.- Kotwice wyprowadzane są wyłącznie z usług TSL w statusie granted typu usługi CA/QC; pusty aktywny zbiór rzuca wyjątek.
- Okres ważności certyfikatu podpisującego musi obejmować czas walidacji; naruszenia zwracają
signer_cert_expiredlubsigner_cert_not_yet_valid. - Każdy wynik jest obiektem
AsicTrustBindingResultniosącymtrusted,anchorBundleVersioni co najmniej jeden kod powodu; nie ma werdyktu bez powodu. - Niezaufani podpisujący są zwracani, nigdy rzucani; nieużyteczny materiał zaufania jest rzucany, nigdy zwracany jako werdykt.
- Parsowanie kontenera nigdy nie zachodzi wewnątrz tego API; wejściami są wyodrębniony PEM, zaufana lista i czas walidacji.
Rozwiązanie zastępcze w Core
Dział zatytułowany „Rozwiązanie zastępcze w Core”NextPDF Core waliduje podpisy PDF (CMS/PAdES) względem kotwic zaufania, które przypinasz jawnie przez jego kontrakt CaTrustAnchorBundle — zobacz Core security. Core nie ma pobierania zaufanych list (TSL) ani specyficznego dla ASiC powiązania zaufania. Z samym Core możesz utrzymywać własny zbiór kotwic do walidacji podpisów PDF; wyprowadzanie kotwic z zaufanej listy ETSI TS 119 612 i wiązanie z nimi podpisujących z kontenerów ASiC wymaga NextPDF Enterprise.
Granica publikacji
Dział zatytułowany „Granica publikacji”Ta strona dokumentuje wyłącznie zewnętrznie obserwowalne zachowanie oraz wspieraną publiczną powierzchnię API. Wewnętrzne ścieżki przestrzeni nazw, klasy pomocnicze, tabele mechanizmów, nazwy plików runbooków i prefiksy zgłoszeń są poza zakresem.
Zobacz także
Dział zatytułowany „Zobacz także”- Trusted lists — pobierz, uwierzytelnij i sparsuj TSL, który zasila dostawcę kotwic.
- Signature verification — powierzchnia weryfikacji Enterprise dla podpisów PDF.
- FIPS 140-2/3 cryptographic policy — postawa trybu FIPS w Enterprise.
- How a digital signature proves who signed — tło od pierwszych zasad.
- Long-term validation — dlaczego czas walidacji i zachowane dowody mają znaczenie.