Zum Inhalt springen
getnextpdf.com

Enterprise Edition

ASiC-Vertrauensbindung

Ein ASiC-Container bündelt signierte Dateien mit den Signaturen, die sie schützen. Die schwierige Frage ist nicht „berechnet sich die Signatur?”, sondern „wer steht hinter dem Unterzeichner?”. NextPDF\Enterprise\Security\Asic\AsicTrustBinder beantwortet genau diese Frage. Sie übergeben ihm das Signaturzertifikat aus der Container-Signatur, eine vertrauenswürdige Liste und eine Validierungszeit. Er antwortet mit einem AsicTrustBindingResult: einem Urteil vertrauenswürdig/nicht vertrauenswürdig, der Version des Anker-Bundles, gegen die er entschieden hat, und maschinenlesbaren Begründungen. Jede Ablehnung benennt ihre Ursache, sodass sich der Prüfnachweis von selbst schreibt.

Eine Grenze ist bewusst gezogen und vorab erwähnenswert. Diese API parst ASiC-Container nicht. Ihre Werkzeuge öffnen den Container und extrahieren das Signaturzertifikat; NextPDF besitzt die Vertrauensentscheidung.

Diese Fähigkeit wird in NextPDF Enterprise (nextpdf/enterprise) ausgeliefert und wird mit einer Enterprise-Tier-Lizenzhülle aktiviert. Eine Bereitstellung ohne diese Berechtigung lädt die Klassen der Fähigkeit nicht. Editionen vergleichen und eine Lizenz erwerben.

Terminal-Fenster
composer require nextpdf/enterprise

Die Aktivierung erfordert Ihre Enterprise-Lizenzhülle. Siehe Installieren und authentifizieren. Die Klassen auf dieser Seite liegen unter NextPDF\Enterprise\Security\Asic und NextPDF\Enterprise\Security\Tsl.

ASiC (Associated Signature Containers, ETSI EN 319 162-1) verpackt Datendateien und Signaturen in einem Archiv. Ein ASiC-Baseline-Container bettet ausschließlich CAdES- oder XAdES-Baseline-Signaturen ein. Eine CAdES-Baseline-Signatur führt ihr Signaturzertifikat innerhalb von SignedData.certificates, sodass von einem Prüfer erwartet wird, dieses aus der Container-Signatur zu extrahieren, wenn die Signatur wohlgeformt und von den Container-Werkzeugen unterstützt ist. Dieses extrahierte Zertifikat ist die Eingabe dieser API.

Die Vertrauensquelle ist eine vertrauenswürdige Liste (TSL) nach ETSI TS 119 612: ein signiertes XML-Dokument, das Vertrauensdiensteanbieter und ihre Dienstzertifikate aufzählt. NextPDF\Enterprise\Security\Tsl\TslTrustAnchorProvider wandelt ein geparstes TslDocument in ein Anker-Bundle um. Nur Dienste, die sowohl im Status granted sind als auch vom Diensttyp CA/QC, säen den Ankersatz. Das Bundle trägt eine Versionszeichenkette, die aus der TSL-Sequenznummer und dem Territorium abgeleitet wird, plus einen SHA-256-Integritätsdigest.

Zwei Fail-closed-Gates laufen vor jedem Anker-Vergleich:

  1. TSL-Aktualität. Eine vertrauenswürdige Liste, deren NextUpdate-Zeitpunkt verstrichen ist, muss als abgelaufen verworfen werden. AsicTrustBinder::verify() prüft die Aktualität zur angegebenen Validierungszeit, bevor ein einziger Anker abgeleitet wird. Eine veraltete Liste oder ein NextUpdate-Wert ohne expliziten UTC-Bezeichner wirft TslParseException.
  2. Gültigkeitszeitraum des Unterzeichners. Die Pfadvalidierung nach RFC 5280 verlangt, dass der Gültigkeitszeitraum des Zertifikats die Validierungszeit umfasst. Eine kryptografisch unversehrte Signatur, deren Zertifikat zu diesem Zeitpunkt abgelaufen oder noch nicht gültig war, wird mit einem präzisen Begründungscode abgelehnt.

Erst dann prüft der Binder das Signaturzertifikat gegen jeden Anker. Eine Übereinstimmung ergibt trusted: true mit der Begründung anchor_signature_match. Keine Übereinstimmung ergibt trusted: false mit der Begründung no_anchor_chain.

