Ga naar inhoud
getnextpdf.com

Een handtekening correct valideren

Spec: RFC 5280, §6Spec: RFC 6960Spec: RFC 5652

“De handtekening is geldig” betekent meestal dat er maar één ding is gecontroleerd: de wiskunde klopte. Een correcte validatie controleert minstens vijf onafhankelijke zaken, en elk daarvan kan zo mislukken dat een groen vinkje betekenisloos wordt. Deze pagina zet de volledige reeks controles uiteen en legt uit waarom een gedeeltelijk antwoord gevaarlijk is.

Eén enkele boolean is de gevaarlijkste uitvoer binnen dit onderwerp. Hij verleidt een lezer ertoe “geldig” te zien als “betrouwbaar”, terwijl “geldig” alleen kan betekenen dat de bytes niet zijn gewijzigd ten opzichte van een handtekening die hoort bij een sleutel uit een certificaat dat drie jaar geleden is verlopen, vorige maand is ingetrokken en naar geen enkele autoriteit verwijst die u herkent. Elk daarvan is een afzonderlijke controle. Software die één boolean rapporteert, heeft stilzwijgend gekozen welke controles ertoe deden, en heeft dat namens u gedaan. In een gereguleerde of contractuele context is “de tool zei geldig” geen verweer als die tool alleen de goedkoopste eigenschap heeft geverifieerd.

Een volledige validatie beantwoordt vijf afzonderlijke vragen. Ze zijn onafhankelijk — als één slaagt, zegt dat niets over de andere:

  1. Integriteit — leveren de ondertekende bytes nog steeds dezelfde hash op als wat de handtekening dekt? (Herbereken de byte-range-digest; vergelijk.)
  2. Authenticiteit — verifieert de cryptografische handtekening met de publieke sleutel in het ondertekeningscertificaat, over de ondertekende attributen?
  3. Certificaatpad — verwijst dat certificaat via een keten naar een trust anchor die u hebt gekozen, waarbij elke schakel geldig is?
  4. Tijd — viel het certificaat op het relevante tijdstip binnen het geldigheidsvenster ervan, en is dat tijdstip vertrouwd in plaats van zelf opgegeven?
  5. Intrekking — was het certificaat op dat tijdstip niet ingetrokken, aan de hand van bewijs (OCSP/CRL) dat u daadwerkelijk kunt verkrijgen of dat is ingesloten?

Een oordeel “geldig” waarvoor niet alle vijf controles zijn uitgevoerd, is een onvolledig antwoord dat eruitziet als een volledig antwoord.

Het standpunt van NextPDF is dat elke vraag op zichzelf staat en expliciet moet worden beantwoord. Geen vraag verdwijnt in één optimistische vlag, en geen vraag wordt stilzwijgend overgeslagen omdat een controle ongelegen uitkwam. Dit wordt afgedwongen door tests. Daarom is deze pagina gemarkeerd als test-backed in plaats van standard-backed: het gedrag wordt geborgd door de testsuite, niet alleen beargumenteerd vanuit een clausule.

Integriteit en authenticiteit worden van begin tot eind getest. Met een bekend certificaat wordt een echte structuur met ondertekende attributen ondertekend, en de testsuite verifieert de handtekening met de bijbehorende publieke sleutel, over meerdere tijdvectoren. Een wijziging die de canonieke structuur breekt, breekt dus de test. Certificaatpadvalidatie wordt afgedekt door tests die opzettelijk een handtekeningbyte manipuleren en vaststellen dat het resultaat niet geldig is, met een gestructureerde reden — geen weggegooide uitzondering, maar een expliciet vastgelegde fout. Verificatie van het tijdstempeltoken is opgedeeld in afzonderlijke stappen — decoderen, ondertekenaarsinformatie, ondertekende attributen, berichtdigest, certificaatbinding, sleutelgebruik, handtekening, produced-at — en elke stap wordt afzonderlijk getest, zodat “het tijdstempel is geverifieerd” betekent dat elke stap is geverifieerd. Voor een handtekeningtijdstempel is een van die stappen niet optioneel en niet generiek: de message imprint van het token moet zich binden aan de handtekening die het beweert te dekken — de hash in het token moet gelijk zijn aan de hash van de eigen handtekeningwaarde van de ondertekenaar, anders bevestigt het token andere bytes. NextPDF stelt dit beschikbaar als een specifieke verifySignatureTimestamp-controle die de handtekeningwaarde als verplichte invoer aanneemt, zodat deze niet kan worden overgeslagen, en die fail-closed afwijst bij een lege invoer, een niet-herkend of zwak (SHA-1) imprint-algoritme, een misvormde imprint of een hash die niet overeenkomt. Een soft-failure bij intrekking (een onbereikbare responder) wordt, in de code en in de tests, onderscheiden van een definitieve “ingetrokken”. De twee worden nooit teruggebracht tot hetzelfde antwoord.

  1. IntegrityRecompute the byte-range digest and compare it to the value the signature covers.
  2. AuthenticityVerify the cryptographic signature against the certificate’s public key, over the signed attributes — not the raw content.
  3. Certificate pathBuild and validate the chain to a trust anchor you chose; every link’s signature, validity, and constraints must hold.
  4. TimeConfirm the certificate was valid at the relevant instant, and that the instant is trusted time, not the signer’s clock.
  5. RevocationConfirm the certificate was not revoked at that time, using obtainable or embedded OCSP/CRL evidence.
