Ga naar inhoud
getnextpdf.com

Enterprise editie

eIDAS-betrouwbaarheidsniveaus

NextPDF Enterprise zet EU-trusted-list-bewijs om in een expliciet eIDAS Level of Assurance (LoA). De NextPDF\Enterprise\Security\Eidas\LoaMapping-service classificeert één trust-service-entry als Low, Substantial of High. Ze retourneert een LoaAssertion die het niveau plus machineleesbare reason codes draagt. Je workflow kan op betrouwbaarheid gaten — “vereis High” — en de redenen als audit-bewijs archiveren. Een bijbehorende guard, CertPiiGuard, redigeert de identiteitsvelden van de ondertekenaar voordat auditrecords het proces verlaten.

Twee grenzen kaderen deze mogelijkheid eerlijk in. Ten eerste behoort kwalificatie altijd toe aan de trust service provider (TSP) onder toezicht van de lidstaat. NextPDF beweert een classificatie over gepubliceerd bewijs; het verleent, kent of certificeert nooit kwalificatie. Ten tweede behandelt deze pagina uitsluitend LoA-bewering en -mapping. De structurele PAdES-policy eidasQualified(), inclusief de bijbehorende pass/fail-criteria, is gedocumenteerd in Validatie.

Deze mogelijkheid wordt geleverd in NextPDF Enterprise (nextpdf/enterprise) en wordt geactiveerd met een licentie-envelop op Enterprise-niveau. Een deployment zonder die entitlement laadt de klassen van de mogelijkheid niet. Vergelijk edities en verkrijg een licentie.

Terminal window
composer require nextpdf/enterprise

Het nextpdf/premium metapackage lost ook het Enterprise-package op. Activatie gebruikt je Enterprise-licentie-envelop; zie Licenties en activatie. De eIDAS-klassen hebben geen PHP-extensie nodig buiten de engine-baseline. Ze autoloaden onder NextPDF\Enterprise\Security\Eidas en NextPDF\Enterprise\Signature\Eidas.

Regulation (EU) No 910/2014 (eIDAS) definieert drie betrouwbaarheidsniveaus: low, substantial en high (Article 8(1)). Elk niveau drukt een mate van vertrouwen in een geclaimde identiteit uit. Niveau high voegt controles toe waarvan het doel is om identiteitsmisbruik of -wijziging te voorkomen — niet slechts te verminderen (Article 8(2)(c)). Article 8 definieert deze niveaus voor elektronische-identificatieschema’s. NextPDF hergebruikt hetzelfde vocabulaire om het trust-service-bewijs achter een ondertekeningscertificaat te classificeren. Dat hergebruik is een engineeringsconventie voor policy-gating en audit, geen juridische gelijkstelling.

De LoaLevel-enum modelleert de drie niveaus. De achterliggende waarden zijn de eIDAS-LoA-URI’s in plaats van kale labels, zodat een gepersisteerde bewering de volledige identificator draagt. rank() geeft een totale ordening (Low = 1, Substantial = 2, High = 3), en meetsOrExceeds() vergelijkt met een vereiste ondergrens.

LoaMapping berekent een niveau uit één trusted-list-entry — een TspService uit het Enterprise-trusted-list-subsysteem (NextPDF\Enterprise\Security\Tsl). De mapping is deterministisch:

Trusted-list-bewijsNiveauReason codes
Servicestatus is niet grantedLowservice_not_granted
Servicetype is niet CA/QCLowservice_not_qualified_ca
Granted CA/QC met QCWithQSCD en zonder QCNoQSCDHighca_qc_with_qscd plus esig_or_eseal of qc_default
Granted CA/QC in overige gevallenSubstantialca_qc_no_qscd_or_unspecified

De QSCD-qualifier (qualified signature creation device) is het scharnierpunt. Onder Article 3(12) vereist een gekwalificeerde elektronische handtekening zowel een gekwalificeerd certificaat als een gekwalificeerd aanmaakapparaat. Een trusted-list-verklaring dat certificaten op een QSCD worden beheerd, is daarom het bewijs dat een High-bewering ondersteunt. Zonder die verklaring ondersteunt een granted gekwalificeerde CA nog steeds Substantial, nooit High.

Het resultaat is een LoaAssertion: het niveau plus een lijst met reason codes. De redenen laten een auditconsument de classificatie later opnieuw afleiden uit hetzelfde bewijs. Downstream policy-evaluators kunnen de bewering vastleggen naast een handtekeningvalidatie-uitkomst.

