3

我的应用程序中有一个使用 SSL 的客户端-服务器架构。目前,私钥存储在 CAPI 的密钥存储位置。出于安全原因,我想将密钥存储在更安全的地方,最好是为此目的而构建的硬件签名模块 (HSM)。不幸的是,由于私钥存储在这样的设备上,我无法弄清楚如何在我的应用程序中使用它。

在服务器上,我只是使用SslStream类和AuthenticateAsServer(...)调用。此方法采用X509Certificate已加载其私钥的对象,但由于私钥存储在 HSM 上的安全(例如不可导出)位置,我不知道如何执行此操作。

在客户端,我正在使用一个HttpWebRequest对象,然后使用该ClientCertificates属性添加我的客户端身份验证证书,但我在这里遇到了同样的问题:如何获取私钥?

我知道有一些 HSM 充当 SSL 加速器,但我并不真的需要加速器。此外,这些产品往往与我没有使用的 IIS 和 Apache 等 Web 服务器进行特殊集成。

有任何想法吗?我唯一能想到的就是编写我自己的 SSL 库,它允许我将交易的签名部分交给 HSM,但这似乎是一项巨大的工作。

4

5 回答 5

7

正如 Rasmus 所说,您应该使用 HSM 生产者的 CSP。检查此链接:

http://forums.asp.net/t/1531893.aspx

我成功地在客户端上使用了一些不同的方法,用于客户端身份验证的 HTTPSHttpWebRequestClientCertificates智能卡。在我的情况下,私钥存储在智能卡中(类似于 HSM)。智能卡 CSP 然后使用 PKCS#11 进行签名、加密/解密等,但这并不重要。属性X509Certificate.Handle在 SSL 建立中用于对客户端的质询进行签名,此句柄包含有关证书私钥的信息。

在我的情况下,我想以编程方式为智能卡设置 pin 以避免在 SSL 创建过程中来自智能卡的“输入 PIN”对话框,我已经使用此功能完成了它:

public void SetContext(X509Certificate2 cert)
{
        IntPtr p = IntPtr.Zero;
        bool result = Win32.CryptAcquireContext(ref p, "keyContainer", "Siemens Card API CSP", 1, 0);
        byte[] pin = new ASCIIEncoding().GetBytes("0000");
        result = Win32.CryptSetProvParam(p, 32, pin, 0);
        result = Win32.CertSetCertificateContextProperty(cert.Handle, 1, 0, p);
}

您可以在 中找到所有已安装 CSP 的名称HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Defaults\ProviderWin32是我的 C++/C# 互操作类,如下所示:

[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool CryptAcquireContext(
        ref IntPtr hProv,
        string pszContainer,
        string pszProvider,
        uint dwProvType,
        uint dwFlags
        );
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    public static extern bool CryptSetProvParam(
        IntPtr hProv,
        uint dwParam,
        [In] byte[] pbData,
        uint dwFlags);
[DllImport("CRYPT32.DLL")]
    internal static extern Boolean CertSetCertificateContextProperty(
        IntPtr pCertContext,
        uint dwPropId,
        uint dwFlags,
        IntPtr pvData
        );
于 2010-09-24T12:02:10.733 回答
2

如果 HSM 带有 CAPI CSP 可以执行以下操作:

var certificate = new X509Certificate2(pathToPublicCert);

var cspParameters = new CspParameters()
{
   ProviderType = 1, /* Use 1 instead of 24 (the default) */
   ProivderName = "My HSM Cryptographic Provider Name",
   KeyContainerName = "My Private Key Container Name",
   KeyNumber = 1, /* Key exchange key */
   Flags = CspProviderFlags.UseExistingKey | CspProviderFlags.UseNonExportableKey,
};

var privateKey = new RSACryptoServiceProvider(cspParameters);

certificate.PrivateKey = privateKey;

这应该有效。请注意,如果您使用 24 而不是 1 作为提供程序类型,这可能不起作用(至少对于默认 CSP 不起作用)。

于 2011-01-31T00:29:01.707 回答
0

根据 HSM 的配置设置导出私钥。您需要与 HSM 供应商联系以了解他们的哪些 HSM 提供此功能。

于 2009-08-24T10:01:10.260 回答
0

HSM 可能附带 CryptoAPI CSP 实现。如果密钥正确映射到 CryptoAPI 中的证书,则 SslStream 应该能够使用它而无需导出它。

于 2009-09-09T14:05:58.250 回答
0

在我使用过的 HSM 中,这对你是隐藏的。生成密钥对通常有不同的过程(用于生成证书请求或将完成的证书分发到比生成证书请求的位置更多的机器,具体取决于它是哪种 HSM),但是一旦安装了证书在机器上,它显示为带有私钥的普通证书,您只需像使用任何其他证书一样使用它。

于 2009-08-05T18:44:19.840 回答