技術記事

HotPDF Component: Delphi での digital signatures and PAdES-ready signing

HotPDF は Delphi/C++Builder アプリケーション向けのネイティブ VCL PDF ライブラリです。外部 PDF ランタイムを配置せずに、PDF 作成、編集、フォーム、注釈、暗号化、デジタル署名、Unicode フォント、標準対応出力、プリフライトレポートを扱えます。

この記事は Delphi teams adding certificate-based approval, invoice signing, or long-term validation evidence 向けです。digital signatures and PAdES-ready signing を単なるコンポーネント呼び出しではなく、本番向けのドキュメントエンジニアリングとして扱います。

実務上のリスクは a PDF may contain a visible signature box while the byte range, certificate chain, timestamp, revocation data, or later incremental update invalidates trust です。そのため、明確な契約、観測可能な診断、実際の顧客ファイルに近い回帰サンプルが必要です。

アーキテクチャ上の判断

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

実装フロー

Prepare evidence before reserving the signature field. The order below keeps the workflow reviewable for Delphi and C++Builder teams.

  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

検証エビデンス

Signature evidence worth keeping. Keep these fields with the output or support record.

  • 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

digital signatures and PAdES-ready signing に関する技術レビューの注意点

これらのレビュー項目を使って、機能がデモ段階を超え、リリース、サポート、顧客エスカレーションの場で説明できることを確認します

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

境界ケース

  • 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 の補足

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. 重要な用語には PAdES, digital signature, byte range, timestamp, DSS, revocation.

Delphi コード例

次の Delphi スケッチは、このテーマに対する実用的なサービス境界を示します。ポリシー確認、ログ記録、検証を製品呼び出しの狭い部分の外側に置くと、ワークフローをテストしやすくなります。

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;

本番チェックリスト

  • ワークフローは、空のファイル、通常の顧客ファイル、最悪ケースのファイルで実行します
  • 生成された PDF は、対象のビューアー、検証ツール、プリンター、または downstream アプリケーションで開きます
  • 製品バージョン、プロファイルバージョン、入力ハッシュ、出力パス、経過時間、警告数を記録します
  • パスワード、証明書、一時ファイル、顧客データは明確な保持ルールの下で管理します
  • 顧客ファイルが新しい境界ケースを示したら、回帰用ドキュメントを追加します

製品ドキュメント

HotPDF Component

追加のコード例

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);