Odborný článok

Post-kvantové a EdDSA podpisovanie PDF s HotPDF v Delphi

HotPDF overuje ML-DSA-44, ML-DSA-65, ML-DSA-87, Ed25519 a Ed448 CMS podpisy v načítaných PDF dokumentoch a podpisuje cez pripojiteľných providerov, takže súkromný kľúč nikdy nemusí žiť vo vnútri vášho Delphi procesu. Druhá polovica je časť, ktorú väčšina tímov potrebuje ako prvú. Hardvérový token, vzdialená podpisová služba a národná eID karta všetky odmietajú vydať kľúč a kým nie je podpisová linka oddelená od úložiska kľúčov, nedá sa použiť žiadny z nich

Toto oddelenie je zmyslom THPDFSignatureProvider. HotPDF si ponecháva časti, ktoré má vlastniť — parsing CMS, stavbu SignedData, rozmiestnenie /ByteRange — a deleguje jedinú operáciu, ktorú vlastniť nemôže, a to premenu digestu na podpis kľúčom, ktorý nesmie vidieť. Všetko ďalšie vyplýva z tohto rozdelenia

Prečo platný ML-DSA podpis zlyhá pri overovaní?

Pretože HotPDF odmieta ML-DSA na načítanom dokumente, ktorý nedeklaruje príslušné rozšírenie. ML-DSA — mriežkový podpisový schéma štandardizovaný ako FIPS 204 a dôvod, prečo ľudia hovoria „post-kvantové PDF" — nemá zatiaľ žiadnu registráciu v ISO 32000-2. PDF, ktoré jeden nesie, používa algoritmus, ktorý základný štandard nemenuje, a súbor, ktorý potichu používa nepomenovaný algoritmus, je súbor, ktorého verdikt nedokáže zopakovať nikto iný

Tak HotPDF robí nárok explicitným. EnsureMLDSAExtensions zvýši dokument na PDF 2.0, kde je to povolené, a zapíše /Extensions /HotPDF << /BaseVersion /2.0 /ExtensionLevel 1 >> do katalógu. Na čítacej strane LoadedDocumentDeclaresMLDSAExtension hlási, či táto deklarácia prežila, a VerifyLoadedSignatureWithOptions aplikuje ten istý test skôr, než bude rešpektovať Options.AllowMLDSA. Nastavte príznak na nedeklarovanom dokumente a zostane vypnutý — voľba môže uvoľniť politiku, nikdy však štrukturálny predpoklad

HotPDF zatarasí overovanie PDF ML-DSA za explicitnou deklaráciou rozšírenia Catalog zapísanou EnsureMLDSAExtensions pred uložením dokumentu a odmietne mriežkové algoritmy na nedeklarovaných súboroch, aj keď je nastavené AllowMLDSA
HotPDF pripúšťa ML-DSA len keď Catalog stále deklaruje rozšírenie, čo udržuje post-quantum verdikt reprodukovateľný, a volanie EnsureMLDSAExtensions pred EndDoc kladie deklaráciu dovnútra podpísaného bajtového rozsahu, nie zaň
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;   // deklarujte pred zapísaním podpisu
    Pdf.EndDoc;
  finally
    Pdf.Free;
  end;
end;

Zavolajte to pred uložením, nie po ňom. Deklarácia je súčasťou podpísaného rozsahu bajtov a katalóg opravený dodatočne je buď nepodpísanou zmenou podpísaného súboru, alebo druhou revíziou, ktorú validátor nahlási ako modifikáciu

Tri rodiny algoritmov, jeden vstupný bod overovania

Všetky tri rodiny prichádzajú cez VerifyLoadedSignatureWithOptions, ktorý prijíma index podpisu, zdrojový stream, záznam THPDFCMSVerifyOptions a out parameter s detailmi podpisu. Záznam má presne tri polia a každé odpovedá na otázku, ktorá kedysi vyžadovala prestavbu

