Signing PDF Documents with a Certificate from an HSM
Requirements: SecureBlackbox or Secure PDF
Introduction
Customers often ask whether our components can be used to access hardware security module (HSM)–based X.509 certificates, such as those from smart cards, Personal Identity Verification (PIV) cards, or USB tokens to eventually sign data with them. The good news is that this functionality is fully supported, particularly for signing PDF documents, in the appropriate components:
- CertificateStorage and PDFSigner in SecureBlackbox, and
- CertMgr and PDFSign in Secure PDF.
This article provides guidance on configuring these components, ensuring secure and compliant digital signing workflows.
Contents
SecureBlackbox
First, use the following CertificateStorage code to extract the certificates from the HSM through the PKCS#11 interface:
CertificateStorage storage = new CertificateStorage();
// Opening the storage
storage.Open("pkcs11://user:pin@/c:/path/to/driver.dll");
Certificate signingCert = null;
// Iterating through the certificates
for (int i = 0; i < storage.Certificates.Count; i++)
{
Certificate cert = storage.Certificates[i];
Console.WriteLine("Certificate " + (i + 1).ToString() + ": " + cert.SubjectRDN);
// Saving the first certificate with a private key
if (cert.PrivateKeyExists)
{
signingCert = cert;
break;
}
}
To access the certificates stored on the hardware device, you will need to open it by providing the PKCS#11 URI as a parameter to the Open method. This URI includes the token's credentials (user:pin) and the path to the PKCS#11 driver library. If the storage is opened successfully, the Certificates collection will be populated with the certificates from the HSM.
Once the desired certificate has been imported and saved, you are ready to sign using PDFSigner:
PDFSigner signer = new PDFSigner();
signer.InputFile = "sample.pdf";
signer.OutputFile = "signed.pdf";
signer.SigningCertificate = signingCert;
signer.Sign();
// Closing the storage
storage.Close(false);
Secure PDF
With CertMgr, an event-based approach is used to retrieve the desired certificate instead of populating a collection. Set the following properties accordingly:
- CertStoreType to cstPKCS11
- CertStore to the path to the driver DLL
- CertStorePassword to the PIN
When the ListStoreCertificates method is called, the CertList event will fire for each certificate in the store. Once you have identified the certificate, it is recommended to save it from within this event so that you can provide it to PDFSign in the next step.
CertMgr mgr = new CertMgr();
// Opening the storage
mgr.CertStoreType = CertStoreTypes.cstPKCS11;
mgr.CertStore = "c:/path/to/driver.dll";
mgr.CertStorePassword = "12345"; // driver's PIN
string privateKeyBlob = "";
bool found = false;
mgr.OnCertList += (s, e) =>
{
// Saving the first certificate with a private key
if (!found && e.HasPrivateKey)
{
privateKeyBlob = e.CertEncoded;
found = true;
}
};
mgr.ListStoreCertificates();
Using the saved private key blob, assign a new Certificate object to the SigningCert property, and then sign:
PDFSign signer = new PDFSign();
signer.InputFile = "sample.pdf";
signer.OutputFile = "signed.pdf";
signer.SigningCert = new Certificate(CertStoreTypes.cstPKCS11, privateKeyBlob, "test", "*");
signer.Sign();
CryptoAPI versus PKCS#11
Both SecureBlackbox and Secure PDF can work with hardware devices that are accessible through either CryptoAPI or PKCS#11. On Windows systems, HSM drivers typically map certificates to the current user's MY store, creating a link from the certificate to its nonexportable private key in the process. The certificate is not physically located in the store but rather virtualized there by the HSM vendor's key storage provider (KSP) plugin. In such scenarios, the components use CryptoAPI to redirect the signing call to the HSM's KSP, which then forwards the call to the hardware device where the signing actually occurs.
If your HSM does not automatically map certificates or is prevented from doing so because of the absence of system certificate stores altogether (e.g., on Linux systems), then the components will instead communicate directly with the HSM through PKCS#11 for both certificate access and signing operations.
We appreciate your feedback. If you have any questions, comments, or suggestions about this article please contact our support team at support@nsoftware.com.