Wrapping a key using OpenSSL on Linux

This topic shows how to manually wrap a key before importing the key into Cloud KMS. You only need to follow the instructions in this topic if you do not want to use the gcloud command-line tool to automatically wrap the key before importing it. For an overview of the differences, refer to How key import works.

You can complete the steps in this topic in 5 to 10 minutes, not including the Before you begin steps.

Before you begin

Before you can wrap a key, you must complete the following prerequisites.

  1. Create a target key ring and key, and create an import job.
  2. Verify that your key is available locally and formatted correctly for import into Cloud KMS.
  3. Patch and recompile OpenSSL

Retrieve the wrapping key

This section shows how to retrieve the wrapping key from the import job you created in Before you begin. Using the Google Cloud Console is recommended.

Console

  1. Go to the Cryptographic Keys page in the Cloud Console.

    Go to the Cryptographic Keys page

  2. Click the name of the key ring that contains your import job.

  3. Click the Import Jobs tab at the top of the page.

  4. Click More , then Download wrapping key in the pop-up menu.

gcloud

To verify that the import job is active, run the gcloud kms import-jobs describe command:

gcloud kms import-jobs describe import-job \
  --location location \
  --keyring key-ring-name \
  --format="value(state)"
state: ACTIVE

Run the following command to save the public key from the import job to ${HOME}/wrapping-key.pem

gcloud kms import-jobs describe \
  --location=location \
  --keyring=keyring \
  --format="value(publicKey.pem)" \
  import-job-name > ${HOME}/wrapping-key.pem

API

  1. Call the [ImportJob.get][11] method.

  2. Retrieve the public key via the [publicKey][13] field of the ImportJob.get response. This value is of type [WrappingPublicKey][14]. The [pem][21] field of the [WrappingPublicKey][22] type is the public key encoded in Privacy Enhanced Mail (PEM) format.

For more information about the PEM-encoded format, see RFC 7468, especially the General Considerations and Textual Encoding of Subject Public Key Info sections.

Set up environment variables

The OpenSSL commands require several file paths as input values. Define environment variables for the file paths to make it easier to run the commands.

  1. Set the OpenSSL_V110 variable to the path of your openssl.sh script. If you followed the instructions for patching and recompiling OpenSSL exactly, you can use this command without modifying the value of the variable.

    OPENSSL_V110="${HOME}/local/bin/openssl.sh"
    

  2. Set the PUB_WRAPPING_KEY variable to the full path to the wrapping key you downloaded from the import job. The wrapping key ends in .pem.

    The following commands set the PUB_WRAPPING_KEY variable to ${HOME}/wrapping-key.pem.

    PUB_WRAPPING_KEY="${HOME}/wrapping-key.pem"
    

  3. Set the TARGET_KEY variable to the full path to the unwrapped key.

    • For symmetric keys, set TARGET_KEY to the path to the .bin file.
    • For asymmetric keys, set TARGET_KEY to the path to the .der file.
    TARGET_KEY=/path/to/key
    

  4. Set the BASE_DIR variable to a directory where temporary files can be written, and create the directory if necessary. This directory should only be accessible by your current user. Do not use a trailing / character at the end of the directory name.

    BASE_DIR="${HOME}/wrap_tmp"
    mkdir -m 700 -p ${BASE_DIR}
    

  5. Define environment variables for the three intermediate files.

    TEMP_AES_KEY="${BASE_DIR}/temp_aes_key.bin"
    TEMP_AES_KEY_WRAPPED="${BASE_DIR}/temp_aes_key_wrapped.bin"
    TARGET_KEY_WRAPPED="${BASE_DIR}/target_key_wrapped.bin"
    

  6. Set the RSA_AES_WRAPPED_KEY variable to the full path to write the wrapped target key that you will eventually import, and make sure you have access to write to the directory.

    RSA_AES_WRAPPED_KEY=/path/to/wrapped-target-key.bin
    mkdir -m u+wx -p $(dirname ${RSA_AES_WRAPPED_KEY})
    

  7. Verify that all the environment variables are set correctly using the following commands:

    echo "OPENSSL_V110: " ${OPENSSL_V110}; \
    echo "PUB_WRAPPING_KEY: " ${PUB_WRAPPING_KEY}; \
    echo "TARGET_KEY: " ${TARGET_KEY}; \
    echo "BASE_DIR: " ${BASE_DIR}; \
    echo "TEMP_AES_KEY: " ${TEMP_AES_KEY}; \
    echo "TEMP_AES_KEY_WRAPPED: " ${TEMP_AES_KEY_WRAPPED}; \
    echo "TARGET_KEY_WRAPPED: " ${TARGET_KEY_WRAPPED}; \
    echo "RSA_AES_WRAPPED_KEY: " ${RSA_AES_WRAPPED_KEY}
    

When the variables are set correctly, you are ready to wrap the key.

Wrap the key

  1. Run the following command to generate a temporary random AES key that is 32 bytes long and to save it to the location pointed to by ${TEMP_AES_KEY}.

    "${OPENSSL_V110}" rand -out "${TEMP_AES_KEY}" 32
    

  2. Wrap the temporary AES key with the wrapping public key using the CKM_RSA_PKCS_OAEP algorithm.

    "${OPENSSL_V110}" rsautl \
       -encrypt \
       -pubin \
       -inkey "${PUB_WRAPPING_KEY}" \
       -in "${TEMP_AES_KEY}" \
       -out "${TEMP_AES_KEY_WRAPPED}" \
       -oaep
    

  3. Wrap the target key with the temporary AES key using the CKM_AES_KEY_WRAP_PAD algorithm. Replace target-key-file with the name of the .bin or pub file for the key.

    "${OPENSSL_V110}" enc \
      -id-aes256-wrap-pad \
      -iv A65959A6 \
      -K $( hexdump -v -e '/1 "%02x"' < "${TEMP_AES_KEY}" ) \
      -in "${TARGET_KEY}" \
      -out "${TARGET_KEY_WRAPPED}"
    

    The -iv A65959A6 flag sets A65959A6 as the Alternate Initial Value. This is required by the RFC 5649 specification.

    You have now wrapped two keys:

    • ${TEMP_AES_KEY_WRAPPED} is the temporary AES key you created on the local system, wrapped with the public key from the import job.
    • ${TARGET_KEY_WRAPPED} is the target key that you will import, wrapped with the temporary AES key you generated.
  4. Concatenate the two wrapped keys and write the output to a single file. Do not modify the order of the two keys in the command below; the temporary key must come before the target key.

    cat "${TEMP_AES_KEY_WRAPPED}" "${TARGET_KEY_WRAPPED}" > "${RSA_AES_WRAPPED_KEY}"
    
  5. Delete the intermediate files that are no longer needed.

    rm ${BASE_DIR}/*
    

Your wrapped key exists at location ${RSA_AES_WRAPPED_KEY} variable, and you can make a request to import your key.