본문 바로가기
6. 보안 Security

OCI Vault 의 Software 보호 모드 Master Encryption Key 추출하기 2편 - RSA 알고리즘

by 동인천급행열차 2024. 4. 17.

OCI 의 키관리 서비스인 Vault 에서 Software 보호 모드의 Master Encryption Key : RSA 알고리즘 를 추출하는 방법을 가이드합니다.
 
HSM 모듈을 사용하는 Master Encryption Key와 달리, Software 보호 모드를 사용하는 Master Encryption Key의 경우 OCI CLI를 통해 추출하여 로컬 환경에서도 동일하게 사용하실 수 있습니다.
 
OAEP(Optimal Asymmetric Encryption Padding)라는 메커니즘을 통해 Software 보호 모드의 Master Encryption Key를 변환하고, 이를 공개 RSA 래핑 키를 사용하여 Software 보호 모드 Mater Encryption Key를 래핑한 다음, 개인 RSA 래핑 키를 사용하여 래핑을 풀어 Mater Encryption Key 를 내보내는 과정으로 이루어집니다.

 

본 가이드를 위한 사전 요구환경은 다음과 같습니다.

  1. OpenSSL 1.1.1 설치
  2. OCI CLI 환경 구성

OpenSSL 1.1.1 버전은 OCI VM에 기본적으로 설치가 되어있으며 (버전 확인 명령어: ~]$ openssl version),
OCI CLI 환경 구성 방법은 본 포스팅에서 다루지 않습니다.

 

[Step1. Yum Repository 설정] 

Step2 단계에서 OpenSSL 패치를 위한 의존성 설치 과정이 필요합니다.

 

아래와 같이 의존성 설치 명령어 실행시 아래와 같은 메시지가 발생하고 정상적으로 설치가 안된다면, Step1 단계를 통해 Repository 설정이 필요합니다.

~]$ sudo yum install patch make gcc -y

There are no enabled repositories in etc/yum/repos.d, /etc/yum/repos.d /etc/distro/repos.d

 

Oracle Linux 8을 사용하실 경우 별도의 yum repository 설정이 없기 때문에 repository 설정을 추가해주셔야 합니다.

 

본 포스팅에서는 타 OS 및 버전의 Repository 추가 방법은 다루지 않습니다.

 

/etc/yum.repos.d/ 경로 이하에 repository 설정 파일을 생성 후 설정을 입력합니다.

~]$ sudo vim /etc/yum.repos.d/temp_base.repo

[ol8_baseos_latest]
name=Oracle Linux 8 BaseOS Latest ($basearch)
baseurl=https://yum$ociregion.$ocidomain/repo/OracleLinux/OL8/baseos/latest/$basearch/
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-oracle
gpgcheck=1
enabled=1

 

참고자료 : https://docs.oracle.com/en/operating-systems/oracle-linux/software-management/sfw-mgmt-ConfigureaSystemtoUseEnterpriseLinuxYumServer.html#recover-base-yum

 

[Step2. OpenSSL 패치]

RSA Key를 Export하기 위한  Key 래핑에는  RSA_OAEP_AES_SHA256 알고리즘을 사용해야 합니다.

 

RSA_AES_KEY_WRAP과 호환되는 OpenSSL -id-aes256-wrap-pad 명령어 사용을 위해서는 OpenSSL의 패치가 필요합니다.

 

OpenSSL의 패치방법은 아래의 가이드 문서로 대체합니다.

 

https://docs.oracle.com/en-us/iaas/Content/KeyManagement/Tasks/to_configure_and_patch_openssl.htm

 

문서 내 1~10번까지의 절차를 수행하시어 패치하시기 바랍니다.

 

정상적으로 패치가 완료될 경우 $HOME/local/bin 경로에 OpenSSL 실행 스크립트 openssl.sh가 생성됩니다.

 

[Step3.  Export 스크립트 수행]

아래의 스크립트를 $HOME 경로에 생성하여 줍니다. 붉은색의 변수만을 변경해주시면 됩니다.

 

~]$ vim $HOME/export_scritpt.sh
~]$ chmod 755 $HOME/export_scritpt.sh

 

OPENSSL= openssl.sh 파일 경로로 $HOME/local/bin/openssl.sh 을 기본으로 합니다.
KEY_OCID= 추출을 원하는 Software Protect Mode Master Encryption Key의 OCID, Vault 내 Master Encryption Key 메뉴에서 확인

RSA_KEY_SIZE_IN_BYTES= 마스터 암호화 키의 RSA 알고리즘 사이즈 에 따라 2048 -> 256, 4096 ->512 를 설정 

VAULT_CRYPTO_ENDPOINT="Master Encryption Key가 존재하는 Vault의 Crprytographic Endpoint, Vault 메뉴에서 확인

 

그외 추출되는 KEY_PATH는 고정변수로 작성되었으나, 편의에 따라 경로와 파일명 등을 자유롭게 수정하여 사용하셔도 무방합니다.

#!/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_AES_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/opc/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.ap-seoul-1.<----생략---->pksdfzobkxrcy4a" # 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://<----생략---->-crypto.kms.ap-seoul-1.oci.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.


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}

 

error가 없이 위 화면과 같이 수행된다면 성공
정상적으로 수행된다면 위와 같이 파일사이즈가 있는 key들이 추출됩니다. 에러가 발생할 경우 파일은 생성되나 파일사이즈가 0으로 유효하지 않은 key 입니다.

 

*Master Encryption Key 유출로 인한 보안사고의 책임은 사용자에게 있으므로, 해당 기능 사용에 각별한 주의가 필요합니다.

 

작성자: 최동혁 / Oracle Cloud Architect

개인 시간을 투자하여 작성된 글로서, 글의 내용에 오류가 있을 수 있으며, 글 속의 의견은 개인적인 의견입니다.

댓글