python-pkcs11 icon indicating copy to clipboard operation
python-pkcs11 copied to clipboard

CloudHSM Support

Open videlanicolas opened this issue 7 years ago • 27 comments

Hi! I'm wondering if there is a project to add CloudHSM on the list of supported devices. I can help with the implementation.

Please tag this as feature request!

videlanicolas avatar Nov 13 '17 13:11 videlanicolas

Yes, I'd be very interested in adding CloudHSM to the support list. I don't have access to a CloudHSM setup, would it be possible to add a Buildbot client to an EC2 connected to CloudHSM? Then we could test pull requests against the device immediately.

danni avatar Nov 14 '17 02:11 danni

I can confirm that python-pkcs11 works with CloudHSM, as I'm running a workload in exactly that configuration. Of course this isn't the same as it being supported. :-) As far as ongoing testing is concerned, I guess the main factor would be cost: CloudHSM costs ~ $1.50 an hour to run.

Of course you could spin the CloudHSM down when it's not being used and there's nothing to test but then the test has a fair bit more work to do (spin up CloudHSM, connect etc, run tests, spin down). A possibility though.

g-a-d avatar Nov 14 '17 08:11 g-a-d

I think there's also a significant upfront payment to provision a CloudHSM into your environment. Basically I don't have that kind of money. I'd hoped to convince Amazon to donate some resources, but I haven't succeeded yet.

danni avatar Nov 14 '17 22:11 danni

There used to be an upfront cost, under the original CloudHSM product (now rebadged 'CloudHSM Classic'). Basically you'd purchase a device and they'd rack it for you and look after it. Not very cloudy at all.

However in August they massively updated the product and it's now much more of a cloud-native product; no up-front cost, per-hour billing, spin up/down at will, etc. It's different hardware (was Safenet Luna, now Cavium LiquidSecurity) but of course both support PKCS11.

Details: https://aws.amazon.com/blogs/aws/aws-cloudhsm-update-cost-effective-hardware-key-management/

g-a-d avatar Nov 15 '17 00:11 g-a-d

hi, i am using the library with cloudhsm and it works just fine. i am using it for key generation and storage for both aes and rsa, and also for encryption and decryption. works really well and its simple to run. i haven't run beyond those few operations but given its pkcs#11 both ends then it should all work fine. cost wise cloudhsm is now USD $1.99 per hour per hsm (you can have just one, or a cluster). its very cheap when you consider you are getting dedicated hsm's for your exclusive use, but as a managed service.

ralphstone avatar Jan 27 '18 00:01 ralphstone

I could set up a CloudFormation to temporarily spin up an EC2 / CloudHSM to run the unit tests, however I am sort of hoping someone might be willing to install the Buildbot on their existing test system.

danni avatar Jan 29 '18 00:01 danni

I have the unit tests running with my cloudhsm but there is quite a lot of failures so I think I might be missing something since the library does work with it for the most part. The unit test logs can be found https://pastebin.com/e44v941P. The only problem I've ran into with cloudhsm only started happening recently. I am receiving a CKR_TEMPLATE_INCONSISTENT error when attempting to create an AES key. I have upgraded to 0.5.0 but unfortunately the problem persists. I had successfully created AES keys in December 2017.

brianorwhatever avatar Feb 01 '18 23:02 brianorwhatever

I've been trying to find a user guide for the Cavium devices to get an idea of what it doesn't like, and/or any debugging environment variables that might allow it to inform us what it doesn't like.

Here is the template used to create keys:

        template_ = {
            Attribute.CLASS: ObjectClass.SECRET_KEY,
            Attribute.ID: id or b'',
            Attribute.LABEL: label or '',
            Attribute.TOKEN: store,
            Attribute.PRIVATE: True,
            Attribute.SENSITIVE: True,
            # Capabilities
            Attribute.ENCRYPT: MechanismFlag.ENCRYPT & capabilities,
            Attribute.DECRYPT: MechanismFlag.DECRYPT & capabilities,
            Attribute.WRAP: MechanismFlag.WRAP & capabilities,
            Attribute.UNWRAP: MechanismFlag.UNWRAP & capabilities,
            Attribute.SIGN: MechanismFlag.SIGN & capabilities,
            Attribute.VERIFY: MechanismFlag.VERIFY & capabilities,
            Attribute.DERIVE: MechanismFlag.DERIVE & capabilities,
        }

        if key_type is KeyType.AES:
            if key_length is None:
                raise ArgumentsBad("Must provide `key_length'")

            template_[Attribute.VALUE_LEN] = key_length // 8  # In bytes

