Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for AWS CloudHSM #179

Open
dlutsch opened this issue Oct 16, 2023 · 11 comments
Open

Support for AWS CloudHSM #179

dlutsch opened this issue Oct 16, 2023 · 11 comments

Comments

@dlutsch
Copy link

dlutsch commented Oct 16, 2023

As best I can tell there is currently no native support for accessing private keys stored in Amazon's CloudHSM service. It would be great if this feature could be added.

@ebourg
Copy link
Owner

ebourg commented Oct 16, 2023

I agree it would be nice to support it, but this service is very expensive ($1600/month) and I can't spend that much for this project. If someone using AWS CloudHSM could share its access I would get a look.

@ebourg
Copy link
Owner

ebourg commented Oct 17, 2023

I got a look at the AWS documentation, and as I understand the CloudHSM REST API allows one to only manage the HSM instances, and not to perform cryptographic operations. This is performed through a dedicated client SDK that takes the form of a PKCS#11 module or a JCA provider. The client SDK doesn't look to be open source, the JCA provider isn't available on Maven Central and must be installed with a system package. The provider is actually a wrapper over a native library, so figuring out the underlying protocol to access the HSM isn't trivial.

However an HSM can be configured as a keystore for AWS KMS, so Jsign should be able to use a key in a CloudHSM instance already.

@ebourg
Copy link
Owner

ebourg commented Oct 17, 2023

Also worth noting, the name "LiquidSecurity" appears in the documentation and in the native library, that's most likely the name of the Marvell HSM hardware used by AWS. It seems to use an undocumented binary protocol.

If someone manages to reverse engineer this protocol we may be able to integrate it directly into Jsign, but in the meantime it's more reasonable to use the PKCS#11 module provided by AWS. We could add an AWSCLOUDHSM storetype that configures the SunPKCS11 provider similarly to the YUBIKEY and OPENSC storetypes, but I'll need someone to share a CloudHSM account to test it properly.

@hellais
Copy link

hellais commented Jul 26, 2024

Hey @ebourg we are currently using cloudHSM and would be glad to test out whatever code you write on our CloudHSM instance. We are currently struggling with writing a valid SunPKCS11 configuration file that is going to work with our keys.

We have a bunch of keys that our cert provider gave us and are stored on the HSM cluster like this (this is the truncated output of key list command run in interactive mode via /opt/bin/cloudhsm/bin/cloudhsm-cli):

