How do I use OpenSSL and the CloudHSM Command Line Tool to securely transfer my keys to CloudHSM?

7 minute read
4

I want to use the CloudHSM Command Line Tool (CloudHSM CLI) to run the "key unwrap" subcommand to import local keys to AWS CloudHSM.

Short description

First, encrypt your payload key with an ephemeral Advanced Encryption Standard (AES) key. Then, encrypt the ephemeral AES key with your public key from a key pair. Finally, join the encrypted payload key and encrypted ephemeral key into a single file. The file is sent to your CloudHSM in an encrypted format, and the private key decrypts the file from the key pair. The AES_KEY_WRAP mechanism decrypts the ephemeral AES key and uses the key to decrypt your payload key.

Note: Complete the following steps on an Amazon Elastic Compute Cloud (Amazon EC2) instance that runs Linux. It's a best practice to use an Amazon Linux 2023 Amazon Machine Image (AMI) that includes the required OpenSSL version and utilities.

Create the following keys:

  • Payload AES, RSA, or EC key that you import and use with your CloudHSM.
  • Temporary AES key that AES_KEY_WRAPrequires to encrypt the payload. It's a best practice to use AES because there are no size limits on what you can encrypt.
  • RSA key pair to securely wrap and unwrap the keys into your CloudHSM.

To use envelop wrap, you must have OpenSSL version 3.x.

To determine the OpenSSL version that you have, run the following command:

openssl version

Example output:

OpenSSL 3.0.8 7 Feb 2023 (Library: OpenSSL 3.0.8 7 Feb 2023)

Resolution

Note: In the following commands, replace the following values with your values:

  • YOUR_CRYPTO_USER_NAME with your crypto username
  • YOUR_CRYPTO_USER_PASSWORD with your password
  • YOUR_WRAPPING_KEY_LABEL with the key label that you assigned to wrap your RSA public key
  • YOUR_UNWRAPPING_KEY_LABEL with the key label that you assigned to unwrap your RSA private key
  • YOUR_IMPORTED_KEY_LABEL with the key label that you assigned to the imported payload key

Your wrapping and unwrapping key labels must be unique because key labels are a filter condition for the key generate-file and key unwrap commands. Or, you can use a different filter condition to uniquely identify keys. For more information about key filters, see Filter keys using CloudHSM CLI.

Set crypto-user credentials for CloudHSM CLI

Run the following commands:

export CLOUDHSM_ROLE="crypto-user"
export CLOUDHSM_PIN="YOUR_CRYPTO_USER_NAME:YOUR_CRYPTO_USER_PASSWORD"

Import the AES payload

To create, encrypt, and import the local keys, complete the following steps:

  1. To create the payload AES, ephemeral AES, and RSA keys, run the following commands:

    openssl rand -out payload_aes 32
    openssl rand -out ephemeral_aes 32
    /opt/cloudhsm/bin/cloudhsm-cli key generate-asymmetric-pair rsa --public-label YOUR_WRAPPING_KEY_LABEL --private-label YOUR_UNWRAPPING_KEY_LABEL --modulus-size-bits 4096 --public-exponent 65537 --private-attributes unwrap=true
    /opt/cloudhsm/bin/cloudhsm-cli key generate-file --encoding pem --path public.pem --filter attr.label=YOUR_WRAPPING_KEY_LABEL

    Note: To track your files, create the keys in their own directory.

  2. To put the raw hex values of the ephemeral AES key into a variable, run the following command:

    EPHEMERAL_AES_HEX=$(hexdump -v -e '/1 "%02X"' < ephemeral_aes)

    Note: Make sure that you installed the hexdump utility. If you don't install hexdump, then the preceding command returns an error. Refer to your operating system (OS) documentation for instructions on how to install the hexdump utility.

  3. To use the ephemeral AES key to wrap the payload, run the OpenSSL enc command:

    openssl enc -id-aes256-wrap-pad -K $EPHEMERAL_AES_HEX -iv A65959A6 -in payload_aes -out payload_wrapped

    Note: The -id-aes256-wrap-pad cipher is the RFC 3394-compliant wrap mechanism that coexists with CKM_RSA_AES_KEY_WRAP. The RFC 3394 extension, RFC 5649, sets the -iv values. For more information, see AES key wrap with padding algorithm and AES key wrap algorithm on the IETF website.

  4. Use the public key from the RSA key pair to encrypt the AES key:

    openssl pkeyutl -encrypt -in ephemeral_aes -out ephemeral_wrapped -pubin -inkey public.pem -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha1 -pkeyopt rsa_mgf1_md:sha1
  5. From your local machine, join the encrypted payload key and ephemeral AES key into a single file that's named rsa_aes_wrapped:

    cat ephemeral_wrapped payload_wrapped > rsa_aes_wrapped
  6. To use the RSA private key with key unwrap rsa-aes to unwrap the joined payload key into the CloudHSM, run the following command:

    /opt/cloudhsm/bin/cloudhsm-cli key unwrap rsa-aes --data-path rsa_aes_wrapped --key-type-class aes --label YOUR_IMPORTED_KEY_LABEL --hash-function sha1 --mgf mgf1-sha1 --filter attr.label=YOUR_UNWRAPPING_KEY_LABEL --attributes decrypt=true encrypt=true

    Note: You must use --key-type-class aes to unwrap AES keys. Based on key usage, use --attributes to assign key attributes. For more information about options and key attributes, see Key attributes for CloudHSM CLI and the examples of how to use the key unwrap rsa-aes command.

    You receive an import of the payload AES key that's similar to the following output:

    {
      "error_code": 0,
      "data": {
        "key": {
          "key-reference": "0x000000000068031a",
          "key-info": {
            "key-owners": [
              {
                "username": "YOUR_CRYPTO_USER_NAME",
                "key-coverage": "full"
              }
            ],
            "shared-users": [],
            "cluster-coverage": "full"
          },
          "attributes": {
            "key-type": "aes",
            "label": "YOUR_IMPORTED_KEY_LABEL",
            "id": "0x",
            "check-value": "0xb31c2a",
            "class": "secret-key",
            "encrypt": true,
            "decrypt": true,
            "token": true,
            "always-sensitive": false,
            "derive": false,
            "destroyable": true,
            "extractable": true,
            "local": false,
            "modifiable": true,
            "never-extractable": false,
            "private": true,
            "sensitive": true,
            "sign": true,
            "trusted": false,
            "unwrap": false,
            "verify": true,
            "wrap": false,
            "wrap-with-trusted": false,
            "key-length-bytes": 32
          }
        }
      }
    }

