bentonstark / py-hsm

Python module for accessing PKCS#11 compliant HSMs
Other
56 stars 17 forks source link

Can't generate ECC keypair on AWS CloudHSM #7

Closed mattburgess closed 4 years ago

mattburgess commented 5 years ago

Hi, we're trying to assess CloudHSM for its suitability for our project. After a bit of wrangling, I've managed to get py-hsm to generate an AES key and an RSA keypair. However, I can't figure out the right set of parameters to pass to it to generate an ECC keypair. No matter what I try I always get this back:

  File "/usr/local/lib/python3.7/site-packages/pyhsm/hsmclient.py", line 1654, in create_ecc_key_pair
    raise HsmError(bytes_to_str(msg.value))
pyhsm.hsmerror.HsmError: 'create_ec_key_pair: __gen_ec_key_pair failed with the return value 19. CKR_ATTRIBUTE_VALUE_INVALID (0x00000013)'

This happens to be reproducible by examples/ecgen-test.py:

Similar issues were encountered with both AES & RSA generation, but by tweaking various parameters I was able to get those to work. I'm not sure if the underlying libhsm or lower level API supports it, but if it could bubble up the attribute and attribute value it didn't like, that'd really help! Otherwise, if anyone knows how to call create_ecc_key_pair() successfully against a CloudHSM device I'd appreciate any help please.

bentonstark commented 5 years ago

Hi Matthew. When you say "CloudHSM" are you referring to the AWS CloudHSM which is Cavium Liquid Security backed service or some other vendor such as SafeNet / Gemalto?

Both the libhsm and py-hsm components support EC key generation and usage and have been heavily tested again various HSM providers. That said, depending on the version of Cavium HSM on the firmware of the actual hardware device there are known issues with regards to what attributes they support and what those values can be.

On Mon, Oct 15, 2018 at 10:16 AM Matthew Burgess notifications@github.com wrote:

Hi, we're trying to assess CloudHSM for its suitability for our project. After a bit of wrangling, I've managed to get py-hsm to generate an AES key and an RSA keypair. However, I can't figure out the right set of parameters to pass to it to generate an ECC keypair. No matter what I try I always get this back:

File "/usr/local/lib/python3.7/site-packages/pyhsm/hsmclient.py", line 1654, in create_ecc_key_pair raise HsmError(bytes_to_str(msg.value)) pyhsm.hsmerror.HsmError: 'create_ec_key_pair: __gen_ec_key_pair failed with the return value 19. CKR_ATTRIBUTE_VALUE_INVALID (0x00000013)'

This happens to be reproducible by examples/ecgen-test.py:

Similar issues were encountered with both AES & RSA generation, but by tweaking various parameters I was able to get those to work. I'm not sure if the underlying libhsm or lower level API supports it, but if it could bubble up the attribute and attribute value it didn't like, that'd really help! Otherwise, if anyone knows how to call create_ecc_key_pair() successfully against a CloudHSM device I'd appreciate any help please.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/bentonstark/py-hsm/issues/7, or mute the thread https://github.com/notifications/unsubscribe-auth/AK8sQwBnti56GYFZR-7o6dLIXJil7LmIks5ulJjLgaJpZM4Xcb3q .

mattburgess commented 5 years ago

If it helps any, I've created a keypair on the CloudHSM device using the command line tools, and have tried the following code to do the same using py-hsm:

        key_handles = c.create_ecc_key_pair(
                public_key_label="my_ec_pub",
                private_key_label="my_ec_pvt",
                ec_params=EcCurveOids.P384,
                token=True,
                public_private=True,
                private_private=True,
                sensitive=True, # Private = True, Public = False
                modifiable=True,
                extractable=True, # Private = False, Public = True
                sign_verify=True, # Sign = False, Verify = True
                encrypt_decrypt=False,
                wrap_unwrap=False,
                derive=False)
        print("public_handle: {0}".format(key_handles[0]))
        print("private_handle: {0}".format(key_handles[1]))

I've marked up which attributes differ on the cmd-line generated keys, as I suspect that py-hsm/libhsm's behaviour of trying to set the attributes the same on both the public and private keys might be where things are going wrong:

Attribute Private Public
sign True False
verify False True
extractable True False
sensitive True False
mattburgess commented 5 years ago

Yes, sorry, it's the AWS CloudHSM (Cavium) device I'm using. I've been careful to ensure I'm using the latest CloudHSM command line tools and PKCS11 libraries due to https://docs.aws.amazon.com/cloudhsm/latest/userguide/KnownIssues.html#ki-pkcs11-sdk - here's as much device info as I think I can get at the moment:

    SDK Version: 2.03
----------------------------------------
slotNumber: 1
label: cavium
manufacturer: Cavium Networks
model: NITROX-III CNN35
serialNumber: 3.0G1634-ICM001
sessionCount: 0
hardwareVersion: 3.0
firmwareVersion: 2.3
bentonstark commented 5 years ago