Nog één onderdeel wordt in deze module geleverd: CertPiiGuard. Wanneer validatie-artefacten in JSON-auditbundels worden geserialiseerd, draagt het ondertekenaarscertificaat persoonsgegevens — de Subject CN, e-mailattributen en het serialNumber-attribuut, dat een nationaal identificatienummer voor natuurlijke personen kan coderen. GDPR Article 5(1)(c) vereist dat verwerking beperkt blijft tot wat noodzakelijk is. De guard redigeert die velden daarom standaard, waarbij waarden worden vervangen door [REDACTED] terwijl de structurele envelop (organisatie, land, keten- en statusvelden) behouden blijft. Consumenten kunnen nog steeds verifiëren of een handtekening geslaagd is zonder te leren wie heeft ondertekend.

De dragende beslissing is het scheiden van de betrouwbaarheidsbewering van het validatieoordeel. Handtekeningvalidatie eindigt, volgens ETSI EN 319 102-1, in een statusindicatie — TOTAL-PASSED, TOTAL-FAILED of INDETERMINATE — en dat oordeel behoort tot de validatielaag. LoA-mapping is een aparte, herhaalbare classificatie over trusted-list-bewijs, met reason codes in plaats van een kaal label. Dit voorkomt dat NextPDF ooit een betrouwbaarheidsclaim als een validatieresultaat presenteert, of een validatieresultaat als een kwalificatietoekenning. Het maakt de mapping ook conservatief van constructie: ontbrekend of dubbelzinnig bewijs verlaagt het niveau, verhoogt het nooit.

Ontwerpachtergrond: Gekwalificeerde handtekeningen, uitgelegd.

Alle onderstaande symbolen zijn publieke API in nextpdf/enterprise 3.1.0.

enum LoaLevel: string
{
case Low = 'http://eidas.europa.eu/LoA/low';
case Substantial = 'http://eidas.europa.eu/LoA/substantial';
case High = 'http://eidas.europa.eu/LoA/high';
public function rank(): int
public function meetsOrExceeds(self $required): bool
}

Gooit of faalt met: niets vanuit rank() of meetsOrExceeds(). Native enum-constructie via LoaLevel::from() gooit \ValueError bij een niet-herkende URI; LoaLevel::tryFrom() retourneert in plaats daarvan null.

final class LoaMapping
{
public function loaForService(TspService $service): LoaAssertion
}

Gooit of faalt met: niets. De methode is totaal — elke TspService-invoer levert een LoaAssertion op.

De invoer-DTO’s NextPDF\Enterprise\Security\Tsl\TspService en NextPDF\Enterprise\Security\Tsl\TspServiceQualifier zijn stabiele publieke DTO’s (@api). De mapping raadpleegt TspService::STATUS_GRANTED, TspService::TYPE_CA_QC en de qualifier-constanten TspServiceQualifier::QSCD_STATEMENT (QCWithQSCD), TspServiceQualifier::NO_QSCD (QCNoQSCD), TspServiceQualifier::FOR_ESIG en TspServiceQualifier::FOR_ESEAL.

final readonly class LoaAssertion
{
/**
* @param list<non-empty-string> $reasons Machine-readable reason codes for the assertion.
*/
public function __construct(
public LoaLevel $level,
public array $reasons,
) {}
}

Gooit of faalt met: niets. Immutable value object.

final readonly class CertPiiGuard
{
public function __construct(
private bool $disclosePii = false,
) {}
public function disclosesPii(): bool
public function guardSignerCommonName(string $signer): string
public function guardDistinguishedName(string $dn): string
public function guardTsaName(string $tsaName): string
public function guardRootIssuer(string $issuer): string
public function guardChainIssue(string $issue): string
}

Gooit of faalt met: niets. Guards zijn pure string-transformaties. Bij een DN-component die niet met zekerheid getokeniseerd kan worden, faalt de guard closed en klapt de component samen tot [REDACTED] in plaats van een deels gemaskeerde waarde uit te zenden.

Parse een LoA-URI en vergelijk die met een vereiste ondergrens.

loa-quick-start.php
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Enterprise\Security\Eidas\LoaLevel;
// A LoA URI as persisted in an audit record or received from a peer system.
$uri = 'http://eidas.europa.eu/LoA/substantial';
try {
$level = LoaLevel::from($uri);
} catch (\ValueError $e) {
// Unknown URI: refuse to classify. Never guess an assurance level.
echo "Unrecognized LoA URI: {$uri}\n";
exit(1);
}
echo 'Level: ' . $level->name . ' (rank ' . $level->rank() . ")\n";
echo 'Meets substantial: ' . ($level->meetsOrExceeds(LoaLevel::Substantial) ? 'yes' : 'no') . "\n";
echo 'Meets high: ' . ($level->meetsOrExceeds(LoaLevel::High) ? 'yes' : 'no') . "\n";

