Zum Inhalt springen
getnextpdf.com

Enterprise Edition

Stapelvalidierung von Signaturen

NextPDF Enterprise validiert digitale Signaturen über viele PDF-Dokumente hinweg in einem einzigen Aufruf. NextPDF\Enterprise\Signature\BatchSignatureValidator::validate() nimmt eine Liste von Dokumenten entgegen und liefert einen BatchValidationReport. Jede Signatur durchläuft dieselbe fail-closed Pipeline: kryptografische CMS-Authentifizierung über den signierten Bytebereich, vertrauensverankerte Zertifikatsketten-Validierung und OCSP/CRL-Sperrprüfung. Der Bericht enthält Details pro Dokument und pro Signatur — CertChainStatus, RevocationStatus, TimestampStatus — sodass Compliance-Werkzeuge jedes Urteil aus dessen aufgezeichneten Nachweisen erneut ableiten können.

Das Urteilsmodell ist bewusst streng. Eine Signatur ist nur dann Valid, wenn alle Nachweise positiv belegt sind. Fehlende Sperrnachweise führen zu Indeterminate, niemals zu Valid. Diese Seite behandelt den Stapel-Orchestrator und seine Ergebnistypen. Die AdES-Verifikationsseite für einzelne Dokumente wird in Signaturprüfung dokumentiert. Das Einbetten von Material für die Langzeitvalidierung wird in Archiv dokumentiert.

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

Terminal-Fenster
composer require nextpdf/enterprise

Das nextpdf/premium Metapaket löst ebenfalls das Enterprise-Paket auf. Die Aktivierung nutzt Ihre Enterprise-Lizenzhülle; siehe Lizenzierung und Aktivierung. Die Stapeltypen werden unter NextPDF\Enterprise\Signature automatisch geladen. Es ist keine PHP-Erweiterung über die Engine-Baseline hinaus erforderlich.

Ein Aufruf von validate() verarbeitet eine Liste von DocumentSignatureInput-Werten. Jede Eingabe enthält eine Dokumentkennung, die rohen PDF-Bytes und optionale PEM-kodierte Vertrauensanker. Der Validator extrahiert die Signaturwörterbücher jedes Dokuments und führt pro Signatur drei Stufen aus.

Stufe 1 — kryptografische Authentifizierung. Der abgetrennte CMS/PKCS#7-Blob aus /Contents wird über die von /ByteRange abgedeckten Bytes verifiziert. Der Verifizierer berechnet den Inhalts-Digest selbst neu und vergleicht ihn mit dem messageDigest signed attribute. Er vertraut niemals einem vom Produzenten gelieferten Digest (RFC 5652 §5.6). Der Signaturwert muss verifiziert werden, und das signierende Zertifikat muss an das CMS gebunden sein. Fehlende oder fehlerhafte /Contents oder /ByteRange, ein nicht parsbares CMS, eine Digest-Abweichung oder eine fehlgeschlagene Signaturprüfung führen allesamt zu fail-closed. Eine Signatur, die unter SHA-1 verifiziert, gilt als schwach und ist niemals ein vollständiges Bestehen.

Stufe 2 — Kettenvalidierung und Vertrauensverankerung. Die aus dem CMS wiederhergestellte Signiererkette wird als voraussichtlicher Zertifizierungspfad validiert. Die von Ihnen bereitgestellten trustedCerts sind die Vertrauensanker-Eingabe im Sinne von RFC 5280 §6.1.1: Der Endpunkt der Kette muss anhand des DER-SHA-256-Fingerabdrucks mit einem bereitgestellten Anker übereinstimmen. Eine strukturell konsistente Kette, deren Endpunkt kein konfigurierter Anker ist, wird niemals als vertrauenswürdig gemeldet. Ohne nutzbare Anker wird nur das strukturelle Urteil gemeldet, und CertChainStatus::$trusted bleibt false.

