我的应用程序中有一个使用 SSL 的客户端-服务器架构。目前,私钥存储在 CAPI 的密钥存储位置。出于安全原因,我想将密钥存储在一个更安全的地方,最好是为此目的而构建的硬件签名模块 (HSM)。不幸的是,私钥存储在这样的设备上,我无法弄清楚如何在我的应用程序中使用它。
在服务器上,我只是使用SslStream类和AuthenticateAsServer(...)调用。此方法采用一个X509Certificate已加载其私钥的对象,但由于私钥存储在 HSM 上的安全(例如不可导出)位置,我不知道如何执行此操作。
在客户端,我使用一个HttpWebRequest对象,然后使用该ClientCertificates属性添加我的客户端身份验证证书,但我在这里遇到了同样的问题:如何获取私钥?
我知道有一些 HSM 可以充当 SSL 加速器,但我真的不需要加速器。此外,这些产品往往与我没有使用的 Web 服务器(例如 IIS 和 Apache)进行特殊集成。
有任何想法吗?我唯一能想到的就是编写自己的 SSL 库,这样我就可以将交易的签名部分交给 HSM,但这似乎是一项巨大的工作。
小智 7
正如 Rasmus 所说,您应该使用 HSM 生产商的 CSP。检查此链接:
http://forums.asp.net/t/1531893.aspx
我成功地在客户端上使用了一些不同的方法,通过HttpWebRequest,ClientCertificates和智能卡进行客户端身份验证的 HTTPS 。在我的情况下,私钥存储在智能卡中(类似于 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);
}
Run Code Online (Sandbox Code Playgroud)
您可以在HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Defaults\Provider. 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
);
Run Code Online (Sandbox Code Playgroud)