1

Summary

Use CNG or Pkcs11Interop or any other alternatives to login to an HSM, search for a privatekey then pass it on to a 3rd party application for use. The key cannot be extracted from the HSM or stored in memory.

a 3rd Party application needs to make use of a private key that is stored on a Hardware Security Module (HSM). I have looked into two methods CNG and Pkcs11Interop.

The code needs to accomplish the following:

1-Authenticate and establish a session with the HSM

2-Search for the key

3-Pass the private key to the 3rd party using RSACryptoServiceProvider or other methods.

Important: The key cannot be accessed extracted from the HSM or access directly (by design for security purposes).

Below are the two samples I've put together for both CNG and PKCS11Interop

The Problem:

1-CNG I am struggling to authenticate (if that's possible)

2-PKCS11Interop I've been able to login, search for the key but struggling to make use of the key.

Happy to use either of the methods, and I welcome any assistance, alternative solutions or advice.

CNG Code: This code works when authentication is disabled on HSM

Q. Is there a way to authenticate using a password , open a session prior to using the key?

CngProvider provider = new CngProvider("CNGProvider");
const string KeyName = "somekey";
key = CngKey.Open(KeyName, provider);
Console.WriteLine("found the key!");
var cngRsa = new RSACng(key);
var privateSshKey = new SshPrivateKey(cngRsa);

PKCS11Interop, I managed to authenticate, search for the key and assign it to a handle..

Q. How do i go about passing the private key onto a standard .Net Framework type AsymmetricAlgorithm? while keeping in mind it not exportable? can it be passed to RSACryptoServiceProvider? and then onto AsymmetricAlgorithm?

using (IPkcs11Library pkcs11Library = Settings.Factories.Pkcs11LibraryFactory.LoadPkcs11Library(Settings.Factories, Settings.Pkcs11LibraryPath, Settings.AppType))
        {
            ISlot slot = Helpers.GetUsableSlot(pkcs11Library);
            using (ISession session = slot.OpenSession(SessionType.ReadWrite))
            {
                //search for key
                try
                {
                const string keyname = "somekey";
                // Login as normal user
                session.Login(CKU.CKU_USER, Settings.NormalUserPin);
                IObjectHandle publicKeyHandle = Helpers.CreateDataObject(session);
                IObjectHandle privateKeyHandle = Helpers.CreateDataObject(session);
                // Prepare attribute template that defines search criteria
                List<IObjectAttribute> privateKeyAttributes = new List<IObjectAttribute>();
                privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_CLASS, CKO.CKO_PRIVATE_KEY));
                privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_KEY_TYPE, CKK.CKK_RSA));
                privateKeyAttributes.Add(session.Factories.ObjectAttributeFactory.Create(CKA.CKA_LABEL, keyname));

                List<IObjectHandle> foundPrivateKeys = session.FindAllObjects(privateKeyAttributes);
                if (foundPrivateKeys == null || foundPrivateKeys.Count != 1)
                    throw new Exception("Unable to find private key");

                // Use found object handles
                 privateKeyHandle = foundPrivateKeys[0];
                session.FindObjectsFinal();

                // How do i go about using the privatekey handle here?

                session.DestroyObject(privateKeyHandle);
                session.Logout();
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine("Crypto error: " + ex.Message);
                        }
                        Console.WriteLine("done!");
                        System.Console.Write("[Hit Enter to Continue]");
                        System.Console.ReadLine();

                    }
                }
Raeef
  • 13
  • 4

1 Answers1

0

With an HSM, by design, you cannot "Pass the private key to a 3rd party app".

You also cannot pass the key handle between processes (although this might work in some implementations - a key handle should be PKCS11 session specific).

Your 3rd party app needs to offload cryptographic operations to the HSM by using a configurable cryptography library like OpenSSL (or similar) or if it is using CNG it should allow you to configure the provider.

Q. Is there a way to authenticate using a password , open a session prior to using the key?

A.: For an app that uses CNG, you should use the CNG Key Storage Provider (KSP) from the HSM Vendor after you have configured it.

The HSM Vendor KSP will then prompt for the password or, if you configured the provider (using a utility or configuration file from the HSM vendor) to store the password/pin, it will just work.

eHSM sample code using NCryptNative:

    SafeNCryptProviderHandle handle;
    NCryptOpenStorageProvider(handle, "eHSM Key Storage Provider",0);
    ...

Q. How do i go about passing the private key onto a standard .Net Framework type AsymmetricAlgorithm? while keeping in mind it not exportable? can it be passed to RSACryptoServiceProvider? and then onto AsymmetricAlgorithm?

A.: No, you cannot pass key material and you cannot pass the raw PKCS11 handle to the CNG Framework. You either have to use the PKCS11Interop functions to perform all cryptographic operations OR you have to do everything in CNG (correctly configured as above).

To directly use the PKCS11 interface you continue calling PKCS11 functions with the key handle, ie.

    // How do i go about using the privatekey handle here?

    // something like this
    session.SignInit(mechanism, privateKeyHandle);
    session.Sign(data, signature));

kosierosie
  • 21
  • 3