mirror of
https://github.com/linux-apfs/apfstests.git
synced 2026-05-01 15:01:44 -07:00
generic: test adding filesystem-level fscrypt key via key_id
Add a test which tests adding a key to a filesystem's fscrypt keyring
via an "fscrypt-provisioning" keyring key. This is an alternative to
the normal method where the raw key is given directly.
For more details, see kernel commit 93edd392cad7 ("fscrypt: support
passing a keyring key to FS_IOC_ADD_ENCRYPTION_KEY").
This test depends on an xfs_io patch which adds the '-k' option to the
'add_enckey' command, e.g.:
xfs_io -c "add_enckey -k KEY_ID" MOUNTPOINT
This test is skipped if the needed kernel or xfs_io support is absent.
This has been tested on ext4, f2fs, and ubifs.
Signed-off-by: Eric Biggers <ebiggers@google.com>
Signed-off-by: Eryu Guan <guaneryu@gmail.com>
This commit is contained in:
+70
-14
@@ -227,6 +227,28 @@ _generate_raw_encryption_key()
|
|||||||
echo $raw
|
echo $raw
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# 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()
|
||||||
|
{
|
||||||
|
local value=$1
|
||||||
|
local nbytes=$2
|
||||||
|
local i
|
||||||
|
local big_endian=$(echo -ne '\x11' | od -tx2 | head -1 | \
|
||||||
|
cut -f2 -d' ' | cut -c1)
|
||||||
|
|
||||||
|
if (( big_endian )); then
|
||||||
|
for (( i = 0; i < nbytes; i++ )); do
|
||||||
|
printf '\\x%02x' $(((value >> (8*(nbytes-1-i))) & 0xff))
|
||||||
|
done
|
||||||
|
else
|
||||||
|
for (( i = 0; i < nbytes; i++ )); do
|
||||||
|
printf '\\x%02x' $(((value >> (8*i)) & 0xff))
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# Add the specified raw encryption key to the session keyring, using the
|
# Add the specified raw encryption key to the session keyring, using the
|
||||||
# specified key descriptor.
|
# specified key descriptor.
|
||||||
_add_session_encryption_key()
|
_add_session_encryption_key()
|
||||||
@@ -237,12 +259,12 @@ _add_session_encryption_key()
|
|||||||
#
|
#
|
||||||
# Add the key to the session keyring. The required structure is:
|
# Add the key to the session keyring. The required structure is:
|
||||||
#
|
#
|
||||||
# #define FS_MAX_KEY_SIZE 64
|
# #define FSCRYPT_MAX_KEY_SIZE 64
|
||||||
# struct fscrypt_key {
|
# struct fscrypt_key {
|
||||||
# u32 mode;
|
# __u32 mode;
|
||||||
# u8 raw[FS_MAX_KEY_SIZE];
|
# __u8 raw[FSCRYPT_MAX_KEY_SIZE];
|
||||||
# u32 size;
|
# __u32 size;
|
||||||
# } __packed;
|
# };
|
||||||
#
|
#
|
||||||
# The kernel ignores 'mode' but requires that 'size' be 64.
|
# The kernel ignores 'mode' but requires that 'size' be 64.
|
||||||
#
|
#
|
||||||
@@ -253,15 +275,8 @@ _add_session_encryption_key()
|
|||||||
# nice to use the common key prefix, but for now use the filesystem-
|
# nice to use the common key prefix, but for now use the filesystem-
|
||||||
# specific prefix to make it possible to test older kernels...
|
# specific prefix to make it possible to test older kernels...
|
||||||
#
|
#
|
||||||
local big_endian=$(echo -ne '\x11' | od -tx2 | head -1 | \
|
local mode=$(_num_to_hex 0 4)
|
||||||
cut -f2 -d' ' | cut -c1 )
|
local size=$(_num_to_hex 64 4)
|
||||||
if (( big_endian )); then
|
|
||||||
local mode='\x00\x00\x00\x00'
|
|
||||||
local size='\x00\x00\x00\x40'
|
|
||||||
else
|
|
||||||
local mode='\x00\x00\x00\x00'
|
|
||||||
local size='\x40\x00\x00\x00'
|
|
||||||
fi
|
|
||||||
echo -n -e "${mode}${raw}${size}" |
|
echo -n -e "${mode}${raw}${size}" |
|
||||||
$KEYCTL_PROG padd logon $FSTYP:$keydesc @s >>$seqres.full
|
$KEYCTL_PROG padd logon $FSTYP:$keydesc @s >>$seqres.full
|
||||||
}
|
}
|
||||||
@@ -389,6 +404,44 @@ _user_do_enckey_status()
|
|||||||
_user_do "$XFS_IO_PROG -c \"enckey_status $* $keyspec\" \"$mnt\""
|
_user_do "$XFS_IO_PROG -c \"enckey_status $* $keyspec\" \"$mnt\""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Require support for adding a key to a filesystem's fscrypt keyring via an
|
||||||
|
# "fscrypt-provisioning" keyring key.
|
||||||
|
_require_add_enckey_by_key_id()
|
||||||
|
{
|
||||||
|
local mnt=$1
|
||||||
|
|
||||||
|
# Userspace support
|
||||||
|
_require_xfs_io_command "add_enckey" "-k"
|
||||||
|
|
||||||
|
# Kernel support
|
||||||
|
if $XFS_IO_PROG -c "add_enckey -k 12345" "$mnt" \
|
||||||
|
|& grep -q 'Invalid argument'; then
|
||||||
|
_notrun "Kernel doesn't support key_id parameter to FS_IOC_ADD_ENCRYPTION_KEY"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Add a key of type "fscrypt-provisioning" to the session keyring and print the
|
||||||
|
# resulting key ID.
|
||||||
|
_add_fscrypt_provisioning_key()
|
||||||
|
{
|
||||||
|
local desc=$1
|
||||||
|
local type=$2
|
||||||
|
local raw=$3
|
||||||
|
|
||||||
|
# The format of the key payload must be:
|
||||||
|
#
|
||||||
|
# struct fscrypt_provisioning_key_payload {
|
||||||
|
# __u32 type;
|
||||||
|
# __u32 __reserved;
|
||||||
|
# __u8 raw[];
|
||||||
|
# };
|
||||||
|
#
|
||||||
|
local type_hex=$(_num_to_hex $type 4)
|
||||||
|
local reserved=$(_num_to_hex 0 4)
|
||||||
|
echo -n -e "${type_hex}${reserved}${raw}" |
|
||||||
|
$KEYCTL_PROG padd fscrypt-provisioning "$desc" @s
|
||||||
|
}
|
||||||
|
|
||||||
# Retrieve the encryption nonce of the given inode as a hex string. The nonce
|
# Retrieve the encryption nonce of the given inode as a hex string. The nonce
|
||||||
# was randomly generated by the filesystem and isn't exposed directly to
|
# was randomly generated by the filesystem and isn't exposed directly to
|
||||||
# userspace. But it can be read using the filesystem's debugging tools.
|
# userspace. But it can be read using the filesystem's debugging tools.
|
||||||
@@ -717,6 +770,9 @@ FSCRYPT_MODE_ADIANTUM=9
|
|||||||
FSCRYPT_POLICY_FLAG_DIRECT_KEY=0x04
|
FSCRYPT_POLICY_FLAG_DIRECT_KEY=0x04
|
||||||
FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64=0x08
|
FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64=0x08
|
||||||
|
|
||||||
|
FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR=1
|
||||||
|
FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER=2
|
||||||
|
|
||||||
_fscrypt_mode_name_to_num()
|
_fscrypt_mode_name_to_num()
|
||||||
{
|
{
|
||||||
local name=$1
|
local name=$1
|
||||||
|
|||||||
Executable
+155
@@ -0,0 +1,155 @@
|
|||||||
|
#! /bin/bash
|
||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
# Copyright 2019 Google LLC
|
||||||
|
#
|
||||||
|
# FS QA Test No. 593
|
||||||
|
#
|
||||||
|
# Test adding a key to a filesystem's fscrypt keyring via an
|
||||||
|
# "fscrypt-provisioning" keyring key. This is an alternative to the normal
|
||||||
|
# method where the raw key is given directly.
|
||||||
|
#
|
||||||
|
seq=`basename $0`
|
||||||
|
seqres=$RESULT_DIR/$seq
|
||||||
|
echo "QA output created by $seq"
|
||||||
|
|
||||||
|
here=`pwd`
|
||||||
|
tmp=/tmp/$$
|
||||||
|
status=1 # failure is the default!
|
||||||
|
trap "_cleanup; exit \$status" 0 1 2 3 15
|
||||||
|
|
||||||
|
_cleanup()
|
||||||
|
{
|
||||||
|
cd /
|
||||||
|
rm -f $tmp.*
|
||||||
|
}
|
||||||
|
|
||||||
|
# get standard environment, filters and checks
|
||||||
|
. ./common/rc
|
||||||
|
. ./common/filter
|
||||||
|
. ./common/encrypt
|
||||||
|
|
||||||
|
# remove previous $seqres.full before test
|
||||||
|
rm -f $seqres.full
|
||||||
|
|
||||||
|
# real QA test starts here
|
||||||
|
_supported_fs generic
|
||||||
|
_supported_os Linux
|
||||||
|
_require_scratch_encryption -v 2
|
||||||
|
_require_command "$KEYCTL_PROG" keyctl
|
||||||
|
|
||||||
|
_new_session_keyring
|
||||||
|
_scratch_mkfs_encrypted &>> $seqres.full
|
||||||
|
_scratch_mount
|
||||||
|
_require_add_enckey_by_key_id $SCRATCH_MNT
|
||||||
|
|
||||||
|
test_with_policy_version()
|
||||||
|
{
|
||||||
|
local vers=$1
|
||||||
|
local dir=$SCRATCH_MNT/dir
|
||||||
|
local keyid
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "# =========================="
|
||||||
|
echo "# Test with policy version $vers"
|
||||||
|
echo "# =========================="
|
||||||
|
|
||||||
|
case $vers in
|
||||||
|
1)
|
||||||
|
local keytype=$FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR
|
||||||
|
local keyspec=$TEST_KEY_DESCRIPTOR
|
||||||
|
local add_enckey_args="-d $TEST_KEY_DESCRIPTOR"
|
||||||
|
;;
|
||||||
|
2)
|
||||||
|
local keytype=$FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER
|
||||||
|
local keyspec=$TEST_KEY_IDENTIFIER
|
||||||
|
local add_enckey_args=""
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
_fail "Unknown policy version: $vers"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# First add the key in the regular way (raw key given directly), create
|
||||||
|
# an encrypted file with some contents, and remove the key. After this,
|
||||||
|
# the encrypted file should no longer be readable.
|
||||||
|
|
||||||
|
echo -e "\n# Adding key to filesystem"
|
||||||
|
_add_enckey $SCRATCH_MNT "$TEST_RAW_KEY" $add_enckey_args
|
||||||
|
|
||||||
|
echo -e "\n# Creating encrypted file"
|
||||||
|
mkdir $dir
|
||||||
|
_set_encpolicy $dir $keyspec
|
||||||
|
echo "contents" > $dir/file
|
||||||
|
|
||||||
|
echo -e "\n# Removing key from filesystem"
|
||||||
|
_rm_enckey $SCRATCH_MNT $keyspec
|
||||||
|
cat $dir/file |& _filter_scratch
|
||||||
|
|
||||||
|
# Now we should be able to add the key back via an fscrypt-provisioning
|
||||||
|
# key which contains the raw key, instead of providing the raw key
|
||||||
|
# directly. After this, the encrypted file should be readable again.
|
||||||
|
|
||||||
|
echo -e "\n# Adding fscrypt-provisioning key"
|
||||||
|
keyid=$(_add_fscrypt_provisioning_key $keyspec $keytype "$TEST_RAW_KEY")
|
||||||
|
|
||||||
|
echo -e "\n# Adding key to filesystem via fscrypt-provisioning key"
|
||||||
|
$XFS_IO_PROG -c "add_enckey -k $keyid $add_enckey_args" $SCRATCH_MNT
|
||||||
|
|
||||||
|
echo -e "\n# Reading encrypted file"
|
||||||
|
cat $dir/file
|
||||||
|
|
||||||
|
echo -e "\n# Cleaning up"
|
||||||
|
rm -rf $dir
|
||||||
|
_scratch_cycle_mount # Clear all keys
|
||||||
|
}
|
||||||
|
|
||||||
|
# Test with both v1 and v2 encryption policies.
|
||||||
|
test_with_policy_version 1
|
||||||
|
test_with_policy_version 2
|
||||||
|
|
||||||
|
# Now test that invalid fscrypt-provisioning keys can't be created, that
|
||||||
|
# fscrypt-provisioning keys can't be read back by userspace, and that the
|
||||||
|
# filesystem only accepts properly matching fscrypt-provisioning keys.
|
||||||
|
echo
|
||||||
|
echo "# ================"
|
||||||
|
echo "# Validation tests"
|
||||||
|
echo "# ================"
|
||||||
|
|
||||||
|
echo -e "\n# Adding an invalid fscrypt-provisioning key fails"
|
||||||
|
echo "# ... bad type"
|
||||||
|
_add_fscrypt_provisioning_key desc 0 "$TEST_RAW_KEY"
|
||||||
|
echo "# ... bad type"
|
||||||
|
_add_fscrypt_provisioning_key desc 10000 "$TEST_RAW_KEY"
|
||||||
|
echo "# ... raw key too small"
|
||||||
|
_add_fscrypt_provisioning_key desc $FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR ""
|
||||||
|
echo "# ... raw key too large"
|
||||||
|
_add_fscrypt_provisioning_key desc $FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR \
|
||||||
|
"$TEST_RAW_KEY$TEST_RAW_KEY"
|
||||||
|
|
||||||
|
echo -e "\n# keyctl_read() doesn't work on fscrypt-provisioning keys"
|
||||||
|
keyid=$(_add_fscrypt_provisioning_key desc $FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR \
|
||||||
|
"$TEST_RAW_KEY")
|
||||||
|
$KEYCTL_PROG read $keyid
|
||||||
|
$KEYCTL_PROG unlink $keyid @s
|
||||||
|
|
||||||
|
echo -e "\n# Only keys with the correct fscrypt_provisioning_key_payload::type field can be added"
|
||||||
|
echo "# ... keyring key is v1, filesystem wants v2 key"
|
||||||
|
keyid=$(_add_fscrypt_provisioning_key desc $FSCRYPT_KEY_SPEC_TYPE_DESCRIPTOR \
|
||||||
|
"$TEST_RAW_KEY")
|
||||||
|
$XFS_IO_PROG -c "add_enckey -k $keyid" $SCRATCH_MNT
|
||||||
|
$KEYCTL_PROG unlink $keyid @s
|
||||||
|
|
||||||
|
echo "# ... keyring key is v2, filesystem wants v1 key"
|
||||||
|
keyid=$(_add_fscrypt_provisioning_key desc $FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER \
|
||||||
|
"$TEST_RAW_KEY")
|
||||||
|
$XFS_IO_PROG -c "add_enckey -k $keyid -d $TEST_KEY_DESCRIPTOR" $SCRATCH_MNT
|
||||||
|
$KEYCTL_PROG unlink $keyid @s
|
||||||
|
|
||||||
|
echo -e "\n# Only keys of type fscrypt-provisioning can be added"
|
||||||
|
keyid=$(head -c 64 /dev/urandom | $KEYCTL_PROG padd logon foo:desc @s)
|
||||||
|
$XFS_IO_PROG -c "add_enckey -k $keyid" $SCRATCH_MNT
|
||||||
|
$KEYCTL_PROG unlink $keyid @s
|
||||||
|
|
||||||
|
# success, all done
|
||||||
|
status=0
|
||||||
|
exit
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
QA output created by 593
|
||||||
|
|
||||||
|
# ==========================
|
||||||
|
# Test with policy version 1
|
||||||
|
# ==========================
|
||||||
|
|
||||||
|
# Adding key to filesystem
|
||||||
|
Added encryption key with descriptor 0000111122223333
|
||||||
|
|
||||||
|
# Creating encrypted file
|
||||||
|
|
||||||
|
# Removing key from filesystem
|
||||||
|
Removed encryption key with descriptor 0000111122223333
|
||||||
|
cat: SCRATCH_MNT/dir/file: No such file or directory
|
||||||
|
|
||||||
|
# Adding fscrypt-provisioning key
|
||||||
|
|
||||||
|
# Adding key to filesystem via fscrypt-provisioning key
|
||||||
|
Added encryption key with descriptor 0000111122223333
|
||||||
|
|
||||||
|
# Reading encrypted file
|
||||||
|
contents
|
||||||
|
|
||||||
|
# Cleaning up
|
||||||
|
|
||||||
|
# ==========================
|
||||||
|
# Test with policy version 2
|
||||||
|
# ==========================
|
||||||
|
|
||||||
|
# Adding key to filesystem
|
||||||
|
Added encryption key with identifier 69b2f6edeee720cce0577937eb8a6751
|
||||||
|
|
||||||
|
# Creating encrypted file
|
||||||
|
|
||||||
|
# Removing key from filesystem
|
||||||
|
Removed encryption key with identifier 69b2f6edeee720cce0577937eb8a6751
|
||||||
|
cat: SCRATCH_MNT/dir/file: No such file or directory
|
||||||
|
|
||||||
|
# Adding fscrypt-provisioning key
|
||||||
|
|
||||||
|
# Adding key to filesystem via fscrypt-provisioning key
|
||||||
|
Added encryption key with identifier 69b2f6edeee720cce0577937eb8a6751
|
||||||
|
|
||||||
|
# Reading encrypted file
|
||||||
|
contents
|
||||||
|
|
||||||
|
# Cleaning up
|
||||||
|
|
||||||
|
# ================
|
||||||
|
# Validation tests
|
||||||
|
# ================
|
||||||
|
|
||||||
|
# Adding an invalid fscrypt-provisioning key fails
|
||||||
|
# ... bad type
|
||||||
|
add_key: Invalid argument
|
||||||
|
# ... bad type
|
||||||
|
add_key: Invalid argument
|
||||||
|
# ... raw key too small
|
||||||
|
add_key: Invalid argument
|
||||||
|
# ... raw key too large
|
||||||
|
add_key: Invalid argument
|
||||||
|
|
||||||
|
# keyctl_read() doesn't work on fscrypt-provisioning keys
|
||||||
|
keyctl_read_alloc: Operation not supported
|
||||||
|
|
||||||
|
# Only keys with the correct fscrypt_provisioning_key_payload::type field can be added
|
||||||
|
# ... keyring key is v1, filesystem wants v2 key
|
||||||
|
Error adding encryption key: Key was rejected by service
|
||||||
|
# ... keyring key is v2, filesystem wants v1 key
|
||||||
|
Error adding encryption key: Key was rejected by service
|
||||||
|
|
||||||
|
# Only keys of type fscrypt-provisioning can be added
|
||||||
|
Error adding encryption key: Key was rejected by service
|
||||||
@@ -595,3 +595,4 @@
|
|||||||
590 auto prealloc preallocrw
|
590 auto prealloc preallocrw
|
||||||
591 auto quick rw pipe splice
|
591 auto quick rw pipe splice
|
||||||
592 auto quick encrypt
|
592 auto quick encrypt
|
||||||
|
593 auto quick encrypt
|
||||||
|
|||||||
Reference in New Issue
Block a user