Stufe 3 — Sperrprüfung. Die Sperrprüfung läuft nach der Authentifizierung über die wiederhergestellte Kette und spiegelt das Modell von ETSI EN 319 102-1 wider, in dem die Sperrprüfung auf eine erfolgreiche Pfadvalidierung folgt (clause 5.2.6.2). OCSP ist primär: Nur eine kryptografisch verifizierte Antwort zählt, als Good oder Revoked. Der CRL-Pfad ist der Fallback und bezeugt die Aktualität der Liste. Wenn keiner der Clients konfiguriert ist, ist der Status unavailable.

Das Urteil pro Signatur ist ein SignatureValidationStatus. Die Taxonomie spiegelt das Statusmodell von ETSI EN 319 102-1 (TOTAL-PASSED / TOTAL-FAILED / INDETERMINATE) auf Granularität pro Signatur wider:

NachweisUrteil
Zertifikat bestätigt gesperrtInvalid (entscheidend, unabhängig von anderen Prüfungen)
CMS-Authentifizierung fehlgeschlagen, kein Signierermaterial wiederhergestelltError
CMS-Authentifizierung fehlgeschlagen, Signierermaterial vorhandenInvalid
Authentifiziert, aber die Kette validiert nichtInvalid (oder Error ohne Kette)
Authentifiziert und kettengültig, aber kein bestätigter VertrauensankerIndeterminate
Authentifiziert, kettengültig, vertrauenswürdig, aber keine eindeutige Nicht-SperrungIndeterminate
Alle der obigen positiv belegtValid

Die Regel der eindeutigen Nicht-Sperrung. „Nicht als gesperrt bewiesen” ist nicht dasselbe wie „als nicht gesperrt bewiesen”. Ein Valid-Urteil erfordert mindestens ein Good-Sperrergebnis. Eine verifiziert-gute OCSP-Antwort ist die eindeutige Form: Sie bestätigt den eigenen Status des Signiererzertifikats. Eine kryptografisch akzeptierte, aktuelle CRL erfüllt in dieser Implementierung ebenfalls das Kriterium, aber nur als Aktualitäts- und Integritätsnachweis — der Pfad parst keine Einträge pro Seriennummer, daher liefert er keine Sperrgewähr pro Seriennummer und niemals ein positives revoked-Urteil. Konfigurieren Sie OCSP überall dort, wo eine positive Sperrerkennung von Bedeutung ist: Eine reine CRL-Bereitstellung wird ein gesperrtes Zertifikat nicht als Invalid sichtbar machen. Wenn sowohl OCSP- als auch CRL-Ergebnisse Unknown oder Unavailable sind, ist der Sperrstatus unbestimmt und das Urteil lautet Indeterminate. Dies folgt ETSI EN 319 102-1: nicht verfügbare Sperrstatusinformationen führen zu INDETERMINATE, niemals zu einem Bestehen (clause 5.1.3, TRY_LATER). Dies ist eine Verhaltensverschärfung in 3.1.0 mit Auswirkung auf die Abwärtskompatibilität: Frühere Versionen konnten Valid ohne eindeutigen Sperrnachweis melden. Bereitstellungen, die keinen OCSP- oder CRL-Client konfigurieren, sehen jetzt häufig Indeterminate, wo sie zuvor Valid sahen.

Zwei Grenzen umreißen diese Fähigkeit ehrlich. Erstens wertet der Stapelvalidator keine eingebetteten Zeitstempeltoken aus: TimestampStatus in Stapelergebnissen ist immer der abwesende Zustand. Die Auswertung von RFC 3161-Zeitstempeln gehört zur Verifikationsseite für einzelne Dokumente; siehe Signaturprüfung. Zweitens ist diese Seite eine reine Lesevalidierung. Das Einbetten von DSS/VRI-Material für die Langzeitgültigkeit ist die Fähigkeit Archiv.

Die tragende Entscheidung ist ein fail-closed Urteilsproduzent. Valid wird nur aus positivem Nachweis auf allen drei Achsen geprägt: kryptografische Authentifizierung, eine vertrauensverankerte Kette und eindeutige Nicht-Sperrung. Alles Unbelegte degradiert zu Indeterminate, statt standardmäßig zu bestehen, was die Haltung von EN 319 102-1 für fehlendes Sperrmaterial ist. Der Stapeldurchsatz erkauft niemals Strenge zurück: Die Stapelschicht ist eine Orchestrierung über denselben auditierten CMS-Verifizierer, der für ein einzelnes Dokument verwendet wird, sodass ein Lauf über 1.000 Dokumente identische Kryptografie anwendet. Der Bericht trennt außerdem Nachweis von Urteil — CertChainStatus und RevocationStatus zeichnen die Eingaben auf, auf denen jedes Urteil beruht, sodass ein Prüfer es später erneut ableiten kann.

