SSL with private key on an HSM

对着背影说爱祢 提交于 2019-12-04 17:12:55

As Rasmus stated you should use CSP from your HSM producer. Check this link:

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

I successfully used a little bit different approach on the client for client-authenticated HTTPS with HttpWebRequest, ClientCertificates and smart card. In my case private key is stored in the smart card (similar to HSM). Smart card CSP then uses PKCS#11 for signing, enc/decrypt etc, but that is not important. Property X509Certificate.Handle is used in SSL establishment for signing the challenge on the client and this handle contains information about certificate's private key.

In my case I wanted to set pin programatically for smart card to avoid "Enter PIN" dialog from smart card in process of SSL creation, and I've done it with this function:

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);
}

You can find names of all installed CSPs in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Defaults\Provider. Win32 is my class for C++/C# interop and looks like this:

[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
        );

If the HSM comes with CAPI CSP with can do the following:

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;

This should work. Note that if you use 24 instead of 1 for provider type this might not work (it does not at least for the default CSP).

In the HSMs I've worked with, this is hidden from you. There's typically a different process for generating the key pairs (either for generating the certificate request or for distributing the completed certificate to more machines than where you generated the certificate request, depending on what kind of HSM it is), but once the certificate is installed on the machine, it appears as a normal certificate with a private key, and you just use it as you would any other certificate.

Private keys are exported depending on the configuration settings of the HSM. You need to speak to the HSM vendor to find out which of their HSM's provide this feature.

The HSM may ship with a CryptoAPI CSP implementation. If the key is properly mapped to the certificate in CryptoAPI, the SslStream should be able to use it without exporting it.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!