0

We're trying to import an RSA key pair using C# and PKCS#11 into our HSM. Importing the private key using:

    var privateKeyAttributes = new List<ObjectAttribute>();
    privateKeyAttributes.Add(new ObjectAttribute(CKA.CKA_ID, ckaId));
    privateKeyAttributes.Add(new ObjectAttribute(CKA.CKA_LABEL, ckaId));
    privateKeyAttributes.Add(new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_PRIVATE_KEY));
    privateKeyAttributes.Add(new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_RSA));
    privateKeyAttributes.Add(new ObjectAttribute(CKA.CKA_TOKEN, true));
    privateKeyAttributes.Add(new ObjectAttribute(CKA.CKA_PRIVATE, true));
    privateKeyAttributes.Add(new ObjectAttribute(CKA.CKA_SENSITIVE, true));
    privateKeyAttributes.Add(new ObjectAttribute(CKA.CKA_DECRYPT, true));
    privateKeyAttributes.Add(new ObjectAttribute(CKA.CKA_SIGN, true));
    privateKeyAttributes.Add(new ObjectAttribute(CKA.CKA_SIGN_RECOVER, true));
    privateKeyAttributes.Add(new ObjectAttribute(CKA.CKA_UNWRAP, true));
    privateKeyAttributes.Add(new ObjectAttribute(CKA.CKA_MODULUS, privateKeyParams.Modulus));
    privateKeyAttributes.Add(new ObjectAttribute(CKA.CKA_PRIVATE_EXPONENT, privateKeyParams.D));
    var privateKeyHandle = session.CreateObject(privateKeyAttributes);

Fails with the error code CKR_TEMPLATE_INCONSISTENT. Unfortunately, it doesn't say what is inconsistent. I tried various other combinations of attributes and it always fails :-(

How to properly import the private key via PKCS#11?


Note: Importing the public key using very similar code works:

    var publicKeyAttributes = new List<ObjectAttribute>();
    publicKeyAttributes.Add(new ObjectAttribute(CKA.CKA_ID, ckaId));
    publicKeyAttributes.Add(new ObjectAttribute(CKA.CKA_LABEL, ckaId));
    publicKeyAttributes.Add(new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_PUBLIC_KEY));
    publicKeyAttributes.Add(new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_RSA));
    publicKeyAttributes.Add(new ObjectAttribute(CKA.CKA_TOKEN, true));
    publicKeyAttributes.Add(new ObjectAttribute(CKA.CKA_PRIVATE, true));
    publicKeyAttributes.Add(new ObjectAttribute(CKA.CKA_ENCRYPT, true));
    publicKeyAttributes.Add(new ObjectAttribute(CKA.CKA_VERIFY, true));
    publicKeyAttributes.Add(new ObjectAttribute(CKA.CKA_VERIFY_RECOVER, true));
    publicKeyAttributes.Add(new ObjectAttribute(CKA.CKA_WRAP, true));
    publicKeyAttributes.Add(new ObjectAttribute(CKA.CKA_MODULUS, publicKeyParams.Modulus));
    publicKeyAttributes.Add(new ObjectAttribute(CKA.CKA_PUBLIC_EXPONENT, publicKeyParams.Exponent));
    var publicKeyHandle = session.CreateObject(publicKeyAttributes);
D.R.
  • 20,268
  • 21
  • 102
  • 205
  • Is it true that private keys simply can't be directly imported like this and they have to be wrapped/unwrapped instead? – D.R. Dec 12 '18 at 14:17
  • It depends on the HSM vendor. But yes, most vendors do not allow direct import of keys (secret/private) into the HSM from the software. It has to be wrapped and unwrapped. – always_a_rookie Dec 12 '18 at 14:51
  • Do you know how to import an RSA private key? I've only found example to import a secret key (which is just a byte blob). An RSA private key consists of multiple blobs and I'm not sure how to unwrap it onto the HSM. – D.R. Dec 12 '18 at 16:45
  • A private key can be extracted as a single blob as well. You need to see how to do that in c#. – always_a_rookie Dec 12 '18 at 16:53
  • Yeah, but which kind of format does PKCS#11 want for unwrapping the key? – D.R. Dec 12 '18 at 17:38

3 Answers3

2

The answer is: you can't directly import a private key into a SafeNet Luna HSM. You have to first encrypt (wrap) the private key and can only then transfer it to the HSM. See PKCS#11 unwrap private key to HSM for an answer on how to do this.

D.R.
  • 20,268
  • 21
  • 102
  • 205
1

Try "CKA_PRIVATE = false": new ObjectAttribute(CKA.CKA_PRIVATE, false)

leo messi
  • 21
  • 2
0

Unfortunately PKCS#11 API does not provide details which exact attribute from supplied template caused the error but many PKCS#11 libraries support some kind of internal logging mechanism which may reveal the real cause of error. Exact steps needed to enable logging should be present in the documentation provided by the PKCS#11 library vendor.

My guess is that you're receiving CKR_TEMPLATE_INCONSISTENT because you are setting CKA_SENSITIVE to true. Private key imported in plain form has already lost its "sensitivity" because it was exposed to an external environment. I'm successfully using following template in Pkcs11Interop.X509Store project:

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_LABEL, ...),
    new ObjectAttribute(CKA.CKA_ID, ...),
    new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_RSA),
    new ObjectAttribute(CKA.CKA_MODULUS, rsaPrivKeyParams.Modulus.ToByteArrayUnsigned()),
    new ObjectAttribute(CKA.CKA_PUBLIC_EXPONENT, rsaPrivKeyParams.PublicExponent.ToByteArrayUnsigned()),
    new ObjectAttribute(CKA.CKA_PRIVATE_EXPONENT, rsaPrivKeyParams.Exponent.ToByteArrayUnsigned()),
    new ObjectAttribute(CKA.CKA_PRIME_1, rsaPrivKeyParams.P.ToByteArrayUnsigned()),
    new ObjectAttribute(CKA.CKA_PRIME_2, rsaPrivKeyParams.Q.ToByteArrayUnsigned()),
    new ObjectAttribute(CKA.CKA_EXPONENT_1, rsaPrivKeyParams.DP.ToByteArrayUnsigned()),
    new ObjectAttribute(CKA.CKA_EXPONENT_2, rsaPrivKeyParams.DQ.ToByteArrayUnsigned()),
    new ObjectAttribute(CKA.CKA_COEFFICIENT, rsaPrivKeyParams.QInv.ToByteArrayUnsigned())
};
jariq
  • 11,681
  • 3
  • 33
  • 52
  • Tried it without CKA_SENSITIVE -> no success. Even tried exactly your template -> no success. – D.R. Dec 13 '18 at 09:33
  • @D.R. please enable logging as described in SafeNet documentation and explore/share the logs. – jariq Dec 13 '18 at 11:04