Die tragende Entwurfsentscheidung ist eine strikte Trennung zwischen Container-Mechanik und Vertrauensentscheidung, wobei die Vertrauensentscheidung gezwungen wird, bezüglich der Zeit explizit zu sein. Containerformate variieren (ASiC-S, ASiC-E, CAdES- oder XAdES-Nutzlasten), doch die Vertrauensfrage ist ein invarianter Kern: Verkettet dieses Zertifikat zu einem Anker aus einer aktuellen vertrauenswürdigen Liste zu einem angegebenen Zeitpunkt? Diesen Kern frei von ZIP- und XML-Parsing zu halten, hält ihn klein genug, um ihn erschöpfend zu testen und an jedem Gate fail-closed zu halten. Dieselbe Überlegung verbietet einen stillen now-Standard: Die Validierungszeit ändert das Urteil, also muss der Aufrufer sie besitzen. Die Aktualität wird innerhalb des Anker-Ableitungspfads selbst geprüft, nicht in einem optionalen Kollaborateur, sodass kein Erzeuger-Pfad sie überspringen kann.

Entwurfshintergrund: Wie eine digitale Signatur beweist, wer signiert hat.

Die Konstruktion nimmt den Anker-Provider entgegen, der vertrauenswürdige Listen in Anker-Bundles verwandelt.

public function __construct(
private readonly TslTrustAnchorProvider $anchorProvider,
) {}

Der primäre Einstiegspunkt prüft ein Unterzeichnerzertifikat gegen eine vertrauenswürdige Liste:

public function verify(
string $signerCertPem,
TslDocument $tsl,
DateTimeInterface $validationTime,
): AsicTrustBindingResult
  • $signerCertPem — nicht leere PEM-Zeichenkette: das Signaturzertifikat aus der ASiC-Signatur.
  • $tsl — die geparste, authentifizierte vertrauenswürdige Liste.
  • $validationTime — der Zeitpunkt, den der Gültigkeitszeitraum des Unterzeichnerzertifikats umfassen muss. Es gibt keinen Standardwert.

Wirft oder scheitert mit: NextPDF\Enterprise\Security\Tsl\TslParseException, wenn die TSL veraltet ist (NextUpdate verstrichen), wenn NextUpdate kein kanonischer UTC-Wert ist oder wenn die Liste keine aktiven CA/QC-Dienste enthält. Nicht vertrauenswürdige Unterzeichner werfen nicht; sie liefern ein Ergebnis mit trusted: false und einem Begründungscode.

Für Batch-Arbeitslasten prüfen Sie gegen ein vorab erstelltes Bundle:

public function verifyAgainstBundle(
string $signerCertPem,
EnterpriseCaTrustAnchorBundle $bundle,
DateTimeInterface $validationTime,
): AsicTrustBindingResult

Wirft oder scheitert mit: keine eigenen Ausnahmen; jedes Ergebnis ist ein AsicTrustBindingResult. Beziehen Sie das Bundle aus TslTrustAnchorProvider::buildBundle() — konstruieren Sie es nicht von Hand.

public function buildBundle(TslDocument $tsl, DateTimeImmutable $now): EnterpriseCaTrustAnchorBundle

Wirft oder scheitert mit: TslParseException, wenn die TSL veraltet ist, ihr NextUpdate kein kanonischer UTC-Wert ist oder sie keine aktiven CA/QC-Dienste hat.

public function __construct(
public bool $trusted,
public string $anchorBundleVersion,
public array $reasons,
) {}

$reasons ist eine list<non-empty-string> maschinenlesbarer Codes. $anchorBundleVersion verzeichnet den verwendeten Ankersatz in der Form tsl-<territory>-seq<N> (zum Beispiel tsl-eu-seq42).

BegründungscodeBedeutung
anchor_signature_matchDas Unterzeichnerzertifikat verifiziert gegen einen TSL-abgeleiteten Anker. Vertrauenswürdig.
no_anchor_chainKein Anker im Bundle verifiziert das Unterzeichnerzertifikat. Nicht vertrauenswürdig.
signer_cert_expiredDie Validierungszeit liegt nach dem notAfter des Zertifikats. Nicht vertrauenswürdig.
signer_cert_not_yet_validDie Validierungszeit liegt vor dem notBefore des Zertifikats. Nicht vertrauenswürdig.
cannot_parse_signer_certDas übergebene PEM parst nicht als X.509-Zertifikat. Nicht vertrauenswürdig.

