HotPDF tikrina ML-DSA-44, ML-DSA-65, ML-DSA-87, Ed25519 ir Ed448 CMS parašus įkeltuose PDF dokumentuose, ir jis pasirašo per įkišamus paslaugų teikėjus, todėl privatūs raktai niekada neturi gyventi jūsų Delphi procese. Antroji pusė yra ta dalis, kurios dauguma komandų pirmiausia reikia. Aparatinis raktas, nuotolinė pasirašymo paslauga ir nacionalinė eID kortelė visi atsisako atiduoti raktą, o kol pasirašymo konvejeris nėra atskirtas nuo raktų saugyklos, nė vienas iš jų išvis negali būti naudojamas
To atskyrimas ir yra THPDFSignatureProvider tikslas. HotPDF pasilaiko dalis, kurias turėtų valdyti — CMS analizė, SignedData kūrimas, /ByteRange išdėstymas — ir perduoda vieną operaciją, kurios ji negali valdyti, tai yra santraukos pavertimą parašu raktu, kurio jai neleidžiama matyti. Viskas žemiau išplaukia iš šio padalijimo
Kodėl tinkamas ML-DSA parašas nepraeina tikrinimo?
Nes HotPDF atsisako ML-DSA įkeltame dokumente, kuris nedeklaruoja tam plėtinio. ML-DSA — gardelinė parašų schema, standartizuota kaip FIPS 204, ir priežastis, kodėl žmonės sako „pokvantinis PDF“ — dar neturi ISO 32000-2 registracijos. PDF, nešantis jį, naudoja algoritmą, kurio bazinis standartas nepavadina, o failas, tyliai naudojantis nepavadintą algoritmą, yra failas, kurio verdikto niekas kitas negali atkartoti
Tad HotPDF padaro deklaraciją aiškią. EnsureMLDSAExtensions pakelia dokumentą į PDF 2.0, kai leidžiama, ir įrašo /Extensions /HotPDF << /BaseVersion /2.0 /ExtensionLevel 1 >> į katalogą. Skaitymo pusėje LoadedDocumentDeclaresMLDSAExtension praneša, ar ta deklaracija išgyveno, o VerifyLoadedSignatureWithOptions taiko tą patį testą prieš gerbdamas Options.AllowMLDSA. Nustatykite vėliavėlę nedeklaruotame dokumente, ir ji lieka išjungta — parinktis gali atleisti politiką, bet niekada ne struktūrinį reikalavimą
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;
Kvieskite tai prieš išsaugant, o ne po. Deklaracija yra pasirašyto baitų intervalo dalis, o katalogas, pataisytas vėliau, yra arba nepasirašytas pasirašyto failo pakeitimas, arba antroji redakcija, kurią validatorius praneš kaip modifikaciją
Trios algoritmų šeimos, vienas tikrinimo įėjimo taškas
Visos trys šeimos ateina per VerifyLoadedSignatureWithOptions, kuris priima parašo indeksą, šaltinio srautą, THPDFCMSVerifyOptions įrašą ir išėjimo parametrą parašo detalėms. Įrašas turi lygiai tris laukus, ir kiekvienas atsako į klausimą, anksčiau reikalavusį perkompiliavimo
SignatureProvider pakeičia jūsų savąją paslaugų teikėją į įmontuotą platformos. OpenSSLLibraryPath parenka OpenSSL 3 biblioteką, kuri ir tiekia gryno režimo Ed25519 ir Ed448 tikrinimą, kurio Windows CNG ne visur siūlo. AllowMLDSA įsijungia į gardelinius algoritmus, sąlygotai aukščiau esančio plėtinio tikrinimo. Tikslus algoritmo OID, kuris buvo atpažintas, grįžta THPDFSignatureInfo.SignatureAlgorithmOID, todėl audito žurnalas gali užrašyti, kas buvo tikrintas, o ne kas buvo prašyta
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 ir Ed448 nereikalauja plėtinio deklaracijos, nes ISO 32000-2 juos jau priima. Jiems reikia paslaugų teikėjo, kuris juos įgyvendina, kas daugumoje Windows diegimų reiškia OpenSSLLibraryPath nukreipimą į biblioteką, kurią pateikiate ir valdote, o ne į tai, kas atsitiktinai yra kompiuteryje
Ką iš tikrųjų žada pasirašymo paslaugų teikėjas?
Paslaugų teikėjas žada vieną dalyką: gavęs užklausą, grąžinti būseną ir, kai pasirašoma, baitus. THPDFSignatureProviderRequest neša algoritmą ir jo OID, santraukos OID, PSS druskos ilgį, ar įvestis yra pranešimas, ar jau apskaičiuota santrauka, pačią įvestį, viešąjį raktą ar sertifikatą, rakto identifikatorių ir operacijos identifikatorių. Nieko tame įraše nėra HotPDF-specifinio — tai yra žodynas, kurį rakto tvarkyklė ar pasirašymo paslauga jau kalba
Su biblioteka pristatomi trys įgyvendinimai. THPDFCallbackSignatureProvider apgaubia anoniminius metodus, kas yra trumpiausias kelias nuo esamo vidinio pasirašymo pobūdžio iki veikiančio PDF parašo. THPDFRemoteSignatureProvider apgaubia transportavimo atgalinį iškvietimą su pakartojimo limitu, atšaukimo registru ir ribomis įvesčiai bei parašo dydžiui, kad pakibęs HSM negalėtų tapti pakibusia programa. THPDFPKCS11SignatureProvider serijuoja RSA operacijas prieš kviesiančiojo valdomą, jau autentifikuotą PKCS#11 sesiją ir privataus rakto deskriptorių — HotPDF niekada neprisijungia, niekano nemato PIN ir niekada neuždaro sesijos, kurios neatidarė
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;
Kodėl būsenos išvardijimas turi šešias reikšmes vietoj boolean
THPDFSignatureProviderStatus atskiria spsValid, spsInvalid, spsUnsupported, spsMalformed, spsProviderError ir spsCancelled, ir jų suliejimas kainuoja gebėjimą elgtis teisingai. Kriptografiškai neteisingas parašas (spsInvalid) yra saugumo įvykis. Algoritmas, kurio paslaugų teikėjas neįgyvendina (spsUnsupported), yra diegimo spraga. Transportavimo triktis (spsProviderError) verta pakartoti, o naudotojo atšauktas rakto raginimas (spsCancelled) išvis neverta pakartoti
Taisyklė pasirašymui yra siaura: pasirašymo paslaugų teikėjas grąžina spsValid tik su netuščiu parašu. Tikrinimo paslaugų teikėjai grąžina spsValid arba spsInvalid, o kitos keturios lieka atskiros abiem keliais. Jei rašote paslaugų teikėją, pasipriešinkite pagundai viską, ko neatpažįstate, priimti kaip spsInvalid — tai paverčia trūkstamą DLL pranešimu, kad kliento parašas yra suklastotas
Kur parašas tikrai nusileidžia faile
Dvi funkcijos sujungia paslaugų teikėjus su realiais PDF baitais. HPDFCMSBuildSignedDataWithProvider stato atskirtą CMS iš dokumento SHA-256 santraukos, kas yra teisingas įėjimo taškas, kai jūsų darbo eiga santrauką apskaičiuoja kitur. HPDFCMSSignPDFStreamWithProvider pasirašo esamą parašo vietą PDF sraute ir išlaiko standartinį /ByteRange konvejerį, kas yra teisingas įėjimo taškas, kai HotPDF pats išdėstė vietą
To konvejerio išlaikymas svarbesnis, nei skamba. /ByteRange konvencija — du intervalai, praleidžiantys šešioliktainio parašo langą — yra tai, ką validatorius pirmiausia tikrina, o iš paslaugų teikėjo grįstas kelias, ją perrašęs, sulaužytų PAdES atitiktį, neatsižvelgiant į tai, koks tvirtas būtų kriptografija. HotPDF išlaiko išdėstymą tokį patį kaip įmontuotas pasirašymo kelias, todėl dokumentas, pasirašytas per PKCS#11 raktą, patikrinamas su tuo pačiu parašo tikrinimo kodu kaip ir pasirašytas iš PFX failo. Dėl profilio taisyklių, esančių virš algoritmo parinkties, žr. PAdES bazinių parašų Delphi aprašymą, o dėl ECDSA-specifinių kodavimo spąstų, anksčiau už šio paslaugų teikėjo modelio, — ECDSA CMS tikrinimo ir P1363 parašų formatų pastabas
Migracijos tvarka, kuri nepaliekajūsų dokumentų likimo valiai
Pokvantinis pasirengimas yra grafiko problema, o ne jungiklis. Beveik joks šiandien naudojamas PDF žiūryklė netikrina ML-DSA, todėl dokumentas, pasirašytas tik juo, iš skaitytojo pusės yra dokumentas su nepatikrinamu parašu. Tvarka, kuri išgyvena kontaktą su realiais archyvais, yra: laikyti RSA arba ECDSA kaip parašą, kurį vertins validatorius, pridėti plėtinio deklaraciją ir antrą ML-DSA parašą ten, kur politika reikalauja kvantui atsparių įrodymų, ir perkelti pagrindinį parašą tik tada, kai vartojančios sistemos bus pasivijusios
Ką HotPDF jums šiandien duoda, tai gebėjimą rašyti ir tikrinti abu, iš to paties kodo, su algoritmu sąžiningai užrašytu faile ir tikrinimo rezultate. HotPDF yra natyvus VCL PDF komponentas, skirtas Delphi ir C++Builder, be išorinės PDF vykdymo aplinkos, todėl pasirašymo ir tikrinimo keliai keliauja jūsų vykdomajame faile, o ne šalia jo — žr. HotPDF Delphi PDF komponento puslapį dėl pilno savybių sąrašo ir bandomosios versijos atsisiuntimo