Earlier this year I worked extensively with Cavium to identify and have them fix some of these specific issues. They did that fix for the version of firmware I was working with for their FIPS HSM device. The AWS CloudHSM based on these known issues appears to be several versions behind. Particularly the CKA_DERIVE and CKA_SENSITIVE attributes not being properly supported or understood by the HSM's firmware.

Basically this is not a problem with the libhsm or py-hsm libraries as they work with all the other HSMs I have tested it with. So the workaround will be to make some Cavium specific modifications until they update the firmware on the CloudHSM device. Probably the easiest way to do that is via a patch.

On Mon, Oct 15, 2018 at 11:08 AM Matthew Burgess notifications@github.com wrote:

Yes, sorry, it's the AWS CloudHSM (Cavium) device I'm using. I've been careful to ensure I'm using the latest CloudHSM command line tools and PKCS11 libraries due to https://docs.aws.amazon.com/cloudhsm/latest/userguide/KnownIssues.html#ki-pkcs11-sdk

  • here's as much device info as I think I can get at the moment:

    SDK Version: 2.03

    slotNumber: 1 label: cavium manufacturer: Cavium Networks model: NITROX-III CNN35 serialNumber: 3.0G1634-ICM001 sessionCount: 0 hardwareVersion: 3.0 firmwareVersion: 2.3

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/bentonstark/py-hsm/issues/7#issuecomment-429892267, or mute the thread https://github.com/notifications/unsubscribe-auth/AK8sQ0yrm1psc-RzGH7qy27QKHAMjGeFks5ulKTpgaJpZM4Xcb3q .

mattburgess commented 5 years ago

Thanks for the really quick response @bentonstark! On a related note, I've just tried the wrapping/unwrapping example and hit this:

  File "/usr/local/lib/python3.7/site-packages/pyhsm/hsmclient.py", line 2495, in wrap_key
    raise HsmError(bytes_to_str(msg.value))
pyhsm.hsmerror.HsmError: 'wrap_key: __wrap_key() failed to wrap target key; return value 112 CKR_MECHANISM_INVALID (0x00000070)'

According to https://docs.aws.amazon.com/cloudhsm/latest/userguide/pkcs11-mechanisms.html I think I need to specify CKM_AES_KEY_WRAP when wrapping a key. That doesn't appear to be defined in hmsenums.py. According to oasis, it should be '0x00002109'. If you think my analysis is correct, I'm happy to raise a PR to add this, otherwise feel free to tell me I'm completely on the wrong track!

bentonstark commented 5 years ago

Be aware that the version of Cavium you are accessing probably has limitations on key wrapping support. Cavium has a very narrow list of PKCS#11 functions they support especially when compared to other HSM vendors such as Gemalto / SafeNet and Utimaco. For example, the version you are using probably has not support allows for a symmetric key such as an AES key to be wrapped off with an asymmetric key such as an RSA public key.

Cavium only supports CKM_AES_KEY_WRAP mechanism with C_Wrap / C_Unwrap calls. Calling C_Wrap to wrap an AES using and RSA public key with mechanism CKM_RSA_PKCS_OAEP results in the error CKR_MECHANISM_INVALID.

You can set send in any valid mechanism directly without using the enumerations as shown in the test script. https://github.com/bentonstark/py-hsm/blob/master/examples/keywrap.py#L39

On Mon, Oct 15, 2018 at 11:45 AM Matthew Burgess notifications@github.com wrote:

Thanks for the really quick response @bentonstark https://github.com/bentonstark! On a related note, I've just tried the wrapping/unwrapping example and hit this:

File "/usr/local/lib/python3.7/site-packages/pyhsm/hsmclient.py", line 2495, in wrap_key raise HsmError(bytes_to_str(msg.value)) pyhsm.hsmerror.HsmError: 'wrap_key: __wrap_key() failed to wrap target key; return value 112 CKR_MECHANISM_INVALID (0x00000070)'

According to https://docs.aws.amazon.com/cloudhsm/latest/userguide/pkcs11-mechanisms.html I think I need to specify CKM_AES_KEY_WRAP when wrapping a key. That doesn't appear to be defined in hmsenums.py. According to oasis, it should be '0x00002109'. If you think my analysis is correct, I'm happy to raise a PR to add this, otherwise feel free to tell me I'm completely on the wrong track!

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/bentonstark/py-hsm/issues/7#issuecomment-429907337, or mute the thread https://github.com/notifications/unsubscribe-auth/AK8sQ4gu0dmukFwUqaFYfWV-su9SG_RZks5ulK2egaJpZM4Xcb3q .

edomaur commented 5 years ago

hello,

I've exactly the same problem, resulting in a CKR_ATTRIBUTE_VALUE_INVALID error. I tried the rsagent_test.py script :

python rsagen-test.py -size 2048 -mech RSA_PKCS_KEY_PAIR_GEN -p11 /opt/cloudhsm/lib/libcloudhsm_pkcs11_standard.so -pin UUUU:XXXXXXX -slot 1

and the result is :

starting

 test...
        SDK Version: 2.03