Ihre Container-Werkzeuge haben das Signaturzertifikat bereits extrahiert. Binden Sie es an eine vertrauenswürdige Liste eines Mitgliedstaats, die Sie abgerufen und authentifiziert haben (siehe Vertrauenswürdige Listen).

asic-trust-binding-quickstart.php
<?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";

Erwartete Ausgabe für einen Unterzeichner, der von einem gelisteten CA/QC-Dienst ausgestellt wurde:

TRUSTED
Anchors: tsl-eu-seq42
Reasons: anchor_signature_match

Leiten Sie das Anker-Bundle einmal pro vertrauenswürdiger Liste ab und prüfen Sie dann viele Container-Unterzeichner dagegen. Eine veraltete oder unbrauchbare TSL lässt den gesamten Batch fail-closed scheitern; individuelle Unterzeichnerprobleme treten pro Container zutage.

asic-trust-binding-batch.php
<?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,
);
}

Erwartete Ausgabe, wenn ein Unterzeichnerzertifikat abgelaufen ist:

invoice-2026-06.asice => trusted (anchor_signature_match; anchors tsl-eu-seq42)
tender-2019.asice => rejected (signer_cert_expired; anchors tsl-eu-seq42)
  • Die Validierungszeit ist verpflichtend und ausschlaggebend. Es gibt keinen stillen now-Standard. Eine Signatur, die 2019 verifiziert hat, meldet signer_cert_expired, wenn Sie zu einem Zeitpunkt in 2026 nach notAfter validieren. Für historisches Material übergeben Sie die Zeit, die Ihr Nachweis stützt (zum Beispiel eine Proof-of-Existence-Zeit), nicht die Wanduhr.
  • Eine veraltete TSL wirft; sie ist kein „nicht vertrauenswürdig”-Urteil. Eine TslParseException aus verify() oder buildBundle() bedeutet, dass die Vertrauensquelle unbrauchbar ist. Behandeln Sie sie als Betriebsfehler: Aktualisieren Sie die Liste, verzeichnen Sie sie nicht als Unterzeichnerablehnung.
  • Anker werden als direkte Aussteller geprüft. Jeder Anker wird als das Zertifikat probiert, das das Unterzeichnerzertifikat signiert hat. TSLs der EU-Mitgliedstaaten listen die ausstellenden CA/QC-Dienstzertifikate auf, sodass qualifizierte Endentitätszertifikate typischerweise direkt übereinstimmen. Ein Unterzeichner, der von einer Zwischen-CA ausgestellt wurde, die nicht selbst ein gelisteter aktiver CA/QC-Dienst ist, ergibt no_anchor_chain.
  • Die Anker-Ableitung filtert hart. Dienste, die zurückgezogen sind oder von einem anderen Typ als CA/QC, werden niemals zu Ankern. Eine Liste, deren aktiver CA/QC-Satz leer ist, wirft, statt ein leeres Bundle zu erzeugen.
  • NextUpdate muss kanonisches UTC sein. Ein Wert ohne expliziten Z- oder numerischen Offset-Bezeichner wird fail-closed abgelehnt, niemals in der lokalen Zeitzone des Servers umgedeutet.
  • Fehlerhafte Eingaben verschlechtern sich präzise. Ein PEM, das nicht parst, liefert cannot_parse_signer_cert; ein noch nicht gültiges Zertifikat wird von einem abgelaufenen unterschieden.
  • Verzeichnen Sie anchorBundleVersion. Es benennt den genauen Ankersatz (tsl-<territory>-seq<N>) hinter jedem Urteil, und genau danach wird ein Prüfer fragen.
  • Fail-closed durch Konstruktion. Die Aktualität wird geprüft, bevor irgendein Anker abgeleitet wird. Das Gate zur Gültigkeit des Unterzeichners läuft vor jedem Anker-Vergleich. Unbrauchbares Vertrauensmaterial wirft; fragwürdige Unterzeichner werden mit Begründungen abgelehnt. Kein Pfad verschlechtert sich zu einem stillen Durchlass.
  • Vertrauensbindung ist eine Schicht, nicht die gesamte Validierung. Diese API verifiziert nicht den CAdES-Signaturwert über den Container-Inhalt, prüft keinen Widerruf (kein CRL- oder OCSP-Abruf) und authentifiziert das TSL-Dokument selbst nicht. Authentifizieren Sie die Liste zuerst über die Trusted-List-Pipeline (siehe Vertrauenswürdige Listen), verifizieren Sie die Signatur kryptografisch mit Ihren Signaturwerkzeugen und ergänzen Sie die Widerrufsprüfung gemäß Ihrer Richtlinie.
  • Wählen Sie die Validierungszeit bewusst. Das Urteil ist eine Funktion der Zeit, die Sie übergeben. Leiten Sie sie aus vertrauenswürdigem Nachweis ab (ein qualifizierter Zeitstempel, ein Archiveintrag), nicht aus einer durch Angreifer beeinflussbaren Uhr.
  • Nachweisausgaben sind deterministisch. trusted, anchorBundleVersion und reasons sind stabile, maschinenlesbare Werte, geeignet für signierte Prüfprotokolle.

