介紹與動機
在企業級系統實作數位簽章時,安全性是絕對不可妥協的。
將憑證儲存在本機的 PFX 或 P12 檔案中雖然方便,卻會使私鑰面臨被抽取或洩漏的風險。相較之下,PKCS#11 硬體代幣(如 USB 加密狗、智慧卡與 HSM)能將金鑰封存於防篡改的邊界內,確保金鑰永不離開裝置。
本篇文章示範如何結合 GroupDocs.Signature for .NET 與 Pkcs11Interop,使用硬體代幣簽署 PDF 文件。此方式兼具便利性與合規性:GroupDocs 負責所有 PDF 層級的封裝(簽章欄位、摘要計算、嵌入),而代幣則執行實際的密碼運算簽章。
⚠️ 早期實作通知
這個解決方案目前以早期實作的形式提供,用於在 GroupDocs.Signature 中使用 PKCS#11 數位簽章加密狗。
雖然它能讓文件以硬體代幣簽署,我們強烈建議在您的環境中進行額外測試,以確保符合您的合規與安全需求。
我們非常期待收到您的回饋、測試結果以及改進建議。
挑戰:在 PKCS#11 與 PDF 簽署之間搭橋
將 PKCS#11 代幣整合到文件簽署工作流程中會面臨多項非凡挑戰:
- 低階複雜度 ── PKCS#11 API(Cryptoki)需要管理槽位、會話、句柄與屬性,以找尋正確的私鑰。
- PDF 層級封裝 ── 簽署 PDF 不僅是簽署位元組:函式庫必須對選定的位元組範圍計算正確的摘要,將簽章包裹於 CMS/PKCS#7 容器,加入時間戳記,並嵌入驗證資訊。
- 供應商差異 ── 不同代幣/供應商模組可能需要自訂屬性對映或額外的中介軟體。
- 合規與稽核 ── 生產系統需要穩健的 PIN 處理、會話生命週期管理、錯誤復原與記錄功能。
此範例專案透過結合 GroupDocs.Signature 中的 ICustomSignHash 介面與 Pkcs11Interop,將簽署工作委交給代幣,同時讓 GroupDocs 處理 PDF 結構。
範例專案的功能
- 示範如何使用 PKCS#11 代幣(加密狗、智慧卡、HSM)簽署 PDF 文件。
- 支援 Windows 憑證庫 後備方案:若憑證已安裝於 Windows,程式碼可改用該憑證。
- 實作 自訂摘要簽署:GroupDocs 計算摘要;代幣僅簽署該雜湊值。
- 私鑰始終 保留於硬體——絕不匯出。
- 將代幣邏輯(會話、金鑰搜尋、簽署)封裝於
Pkcs11DigitalSigner.cs。 - 提供
Helpers.cs中的輔助程式(例如在 Windows 憑證庫中搜尋憑證)。 - 設定集中於
Settings.cs。 - 作為可依環境調整的參考實作。
設定與前置需求
前置需求
- .NET 6.0 以上(或 .NET Framework 4.6.2)
- 來自代幣供應商的有效 PKCS#11 函式庫(DLL)
- 具備有效憑證的硬體代幣(USB 加密狗、智慧卡或 HSM)
- GroupDocs.Signature for .NET(試用版或授權版)
- Pkcs11Interop 函式庫
安裝
git clone https://github.com/groupdocs-signature/esign-documents-with-pkcs11-using-groupdocs-signature-dotnet.git
cd esign-documents-with-pkcs11-using-groupdocs-signature-dotnet
dotnet restore
在 Visual Studio 或您慣用的 IDE 中開啟方案,確保相依性已解決。
リポジトリ構造深度解析
GroupDocs.Signature-for-.NET-PKCS11-Sample/
├── GroupDocs.Signature-for-.NET-PKCS11-Sample.csproj # 專案檔案
├── Program.cs # 入口點與使用流程
├── Settings.cs # PKCS#11 / 代幣設定
├── Helpers.cs # 工具函式(Windows 憑證庫、憑證過濾)
├── Pkcs11DigitalSigner.cs # 透過 PKCS#11 實作 ICustomSignHash
└── README.md # 概要與使用說明
- Program.cs ── 協調簽署流程;示範代幣與 Windows 憑證兩種情境。
- Settings.cs ── 含有
Pkcs11LibraryPath、TokenPin、CertificateSubject等常數/佔位符。 - Helpers.cs ── 包含依主旨名稱於 Windows 憑證庫中搜尋憑證的程式碼(用於後備流程)。
- Pkcs11DigitalSigner.cs ── 核心邏輯:載入 PKCS#11 模組、開啟會話、定位私鑰物件、簽署摘要,並回傳
X509Certificate2或簽章回呼實作。 - README.md ── 提供概覽、挑戰與使用說明(本部落格文章即為補充說明)。
程式碼說明與導覽
Settings.cs
public static class Settings
{
public const string Pkcs11LibraryPath = "<PKCS11_LIBRARY_PATH>";
public const string TokenPin = "<TOKEN_PIN>";
public const string CertificateSubject = "<CERT_SUBJECT>";
}
此類別將設定資訊抽離,使您在部署環境中能輕鬆取代。
Pkcs11DigitalSigner.cs ── 高階流程
public class Pkcs11DigitalSigner : ICustomSignHash
{
public byte[] SignHash(byte[] hash)
{
// 此方法由 GroupDocs.Signature 呼叫,當需要代幣簽署雜湊值時
using (var pkcs11 = new Pkcs11(Settings.Pkcs11LibraryPath, AppType.SingleThreaded))
{
// 載入模組、開啟會話、以 PIN 登入、尋找金鑰並執行簽署
}
}
public X509Certificate2 GetCertificateFromPkcs11()
{
// 從代幣取得公鑰憑證,以便設定簽署選項
}
}
SignHash為核心方法:接收 GroupDocs 計算好的摘要,然後使用 PKCS#11 API 進行簽署。GetCertificateFromPkcs11取得儲存在代幣內的憑證(含公鑰),以確保簽章的元資料正確。
Program.cs ── 使用流程
class Program
{
static void Main()
{
string inputFile = "sample.pdf";
string outputFile = "signed.pdf";
// (1) PKCS#11 簽署
var tokenSigner = new Pkcs11DigitalSigner();
var cert = tokenSigner.GetCertificateFromPkcs11();
using (var signature = new Signature(inputFile))
{
var options = new DigitalSignOptions(cert)
{
Comments = "Signed with PKCS#11 token",
SignTime = DateTime.Now,
CustomSignHash = tokenSigner // 連結代幣簽署
};
signature.Sign(outputFile, options);
}
// (2) Windows 憑證庫後備方案(可選)
// var storeCert = Helpers.GetCertificateFromWindowsStore(Settings.CertificateSubject);
// using (var signature2 = new Signature(inputFile))
// {
// var options2 = new DigitalSignOptions(storeCert) { ... };
// signature2.Sign("signed_store.pdf", options2);
// }
}
}
重點說明:
- 透過
DigitalSignOptions的CustomSignHash屬性指向tokenSigner,讓 GroupDocs 委交實際的雜湊簽署給代幣。 - 註解掉的後備流程示範當硬體代幣無法使用時,如何切換至 Windows 憑證庫。
使用情境與實務案例
- 印度與 CA 發行的 USB 簽章加密狗
在印度,許多具法律效力的 eSignature 必須使用由認證機構頒發、儲存在 USB 加密狗內的憑證。此範例讓應用程式(如文件閘道、入口網站)能直接與這類加密狗整合。 - 企業文件工作流程
於合約管理或審批流程等內部系統,硬體簽署可防止未授權使用者偽造文件簽章。 - 法規/合規驅動的簽署
政府與受規範產業常要求簽章來源於硬體受控金鑰。此整合協助滿足嚴格的稽核與合規需求。
常見問題與故障排除
- 函式庫路徑錯誤 → PKCS#11 DLL 必須與代幣供應商的模組相符(例如
softhsm2.dll、cryptoki.dll)。 - PIN 鎖定或驗證失敗 → 多次錯誤輸入可能導致代幣鎖定,請參考供應商政策。
- 找不到金鑰 → 確認提供的憑證主旨正確,代幣內必須有相符的憑證。
- 缺少驅動或中介軟體 → 某些代幣需先安裝供應商提供的驅動,才能讓 Pkcs11Interop 正常通訊。
- 執行緒問題 → PKCS#11 操作未必具備執行緒安全;除非供應商明確支援,多數情況請使用單執行緒模式。
- 逾時或會話重設 → 長時間操作可能導致會話關閉或逾時,請確保妥善管理會話的開啟與關閉。
安全性與最佳實務
- 絕不要在程式碼中硬編寫正式環境的機密資訊(如 PIN、函式庫路徑);請使用安全設定或機密管理服務。
- 使用強度高的 PIN,並遵循政策定期更換。
- 記錄操作與錯誤(但勿記錄 PIN 等敏感資訊)。
- 限制代幣會話數,簽署完成後立即登出。
- 簽署後驗證簽章(鏈結檢查、時間戳記)。
- 在不同環境與代幣類型(加密狗/智慧卡/HSM)上進行測試。
待辦事項與資源
準備好自己動手了嗎?先將倉儲複製下來,更新佔位符,然後執行範例。您可能想進一步探索的主題包括:
- 自訂雜湊簽署(將摘要與簽署委交給代幣)
- 時間戳記與 LTV / DSS 嵌入
- 迭代簽署(在同一文件中加入多個簽章)
- 與遠端 HSM 服務或雲端代幣庫的整合