C_GenerateKeyPair failed with error CKR_ATTRIBUTE_VALUE_INVALID : 0x00000013
Traceback (most recent call last):
  File "rsagen-test.py", line 84, in <module>
    __main()
  File "rsagen-test.py", line 36, in __main
    args.func(args)
  File "rsagen-test.py", line 61, in __menu_handler
    public_private=False)
  File "/root/PYHSM/lib/python3.4/site-packages/pyhsm/hsmclient.py", line 1476, in create_rsa_key_pair
    raise HsmError(bytes_to_str(msg.value))
pyhsm.hsmerror.HsmError: 'create_rsa_key_pair: __gen_rsa_key_pair failed with the return value 19. CKR_ATTRIBUTE_VALUE_INVALID (0x00000013)'

Any idea ?

bentonstark commented 5 years ago

The client version and firmware version of Cavium's Liquid Security appliance in use by AWS CloudHSM has numerous bugs. One such bug is the failure to properly support CKA_DERIVE in attribute templates when invoking C_GenerateKeyPair for both RSA and EC keys.. The other is a client software bug which also produces the error CKR_ATTRIBUTE_VALUE_INVALID when invoking C_GenerateKeyPair for both RSA and EC keys.

You need to make verify you are on the latest client version. See the following AWS notes. If things are still not working after the client update let me know.

https://docs.aws.amazon.com/cloudhsm/latest/userguide/KnownIssues.html#ki-pkcs11-sdk

edomaur commented 5 years ago

Yes, it's the last version (or at least the 1.1.1) I've installed it last week :

Installed Packages
Name        : cloudhsm-client-pkcs11
Arch        : x86_64
Version     : 1.1.1
Release     : 1.el7
Size        : 4.0 M
Repo        : installed
Summary     : AWS CloudHSM PKCS#11 software library.
URL         : https://aws.amazon.com/documentation/cloudhsm/
License     : unknown
Description : AWS CloudHSM PKCS#11 software library.

and this :

    SDK Version: 2.03
----------------------------------------
slotNumber: 1
label: cavium
manufacturer: Cavium Networks
model: NITROX-III CNN35
serialNumber: 3.0G1640-ICM001
sessionCount: 0
hardwareVersion: 3.0
firmwareVersion: 2.3

(the same as @mattburgess except for the serial number)

edomaur commented 5 years ago

What I think is interesting is that I can generate RSA key pairs with the pkcs11-tool from the opensc package, and it works. CKR_ATTRIBUTE_TYPE_INVALID is handled as a warning but the keys are created. Perhaps CKR_ATTRIBUTE_VALUE_INVALID is linked to the type of the attribute ? (I'm a bit lost)

# pkcs11-tool --module /opt/cloudhsm/lib/libcloudhsm_pkcs11.so --keypairgen --key-type rsa:2048 --id 38 --label 'test-11' --login --pin '<USER>:<PASSWORD>'
        SDK Version: 2.03
Using slot 0 with a present token (0x1)
Key pair generated:
Private Key Object; RSA 
  label:      test-11
  ID:         38
  Usage:      decrypt, sign
C_GetAttributeValue failed with error CKR_ATTRIBUTE_TYPE_INVALID : 0x00000012
, unwrap

C_GetAttributeValue failed with error CKR_ATTRIBUTE_TYPE_INVALID : 0x00000012
warning: PKCS11 function C_GetAttributeValue(ALWAYS_AUTHENTICATE) failed: rv = CKR_ATTRIBUTE_TYPE_INVALID (0x12)

Public Key Object; RSA 2048 bits
  label:      test-11
  ID:         38
  Usage:      encrypt, verify, wrap
bentonstark commented 5 years ago

Its still all bugs in Cavium's software. I just recently did a HSM comparison report between 5 vendors and Cavium by far has the most issues with PKCS inconsistencies and implementation errors. The CKR_ errors produced by the vendors PKCS-11 API are not something that can be dismissed by the consumer of the API as a warning. Ignoring them is at the peril of the implementer. The error coming back from pkcs11-tool is on the query operation that happens after the C_GenerateKeyPair call. Basically the tool is asking to pull the attributes to verify the key was created and Cavium doesn't support some of the attribute calls resulting in a CKR_ATTRIBUTE_TYPE error to be returned. It looks like the first error did not report which attribute it failed on and the second failure was due to a query on CKA_ALWAYS_AUTHENTICATE.

Your next step to try and fix this issue is to take note of the message I put on the libhsm home page. _Note: Latest Cavium firmware requires CKADERIVE statements to be commented out from all templates. This will require you to grep through the p11hsm.cpp source file and commenting out any CKA_DERIVE template statements. In my testing with the Cavium FIPS PCIE card, Cavium was able to get the fix into their upstream code commits but I have no idea if AWS pushed them to all their servers.

The specific code section in libhsm that builds up the templates for C_GenerateKeyPair is the block lines 456 to 487. That is the code that sets up the template for RSA key pair creation. You can start with commenting out Line 484 and then re-compiling and re-installing the library on your machine. If that works you will then need to comment out all CKA_DERIVE statement that fail.

You will notice the opensc pkcs11-tool's source has a branch where they don't set CKA_DERIVE unless explicitly directed by the user.

edomaur commented 5 years ago

Ok, thanks for you help :-)