該頁面可以包含自動翻譯的文字。

如何在 C# 和 VB.NET 中使用 USB 令牌和 HSM 裝置對 PDF 進行簽名

受信任的憑證授權單位不再允許下載文件簽署憑證的私鑰。私鑰必須儲存在安全硬體中,例如 USB 令牌、智慧卡或基於雲端的 HSM。

您可以使用 Docotic.Pdf 函式庫 在 .NET 中使用 HSM 裝置對 PDF 文件進行簽署。本文介紹如何與 Azure Key Vault、AWS KMS 以及符合 PKCS#11 標準的硬體整合。

Docotic.Pdf 函式庫 9.7.18373 回歸測試 15,244 已通過 NuGet 總下載量 5,976,723

您可以在 下載 C# .NET PDF 函式庫 頁面取得該資料庫和免費的限時授權金鑰。

外部 PDF 簽名

先決條件

本文中的程式碼範例使用自簽名憑證對 PDF 文件進行簽名。預設情況下,PDF 檢視器不信任這些簽名。自簽名證書僅應用於測試,不應用於生產環境。若要產生受信任的 PDF 簽名,請使用第三方憑證授權單位所核發的文件簽名憑證。

取得正確的證書

優先選擇 Adobe 認可信任清單 (AATL) 中列出的公司所頒發的憑證。 Adobe Acrobat 預設信任此類公司的證書,不會報告「證書有效性未知」的警告。

若要建立符合歐盟 (eIDAS) 標準的文檔,您需要使用由 歐盟信任清單 (EUTL) 中列出的提供者所頒發的合格證書。

了解如何在 .NET 中使用您的證書

當您訂購文件簽署憑證時,通常會獲得 HSM 裝置的存取權限。這可以是實體 USB 令牌,也可以是基於雲端的 HSM 解決方案。

然後,您應該學習如何使用此 HSM 簽署資料。這通常是最棘手的部分,因為所有加密提供者都不同。您應該遵循 USB 令牌或雲端 API 的文檔。

理想情況下,您需要找到一個對應的 .NET SDK。或至少找到一個原生 SDK 並透過 .NET 互通使用它。

您的目標是編寫能夠使用您的憑證對任何位元組進行簽署的 C# 或 VB.NET 程式碼。

用於外部簽名的 PDF API

一旦您可以使用 HSM 裝置對任何位元組進行簽名,就可以使用 Docotic.Pdf 簽署 PDF 文件了。為此,請實作 IPdfSigner 介面 並將其用於簽名。

實作 IPdfSigner 介面

IPdfSigner 聲明了兩個成員。 SignatureAlgorithm 屬性傳回用於簽章的演算法。通常,您會使用 RSA 或 ECDSA 演算法。

Sign 方法是外部簽章流程的關鍵部分。 Docotic.Pdf 將 PDF 文件位元組的摘要提供給此方法。您應該使用 HSM 設備對此摘要進行簽名,並傳回數位簽名的位元組。請注意,您不能在此處傳回 PKCS#7 物件。只需生成並返回加密簽名即可。

Docotic.Pdf 為每個簽章呼叫兩次 Sign 方法。第一次呼叫用於計算簽章所需的空間。第二次呼叫用於實際簽名文檔。

建立 PdfSigningOptions 用於外部簽名

使用 PdfSigningOptions(IPdfSigner, X509Certificate2[]) 建構子 使用您的 IPdfSigner 實作對 PDF 文件進行簽署。取得憑證鏈並將其作為第二個參數提供。至少需要一個證書,並且簽名證書應放在最前面。

最後一塊拼圖是 PdfSigningOptions.DigestAlgorithm 屬性。此屬性的值必須與 IPdfSigner.SignatureAlgorithmIPdfSigner.Sign 實作一致。

讓我們回顧一下在常見情況下如何使用外部簽名對 PDF 進行簽名。

使用 C# 中的 PKCS#11 驅動程式簽署 PDF 文檔

如果您的加密 USB 令牌或智慧卡附帶 PKCS#11 驅動程序,則可以在 .NET 中使用 Pkcs11Interop.X509StorePkcs11Interop 函式庫。 Pkcs11Interop與 Atos CardOS 智慧卡、YubiKey PIV、SmartCard-HSM、SafeNet ProtectServer HSM 和其他 HSM 相容。

使用 PKCS#11 驅動程式簽署 PDF 文檔 程式碼範例展示如何使用 USB 令牌或智慧卡對 PDF 文件進行簽署。您需要自訂以下程式碼行:

