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

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

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

我知道有些HSM可以充当SSL加速器,但我实际上并不需要加速器。而且,这些产品倾向于与Web服务器(如IIS和Apache)进行特殊集成,而我并未使用它们。

有任何想法吗?我唯一能想到的就是编写自己的SSL库,该库使我可以将事务的签名部分交给HSM,但这似乎需要大量工作。

最佳答案

正如拉斯穆斯所说,您应该使用HSM生产商提供的CSP。检查此链接:

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

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

在我的情况下,我想以编程方式设置智能卡的密码,以避免在创建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);
}


您可以在HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Defaults\Provider中找到所有已安装的CSP的名称。 Win32是我的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
        );

10-07 12:53
查看更多