Wrapping a key using OpenSSL on Linux

Before you can import a key to Cloud HSM, you need to wrap your key using the PKCS#11 CKM_RSA_AES_KEY_WRAP mechanism. This topic provides information about wrapping the key by using OpenSSL.

Before you begin

If you do not yet have a wrapping key:

  1. Complete the Before you begin steps for importing a key.
  2. Create an import job.
  3. Retrieve the wrapping key from the import job and download it locally.

Set up OpenSSL v1.1.0

To wrap key material following the PKCS#11 CKM_RSA_AES_KEY_WRAP standard using OpenSSL, version v1.1.0* of OpenSSL is required. This is not the default version on most machines. This topic describes the steps for installing, patching, and building a local copy of OpenSSL v1.1.0 while not interfering with the machine's default installation of OpenSSL.

  1. Determine the latest v1.1.0 release at https://www.openssl.org/source/. If the latest version is not 1.1.0j, make a note of the version for use in the next step.

  2. At a command prompt, create local folders, download the OpenSSL release, and unzip it. If you are using a 1.1.0 version other than 1.1.0j, modify the curl and tar commands to use your version.

    mkdir $HOME/build
    mkdir -p $HOME/local/ssl
    cd $HOME/build
    curl -O https://www.openssl.org/source/openssl-1.1.0j.tar.gz
    tar -zxf openssl-1.1.0j.tar.gz
  3. Apply a custom patch to the local OpenSSL copy. At the time this documentation was written, version 1.1.0j is the newest OpenSSL version and it does not enable the EVP_CIPHER_CTX_FLAG_WRAP_ALLOW flag. Apply the following patch to enable it. Again, modify "1.1.0j" in the patch below if you are using a different version.

    cat <<-EOF | patch -d $HOME/build/ -p0
    diff -ur orig/openssl-1.1.0j/apps/enc.c openssl-1.1.0j/apps/enc.c
    --- orig/openssl-1.1.0j/apps/enc.c      2017-11-02 10:29:02.000000000 -0400
    +++ openssl-1.1.0j/apps/enc.c   2017-11-18 14:00:31.106304557 -0500
    @@ -478,6 +478,7 @@
             BIO_get_cipher_ctx(benc, &ctx);
    +        EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);
             if (!EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, enc)) {
                 BIO_printf(bio_err, "Error setting cipher %s\n",

  4. Build the local version of the openssl binary.

    cd $HOME/build/openssl-1.1.0j/
    ./config --prefix=$HOME/local --openssldir=$HOME/local/ssl
    make -j$(grep -c ^processor /proc/cpuinfo)
    make test
    make install

    The --prefix and --openssldir options are used to place the custom OpenSSL installation into your home directory. Replacing or modifying your system's default OpenSSL version is not recommended, and just copying the openssl binary out of the build directory is not sufficient.

  5. Check that the new openssl binary installed successfully:

    cd $HOME
    test -x local/bin/openssl || echo FAIL

    If the local OpenSSL files are in the correct location, you should not see FAIL in the output of the test command.

  6. This openssl is dynamically linked against libraries that reside in $HOME/local/ssl/lib/ and {ld} won't be able to run it directly. You can assist {ld} by using the environment variable LD_LIBRARY_PATH. Since you will run openssl multiple times, you should make a script named openssl.sh and make it executable.

    cd $HOME/local/bin/
    cat > ./openssl.sh <<-EOF
    env LD_LIBRARY_PATH=$HOME/local/lib/ $HOME/local/bin/openssl "\$@"
    chmod 755 ./openssl.sh

  7. Start the new version.


    You see an OpenSSL> prompt, indicating that you are within the OpenSSL CLI.

  8. Within the OpenSSL CLI, run the version command to confirm you are using the patched version, v1.1.0.

    OpenSSL> version
    OpenSSL 1.1.0j  20 Nov 2018
    OpenSSL> exit

If there are any other parts of the normal openssl installation you are looking for, they are installed under $HOME/local/ssl/. For example, you can view man pages using this command:

env MANPATH=$HOME/local/share/man/ man openssl

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 did not use the recommended path when you set up OpenSSL locally, modify the value assigned to OpenSSL_V110 as needed.

  2. The key material to be imported needs to be in a specific format prior to being wrapped.

    The symmetric key should exist in a file with extension .bin. Define TARGET_KEY to the absolute path of the binary formatted key (but only the directory portion, not the .bin file itself).


  3. Define WRAP_PUB_KEY to the absolute path of the wrapping public key that you received from Cloud HSM (but only the directory portion, not the .bin file itself).

  4. Define RSA_AES_WRAPPED_KEY to the absolute path of where the wrapped key will be written.

  5. Several intermediate files are used during the key wrapping process. To make it easy to clean up the intermediate files, define environment variables for the file paths. Define BASE_DIR as the location of the directory for the intermediate files. Use a different path for BASE_DIR if you prefer.

    mkdir "$BASE_DIR"

    Define environment variables for the intermediate files.


Wrap the key

  1. Generate a temporary random AES key that is 32 bytes long.

    "${OPENSSL_V110}" rand -out "${TEMP_AES_KEY}" 32
  2. Wrap the temporary AES key with the wrapping public key using CKM_RSA_PKCS_OAEP.

    "${OPENSSL_V110}" rsautl -encrypt \
    -pubin -inkey "${WRAP_PUB_KEY}" \
    -in "${TEMP_AES_KEY}" \
    -out "${TEMP_AES_KEY_WRAPPED}" \
  3. Wrap the target key with the temporary AES key using CKM_AES_KEY_WRAP_PAD.

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

    Note the use of -iv A65959A6 sets A65959A6 as the Alternate Initial Value as required by the RFC 5649 specification.

  4. Overwrite the temporary AES key with zeroes and then delete it.

    dd if=/dev/zero bs=32 count=1 of="${TEMP_AES_KEY}"; rm "${TEMP_AES_KEY}"
  5. Concatenate the two wrapped keys and write the output to a file. The order shown for the two wrapped keys is required for the unwrap process to know how to split the binary blob.

  6. Delete the intermediate files that are no longer needed.


    Your wrapped key is located in ${RSA_AES_WRAPPED_KEY}.

You can now use the wrapped key to make a request to import your key.