string pkcsLibraryPath = @"C:\Program Files\SoftHSM2\lib\softhsm2-x64.dll";
ulong slotId = 1743347971;
string alias = "YOUR-ALIAS";
string certLabel = "YOUR-CERTIFICATE";
string pin = "YOUR-PIN";
var digestAlgorithm = PdfDigestAlgorithm.Sha512;

我們的範例配置使用 SoftHSM2 作為 USB 令牌的模擬器。在實際應用中,您不需要 SoftHSM2,而是使用 USB 令牌自帶的驅動程式。

使用 Azure Key Vault 簽章 PDF 文檔

Microsoft Azure Key Vault 安全地儲存憑證和金鑰。您需要進行以下準備:

  1. 建立 Azure 帳戶。
  2. 建立 Azure 使用者。
  3. 建立 Key Vault。
  4. 允許所選 Azure 使用者存取 Key Vault。
  5. 將文件簽章憑證新增至 Key Vault。您可以從整合式憑證授權單位 匯入 憑證。

然後,使用 Azure.Security.KeyVault.Keys NuGet 套件在 .NET 中簽署。使用 Azure Key Vault 中的金鑰進行簽署的 C# 範例程式碼如下:

var vaultUrl = new Uri("https://YOUR-VAULT.vault.azure.net/");
var credential = new DefaultAzureCredential();

var keyClient = new KeyClient(vaultUrl, credential);
KeyVaultKey key = keyClient.GetKey("YOUR-KEY");
var cryptoClient = new CryptographyClient(key.Id, credentials);
byte[] messageToSign = ..;
byte[] signature = cryptoClient.SignData(SignatureAlgorithm.RS512, messageToSign).Signature;

相關的IPdfSigner實作可能如下所示:

class AzureSigner : IPdfSigner
{
    private readonly CryptographyClient m_client;
    private readonly AzureSignatureAlgorithm m_signingAlgorithm;

    public AzureSigner(CryptographyClient client, AzureSignatureAlgorithm signingAlgorithm)
    {
        m_client = client;
        m_signingAlgorithm = signingAlgorithm;
    }

    public PdfSignatureAlgorithm SignatureAlgorithm
    {
        get
        {
            if (m_signingAlgorithm == AzureSignatureAlgorithm.RS256 ||
                m_signingAlgorithm == AzureSignatureAlgorithm.RS384 ||
                m_signingAlgorithm == AzureSignatureAlgorithm.RS512)
                return PdfSignatureAlgorithm.Rsa;

            throw new NotSupportedException($"Unsupported {nameof(SignatureAlgorithm)} value: {m_signingAlgorithm}");
        }
    }

    public PdfDigestAlgorithm DigestAlgorithm
    {
        get
        {
            if (m_signingAlgorithm == AzureSignatureAlgorithm.RS256)
                return PdfDigestAlgorithm.Sha256;

            if (m_signingAlgorithm == AzureSignatureAlgorithm.RS384)
                return PdfDigestAlgorithm.Sha384;

            if (m_signingAlgorithm == AzureSignatureAlgorithm.RS512)
                return PdfDigestAlgorithm.Sha512;

            throw new NotSupportedException($"Unsupported {nameof(SignatureAlgorithm)} value: {m_signingAlgorithm}");
        }
    }

    public byte[] Sign(byte[] message)
    {
        return m_client.SignData(m_signingAlgorithm, message).Signature;
    }
}

最後,使用此 AzureSigner 類別對 PDF 文件進行簽署:

CryptographyClient cryptoClient = ..;
using X509Certificate2 cert = ..
var signer = new AzureSigner(cryptoClient, SignatureAlgorithm.RS512);

using var pdf = new PdfDocument();

PdfPage page = pdf.Pages[0];
PdfSignatureField field = page.AddSignatureField(50, 50, 200, 200);

var options = new PdfSigningOptions(signer, new[] { cert })
{
    DigestAlgorithm = signer.DigestAlgorithm,
    Field = field,
};

pdf.SignAndSave(options, ..);

在 GitHub 上探索完整的 使用 Azure Key Vault 簽署 PDF 文檔 程式碼範例。

使用 AWS KMS 簽署 PDF 文件

AWS 金鑰管理服務 (KMS) 是另一種安全的加密金鑰儲存方式。準備步驟與 Azure Key Vault 相同:

  1. 建立 AWS 帳戶。
  2. 建立 IAM 使用者。
  3. 新增簽名密鑰。
  4. 允許所選 IAM 使用者存取金鑰。