De vijf onafhankelijke vragen die een correcte PDF-handtekeningvalidatie beantwoordt, op volgorde. Elke is afzonderlijk: als één slaagt, zegt dat niets over de andere, en als er één wordt overgeslagen, wordt het totaalresultaat onvolledig.

Het leerpunt is geen API-aanroep. Het zijn de vragen die u moet kunnen beantwoorden voordat u handelt op basis van een resultaat. Beschouw dit als de checklist waaraan u in een review wordt gehouden.

<?php
declare(strict_types=1);
// A correct validation produces a structured outcome, not one boolean.
// Before you trust a signature, you must be able to answer ALL of these:
//
// integrity : Does the byte-range digest still match? (tamper check)
// authenticity: Does the signature verify over the SIGNED ATTRIBUTES,
// not just the content?
// path : Does the certificate chain to a trust anchor YOU chose,
// with every link valid at the relevant time?
// time : Is the relevant time TRUSTED (a timestamp), or merely the
// signer's self-asserted clock?
// revocation : Was the certificate not revoked at that time, by evidence
// you obtained or that the document embedded?
//
// "valid: true" without an answer to every line above is an incomplete
// result. A path-validation outcome carries a `valid` flag AND a structured
// `reasons` list precisely so a failure says WHY — never a bare false.

Als het antwoord op een regel “ik weet het niet” is, is de eerlijke status niet “geldig”. Het is “nog niet vastgesteld” — en die twee als hetzelfde behandelen is de fout die deze pagina probeert te voorkomen.

De valkuil is “cryptografisch geldig” gelijkstellen aan “betrouwbaar”. Integriteit en authenticiteit samen bewijzen alleen dat deze bytes zijn ondertekend door de houder van deze sleutel. Ze zeggen niets over de vraag of het certificaat bij die sleutel vertrouwd, geldig of niet-ingetrokken was. Een document dat is ondertekend met een zelfgegenereerd certificaat kan “cryptografisch geldig” zijn en toch niets waard. De omgekeerde valkuil is een onbepaalde intrekkingscontrole (responder offline) behandelen als een succes — of als een fout. Het is geen van beide. Het is onbekend, en een correcte validator rapporteert het als onbekend in plaats van naar een van beide kanten te gokken. Een groen vinkje dat verbergt welke van de vijf controles daadwerkelijk zijn uitgevoerd, is geen validatie-uitkomst. Het is een beslissing die iemand anders namens u heeft genomen.

NextPDF voert de structurele en cryptografische controles uit en test deze. Het kiest uw trust anchors niet en geeft geen garantie over het beleid daarbovenop. Welke certificaten u vertrouwt, is een deployment-beslissing die de engine niet kan nemen. Een keten die uitkomt bij een anchor die u niet had moeten vertrouwen, is nog steeds een validatie waarop u niet kunt vertrouwen. Intrekkingsbewijs kan alleen worden gecontroleerd als het verkrijgbaar of ingesloten is. Een offline responder levert “onbepaald” op, en dat omzetten in een oordeel is een beleidskeuze, geen beslissing van de engine. Deze pagina beschrijft de reeks controles, niet de juridische toereikendheid. Of een gevalideerde handtekening een bepaald rechtsgevolg heeft, hangt af van het certificaat, de ondertekenaar, het rechtsgebied en de verplichting. Hoe ingesloten bewijs deze controles in de loop van de tijd beantwoordbaar houdt, wordt behandeld in Long-term validation; het byte-range-mechanisme achter de integriteitscontrole staat in How signatures sit in a PDF.

Beschikbaarheid per niveau van het validatieoppervlak:

Signature validation checks — edition availability
EditionAvailability
Core

Integriteit en authenticiteit over ondertekende attributen, plus RFC 5280 §6 certificaatpadvalidatie tegen een opgegeven trust anchor.

Pro

Voegt RFC 3161 verificatie van het tijdstempeltoken toe — de vraag naar vertrouwde tijd, opgesplitst in onafhankelijk gecontroleerde stappen.

Enterprise

Voegt intrekkingsevaluatie (OCSP/CRL) en validatie tegen ingesloten langetermijnmateriaal toe, waarbij onbepaalde uitkomsten worden onderscheiden van definitieve.

  • Integriteitscontrole — het opnieuw berekenen van de byte-range-digest en deze vergelijken met de waarde die de handtekening dekt.
  • Authenticiteitscontrole — het verifiëren van de cryptografische handtekening met de publieke sleutel van het ondertekeningscertificaat, over de ondertekende attributen.
  • Ondertekende attributen — de geauthenticeerde CMS-attributen (content-type, message-digest, signing-time, signing-certificate-v2) waarover de handtekening daadwerkelijk wordt berekend.
  • Certificaatpadvalidatie — het opbouwen en controleren van de keten van het ondertekeningscertificaat tot een gekozen trust anchor (RFC 5280 §6).
  • Trust anchor — een certificeringsautoriteit die u hebt besloten te vertrouwen; de wortel van een aanvaardbaar pad.
  • Intrekkingscontrole — het bepalen of een certificaat op het relevante tijdstip was ingetrokken, via OCSP of een CRL.
  • Onbepaald — een intrekkingsuitkomst die noch “goed” noch “ingetrokken” is omdat het bewijs niet kon worden verkregen; geen succes en geen fout.
  • Imprint-binding (handtekeningtijdstempel) — de controle dat de message imprint van een handtekeningtijdstempel gelijk is aan de hash van de SignerInfo-handtekeningwaarde van de ondertekenaar die het dekt, zodat het tijdstempel aantoonbaar van toepassing is op die handtekening in plaats van op andere bytes.