2

I am trying to transfer an RSA private key to my HSM (SafeNet eToken) via PKCS#11 interop, and and then unwrap it on the HSM.

This is my code (updated):

            session.Login(CKU.CKU_USER, pin);
            var x509Certificate = new X509Certificate2(File.ReadAllBytes(path), "", X509KeyStorageFlags.Exportable);
            var privateKey = x509Certificate.PrivateKey as RSACryptoServiceProvider;
            var keyPair = DotNetUtilities.GetRsaKeyPair(privateKey);
            byte[] privateKeyBytes;
            using (var memoryStream = new MemoryStream())
            {
                using (TextWriter streamWriter = new StreamWriter(memoryStream))
                {
                    var pemWriter = new PemWriter(streamWriter);
                    pemWriter.WriteObject(keyPair.Private);
                    streamWriter.Flush();
                }
                privateKeyBytes = memoryStream.GetBuffer();
            }

            // Create temporary DES3 key for wrapping/unwrapping
            var tempKeyAttributes = new List<ObjectAttribute>
            {
                new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_SECRET_KEY),
                new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_DES3),
                new ObjectAttribute(CKA.CKA_ENCRYPT, true),
                new ObjectAttribute(CKA.CKA_UNWRAP, true)
            };
            var tempKey = session.GenerateKey(new Mechanism(CKM.CKM_DES3_KEY_GEN), tempKeyAttributes);

            var encrypted =
                session.Encrypt(new Mechanism(CKM.CKM_DES3_ECB), tempKey, privateKeyBytes);

            string label = "private1";

            // Define how the new RSA private key should look like on the HSM
            var privateKeyAttributes = new List<ObjectAttribute>
            {
                new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_PRIVATE_KEY),
                new ObjectAttribute(CKA.CKA_TOKEN, true),
                new ObjectAttribute(CKA.CKA_PRIVATE, true),
                new ObjectAttribute(CKA.CKA_MODIFIABLE, true),
                new ObjectAttribute(CKA.CKA_SENSITIVE, false),
                new ObjectAttribute(CKA.CKA_LABEL, label),
                new ObjectAttribute(CKA.CKA_ID, Encoding.ASCII.GetBytes(label)),
                new ObjectAttribute(CKA.CKA_ALWAYS_AUTHENTICATE, false),
                new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_RSA),

            };
            var privateKeyHandle = session.UnwrapKey(new Mechanism(CKM.CKM_DES3_ECB), tempKey,
                encrypted, privateKeyAttributes);


//results in: Method C_UnwrapKey returned CKR_WRAPPED_KEY_INVALID

But it does not work - fails with Net.Pkcs11Interop.Common.Pkcs11Exception: Method C_UnwrapKey returned CKR_TEMPLATE_INCONSISTENT.

(UPDATED) Now it results in CKR_WRAPPED_KEY_INVALID. But if I import the same PFX file manuall using SafeNet, no errors occur - everything seems fine.

Any ideas? Maybe there are some parameters I used wrong?

Vladimir K
  • 53
  • 6
  • 2
    In your`privateKeyAttributes` try not setting any attributes from the Private Key. Basically the last 8 attributes you are setting (modulus, ... coefficient), remove them, and work with the other attributes. Those will be populated after the unwrap is successful. – always_a_rookie Apr 05 '19 at 19:34
  • Vladimir have you managed to resolve your issue with hints from the first comment? – jariq Apr 07 '19 at 21:23
  • (Updated the method code at the top according to your recommendations) Thank you, CKR_TEMPLATE_INCONSISTENT has gone, but now i am getting "Method C_UnwrapKey returned CKR_WRAPPED_KEY_INVALID". So, privateKeyBytes length is exactly 2048. But If I import the same PFX file manuall using SafeNet, no errors occur - everything seems fine. – Vladimir K Apr 08 '19 at 07:10
  • 1
    You are currently using `ECB` mode. Try encrypting the private key using `CBC` mode by providing an `IV`. – always_a_rookie Apr 08 '19 at 15:58
  • @VladimirK I don't think you should be using PEM encoded private key. Take a look at [this answer to similar question](https://stackoverflow.com/a/53761064/3325704) – jariq Apr 08 '19 at 19:37
  • @jarik Thank you guys! Finally bouncy castle method did the trick. (posted an update with working code above) – Vladimir K Apr 09 '19 at 09:58

1 Answers1

3

FINALLY the code that does the thing:

   var x509Certificate = new X509Certificate2(File.ReadAllBytes(path), "",
                X509KeyStorageFlags.Exportable);
            var privateKey = x509Certificate.PrivateKey as RSACryptoServiceProvider;
            if (privateKey == null) throw new Exception($"Private key is null for {x509Certificate.SerialNumber}");
            var privateKeyParams = privateKey.ExportParameters(true);
            session.Login(CKU.CKU_USER, pin);
            // Create temporary DES3 key for wrapping/unwrapping
            var tempKeyAttributes = new List<ObjectAttribute>
            {
                new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_SECRET_KEY),
                new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_DES3),
                new ObjectAttribute(CKA.CKA_ENCRYPT, true),
                new ObjectAttribute(CKA.CKA_DECRYPT, true),
                new ObjectAttribute(CKA.CKA_UNWRAP, true),
                new ObjectAttribute(CKA.CKA_WRAP, true)
            };
            // Preparing unencrypted private key
            var unencryptedPrivateKey = PrivateKeyInfoFactory.CreatePrivateKeyInfo(
                new RsaPrivateCrtKeyParameters(
                    new BigInteger(1, privateKeyParams.Modulus),
                    new BigInteger(1, privateKeyParams.Exponent),
                    new BigInteger(1, privateKeyParams.D),
                    new BigInteger(1, privateKeyParams.P),
                    new BigInteger(1, privateKeyParams.Q),
                    new BigInteger(1, privateKeyParams.DP),
                    new BigInteger(1, privateKeyParams.DQ),
                    new BigInteger(1, privateKeyParams.InverseQ))).GetEncoded();
            var tempKey = session.GenerateKey(new Mechanism(CKM.CKM_DES3_KEY_GEN), tempKeyAttributes);
            var result = new MemoryStream();
            var stream = new MemoryStream(unencryptedPrivateKey);
            //Encrypting
            session.Encrypt(new Mechanism(CKM.CKM_DES3_ECB), tempKey, stream,
                result);
            var encrypted = result.ToArray();
            string label = x509Certificate.SerialNumber;
            // Define how the new RSA private key should look like on the HSM
            var privateKeyAttributes = new List<ObjectAttribute>
            {
                new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_PRIVATE_KEY),
                new ObjectAttribute(CKA.CKA_TOKEN, true),
                new ObjectAttribute(CKA.CKA_PRIVATE, true),
                new ObjectAttribute(CKA.CKA_MODIFIABLE, true),
                new ObjectAttribute(CKA.CKA_SENSITIVE, false),
                new ObjectAttribute(CKA.CKA_LABEL, label),
                new ObjectAttribute(CKA.CKA_ID, Encoding.ASCII.GetBytes(label)),
                new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_RSA)
            };
            var privateKeyHandle = session.UnwrapKey(new Mechanism(CKM.CKM_DES3_ECB), tempKey,
                encrypted, privateKeyAttributes);
            return privateKeyHandle;
Vladimir K
  • 53
  • 6