Design-Hintergrund: Signieren im großen Maßstab, ohne Kompromisse.

Alle nachfolgenden Symbole sind öffentliche API in nextpdf/enterprise 3.1.0.

final class BatchSignatureValidator
{
public function __construct(
?SignatureExtractor $extractor = null,
?CertificateChainValidator $chainValidator = null,
private readonly ?OcspClient $ocspClient = null,
private readonly ?CrlFetcher $crlFetcher = null,
?CmsSignatureDataExtractor $cmsExtractor = null,
private readonly ClockInterface $clock = new SystemClock(),
)
public function validate(array $inputs): BatchValidationReport
}

Wirft oder scheitert mit: validate() wirft \InvalidArgumentException, wenn die Eingabeliste leer ist, und \OverflowException, wenn der Stapel 1.000 Dokumente überschreitet. Ein Dokument, das kein parsbares PDF ist, wirft nicht; es wird zu einem Error-Ergebnis pro Dokument. Die $clock ist eine PSR-20 Psr\Clock\ClockInterface, die für die CRL-Aktualitätsentscheidung verwendet wird, sodass Urteile unter einer eingefrorenen Testuhr deterministisch sind.

final readonly class DocumentSignatureInput
{
public string $documentId;
public function __construct(
string $documentId,
public string $pdfData,
public array $trustedCerts = [],
)
}

Wirft oder scheitert mit: \InvalidArgumentException, wenn $documentId eine leere Zeichenkette ist. $trustedCerts ist eine Liste von PEM-kodierten Vertrauensanker-Zertifikaten.

final readonly class BatchValidationReport
{
public function __construct(
public array $documents,
public int $totalDocuments,
public int $totalSignatures,
public int $totalValid,
public int $totalInvalid,
public float $durationMs,
)
public function allValid(): bool
public function hasDocumentsWithoutSignatures(): bool
public function toJson(?CertPiiGuard $piiGuard = null): string
}

Wirft oder scheitert mit: toJson() wirft \JsonException, wenn die Kodierung fehlschlägt. allValid() ist nur dann true, wenn Signaturen vorhanden sind und keine davon nicht-gültig ist. Standardmäßig wendet toJson() einen datenschutzfreundlichen NextPDF\Enterprise\Signature\Eidas\CertPiiGuard an, der den Signierernamen, den Wurzelaussteller, den TSA-Namen und Ketten-Problemdiagnosen maskiert; siehe eIDAS-Vertrauensniveaus für die API des Guards.

DocumentValidationResult und DocumentValidationStatus

Abschnitt betitelt „DocumentValidationResult und DocumentValidationStatus“
final readonly class DocumentValidationResult
{
public function __construct(
public string $documentId,
public DocumentValidationStatus $status,
public array $signatures,
public int $validCount,
public int $invalidCount,
)
public function hasSignatures(): bool
public function totalSignatures(): int
}
enum DocumentValidationStatus: string
{
case AllValid = 'all_valid';
case SomeInvalid = 'some_invalid';
case AllInvalid = 'all_invalid';
case NoSignatures = 'no_signatures';
case Error = 'error';
}

Wirft oder scheitert mit: nichts. Unveränderliches Wertobjekt und backed enum.

SignatureValidationResult und SignatureValidationStatus

Abschnitt betitelt „SignatureValidationResult und SignatureValidationStatus“
final readonly class SignatureValidationResult
{
public function __construct(
public SignatureValidationStatus $status,
public CertChainStatus $certChain,
public TimestampStatus $timestamp,
public RevocationStatus $revocation,
public string $signer,
public string $level = '',
public string $subFilter = '',
public string $reason = '',
)
public function isValid(): bool
}
enum SignatureValidationStatus: string
{
case Valid = 'valid';
case Invalid = 'invalid';
case Indeterminate = 'indeterminate';
case Error = 'error';
}