Verwachte uitvoer:

Level: Substantial (rank 2)
Meets substantial: yes
Meets high: no

Classificeer een trusted-list-entry, gate op een vereist niveau, en zend een geredigeerd auditrecord uit.

loa-audit-gate.php
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Enterprise\Security\Eidas\LoaLevel;
use NextPDF\Enterprise\Security\Eidas\LoaMapping;
use NextPDF\Enterprise\Security\Tsl\TspService;
use NextPDF\Enterprise\Security\Tsl\TspServiceQualifier;
use NextPDF\Enterprise\Signature\Eidas\CertPiiGuard;
// Normally produced by the Enterprise trusted-list subsystem from a
// member-state TSL; constructed inline here for a self-contained example.
$caPem = (string) file_get_contents(__DIR__ . '/example-qc-ca.pem');
$service = new TspService(
tspName: 'Example Qualified TSP',
serviceName: 'Example Qualified CA G2',
serviceTypeIdentifier: TspService::TYPE_CA_QC,
serviceStatus: TspService::STATUS_GRANTED,
statusStartingTime: '2024-01-01T00:00:00Z',
serviceCertificatePem: $caPem,
qualifiers: [
new TspServiceQualifier(qualifierUri: TspServiceQualifier::QSCD_STATEMENT),
new TspServiceQualifier(qualifierUri: TspServiceQualifier::FOR_ESIG),
],
additionalServiceInformation: [],
);
try {
// Required floor from deployment configuration; defaults to High.
$required = LoaLevel::from(getenv('LOA_REQUIRED') ?: LoaLevel::High->value);
} catch (\ValueError $e) {
echo "Invalid LOA_REQUIRED URI; refusing to continue.\n";
exit(1);
}
$mapping = new LoaMapping();
$assertion = $mapping->loaForService($service);
// Privacy by default: signer identity fields are redacted in audit output.
$guard = new CertPiiGuard();
$audit = [
'loa' => $assertion->level->value,
'reasons' => $assertion->reasons,
'meets_required' => $assertion->level->meetsOrExceeds($required),
'signer' => $guard->guardSignerCommonName('CN=Jane Example, O=Example Corp, C=DE'),
];
echo json_encode($audit, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n";

Verwachte uitvoer:

{
"loa": "http://eidas.europa.eu/LoA/high",
"reasons": [
"ca_qc_with_qscd",
"esig_or_eseal"
],
"meets_required": true,
"signer": "CN=[REDACTED], O=Example Corp, C=DE"
}
  • LoaLevel::from() gooit \ValueError bij onbekende URI’s. Gebruik LoaLevel::tryFrom() waar null-afhandeling de voorkeur heeft.
  • Tegenstrijdig apparaatbewijs blijft conservatief. Een service die zowel QCWithQSCD als QCNoQSCD draagt, mapt naar Substantial, niet High.
  • Een granted CA/QC-service zonder qualifiers mapt naar Substantial met reden ca_qc_no_qscd_or_unspecified — gekwalificeerd van standaard, apparaat onbewezen.
  • Qualifier-URI’s buiten de gevolgde set beïnvloeden de classificatie niet. Onbekende of toekomstige qualifiers verhogen het niveau nooit.
  • De mapping leest alleen de huidige servicestatus. Ze evalueert geen statusStartingTime-historie; punt-in-tijd-vensters behoren tot de validatielaag.
  • Persisteer de achterliggende URI van de enum, niet het rank()-getal. Ranks bestaan alleen voor vergelijking.
  • CertPiiGuard klapt een kale naam zonder = volledig samen tot [REDACTED]; lege strings passeren alle guards ongewijzigd.
  • Legacy OpenSSL-DN’s met schuine strepen als scheidingsteken worden gedetecteerd en structureel gemaskeerd. Een / binnen een RFC 4514-waarde wordt als inhoud behandeld, niet als scheidingsteken.
  • Niet-PII-DN-attributen (O, OU, C, ST, L) worden behouden, zodat jurisdictieredenering de redactie overleeft.
  • Privacy standaard. De guard-constructor defaultt naar disclosePii: false. Construeer new CertPiiGuard(disclosePii: true) alleen daar waar je een gedocumenteerde wettelijke grondslag hebt voor het verwerken van de ondertekenaaridentiteit. Dit implementeert GDPR Article 5(1)(c) dataminimalisatie op de serialisatiegrens.
  • Fail-closed-redactie. Wanneer een DN-component niet met zekerheid getokeniseerd kan worden, klapt de hele component samen tot [REDACTED]. Een privacycontrole faalt nooit open.
  • Deterministische uitvoer. Guards gebruiken pure string-verwerking — geen klokken, geen willekeur — zodat gemaskeerde uitvoer byte-stabiel is voor identieke invoer. Stabiele uitvoer houdt audit-diffs betekenisvol.
  • Redactie is geen encryptie. [REDACTED] verwijdert de waarde uit het record. Als je de identiteit herstelbaar nodig hebt, sla die dan apart op onder een eigen wettelijke grondslag en toegangscontrole.
  • Garbage in, garbage out. Een LoaAssertion is slechts zo betrouwbaar als het trusted-list-bewijs erachter. Verwerf en signature-check trusted lists via het Enterprise-trusted-list-subsysteem voordat je entries aan de mapping voedt.

NextPDF Enterprise implementeert gedrag dat is geïnformeerd door Regulation (EU) No 910/2014 Article 8 (betrouwbaarheidsniveaus) en Article 3(12) (elementen van een gekwalificeerde elektronische handtekening), en door het ETSI-trusted-list-qualifier-vocabulaire. Ondersteuning is geen conformiteit, en conformiteit is geen certificering. NextPDF houdt geen certificering en verleent er geen. NextPDF is geen gekwalificeerde trust service provider, geen conformiteitsbeoordelingsinstantie en geen toezichthoudende instantie. Een LoaAssertion is een softwareclassificatie van gepubliceerd bewijs. Het is geen juridische vaststelling van kwalificatie of van betrouwbaarheid, en het kan een handtekening niet gekwalificeerd maken.

Regulation (EU) 2024/1183 (eIDAS 2) blijft verwijzen naar de Article 8-niveaus en vereist dat European Digital Identity Wallets op betrouwbaarheidsniveau high worden geleverd. Deze pagina citeert dat als regelgevende context; NextPDF doet geen wallet-gerelateerde functionaliteitsclaim.

Of een specifieke handtekening voldoet aan een structurele eIDAS-georiënteerde policy is een aparte vraag, beantwoord door de validatiemodule; zie Validatie.

De eIDAS-LoA-klassen voeren geen cryptografische operaties uit — geen hashing, geen handtekeningverificatie, geen willekeur. De Enterprise-FIPS-modus-policy gate’t cryptografische keuzes, dus heeft ze in deze module niets te gaten. Het inschakelen van FIPS-modus verandert de LoA-mapping of het PII-guard-gedrag niet. Cryptografische verificatie van handtekeningen en trusted lists wordt beheerd door de verificatie- en beveiligingsmodules, waar FIPS-modus-policy van toepassing is.

  • LoaMapping::loaForService() is totaal en deterministisch. Elke TspService levert een LoaAssertion op; de methode gooit nooit en raadpleegt geen klok, netwerk of globale state.
  • Classificatie is conservatief. Ontbrekend, onbekend of tegenstrijdig bewijs verlaagt het niveau; niets verhoogt het behalve expliciet granted-CA/QC-met-QSCD-bewijs.
  • Reason codes zijn machineleesbaar en stabiel: service_not_granted, service_not_qualified_ca, ca_qc_with_qscd, esig_or_eseal, qc_default, ca_qc_no_qscd_or_unspecified.
  • Niveauvolgorde ligt vast: Low < Substantial < High, blootgelegd via rank() en meetsOrExceeds().
  • CertPiiGuard defaultt naar redactie en faalt closed bij tokenisatietwijfel. Met disclosePii: true retourneert elke guard zijn invoer verbatim.
  • Guard-uitvoer is byte-stabiel voor identieke invoer.

NextPDF Core verifieert PDF-handtekeningen cryptografisch en faalt closed op gebroken bewijs. Core heeft geen EU-trusted-list-model, geen LoaLevel-vocabulaire, geen LoA-mapping en geen eIDAS-laag-PII-guard voor audit-serialisatie. Op Core alleen moet je zelf betrouwbaarheidsclassificaties afleiden uit trust-data die je onderhoudt, en je eigen redactie toepassen voordat auditrecords het proces verlaten.

Deze pagina documenteert uitsluitend extern waarneembaar gedrag en het ondersteunde publieke API-oppervlak. Interne namespace-paden, helperklassen, mechanismetabellen, runbook-bestandsnamen en ticketprefixen vallen buiten de scope.