Without any way to increase the debug level from the device, it will have to be a process of elimination to work out which attribute is upsetting it.

danni avatar Feb 02 '18 04:02 danni

i can login to the hsm and fetch all attributes for one of my keys generated using the hsm console...i'm out now but will ping through later

ralphstone avatar Feb 02 '18 04:02 ralphstone

I have tried some elimination but I can't find anything that seems to help. I was able to extract these attributes from a key that works. I can't remember if I created this key from python last year or through the cloudhsm key management tool.

OBJ_ATTR_CLASS 0x00000004 OBJ_ATTR_DECRYPT 0x00000001 OBJ_ATTR_ENCRYPT 0x00000001 OBJ_ATTR_EXTRACTABLE 0x00000001 OBJ_ATTR_ID

OBJ_ATTR_KCV 0x8e50be OBJ_ATTR_KEY_TYPE 0x0000001f OBJ_ATTR_LABEL aes256 OBJ_ATTR_LOCAL 0x00000001 OBJ_ATTR_MODULUS_BITS 0x00000000 OBJ_ATTR_PRIVATE 0x00000001 OBJ_ATTR_SENSITIVE 0x00000001 OBJ_ATTR_SIGN 0x00000000 OBJ_ATTR_TOKEN 0x00000001 OBJ_ATTR_UNWRAP 0x00000001 OBJ_ATTR_VALUE_LEN 0x00000020 OBJ_ATTR_VERIFY 0x00000000 OBJ_ATTR_WRAP 0x00000001

brianorwhatever avatar Feb 02 '18 21:02 brianorwhatever

The problem could be related to creating ephemeral objects in a read-only session. I had this problem on the Nitrokey too, because they just hadn’t implemented this part of the spec (or couldn’t). I didn’t change it because writes on that device are slow and I am quite fond of the release your session and all is forgotten nature of the test suite.

On 3 February 2018 at 08:21:07, Brian Richter ([email protected](mailto:[email protected])) wrote:

I have tried some elimination but I can't find anything that seems to help. I was able to extract these attributes from a key that works. I can't remember if I created this key from python last year or through the cloudhsm key management tool.

OBJ_ATTR_CLASS 0x00000004 OBJ_ATTR_DECRYPT 0x00000001 OBJ_ATTR_ENCRYPT 0x00000001 OBJ_ATTR_EXTRACTABLE 0x00000001 OBJ_ATTR_ID

OBJ_ATTR_KCV 0x8e50be OBJ_ATTR_KEY_TYPE 0x0000001f OBJ_ATTR_LABEL aes256 OBJ_ATTR_LOCAL 0x00000001 OBJ_ATTR_MODULUS_BITS 0x00000000 OBJ_ATTR_PRIVATE 0x00000001 OBJ_ATTR_SENSITIVE 0x00000001 OBJ_ATTR_SIGN 0x00000000 OBJ_ATTR_TOKEN 0x00000001 OBJ_ATTR_UNWRAP 0x00000001 OBJ_ATTR_VALUE_LEN 0x00000020 OBJ_ATTR_VERIFY 0x00000000 OBJ_ATTR_WRAP 0x00000001

