チュートリアル: Delphi での PAdES PDF 署名
未署名の請求書 PDF から、組み込み RFC 3161 タイムスタンプ付き PAdES-B-T ドキュメントを生成する完全なウォークスルー — eIDAS、AdES 検証ソフト、ほとんどの公共部門ポータルが期待するレベルです。鍵プロバイダー(PKCS#11 スマートカードまたは Windows 証明書ストア)を構成し、適切な PAdES プロファイルを選び、署名済みファイルをエンド・ツー・エンドで検証します。
未署名の請求書 PDF から、組み込み RFC 3161 タイムスタンプ付き PAdES-B-T ドキュメントを生成する完全なウォークスルー — eIDAS、AdES 検証ソフト、ほとんどの公共部門ポータルが期待するレベルです。鍵プロバイダー(PKCS#11 スマートカードまたは Windows 証明書ストア)を構成し、適切な PAdES プロファイルを選び、署名済みファイルをエンド・ツー・エンドで検証します。
PDF を読み込み、スマートカードまたは PFX で署名し、信頼できるタイムスタンプを埋め込み、検証可能な PAdES ファイルをディスクに書き出す VCL フォームアプリケーション。
PAdES-B-B(基本)、PAdES-B-T(タイムスタンプ付き)、PAdES-B-LT(失効データ付き長期)または PAdES-B-LTA(アーカイブタイムスタンプ付き長期)。PAdES-B-T は請求書、契約、ほとんどの公共部門ワークフローの妥当なデフォルトです。
sgcSign は 10 の鍵プロバイダーをサポートします。このチュートリアルはハードウェアトークン用の TsgcPKCS11KeyProvider と、Windows にすでにインストールされた証明書用の TsgcWindowsStoreKeyProvider をカバーします。PFX、PEM、Azure Trusted Signing、AWS KMS、Google KMS でも同じコードパスが動作します。
TsgcSignPDF が署名パイプラインを駆動し、TsgcSignProfile_PAdES がプロファイルを構成し、TsgcSignatureVerifier が最終ドキュメントを検証します。各ステップはイベントを公開しているため、各段階で何が起きているかを検査できます。
各鍵プロバイダーは自身のユニットにあります。使用しないユニットをリンクしないよう、必要なプロバイダーのみを参照してください。
uses 句このチュートリアルでは 2 つの鍵プロバイダー(PKCS#11 と Windows ストア)と PAdES 署名ユニットを取り込みます。sgcSign_TSA は RFC 3161 タイムスタンプクライアントです — TSA URL を設定すると PAdES プロファイルが自動的に使用します。
PFX ファイルしかない場合は、sgcSign_KeyProvider_PKCS11 を sgcSign_KeyProvider_PFX に置き換え、5 分クイックスタート で示すように TsgcPFXKeyProvider を使用してください。
uses Classes, SysUtils, // sgc sgcSign_KeyProvider_PKCS11, sgcSign_KeyProvider_WindowsStore, sgcSign_PDF, sgcSign_Profile_PAdES, sgcSign_TSA, sgcSign_Verifier;
2 つの一般的な選択肢 — PKCS#11 ハードウェアトークン(スマートカード、USB HSM)または Windows 証明書ストアにすでにある証明書。
ModulePath をベンダー PKCS#11 DLL に向けます(例: SafeNet では C:\Windows\System32\eTPKCS11.dll)。Slot プロパティはトークンスロットを選択します — 最初に利用可能なトークンには 0 を使用。PIN は OnPinPrompt イベント経由で配信されるため、ソースに保存されることはありません。
LoadFromToken を呼ぶとセッションが開かれ、ラベルまたはサムプリントで署名証明書が検索され、秘密鍵ハンドルが準備されます。バイトはトークンを離れません — 実際の RSA-PSS または ECDSA 署名はデバイス上で行われます。
var vKeyProvider: TsgcPKCS11KeyProvider; begin vKeyProvider := TsgcPKCS11KeyProvider.Create(nil); try vKeyProvider.ModulePath := 'C:\Windows\System32\eTPKCS11.dll'; vKeyProvider.Slot := 0; vKeyProvider.CertificateLabel := 'My Signing Cert'; vKeyProvider.OnPinPrompt := procedure(Sender: TObject; var aPIN: string) begin aPIN := InputBox('Smart card', 'PIN:', ''); end; vKeyProvider.LoadFromToken; // vKeyProvider is now ready to sign finally // keep alive until signing finishes, then Free end; end;
証明書がすでに Windows ストアにインストールされている場合 — 例えば、ベンダーのミニドライバー付きの適格 eID カードを使用している場合 — は、代わりに TsgcWindowsStoreKeyProvider を使用してください。プロバイダーは CNG と通信するため、元の CSP に関係なく SHA-256/SHA-384 が動作します。
サブジェクト、サムプリント、シリアル番号で照合します。StoreLocation を slCurrentUser に設定すると個人ストアを使用、slLocalMachine はマシンストアを使用し、通常管理者権限を必要とします。
var vKeyProvider: TsgcWindowsStoreKeyProvider; begin vKeyProvider := TsgcWindowsStoreKeyProvider.Create(nil); vKeyProvider.StoreLocation := slCurrentUser; vKeyProvider.StoreName := 'MY'; vKeyProvider.Thumbprint := '1234ABCD5678EF901234567890ABCDEF12345678'; vKeyProvider.LoadFromStore; end;
PAdES-B-T は署名に RFC 3161 タイムスタンプを追加するため、検証者は — 署名証明書が後に失効または取り消された場合でも — ドキュメントが既知の時点より前に署名されたことを証明できます。
Level は AdES レベルを選択します — palB、palT、palLT または palLTA。PAdES-B-T には palT を設定。プロファイルは空でない TSA.URL を期待します。
HashAlgorithm はデフォルトで shaSHA256 で、すべてのモダンな検証者が期待するものです。SHA-384 と SHA-512 も利用可能。eIDAS がもはや受け付けないため SHA-1 は意図的に提供されません。
SignatureField サブオブジェクトは、PDF 内のどこに可視署名ウィジェットを配置するかを制御します — ページ番号、矩形座標、オプションの理由/場所/連絡先テキストフィールド。不可視署名(デフォルト)には空のままにしてください。
var vProfile: TsgcSignProfile_PAdES; begin vProfile := TsgcSignProfile_PAdES.Create(nil); vProfile.Level := palT; vProfile.HashAlgorithm := shaSHA256; // RFC 3161 timestamp authority vProfile.TSA.URL := 'http://timestamp.digicert.com'; vProfile.TSA.HashAlgorithm := shaSHA256; // Optional visible signature widget vProfile.SignatureField.Visible := True; vProfile.SignatureField.Page := 1; vProfile.SignatureField.Rect := Rect(50, 50, 250, 120); vProfile.SignatureField.Reason := 'Approved'; vProfile.SignatureField.Location := 'Madrid'; end;
鍵プロバイダーとプロファイルを TsgcSignPDF に結線し、入力と出力のファイル名で SignFile を呼び出します。
SignFile は入力 PDF を読み、ドキュメントダイジェストを計算し、鍵プロバイダーを呼んで署名を生成し、TSA からタイムスタンプを取得し、結果を書き出します。入力にすでに署名が含まれている場合、sgcSign は増分更新を追加します — 元の署名は有効なまま残ります。
OnProgress イベントは各フェーズ(reading、hashing、signing、timestamping、writing)を報告するため、複数 MB のファイルでプログレスバーに便利です。
var vSigner: TsgcSignPDF; begin vSigner := TsgcSignPDF.Create(nil); try vSigner.KeyProvider := vKeyProvider; vSigner.Profile := vProfile; vSigner.OnProgress := procedure(Sender: TObject; const aPhase: string; aPct: Integer) begin Memo1.Lines.Add(Format('%s — %d%%', [aPhase, aPct])); end; vSigner.SignFile('invoice.pdf', 'invoice-signed.pdf'); finally vSigner.Free; end; end;
署名済みドキュメントは検証できて初めて有用です。TsgcSignatureVerifier は 1 回の呼び出しで暗号署名、証明書チェーン、組み込みタイムスタンプを検証します。
VerifyFile メソッドは署名ごとの内訳を持つ TsgcSignatureReport を返します。各エントリには Status(svValid、svInvalid、svUnknown)、署名者サブジェクト、実際に検出された AdES レベル、タイムスタンプ値、チェーンや失効問題が含まれます。
Report.Level を期待するレベルと比較してください — palT を望んだので、palB を報告する検証は、タイムスタンプ要求が静かに失敗したことを意味します。通常の容疑者は TSA URL です。
var vVerifier: TsgcSignatureVerifier; vReport: TsgcSignatureReport; i: Integer; begin vVerifier := TsgcSignatureVerifier.Create(nil); try vReport := vVerifier.VerifyFile('invoice-signed.pdf'); for i := 0 to vReport.SignatureCount - 1 do begin Memo1.Lines.Add('Signer: ' + vReport.Signatures[i].Subject); Memo1.Lines.Add('Level: ' + vReport.Signatures[i].LevelAsString); Memo1.Lines.Add('Status: ' + vReport.Signatures[i].StatusAsString); Memo1.Lines.Add('TSA time: ' + DateTimeToStr(vReport.Signatures[i].TimestampUTC)); end; finally vVerifier.Free; end; end;
開発者が最初の PAdES ドキュメントに署名するときに最もよく見る問題の短いリスト。
一部の TSA は HTTPS 専用で、平文の http:// URL をソフトエラーで拒否します。palT を要求したのに Report.Level が palB として戻る場合、TSA URL を https:// 相当に切り替えてください。ほとんどの公開 TSA は両方のスキームを公開しています。
テスト証明書はしばしば id-kp-documentSigning EKU を欠きます。暗号署名が有効でも、Adobe Reader は警告を表示します。本番には CA から明示的なドキュメント署名 EKU を持つ証明書を要求してください。
PDF/A-2 と PDF/A-3 アーカイブは、すべての失効情報をドキュメント自体に埋め込むことを要求します。palLT または palLTA を使用 — sgcSign は署名時に OCSP 応答と CRL を収集し、DSS 辞書に埋め込みます。
一部の PKCS#11 ドライバーは数秒の非活動後にセッションを閉じます。署名操作全体の間 TsgcPKCS11KeyProvider インスタンスを生かしておき、SignFile が戻った後にのみ Free を呼んでください。
長期アーカイブ、国別プロファイル、または署名をデスクトップから集中サーバーへ移行。
VeriFactu、FatturaPA、KSeF、FACTUR-X、EU 雇用契約プロファイル向けのワンライナー — すべて同じ PAdES / XAdES エンジンの上に構築されています。
続きを読む →署名をセルフホスト型デーモンに移行 — PAdES の上の REST API、GitHub Actions 統合、Authenticode、ClickOnce。
続きを読む →PFX と Windows ストアを超えて — Azure Trusted Signing、AWS KMS、Google KMS、HashiCorp Vault、Certum、CSC v2 クラウドプロバイダー。
続きを読む →