aws-cloudhsm > key list
{
  "error_code": 0,
  "data": {
    "matched_keys": [
      {
        "key-reference": "0x000000000000001d",
        "attributes": {
          "label": "XXXX_2024-04-26_6"
        }
      },
      {
        "key-reference": "0x000000000000001e",
        "attributes": {
          "label": "XXXX_2024-04-26_5"
        }
      },
      {
        "key-reference": "0x000000000000001f",
        "attributes": {
          "label": "XXXX_2024-04-26_6"
        }
      },
      {
        "key-reference": "0x0000000000000021",
        "attributes": {
          "label": "XXXX_2024-04-26_4"
        }
[.. SNIP ...]
   ],
    "total_key_count": 12,
    "returned_key_count": 10,
    "next_token": "10"
  }
}

We tried setting it up by creating a sunpkcs.cfg that looks something like:

name = OONICloudHSM
library = /opt/cloudhsm/lib/libcloudhsm_pkcs11.so
attributes(*,CKO_PRIVATE_KEY,CKK_RSA) = {
  CKA_SIGN = true
  CKA_ID = "0x000000000000001d"
}

Or with CKA_LABEL = XXXX_2024-04-26_6

But we kept running into parsing errors. Do you perhaps have some suggestions on how we might go about getting this to work?

The HSM has this proprietary binary called /opt/cloudhsm/bin/cloudhsm-cli which implements all the key operations and in order to perform signing you need to authenticate to the HSM using a username which has the role set to crypto-user.

I am imagining that these aspects of code signing are somehow part of the PKCS#11 protocol and I imagine it would be quite similar to how the https://github.com/ebourg/jsign/blob/master/jsign-crypto/src/main/java/net/jsign/SafeNetEToken.java and yubikey are setup.

We would be glad to assist in debugging this and I imagine it should be possible to even get it to work by just using the existing CLI with some particular flags using the generic pkcs#11 protocol.

We were able to get authentication to work using:

jsign --storetype PKCS11 -s sunpkcs.cfg --storepass "$CRYPTO_USERNAME:$CRYPTO_PASSWORD" myapp.exe

Where sunpkcs.cfg is what I was showing you above. Authentication works with the HSM, however we have some pieces missing on how we actually filter the correct key from the list.

Could you perhaps give us some help on how we might go about getting this to work? We would be glad to run commands on our cluster to help you help us get this working.

Thank you so much for your time and assistance.

@ebourg
Copy link
Owner

ebourg commented Jul 26, 2024

@hellais Did you check if the CloudHSM instance is available as a keystore for AWS KMS?

We were able to get authentication to work using:

jsign --storetype PKCS11 -s sunpkcs.cfg --storepass "$CRYPTO_USERNAME:$CRYPTO_PASSWORD" myapp.exe

What error message or stacktrace did you get with this syntax?

@hellais
Copy link

hellais commented Jul 26, 2024

Did you check if the CloudHSM instance is available as a keystore for AWS KMS?

I am going to try going this route, but it's quite a few hoops to jump through because we must use CloudHSM since it's a requirement to having an EV code signing cert.

I will let you know how it goes.

jsign --storetype PKCS11 -s sunpkcs.cfg --storepass "$CRYPTO_USERNAME:$CRYPTO_PASSWORD" myapp.exe
What error message or stacktrace did you get with this syntax?

When I run that command using:

name = OONICloudHSM
library = /opt/cloudhsm/lib/libcloudhsm_pkcs11.so

I get:

jsign: No certificate found in the keystore SunPKCS11-OONICloudHSM
Try `jsign --help' for more information.

While when I put in the config this:

name = OONICloudHSM
library = /opt/cloudhsm/lib/libcloudhsm_pkcs11.so
attributes(*,CKO_PRIVATE_KEY,CKK_RSA) = {
  CKA_SIGN = true
  CKA_ID = "0x0000000000000021"
}

I get the following error stack trace:

java.security.ProviderException: Failed to create a SunPKCS11 provider from the configuration sunpkcs.cfg
	at net.jsign.ProviderUtils.createSunPKCS11Provider(ProviderUtils.java:55)
	at net.jsign.KeyStoreType$5.getProvider(KeyStoreType.java:155)
	at net.jsign.KeyStoreBuilder.provider(KeyStoreBuilder.java:268)
	at net.jsign.KeyStoreBuilder.build(KeyStoreBuilder.java:281)
	at net.jsign.SignerHelper.build(SignerHelper.java:256)
	at net.jsign.SignerHelper.sign(SignerHelper.java:388)
	at net.jsign.JsignCLI.execute(JsignCLI.java:134)
	at net.jsign.JsignCLI.main(JsignCLI.java:40)
Caused by: java.lang.reflect.InvocationTargetException
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:118)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at net.jsign.ProviderUtils.createSunPKCS11Provider(ProviderUtils.java:48)
	... 7 more
Caused by: java.security.InvalidParameterException: Error configuring SunPKCS11 provider
	at jdk.crypto.cryptoki/sun.security.pkcs11.SunPKCS11.configure(SunPKCS11.java:130)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
	... 9 more
Caused by: sun.security.pkcs11.ConfigurationException: Unexpected value: Token[0x0000000000000021], line 5
	at jdk.crypto.cryptoki/sun.security.pkcs11.Config.excToken(Config.java:392)
	at jdk.crypto.cryptoki/sun.security.pkcs11.Config.parseWord(Config.java:579)
	at jdk.crypto.cryptoki/sun.security.pkcs11.Config.parseAttributes(Config.java:865)
	at jdk.crypto.cryptoki/sun.security.pkcs11.Config.parse(Config.java:431)
	at jdk.crypto.cryptoki/sun.security.pkcs11.Config.<init>(Config.java:215)
	at jdk.crypto.cryptoki/sun.security.pkcs11.SunPKCS11$1.run(SunPKCS11.java:126)
	at jdk.crypto.cryptoki/sun.security.pkcs11.SunPKCS11$1.run(SunPKCS11.java:123)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:571)
	at jdk.crypto.cryptoki/sun.security.pkcs11.SunPKCS11.configure(SunPKCS11.java:123)
	... 10 more

The output of the first command makes me believe that authentication to the PKCS11 provider is actually working (if I don't pass in the --storepass flag I get an auth error), but there is something broken with the sunpkcs.cfg

@hellais
Copy link

hellais commented Jul 26, 2024

I think I am making some progress.

I have gotten to the point where I have a different error when I run:

jsign --certfile /home/ec2-user/Cert_chain.p7b --storetype PKCS11 -s sunpkcs.cfg --storepass "XXXX:XXXX" binary.exe

Where Cert_chain.p7b is the full cert chain and sunpkcs.cfg contains:

name = OONICloudHSM
library = /opt/cloudhsm/lib/libcloudhsm_pkcs11.so
attributes(*,CKO_PRIVATE_KEY, *) = {
  CKA_SIGN = true
  CKA_LABEL = 0x000000000000001d
}

(the issue I think was that I was putting " quotes around the LABEL)

I now get this error:

jsign: No certificate found in the keystore SunPKCS11-OONICloudHSM
Try `jsign --help' for more information.

Any ideas on how I can get it to pick up the cert chain?

@hellais
Copy link

hellais commented Jul 26, 2024

Did you check if the CloudHSM instance is available as a keystore for AWS KMS?

I have tested this and unfortunately it's only possible to use KMS to use CloudHSM as a custom backend to create new keys. Since we already have our keys from our EV cert issuer (after having done the ceremony to issue the keys on an HSM), it's not a viable option, since we need to use the existing keys inside of CloudHSM.

CloudHSM should be compliant with PKCS11 so I believe there should be some way to massage the SunPKCS11 config to get it to work, I'm probably just missing a few pieces, see: #179 (comment)

@ebourg
Copy link
Owner

ebourg commented Jul 26, 2024

@hellais You could try setting the --alias parameter, for example:

jsign --storetype PKCS11 --keystore sunpkcs.cfg --storepass XXXX --certfile chain.p7b --alias XXXX_2024-04-26_6 binary.exe

or:

jsign --storetype PKCS11 --keystore sunpkcs.cfg --storepass XXXX --certfile chain.p7b --alias 0x000000000000001d binary.exe

@hellais
Copy link

hellais commented Jul 26, 2024

Thanks for the reply, I tried setting the alias, both as the key label and as the key id, but still it doesn't seem to be working.

@ebourg
Copy link
Owner

ebourg commented Jul 26, 2024

You may get some hints about the underlying issue by enabling the SunPKCS11 debugging mode:

JSIGN_OPTS=-Djava.security.debug=sunpkcs11 jsign --storetype PKCS1 ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants