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 ist das portable PAdES-Signatur-Backend und das Gegenstück zum Windows-CNG-Backend. Es löst ein Signer-Zertifikat samt Private Key aus einem PKCS#11-Token auf und gibt einen TPadesResolvedSigner zurück, dessen ICmsSigner die SignerInfo-Signatur durch das Token erzeugt, sodass der Schlüssel es nie verlässt
Das Modul wird zur Laufzeit per Pfad geladen - opensc-pkcs11.so, libsofthsm2.so, eine Vendor-DLL - nichts wird zur Build-Zeit gelinkt, und ein fehlendes Modul wird gemeldet, statt fatal zu enden. Nur C_GetFunctionList wird namenbasiert aufgelöst; alle anderen Einstiegspunkte stammen aus der Funktionstabelle, die es zurückgibt - so ist es vom Standard vorgesehen
ConfigurePkcs11SignerProvider baut aus einem TPdfPkcs11Options-Wert einen TPdfPkcs11SignerProvider und installiert ihn als aktives PAdES-Signer-Backend, zurück kommt das IPdfPkcs11SignerProvider-Interface, das auch die Token-Aufzählungsmethoden mitbringt
Pkcs11ModuleAvailable und Pkcs11ModuleVersion melden, ob ein gegebenes Modul lädt und eine brauchbare Funktionstabelle vorweist, sodass eine Anwendung beim Start entscheiden kann, ob Token-Signierung auf dieser Maschine möglich ist. Geladene Module werden nach Pfad zwischengespeichert, denn der Standard erlaubt nur eine Initialisierung pro Prozess und Modul
Resolve wählt das Zertifikat über TPadesSignerOptions.CertificateThumbprint, wenn einer übergeben wurde, sonst über CertificateLabel, und sucht dann das Private-Key-Objekt, das denselben Token-Bezeichner trägt wie das Zertifikat. Der Schlüsselalgorithmus des Zertifikats bestimmt die Algorithmusfamilie: Ein EC-Schlüssel signiert mit ECDSA, und seine Rohsignatur wird in die DER-SEQUENCE umkodiert, die CMS erwartet; ein RSA-Schlüssel folgt dem angeforderten Padding-Schema
EnumerateSlots und EnumerateCertificates dienen Auswahl-Oberflächen: Sie lassen eine Anwendung die Slots auflisten, die ein Modul meldet, und die Zertifikate, die ein gewählter Slot hält, bevor eine Signaturoption festgelegt wird
| Funktion | Beschreibung |
|---|---|
Pkcs11ModuleAvailable | Gibt True zurück, wenn das Modul am angegebenen Pfad lädt und eine brauchbare Funktionstabelle vorweist |
Pkcs11ModuleVersion | Gibt die vom Modul gemeldete Versionszeichenkette zurück, oder einen leeren String, wenn das Modul nicht lädt |
Pkcs11AbiLayout | Gibt das von diesem Build aufgelöste ABI-Layout zurück, als ulong=<n> attr=<n> pss=<n> table=<n> |
ConfigurePkcs11SignerProvider | Baut aus den übergebenen Optionen einen Provider, installiert ihn als PAdES-Signer-Backend und gibt ihn als IPdfPkcs11SignerProvider zurück |
| Typ | Zweck |
|---|---|
EPdfPkcs11Error | Exception, die ausgelöst wird, wenn kein Modulpfad konfiguriert ist, das Modul nicht geladen werden kann, ein Token-Aufruf fehlschlägt oder kein passendes Zertifikat beziehungsweise kein passender Private Key gefunden wird |
TPdfPkcs11Options | Record, der Modul, Slot, PIN und Zertifikat benennt, mit denen der Provider arbeitet |
TPdfPkcs11SignerProvider | Provider-Klasse, die IPadesSignerProvider und IPdfPkcs11SignerProvider auf einem PKCS#11-Modul implementiert |
| Feld | Beschreibung |
|---|---|
ModulePath | Pfad zum PKCS#11-Modul; erforderlich, denn welches Modul einen Token bedient, ist eine Deployment-Entscheidung, und einen brauchbaren Standardwert gibt es nicht |
SlotId | Zu öffnender Token-Slot, wird nur beachtet, wenn UseSpecificSlot True ist |
UseSpecificSlot | Auf False lassen, um den ersten Slot zu nehmen, der einen Token vorweist |
Pin | Benutzer-PIN; der Provider löscht seine eigene Kopie, sobald der Token sie verbraucht hat, und für die Lebensdauer des übergebenen Strings bleibt der Aufrufer verantwortlich |
CertificateLabel | Optionales Objekt-Label des Zertifikats, mit dem signiert wird; wird nur verwendet, wenn TPadesSignerOptions.CertificateThumbprint leer ist |
Default | Statische Fabrik, die Optionen mit leerem Modulpfad, Slot 0, automatischer Slot-Auswahl und ohne PIN oder Label liefert |
| Member | Beschreibung |
|---|---|
Create | Konstruiert den Provider aus einem TPdfPkcs11Options-Wert; das Modul selbst wird bei der ersten Nutzung geöffnet |
Destroy | Schließt eine offene Token-Session, bevor die Instanz freigegeben wird |
BackendName | Gibt den Backend-Namen zurück, ergänzt um den Moduldateinamen, wenn ein Modulpfad konfiguriert ist |
Resolve | Löst TPadesSignerOptions in einen TPadesResolvedSigner auf, der Token-Signer und Signer-Zertifikats-DER enthält |
EnumerateSlots | Liefert jeden Slot, den das Modul meldet, als TPdfPkcs11Slots, einschließlich Slots ohne Token |
EnumerateCertificates | Liefert die Zertifikate eines Slots als TPdfPkcs11Certificates und öffnet zuvor eine Session auf diesem Slot |
CloseProtectedSessions | Meldet sich dort ab, wo eine Anmeldung erfolgte, und schließt die offene Session, um den Token für andere Konsumenten freizugeben |
CK_ULONG folgt dem C-unsigned long, ist also unter Windows (LLP64) 4 Bytes und unter Linux und macOS (LP64) 8 Bytes groß; jedes Handle, jede Anzahl und jeder Attributtyp ist ein CK_ULONGPkcs11AbiLayout meldet das von diesem Build aufgelöste Layout, sodass eine Abweichung diagnostizierbar ist, statt still zum Absturz zu führen: Win32 meldet ulong=4 attr=12 pss=12 table=2, Win64 meldet ulong=4 attr=16 pss=12 table=2, und ein LP64-Ziel meldet ulong=8 attr=24 pss=24 table=8CertificateLabel gewinnt das erste Zertifikat auf dem Token - das passt für einen Token mit einem einzigen Zertifikat, aber nicht für eine Produktionsumgebung