Enterprise editie
ASiC-vertrouwensbinding
In één oogopslag
Sectie met titel “In één oogopslag”Een ASiC-container bundelt ondertekende bestanden met de handtekeningen die ze beschermen. De moeilijke vraag is niet “klopt de handtekening rekenkundig?” maar “wie staat er achter de ondertekenaar?”. NextPDF\Enterprise\Security\Asic\AsicTrustBinder beantwoordt precies die vraag. Je geeft het het ondertekeningscertificaat uit de containerhandtekening, een trusted list en een validatietijd. Het antwoordt met een AsicTrustBindingResult: een trusted/untrusted verdict, de anchor-bundleversie waartegen het besliste en machineleesbare redenen. Elke afwijzing benoemt zijn oorzaak, zodat het auditbewijs zichzelf schrijft.
Eén grens is bewust gekozen en verdient het om vooraf gesteld te worden. Deze API parseert geen ASiC-containers. Jouw tooling opent de container en extraheert het ondertekeningscertificaat; NextPDF bezit de vertrouwensbeslissing.
Beschikbaarheid & licensing
Sectie met titel “Beschikbaarheid & licensing”Deze mogelijkheid zit in NextPDF Enterprise (nextpdf/enterprise) en activeert met een license envelope op Enterprise-niveau. Een deployment zonder dat recht laadt de klassen van de mogelijkheid niet. Vergelijk edities en verkrijg een licentie.
Installatie
Sectie met titel “Installatie”composer require nextpdf/enterpriseActivatie vereist je Enterprise license envelope. Zie Installeren en authenticeren. De klassen op deze pagina leven onder NextPDF\Enterprise\Security\Asic en NextPDF\Enterprise\Security\Tsl.
Conceptueel overzicht
Sectie met titel “Conceptueel overzicht”ASiC (Associated Signature Containers, ETSI EN 319 162-1) verpakt databestanden en handtekeningen in één archief. Een baseline ASiC-container embedt uitsluitend CAdES- of XAdES-baseline-handtekeningen. Een CAdES-baseline-handtekening draagt zijn ondertekeningscertificaat binnen SignedData.certificates, dus van een verifier wordt verwacht dat die het extraheert uit de containerhandtekening wanneer de handtekening welgevormd is en ondersteund wordt door de container tooling. Dat geëxtraheerde certificaat is de input van deze API.
De vertrouwensbron is een ETSI TS 119 612 trusted list (TSL): een ondertekend XML-document dat trust service providers en hun servicecertificaten opsomt. NextPDF\Enterprise\Security\Tsl\TslTrustAnchorProvider zet een geparseerd TslDocument om in een anchor bundle. Alleen services die zowel in granted status verkeren als van het CA/QC-servicetype zijn, voeden de anchor set. De bundle draagt een versiestring die is afgeleid van het TSL-sequentienummer en het territorium, plus een SHA-256 integriteitsdigest.
Twee fail-closed gates draaien voordat er enige anchor-vergelijking plaatsvindt:
- TSL-versheid. Een trusted list waarvan het
NextUpdate-moment is verstreken, moet als verlopen worden weggegooid.AsicTrustBinder::verify()bevestigt versheid op de opgegeven validatietijd voordat het ook maar één anchor afleidt. Een verouderde lijst, of eenNextUpdate-waarde zonder expliciete UTC-aanduiding, gooitTslParseException. - Geldigheidsperiode van de ondertekenaar. RFC 5280 path validation vereist dat de geldigheidsperiode van het certificaat de validatietijd omvat. Een cryptografisch intacte handtekening waarvan het certificaat op dat moment verlopen was, of nog niet geldig, wordt afgewezen met een precieze reason code.
Pas dan test de binder het ondertekeningscertificaat tegen elke anchor. Een match levert trusted: true op met reden anchor_signature_match. Geen match levert trusted: false op met reden no_anchor_chain.
Waarom het zo werkt
Sectie met titel “Waarom het zo werkt”De dragende ontwerpbeslissing is een strikte scheiding tussen containermechaniek en de vertrouwensbeslissing, waarbij de vertrouwensbeslissing gedwongen wordt om expliciet te zijn over tijd. Containerformaten variëren (ASiC-S, ASiC-E, CAdES- of XAdES-payloads), maar de vertrouwensvraag is één invariante kern: chaint dit certificaat naar een anchor uit een verse trusted list op een gesteld moment? Die kern vrijhouden van ZIP- en XML-parsing houdt hem klein genoeg om uitputtend te testen en om bij elke gate fail-closed te gaan. Dezelfde redenering verbiedt een stille now-default: validatietijd verandert het verdict, dus de aanroeper moet die bezitten. Versheid wordt bevestigd binnen het anchor-afleidingspad zelf, niet in een optionele collaborator, zodat geen enkel producerpad het kan overslaan.
Ontwerpachtergrond: Hoe een digitale handtekening bewijst wie ondertekende.
API-oppervlak
Sectie met titel “API-oppervlak”AsicTrustBinder
Sectie met titel “AsicTrustBinder”De constructie neemt de anchor provider die trusted lists omzet in anchor bundles.
public function __construct( private readonly TslTrustAnchorProvider $anchorProvider,) {}Het primaire toegangspunt verifieert een ondertekenaarscertificaat tegen een trusted list:
public function verify( string $signerCertPem, TslDocument $tsl, DateTimeInterface $validationTime,): AsicTrustBindingResult$signerCertPem— non-empty PEM-string: het ondertekeningscertificaat uit de ASiC-handtekening.$tsl— de geparseerde, geauthenticeerde trusted list.$validationTime— het moment dat de geldigheidsperiode van het ondertekenaarscertificaat moet omvatten. Er is geen default.
Gooit of faalt met: NextPDF\Enterprise\Security\Tsl\TslParseException wanneer de TSL verouderd is (NextUpdate verstreken), wanneer NextUpdate geen canonieke UTC-waarde is, of wanneer de lijst geen actieve CA/QC-services bevat. Untrusted ondertekenaars gooien niet; ze geven een resultaat terug met trusted: false en een reason code.
Voor batch-workloads verifieer je tegen een vooraf gebouwde bundle:
public function verifyAgainstBundle( string $signerCertPem, EnterpriseCaTrustAnchorBundle $bundle, DateTimeInterface $validationTime,): AsicTrustBindingResultGooit of faalt met: geen eigen excepties; elke uitkomst is een AsicTrustBindingResult. Verkrijg de bundle van TslTrustAnchorProvider::buildBundle() — construeer hem niet met de hand.
TslTrustAnchorProvider
Sectie met titel “TslTrustAnchorProvider”public function buildBundle(TslDocument $tsl, DateTimeImmutable $now): EnterpriseCaTrustAnchorBundleGooit of faalt met: TslParseException als de TSL verouderd is, zijn NextUpdate geen canonieke UTC-waarde is, of het geen actieve CA/QC-services heeft.
AsicTrustBindingResult
Sectie met titel “AsicTrustBindingResult”public function __construct( public bool $trusted, public string $anchorBundleVersion, public array $reasons,) {}$reasons is een list<non-empty-string> van machineleesbare codes. $anchorBundleVersion registreert de gebruikte anchor set, in de vorm tsl-<territory>-seq<N> (bijvoorbeeld tsl-eu-seq42).
| Reason code | Betekenis |
|---|---|
anchor_signature_match | Het ondertekenaarscertificaat verifieert tegen een TSL-afgeleide anchor. Trusted. |
no_anchor_chain | Geen enkele anchor in de bundle verifieert het ondertekenaarscertificaat. Untrusted. |
signer_cert_expired | De validatietijd valt na de notAfter van het certificaat. Untrusted. |
signer_cert_not_yet_valid | De validatietijd valt vóór de notBefore van het certificaat. Untrusted. |
cannot_parse_signer_cert | De opgegeven PEM parseert niet als een X.509-certificaat. Untrusted. |
Codevoorbeeld — Snelstart
Sectie met titel “Codevoorbeeld — Snelstart”Jouw container tooling heeft het ondertekeningscertificaat al geëxtraheerd. Bind het aan een trusted list van een lidstaat die je hebt opgehaald en geauthenticeerd (zie 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";Verwachte output voor een ondertekenaar uitgegeven door een vermelde CA/QC-service:
TRUSTEDAnchors: tsl-eu-seq42Reasons: anchor_signature_matchCodevoorbeeld — Productie
Sectie met titel “Codevoorbeeld — Productie”Leid de anchor bundle één keer per trusted list af, verifieer daarna vele containerondertekenaars ertegen. Eén verouderde of onbruikbare TSL faalt de hele batch fail-closed; individuele ondertekenaarsproblemen komen per container aan de oppervlakte.
<?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, );}Verwachte output wanneer één ondertekenaarscertificaat is verlopen:
invoice-2026-06.asice => trusted (anchor_signature_match; anchors tsl-eu-seq42)tender-2019.asice => rejected (signer_cert_expired; anchors tsl-eu-seq42)Randgevallen & valkuilen
Sectie met titel “Randgevallen & valkuilen”- Validatietijd is verplicht en beslissend. Er is geen stille
now-default. Een handtekening die in 2019 verifieerde, rapporteertsigner_cert_expiredwanneer je valideert op een moment in 2026 voorbijnotAfter. Geef voor historisch materiaal de tijd door die je bewijs ondersteunt (bijvoorbeeld een proof-of-existence-tijd), niet de wandklok. - Een verouderde TSL gooit; het is geen “untrusted” verdict. Een
TslParseExceptionuitverify()ofbuildBundle()betekent dat de vertrouwensbron onbruikbaar is. Behandel het als een operationele fout: ververs de lijst, registreer het niet als een ondertekenaarsafwijzing. - Anchors worden getest als directe uitgevers. Elke anchor wordt geprobeerd als het certificaat dat het ondertekenaarscertificaat ondertekende. EU-lidstaat-TSL’s vermelden de uitgevende CA/QC-servicecertificaten, dus end-entity gekwalificeerde certificaten matchen doorgaans direct. Een ondertekenaar uitgegeven door een intermediaire CA die zelf geen vermelde actieve CA/QC-service is, levert
no_anchor_chainop. - Anchor-afleiding filtert hard. Services die zijn ingetrokken, of van enig ander type dan CA/QC, worden nooit anchors. Een lijst waarvan de actieve CA/QC-set leeg is, gooit in plaats van een lege bundle te produceren.
NextUpdatemoet canonieke UTC zijn. Een waarde zonder explicieteZof numerieke offset-aanduiding wordt fail-closed afgewezen, nooit geherinterpreteerd in de lokale tijdzone van de server.- Malformed input degradeert precies. Een PEM die niet parseert, geeft
cannot_parse_signer_certterug; een nog-niet-geldig certificaat wordt onderscheiden van een verlopen certificaat. - Registreer
anchorBundleVersion. Het benoemt de exacte anchor set (tsl-<territory>-seq<N>) achter elk verdict, wat een auditor zal vragen.
Beveiligingsnotities
Sectie met titel “Beveiligingsnotities”- Fail-closed door constructie. Versheid wordt bevestigd voordat er enige anchor wordt afgeleid. De geldigheidsgate van de ondertekenaar draait voor enige anchor-vergelijking. Onbruikbaar vertrouwensmateriaal gooit; twijfelachtige ondertekenaars worden afgewezen met redenen. Geen enkel pad degradeert naar een stille pass.
- Vertrouwensbinding is één laag, niet de hele validatie. Deze API verifieert niet de CAdES-handtekeningwaarde over de containerinhoud, controleert geen revocation (geen CRL- of OCSP-lookup) en authenticeert het TSL-document zelf niet. Authenticeer de lijst eerst via de trusted-list-pipeline (zie Trusted lists), verifieer de handtekening cryptografisch met jouw signature tooling en voeg revocation checking toe volgens jouw beleid.
- Kies de validatietijd bewust. Het verdict is een functie van de tijd die je doorgeeft. Leid deze af uit betrouwbaar bewijs (een gekwalificeerd timestamp, een archiefrecord), niet uit een door een aanvaller beïnvloedbare klok.
- Bewijsoutputs zijn deterministisch.
trusted,anchorBundleVersionenreasonszijn stabiele, machineleesbare waarden geschikt voor ondertekende audit logs.
Conformiteit
Sectie met titel “Conformiteit”AsicTrustBinder ondersteunt workflows afgestemd op ETSI EN 319 162-1 (ASiC baseline containers), ETSI EN 319 122-1 (CAdES baseline signatures) en ETSI TS 119 612 (trusted lists), en past de RFC 5280 geldigheidsperiode-gate toe op de opgegeven validatietijd.
Ondersteuning is geen conformiteit, en conformiteit is geen certificering. NextPDF implementeert de controles die deze pagina beschrijft; het is door geen enkele instantie tegen deze standaarden gecertificeerd, en het gebruik van deze API maakt jouw output op zichzelf niet “gekwalificeerd” of juridisch geldig onder eIDAS of enig ander regime. NextPDF houdt geen certificering en verleent er geen. Of een compleet validatieproces aan een gegeven juridische of aanbestedingseis voldoet, is een beoordeling voor jouw assessoren.
Gedrag in FIPS-modus
Sectie met titel “Gedrag in FIPS-modus”De vertrouwensbinding voert X.509 certificaat-handtekeningcontroles in-process uit; het wordt niet gerouteerd door de Enterprise FIPS-modus runtime guard, en het inschakelen van FIPS-modus verandert het gedrag niet. Het is geen FIPS-gevalideerde cryptografische service, en er wordt geen FIPS 140-certificering geclaimd. Deployments met FIPS-verplichtingen zouden deze API dienovereenkomstig moeten afbakenen en zie FIPS 140-2/3 cryptografisch beleid.
Gedragscontract
Sectie met titel “Gedragscontract”verify()leidt anchors alleen af uit een TSL die vers is op de opgegeven validatietijd; een verouderde of malformed lijst gooitTslParseExceptionvoordat er een anchor bestaat.- Anchors worden uitsluitend afgeleid uit TSL-services in granted status met het CA/QC-servicetype; een lege actieve set gooit.
- De geldigheidsperiode van het ondertekenaarscertificaat moet de validatietijd omvatten; overtredingen geven
signer_cert_expiredofsigner_cert_not_yet_validterug. - Elke uitkomst is een
AsicTrustBindingResultdietrusted,anchorBundleVersionen ten minste één reason code draagt; er is geen verdict zonder reden. - Untrusted ondertekenaars worden teruggegeven, nooit gegooid; onbruikbaar vertrouwensmateriaal wordt gegooid, nooit als verdict teruggegeven.
- Containerparsing gebeurt nooit binnen deze API; de inputs zijn de geëxtraheerde PEM, de trusted list en de validatietijd.
Core-terugval
Sectie met titel “Core-terugval”NextPDF Core valideert PDF-handtekeningen (CMS/PAdES) tegen trust anchors die je expliciet pint via zijn CaTrustAnchorBundle-contract — zie Core security. Core heeft geen trusted-list (TSL) ingestie en geen ASiC-specifieke vertrouwensbinding. Met Core alleen kun je je eigen anchor set onderhouden voor PDF-handtekeningvalidatie; anchors afleiden uit een ETSI TS 119 612 trusted list en ASiC-containerondertekenaars eraan binden vereist NextPDF Enterprise.
Publicatiegrens
Sectie met titel “Publicatiegrens”Deze pagina documenteert alleen extern waarneembaar gedrag en het ondersteunde publieke API-oppervlak. Interne namespace-paden, helper-klassen, mechanismetabellen, runbook-bestandsnamen en ticketprefixen vallen buiten de scope.
Zie ook
Sectie met titel “Zie ook”- Trusted lists — de TSL ophalen, authenticeren en parsen die de anchor provider voedt.
- Signature verification — het Enterprise verificatie-oppervlak voor PDF-handtekeningen.
- FIPS 140-2/3 cryptografisch beleid — de Enterprise FIPS-modus-houding.
- Hoe een digitale handtekening bewijst wie ondertekende — achtergrond vanuit eerste principes.
- Langetermijnvalidatie — waarom validatietijd en bewaard bewijs ertoe doen.