All of lore.kernel.org
 help / color / mirror / Atom feed
From: Eric Biggers <ebiggers@kernel.org>
To: fstests@vger.kernel.org
Cc: linux-block@vger.kernel.org, linux-fscrypt@vger.kernel.org,
	Gaurav Kashyap <quic_gaurkash@quicinc.com>
Subject: [RFC PATCH 7/8] common/encrypt: support hardware-wrapped key testing
Date: Sun, 27 Feb 2022 23:47:21 -0800	[thread overview]
Message-ID: <20220228074722.77008-8-ebiggers@kernel.org> (raw)
In-Reply-To: <20220228074722.77008-1-ebiggers@kernel.org>

From: Eric Biggers <ebiggers@google.com>

To support testing the kernel's support for hardware-wrapped inline
encryption keys, add some new functions to common/encrypt:

  - _require_hw_wrapped_key_support(): Checks that a block device
    supports hardware-wrapped keys and that some related fscryptctl
    commands are present.

  - _require_scratch_inlinecrypt(): Checks that the filesystem accepts
    the inlinecrypt mount option.

  - _generate_raw_hw_key(): Generates a raw key of an appropriate size
    for importing as a hardware-wrapped key.

  - _add_hw_wrapped_key(): Imports and prepares a hardware-wrapped key,
    then adds it to a filesystem.

In addition, update _require_encryption_policy_support() and
_verify_ciphertext_for_encryption_policy() to support
FSCRYPT_POLICY_FLAG_HW_WRAPPED_KEY.

Note: some of this relies on being able to call new block device ioctls.
For now these are accessed through the fscryptctl program.

Signed-off-by: Eric Biggers <ebiggers@google.com>
---
 common/config  |   1 +
 common/encrypt | 116 ++++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 106 insertions(+), 11 deletions(-)

diff --git a/common/config b/common/config
index 479e50d1..85a7919c 100644
--- a/common/config
+++ b/common/config
@@ -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.
diff --git a/common/encrypt b/common/encrypt
index d8e2dba9..e91e05c4 100644
--- a/common/encrypt
+++ b/common/encrypt
@@ -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
-- 
2.35.1


  parent reply	other threads:[~2022-02-28  7:48 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-02-28  7:47 [RFC PATCH 0/8] xfstests: test the fscrypt hardware-wrapped key support Eric Biggers
2022-02-28  7:47 ` [RFC PATCH 1/8] fscrypt-crypt-util: use an explicit --direct-key option Eric Biggers
2022-02-28  7:47 ` [RFC PATCH 2/8] fscrypt-crypt-util: refactor get_key_and_iv() Eric Biggers
2022-02-28  7:47 ` [RFC PATCH 3/8] fscrypt-crypt-util: add support for dumping key identifier Eric Biggers
2022-02-28  7:47 ` [RFC PATCH 4/8] common/encrypt: log full ciphertext verification params Eric Biggers
2022-02-28  7:47 ` [RFC PATCH 5/8] common/encrypt: verify the key identifiers Eric Biggers
2022-02-28  7:47 ` [RFC PATCH 6/8] fscrypt-crypt-util: add hardware KDF support Eric Biggers
2022-02-28  7:47 ` Eric Biggers [this message]
2022-02-28  7:47 ` [RFC PATCH 8/8] generic: verify ciphertext with hardware-wrapped keys Eric Biggers

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220228074722.77008-8-ebiggers@kernel.org \
    --to=ebiggers@kernel.org \
    --cc=fstests@vger.kernel.org \
    --cc=linux-block@vger.kernel.org \
    --cc=linux-fscrypt@vger.kernel.org \
    --cc=quic_gaurkash@quicinc.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.