HotPDF verificerer ML-DSA-44-, ML-DSA-65-, ML-DSA-87-, Ed25519- og Ed448-CMS-signaturer i indlæste PDF-dokumenter, og den signerer gennem plugbare udbydere, så den private nøgle aldrig behøver at bo inde i din Delphi-proces. Den anden halvdel er den del, de fleste teams har brug for først. Et hardware-token, en fjernsigneringstjeneste og et nationalt eID-kort nægter alle at udlevere en nøgle, og indtil signerings-pipelinen er adskilt fra nøglelageret, kan ingen af dem bruges overhovedet
Den opsplitning er pointen med THPDFSignatureProvider. HotPDF bevarer de dele, den bør eje — parsing af CMS, opbygning af SignedData, layout af /ByteRange — og delegerer den ene operation, den ikke kan eje, som er at forvandle et digest til en signatur med en nøgle, den ikke har lov til at se. Alt det følgende følger af den opdeling
Hvorfor fejler en gyldig ML-DSA-signatur verificering?
Fordi HotPDF afviser ML-DSA på et indlæst dokument, der ikke erklærer udvidelsen for det. ML-DSA — det gitter-baserede signatur-skema standardiseret som FIPS 204, og grunden til at folk siger "post-kvantum PDF" — har ingen ISO 32000-2-registrering endnu. En PDF, der bærer en, bruger en algoritme, basisstandarden ikke navngiver, og en fil, der tavst bruger en unavngiven algoritme, er en fil, hvis dom ikke kan reproduceres af nogen anden
Så HotPDF gør kravet eksplicit. EnsureMLDSAExtensions hæver dokumentet til PDF 2.0, hvor det er tilladt, og skriver /Extensions /HotPDF << /BaseVersion /2.0 /ExtensionLevel 1 >> ind i kataloget. På læsesiden rapporterer LoadedDocumentDeclaresMLDSAExtension, om den erklæring overlevede, og VerifyLoadedSignatureWithOptions anvender samme tjek, før den vil honorere Options.AllowMLDSA. Sæt flaget på et ikke-erklæret dokument, og det forbliver slået fra — tilvalget kan lempre politik, aldrig det strukturelle krav
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;
Kald den før du gemmer, ikke efter. Erklæringen er del af det signerede byte-interval, og et katalog, der patches bagefter, er enten en usigneret ændring af en signeret fil eller en second revision, som en validator vil rapportere som en ændring
Tre algoritme-familier, ét verifikations-indgangspunkt
Alle tre familier ankommer gennem VerifyLoadedSignatureWithOptions, som tager et signatur-indeks, kilde-strømmen, en THPDFCMSVerifyOptions-record og en out-parameter til signatur-detaljerne. Recorden har præcis tre felter, og hvert besvarer et spørgsmål, der tidligere krævede en ombygning
SignatureProvider substituerer din egen udbyder for den indbyggede platform-udbyder. OpenSSLLibraryPath vælger et OpenSSL 3-bibliotek, hvilket er det, der leverer den pure-mode Ed25519- og Ed448-verifikation, som Windows CNG ikke tilbyder alle steder. AllowMLDSA melder sig ind under gitter-algoritmerne, underlagt udvidelsestjekket ovenfor. Den præcise algoritme-OID, der blev genkendt, kommer tilbage i THPDFSignatureInfo.SignatureAlgorithmOID, så en revisionslog kan registrere, hvad der blev verificeret, frem for hvad der blev anmodet 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 behøver ingen udvidelses-erklæring, fordi ISO 32000-2 allerede admit-ter dem. De har brug for en udbyder, der implementerer dem, hvilket på de fleste Windows-udrulninger betyder at pege OpenSSLLibraryPath på et bibliotek, du shipper og kontrollerer, frem for på det, der tilfældigvis er på maskinen
Hvad loveder en signerings-udbyder reelt?
En udbyder loveder én ting: givet en anmodning, returner en status og, når der signeres, byte. THPDFSignatureProviderRequest bærer algoritmen og dens OID, digest-OID'en, PSS-salt-længden, om inputtet er en besked eller et allerede-beregnet digest, selve inputtet, den offentlige nøgle eller certifikat, en nøgle-identifikator og en operations-identifikator. Intet i den record er HotPDF-specifikt — det er det ordforråd, en token-driver eller en signeringstjeneste allerede taler
Tre implementeringer shipper med biblioteket. THPDFCallbackSignatureProvider indpakker anonyme metoder, hvilket er den korteste vej fra en eksisterende intern signerings-rutine til en fungerende PDF-signatur. THPDFRemoteSignatureProvider indpakker en transport-callback med en retry-grænse, et annullerings-register og grænser for input- og signatur-størrelse, så et hængende HSM ikke kan blive et hængende program. THPDFPKCS11SignatureProvider serialiserer RSA-operationer mod en kalder-ejet, allerede-autentificeret PKCS#11-session og private-nøgle-handle — HotPDF logger aldrig ind, ser aldrig en PIN og lukker aldrig en session, den ikke selv åbnede
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-enum'en seks værdier i stedet for en boolean?
THPDFSignatureProviderStatus skelner mellem spsValid, spsInvalid, spsUnsupported, spsMalformed, spsProviderError og spsCancelled, og at kollapse dem koster dig evnen til at handle korrekt. En signatur, der er kryptografisk forkert (spsInvalid), er en sikkerhedshændelse. En algoritme, som udbyderen ikke implementerer (spsUnsupported), er et udrulnings-hul. Et transport-fejl (spsProviderError) er værd at prøve igen, og en bruger-annulleret token-prompt (spsCancelled) slet ikke værd at prøve igen
Reglen for signering er snæver: en signerings-udbyder returnerer kun spsValid med en ikke-tom signatur. Verifikations-udbydere returnerer spsValid eller spsInvalid, og de andre fire forbliver adskilte på begge stier. Skriver du en udbyder, så modstå fristelsen til at mappe alt, du ikke genkender, over på spsInvalid — det forvandler en manglende DLL til en rapport om, at kundens signatur er forfalsket
Hvor signaturen reelt lander i filen
To funktioner forbinder udbydere med rigtige PDF-byte. HPDFCMSBuildSignedDataWithProvider bygger detached CMS fra et dokument-SHA-256-digest, hvilket er det rigtige indgangspunkt, når din arbejdsgang beregner digestet andetsteds. HPDFCMSSignPDFStreamWithProvider signerer en eksisterende signatur-placeholder i en PDF-strøm og bevarer den standard /ByteRange-pipeline, hvilket er det rigtige indgangspunkt, når HotPDF selv layoutede placeholderen
At bevare den pipeline betyder mere, end det lyder som. /ByteRange-konventionen — to intervaller, der springer hex-signatur-vinduet over — er det, enhver validator tjekker først, og en udbyder-baseret sti, der omskrev den, ville bryde PAdES-compliance uanset hvor sund kryptografien var. HotPDF bevarer layoutet identisk med den indbyggede signeringssti, så et dokument signeret gennem en PKCS#11-token verificerer med samme signatur-verifikationskode som et signeret fra en PFX-fil. For de profil-regler, der ligger over algoritme-valget, se gennemgangen af PAdES-baseline-signaturer i Delphi, og for de ECDSA-specifikke kodningsfælder, der gik forud for denne udbyder-model, noterne om ECDSA-CMS-verifikation og P1363-signaturformater
En migrationsrækkefølge, der ikke efterlader dine dokumenter i stikken
Post-kvantum-beredskab er et planlægningsproblem, ikke en kontakt. Næsten ingen udrullet PDF-fremviser validerer ML-DSA i dag, så et dokument signeret med den alene er, fra læserens synspunkt, et dokument med en unverificerbar signatur. Den rækkefølge, der overlever mødet med rigtige arkiver, er: bevar RSA eller ECDSA som den signatur, en validator vil bedømme, tilføj udvidelses-erklæringen og en anden ML-DSA-signatur, hvor en politik kræver kvantum-resistent bevis, og flyt den primære signatur kun, når de forbrugende systemer har indhentet sig
Hvad HotPDF giver dig i dag er evnen til at skrive og verificere begge, fra samme kode, med algoritmen optegnet ærligt i filen og i verifikationsresultatet. HotPDF er en native VCL PDF-komponent til Delphi og C++Builder uden ekstern PDF-runtime, så signerings- og verifikations-stierne shipper inde i din eksekverbare frem for ved siden af den — se HotPDF Delphi PDF-komponent-siden for den fulde funktionsliste og trial-download