EPdfPkcs11Error = class(Exception);
TPdfPkcs11Options = record
ModulePath: string;
SlotId: UInt64;
UseSpecificSlot: Boolean;
Pin: string;
CertificateLabel: string;
class function Default: TPdfPkcs11Options; static;
end;
TPdfPkcs11SignerProvider = class(TInterfacedObject, IPadesSignerProvider,
IPdfPkcs11SignerProvider)
constructor Create(const Options: TPdfPkcs11Options);
destructor Destroy; override;
function BackendName: string;
function Resolve(const Options: TPadesSignerOptions): TPadesResolvedSigner;
function EnumerateSlots: TPdfPkcs11Slots;
function EnumerateCertificates(SlotID: UInt64): TPdfPkcs11Certificates;
procedure CloseProtectedSessions;
end;
function Pkcs11ModuleAvailable(const ModulePath: string): Boolean;
function Pkcs11ModuleVersion(const ModulePath: string): string;
function Pkcs11AbiLayout: string;
function ConfigurePkcs11SignerProvider(
const Options: TPdfPkcs11Options): IPdfPkcs11SignerProvider;
FPdfPkcs11 はポータブルな PAdES 署名バックエンドで、Windows の CNG バックエンドと対になる存在です。PKCS#11 トークンから署名者証明書とその秘密鍵を解決し、その ICmsSigner がトークンを通じて SignerInfo の署名を生成する TPadesResolvedSigner を返します。鍵がトークンの外に出ることはありません
モジュールは実行時にパスで読み込まれます。opensc-pkcs11.so、libsofthsm2.so、ベンダーの DLL などです。ビルド時には何もリンクされず、モジュールが存在しないことは致命的ではなく報告されます。名前で解決されるのは C_GetFunctionList だけです。それ以外のエントリポイントはすべて、その関数が返す関数テーブルから取られます。これは標準がモジュールへの到達方法として意図する形です
ConfigurePkcs11SignerProvider は TPdfPkcs11Options の値から TPdfPkcs11SignerProvider を構築してアクティブな PAdES 署名バックエンドとして登録し、トークン列挙メソッドも備えた IPdfPkcs11SignerProvider インターフェイスを返します
Pkcs11ModuleAvailable と Pkcs11ModuleVersion は、指定したモジュールが読み込まれて利用可能な関数テーブルを公開するかどうかを報告します。アプリケーションは起動時にこのマシンでトークン署名が可能かを判断できます。読み込まれたモジュールはパス単位でキャッシュされます。標準はモジュールごとにプロセスあたり 1 回の初期化しか許さないためです
Resolve は、指定されていれば TPadesSignerOptions.CertificateThumbprint で、そうでなければ CertificateLabel で証明書を選び、証明書と同じトークン識別子を持つ秘密鍵オブジェクトを特定します。証明書の鍵アルゴリズムがアルゴリズム族を決めます。EC 鍵は ECDSA で署名し、その生の署名は CMS が期待する DER SEQUENCE に再エンコードされます。RSA 鍵は要求されたパディング方式に従います
EnumerateSlots と EnumerateCertificates は選択用ユーザーインターフェイスのためのものです。署名オプションを固定する前に、アプリケーションはモジュールが報告するスロットや、選んだスロットが保持する証明書を一覧できます
| 関数 | 説明 |
|---|---|
Pkcs11ModuleAvailable | 指定されたパスのモジュールが読み込まれ、利用可能な関数テーブルを公開するときに True を返します |
Pkcs11ModuleVersion | モジュールが報告するバージョン文字列を返します。モジュールが読み込めない場合は空文字列です |
Pkcs11AbiLayout | このビルドが解決した ABI レイアウトを ulong=<n> attr=<n> pss=<n> table=<n> の形で返します |
ConfigurePkcs11SignerProvider | 指定されたオプションからプロバイダを構築して PAdES 署名バックエンドとして登録し、IPdfPkcs11SignerProvider として返します |
| 型 | 目的 |
|---|---|
EPdfPkcs11Error | モジュールパスが設定されていない、モジュールを読み込めない、トークン呼び出しが失敗した、一致する証明書や秘密鍵が見つからない、といった場合に発生する例外です |
TPdfPkcs11Options | プロバイダが扱うモジュール、スロット、PIN、証明書を名指しするレコードです |
TPdfPkcs11SignerProvider | PKCS#11 モジュールの上に IPadesSignerProvider と IPdfPkcs11SignerProvider を実装するプロバイダクラスです |
| フィールド | 説明 |
|---|---|
ModulePath | PKCS#11 モジュールのパスです。必須です。どのモジュールがトークンを提供するかはデプロイの判断事項であり、有用な既定値はありません |
SlotId | 開くトークンスロットです。UseSpecificSlot が True のときのみ尊重されます |
UseSpecificSlot | False のままにすると、トークンが存在すると報告した最初のスロットを使います |
Pin | ユーザー PIN です。プロバイダはトークンが消費した後で自分のコピーをクリアします。渡された文字列自体の寿命は呼び出し側の責任です |
CertificateLabel | 署名に使う証明書のオブジェクトラベル (省略可) です。TPadesSignerOptions.CertificateThumbprint が空のときのみ使われます |
Default | モジュールパスが空、スロット 0、スロット自動選択、PIN とラベルなしのオプションを返す静的ファクトリです |
| メンバー | 説明 |
|---|---|
Create | TPdfPkcs11Options の値からプロバイダを構築します。モジュール自体は最初の使用時に開かれます |
Destroy | インスタンスを解放する前に、開いているトークンセッションがあれば閉じます |
BackendName | バックエンド名を返します。モジュールパスが設定されていればモジュールのファイル名が末尾に付きます |
Resolve | TPadesSignerOptions を、トークン署名者と署名者証明書の DER を含む TPadesResolvedSigner に解決します |
EnumerateSlots | モジュールが報告するすべてのスロットを TPdfPkcs11Slots として返します。トークンが存在しないスロットも含みます |
EnumerateCertificates | 1 つのスロットが保持する証明書を TPdfPkcs11Certificates として返します。そのスロットで先にセッションを開きます |
CloseProtectedSessions | ログインした場所でログアウトし、開いているセッションを閉じて、トークンを他の利用者に解放します |
CK_ULONG は C の unsigned long に従うため、Windows (LLP64) では 4 バイト、Linux と macOS (LP64) では 8 バイトです。すべてのハンドル、カウント、属性型が CK_ULONG ですPkcs11AbiLayout はこのビルドが解決したレイアウトを報告します。不一致がサイレントなクラッシュではなく診断可能になります。Win32 は ulong=4 attr=12 pss=12 table=2、Win64 は ulong=4 attr=16 pss=12 table=2、LP64 ターゲットは ulong=8 attr=24 pss=24 table=8 を報告しますCertificateLabel もなければ、トークンの最初の証明書が使われます。証明書が 1 つだけのトークンには向きますが、実運用のデプロイには向きません