@@ -228,6 +228,7 @@ export E2IMAGE_PROG="$(type -P e2image)"
export BLKZONE_PROG="$(type -P blkzone)"
export GZIP_PROG="$(type -P gzip)"
export BTRFS_IMAGE_PROG="$(type -P btrfs-image)"
+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.
@@ -58,22 +58,21 @@ _require_scratch_encryption()
# If required, check for support for the specific type of encryption
# policy required by the test.
if [ $# -ne 0 ]; then
- _require_encryption_policy_support $SCRATCH_MNT "$@"
+ _require_scratch_encryption_policy_support "$@"
fi
_scratch_unmount
}
-_require_encryption_policy_support()
+_require_scratch_encryption_policy_support()
{
- local mnt=$1
- local dir=$mnt/tmpdir
+ local dir=$SCRATCH_MNT/tmpdir
local set_encpolicy_args=""
local policy_flags=0
local policy_version=1
local c
- OPTIND=2
+ OPTIND=1
while getopts "c:n:f:v:" c; do
case $c in
c|n)
@@ -94,6 +93,12 @@ _require_encryption_policy_support()
done
set_encpolicy_args=${set_encpolicy_args# }
+ if (( policy_flags & FSCRYPT_POLICY_FLAG_HW_WRAPPED_KEY )); then
+ echo "Checking whether $SCRATCH_DEV supports hardware-wrapped keys" \
+ >> $seqres.full
+ _require_hw_wrapped_key_support $SCRATCH_DEV
+ fi
+
echo "Checking whether kernel supports encryption policy: $set_encpolicy_args" \
>> $seqres.full
@@ -117,8 +122,15 @@ _require_encryption_policy_support()
# Both the kernel and xfs_io support v2 encryption policies, and
# therefore also filesystem-level keys -- since that's the only
# way to provide keys for v2 policies.
- local raw_key=$(_generate_raw_encryption_key)
- local keyspec=$(_add_enckey $mnt "$raw_key" | awk '{print $NF}')
+ if (( policy_flags & FSCRYPT_POLICY_FLAG_HW_WRAPPED_KEY )); then
+ local raw_key=$(_generate_raw_hw_key)
+ 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
_require_command "$KEYCTL_PROG" keyctl
_new_session_keyring
@@ -143,6 +155,47 @@ _require_encryption_policy_support()
rm -r $dir
}
+# Require that the filesystem accepts the "inlinecrypt" mount option.
+#
+# Note: this doesn't check whether $SCRATCH_DEV has any specific inline
+# encryption capabilities. For encryption policies that require specific
+# capabilities, support is detected later by
+# _require_scratch_encryption_policy_support() (provided that inlinecrypt has
+# been added to $MOUNT_OPTIONS by that point).
+_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
+
+ _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
+
+ if ! head -c $RAW_HW_KEY_SIZE /dev/urandom | \
+ "$FSCRYPTCTL_PROG" import_hw_wrapped_key "$dev" \
+ >/dev/null 2>$tmp.err
+ then
+ if grep -E -q \
+ "(Operation not supported)|(Inappropriate ioctl for device)" $tmp.err
+ then
+ _notrun "$dev doesn't support hardware-wrapped inline encryption keys"
+ fi
+ _fail "Unexpected error from fscryptctl import_hw_wrapped_key: $(< $tmp.err)"
+ fi
+}
+
_scratch_mkfs_encrypted()
{
case $FSTYP in
@@ -220,14 +273,24 @@ _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
+
+# Generate a raw key of the proper size to be imported as a hardware-wrapped
+# key.
+_generate_raw_hw_key()
+{
+ _generate_raw_encryption_key $RAW_HW_KEY_SIZE
+}
+
# 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.
@@ -358,6 +421,21 @@ _add_enckey()
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
@@ -771,6 +849,7 @@ FSCRYPT_MODE_ADIANTUM=9
FSCRYPT_POLICY_FLAG_DIRECT_KEY=0x04
FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64=0x08
FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32=0x10
+FSCRYPT_POLICY_FLAG_HW_WRAPPED_KEY=0x20
FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR=1
FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER=2
@@ -800,6 +879,7 @@ _fscrypt_mode_name_to_num()
# '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
+# 'hw_wrapped_key': test the HW_WRAPPED_KEY policy flag
#
_verify_ciphertext_for_encryption_policy()
{
@@ -832,6 +912,9 @@ _verify_ciphertext_for_encryption_policy()
iv_ino_lblk_32)
(( policy_flags |= FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32 ))
;;
+ hw_wrapped_key)
+ (( policy_flags |= FSCRYPT_POLICY_FLAG_HW_WRAPPED_KEY ))
+ ;;
*)
_fail "Unknown option '$opt' passed to ${FUNCNAME[0]}"
;;
@@ -855,6 +938,10 @@ _verify_ciphertext_for_encryption_policy()
elif (( policy_flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32 )); then
crypt_util_args+=" --iv-ino-lblk-32"
fi
+ if (( policy_flags & FSCRYPT_POLICY_FLAG_HW_WRAPPED_KEY )); then
+ crypt_util_args+=" --enable-hw-kdf"
+ crypt_util_contents_args+=" --use-inlinecrypt-key"
+ fi
else
if (( policy_flags & ~FSCRYPT_POLICY_FLAG_DIRECT_KEY )); then
_fail "unsupported flags for v1 policy: $policy_flags"
@@ -891,11 +978,18 @@ _verify_ciphertext_for_encryption_policy()
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 (( policy_flags & FSCRYPT_POLICY_FLAG_HW_WRAPPED_KEY )); then
+ local raw_key=$(_generate_raw_hw_key)
+ 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)
_new_session_keyring
_add_session_encryption_key $keyspec $raw_key