Wirft oder scheitert mit: nichts. $signer ist der CMS-verifizierte Zertifikatsbetreff, wenn die Authentifizierung bestanden wurde, andernfalls die leere Zeichenkette. $level ist eine aus dem SubFilter abgeleitete Bezeichnung (zum Beispiel B-B für ETSI.CAdES.detached), keine AdES-Konformitätsbestimmung.

final readonly class CertChainStatus
{
public function __construct(
public bool $valid,
public bool $trusted,
public int $chainLength,
public string $rootIssuer,
public array $issues = [],
)
public function hasIssues(): bool
}

Wirft oder scheitert mit: nichts. $trusted wird nur bei einem bestätigten Treffer der Vertrauensanker-Mitgliedschaft gesetzt, niemals aus der Nicht-Leerheit der Ankerliste.

final readonly class RevocationStatus
{
public function __construct(
public RevocationCheckResult $ocspStatus,
public RevocationCheckResult $crlStatus,
public bool $isRevoked,
public ?DateTimeImmutable $revocationDate = null,
)
public static function unavailable(): self
public function hasConclusiveGood(): bool
}
enum RevocationCheckResult: string
{
case Good = 'good';
case Revoked = 'revoked';
case Unknown = 'unknown';
case Unavailable = 'unavailable';
}

Wirft oder scheitert mit: nichts von den gezeigten Membern. Die Klasse stellt außerdem nachweisgeprüfte statische Factories bereit (good(), revoked(), fromResults()), die \InvalidArgumentException werfen, wenn der behauptete Status dem OCSP/CRL-Nachweis widerspricht — ein gesperrtes Ergebnis kann niemals als nicht-gesperrt geprägt werden, oder umgekehrt. hasConclusiveGood() ist nur bei einem nicht-gesperrten Status true, bei dem mindestens eine Prüfung Good ist.

final readonly class TimestampStatus
{
public function __construct(
public bool $present,
public bool $valid,
public ?DateTimeImmutable $timestampTime = null,
public string $tsaName = '',
public array $issues = [],
)
public static function absent(): self
}

Wirft oder scheitert mit: nichts. In Stapelergebnissen ist dies immer der absent()-Zustand; siehe Randfälle & Fallstricke.

Validieren Sie ein Dokument und lesen Sie den Bericht. Dieses Beispiel verwendet ein unsigniertes PDF, sodass die Ausgabe deterministisch ist.

batch-quick-start.php
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Enterprise\Signature\BatchSignatureValidator;
use NextPDF\Enterprise\Signature\DocumentSignatureInput;
// A minimal, unsigned PDF: the validator reports it as no_signatures.
$unsigned = "%PDF-1.7\n1 0 obj\n<< /Type /Catalog >>\nendobj\ntrailer\n<< /Root 1 0 R >>\n%%EOF\n";
$validator = new BatchSignatureValidator();
try {
$report = $validator->validate([
new DocumentSignatureInput(documentId: 'doc-001', pdfData: $unsigned),
]);
} catch (\InvalidArgumentException $e) {
// Empty input list, or an empty documentId.
echo 'Rejected: ' . $e->getMessage() . "\n";
exit(1);
}
echo 'Documents: ' . $report->totalDocuments . "\n";
echo 'Signatures: ' . $report->totalSignatures . "\n";
foreach ($report->documents as $doc) {
echo $doc->documentId . ': ' . $doc->status->value . "\n";
}
echo 'All valid: ' . ($report->allValid() ? 'yes' : 'no') . "\n";
echo 'Unsigned documents: ' . ($report->hasDocumentsWithoutSignatures() ? 'yes' : 'no') . "\n";

Erwartete Ausgabe:

Documents: 1
Signatures: 0
doc-001: no_signatures
All valid: no
Unsigned documents: yes

Beachten Sie, dass allValid() hier no meldet: Es erfordert mindestens eine Signatur und keine nicht-gültigen Ergebnisse, sodass eine leere Signaturmenge niemals stillschweigend besteht.

