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 토큰에서 서명자 인증서와 개인 키를 해석한 뒤, 토큰을 통해 SignerInfo 서명을 만드는 ICmsSigner를 가진 TPadesResolvedSigner를 반환하므로 키는 절대 토큰을 떠나지 않습니다
모듈은 실행 시점에 경로로 로드됩니다. opensc-pkcs11.so, libsofthsm2.so, 벤더 DLL 같은 것입니다. 빌드 시점에 링크되는 것은 없고 모듈이 없으면 치명적 오류 대신 보고됩니다. 이름으로 해석되는 것은 C_GetFunctionList뿐이고 나머지 엔트리 포인트는 그것이 돌려주는 함수 테이블에서 얻는데, 이것이 표준이 의도한 모듈 접근 방식입니다
ConfigurePkcs11SignerProvider는 TPdfPkcs11Options 값으로 TPdfPkcs11SignerProvider를 만들어 활성 PAdES 서명자 백엔드로 설치하고, 토큰 열거 메서드까지 함께 갖고 있는 IPdfPkcs11SignerProvider 인터페이스를 반환합니다
Pkcs11ModuleAvailable과 Pkcs11ModuleVersion은 주어진 모듈이 로드되어 쓸 수 있는 함수 테이블을 노출하는지 보고하므로, 애플리케이션은 시작 시 이 머신에서 토큰 서명이 가능한지 판단할 수 있습니다. 로드된 모듈은 경로별로 캐싱됩니다. 표준은 모듈당 프로세스당 초기화를 하나만 허용하기 때문입니다
Resolve는 썸프린트가 주어지면 TPadesSignerOptions.CertificateThumbprint로, 아니면 CertificateLabel로 인증서를 고른 뒤 인증서와 같은 토큰 식별자를 지닌 개인 키 객체를 찾습니다. 인증서 키 알고리즘이 알고리즘 계열을 결정합니다. EC 키는 ECDSA로 서명하고 raw 서명을 CMS가 기대하는 DER SEQUENCE로 다시 인코딩하며, RSA 키는 요청된 패딩 방식을 따릅니다
EnumerateSlots와 EnumerateCertificates는 선택 UI를 위한 것으로, 어떤 서명 옵션도 고정하기 전에 애플리케이션이 모듈이 보고하는 슬롯과 선택한 슬롯이 담은 인증서를 나열하게 해줍니다
| Function | Description |
|---|---|
Pkcs11ModuleAvailable | 주어진 경로의 모듈이 로드되어 쓸 수 있는 함수 테이블을 노출하면 True를 반환합니다 |
Pkcs11ModuleVersion | 모듈이 보고하는 버전 문자열을 반환하고, 모듈이 로드되지 않으면 빈 문자열을 반환합니다 |
Pkcs11AbiLayout | 이 빌드가 해석한 ABI 배치를 ulong=<n> attr=<n> pss=<n> table=<n> 형태로 반환합니다 |
ConfigurePkcs11SignerProvider | 전달된 옵션으로 공급자를 만들어 PAdES 서명자 백엔드로 설치하고 IPdfPkcs11SignerProvider로 반환합니다 |
| Type | Purpose |
|---|---|
EPdfPkcs11Error | 모듈 경로가 구성되지 않았거나, 모듈을 로드할 수 없거나, 토큰 호출이 실패하거나, 일치하는 인증서나 개인 키를 찾지 못했을 때 발생하는 예외입니다 |
TPdfPkcs11Options | 공급자가 다룰 모듈, 슬롯, PIN, 인증서를 지정하는 레코드입니다 |
TPdfPkcs11SignerProvider | PKCS#11 모듈 위에서 IPadesSignerProvider와 IPdfPkcs11SignerProvider를 구현하는 공급자 클래스입니다 |
| Field | Description |
|---|---|
ModulePath | PKCS#11 모듈의 경로입니다. 필수 값입니다. 어떤 모듈이 토큰을 담당할지는 배포 판단 사항이고 쓸 만한 기본값이 없습니다 |
SlotId | 열 토큰 슬롯이며 UseSpecificSlot이 True일 때만 존중됩니다 |
UseSpecificSlot | False로 두면 토큰이 있다고 보고하는 첫 슬롯을 사용합니다 |
Pin | 사용자 PIN입니다. 공급자는 토큰이 소비한 뒤 자신의 사본을 지우지만, 넘긴 문자열의 수명은 호출자가 계속 책임집니다 |
CertificateLabel | 서명에 쓸 인증서의 선택적 객체 레이블이며 TPadesSignerOptions.CertificateThumbprint가 비어 있을 때만 사용됩니다 |
Default | 빈 모듈 경로, 슬롯 0, 자동 슬롯 선택, PIN과 레이블 없음을 가진 옵션을 반환하는 static 팩토리입니다 |
| Member | Description |
|---|---|
Create | TPdfPkcs11Options 값으로 공급자를 구성합니다. 모듈 자체는 첫 사용 시 열립니다 |
Destroy | 인스턴스가 해제되기 전에 열려 있는 토큰 세션을 닫습니다 |
BackendName | 백엔드 이름을 반환하며, 모듈 경로가 구성되어 있으면 모듈 파일 이름을 덧붙입니다 |
Resolve | TPadesSignerOptions를 토큰 서명자와 서명자 인증서 DER을 담은 TPadesResolvedSigner로 해석합니다 |
EnumerateSlots | 모듈이 보고하는 모든 슬롯을 TPdfPkcs11Slots로 반환합니다. 토큰이 없는 슬롯도 포함됩니다 |
EnumerateCertificates | 한 슬롯이 담은 인증서를 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도 없으면 토큰의 첫 인증서가 선택됩니다. 인증서 하나짜리 토큰에는 맞지만 프로덕션 배포에는 맞지 않습니다