署名用証明書が期限切れになりCAが交代した何年も後でも署名付きPDFを検証できるように、PDFiumコンポーネントはWindows上で長期PAdES署名を作成できます。信頼できる時刻のためのRFC 3161タイムスタンプ、検証資料を埋め込むドキュメントセキュリティストア(DSS)、およびファイル全体をカバーするアーカイブDocTimeStampです。これら3つの追加要素がPAdESのB-T、B-LT、およびB-LTA基準レベルであり、PDFiumコンポーネントは1回の署名呼び出しでこれらすべてに対応します。これはWindowsのみの機能であり、PadesCryptoAvailableによって制限されます
この記事はシリーズの3番目の記事です。最初の記事であるPDFium VCLを使用したPAdES B-BによるPDF署名では基本署名について説明し、2番目の記事であるPDFデジタル署名とPAdESレベルの検査では署名の読み戻しと到達したレベルの判定について説明しました。ここではアーカイブについて取り上げます。証明書の有効期限が切れた後も存続し、週単位ではなく年単位で測定される保持期間中検証可能な状態を維持しなければならない署名です
なぜ有効なPDF署名が時間の経過とともに検証できなくなるのか
基本署名は、署名後にこれらのバイトが変更されたかどうかという1つの疑問にのみ答えます。それ自体では、署名がいつ行われたかを証明することはできず、このギャップが後に検証を破綻させる原因となります。CMS構造には署名時刻属性が含まれていますが、署名者は独自の時計からその値を書き込むため、バリデータにはそれを信頼する理由がありません。後に署名証明書の期限が切れるかCAがそれを失効させた場合、厳格なバリデータは、証明書が有効な间に行われた署名と、期限切れ後に偽造された署名を区別できなくなります。署名は作成された日には問題なかったものの、自身の非によらず検証不可能になってしまいます
長期アーカイブは、2つのステップでこれを解決します。第一に、信頼できる第三者機関であるタイムスタンプ局(TSA)が時刻を暗号的に証明するため、署名者の誠実さに依存しなくなります。第二に、信頼チェーンを構築してチェックするために必要なすべての証明書、失効応答、およびCRLがPDF自体の中に埋め込まれるため、検証時にすでに存在しない可能性のあるサーバーに依存しなくなります。ETSI EN 319 142-1として標準化されているPAdESは、これらを実行レベルとして階層化しており、PDFiumコンポーネントは各レベルが必要とする構造を書き込みます
PAdESは互いに積み重なる4つの基準レベルを定義しており、PDFiumコンポーネントはそれらをTPadesLevel列挙型(plB_B, plB_T, plB_LT, plB_LTA)を通じて公開しています。B-Bはプレーンな署名です。B-Tは署名値の上に信頼されたタイムスタンプを追加します。B-LT(長期)は、多くの人が「LTV」と呼んでいる埋め込み検証資料を追加します。B-LTA(長期アーカイブタイムスタンプ付き)は、すべてをファイル全体をカバーするもう1つのタイムスタンプでラップするため、埋め込まれた資料自体がアーカイブの瞬間から変更されていないことが証明可能になります
実用的な解釈は階段のようなものです。B-Tは「いつ」を証明します。B-LTは「何を使って」署名を検証できるかを証明します。B-LTAは、封印されてからパッケージ全体が改ざんされていないことを証明します。これは、前のタイムスタンプが期限切れになる前に新しいDocTimeStampを追加して更新し、アーカイブを無期限に延長できるレベルです。長期の保持義務がある契約書やコンプライアンス記録の場合、B-LTAが目標になり、B-LTが実用的な最低ラインになります
信頼できる時刻の追加:RFC 3161によるPAdES B-T
PDFiumコンポーネントは、TPadesSignOptionsの2つのフィールドを設定することで、B-B署名をB-Tに変換します。LevelをplB_Tに引き上げ、TsaUrlを指定します。両方が存在する場合、署名パイプラインは生の署名オクテットをSHA-256でハッシュ化し、そのダイジェストをRFC 3161のmessageImprintとしてパッケージ化し、WinHttp経由でTSAにリクエストをPOSTし、返されたトークンをEN 319 142-1 §6.3に準拠してSignerInfoのunsignedAttrs [1]内にsignature-time-stamp署名なし属性(OID 1.2.840.113549.1.9.16.2.14)として埋め込みます。タイムスタンプは特に署名値をカバーするため、信頼できる時刻がまさにその署名に関連付けられます
uses
PDFium, FPdfPades;
procedure SignWithTimestamp;
var
Pdf: TPdf;
Options: TPadesSignOptions;
begin
Pdf := TPdf.Create(nil);
try
if not Pdf.PadesCryptoAvailable then
raise Exception.Create('PAdES signing backend is Windows-only');
Pdf.FileName := 'contract.pdf';
Pdf.Active := True;
Options := TPadesSignOptions.Default;
Options.CertificateThumbprint := 'A1B2C3D4E5F6071829304152637485960A1B2C3D';
Options.Level := plB_T;
Options.TsaUrl := 'http://timestamp.example-tsa.com/tsr';
Options.Reason := 'Contract execution';
// Nonce left at 0: the component derives a unique anti-replay value.
Pdf.SignPades('contract-bt.pdf', Options);
finally
Pdf.Free;
end;
end;
CertificateThumbprintは、使用可能な秘密鍵を持つ「現在のユーザー」の「個人(MY)」ストア内にある証明書のSHA-1ハッシュ(16進数)です。NonceフィールドはRFC 3161のリプレイ防止値です。これをゼロのままにしておくと、コンポーネントはカウンター、時計、ティックカウント、およびプロセスIDのSHA-256折りたたみからリクエストごとに一意の値を導出するため、同じミリ秒に発行された2つのリクエストが衝突することはありません。信頼できる暗号化RNGがある場合にのみ、独自の値を渡してください。注意点として、B-Tには接続可能なTSAが必要であるため、署名時に网络呼び出しが発生し、TSAの可用性とレイテンシの影響を受けます
検証資料の埋め込み:B-LTとB-LTAを1回の呼び出しで
長期検証への移行は、LevelをplB_LTAに設定し、TsaUrlを維持するという単一の変更のみです。PDFiumコンポーネントは、1回のSignPades呼び出しで全段階を実行します。B-Bに署名し、B-T用のタイムスタンプを設定し、B-LT用のドキュメントセキュリティストアを注入し、B-LTA用のアーカイブタイムスタンプを追加します。それぞれが独自の増分更新として実行されるため、それ以前のバイトデータはバイト単位で完全に保持されます
procedure SignForArchive;
var
Pdf: TPdf;
Options: TPadesSignOptions;
begin
Pdf := TPdf.Create(nil);
try
Pdf.FileName := 'contract.pdf';
Pdf.Active := True;
Options := TPadesSignOptions.Default;
Options.CertificateThumbprint := 'A1B2C3D4E5F6071829304152637485960A1B2C3D';
Options.Level := plB_LTA; // drives B-B -> B-T -> B-LT -> B-LTA
Options.TsaUrl := 'http://timestamp.example-tsa.com/tsr';
Options.Location := 'Head Office';
// One call writes the timestamp, the DSS and the archive DocTimeStamp.
Pdf.SignPades('contract-lta.pdf', Options);
finally
Pdf.Free;
end;
end;
B-LT段階において、PDFiumコンポーネントはCertGetCertificateChainで証明書チェーンを構築し、EN 319 142-1 §5.4.2の規定通り、署名者証明書と/Certs配列内のすべての中間CA(および並行する/OCSPsと/CRLs配列)を保持する/DSS辞書を、レベル1の/Extensions /ESICマーカーとともに書き込みます。自己署名ルートは、RFC 5652 §10.2.3で許可されており、バリデータが保持している信頼アンカーであるため、意図的に除外されます。結果として、リーダーが手元のファイルだけで検証できる署名が完成します
B-LTAの場合、コンポーネントはドキュメントタイムスタンプ(/ByteRangeがファイル全体をカバーし、/Contentsがその範囲にわたるRFC 3161トークンを保持する/SubFilter /ETSI.RFC3161を持つ署名辞書)を追加し、ESICマーカーをレベル2に昇格させます。これは、§5.4.3およびTS 119 142-3で定義されているアーカイブステップです。DocTimeStampは署名だけでなくDSSもカバーするため、埋め込まれた検証資料がアーカイブ時に存在し、改ざんされていなかったことを証明します。これこそが、長期保持ポリシーが示すべき内容そのものです
既存の署名の拡張
外部のB-B署名をアーカイブ用にB-LTに引き上げる場合など、すでにドキュメントに署名が存在し、検証ストアの追加または更新のみが必要な場合があります。PDFiumコンポーネントは、SaveAsPadesDssを介してDSSインジェクターを直接公開しており、既存の署名バイトを変更することなく、/DSSおよび/Extensions構造を増分更新として追加します
procedure AddValidationStore;
var
Pdf: TPdf;
DssOpts: TPadesDssOptions;
Cert: TPadesDssMaterial;
begin
Pdf := TPdf.Create(nil);
try
Pdf.FileName := 'already-signed.pdf';
Pdf.Active := True;
DssOpts := TPadesDssOptions.Default;
DssOpts.EsicExtensionLevel := 1; // 1 for B-LT, 2 for B-LTA
Cert.DerBytes := LoadSignerCertDer; // your DER-encoded certificate
SetLength(DssOpts.Certs, 1);
DssOpts.Certs[0] := Cert;
Pdf.SaveAsPadesDss('already-signed-lt.pdf', DssOpts);
finally
Pdf.Free;
end;
end;
バリデータが必要とするDERエンコードされた証明書、およびオプションでOCSP応答とCRLを提供します。B-LTストアの場合はEsicExtensionLevelを1に設定し、DocTimeStampが続く場合は2に設定します。IncludeVriはデフォルトのFalseのままにしておきます。EN 319 142-1 §5.4.2.3は署名ごとの/VRI辞书をオプションとして扱っており、ターゲットとする特定のリーダーが要求しない限り使用しないことを推奨しています
考慮すべきコストと制限事項
これら各レベルの適合範囲を決定する3つの実質的な制限があります。第一に、暗号化バックエンドはWindows専用です。署名とタイムスタンプの設定はプラットフォームのCNGおよびWinHttpストアを経由するため、他の環境ではPadesCryptoAvailableがFalseを返し、SignPadesが例外を発生させます。解説記事で説明した読み取り側の検査はクロスプラットフォームで維持されますが、署名の書き込みのみがWindowsに依存します。第二に、B-TとB-LTAはタイムスタンプ局(TSA)に依存します。これは、署名時にネットワークのラウンドトリップが発生すること、および外部サービスの稼働状況やレート制限が署名処理の一部になることを意味します
第三に、各レベルでストレージコストが発生します。すべてのステージはファイルを書き換えるのではなく増分更新を追加し、DSSは完全な証明書チェーンを埋め込み、アーカイブDocTimeStampはそのトークン用のスペースを予約するため、B-LTAファイルは元のB-Bファイルよりも著しく大きくなります。これは意図的なトレードオフです。将来の検証可能性を購入するために、今バイト数を消費します。ほとんどの契約書やコンプライアンスのアーカイブにおいて、これは適切な選択ですが、仮定に頼るのではなく、実際のドキュメントで測定する価値があります。作成されたファイルが意図したレベルに実際に達しているか確認する必要がある場合は、PDFデジタル署名とPAdESレベルの検査で紹介した手法で検証してください。また、ドキュメントパイプラインをより広範囲に保護する場合は、PDFセキュリティリスクの監査に関する注意書きで関連するチェックについて説明しています
ここで紹介したPAdES署名、DSS、およびアーカイブタイムスタンプ機能は、製品ページに完全な署名リファレンスとプラットフォーム要件が掲載されている、DelphiおよびC++Builder用のPDFiumコンポーネントの一部です