Artykuł techniczny

HotPDF: digital signatures and PAdES-ready signing in Delphi

HotPDF to natywna biblioteka PDF VCL dla aplikacji Delphi i C++Builder, które potrzebują bezpośredniego tworzenia i edycji PDF, formularzy, adnotacji, szyfrowania, podpisów cyfrowych, czcionek Unicode, wyjścia zgodnego ze standardami i raportów preflight bez instalowania zewnętrznego runtime PDF.

Ten artykuł jest przeznaczony dla Delphi zespołów dodających certificate-based approval, invoice signing, or long-term validation evidence. Traktuje digital signatures and PAdES-ready signing jako produkcyjną inżynierię dokumentów, a nie pojedyncze wywołanie komponentu.

Praktyczne ryzyko polega na tym, że a PDF may contain a visible signature box while the byte range, certificate chain, timestamp, revocation data, or later incremental update invalidates trust. Dlatego przepływ wymaga spisanego kontraktu, obserwowalnej diagnostyki i realistycznych plików regresyjnych.

Decyzje architektoniczne

Design signing as a revision-controlled workflow. certificate source, private-key boundary, and operator approval process / timestamp authority, revocation source, and long-term validation profile

  • certificate source, private-key boundary, and operator approval process
  • timestamp authority, revocation source, and long-term validation profile
  • visible signature appearance, signer reason, contact, and location fields
  • whether later annotations, forms, or metadata updates are allowed after signing

Przebieg implementacji

Prepare evidence before reserving the signature field. Poniższa kolejność zachowuje czytelność przepływu pracy dla zespołów Delphi i C++Builder.

  1. freeze the document content and preflight it before signature reservation
  2. load certificate material from the approved key store or signing service
  3. reserve the signature field and byte range with enough space for the final value
  4. apply timestamp and revocation data according to the selected PAdES profile
  5. verify the final file in at least one independent validator before release

Dowody walidacji

Signature evidence worth keeping. Zachowaj te pola wraz z wynikiem lub rekordem wsparcia.

  • signer certificate fingerprint, chain status, timestamp result, and revocation source
  • signature byte range, digest algorithm, PAdES profile, and validation summary
  • document hash before signing and final hash after the signed revision is saved
  • policy decision for any warning that did not block the signature

PAdES is a lifecycle, not only a signature

PAdES-ready output needs deterministic document bytes, a verified certificate context, timestamp policy, revocation evidence, and a save strategy that does not alter signed byte ranges after the signature is applied.

Profile ownership and versioning

A named, versioned profile is easier to review than options scattered across forms, scripts, and batch parameters. It also makes support reports readable when customers use older templates or policies.

  • certificate source, private-key boundary, and operator approval process
  • timestamp authority, revocation source, and long-term validation profile
  • visible signature appearance, signer reason, contact, and location fields
  • whether later annotations, forms, or metadata updates are allowed after signing
  • signer certificate fingerprint, chain status, timestamp result, and revocation source
  • signature byte range, digest algorithm, PAdES profile, and validation summary

Notatki przeglądu inżynierskiego dla digital signatures and PAdES-ready signing

Użyj tych notatek przeglądu, aby upewnić się, że funkcja wyszła poza demonstrację i da się ją obronić podczas wydania, wsparcia i eskalacji klienta.

  • Decyzja: certificate source, private-key boundary, and operator approval process. Punkt nacisku implementacji: load certificate material from the approved key store or signing service. Dowody akceptacji: document hash before signing and final hash after the signed revision is saved. Wyzwalacz regresji: timestamp and revocation services need timeout and retry policies
  • Decyzja: timestamp authority, revocation source, and long-term validation profile. Punkt nacisku implementacji: reserve the signature field and byte range with enough space for the final value. Dowody akceptacji: policy decision for any warning that did not block the signature. Wyzwalacz regresji: editing metadata or form values after signing can invalidate the signed revision
  • Decyzja: visible signature appearance, signer reason, contact, and location fields. Punkt nacisku implementacji: apply timestamp and revocation data according to the selected PAdES profile. Dowody akceptacji: signer certificate fingerprint, chain status, timestamp result, and revocation source. Wyzwalacz regresji: certificate chain checks can pass on a developer machine but fail offline
  • Decyzja: whether later annotations, forms, or metadata updates are allowed after signing. Punkt nacisku implementacji: verify the final file in at least one independent validator before release. Dowody akceptacji: signature byte range, digest algorithm, PAdES profile, and validation summary. Wyzwalacz regresji: visible appearance text should not be treated as cryptographic evidence
  • Decyzja: certificate source, private-key boundary, and operator approval process. Punkt nacisku implementacji: freeze the document content and preflight it before signature reservation. Dowody akceptacji: document hash before signing and final hash after the signed revision is saved. Wyzwalacz regresji: timestamp and revocation services need timeout and retry policies