SignatureProvider nahradzuje vstavaný platformný provider tým vaším. OpenSSLLibraryPath vyberá knižnicu OpenSSL 3, ktorá dodáva overovanie Ed25519 a Ed448 v režime pure-mode, ktoré Windows CNG neponúka všade. AllowMLDSA zapája mriežkové algoritmy, podmienene kontrolou rozšírenia vyššie. Presný OID algoritmu, ktorý bol rozpoznaný, sa vráti v THPDFSignatureInfo.SignatureAlgorithmOID, takže audit log môže zaznamenať, čo bolo overené, a nie čo bolo požadované

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 a Ed448 nepotrebujú deklaráciu rozšírenia, pretože ISO 32000-2 ich už pripúšťa. Potrebujú však providera, ktorý ich implementuje, čo na väčšine Windows nasadení znamená nasmerovať OpenSSLLibraryPath na knižnicu, ktorú dodávate a ovládate vy, a nie na to, čo sa náhodou nachádza na stroji

Čo podpisový provider skutočne sľubuje?

Provider sľubuje jednu vec: prijatím požiadavky vráti stav a pri podpisovaní aj bajty. THPDFSignatureProviderRequest nesie algoritmus a jeho OID, OID digestu, dĺžku PSS soli, či vstup je správa alebo už vypočítaný digest, samotný vstup, verejný kľúč alebo certifikát, identifikátor kľúča a identifikátor operácie. Nič v tomto zázname nie je špecifické pre HotPDF — je to slovník, ktorým už hovorí ovládač tokenu alebo podpisová služba

S knižnicou sa dodávajú tri implementácie. THPDFCallbackSignatureProvider obaľuje anonymné metódy, čo je najkratšia cesta od existujúcej interného podpisovej rutiny k fungujúcemu PDF podpisu. THPDFRemoteSignatureProvider obaľuje transportný callback s limitom opakovaní, registrom zrušenia a ohraničeniami veľkosti vstupu a podpisu, takže zatuhnuté HSM sa nemôže stať zatuhnutou aplikáciou. THPDFPKCS11SignatureProvider serializuje RSA operácie voči volajúcim vlastnenej, už autentifikovanej PKCS#11 relácii a handle súkromného kľúča — HotPDF sa nikdy neprihlasuje, nikdy nevidí PIN a nikdy nezatvára reláciu, ktorú sám neotvoril

Zástrční poskytovatelia podpisov HotPDF vymieňajú jeden obyčajný záznam žiadosti a vracajú šesťhodnotový status, ukázané pre implementácie callback, remote a PKCS#11, zatiaľ čo súkromný kľúč nikdy nevstúpi do procesu Delphi
Všetky tri dodané implementácie rozprávajú rovnaký request záznam a odpovedajú rovnakým šesťhodnotovým stavom, čo umožňuje hardvérovým tokenom, vzdialeným HSM službám a národným eID kartám nechať si svoje kľúče namiesto ich exportu
var
  Provider: THPDFRemoteSignatureProvider;
begin
  Provider := THPDFRemoteSignatureProvider.Create(
    function(const Req: THPDFSignatureProviderRequest; Attempt: Integer;
      out Signature: TBytes): THPDFSignatureProviderStatus
    begin
      // POST Req.Input do podpisovej služby; Req.KeyIdentifier vyberá kľúč
      if PostToSigningService(Req.KeyIdentifier, Req.Input, Signature) then
        Result := spsValid
      else
        Result := spsProviderError;
    end,
    3,          // RetryLimit
    1048576,    // MaxInputBytes
    65536);     // MaxSignatureBytes
  try
    // odovzdajte Provider volaniu na podpisovanie
  finally
    Provider.Free;
  end;
end;

Prečo má enum stavu šesť hodnôt namiesto boolu

THPDFSignatureProviderStatus odlišuje spsValid, spsInvalid, spsUnsupported, spsMalformed, spsProviderError a spsCancelled a ich zrútenie vás pripraví o schopnosť konať správne. Podpis, ktorý je kryptograficky chybný (spsInvalid), je bezpečnostná udalosť. Algoritmus, ktorý provider neimplementuje (spsUnsupported), je medzera v nasadení. Zlyhanie transportu (spsProviderError) sa oplatí opakovať a používateľom zrušený prompt tokenu (spsCancelled) sa neoplatí opakovať vôbec

