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

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;

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

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;

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

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