tags:

views:

577

answers:

4

I have a client-server architecture in my application that uses SSL. Currently, the private key is stored in CAPI's key store location. For security reasons, I'd like to store the key in a safer place, ideally a hardware signing module (HSM) that is built for this purpose. Unfortunately, with the private key stored on such a device, I can't figure out how to use it in my application.

On the server, I am simply using the SslStream class and the AuthenticateAsServer(...) call. This method takes an X509Certificate object that has its private key loaded, but since the private key is stored in a secure (e.g. non exportable) location on the HSM, I don't know how to do this.

On the client, I am using an HttpWebRequest object and then using the ClientCertificates property to add my client authentication certificate, but I have the same problem here: how do I get the private key?

I know there are some HSMs that act as SSL accelerators but I don't really need an accelerator. Also, these products tend to have special integration with web servers such as IIS and Apache which I'm not using.

Any ideas? The only thing I can think of would be to write my own SSL library that would allow me to hand off the signing portion of the transaction to the HSM, but this seems like a huge amount of work.

A: 

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.

Rovpedal
Which HSMs have you worked with that function in that manner? I'm evaluating a couple and they both function similarly by providing a cryptographic service provider for use with CAPI. They each have the ability to simply generate keys, encrypt/decrypt, hash, and sign data. As far as I can tell I would need to build my own certificate request and have the HSM sign it for me (since only it has the private key). Hopefully I'm missing something or maybe I'm just not looking at the right HSMs?
Jason
Mainly a variation of nCipher HSMs; PCI HSMs + NetHSMs.The executive version of how their devices work is that the crypto operation travels to the HSM, the HSM is the only that knows the private key, so it does the crypto operation and then returns back the result.In fact, the private key DOES reside in the normal certificate store on the machine, but it is 3DES encrypted, and the 3DES-key is what is in the HSM. When you do your crypto-operation, the data + the cert key + the 3DES key identifier is all sent to the HSM, the private key of the cert decrypted and the operation performed.
Rovpedal
Interesting, I'll have to look into those products. So if I understand the workflow, when the private key is decrypted is it available to you in software? That would sort of defeat the purpose of the HSM. So maybe the decrypted key is only available to the HSM itself, in which case how does your application use it?
Jason
The certificate key is only decrypted inside the HSM - where the 3DES key exists. The HSM driver installs itself as a crypto service provider in the system, which is why this is transparent to your application.
Rovpedal
A: 

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.

Raj
The whole point of using an HSM is to protect the private keys. I don't want an HSM that allows exportation of the private keys as that would defeat the whole purpose. Unfortunately it also makes my life pretty difficult since I can't conveniently use the private key as I normally would (thus my question).
Jason
A: 

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.

Rasmus Faber
The HSM does have a CAPI CSP. However, I'm not entirely sure how to add a cert to CAPI using a private key stored on the HSM. I can generate a private key on the HSM through the CSP, but how can I generate a cert using that key?
Jason
A: 

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
        );
Juraj Majer