Pravidlo pre podpisovanie je úzke: podpisový provider vráti spsValid iba s nepráznym podpisom. Overovací provideri vracajú spsValid alebo spsInvalid a ostatné štyri zostávajú odlišné na oboch cestách. Ak píšete providera, odolávajte pokušeniu mapovať všetko, čo nerozpoznáte, na spsInvalid — to zmení chýbajúce DLL na hlásenie, že podpis zákazníka je sfalšovaný

Kde podpis skutočne pristanuje v súbore

Dve funkcie prepájajú providerov s reálnymi PDF bajtmi. HPDFCMSBuildSignedDataWithProvider stavia oddelený CMS z digestu dokumentu SHA-256, čo je správny vstupný bod, keď váš workflow počíta digest inde. HPDFCMSSignPDFStreamWithProvider podpisuje existujúci zástupný podpis v PDF streame a zachováva štandardnú linku /ByteRange, čo je správny vstupný bod, keď HotPDF rozmiestnil zástupné miesto sám

Zachovanie tejto linky má väčší význam, než to znie. Konvencia /ByteRange — dva rozsahy, ktoré preskakujú hex okno podpisu — je to, čo validátor kontroluje ako prvé a cesta založená na providerovi, ktorá by ju prepísala, by zlomila zhodu s PAdES bez ohľadu na to, aká bola kryptografia správna. HotPDF drží rozvrhnutie identické s vstavanou podpisovou cestou, takže dokument podpísaný cez PKCS#11 token sa overí tým istým kódom overovania podpisov ako ten podpísaný z PFX súboru. Pre pravidlá profilu, ktoré sedia nad voľbou algoritmu, pozri návod k PAdES baseline podpisom v Delphi a pre ECDSA-špecifické pasce enkódovania, ktoré predchádzajú tomuto modelu providera, poznámky k ECDSA CMS overovaniu a formátom podpisu P1363

Dva podpisové vstupné body poskytovateľov HotPDF, HPDFCMSBuildSignedDataWithProvider pre externe vypočítaný digest a HPDFCMSSignPDFStreamWithProvider pre vyložený zástupný symbol, sa zbiehajú na jednom rozložení CMS zachovávajúcom rozsahy /ByteRange, ktoré validátory kontrolujú ako prvé
Ktorýkoľvek vstupný bod zapisuje identický podpísaný tvar dvoch pokrytých rozsahov okolo hex okna, takže dokument podpísaný poskytovateľom dosiahne každý validátor presne ako ten podpísaný z PFX súboru

Poradie migrácie, ktoré nenechá vaše dokumenty v štoku

Post-kvantová pripravenosť je problém harmonogramu a nie prepínač. Takmer žiadny nasadený PDF prehliadač dnes ML-DSA nevaliduje, takže dokument podpísaný iba ním je z pohľadu čítačky dokument s nepreveriteľným podpisom. Poradie, ktoré prežije kontakt s reálnymi archívmi, je: ponechať RSA alebo ECDSA ako podpis, ktorý bude validátor posudzovať, pridať deklaráciu rozšírenia a druhý ML-DSA podpis tam, kde politika vyžaduje kvantovo odolný dôkaz, a presunúť primárny podpis až vtedy, keď konzumujúce systémy dobehli

Čo vám HotPDF dnes dáva, je schopnosť zapisovať a overovať obe z toho istého kódu, s algoritmom úprimne zaznamenaným v súbore aj vo výsledku overovania. HotPDF je natívny VCL PDF komponent pre Delphi a C++Builder bez externého PDF runtime, takže podpisové a overovacie cesty putujú vo vnútri vášho spustiteľného súboru a nie vedľa neho — kompletný zoznam funkcií a skúšobnú stiahnutie nájdete na stránke HotPDF Delphi PDF komponentu