Validieren Sie ein Verzeichnis signierter Verträge mit Sperr-Clients, Vertrauensankern, Stapel-Chunking und einem PII-geschützten JSON-Bericht.

batch-validate-contracts.php
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Enterprise\Security\Ltv\CrlFetcher;
use NextPDF\Enterprise\Security\Ltv\OcspClient;
use NextPDF\Enterprise\Security\Ltv\OcspResponseCache;
use NextPDF\Enterprise\Signature\BatchSignatureValidator;
use NextPDF\Enterprise\Signature\DocumentSignatureInput;
use NextPDF\Enterprise\Signature\SignatureValidationStatus;
// Any PSR-18 client works; Guzzle shown here.
$httpClient = new \GuzzleHttp\Client(['timeout' => 10]);
// Revocation clients make a conclusive non-revoked (Good) result reachable.
// Without them, every verdict tops out at Indeterminate. The response cache
// lets repeat signers across the batch resolve without extra network calls.
$validator = new BatchSignatureValidator(
ocspClient: new OcspClient($httpClient, cache: new OcspResponseCache()),
crlFetcher: new CrlFetcher($httpClient),
);
// Trust anchors are an input: the chain terminus must match one of these.
$anchors = [(string) file_get_contents('/etc/nextpdf/trust/enterprise-root.pem')];
$inputs = [];
foreach (glob('/var/contracts/signed/*.pdf') ?: [] as $path) {
$inputs[] = new DocumentSignatureInput(
documentId: basename($path),
pdfData: (string) file_get_contents($path),
trustedCerts: $anchors,
);
}
$exit = 0;
// One call is capped at 1,000 documents; chunk larger runs.
foreach (array_chunk($inputs, 1000) as $batch) {
try {
$report = $validator->validate($batch);
// Signer PII is redacted by default in the serialized report.
file_put_contents('/var/log/nextpdf/batch-report.jsonl', $report->toJson() . PHP_EOL, FILE_APPEND); // one JSON document per line
} catch (\InvalidArgumentException | \OverflowException $e) {
fwrite(STDERR, 'Batch rejected: ' . $e->getMessage() . "\n");
exit(2);
} catch (\JsonException $e) {
fwrite(STDERR, 'Report encoding failed: ' . $e->getMessage() . "\n");
exit(3);
}
foreach ($report->documents as $doc) {
foreach ($doc->signatures as $sig) {
if ($sig->status !== SignatureValidationStatus::Valid) {
$exit = 1;
fwrite(STDERR, sprintf(
"%s: %s (chain trusted: %s, revoked: %s)\n",
$doc->documentId,
$sig->status->value,
$sig->certChain->trusted ? 'yes' : 'no',
$sig->revocation->isRevoked ? 'yes' : 'no',
));
}
}
}
}
exit($exit);

Erwartete Ausgabe (stderr, für ein Dokument, dessen Sperrnachweis nicht verfügbar war; andere Zeilen variieren mit Ihren Eingaben):

contract-0042.pdf: indeterminate (chain trusted: yes, revoked: no)

Der JSON-Bericht serialisiert die Signierer-Identitätsfelder durch den standardmäßigen CertPiiGuard, sodass ein Eintrag pro Signatur so aussieht (Auszug, illustrativ):

