Import RSA Private Key to CloudHSM

May 20, 2026 · 4 min read · Michael Uchytil
Intermediate 45 minutes
Prerequisites:
  • Activated CloudHSM Cluster
  • CloudHSM Cli Installed
CloudHSM AWS RSA

Overview

In this tutorial, I’ll be guiding you through the process of importing an existing RSA private key into your CloudHSM cluster using the AES-RSA method. This process is usually required in situations when one has must store the private key backing either a TLS or signing certificate originating from a 3rd party provider in a secure manner.

Prerequisites

Before starting, ensure you have:

  • A working CloudHSM cluster
  • Connectivity to the CloudHSM cluster
  • CloudHSM CLI is installed
  • A copy of the private RSA key

Steps

Optional: Generate a Private RSA Key

If you don’t have a private RSA key, you can run the following command to generate one for the purposes of this tutorial

1
openssl genrsa -out cert.pem 4096

Step 1: Convert the RSA private key to DER format

As CloudHSM only accepts keys in DER or binary format, we must convert the private key from pem to der. If your private key is already in der format you can skip this step.

1
2
3
4
openssl pkcs8 -topk8 -inform PEM -outform DER \
-in cert.pem \
-out cert.der \
-nocrypt

Step 2: Generate an Ephemeral AES Key

We need to generate an ephemeral RSA and also save the key material in hex format in order to encrypt the RSA private key.

1
2
openssl rand -out ephemeral_aes 32
EPHEMERAL_AES_HEX=$(hexdump -v -e '/1 "%02X"' < ephemeral_aes)

Step 3: Wrap the RSA key with the Ephemeral AES key

Wrap the private RSA key with the ephemeral AES key using the hexidecimal value stored in the variable.

1
2
3
4
5
6
openssl enc \
-id-aes256-wrap-pad \
-K $EPHEMERAL_AES_HEX \
-iv A65959A6 \
-in cert.der \
-out payload_wrapped

Optional: Generate a RSA Wrapping Key inside the CloudHSM and Generate Public Key PEM

Now that the certificates private key has been wrapped with the ephemeral AES key, we must now wrap the AES key with the CloudHSM wrapping key. If you do not already have a RSA wrapping key within the CloudHSM, you can generate one by running the following commands.

1
2
3
4
5
6
7
8
9
export CLOUDHSM_PIN='<crypto_user_username>:<crypto_user_password>'
export CLOUDHSM_ROLE='crypto-user'

/opt/cloudhsm/bin/cloudhsm-cli key generate-asymmetric-pair rsa \
--public-exponent 65537 \
--modulus-size-bits 4096 \
--public-label wrapping-key-pub \
--private-label wrapping-key-priv \
--private-attributes decrypt=true unwrap=true

While the wrapping private key will remain safely within the CloudHSM, we need to make the wrapping public key accessable in order to wrap the ephemeral aes key. This can be done by invoking the following command:

1
2
3
4
/opt/cloudhsm/bin/cloudhsm-cli key generate-file \
--filter attr.label=wrapping-key-pub \
--path wrapping-key-pub.pem \
--encoding pem

Step 4: Wrap the Ephemeral AES Key with the public CloudHSM wrapping key

Using the public key of the CloudHSM wrapping key pair, wrap the AES wrapping key.

1
2
3
4
5
6
7
8
9
openssl pkeyutl \
-encrypt \
-in ephemeral_aes \
-out ephemeral_wrapped \
-pubin \
-inkey wrapping-key-pub.pem \
-pkeyopt rsa_padding_mode:oaep \
-pkeyopt rsa_oaep_md:sha1 \
-pkeyopt rsa_mgf1_md:sha1

Step 5: Concatinate Payloads

Now that both keys are wrapped, we must concatinate both into the same file in order to pass it as an argument to the CloudHSM. The order is important, we must place the RSA wrapped ephemeral AES key first followed by the AES wrapped RSA private key.

  1. Wrapped AES Ephemeral Key
  2. Wrapped RSA Private Key
1
cat ephemeral_wrapped payload_wrapped > rsa_aes_wrapped

Step 5: Unwrap the RSA Private Key within CloudHSM

With our wraped keys in a single file, unwrap them inside the CloudHSM using the following command:

1
2
3
4
5
6
7
8
/opt/cloudhsm/bin/cloudhsm-cli key unwrap rsa-aes \
--data-path rsa_aes_wrapped \
--key-type-class rsa-private \
--label cert-priv \
--hash-function sha1 \
--mgf mgf1-sha1 \
--filter attr.label=wrapping-key-priv \
--attributes decrypt=true sign=true

Breaking down the command: –data-path: specifies the data file containing the wrapped key material –key-type-class: specifies the type of key being ultimately unwrapped –label: specifies the label the unwrapped RSA key should have. –hash-function: specifies the hashing algorithm which was used to wrap the ephemeral aes key –mgf: specifies the Mask Generation Function (mgf) used to wrap the ephemeral aes key –filter: instructs CloudHSM which key label is used by private key corresponding to the public key used to wrap the aes key. –attributes: enables the unwrapped / imported rsa private key two attributes: decrypt messages and sign files

Conclusion

Congraduations! You should now have successfully imported your external RSA private key.