HotPDF verifiserer ML-DSA-44-, ML-DSA-65-, ML-DSA-87-, Ed25519- og Ed448-CMS-signaturer i innlastede PDF-dokumenter, og den signerer gjennom pluggbare leverandører slik at den private nøkkelen aldri trenger å bo inne i Delphi-prosessen din. Den andre halvdelen er den delen de fleste team trenger først. En maskinvare-token, en fjernsigneringstjeneste og et nasjonalt eID-kort nekter alle å utlevere en nøkkel, og inntil signerings-pipelinen er skilt fra nøkkellageret, kan ingen av dem brukes i det hele tatt
Delingen er poenget med THPDFSignatureProvider. HotPDF beholder delene den bør eie — parsing av CMS, bygging av SignedData, utlegg av /ByteRange — og delegerer den ene operasjonen den ikke kan eie, som er å gjøre et digest om til en signatur med en nøkkel den ikke har lov til å se. Alt nedenfor følger av den delingen
Hvorfor feiler en gyldig ML-DSA-signatur å verifisere?
Fordi HotPDF nekter ML-DSA på et innlastet dokument som ikke erklærer utvidelsen for det. ML-DSA — det gittersignatur-skjemaet standardisert som FIPS 204, og grunnen til at folk sier «post-kvantum-PDF» — har ingen ISO 32000-2-registrering ennå. En PDF som bærer en slik algoritme, bruker en algoritme basisstandarden ikke navngir, og en fil som i stillhet bruker en unavngitt algoritme, er en fil hvis dom ingen andre kan reprodusere
Så HotPDF gjør kravet eksplisitt. EnsureMLDSAExtensions hever dokumentet til PDF 2.0 der det er tillatt, og skriver /Extensions /HotPDF << /BaseVersion /2.0 /ExtensionLevel 1 >> inn i katalogen. På lesesiden rapporterer LoadedDocumentDeclaresMLDSAExtension om den erklæringen overlevde, og VerifyLoadedSignatureWithOptions anvender den samme testen før den vil hedre Options.AllowMLDSA. Sett flagget på et uerklært dokument og det forblir av — opsjonen kan løsne policy, aldri strukturkravet
var
Pdf: THotPDF;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.FileName := 'contract-pq.pdf';
Pdf.BeginDoc;
Pdf.CurrentPage.SetFont('Arial', [], 11);
Pdf.CurrentPage.TextOut(50, 720, 0, 'Supply agreement 2026-114');
Pdf.EnsureMLDSAExtensions; // declare before the signature is written
Pdf.EndDoc;
finally
Pdf.Free;
end;
end;
Kall det før lagring, ikke etter. Erklæringen er del av det signerte byte-intervallet, og en katalog lappet etterpå er enten en usignert endring av en signert fil eller en ny revisjon som en validator vil rapportere som en modifikasjon
Tre algoritmefamilier, ett verifiseringsinngangspunkt
Alle tre familiene ankommer gjennom VerifyLoadedSignatureWithOptions, som tar en signaturindeks, kildestrømmen, en THPDFCMSVerifyOptions-post og en ut-parameter for signaturdetaljene. Posten har nøyaktig tre felt, og hvert svarer på et spørsmål som tidligere krevde ombygging
SignatureProvider bytter ut din egen leverandør mot den innebygde plattformen. OpenSSLLibraryPath velger et OpenSSL 3-bibliotek, som er det som leverer ren-modus Ed25519- og Ed448-verifisering som Windows CNG ikke tilbyr overalt. AllowMLDSA melder seg på gittalgoritmene, underlagt utvidelsessjekken ovenfor. Den eksakte algoritme-OID-en som ble gjenkjent, kommer tilbake i THPDFSignatureInfo.SignatureAlgorithmOID, slik at en revisjonslogg kan registrere hva som ble verifisert snarere enn hva som ble bedt om
var
Opts: THPDFCMSVerifyOptions;
Info: THPDFSignatureInfo;
Status: THPDFSignatureVerifyStatus;
Src: TFileStream;
begin
Opts := THPDFCMSVerifyOptions.Default;
Opts.OpenSSLLibraryPath := 'C:\openssl3\libcrypto-3-x64.dll';
Opts.AllowMLDSA := Pdf.LoadedDocumentDeclaresMLDSAExtension;
Src := TFileStream.Create('contract-pq.pdf', fmOpenRead or fmShareDenyWrite);
try
Status := Pdf.VerifyLoadedSignatureWithOptions(0, Src, Opts, Info);
if Status = svValid then
Memo1.Lines.Add('signed with OID ' + string(Info.SignatureAlgorithmOID));
finally
Src.Free;
end;
end;
Ed25519 og Ed448 trenger ingen utvidelseserklæring, fordi ISO 32000-2 allerede innrømmer dem. De trenger derimot en leverandør som implementerer dem, noe som på de fleste Windows-utrullinger betyr å peke OpenSSLLibraryPath mot et bibliotek du leverer og kontrollerer snarere enn mot det som tilfeldigvis finnes på maskinen
Hva lover en signeringsleverandør faktisk?
En leverandør lover én ting: gitt en forespørsel, returner en status og, ved signering, bytes. THPDFSignatureProviderRequest bærer algoritmen og dens OID, digest-OID-en, PSS-saltlengden, hvorvidt inndata er en melding eller et allerede beregnet digest, selve indataene, den offentlige nøkkelen eller sertifikatet, en nøkkelidentifikator og en operasjonsidentifikator. Ingenting i den posten er HotPDF-spesifikt — det er ordforrådet en token-driver eller en signeringstjeneste allerede snakker
Tre implementasjoner levereres med biblioteket. THPDFCallbackSignatureProvider pakker inn anonyme metoder, som er den korteste veien fra en eksisterende intern signeringrutine til en fungerende PDF-signatur. THPDFRemoteSignatureProvider pakker inn en transport-callback med en ny grense for nytt forsøk, et kanselleringsregister og grenser for inndata- og signaturstørrelse, slik at en fast HSM ikke kan bli en fast applikasjon. THPDFPKCS11SignatureProvider serialiserer RSA-operasjoner mot en oppringer-eid, allerede autentisert PKCS#11-økt og privatnøkkel-håndtak — HotPDF logger aldri inn, ser aldri en PIN, og lukker aldri en økt den ikke åpnet
var
Provider: THPDFRemoteSignatureProvider;
begin
Provider := THPDFRemoteSignatureProvider.Create(
function(const Req: THPDFSignatureProviderRequest; Attempt: Integer;
out Signature: TBytes): THPDFSignatureProviderStatus
begin
// POST Req.Input to the signing service; Req.KeyIdentifier selects the key
if PostToSigningService(Req.KeyIdentifier, Req.Input, Signature) then
Result := spsValid
else
Result := spsProviderError;
end,
3, // RetryLimit
1048576, // MaxInputBytes
65536); // MaxSignatureBytes
try
// hand Provider to the signing call
finally
Provider.Free;
end;
end;
Hvorfor har status-enumen seks verdier i stedet for en boolsk?
THPDFSignatureProviderStatus skiller spsValid, spsInvalid, spsUnsupported, spsMalformed, spsProviderError og spsCancelled, og å kollapse dem koster deg evnen til å handle riktig. En signatur som er kryptografisk feil (spsInvalid) er en sikkerhetshendelse. En algoritme leverandøren ikke implementerer (spsUnsupported) er en utrullingslucka. Et transport-svikt (spsProviderError) er verdt å prøve på nytt, og et brukerkansellert token-spørsmål (spsCancelled) er ikke verdt å prøve på nytt i det hele tatt
Regelen for signering er snever: en signeringsleverandør returnerer spsValid bare med en ikke-tom signatur. Verifiseringsleverandører returnerer spsValid eller spsInvalid, og de andre fire forblir adskilte på begge stier. Hvis du skriver en leverandør, motstå fristelsen til å avbilde alt du ikke gjenkjenner over på spsInvalid — det forvandler en manglende DLL til en rapport om at kundens signatur er forfalsket
Hvor signaturen faktisk lander i filen
To funksjoner kobler leverandører til ekte PDF-bytes. HPDFCMSBuildSignedDataWithProvider bygger frakoblet CMS fra et dokument-SHA-256-digest, som er det rette inngangspunktet når din arbeidsflyt beregner digest-et et annet sted. HPDFCMSSignPDFStreamWithProvider signerer en eksisterende signatur-plassholder i en PDF-strøm og bevarer den standardiserte /ByteRange-pipelinen, som er det rette inngangspunktet når HotPDF la ut plassholderen selv
Å bevare den pipelinen betyr mer enn det høres ut som. /ByteRange-konvensjonen — to intervaller som hopper over det heksadesimale signaturvinduet — er det enhver validator sjekker først, og en leverandør-basert sti som skrev den om, ville ødelagt PAdES-konformans uansett hvor sunn kryptografien var. HotPDF holder layouten identisk med den innebygde signeringsstien, slik at et dokument signert gjennom en PKCS#11-token verifiserer med den samme signaturverifiseringskoden som ett signert fra en PFX-fil. For profilreglene som sitter over algoritmevalget, se gjennomgangen av PAdES-grunnlinjesignaturer i Delphi, og for de ECDSA-spesifikke kodingfellene som er eldre enn denne leverandørmodellen, notatene om ECDSA CMS-verifisering og P1363-signaturformater
En migrasjonsorden som ikke etterlater dokumentene dine i stikken
Post-kvantum-beredskap er et tidsplaneproblem, ikke en bryter. Nesten ingen utrullet PDF-leser validerer ML-DSA i dag, så et dokument signert med kun den er, fra leserens ståsted, et dokument med en uverifiserbar signatur. Den ordenen som overlever kontakt med virkelige arkiver er: behold RSA eller ECDSA som signaturen en validator vil bedømme, legg til utvidelseserklæringen og en andre ML-DSA-signatur der en policy krever kvantemotstandsdyktig bevis, og flytt primærsignaturen først når konsumerende systemer har tatt igjen
Det HotPDF gir deg i dag er evnen til å skrive og verifisere begge, fra den samme koden, med algoritmen registrert ærlig i filen og i verifiseringsresultatet. HotPDF er en VCL-PDF-komponent for Delphi og C++Builder uten noen ekstern PDF-runtime, slik at signerings- og verifiseringsstiene leveres inne i din kjørbare i stedet for ved siden av den — se HotPDF Delphi PDF-komponentsiden for den fullstendige funksjonslisten og prøvenedlastingen