はじめに
OCI(Oracle Cloud Infrastructure)の鍵管理を行うサービスであるVaultで作成した秘密鍵をエクスポートする手順です。ソフトウェア保管の鍵のみになります。HSMに保管した鍵はエクスポートできません。
1.OpenSSLの準備
鍵をエクスポートするためには OpenSSL -id-aes256-wrap-pad 暗号が必要ですが、ではデフォルトで有効になっていません。 また、RSA_AES_KEY_WRAPに必要なエンベロープ ラッピングを許可するように OpenSSL にパッチを適用する必要があります。
- たとえばYumリポジトリから最新版にアップデートしただけの以下ではスクリプトがエラーになり、エクスポートできなかった
[opc@kms_export]$ openssl
OpenSSL> version
OpenSSL 1.1.1k FIPS 25 Mar 2021
OpenSSL1.1.1の最新版をダウンロード
From:https://www.openssl.org/source/old/1.1.1/index.html
#作業用ディレクトリ作成
mkdir kms_export
cd kms_export
mkdir build
cd build
#ダウンロード
wget https://www.openssl.org/source/old/1.1.1/openssl-1.1.1w.tar.gz
#解凍
tar -zxf https://www.openssl.org/source/old/1.1.1/openssl-1.1.1w.tar.gz
#コンパイル用にインストール
sudo yum install patch make gcc -y
enc.c バイナリへのパッチ適用
ダウンロードしたOpenSSLに対してバイナリレベルでパッチ適用します。
以下の4行のみを実環境に合わせて変更します。
特にOpenSSLのバージョン記号など。
- cat <<-EOF | patch -d /home/opc/work/kms_export/build -p0
- diff -ur orig/openssl-1.1.1w/apps/enc.c openssl-1.1.1w/apps/enc.c
- --- orig/openssl-1.1.1w/apps/enc.c
- +++ openssl-1.1.1w/apps/enc.c
cat <<-EOF | patch -d /home/opc/work/kms_export/build -p0
diff -ur orig/openssl-1.1.1w/apps/enc.c openssl-1.1.1w/apps/enc.c
--- orig/openssl-1.1.1w/apps/enc.c
+++ openssl-1.1.1w/apps/enc.c
@@ -533,6 +533,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",
EOF
コンパイルしてインストール
# インストール先を作成
mkdir $HOME/build
mkdir -p $HOME/local/ssl
# ダウンロードしたOpenSSLディレクトリ名でConfigコマンドを実行しています。環境に合わせて変更します。
cd /home/opc/work/kms_export/build/openssl-1.1.1w/
./config --prefix=$HOME/local --openssldir=$HOME/local/ssl
make -j$(grep -c ^processor /proc/cpuinfo)
# 一回プロンプトが止まるので以下を実行してインストール
make install
#インストール後の確認
[opc@openssl-1.1.1w]$ ls $HOME/local/ssl
certs ct_log_list.cnf ct_log_list.cnf.dist misc openssl.cnf openssl.cnf.dist private
openssl.shを作成
関連するライブラリが OpenSSL で使用できるように環境変数LD_LIBRARY_PATHに、$HOME/local/ssl/lib/を設定するOpenssl用のシェルを作成
echo -e '#!/bin/bash \nenv LD_LIBRARY_PATH=$HOME/local/lib/ $HOME/local/bin/openssl "$@"' > ./openssl.sh
動作確認
ここで作るopenssl.sh を 手順「2.鍵のエクスポート」 で利用するシェルスクリプトで指定することになります。
[opc@openssl-1.1.1w]$ . $HOME/local/bin/openssl.sh
OpenSSL> version
OpenSSL 1.1.1w 11 Sep 2023
2.鍵をエクスポート
- 説明
- 次のサンプルスクリプトは、最適非対称暗号化パディング (OAEP) と呼ばれるメカニズムを使用して、ソフトウェアで保護されたマスター暗号化キーを変換します。
- スクリプトは、ソフトウェアで保護されたマスター暗号化キーを、提供された公開 RSA ラッピング キーでラップし、その後、秘密 RSA ラッピング キーでラップを解除してエクスポートします。
- ラップされたマスター暗号化キーを復号化できるのは、秘密 RSA ラッピング キーの所有者のみです。
OCIドキュメントの内容からエクスポートされた鍵(バイナリ)を、一般的なPEM型式のテキストで出力するようにカスタムしています。
そのために追加した行
- 34行目付近:PEM_SOFTWARE_KEY_PATH="./coverted_software_rsakey_e2e.pem"
- 最後あたりの「base64_encoded=$(base64 ${SOFTWARE_KEY_PATH} | tr -d '\n')」以後
以下のファイルを作成します。
環境に合わせて変数を変更してください。
今回は3つの変数 KEY_OCID, OPENSSL, VAULT_CRYPTO_ENDPOINT のみ変更しています。
#!/usr/bin/env bash
#
# This script is for demonstration purposes only. It provides
# a functioning set of calls to show how to export software-protected AES key material
# from the Vault service by using the RSA_OAEP_SHA256 algorithm.
#
set -x
private_key_path=private.pem # private wrapping key which is generated within the script itself, do not change
public_key_path=public.pem ## public wrapping key which is generated within the script itself, do not change
rsa_key_size=2048
OPENSSL="$HOME/local/bin/openssl.sh" # path to openssl
#
# Generate key pair
#
${OPENSSL} genrsa -out ${private_key_path} ${rsa_key_size}
${OPENSSL} rsa -in ${private_key_path} -outform PEM -pubout -out ${public_key_path}
KEY_OCID="ocid1.key.oc1.phx.bbqbotd7aafqw.abs{amplesamplesample}" # The Oracle Cloud Identifier (OCID) of the software-protected master encryption key to export.
ENCRYPTION_ALGORITHM="RSA_OAEP_AES_SHA256"
RSA_KEY_SIZE_IN_BYTES="256" # Specify 256 (for 2048 bits) or 512 (for 4096 bits).
VAULT_CRYPTO_ENDPOINT="https://{sample}-crypto.kms.us-phoenix-1.oraclecloud.com" # The cryptographic endpoint of the vault that contains the software-protected master encryption key.
PUBLIC_KEY_STRING="`cat ${public_key_path}`" # The content of the public key.
PRIVATE_KEY_PATH=${private_key_path} # The location of the private key.
SOFTWARE_KEY_PATH="./outputted_software_rsakey_e2e.pem" # The location for outputting the software-protected master encryption key.
TEMP_AES_KEY_PATH="./outputted_temp_aes_key2.pem" # The location for outputting the temporary AES key.
TEMP_WRAPPED_AES_PATH="./outputted_wrapped_temporary_AES_key2.pem" # The location for outputting the wrapped temporary AES key.
WRAPPED_SOFTWARE_KEY_PATH="./outputted_wrapped_master_encryption_rsakey2.pem" # The location for outputting the wrapped software-protected master encryption key, otherwise known as the wrapped target key.
# ------------------- 追加
PEM_SOFTWARE_KEY_PATH="./coverted_software_rsakey_e2e.pem"
# -------------------
declare -a hex_array wrapped_temp_aes_key_array wrapped_targetKey_array wrapped_targetKey_array_length
# Invoke the CLI to export a software-protected master encryption key. (The response contains the wrapped data in two parts.
# The first part is a wrapped temporary AES key. The second part is the wrapped software-protected master encryption key,
# also known as the wrapped target key.)
wrapped_data=$(oci kms crypto key export --key-id ${KEY_OCID} --algorithm ${ENCRYPTION_ALGORITHM} --public-key "${PUBLIC_KEY_STRING}" --endpoint ${VAULT_CRYPTO_ENDPOINT} | grep encrypted-key | cut -d: -f2 | sed 's# "\(.*\)",#\1#g')
# Decode the encoded wrapped data and convert it to hexadecimal format.
wrapped_data_hex_array=(`echo ${wrapped_data} | base64 -d | xxd -p -c1`)
wrapped_data_hex_array_length=${#wrapped_data_hex_array[*]}
# Extract the wrapped temporary AES key. (The length of this first portion of the wrapped data is equal to the length of the private RSA wrapping key.)
wrapped_temp_aes_key_array=("${wrapped_data_hex_array[@]:0:${RSA_KEY_SIZE_IN_BYTES}}")
start_index_target_key=${#wrapped_temp_aes_key_array[*]}
# Extract the wrapped target key. (This second portion of the wrapped data is the software-protected master encryption key.)
wrapped_targetKey_array=("${wrapped_data_hex_array[@]:${start_index_target_key}:$(( ${wrapped_data_hex_array_length} - ${start_index_target_key} ))}")
wrapped_targetKey_array_length=${#wrapped_targetKey_array[*]}
# Trim spaces so that only hexadecimals remain. Convert hexadecimals to data and write to file.
wrapped_temp_aes_key_data="${wrapped_temp_aes_key_array[@]} | tr -d ' ' | xxd -p -r"
eval "echo -n $wrapped_temp_aes_key_data > $TEMP_WRAPPED_AES_PATH"
# Trim spaces so that only hexadecimals remain. Convert hexadecimals to data and write to file.
wrapped_target_key_data="${wrapped_targetKey_array[@]} | tr -d ' ' | xxd -p -r"
eval "echo $wrapped_target_key_data > $WRAPPED_SOFTWARE_KEY_PATH"
# Unwrap the wrapped_temp_aes_key by using the private RSA wrapping key.
${OPENSSL} pkeyutl -decrypt -inkey ${PRIVATE_KEY_PATH} -in ${TEMP_WRAPPED_AES_PATH} -pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 -pkeyopt rsa_mgf1_md:sha256 -out ${TEMP_AES_KEY_PATH}
TEMP_AES_KEY_HEX=$(hexdump -v -e '/1 "%02X"' < ${TEMP_AES_KEY_PATH})
# Unwrap the wrapped software-protected key material by using the unwrapped temporary AES key. The -id-aes256-wrap-pad OpenSSL cipher value specifies the RFC-3394-compliant CKM_RSA_AES_KEY_WRAP mechanism to use for unwrapping. As required by RFC 5649, -iv specifies an "alternative initial value" that is a 32-bit message length indicator expressed in hexadecimal.
${OPENSSL} enc -iv A65959A6 -in $WRAPPED_SOFTWARE_KEY_PATH -d -id-aes256-wrap-pad -K ${TEMP_AES_KEY_HEX} -out ${SOFTWARE_KEY_PATH}
# ------------------- 追加
# バイナリ ファイルを Base64 エンコードされたテキストに変換する
base64_encoded=$(base64 ${SOFTWARE_KEY_PATH} | tr -d '\n')
# Base64 エンコードされたデータを PEM 形式に変換し、改行を追加する
pem_data="-----BEGIN PRIVATE KEY-----"
line_length=64
index=0
while [ $index -lt ${#base64_encoded} ]; do
pem_data="${pem_data}\n${base64_encoded:index:line_length}"
index=$((index + line_length))
done
pem_data="${pem_data}\n-----END PRIVATE KEY-----"
# PEM 形式のデータを出力する
echo -e ${pem_data} > ${PEM_SOFTWARE_KEY_PATH}
# -----------------------
作成したexportkey.shを実行するとconverted_software_rsakey_e2e.pemが出力されます。
3.エクスポートされた秘密鍵ファイルの確認
テキストレベルでの確認
converted_software_rsakey_e2e.pemの中身はPEM型式の鍵情報であることがわかります。
$ cat converted_software_rsakey_e2e.pem
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC9FTkk42mynoly
kXEYekdj2zLhmzILKn3bfh944D32BAZZZmJaM+y0qXxEW0c7+pBS3a2qBm88ZLBB
lbOIiSUEDNUELtVa41xK7UwFwHfhtxnYSj2pkQEqzh2Wk7AGlF3zTa5iQkMY1qIT
+pEJzrWOBKVT5AZZtKeVjXch/uPVQl6jFiVV4c9Ry4D5gBHQzRJgGgpRJb/Kiiej
tPaBuMxidJXmHq/Gcr2e4SfkCXEIwyLPCV/dbjWfFy0CevBBKsZhhAXO/xN9BWCf
7b1IJMUmeJC3nK7sl+9x9ZRkuOW1CsFQ92rxTr//xcq3ng3zlT7G7jc7vGy9oGO+
.
.
.
opensslコマンドでの有効可否を確認
以下のコマンドでエラーが出なければOKです。
$ openssl rsa -in converted_software_rsakey_e2e.pem -text -noout
RSA Private-Key: (2048 bit, 2 primes)
modulus:
00:bd:15:39:24:e3:69:b2:9e:89:72:91:71:18:7a:
47:63:db:32:e1:9b:32:0b:2a:7d:db:7e:1f:78:e0:
3d:f6:04:06:59:66:62:5a:33:ec:b4:a9:7c:44:5b:
47:3b:fa:90:52:dd:ad:aa:06:6f:3c:64:b0:41:95:
b3:88:89:25:04:0c:d5:04:2e:d5:5a:e3:5c:4a:ed:
4c:05:c0:77:e1:b7:19:d8:4a:3d:a9:91:01:2a:ce:
1d:96:93:b0:06:94:5d:f3:4d:ae:62:42:43:18:d6:
a2:13:fa:91:09:ce:b5:8e:04:a5:53:e4:06:59:b4:
a7:95:8d:77:21:fe:e3:d5:42:5e:a3:16:25:55:e1:
cf:51:cb:80:f9:80:11:d0:cd:12:60:1a:0a:51:25:
bf:ca:8a:27:a3:b4:f6:81:b8:cc:62:74:95:e6:1e:
af:c6:72:bd:9e:e1:27:e4:09:71:08:c3:22:cf:09:
5f:dd:6e:35:9f:17:2d:02:7a:f0:41:2a:c6:61:84:
05:ce:ff:13:7d:05:60:9f:ed:bd:48:24:c5:26:78:
90:b7:9c:ae:ec:97:ef:71:f5:94:64:b8:e5:b5:0a:
c1:50:f7:6a:f1:4e:bf:ff:c5:ca:b7:9e:0d:f3:95:
3e:c6:ee:37:3b:bc:6c:bd:a0:63:be:0a:36:0e:a9:
19:2b
publicExponent: 65537 (0x10001)
・
・
・
・
参考情報
- https://docs.oracle.com/en-us/iaas/Content/KeyManagement/Tasks/exportingkeys_topic-To_export_a_key_by_applying_rsa_oaep_without_a_temporary_aes_key.htm
- https://docs.oracle.com/en-us/iaas/Content/KeyManagement/Tasks/to_configure_and_patch_openssl.htmー
以上