— You are receiving this because you commented. Reply to this email directly, view it on GitHub(https://github.com/danni/python-pkcs11/issues/14#issuecomment-362711133), or mute the thread(https://github.com/notifications/unsubscribe-auth/AAH5wAaqyydcbKlkPsv_9uc3Dngvj9wTks5tQ3xDgaJpZM4Qbwd2).

danni avatar Feb 06 '18 21:02 danni

i modified the code to use this template for AES-256 key generation and it works fine. the hsm seems to not like SENSITIVE being mentioned at all, and PRIVATE needs to be false.

template_ = { Attribute.CLASS: ObjectClass.SECRET_KEY, Attribute.VALUE_LEN: 32, Attribute.ID: id, Attribute.LABEL: label, Attribute.TOKEN: True, Attribute.PRIVATE: False, Attribute.EXTRACTABLE: True, Attribute.LOCAL: True, Attribute.ENCRYPT: True, Attribute.DECRYPT: True, Attribute.SIGN: False, Attribute.VERIFY: False, Attribute.WRAP: True, Attribute.UNWRAP: True }

ralphstone avatar Apr 08 '18 10:04 ralphstone

PRIVATE = False suggests that the object can be read without being authenticated. However it may be unhappy with the values being provided at all.

danni avatar Apr 10 '18 04:04 danni

Hello there, folks! I've been working with CloudHSM and PyKCS11, but last week I started testing it with python-pkcs11. BTW, danni, your documentation is really good!

Let me highlight some important points so as to help you, folks:

  • For all key types, CKA_PRIVATE must be set to TRUE. Otherwise, you can have trouble with the latest versions of the CloudHSM [1]. This is an example of how to generate AES keys:

internal_key = session.generate_key(KeyType.AES, 256, label="AES_internal_key", mechanism=Mechanism.AES_KEY_GEN, template={ Attribute.CLASS: ObjectClass.SECRET_KEY, Attribute.TOKEN: True, Attribute.PRIVATE: True, Attribute.SENSITIVE: True, Attribute.ENCRYPT: True, Attribute.DECRYPT: True, Attribute.WRAP: True, Attribute.UNWRAP: True, Attribute.SIGN: False, Attribute.VERIFY: False, Attribute.EXTRACTABLE: True, Attribute.VALUE_LEN: 32, Attribute.DERIVE: True })

These are the version of the CloudHSM packages I have installed on my client instance (Amazon Linux 1):

cloudhsm-client-1.1.1-1.el6.x86_64 cloudhsm-client-pkcs11-1.1.1-1.el6.x86_64

  • If you want to increase the log level of the CloudHSM client process, edit the /opt/cloudhsm/etc/cloudhsm_client.cfg file, changing the log_level parameter from INFO to DEBUG. Then, reload the CloudHSM client process by running:

sudo stop cloudhsm-client sudo start cloudhsm-client

The logs are written to /opt/cloudhsm/run/cloudhsm_client.log.

danni, could you please send me the instructions of how to set up Buildbot so as to perform the python-pkcs11 tests?

[1] https://docs.aws.amazon.com/cloudhsm/latest/userguide/client-history.html

suzue-chan avatar Sep 18 '18 15:09 suzue-chan

Thanks! So much PKCS#11 documentation is unhelpful and vague. After reading so many different documents, and so much source code, to learn how to program PKCS#11, I figured people deserved some clear documentation.

Unfortunately following a data centre move, I think the machine that had my HSM devices plugged into it is offline, and so the buildbot is offline.

danni avatar Sep 18 '18 23:09 danni

The tests themselves are straightforward to run, just built on the Python unittest module, e.g.

# export PKCS11_MODULE=
# export PKCS11_TOKEN_LABEL=
# export PKCS11_TOKEN_PIN=

python -m unittest

danni avatar Sep 18 '18 23:09 danni

Hey, danni, thanks for info! Let me ask you something...

I've created a Python code that performs wrapping/unwrapping of AES keys. It's working fine.

Now I'm writing a script to perform wrapping/unwrapping of RSA private keys. The wrapping operation is fine, however I'm getting the following error when trying to unwrap the wrapped key:

C_UnwrapKey failed with error CKR_TEMPLATE_INCONSISTENT : 0x000000d1

key_template = { Attribute.PRIVATE: True, Attribute.SENSITIVE: True, Attribute.DECRYPT: True, Attribute.SIGN: True, Attribute.UNWRAP: True, Attribute.LABEL: "unwrapped_rsa_private_key", Attribute.EXTRACTABLE: True Attribute.DERIVE: False }

I noticed that, when you don't specify the parameter 'capabilities' for unwrap_key(), it uses a default value as follows:

capabilities = DEFAULT_KEY_CAPABILITIES[key_type]

This results in the following value:

MechanismFlag.ENCRYPT | MechanismFlag.DECRYPT | MechanismFlag.SIGN | MechanismFlag.VERIFY | MechanismFlag.WRAP | MechanismFlag.UNWRAP

Since I'm unwrapping a private key, I specified a custom capabilities set as follows:

key_capabilities = MechanismFlag.DECRYPT | MechanismFlag.SIGN | MechanismFlag.UNWRAP

And then I invoked unwrap_key() as follows:

unwrapped_key = wrapping_key.unwrap_key(ObjectClass.PRIVATE_KEY, KeyType.RSA, wrapped_key, mechanism=Mechanism.AES_KEY_WRAP, store=True, capabilities=key_capabilities, template=key_template)

But I'm still getting the error CKR_TEMPLATE_INCONSISTENT.

Is there any way to see the complete template that is being sent to C_UnwrapKey?

suzue-chan avatar Sep 19 '18 14:09 suzue-chan

Nothing currently logs the templates, one could add that easily enough.

Here's the prototype template (_pkcs11.pyx:1051):

        template_ = {
            Attribute.CLASS: object_class,
            Attribute.KEY_TYPE: key_type,
            Attribute.ID: id or b'',
            Attribute.LABEL: label or '',
            Attribute.TOKEN: store,
            # Capabilities
            Attribute.ENCRYPT: MechanismFlag.ENCRYPT & capabilities,
            Attribute.DECRYPT: MechanismFlag.DECRYPT & capabilities,
            Attribute.WRAP: MechanismFlag.WRAP & capabilities,
            Attribute.UNWRAP: MechanismFlag.UNWRAP & capabilities,
            Attribute.SIGN: MechanismFlag.SIGN & capabilities,
            Attribute.VERIFY: MechanismFlag.VERIFY & capabilities,
            Attribute.DERIVE: MechanismFlag.DERIVE & capabilities,
        }

Your attributes would then be update()ed onto these.

danni avatar Sep 19 '18 22:09 danni

I am trying to generate an EC-keypair using python-pkcs11 with CloudHSMv2 using LunaHSM. But I am also getting the same known error message: C_GenerateKeyPair failed with error CKR_TEMPLATE_INCOMPLETE : 0x000000d0.

For AES keys, providing a template as @suzue-chan showed in his post above (https://github.com/danni/python-pkcs11/issues/14#issuecomment-422433078) did allow me to create an AES key.

Does anyone know public and private templates that can be provided for CloudHSM to generate an EC keypair with python-pkcs11?

bjarnemagnussen avatar Sep 23 '18 10:09 bjarnemagnussen

Now I'm writing a script to perform wrapping/unwrapping of RSA private keys. The wrapping operation is fine, however I'm getting the following error when trying to unwrap the wrapped key:

C_UnwrapKey failed with error CKR_TEMPLATE_INCONSISTENT : 0x000000d1

Not that it helps much, but I'm also hitting that issue using https://github.com/bentonstark/py-hsm. I suspect this might be a firmware and/or client software issue (not exactly unlikely given https://docs.aws.amazon.com/cloudhsm/latest/userguide/KnownIssues.html).

mattburgess avatar Oct 25 '18 22:10 mattburgess

Oh, hang on, I've just realised that I'm hitting that with AES keys, but you said you got that working? If so, what template did you use for the unwrapped key?

It's probably also important to note here that the Cavium devices that CloudHSMv2 use don't support wrapping keys using an RSA key. You can wrap RSA keys with an AES key, but not the other way around, as CKM_AES_KEY_WRAP is the only supported key wrap mechanism (https://docs.aws.amazon.com/cloudhsm/latest/userguide/pkcs11-mechanisms.html).

mattburgess avatar Oct 25 '18 22:10 mattburgess

Is there any way to see the complete template that is being sent to C_UnwrapKey?

Based on: https://www.cryptsoft.com/pkcs11doc/v220/pkcs11__all_8h.html#aC_UnwrapKey

To partition the unwrapping keys so they can only unwrap a subset of keys the attribute CKA_UNWRAP_TEMPLATE can be used on the unwrapping key to specify an attribute set that will be added to attributes of the key to be unwrapped. If the attributes do not conflict with the user supplied attribute template, in 'pTemplate', then the unwrap will proceed. The value of this attribute is an attribute template and the size is the number of items in the template times the size of CK_ATTRIBUTE. If this attribute is not present on the unwrapping key then no additional attributes will be added. If any attribute conflict occurs on an attempt to unwrap a key then the function shall return CKR_TEMPLATE_INCONSISTENT.

Is it possible that you have an unwrap template on the wrapping key that collides with the passed in pTemplate? The pTemplate should be blank, shouldn't it? If the Unwrap Template is present then all values should apply to the unwrapped key and not have any collisions.

... sorry to bump an old discussion, I was unsure if the comments here have been resolved.

alfredgamulo avatar Jan 17 '19 19:01 alfredgamulo

It's probably also important to note here that the Cavium devices that CloudHSMv2 use don't support wrapping keys using an RSA key. You can wrap RSA keys with an AES key, but not the other way around, as CKM_AES_KEY_WRAP is the only supported key wrap mechanism (https://docs.aws.amazon.com/cloudhsm/latest/userguide/pkcs11-mechanisms.html).

RSA Wraps/Unwraps with Encrypt/Decrypt. Mechanism=CKM_RSA_PKCS

alfredgamulo avatar Jan 17 '19 19:01 alfredgamulo

I believe the unwrapping issues are now being sorted out in #44 / #45. Does anyone feel like putting together a page for the documentation on any template changes required to use CloudHSM ?

danni avatar Mar 03 '19 07:03 danni

Let me document something here while I still have access to Gemalto SafeNet (== standalone version of CloudHSM v1). With commit https://github.com/danni/python-pkcs11/commit/bc372de1485c7cd4cb37aeda2a30cbcd493b53e1:

unwrap_key now works (AES-CBC-PAD, DES3-CBC-PAD of a private key onto the HSM) but the template needs to have a few flags deleted:

# these capabilities must not be sent to the HSM or you will get
# inconsistent template error...
# DEFAULT is new in the commit and represents "delete this attribute from the
# outgoing template"
template={ pkcs11.Attribute.ENCRYPT: pkcs11.constants.DEFAULT,
    pkcs11.Attribute.VERIFY: pkcs11.constants.DEFAULT,
    pkcs11.Attribute.WRAP: pkcs11.constants.DEFAULT }

The other flags DECRYPT SIGN UNWRAP DERIVE are all fine.

aalba6675 avatar Mar 05 '19 02:03 aalba6675

CloudHSM doesn't seem to support C_SetAttributeValue.

wjmelements avatar May 14 '19 04:05 wjmelements

The only attribute supported for C_SetAttributeValue is Attribute.TOKEN (OBJ_ATTR_TOKEN).

(only the following attribute's value can be modified)
           OBJ_ATTR_TOKEN                  = 1

CloudHSM also doesn't support C_GetAttributeValue for most of the attributes.

C_GetAttributeValue failed with error CKR_ATTRIBUTE_TYPE_INVALID : 0x00000012

The following are all of the possible attribute values for getAttributes.

      OBJ_ATTR_CLASS                  = 0
      OBJ_ATTR_TOKEN                  = 1
      OBJ_ATTR_PRIVATE                = 2
      OBJ_ATTR_LABEL                  = 3
      OBJ_ATTR_KEY_TYPE               = 256
      OBJ_ATTR_ID                     = 258
      OBJ_ATTR_SENSITIVE              = 259
      OBJ_ATTR_ENCRYPT                = 260
      OBJ_ATTR_DECRYPT                = 261
      OBJ_ATTR_WRAP                   = 262
      OBJ_ATTR_UNWRAP                 = 263
      OBJ_ATTR_SIGN                   = 264
      OBJ_ATTR_VERIFY                 = 266
      OBJ_ATTR_LOCAL                  = 355
      OBJ_ATTR_MODULUS                = 288
      OBJ_ATTR_MODULUS_BITS           = 289
      OBJ_ATTR_PUBLIC_EXPONENT        = 290
      OBJ_ATTR_VALUE_LEN              = 353
      OBJ_ATTR_EXTRACTABLE            = 354
      OBJ_ATTR_KCV                    = 371

wjmelements avatar May 15 '19 23:05 wjmelements