Google Cloud HSM as a provider for encryption

1.2k Views Asked by At

AWS seems to allow us to have the AWS Cloud HSM as a provider, See here and here

Security.addProvider(new com.cavium.provider.CaviumProvider())

In the samples from GKE however we seem to only have bouncy castle as a provider. See here

Security.addProvider(new BouncyCastleProvider());

Maybe i am missing something fundamental.

Would like to do a initsign as below JCA API

https://docs.oracle.com/javase/10/docs/api/java/security/Signature.html#initSign(java.security.PrivateKey)

2

There are 2 best solutions below

1
On BEST ANSWER

I've implemented a JCA provider for Google Cloud HSM (as well as Azure Key Vault and AWS KMS) as part of the Jsign project. It performs direct API calls and doesn't rely on the gcloud CLI or the Google Cloud SDK. Usage looks like this:

String keyring = "projects/first-rain-123/locations/global/keyRings/mykeyring";
SigningService service = new GoogleCloudSigningService(keyring, token, null);
Provider provider = new SigningServiceJcaProvider(service);

KeyStore keystore = KeyStore.getInstance("GOOGLECLOUD", provider);
keystore.load(null, "".toCharArray());

PrivateKey key = (PrivateKey) keystore.getKey(alias, null);

Signature sig = Signature.getInstance("SHA256withRSA", provider);
sig.initSign(key);
sig.update(data);
byte[] signature = sig.sign();
0
On

I am not sure what the exact question is but it looks like you want to write code that signs data using a private key from an HSM and have that work on AWS and Google Cloud. The steps to do that are:

  1. Load the provider
  2. Open the keystore
  3. Retrieve the private key
  4. Initialize a signing object with the private key (and update it with the data to sign)
  5. Sign

Step 1 can be done programmatically (via Security.addProvider, as you have written in your question) or statically in the java.security file. If you want your code to be agnostic to the cloud platform it is running on, you may want to consider doing this statically (although it is also possible to do it programmatically and keep things platform agnostic).

The rest of the steps just require pretty standard JCE code. Below is an example:

KeyStore keyStore = KeyStore.getInstance("type", "provider name");
PrivateKey privKey = (PrivateKey) keyStore.getKey("alias", null);
Signature sig = Signature.getInstance("transformation", "provider name");
sig.initSign(privKey);
sig.update(dataToSign);
byte[] signature = sig.sign();

You may want to read the provider name and keystore type from a (secured) configuration file, so those aren't hard-coded. After you get that working you'll want to look at how often you go to the keystore to retrieve key objects and possibly consider caching them because keystore retrievals can be expensive, depending on the HSM and provider library being used. That is going a bit beyond the scope of this question, or at least what I am interpreting the question to be, so I will stop there. Hope that helps.