From: Eric Biggers <ebiggers@xxxxxxxxxx> To support testing the kernel's support for hardware-wrapped inline encryption keys, update _verify_ciphertext_for_encryption_policy() to support a hw_wrapped_key option. Signed-off-by: Eric Biggers <ebiggers@xxxxxxxxxx> --- common/config | 1 + common/encrypt | 80 +++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 77 insertions(+), 4 deletions(-) diff --git a/common/config b/common/config index fcff0660..091405b3 100644 --- a/common/config +++ b/common/config @@ -233,10 +233,11 @@ export BLKZONE_PROG="$(type -P blkzone)" export GZIP_PROG="$(type -P gzip)" export BTRFS_IMAGE_PROG="$(type -P btrfs-image)" export BTRFS_MAP_LOGICAL_PROG=$(type -P btrfs-map-logical) export PARTED_PROG="$(type -P parted)" export XFS_PROPERTY_PROG="$(type -P xfs_property)" +export FSCRYPTCTL_PROG="$(type -P fscryptctl)" # use 'udevadm settle' or 'udevsettle' to wait for lv to be settled. # newer systems have udevadm command but older systems like RHEL5 don't. # But if neither one is available, just set it to "sleep 1" to wait for lv to # be settled diff --git a/common/encrypt b/common/encrypt index d90a566a..1caca767 100644 --- a/common/encrypt +++ b/common/encrypt @@ -150,10 +150,46 @@ _require_encryption_policy_support() $KEYCTL_PROG clear $TEST_KEYRING_ID fi rm -r $dir } +# Require that the scratch filesystem accepts the "inlinecrypt" mount option. +# +# This does not check whether the scratch block device has any specific inline +# encryption capabilities. +_require_scratch_inlinecrypt() +{ + _require_scratch + _scratch_mkfs &>> $seqres.full + if ! _try_scratch_mount -o inlinecrypt &>> $seqres.full; then + _notrun "filesystem doesn't support -o inlinecrypt" + fi +} + +# Require that the given block device supports hardware-wrapped inline +# encryption keys, and require that a command-line tool that supports +# importing/generating/preparing them is available. +_require_hw_wrapped_key_support() +{ + local dev=$1 + + echo "Checking for HW-wrapped key support on $dev" >> $seqres.full + local sysfs_dir=$(_sysfs_dev $dev) + if [ ! -e $sysfs_dir/queue ]; then + sysfs_dir=$sysfs_dir/.. + fi + if [ ! -e $sysfs_dir/queue/crypto/hw_wrapped_keys ]; then + _notrun "$dev doesn't support hardware-wrapped inline encryption keys" + fi + + echo "Checking for fscryptctl support for HW-wrapped keys" >> $seqres.full + _require_command "$FSCRYPTCTL_PROG" fscryptctl + if ! "$FSCRYPTCTL_PROG" --help | grep -q "import_hw_wrapped_key"; then + _notrun "fscryptctl too old; doesn't support hardware-wrapped inline encryption keys" + fi +} + _scratch_mkfs_encrypted() { case $FSTYP in ext4|f2fs) _scratch_mkfs -O encrypt @@ -249,18 +285,21 @@ _generate_key_descriptor() } # Generate a raw encryption key, but don't add it to any keyring yet. _generate_raw_encryption_key() { + local size=${1:-64} local raw="" local i - for ((i = 0; i < 64; i++)); do + for ((i = 0; i < $size; i++)); do raw="${raw}\\x$(printf "%02x" $(( $RANDOM % 256 )))" done echo $raw } +RAW_HW_KEY_SIZE=32 + # Serialize an integer into a CPU-endian bytestring of the given length, and # print it as a string where each byte is hex-escaped. For example, # `_num_to_hex 1000 4` == "\xe8\x03\x00\x00" if the CPU is little endian. _num_to_hex() { @@ -405,10 +444,25 @@ _add_enckey() shift 2 echo -ne "$raw_key" | $XFS_IO_PROG -c "add_enckey $*" "$mnt" } +# Create a hardware-wrapped key from the given raw key using the given block +# device, add it to the given filesystem, and print the resulting key +# identifier. +_add_hw_wrapped_key() +{ + local dev=$1 + local mnt=$2 + local raw_key=$3 + + echo -ne "$raw_key" | \ + $FSCRYPTCTL_PROG import_hw_wrapped_key "$dev" | \ + $FSCRYPTCTL_PROG prepare_hw_wrapped_key "$dev" | \ + $FSCRYPTCTL_PROG add_key --hw-wrapped-key "$mnt" +} + _user_do_add_enckey() { local mnt=$1 local raw_key=$2 shift 2 @@ -851,19 +905,21 @@ _fscrypt_mode_name_to_num() # 'v2': test a v2 encryption policy # 'direct': test the DIRECT_KEY policy flag # 'iv_ino_lblk_64': test the IV_INO_LBLK_64 policy flag # 'iv_ino_lblk_32': test the IV_INO_LBLK_32 policy flag # 'log2_dusize=N': test the log2_data_unit_size field +# 'hw_wrapped_key': use a hardware-wrapped inline encryption key # _verify_ciphertext_for_encryption_policy() { local contents_encryption_mode=$1 local filenames_encryption_mode=$2 local opt local policy_version=1 local policy_flags=0 local log2_dusize=0 + local hw_wrapped_key=false local set_encpolicy_args="" local crypt_util_args="" local crypt_util_contents_args="" local crypt_util_filename_args="" local expected_identifier @@ -888,10 +944,15 @@ _verify_ciphertext_for_encryption_policy() (( policy_flags |= FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32 )) ;; log2_dusize=*) log2_dusize=$(echo "$opt" | sed 's/^log2_dusize=//') ;; + hw_wrapped_key) + hw_wrapped_key=true + crypt_util_args+=" --enable-hw-kdf" + crypt_util_contents_args+=" --use-inlinecrypt-key" + ;; *) _fail "Unknown option '$opt' passed to ${FUNCNAME[0]}" ;; esac done @@ -927,10 +988,13 @@ _verify_ciphertext_for_encryption_policy() fi fi set_encpolicy_args=${set_encpolicy_args# } _require_scratch_encryption $set_encpolicy_args -f $policy_flags + if $hw_wrapped_key; then + _require_hw_wrapped_key_support $SCRATCH_DEV + fi _require_test_program "fscrypt-crypt-util" _require_xfs_io_command "fiemap" _require_get_encryption_nonce_support _require_get_ciphertext_filename_support if (( policy_version == 1 )); then @@ -956,15 +1020,23 @@ _verify_ciphertext_for_encryption_policy() crypt_util_contents_args+="$crypt_util_args" crypt_util_filename_args+="$crypt_util_args" echo "Generating encryption key" >> $seqres.full - local raw_key=$(_generate_raw_encryption_key) if (( policy_version > 1 )); then - local keyspec=$(_add_enckey $SCRATCH_MNT "$raw_key" \ - | awk '{print $NF}') + if $hw_wrapped_key; then + local raw_key=$(_generate_raw_encryption_key \ + $RAW_HW_KEY_SIZE) + local keyspec=$(_add_hw_wrapped_key $SCRATCH_DEV \ + $SCRATCH_MNT "$raw_key") + else + local raw_key=$(_generate_raw_encryption_key) + local keyspec=$(_add_enckey $SCRATCH_MNT "$raw_key" | \ + awk '{print $NF}') + fi else + local raw_key=$(_generate_raw_encryption_key) local keyspec=$(_generate_key_descriptor) _init_session_keyring _add_session_encryption_key $keyspec $raw_key fi local raw_key_hex=$(echo "$raw_key" | tr -d '\\x') -- 2.47.1