{
"status": "indeterminate",
"signer": "[REDACTED]",
"level": "B-B",
"subFilter": "ETSI.CAdES.detached"
}
  • Eine leere Eingabeliste wirft \InvalidArgumentException; mehr als 1.000 Dokumente in einem Aufruf werfen \OverflowException. Teilen Sie größere Läufe in Chunks auf, wie im Produktionsbeispiel.
  • Upgrade von früheren Versionen: Ohne konfigurierten OCSP- oder CRL-Client ist die Sperrprüfung unavailable, sodass keine Signatur Valid erreichen kann. Frühere Versionen meldeten hier Valid; 3.1.0 meldet Indeterminate (siehe Konzeptioneller Überblick).
  • Zähler auf Dokumentebene sind streng: Nur Valid erhöht validCount. Invalid, Indeterminate und Error erhöhen allesamt invalidCount. Ein Dokument, dessen einzige Signatur Indeterminate ist, meldet daher all_invalid. Prüfen Sie den status pro Signatur, wenn die Unterscheidung von Bedeutung ist.
  • Die OCSP-Prüfung läuft nur, wenn die wiederhergestellte Kette mindestens zwei Zertifikate hat, weil die Abfrage den Aussteller benötigt. Eine Kette mit einem einzigen Zertifikat fällt auf den CRL-Pfad oder unavailable zurück.
  • crlStatus meldet in Stapelergebnissen niemals revoked. Der CRL-Fallback bezeugt nur die Aktualität der Liste; ein autoritatives gesperrtes Ergebnis kommt von OCSP.
  • timestamp ist in Stapelergebnissen immer absent(). Der Stapelvalidator wertet keine eingebetteten RFC 3161-Token aus; verwenden Sie Signaturprüfung für die Zeitstempelauswertung.
  • signer ist leer, wenn die Authentifizierung fehlschlug. Wenn gesetzt, ist es der Betreff-CN (oder O) des CMS-verifizierten Zertifikats — niemals die nicht authentifizierte /Name-Zeichenkette aus dem Signaturwörterbuch.
  • trustedCerts-Einträge müssen PEM-Zertifikate sein. Eine leere oder fehlerhafte Ankerliste liefert ein rein strukturelles Kettenurteil mit trusted: false, das das Urteil auf Indeterminate begrenzt.
  • Bytes, die nicht mit einem PDF-Header beginnen, erzeugen einen error-Status pro Dokument mit null Signaturen — keine Ausnahme.
  • toJson() schwärzt PII standardmäßig. Übergeben Sie new CertPiiGuard(disclosePii: true) nur dort, wo Sie eine dokumentierte rechtmäßige Grundlage zur Verarbeitung der Signiereridentität besitzen.
  • Fail-closed Urteilsproduzent. Valid erfordert all dies: verifizierte CMS-Authentifizierung über den /ByteRange-Digest, eine gültige Kette, bestätigte Vertrauensanker-Mitgliedschaft und einen eindeutigen nicht-gesperrten Status. Jede unbelegte Prüfung degradiert das Urteil; nichts steht standardmäßig auf Bestehen.
  • Kein Identity-Laundering. Der gemeldete Signierer ist der kryptografisch gebundene Zertifikatsbetreff. Der /Name-Eintrag ist angreifergesteuerte Metadaten und wird niemals als Signierer sichtbar gemacht.
  • Schwache Algorithmen bestehen niemals. Eine SHA-1-Signatur, die verifiziert, wird dennoch als nicht-gültig gemeldet; kryptografische Gültigkeit unter einem schwachen Digest wird nicht in ein vollständiges Bestehen umgewandelt.
  • Vertrauen ist eine Eingabe, keine Schlussfolgerung. Von Ihnen bereitgestellte Anker werden anhand des DER-SHA-256-Fingerabdrucks mit dem Endpunkt der Kette abgeglichen (RFC 5280 §6.1.1). Die Eigenkonsistenz einer Kette oder eine nicht-leere Ankerliste allein begründet niemals Vertrauen.
  • Sperrprüfung ist entscheidend. Eine verifizierte gesperrte Aussage erzwingt Invalid unabhängig von jeder anderen Prüfung; nicht verfügbarer Nachweis erzwingt Indeterminate.
  • Datenschutz durch Voreinstellung in der serialisierten Ausgabe. toJson() maskiert den Signierer-CN, den Wurzelaussteller-DN, den TSA-Namen und Ketten-Problemdiagnosen, sofern Sie sich nicht abmelden, und setzt damit die Datenminimierung nach GDPR Article 5(1)(c) an der Serialisierungsgrenze um.
  • Deterministische Zeit. Die CRL-Aktualitätsentscheidung liest die injizierte PSR-20-Uhr, nicht die Wanduhr des Hosts, sodass Sperrurteile im Test reproduzierbar sind.