Przypadki brzegowe

  • editing metadata or form values after signing can invalidate the signed revision
  • certificate chain checks can pass on a developer machine but fail offline
  • visible appearance text should not be treated as cryptographic evidence
  • timestamp and revocation services need timeout and retry policies

Delphi / C++Builder notes

HotPDF Component should sit behind a small service boundary that receives files, streams, profiles, and credentials, then returns output paths, warnings, metrics, and validation status. Important terms include PAdES, digital signature, byte range, timestamp, DSS, revocation.

Przykład kodu Delphi

Poniższy szkic Delphi pokazuje praktyczną granicę usługi dla tego tematu. Kontrole zasad, logowanie i walidację trzymaj poza wąskim blokiem wywołań produktu, aby przepływ pozostał testowalny.

procedure SignApprovedPdf(const InputFile, OutputFile: string; const Policy: TSignaturePolicy);
var
  Pdf: THotPDF;
begin
  Pdf := THotPDF.Create(nil);
  try
    LoadUnsignedPackage(Pdf, InputFile);
    CheckSigningPolicy(Policy);
    AttachPadesEvidence(Pdf, Policy.Certificate, Policy.TimestampServer);
    SaveSignedPackage(Pdf, OutputFile);
    ValidateSignatureChain(OutputFile, Policy.TrustAnchors);
  finally
    Pdf.Free;
  end;
end;

Lista produkcyjna

  • Uruchom przepływ pracy na pustym pliku, zwykłym pliku klienta i pliku z najgorszego scenariusza
  • Otwórz wygenerowany plik PDF w docelowej przeglądarce, walidatorze, drukarce lub aplikacji nadrzędnej
  • Zaloguj wersję produktu, wersję profilu, hash wejścia, ścieżkę wyjścia, czas wykonania i liczbę ostrzeżeń
  • Przechowuj hasła, certyfikaty, pliki tymczasowe i dane klienta zgodnie z jednoznacznymi zasadami retencji
  • Dodaj dokument regresyjny, gdy plik klienta ujawni nowy przypadek brzegowy

Dokumentacja produktu

HotPDF Component

Dodatkowe przykłady kodu

var
  Doc: THotPDF;
  Fs: TFileStream;
  PdfBytes, HashInput, SigHex: AnsiString;
  R1Start, R1Len, R2Start, R2Len, CStart, CLen: Integer;
begin
  // 1. Write the document with a reserved /Contents hole
  Doc := THotPDF.Create(nil);
  try
    Doc.FileName := 'placeholder.pdf';
    Doc.BeginDoc;
    Doc.CurrentPage.AddSignedSignatureField('Sig1',
      Rect(50, 100, 350, 150), 8192, 'adbe.pkcs7.detached',
      'Contract approval', 'Boston, MA', 'legal@example.com');
    Doc.EndDoc;
  finally
    Doc.Free;
  end;

  // 2. Load the saved bytes; the returned offsets are 0-based
  Fs := TFileStream.Create('placeholder.pdf', fmOpenRead);
  try
    SetLength(PdfBytes, Fs.Size);
    Fs.ReadBuffer(PdfBytes[1], Fs.Size);
  finally
    Fs.Free;
  end;
  THotPDF.PreparePDFForSigning(PdfBytes, R1Start, R1Len, R2Start, R2Len,
    CStart, CLen);

  // 3. Hash both spans and sign externally (HSM, token, service)
  HashInput := Copy(PdfBytes, R1Start + 1, R1Len) +
               Copy(PdfBytes, R2Start + 1, R2Len);
  SigHex := SignWithHsm(HashInput);  // your integration: returns CMS as hex

  // 4. Splice the signature into the reserved hole
  THotPDF.InsertSignatureHex(PdfBytes, SigHex);
  Fs := TFileStream.Create('signed.pdf', fmCreate);
  try
    Fs.WriteBuffer(PdfBytes[1], Length(PdfBytes));
  finally
    Fs.Free;
  end;
end;
// PAdES baseline signature field (ETSI EN 319 142-1)
Pdf.CurrentPage.AddPAdESSignatureField(
  'ApprovalSig', Rect(50, 100, 350, 150), 'B-B',
  'Contract approval', 'Boston, MA', 'legal@example.com');

// Document timestamp: larger reservation for the TSA token and chain
Pdf.CurrentPage.AddDocumentTimestampSignature('ArchiveTS', 16384);