我的应用程序中有一个使用SSL的客户端 - 服务器架构。目前,私钥存储在CAPI的密钥库位置。出于安全原因,我想将密钥存储在一个更安全的地方,理想情况下是为此目的而构建的硬件签名模块(HSM)。不幸的是,由于私钥存储在这样的设备上,我无法弄清楚如何在我的应用程序中使用它。
在服务器上,我只是使用SslStream
类和AuthenticateAsServer(...)
调用。此方法采用加载了私钥的X509Certificate
对象,但由于私钥存储在HSM上的安全(例如,不可导出)位置,因此我不知道如何执行此操作。
在客户端上,我使用HttpWebRequest
对象,然后使用ClientCertificates
属性添加我的客户端身份验证证书,但我在这里遇到同样的问题:如何获取私钥?
我知道有些HSM可以充当SSL加速器,但我并不需要加速器。此外,这些产品往往与我不使用的IIS和Apache等Web服务器进行特殊集成。
有什么想法吗?我唯一能想到的就是编写自己的SSL库,这样我就可以将交易的签名部分交给HSM,但这似乎是一项巨大的工作。
答案 0 :(得分:3)
正如Rasmus所说,你应该使用HSM制作人的CSP。检查此链接:
http://forums.asp.net/t/1531893.aspx
我在客户端上成功使用了一种不同的方法,用于HttpWebRequest
,ClientCertificates
和智能卡的客户端身份验证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#interop类,看起来像这样:
[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
);
答案 1 :(得分: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不起作用)。
答案 2 :(得分:0)
在我使用过的HSM中,这对你来说是隐藏的。通常有一个不同的生成密钥对的过程(用于生成证书请求或将完成的证书分发到比生成证书请求的机器更多的机器,具体取决于它是什么类型的HSM),但是一旦安装了证书在计算机上,它显示为带有私钥的普通证书,您只需像使用任何其他证书一样使用它。
答案 3 :(得分:0)
根据HSM的配置设置导出私钥。您需要与HSM供应商联系,以了解他们的哪个HSM提供此功能。
答案 4 :(得分:0)
HSM可能附带CryptoAPI CSP实施。如果密钥正确映射到CryptoAPI中的证书,则SslStream应该能够在不导出的情况下使用它。