NextPDF Enterprise implementiert Verhalten, das von ETSI EN 319 102-1 (dem dreiwertigen Validierungsstatusmodell und der Regel, dass nicht verfügbare Sperrinformationen zu INDETERMINATE führen), RFC 5652 §5.6 (verifiziererseitige Digest-Neuberechnung) und RFC 5280 §6.1 (Vertrauensanker als Eingaben der vertrauenden Partei zur Pfadvalidierung) geprägt ist. Unterstützung ist nicht Konformität, und Konformität ist nicht Zertifizierung. NextPDF hält keine Zertifizierung und gewährt keine. Der Stapelvalidator ist kein qualifizierter Validierungsdienst, und seine Status sind technische Urteile, die an der EN 319 102-1-Taxonomie ausgerichtet sind — keine TOTAL-PASSED/TOTAL-FAILED/INDETERMINATE-Indikationen aus einem vollständigen Validierungsprozess nach clause 5. Insbesondere führt der Stapelmodus keine Existenznachweis- oder Zeitstempelverarbeitung durch; die Verifikationsseite für einzelne Dokumente deckt diesen Bereich ab.

Der Stapelvalidator zieht keine FIPS-Modus-Richtlinie heran, und die Aktivierung des FIPS-Modus ändert die Stapelurteile nicht. Seine verifikationsseitige Algorithmusbehandlung ist fest und fail-closed: Schwache (SHA-1) Signaturen werden niemals als Valid gemeldet, mit oder ohne FIPS-Modus. Die Enterprise-FIPS-Modus-Richtlinie steuert die Signier-/Generierungsseite, dokumentiert in FIPS 140 — Deep Reference. Die FIPS 140-Unterstützung ist eine Fähigkeitsaussage, keine Validierungs- oder Zertifizierungsbehauptung.

  • validate() wirft \InvalidArgumentException für eine leere Liste und \OverflowException über 1.000 Dokumenten. Fehlerhafte Dokumente werfen niemals; sie erzeugen error-Ergebnisse pro Dokument.
  • Valid erfordert die Konjunktion: CMS kryptografisch verifiziert, Kette gültig, Vertrauensanker-Mitgliedschaft bestätigt und RevocationStatus::hasConclusiveGood() true.
  • Ein bestätigt-gesperrtes Zertifikat ist entscheidend: Das Urteil lautet Invalid unabhängig von allen anderen Nachweisen.
  • Beide Sperrprüfungen Unknown/Unavailable bedeutet Indeterminate, niemals Valid (3.1.0-Verschärfung, Auswirkung auf die Abwärtskompatibilität).
  • Eine authentifizierte, kettengültige Signatur ohne bestätigten Vertrauensanker ist Indeterminate — authentisch, Vertrauen unbelegt.
  • signer ist der CMS-verifizierte Betreff oder die leere Zeichenkette; der /Name-Eintrag wird niemals verwendet.
  • timestamp ist in Stapelergebnissen immer der abwesende Zustand.
  • validCount zählt nur Valid; alle anderen Status zählen in invalidCount, und der Dokumentstatus aggregiert sich aus diesen Zählern.
  • toJson() wendet den datenschutzfreundlichen CertPiiGuard an, sofern kein Guard explizit übergeben wird.
  • Die Berichtsummen sind exakte Summen über die Ergebnisse pro Dokument; durationMs ist die gemessene Wandzeit für den Stapel.

Das Modul Sicherheit / Signieren von NextPDF Core ist die Produzentenseite: Es erstellt CMS-Signaturen, wendet RFC 3161-Zeitstempel an und validiert Ketten und Sperrungen für das Material, das es zur Signierzeit einbettet. Core liefert keinen verifikationsseitigen Stapel-Orchestrator: keinen Multi-Dokument-Bericht, keine aggregierte Statustaxonomie, keine OCSP/CRL-Sperrurteile für Drittdokumente und keine PII-geschützte Berichtsserialisierung. Mit Core allein würden Sie jede Signatur selbst extrahieren und verifizieren und Ihr eigenes Reporting aufbauen. Die Enterprise-Verifikationsseite für einzelne Dokumente (Signaturprüfung) und dieser Stapel-Orchestrator stellen diese Schicht bereit.

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.