Import the RSA payload

Complete the following steps:

  1. To unwrap an RSA private key into the CloudHSM, run the following commands to change the payload key to an RSA private key:

    openssl genrsa -out payload_rsa.pem 2048
    openssl rand -out ephemeral_aes 32
  2. Use a plaintext editor to check the format of the RSA keys:

    PKCS1 format: -----BEGIN RSA PRIVATE KEY----- - PKCS8 format: -----BEGIN PRIVATE KEY-----

    Note: The RSA keys are in PKCS #1 format. However, the CloudHSM CLI assumes that the private key is in PKCS #8 DER format.

  3. To convert the payload_rsa.pem key into PKCS #8 format and DER encoded, run the following command:

    openssl pkcs8 -topk8 -inform PEM -outform DER -in payload_rsa.pem -out payload_rsa_pkcs8.der -nocrypt
  4. Complete steps 2-5 from the Import the AES payload section. Replace payload_aes with payload_rsa_pkcs8.der.

  5. To unwrap the payload RSA private key into the CloudHSM, run the following command:

    /opt/cloudhsm/bin/cloudhsm-cli key unwrap rsa-aes --data-path rsa_aes_wrapped --key-type-class rsa-private --label YOUR_IMPORTED_KEY_LABEL --hash-function sha1 --mgf mgf1-sha1 --filter attr.label=YOUR_UNWRAPPING_KEY_LABEL --attributes decrypt=true sign=true

    Note: You must use --key-type-class rsa-private to unwrap RSA keys. Based on key usage, use --attributes to assign key attributes.

Import the EC payload

To import the payload, complete the following steps:

  1. To unwrap an EC private key into the CloudHSM, run the following commands to change the payload key to an EC private key:

    openssl ecparam -name secp256k1 -genkey -noout -out payload_ec.pemopenssl rand -out ephemeral_aes 32
  2. Use a plaintext editor to check the format of the EC keys:

    PKCS1 format: -----BEGIN EC PRIVATE KEY----- - PKCS8 format: -----BEGIN PRIVATE KEY-----

    Note: The EC keys are in PKCS #1 format. However, the CloudHSM CLI assumes that the private key is in PKCS #8 DER format.

  3. To convert the payload_ec.pem key into PKCS #8 format and DER encoded, run the following command:

    openssl pkcs8 -topk8 -inform PEM -outform DER -in payload_ec.pem -out payload_ec_pkcs8.der -nocrypt
  4. Complete steps 2-5 from the Import the AES payload section. Replace payload_aes with payload_ec_pkcs8.der.

  5. To unwrap the payload EC private key into the CloudHSM, run the following command:

    /opt/cloudhsm/bin/cloudhsm-cli key unwrap rsa-aes --data-path rsa_aes_wrapped --key-type-class ec-private --label YOUR_IMPORTED_KEY_LABEL --hash-function sha1 --mgf mgf1-sha1 --filter attr.label=YOUR_UNWRAPPING_KEY_LABEL --attributes decrypt=true sign=true

    Note: You must use --key-type-class ec-private to unwrap EC keys. Based on key usage, use --attributes to assign key attributes.

Related information

Supported mechanisms for the PKCS #11 library for AWS CloudHSM Client SDK 5

AWS OFFICIAL
AWS OFFICIALUpdated 13 days ago
2 Comments

We are having trouble getting all these steps to work, we run into a problem on the last command that the input data to the cryptographic operation was invalid. Any pointers? We are using SDK5 cli.

replied 2 months ago

Resolved our issue. Do not try this on Windows, run it from linux OS. Also, you may need to directly add an appropriate ID value to the key once it is imported in order for a Windows OS to recognize it.

replied 2 months ago