HotPDF верифицира ML-DSA-44, ML-DSA-65, ML-DSA-87, Ed25519 и Ed448 CMS подписи в заредени PDF документи и подписва чрез включвани доставчици, така че частният ключ никога не трябва да живее вътре във вашия Delphi процес. Втората половина е частта, от която повечето екипи се нуждаят най-напред. Хардуерен токен, отдалечена услуга за подписване и национална eID карта всички отказват да предадат ключ, и докато пайплайнът за подписване не бъде отделен от хранилището на ключове, нито един от тях не може да се използва изобщо
Това разделяне е смисълът на THPDFSignatureProvider. HotPDF запазва частите, които трябва да притежава — синтактичен разбор на CMS, изграждане на SignedData, подредба на /ByteRange — и делегира еднаствената операция, която не може да притежава, а именно превръщането на дайджест в подпис с ключ, който няма право да види. Всичко по-долу следва от това разделение
Защо валиден ML-DSA подпис не минава проверка?
Защото HotPDF отказва ML-DSA върху зареден документ, който не декларира разширението за него. ML-DSA — решетъчната схема за подпис, стандартизирана като FIPS 204, и причината хората да казват «пост-квантов PDF» — все още няма регистрация в ISO 32000-2. PDF, който носи такъв, използва алгоритъм, който базовият стандарт не назовава, а файл, който мълчаливо използва не назован алгоритъм, е файл, чиято присъда не може да бъде възпроизведена от никой друг
Така че HotPDF прави претенцията изрична. EnsureMLDSAExtensions повишава документа до PDF 2.0, когато е разрешено, и записва /Extensions /HotPDF << /BaseVersion /2.0 /ExtensionLevel 1 >> в каталога. От страна на четенето LoadedDocumentDeclaresMLDSAExtension отчита дали тази декларация е оцеляла, а VerifyLoadedSignatureWithOptions прилага същия тест, преди да зачете Options.AllowMLDSA. Задайте флага върху недеклариран документ и той остава изключен — опцията може да разхлаби политика, но никога структурното изискване
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;
Извикайте го преди запазване, не след него. Декларацията е част от подписания байтов диапазон, а каталог, закърпен след това, е или неподписана промяна върху подписан файл, или втора ревизия, която валидатор ще отчита като модификация
Три семейства алгоритми, една точка за верификация
И трите семейства пристигат през VerifyLoadedSignatureWithOptions, който приема индекс на подпис, изходния поток, запис THPDFCMSVerifyOptions и out параметър за детайлите на подписа. Записът има точно три полета и всяко отговаря на въпрос, който по-рано изискваше прездравяване
SignatureProvider замества вашия собствен доставчик с вградения платформен. OpenSSLLibraryPath избира библиотека OpenSSL 3, която е това, което доставя верификация на Ed25519 и Ed448 в чист режим, каквото Windows CNG не предлага навсякъде. AllowMLDSA включва решетъчните алгоритми, при подчинение на горната проверка за разширение. Точният OID на разпознатия алгоритъм се връща в THPDFSignatureInfo.SignatureAlgorithmOID, така че одитен лог може да запише какво е било верифицирано, а не какво е било заявено
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 и Ed448 не се нуждаят от декларация за разширение, защото ISO 32000-2 вече ги допуска. Нуждаят се обаче от доставчик, който ги реализира, което при повечето Windows разгръщания означава да насочите OpenSSLLibraryPath към библиотека, която вие доставяте и контролирате, вместо към каквото и да е на машината
Какво всъщност обещава доставчикът за подписване?
Доставчикът обещава едно нещо: при заявка връща статус и, при подписване, байтове. THPDFSignatureProviderRequest носи алгоритъма и неговия OID, OID на дайджеста, дължината на PSS солта, дали входът е съобщение или вече пресметнат дайджест, самия вход, публичния ключ или сертификат, идентификатор на ключ и идентификатор на операция. Нищо в този запис не е специфично за HotPDF — това е речникът, който драйверът на токен или услугата за подписване вече говори
Три реализации се доставят с библиотеката. THPDFCallbackSignatureProvider обвива анонимни методи, което е най-краткият път от съществуваща вътрешна рутина за подписване до работещ PDF подпис. THPDFRemoteSignatureProvider обвива транспортен callback с лимит за повторни опити, регистър за отменяне и граници за размер на входа и подписа, така че заклещен HSM не може да стане заклещено приложение. THPDFPKCS11SignatureProvider сериализира RSA операции срещу притежавана от извикващия, вече удостоверена PKCS#11 сесия и манипулатор на частен ключ — HotPDF никога не вписва, никога не вижда PIN и никога не затваря сесия, която не е отварял
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;
Защо статусният enum има шест стойности вместо булев
THPDFSignatureProviderStatus разграничава spsValid, spsInvalid, spsUnsupported, spsMalformed, spsProviderError и spsCancelled, а свиването им в едно ви струва способността да действате правилно. Подпис, който е криптографски грешен (spsInvalid), е събитие за сигурност. Алгоритъм, който доставчикът не реализира (spsUnsupported), е пролука в разгръщането. Транспортен отказ (spsProviderError) си струва да се повтори, а подсказване за токен, отменено от потребителя (spsCancelled), не си струва да се повтаря изобщо
Правилото за подписване е тясно: доставчик за подписване връща spsValid само с непразен подпис. Доставчиците за верификация връщат spsValid или spsInvalid, а останалите четири остават разграничени и по двата пътя. Ако пишете доставчик, устояйте на изкушението да изобразявате всичко, което не разпознавате, като spsInvalid — това превръща липсваща DLL в доклад, че подписът на клиента е фалшифициран
Къде подписът реално каца във файла
Две функции свързват доставчиците с реални PDF байтове. HPDFCMSBuildSignedDataWithProvider изгражда отделен CMS от дайджест SHA-256 на документ, което е правилната входна точка, когато работният ви процес изчислява дайджеста другаде. HPDFCMSSignPDFStreamWithProvider подписва съществуващо место за подпис в PDF поток и запазва стандартния пайплайн /ByteRange, което е правилната входна точка, когато HotPDF сам е подредил местото
Запазването на този пайплайн има повече значение, отколкото звучи. Конвенцията /ByteRange — два диапазона, които прескачат hex прозореца на подписа — е това, което всеки валидатор проверява първо, а базиран на доставчик път, който да го презапише, би счупил съответствие с PAdES, без значение колко здрава е криптографията. HotPDF запазва подредбата идентична с вградения път за подписване, така че документ, подписан през PKCS#11 токен, се верифицира със същия код за верификация на подписи като подписан от PFX файл. За правилата на профила, които сядат над избора на алгоритъм, вижте ръководството за PAdES базови подписи в Delphi, а за ECDSA-специфичните капани на кодирането, които предхождат този модел с доставчици — записките за ECDSA CMS верификация и P1363 формати на подписи
Ред на миграция, който не оставя документите ви изостанали
Пост-квантовата готовност е проблем на графика, а не превключвател. Почти никой разгърнат PDF четец не валидира ML-DSA днес, така че документ, подписан само с него, от гледна точка на четеца е документ с неверифицируем подпис. Редът, който оцелява при контакт с реални архиви, е: запазете RSA или ECDSA като подписа, който валидатор ще съди, добавете декларацията за разширение и втори ML-DSA подпис там, където политика изисква квантово-устойчиво доказателство, и преместете първичния подпис само когато консумиращите системи са настигнали
Това, което HotPDF ви дава днес, е способността да записвате и верифицирате и двете, от същия код, с алгоритъма често записан във файла и в резултата от верификацията. HotPDF е нативен VCL PDF компонент за Delphi и C++Builder без външен PDF runtime, така че пъщите за подписване и верификация се доставят вътре във вашия изпълним файл, а не до него — вижте страницата на HotPDF Delphi PDF компонент за пълния списък с функции и пробно изтегляне