AsicTrustBinder unterstützt Arbeitsabläufe, die auf ETSI EN 319 162-1 (ASiC-Baseline-Container), ETSI EN 319 122-1 (CAdES-Baseline-Signaturen) und ETSI TS 119 612 (vertrauenswürdige Listen) ausgerichtet sind, und wendet das Gültigkeitszeitraum-Gate nach RFC 5280 zur angegebenen Validierungszeit an.

Unterstützung ist keine Konformität, und Konformität ist keine Zertifizierung. NextPDF implementiert die auf dieser Seite beschriebenen Prüfungen; es wurde von keiner Stelle gegen diese Standards zertifiziert, und die Nutzung dieser API macht Ihre Ausgabe für sich genommen nicht „qualifiziert” oder rechtlich wirksam unter eIDAS oder einem anderen Regime. NextPDF hält keine Zertifizierung und gewährt keine. Ob ein vollständiger Validierungsprozess eine gegebene rechtliche oder Beschaffungsanforderung erfüllt, ist eine Feststellung Ihrer Gutachter.

Die Vertrauensbindung führt X.509-Zertifikatssignaturprüfungen prozessintern durch; sie wird nicht über den FIPS-Modus-Laufzeitwächter von Enterprise geleitet, und das Aktivieren des FIPS-Modus ändert ihr Verhalten nicht. Sie ist kein FIPS-validierter kryptografischer Dienst, und es wird keine FIPS-140-Zertifizierung beansprucht. Bereitstellungen mit FIPS-Verpflichtungen sollten diese API entsprechend eingrenzen und FIPS 140-2/3 Kryptografierichtlinie beachten.

  • verify() leitet Anker nur aus einer TSL ab, die zur angegebenen Validierungszeit aktuell ist; eine veraltete oder fehlerhafte Liste wirft TslParseException, bevor irgendein Anker existiert.
  • Anker leiten sich ausschließlich aus TSL-Diensten im Status granted mit dem Diensttyp CA/QC ab; ein leerer aktiver Satz wirft.
  • Der Gültigkeitszeitraum des Unterzeichnerzertifikats muss die Validierungszeit umfassen; Verstöße liefern signer_cert_expired oder signer_cert_not_yet_valid.
  • Jedes Ergebnis ist ein AsicTrustBindingResult, das trusted, anchorBundleVersion und mindestens einen Begründungscode trägt; es gibt kein begründungsloses Urteil.
  • Nicht vertrauenswürdige Unterzeichner werden zurückgegeben, niemals geworfen; unbrauchbares Vertrauensmaterial wird geworfen, niemals als Urteil zurückgegeben.
  • Das Parsen des Containers findet niemals innerhalb dieser API statt; die Eingaben sind das extrahierte PEM, die vertrauenswürdige Liste und die Validierungszeit.

NextPDF Core validiert PDF-Signaturen (CMS/PAdES) gegen Vertrauensanker, die Sie explizit über seinen CaTrustAnchorBundle-Vertrag anpinnen — siehe Core-Sicherheit. Core besitzt keine Trusted-List-(TSL-)Aufnahme und keine ASiC-spezifische Vertrauensbindung. Mit Core allein können Sie Ihren eigenen Ankersatz für die PDF-Signaturvalidierung pflegen; das Ableiten von Ankern aus einer vertrauenswürdigen Liste nach ETSI TS 119 612 und das Binden von ASiC-Container-Unterzeichnern an diese erfordert NextPDF Enterprise.

Diese Seite dokumentiert ausschließlich extern beobachtbares Verhalten und die unterstützte öffentliche API-Oberfläche. Interne Namespace-Pfade, Hilfsklassen, Mechanismustabellen, Runbook-Dateinamen und Ticket-Präfixe sind außerhalb des Geltungsbereichs.