對於 AWS,您需要使用 .NET 中的 AWSSDK.KeyManagementService NuGet 套件。 PDF 簽署的範例程式碼與 Azure 場景非常接近:

using var pdf = new PdfDocument();

PdfPage page = pdf.Pages[0];
PdfSignatureField field = page.AddSignatureField(50, 50, 200, 200);

var signingAlgorithm = SigningAlgorithmSpec.RSASSA_PSS_SHA_512;
var signer = new AwsSigner("arn:aws:kms:YOUR-id", signingAlgorithm)
var options = new PdfSigningOptions(signer, new[] { cert })
{
    DigestAlgorithm = signer.DigestAlgorithm,
    Field = field,
};

pdf.SignAndSave(options, ..);


class AwsSigner : IPdfSigner
{
    private readonly string m_keyId;
    private readonly SigningAlgorithmSpec m_signingAlgorithm;

    public AwsSigner(string keyId, SigningAlgorithmSpec signingAlgorithm)
    {
        m_keyId = keyId;
        m_signingAlgorithm = signingAlgorithm;
    }

    public PdfSignatureAlgorithm SignatureAlgorithm
    {
        get
        {
            if (m_signingAlgorithm == SigningAlgorithmSpec.RSASSA_PKCS1_V1_5_SHA_256 ||
                m_signingAlgorithm == SigningAlgorithmSpec.RSASSA_PKCS1_V1_5_SHA_384 ||
                m_signingAlgorithm == SigningAlgorithmSpec.RSASSA_PKCS1_V1_5_SHA_512)
                return PdfSignatureAlgorithm.Rsa;

            throw new NotSupportedException($"Unsupported {nameof(SigningAlgorithmSpec)} value: {m_signingAlgorithm}");
        }
    }

    public PdfDigestAlgorithm DigestAlgorithm
    {
        get
        {
            string alg = m_signingAlgorithm.Value;
            if (alg.EndsWith("256"))
                return PdfDigestAlgorithm.Sha256;

            if (alg.EndsWith("384"))
                return PdfDigestAlgorithm.Sha384;

            if (alg.EndsWith("512"))
                return PdfDigestAlgorithm.Sha512;

            throw new NotSupportedException($"Unsupported {nameof(SigningAlgorithmSpec)} value: {m_signingAlgorithm}");
        }
    }

    public byte[] Sign(byte[] message)
    {
        using var kmsClient = new AmazonKeyManagementServiceClient();
        using var stream = new MemoryStream(message);
        var signRequest = new SignRequest()
        {
            SigningAlgorithm = m_signingAlgorithm,
            KeyId = m_keyId,
            MessageType = MessageType.RAW,
            Message = stream,
        };
        SignResponse signResponse = kmsClient.SignAsync(signRequest).GetAwaiter().GetResult();
        return signResponse.Signature.ToArray();
    }
}

完整的 使用 AWS KMS 簽署 PDF 文檔 程式碼範例也可在 GitHub 上取得。

結論

利用 Docotic.Pdf 庫,您可以使用 USB 令牌、智慧卡或雲端 HSM 簽署 PDF 文件。為此,請使用 C# 或 VB.NET 程式碼實作 IPdfSigner 介面。

從 GitHub 下載並試用 PDF 數位簽章程式碼範例。查看相關文章以了解更多:

常見問題

如何使用 USB 令牌或智慧卡對 PDF 進行簽署?

使用 Docotic.Pdf 和 Pkcs11Interop .NET 函式庫,可以使用令牌或智慧卡對 PDF 進行簽署。如需更多詳情,請參閱使用 C# 中的 PKCS#11 驅動程式簽署 PDF 文檔部分。

如何在 USB 令牌或智慧卡上使用 SoftHSM?

SoftHSM 模擬真實的 HSM 設備。如果您擁有 USB 令牌或智慧卡,則無需使用 SoftHSM。請使用 HSM 設備隨附的 PKCS#11 驅動程式。

如何使用外部簽章對 PDF 文件進行簽名?

請查看使用 Azure Key Vault 簽章 PDF 文檔使用 AWS KMS 簽署 PDF 文件部分。使用其他基於雲端的 HSM 進行外部 PDF 簽章的過程類似。

如何在 .NET 中使用 Azure Key Vault?

請使用 Azure.Security.KeyVault.Keys NuGet 套件。嘗試 GitHub 上的 使用 Azure Key Vault 簽署 PDF 文檔 程式碼範例。