diff options
Diffstat (limited to 'cli-tests')
31 files changed, 2049 insertions, 0 deletions
diff --git a/cli-tests/README.md b/cli-tests/README.md new file mode 100644 index 0000000..dfcc1d0 --- /dev/null +++ b/cli-tests/README.md @@ -0,0 +1,67 @@ +# fscrypt command-line interface tests + +## Usage + +To run the command-line interface (CLI) tests for `fscrypt`, ensure +that your kernel is v5.4 or later and has `CONFIG_FS_ENCRYPTION=y`. +Also ensure that you have the following packages installed: + +* e2fsprogs +* expect +* keyutils + +Then, run: + +```shell +make cli-test +``` + +You'll need to enter your `sudo` password, as the tests require root. + +If you only want to run specific tests, run a command like: + +```shell +make && sudo cli-tests/run.sh t_encrypt t_unlock +``` + +## Updating the expected output + +When the output of `fscrypt` has intentionally changed, the test +`.out` files need to be updated. This can be done automatically by +the following command, but be sure to review the changes: + +```shell +make cli-test-update +``` + +## Writing CLI tests + +The fscrypt CLI tests are `bash` scripts named like `t_*.sh`. + +The test scripts must be executable and begin by sourcing `common.sh`. +They all run in bash "extra-strict mode" (`-e -u -o pipefail`). They +run as root and have access to the following environment: + +* `$DEV`, `$DEV_ROOT`: ext4 filesystem images with encryption enabled + +* `$MNT`, `$MNT_ROOT`: the mountpoints of the above filesystems. + Initially all filesystems are mounted and are setup for fscrypt. + Login protectors will be stored on `$MNT_ROOT`. + +* `$TMPDIR`: a temporary directory that the test may use + +* `$FSCRYPT_CONF`: location of the fscrypt.conf file. Initially this + file exists and specifies to use v2 policies with the default + settings, except password hashing is configured to be extra fast. + +* `$TEST_USER`: a non-root user that the test may use. Their password + is `TEST_USER_PASS`. + +Any output (stdout and stderr) the test prints is compared to the +corresponding `.out` file. If a difference is detected then the test +is considered to have failed. The output is first sent through some +standard filters; see `run.sh`. + +The test is also failed if it exits with nonzero status. + +See `common.sh` for utility functions the tests may use. diff --git a/cli-tests/common.sh b/cli-tests/common.sh new file mode 100644 index 0000000..fcebfd6 --- /dev/null +++ b/cli-tests/common.sh @@ -0,0 +1,154 @@ +#!/bin/bash +# +# common.sh - helper functions for fscrypt command-line interface tests +# +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# + +# Use extra-strict mode. +set -e -u -o pipefail + +# Don't allow running the test scripts directly. They need to be run via +# run.sh, to set up everything correctly. +if [ -z "${MNT:-}" ] || [ -z "${MNT_ROOT:-}" ]; then + echo 1>&2 "ERROR: This script can only be run via run.sh, not on its own." + exit 1 +fi + +# Prints an error message, then fails the test by exiting with failure status. +_fail() +{ + [ $# -ne 1 ] && _fail "wrong argument count to ${FUNCNAME[0]}" + echo 1>&2 "ERROR: $1" + exit 1 +} + +# Runs a shell command and expects that it fails. +_expect_failure() +{ + [ $# -ne 1 ] && _fail "wrong argument count to ${FUNCNAME[0]}" + if eval "$1"; then + _fail "command unexpectedly succeeded: \"$1\"" + fi +} + +# Prints a message to mark the beginning of the next part of the test. +_print_header() +{ + [ $# -ne 1 ] && _fail "wrong argument count to ${FUNCNAME[0]}" + echo + echo "# $1" +} + +# Deletes all files on the test filesystems, including all policies and +# protectors. Leaves the fscrypt metadata directories themselves. +_reset_filesystems() +{ + local mnt + + [ $# -ne 0 ] && _fail "wrong argument count to ${FUNCNAME[0]}" + + for mnt in "$MNT" "$MNT_ROOT"; do + rm -rf "${mnt:?}"/* "${mnt:?}"/.fscrypt/{policies,protectors}/* + done +} + +# Prints the number of filesystems that have encryption support enabled. +_get_enabled_fs_count() +{ + local count + + [ $# -ne 0 ] && _fail "wrong argument count to ${FUNCNAME[0]}" + + count=$(fscrypt status | awk '/filesystems supporting encryption/ { print $4 }') + if [ -z "$count" ]; then + _fail "encryption support status line not found" + fi + echo "$count" +} + +# Prints the number of filesystems that have fscrypt metadata. +_get_setup_fs_count() +{ + local count + + [ $# -ne 0 ] && _fail "wrong argument count to ${FUNCNAME[0]}" + + count=$(fscrypt status | awk '/filesystems with fscrypt metadata/ { print $5 }') + if [ -z "$count" ]; then + _fail "fscrypt metadata status line not found" + fi + echo "$count" +} + +# Removes all fscrypt metadata from the given filesystem. +_rm_metadata() +{ + [ $# -ne 1 ] && _fail "wrong argument count to ${FUNCNAME[0]}" + + rm -r "${1:?}/.fscrypt" +} + +# Runs a shell command, ignoring its output (stdout and stderr) if it succeeds. +# If the command fails, prints its output and fails the test. +_run_noisy_command() +{ + [ $# -ne 1 ] && _fail "wrong argument count to ${FUNCNAME[0]}" + + if ! eval "$1" &> "$TMPDIR/out"; then + _fail "Command failed: '$1'. Output was: $(cat "$TMPDIR/out")" + fi +} + +# Runs the given shell command as the test user. +_user_do() +{ + [ $# -ne 1 ] && _fail "wrong argument count to ${FUNCNAME[0]}" + + su "$TEST_USER" --command="$1" +} + +# Runs the given shell command as the test user and expects it to fail. +_user_do_and_expect_failure() +{ + [ $# -ne 1 ] && _fail "wrong argument count to ${FUNCNAME[0]}" + + _expect_failure "_user_do '$1'" +} + +# Gives the test a new session keyring which contains the test user's keyring +# but not root's keyring. Also clears the test user's keyring. This must be +# called at the beginning of the test script as it may re-execute the script. +_setup_session_keyring() +{ + [ $# -ne 0 ] && _fail "wrong argument count to ${FUNCNAME[0]}" + + # This *should* just use 'keyctl new_session', but that doesn't work if + # the session keyring is owned by a user other than root. So instead we + # have to use 'keyctl session' and re-execute the script. + if [ -z "${FSCRYPT_SESSION_KEYRING_SET:-}" ]; then + export FSCRYPT_SESSION_KEYRING_SET=1 + set +e + keyctl session - "$0" |& grep -v '^Joined session keyring' + exit "${PIPESTATUS[0]}" + fi + + # Link the test user's keyring into the new session keyring. + keyctl setperm @s 0x3f000000 # all possessor permissions + _user_do "keyctl link @u @s" + + # Clear the test user's keyring. + _user_do "keyctl clear @u" +} diff --git a/cli-tests/run.sh b/cli-tests/run.sh new file mode 100755 index 0000000..909b645 --- /dev/null +++ b/cli-tests/run.sh @@ -0,0 +1,299 @@ +#!/bin/bash +# +# run.sh - run the fscrypt command-line interface tests +# +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# + +# Use extra-strict mode. +set -e -u -o pipefail + +# Ensure we're in the cli-tests/ directory. +cd "$(dirname "$0")" + +# Names of the test devices. +# Variables with these names are exported to the tests. +DEVICES=(DEV DEV_ROOT) + +# Names of the mountpoint of each test device. +# Variables with these names are exported to the tests. +MOUNTS=(MNT MNT_ROOT) + +# Name of the test user. This user will be created and deleted by this script. +# This variable is exported to the tests. +TEST_USER=fscrypt-test-user + +# The temporary directory to use. +# This variable is exported to the tests. +TMPDIR=$(mktemp -d /tmp/fscrypt.XXXXXX) + +# The loopback devices that correspond to each test device. +LOOPS=() + +# Update the expected output files to match the actual output? +UPDATE_OUTPUT=false + +LONGOPTS_ARRAY=( +'help' +'update-output' +) +LONGOPTS=$(echo "${LONGOPTS_ARRAY[*]}" | tr ' ' ,) + +cleanup() +{ + local mnt loop + + # Unmount all the test filesystems. + for mnt in "${MOUNTS[@]}"; do + mnt="$TMPDIR/$mnt" + if mountpoint "$mnt" &> /dev/null; then + umount "$mnt" + fi + done + + # Delete the loopback device of each test device. + for loop in "${LOOPS[@]}"; do + losetup -d "$loop" + done + + # Delete all temporary files. + rm -rf "${TMPDIR:?}"/* +} + +cleanup_full() +{ + cleanup + rm -rf "$TMPDIR" + userdel "$TEST_USER" || true +} + +# Filters the output of the test script to make the output consistent on every +# run of the test. For example, references to the mountpoint like +# /tmp/fscrypt.4OTb6y/MNT will be replaced with simply MNT, since the name of +# the temporary directory is different every time. +filter_test_output() +{ + local sedscript="" + local raw_output=$TMPDIR/raw-test-output + local i + + cat > "$raw_output" + + # Filter mountpoint and device names. + for i in "${!DEVICES[@]}"; do + sedscript+="s@$TMPDIR/${MOUNTS[$i]}@${MOUNTS[$i]}@g;" + sedscript+="s@${LOOPS[$i]}@${DEVICES[$i]}@g;" + done + + # Filter the path to fscrypt.conf. + sedscript+="s@$FSCRYPT_CONF@FSCRYPT_CONF@g;" + + # Filter policy and protector descriptors. + sedscript+=$(grep -E -o '\<([a-f0-9]{16})|([a-f0-9]{32})\>' \ + "$raw_output" \ + | awk '{ printf "s@\\<" $1 "\\>@desc" NR "@g;" }') + + # Filter any other paths in TMPDIR. + sedscript+="s@$TMPDIR@TMPDIR@g;" + + sed -e "$sedscript" "$raw_output" +} + +# Prepares to run a test script. +setup_for_test() +{ + local i dev_var mnt_var img mnt loop + + # Start with a clean state. + cleanup + + # ../bin/fscrypt might not be accessible to $TEST_USER. Copy it into + # $TMPDIR so that $TEST_USER is guaranteed to have access to it. + mkdir "$TMPDIR/bin" + cp ../bin/fscrypt "$TMPDIR/bin/" + chmod 755 "$TMPDIR" "$TMPDIR/bin" "$TMPDIR/bin/fscrypt" + + # Create the test filesystems and mountpoints. + LOOPS=() + for i in "${!DEVICES[@]}"; do + dev_var=${DEVICES[$i]} + mnt_var=${MOUNTS[$i]} + img="$TMPDIR/$dev_var" + if ! mkfs.ext4 -O encrypt -F -b 4096 -I 256 "$img" $((1<<15)) \ + &> "$TMPDIR/mkfs.out" + then + cat 1>&2 "$TMPDIR/mkfs.out" + exit 1 + fi + loop=$(losetup --find --show "$img") + LOOPS+=("$loop") + export "$dev_var=$loop" + mnt="$TMPDIR/$mnt_var" + export "$mnt_var=$mnt" + mkdir -p "$mnt" + mount "$loop" "$mnt" + done + + # Give the tests their own "root" mount for storing login protectors, so + # they don't use the real "/". + export FSCRYPT_ROOT_MNT="$MNT_ROOT" + + # Enable consistent output mode. + export FSCRYPT_CONSISTENT_OUTPUT="1" + + # Give the tests their own fscrypt.conf. + export FSCRYPT_CONF="$TMPDIR/fscrypt.conf" + fscrypt setup --time=1ms > /dev/null + + # The tests assume kernel support for v2 policies. + if ! grep -q '"policy_version": "2"' "$FSCRYPT_CONF"; then + cat 1>&2 << EOF +ERROR: Can't run these tests because your kernel doesn't support v2 policies. +You need kernel v5.4 or later. +EOF + exit 1 + fi + + # Set up the test filesystems that aren't already set up. + fscrypt setup "$MNT" > /dev/null +} + +run_test() +{ + local t=$1 + + # Run the test script. + set +e + "./$1.sh" |& filter_test_output > "$t.out.actual" + status=${PIPESTATUS[0]} + set -e + + # Check for failure status. + if [ "$status" != 0 ]; then + echo 1>&2 "FAILED: $t [exited with failure status $status]" + if [ -s "$t.out.actual" ]; then + if (( $(wc -l "$t.out.actual" | cut -f1 -d' ') > 10 )); then + echo 1>&2 "Last 10 lines of test output:" + tail -n10 "$t.out.actual" | sed 1>&2 's/^/ /' + echo 1>&2 + echo 1>&2 "See $t.out.actual for the full output." + else + echo 1>&2 "Test output:" + sed 1>&2 's/^/ /' < "$t.out.actual" + fi + fi + exit 1 + fi + + # Check for output mismatch. + if ! cmp "$t.out" "$t.out.actual" &> /dev/null; then + if $UPDATE_OUTPUT; then + cp "$t.out.actual" "$t.out" + echo "Updated $t.out" + else + echo 1>&2 "FAILED: $t [output mismatch]" + echo 1>&2 "Differences between $t.out and $t.out.actual:" + echo 1>&2 + diff 1>&2 "$t.out" "$t.out.actual" + exit 1 + fi + fi + rm -f "$t.out.actual" +} + +usage() +{ + cat << EOF +Usage: run.sh [--update-output] [TEST_SCRIPT_NAME]..." +EOF + exit 1 +} + +if ! options=$(getopt -o "" -l "$LONGOPTS" -- "$@"); then + usage +fi +eval set -- "$options" +while (( $# >= 1 )); do + case "$1" in + --update-output) + UPDATE_OUTPUT=true + ;; + --) + shift + break + ;; + --help|*) + usage + ;; + esac + shift +done + +if [ "$(id -u)" != 0 ]; then + echo 1>&2 "ERROR: You must be root to run these tests." + exit 1 +fi + +# Check for prerequisites. +PREREQ_CMDS=(mkfs.ext4 expect keyctl) +PREREQ_PKGS=(e2fsprogs expect keyutils) +for i in ${!PREREQ_CMDS[*]}; do + if ! type -P "${PREREQ_CMDS[$i]}" > /dev/null; then + cat 1>&2 << EOF +ERROR: You must install the '${PREREQ_PKGS[$i]}' package to run these tests. + Try a command like 'sudo apt-get install ${PREREQ_PKGS[$i]}'. +EOF + exit 1 + fi +done + +# Use a consistent umask. +umask 022 + +# Use a consistent locale, to prevent output mismatches. +export LANG=C +export LC_ALL=C + +# Always cleanup fully on exit. +trap cleanup_full EXIT + +# Create a test user, so that we can test non-root use of fscrypt. Give them a +# password, so that we can test creating login passphrase protected directories. +userdel "$TEST_USER" &> /dev/null || true +useradd "$TEST_USER" +echo "$TEST_USER:TEST_USER_PASS" | chpasswd +export TEST_USER + +# Let the tests use $TMPDIR if they need it. +export TMPDIR + +# Make it so that running 'fscrypt' in the tests runs the correct binary. +export PATH="$TMPDIR/bin:$PATH" + +if (( $# >= 1 )); then + # Tests specified on command line. + tests=("$@") +else + # No tests specified on command line. Just run everything. + tests=(t_*.sh) +fi +for t in "${tests[@]}"; do + t=${t%.sh} + echo "Running $t" + setup_for_test + run_test "$t" +done + +echo "All tests passed!" diff --git a/cli-tests/t_change_passphrase.out b/cli-tests/t_change_passphrase.out new file mode 100644 index 0000000..747ed89 --- /dev/null +++ b/cli-tests/t_change_passphrase.out @@ -0,0 +1,32 @@ + +# Create encrypted directory + +# Try to unlock with wrong passphrase +[ERROR] fscrypt unlock: incorrect key provided +mkdir: cannot create directory 'MNT/dir/subdir': Required key not available + +# Change passphrase + +# Try to unlock with old passphrase +[ERROR] fscrypt unlock: incorrect key provided +mkdir: cannot create directory 'MNT/dir/subdir': Required key not available + +# Unlock with new passphrase + +# Try to change passphrase (interactively, mismatch) +spawn fscrypt metadata change-passphrase --protector=MNT:desc1
+Enter old custom passphrase for protector "prot":
+Enter new custom passphrase for protector "prot":
+Confirm passphrase:
+[ERROR] fscrypt metadata change-passphrase: entered passphrases do not match
+ +# Change passphrase (interactively) +spawn fscrypt metadata change-passphrase --protector=MNT:desc1
+Enter old custom passphrase for protector "prot":
+Enter new custom passphrase for protector "prot":
+Confirm passphrase:
+Passphrase for protector desc1 successfully changed.
+ +# Lock, then unlock with new passphrase +"MNT/dir" is now locked. +mkdir: cannot create directory 'MNT/dir/subdir': Required key not available diff --git a/cli-tests/t_change_passphrase.sh b/cli-tests/t_change_passphrase.sh new file mode 100755 index 0000000..204512d --- /dev/null +++ b/cli-tests/t_change_passphrase.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +# Test changing the passphrase of a custom_passphrase protector. + +cd "$(dirname "$0")" +. common.sh + +dir="$MNT/dir" + +_print_header "Create encrypted directory" +mkdir "$dir" +echo pass1 | fscrypt encrypt --quiet --name=prot --skip-unlock "$dir" + +_print_header "Try to unlock with wrong passphrase" +_expect_failure "echo pass2 | fscrypt unlock --quiet '$dir'" +_expect_failure "mkdir '$dir/subdir'" +protector=$(fscrypt status "$dir" | awk '/custom protector/{print $1}') + +_print_header "Change passphrase" +echo $'pass1\npass2' | \ + fscrypt metadata change-passphrase --protector="$MNT:$protector" --quiet + +_print_header "Try to unlock with old passphrase" +_expect_failure "echo pass1 | fscrypt unlock --quiet '$dir'" +_expect_failure "mkdir '$dir/subdir'" + +_print_header "Unlock with new passphrase" +echo pass2 | fscrypt unlock --quiet "$dir" +mkdir "$dir/subdir" +rmdir "$dir/subdir" + +_print_header "Try to change passphrase (interactively, mismatch)" +expect << EOF +spawn fscrypt metadata change-passphrase --protector=$MNT:$protector +expect "Enter old custom passphrase" +send "pass2\r" +expect "Enter new custom passphrase" +send "pass3\r" +expect "Confirm passphrase" +send "bad\r" +expect eof +EOF + +_print_header "Change passphrase (interactively)" +expect << EOF +spawn fscrypt metadata change-passphrase --protector=$MNT:$protector +expect "Enter old custom passphrase" +send "pass2\r" +expect "Enter new custom passphrase" +send "pass3\r" +expect "Confirm passphrase" +send "pass3\r" +expect eof +EOF + +_print_header "Lock, then unlock with new passphrase" +fscrypt lock "$dir" +_expect_failure "mkdir '$dir/subdir'" +echo pass3 | fscrypt unlock --quiet "$dir" +mkdir "$dir/subdir" diff --git a/cli-tests/t_encrypt.out b/cli-tests/t_encrypt.out new file mode 100644 index 0000000..af38299 --- /dev/null +++ b/cli-tests/t_encrypt.out @@ -0,0 +1,67 @@ + +# Try to encrypt a nonexistent directory +[ERROR] fscrypt encrypt: no such file or directory +ext4 filesystem "MNT" has 0 protectors and 0 policies + +[ERROR] fscrypt status: get encryption policy MNT/dir: file + or directory not encrypted + +# Try to encrypt a nonempty directory +[ERROR] fscrypt encrypt: MNT/dir: not an empty directory + +Encryption can only be setup on empty directories; files cannot be encrypted +in-place. Instead, encrypt an empty directory, copy the files into that +encrypted directory, and securely delete the originals with "shred". +ext4 filesystem "MNT" has 0 protectors and 0 policies + +[ERROR] fscrypt status: get encryption policy MNT/dir: file + or directory not encrypted + +# Encrypt a directory as non-root user +ext4 filesystem "MNT" has 1 protector and 1 policy + +PROTECTOR LINKED DESCRIPTION +desc1 No custom protector "prot" + +POLICY UNLOCKED PROTECTORS +desc2 Yes desc1 +"MNT/dir" is encrypted with fscrypt. + +Policy: desc2 +Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:2 +Unlocked: Yes + +Protected with 1 protector: +PROTECTOR LINKED DESCRIPTION +desc1 No custom protector "prot" +ext4 filesystem "MNT" has 1 protector and 1 policy + +PROTECTOR LINKED DESCRIPTION +desc1 No custom protector "prot" + +POLICY UNLOCKED PROTECTORS +desc2 Yes desc1 +"MNT/dir" is encrypted with fscrypt. + +Policy: desc2 +Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:2 +Unlocked: Yes + +Protected with 1 protector: +PROTECTOR LINKED DESCRIPTION +desc1 No custom protector "prot" + +# Try to encrypt an already-encrypted directory +[ERROR] fscrypt encrypt: MNT/dir: file or directory already + encrypted + +# Try to encrypt another user's directory as a non-root user +[ERROR] fscrypt encrypt: MNT/dir: you do not own this + directory + +Encryption can only be setup on directories you own, even if you have write +permission for the directory. +ext4 filesystem "MNT" has 0 protectors and 0 policies + +[ERROR] fscrypt status: get encryption policy MNT/dir: file + or directory not encrypted diff --git a/cli-tests/t_encrypt.sh b/cli-tests/t_encrypt.sh new file mode 100755 index 0000000..9f19f5d --- /dev/null +++ b/cli-tests/t_encrypt.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +# General tests for 'fscrypt encrypt'. For protector-specific tests, see +# t_encrypt_custom, t_encrypt_login, and t_encrypt_raw_key. + +cd "$(dirname "$0")" +. common.sh + +dir="$MNT/dir" + +begin() +{ + _reset_filesystems + mkdir "$dir" + _print_header "$@" +} + +show_status() +{ + local encrypted=$1 + + fscrypt status "$MNT" + if $encrypted; then + fscrypt status "$dir" + else + _expect_failure "fscrypt status '$dir'" + fi +} + +begin "Try to encrypt a nonexistent directory" +_expect_failure "echo hunter2 | fscrypt encrypt --quiet '$MNT/nonexistent'" +show_status false + +begin "Try to encrypt a nonempty directory" +touch "$dir/file" +_expect_failure "echo hunter2 | fscrypt encrypt --quiet '$dir'" +show_status false + +begin "Encrypt a directory as non-root user" +chown "$TEST_USER" "$dir" +_user_do "echo hunter2 | fscrypt encrypt --quiet --name=prot '$dir'" +show_status true +_user_do "fscrypt status '$MNT'" +_user_do "fscrypt status '$dir'" + +_print_header "Try to encrypt an already-encrypted directory" +_user_do_and_expect_failure "echo hunter2 | fscrypt encrypt --quiet --name=prot '$dir'" + +begin "Try to encrypt another user's directory as a non-root user" +_user_do_and_expect_failure "echo hunter2 | fscrypt encrypt --quiet --name=prot '$dir'" +show_status false diff --git a/cli-tests/t_encrypt_custom.out b/cli-tests/t_encrypt_custom.out new file mode 100644 index 0000000..572529a --- /dev/null +++ b/cli-tests/t_encrypt_custom.out @@ -0,0 +1,55 @@ + +# Encrypt with custom passphrase protector +ext4 filesystem "MNT" has 1 protector and 1 policy + +PROTECTOR LINKED DESCRIPTION +desc1 No custom protector "prot" + +POLICY UNLOCKED PROTECTORS +desc2 Yes desc1 +"MNT/dir" is encrypted with fscrypt. + +Policy: desc2 +Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:2 +Unlocked: Yes + +Protected with 1 protector: +PROTECTOR LINKED DESCRIPTION +desc1 No custom protector "prot" + +# Encrypt with custom passphrase protector, interactively +spawn fscrypt encrypt MNT/dir
+The following protector sources are available:
+1 - Your login passphrase (pam_passphrase)
+2 - A custom passphrase (custom_passphrase)
+3 - A raw 256-bit key (raw_key)
+Enter the source number for the new protector [2 - custom_passphrase]: 2
+Enter a name for the new protector: prot
+Enter custom passphrase for protector "prot":
+Confirm passphrase:
+"MNT/dir" is now encrypted, unlocked, and ready for use.
+ext4 filesystem "MNT" has 1 protector and 1 policy + +PROTECTOR LINKED DESCRIPTION +desc6 No custom protector "prot" + +POLICY UNLOCKED PROTECTORS +desc7 Yes desc6 +"MNT/dir" is encrypted with fscrypt. + +Policy: desc7 +Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:2 +Unlocked: Yes + +Protected with 1 protector: +PROTECTOR LINKED DESCRIPTION +desc6 No custom protector "prot" + +# Try to use a custom protector without a name +[ERROR] fscrypt encrypt: custom protectors must have a name + +Use --name=PROTECTOR_NAME to specify a protector name. +ext4 filesystem "MNT" has 0 protectors and 0 policies + +[ERROR] fscrypt status: get encryption policy MNT/dir: file + or directory not encrypted diff --git a/cli-tests/t_encrypt_custom.sh b/cli-tests/t_encrypt_custom.sh new file mode 100755 index 0000000..48cbe25 --- /dev/null +++ b/cli-tests/t_encrypt_custom.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +# Test encrypting a directory using a custom_passphrase protector. + +cd "$(dirname "$0")" +. common.sh + +dir="$MNT/dir" + +begin() +{ + _reset_filesystems + mkdir "$dir" + _print_header "$1" +} + +show_status() +{ + local encrypted=$1 + + fscrypt status "$MNT" + if $encrypted; then + fscrypt status "$dir" + else + _expect_failure "fscrypt status '$dir'" + fi +} + +begin "Encrypt with custom passphrase protector" +echo hunter2 | fscrypt encrypt --quiet --name=prot "$dir" +show_status true + +begin "Encrypt with custom passphrase protector, interactively" +expect << EOF +spawn fscrypt encrypt "$dir" +expect "Enter the source number for the new protector" +send "2\r" +expect "Enter a name for the new protector:" +send "prot\r" +expect "Enter custom passphrase" +send "hunter2\r" +expect "Confirm passphrase" +send "hunter2\r" +expect eof +EOF +show_status true + +begin "Try to use a custom protector without a name" +_expect_failure "echo hunter2 | fscrypt encrypt --quiet '$dir'" +show_status false diff --git a/cli-tests/t_encrypt_login.out b/cli-tests/t_encrypt_login.out new file mode 100644 index 0000000..c6eb463 --- /dev/null +++ b/cli-tests/t_encrypt_login.out @@ -0,0 +1,148 @@ + +# Encrypt with login protector +See "MNT/dir/fscrypt_recovery_readme.txt" for important recovery instructions! +ext4 filesystem "MNT" has 2 protectors and 1 policy + +PROTECTOR LINKED DESCRIPTION +desc1 Yes (MNT_ROOT) login protector for fscrypt-test-user +desc2 No custom protector "Recovery passphrase for dir" + +POLICY UNLOCKED PROTECTORS +desc3 Yes desc1, desc2 +ext4 filesystem "MNT_ROOT" has 1 protector and 0 policies + +PROTECTOR LINKED DESCRIPTION +desc1 No login protector for fscrypt-test-user +"MNT/dir" is encrypted with fscrypt. + +Policy: desc3 +Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:2 +Unlocked: Yes + +Protected with 2 protectors: +PROTECTOR LINKED DESCRIPTION +desc1 Yes (MNT_ROOT) login protector for fscrypt-test-user +desc2 No custom protector "Recovery passphrase for dir" + +# => Lock, then unlock with login passphrase +"MNT/dir" is now locked. + +# => Lock, then unlock with recovery passphrase +"MNT/dir" is now locked. + +# Encrypt with login protector, interactively +spawn fscrypt encrypt MNT/dir
+The following protector sources are available:
+1 - Your login passphrase (pam_passphrase)
+2 - A custom passphrase (custom_passphrase)
+3 - A raw 256-bit key (raw_key)
+Enter the source number for the new protector [2 - custom_passphrase]: 1
+Enter login passphrase for fscrypt-test-user:
+Protector is on a different filesystem! Generate a recovery passphrase (recommended)? [Y/n] y
+See "MNT/dir/fscrypt_recovery_readme.txt" for important recovery instructions!
+"MNT/dir" is now encrypted, unlocked, and ready for use.
+ext4 filesystem "MNT" has 2 protectors and 1 policy + +PROTECTOR LINKED DESCRIPTION +desc10 Yes (MNT_ROOT) login protector for fscrypt-test-user +desc11 No custom protector "Recovery passphrase for dir" + +POLICY UNLOCKED PROTECTORS +desc12 Yes desc10, desc11 +ext4 filesystem "MNT_ROOT" has 1 protector and 0 policies + +PROTECTOR LINKED DESCRIPTION +desc10 No login protector for fscrypt-test-user +"MNT/dir" is encrypted with fscrypt. + +Policy: desc12 +Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:2 +Unlocked: Yes + +Protected with 2 protectors: +PROTECTOR LINKED DESCRIPTION +desc10 Yes (MNT_ROOT) login protector for fscrypt-test-user +desc11 No custom protector "Recovery passphrase for dir" + +# Encrypt with login protector as root +See "MNT/dir/fscrypt_recovery_readme.txt" for important recovery instructions! +ext4 filesystem "MNT" has 2 protectors and 1 policy + +PROTECTOR LINKED DESCRIPTION +desc19 Yes (MNT_ROOT) login protector for fscrypt-test-user +desc20 No custom protector "Recovery passphrase for dir" + +POLICY UNLOCKED PROTECTORS +desc21 Yes desc19, desc20 +ext4 filesystem "MNT_ROOT" has 1 protector and 0 policies + +PROTECTOR LINKED DESCRIPTION +desc19 No login protector for fscrypt-test-user +"MNT/dir" is encrypted with fscrypt. + +Policy: desc21 +Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:2 +Unlocked: Yes + +Protected with 2 protectors: +PROTECTOR LINKED DESCRIPTION +desc19 Yes (MNT_ROOT) login protector for fscrypt-test-user +desc20 No custom protector "Recovery passphrase for dir" + +# Encrypt with login protector with --no-recovery +ext4 filesystem "MNT" has 1 protector and 1 policy + +PROTECTOR LINKED DESCRIPTION +desc28 Yes (MNT_ROOT) login protector for fscrypt-test-user + +POLICY UNLOCKED PROTECTORS +desc29 Yes desc28 +ext4 filesystem "MNT_ROOT" has 1 protector and 0 policies + +PROTECTOR LINKED DESCRIPTION +desc28 No login protector for fscrypt-test-user +"MNT/dir" is encrypted with fscrypt. + +Policy: desc29 +Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:2 +Unlocked: Yes + +Protected with 1 protector: +PROTECTOR LINKED DESCRIPTION +desc28 Yes (MNT_ROOT) login protector for fscrypt-test-user + +# Encrypt with login protector on root fs (shouldn't generate a recovery passphrase) +"MNT_ROOT/dir" is encrypted with fscrypt. + +Policy: desc34 +Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:2 +Unlocked: Yes + +Protected with 1 protector: +PROTECTOR LINKED DESCRIPTION +desc35 No login protector for fscrypt-test-user +ext4 filesystem "MNT_ROOT" has 1 protector and 1 policy + +PROTECTOR LINKED DESCRIPTION +desc35 No login protector for fscrypt-test-user + +POLICY UNLOCKED PROTECTORS +desc34 Yes desc35 + +# Try to give a login protector a name +[ERROR] fscrypt encrypt: login protectors do not need a name +ext4 filesystem "MNT" has 0 protectors and 0 policies + +ext4 filesystem "MNT_ROOT" has 0 protectors and 0 policies + +[ERROR] fscrypt status: get encryption policy MNT/dir: file + or directory not encrypted + +# Try to use the wrong login passphrase +[ERROR] fscrypt encrypt: incorrect login passphrase +ext4 filesystem "MNT" has 0 protectors and 0 policies + +ext4 filesystem "MNT_ROOT" has 0 protectors and 0 policies + +[ERROR] fscrypt status: get encryption policy MNT/dir: file + or directory not encrypted diff --git a/cli-tests/t_encrypt_login.sh b/cli-tests/t_encrypt_login.sh new file mode 100755 index 0000000..11a62f1 --- /dev/null +++ b/cli-tests/t_encrypt_login.sh @@ -0,0 +1,86 @@ +#!/bin/bash + +# Test encrypting a directory using a login (pam_passphrase) protector. + +cd "$(dirname "$0")" +. common.sh + +dir="$MNT/dir" + +begin() +{ + _reset_filesystems + mkdir "$dir" + _print_header "$1" +} + +show_status() +{ + local encrypted=$1 + + fscrypt status "$MNT" + fscrypt status "$MNT_ROOT" + if $encrypted; then + fscrypt status "$dir" + else + _expect_failure "fscrypt status '$dir'" + fi +} + +begin "Encrypt with login protector" +chown "$TEST_USER" "$dir" +_user_do "echo TEST_USER_PASS | fscrypt encrypt --quiet --source=pam_passphrase '$dir'" +show_status true +recovery_passphrase=$(grep -E '^ +[a-z]{20}$' "$dir/fscrypt_recovery_readme.txt" | sed 's/^ +//') +recovery_protector=$(fscrypt status "$dir" | awk '/Recovery passphrase/{print $1}') +login_protector=$(fscrypt status "$dir" | awk '/login protector/{print $1}') +_print_header "=> Lock, then unlock with login passphrase" +_user_do "fscrypt lock '$dir'" +# FIXME: should we be able to use $MNT:$login_protector here? +_user_do "echo TEST_USER_PASS | fscrypt unlock --quiet --unlock-with=$MNT_ROOT:$login_protector '$dir'" +_print_header "=> Lock, then unlock with recovery passphrase" +_user_do "fscrypt lock '$dir'" +_user_do "echo $recovery_passphrase | fscrypt unlock --quiet --unlock-with=$MNT:$recovery_protector '$dir'" + +begin "Encrypt with login protector, interactively" +chown "$TEST_USER" "$dir" +_user_do expect << EOF +spawn fscrypt encrypt "$dir" +expect "Enter the source number for the new protector" +send "1\r" +expect "Enter login passphrase" +send "TEST_USER_PASS\r" +expect "Protector is on a different filesystem! Generate a recovery passphrase (recommended)?" +send "y\r" +expect eof +EOF +show_status true + +begin "Encrypt with login protector as root" +echo TEST_USER_PASS | fscrypt encrypt --quiet --source=pam_passphrase --user="$TEST_USER" "$dir" +show_status true + +begin "Encrypt with login protector with --no-recovery" +chown "$TEST_USER" "$dir" +_user_do "echo TEST_USER_PASS | fscrypt encrypt --quiet --source=pam_passphrase --no-recovery '$dir'" +show_status true + +begin "Encrypt with login protector on root fs (shouldn't generate a recovery passphrase)" +mkdir "$MNT_ROOT/dir" +chown "$TEST_USER" "$MNT_ROOT/dir" +_user_do "echo TEST_USER_PASS | fscrypt encrypt --quiet --source=pam_passphrase --no-recovery '$MNT_ROOT/dir'" +fscrypt status "$MNT_ROOT/dir" +fscrypt status "$MNT_ROOT" +rmdir "$MNT_ROOT/dir" + +begin "Try to give a login protector a name" +chown "$TEST_USER" "$dir" +_user_do_and_expect_failure \ + "echo TEST_USER_PASS | fscrypt encrypt --quiet --source=pam_passphrase --name=prot '$dir'" +show_status false + +begin "Try to use the wrong login passphrase" +chown "$TEST_USER" "$dir" +_user_do_and_expect_failure \ + "echo wrong_passphrase | fscrypt encrypt --quiet --source=pam_passphrase '$dir'" +show_status false diff --git a/cli-tests/t_encrypt_raw_key.out b/cli-tests/t_encrypt_raw_key.out new file mode 100644 index 0000000..c7c46eb --- /dev/null +++ b/cli-tests/t_encrypt_raw_key.out @@ -0,0 +1,25 @@ + +# Encrypt with raw_key protector +ext4 filesystem "MNT" has 1 protector and 1 policy + +PROTECTOR LINKED DESCRIPTION +desc1 No raw key protector "prot" + +POLICY UNLOCKED PROTECTORS +desc2 Yes desc1 +"MNT/dir" is encrypted with fscrypt. + +Policy: desc2 +Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:2 +Unlocked: Yes + +Protected with 1 protector: +PROTECTOR LINKED DESCRIPTION +desc1 No raw key protector "prot" + +# Try to encrypt with raw_key protector, using wrong key length +[ERROR] fscrypt encrypt: TMPDIR/raw_key: key file must be 32 bytes +ext4 filesystem "MNT" has 0 protectors and 0 policies + +[ERROR] fscrypt status: get encryption policy MNT/dir: file + or directory not encrypted diff --git a/cli-tests/t_encrypt_raw_key.sh b/cli-tests/t_encrypt_raw_key.sh new file mode 100755 index 0000000..260b094 --- /dev/null +++ b/cli-tests/t_encrypt_raw_key.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +# Test encrypting a directory using a raw_key protector. + +cd "$(dirname "$0")" +. common.sh + +dir="$MNT/dir" +raw_key_file="$TMPDIR/raw_key" + +begin() +{ + _reset_filesystems + mkdir "$dir" + _print_header "$1" +} + +show_status() +{ + local encrypted=$1 + + fscrypt status "$MNT" + if $encrypted; then + fscrypt status "$dir" + else + _expect_failure "fscrypt status '$dir'" + fi +} + +begin "Encrypt with raw_key protector" +head -c 32 /dev/urandom > "$raw_key_file" +fscrypt encrypt --quiet --name=prot --source=raw_key --key="$raw_key_file" "$dir" +show_status true + +begin "Try to encrypt with raw_key protector, using wrong key length" +head -c 16 /dev/urandom > "$raw_key_file" +_expect_failure "fscrypt encrypt --quiet --name=prot --source=raw_key --key='$raw_key_file' '$dir'" +show_status false diff --git a/cli-tests/t_lock.out b/cli-tests/t_lock.out new file mode 100644 index 0000000..c0f9279 --- /dev/null +++ b/cli-tests/t_lock.out @@ -0,0 +1,82 @@ + +# Encrypt directory +"MNT/dir" is encrypted with fscrypt. + +Policy: desc1 +Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:2 +Unlocked: Yes + +Protected with 1 protector: +PROTECTOR LINKED DESCRIPTION +desc2 No custom protector "prot" + +# Lock directory +"MNT/dir" is now locked. + +# => filenames should be in encrypted form +cat: MNT/dir/file: No such file or directory + +# => shouldn't be able to create a subdirectory +mkdir: cannot create directory 'MNT/dir/subdir': Required key not available + +# Unlock directory +Enter custom passphrase for protector "prot": "MNT/dir" is now unlocked and ready for use. +"MNT/dir" is encrypted with fscrypt. + +Policy: desc1 +Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:2 +Unlocked: Yes + +Protected with 1 protector: +PROTECTOR LINKED DESCRIPTION +desc2 No custom protector "prot" +contents + +# Try to lock directory while files busy +[ERROR] fscrypt lock: some files using the key are still open + +Directory was incompletely locked because some files are still open. These files +remain accessible. Try killing any processes using files in the directory, then +re-running 'fscrypt lock'. + +# => status should be incompletely locked +"MNT/dir" is encrypted with fscrypt. + +Policy: desc1 +Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:2 +Unlocked: Partially (incompletely locked) + +Protected with 1 protector: +PROTECTOR LINKED DESCRIPTION +desc2 No custom protector "prot" + +# => open file should still be readable +contents + +# => shouldn't be able to create a new file +bash: MNT/dir/file2: Required key not available + +# Finish locking directory +"MNT/dir" is now locked. +"MNT/dir" is encrypted with fscrypt. + +Policy: desc1 +Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:2 +Unlocked: No + +Protected with 1 protector: +PROTECTOR LINKED DESCRIPTION +desc2 No custom protector "prot" +cat: MNT/dir/file: No such file or directory +mkdir: cannot create directory 'MNT/dir/subdir': Required key not available + +# Try to lock directory while other user has unlocked +Enter custom passphrase for protector "prot": "MNT/dir" is now unlocked and ready for use. +[ERROR] fscrypt lock: other users have added the key too + +Directory couldn't be fully locked because other user(s) have unlocked it. If +you want to force the directory to be locked, use 'sudo fscrypt lock --all-users +DIR'. +contents +"MNT/dir" is now locked. +cat: MNT/dir/file: No such file or directory diff --git a/cli-tests/t_lock.sh b/cli-tests/t_lock.sh new file mode 100755 index 0000000..7ac1727 --- /dev/null +++ b/cli-tests/t_lock.sh @@ -0,0 +1,51 @@ +#!/bin/bash + +# Test locking a directory. + +cd "$(dirname "$0")" +. common.sh + +dir="$MNT/dir" +mkdir "$dir" + +_print_header "Encrypt directory" +echo hunter2 | fscrypt encrypt --quiet --name=prot "$dir" +fscrypt status "$dir" +echo contents > "$dir/file" + +_print_header "Lock directory" +fscrypt lock "$dir" +_print_header "=> filenames should be in encrypted form" +_expect_failure "cat '$dir/file'" +_print_header "=> shouldn't be able to create a subdirectory" +_expect_failure "mkdir '$dir/subdir'" + +_print_header "Unlock directory" +echo hunter2 | fscrypt unlock "$dir" +fscrypt status "$dir" +cat "$dir/file" + +_print_header "Try to lock directory while files busy" +exec 3<"$dir/file" +_expect_failure "fscrypt lock '$dir'" +_print_header "=> status should be incompletely locked" +fscrypt status "$dir" +_print_header "=> open file should still be readable" +cat "$dir/file" +_print_header "=> shouldn't be able to create a new file" +_expect_failure "bash -c \"echo contents > '$dir/file2'\"" + +_print_header "Finish locking directory" +exec 3<&- +fscrypt lock "$dir" +fscrypt status "$dir" +_expect_failure "cat '$dir/file'" +_expect_failure "mkdir '$dir/subdir'" + +_print_header "Try to lock directory while other user has unlocked" +chown "$TEST_USER" "$dir" +_user_do "echo hunter2 | fscrypt unlock '$dir'" +_expect_failure "fscrypt lock '$dir'" +cat "$dir/file" +fscrypt lock --all-users "$dir" +_expect_failure "cat '$dir/file'" diff --git a/cli-tests/t_not_enabled.out b/cli-tests/t_not_enabled.out new file mode 100644 index 0000000..7d74bcf --- /dev/null +++ b/cli-tests/t_not_enabled.out @@ -0,0 +1,39 @@ + +# Disable encryption on DEV + +# Try to encrypt a directory when encryption is disabled +[ERROR] fscrypt encrypt: get encryption policy MNT/dir: + encryption not enabled + +Encryption is either disabled in the kernel config, or needs to be enabled for +this filesystem. See the documentation on how to enable encryption on ext4 +systems (and the risks of doing so). + +# Try to unlock a directory when encryption is disabled +[ERROR] fscrypt unlock: get encryption policy MNT/dir: + encryption not enabled + +Encryption is either disabled in the kernel config, or needs to be enabled for +this filesystem. See the documentation on how to enable encryption on ext4 +systems (and the risks of doing so). + +# Try to lock a directory when encryption is disabled +[ERROR] fscrypt lock: get encryption policy MNT/dir: + encryption not enabled + +Encryption is either disabled in the kernel config, or needs to be enabled for +this filesystem. See the documentation on how to enable encryption on ext4 +systems (and the risks of doing so). + +# Enable encryption on DEV + +# Encrypt a directory when encryption was just enabled +"MNT/dir" is encrypted with fscrypt. + +Policy: desc1 +Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:2 +Unlocked: Yes + +Protected with 1 protector: +PROTECTOR LINKED DESCRIPTION +desc2 No custom protector "prot" diff --git a/cli-tests/t_not_enabled.sh b/cli-tests/t_not_enabled.sh new file mode 100755 index 0000000..3c7d22c --- /dev/null +++ b/cli-tests/t_not_enabled.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +# Test that fscrypt fails when the filesystem doesn't have the encrypt feature +# enabled. Then test enabling it. + +cd "$(dirname "$0")" +. common.sh + +dir="$MNT/dir" +mkdir "$dir" + +_print_header "Disable encryption on $DEV" +count_before=$(_get_enabled_fs_count) +umount "$MNT" +_run_noisy_command "debugfs -w -R 'feature -encrypt' '$DEV'" +mount "$DEV" "$MNT" +count_after=$(_get_enabled_fs_count) +(( count_after == count_before - 1 )) || _fail "wrong enabled count" + +_print_header "Try to encrypt a directory when encryption is disabled" +_expect_failure "fscrypt encrypt '$dir'" + +_print_header "Try to unlock a directory when encryption is disabled" +_expect_failure "fscrypt unlock '$dir'" + +_print_header "Try to lock a directory when encryption is disabled" +_expect_failure "fscrypt lock '$dir'" + +_print_header "Enable encryption on $DEV" +_run_noisy_command "tune2fs -O encrypt '$DEV'" + +_print_header "Encrypt a directory when encryption was just enabled" +echo hunter2 | fscrypt encrypt --quiet --source=custom_passphrase --name=prot "$dir" +fscrypt status "$dir" diff --git a/cli-tests/t_not_supported.out b/cli-tests/t_not_supported.out new file mode 100644 index 0000000..8af840c --- /dev/null +++ b/cli-tests/t_not_supported.out @@ -0,0 +1,11 @@ + +# Mount tmpfs + +# Create fscrypt metadata on tmpfs +Metadata directories created at "MNT/.fscrypt". + +# Try to encrypt a directory on tmpfs +[ERROR] fscrypt encrypt: get encryption policy MNT/dir: + encryption not supported + +Encryption for this type of filesystem is not supported on this kernel version. diff --git a/cli-tests/t_not_supported.sh b/cli-tests/t_not_supported.sh new file mode 100755 index 0000000..53a096a --- /dev/null +++ b/cli-tests/t_not_supported.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +# Test that fscrypt fails when the filesystem doesn't support encryption. + +cd "$(dirname "$0")" +. common.sh + +_print_header "Mount tmpfs" +umount "$MNT" +mount tmpfs -t tmpfs -o size=128m "$MNT" + +_print_header "Create fscrypt metadata on tmpfs" +fscrypt setup "$MNT" + +_print_header "Try to encrypt a directory on tmpfs" +mkdir "$MNT/dir" +_expect_failure "fscrypt encrypt '$MNT/dir'" diff --git a/cli-tests/t_passphrase_hashing.out b/cli-tests/t_passphrase_hashing.out new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/cli-tests/t_passphrase_hashing.out diff --git a/cli-tests/t_passphrase_hashing.sh b/cli-tests/t_passphrase_hashing.sh new file mode 100755 index 0000000..a67dd7c --- /dev/null +++ b/cli-tests/t_passphrase_hashing.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +# Test that the passphrase hashing seems to take long enough. + +cd "$(dirname "$0")" +. common.sh + +dir="$MNT/dir" + +# Test encrypting 5 dirs with default of 1s. +fscrypt setup --force --quiet +start_time=$(date +%s) +for i in $(seq 5); do + rm -rf "$dir" + mkdir "$dir" + echo hunter2 | fscrypt encrypt --quiet --name="prot$i" "$dir" +done +end_time=$(date +%s) +elapsed=$((end_time - start_time)) +if (( elapsed <= 3 )); then + _fail "Passphrase hashing was much faster than expected! (expected about 5 x 1 == 5s, got ${elapsed}s)" +fi + +# Test encrypting 1 dir with difficulty overridden to 5s. +fscrypt setup --force --quiet --time=5s +start_time=$(date +%s) +rm -rf "$dir" +mkdir "$dir" +echo hunter2 | fscrypt encrypt --quiet --name=prot6 "$dir" +end_time=$(date +%s) +elapsed=$((end_time - start_time)) +if (( elapsed <= 3 )); then + _fail "Passphrase hashing was much faster than expected! (expected about 5s, got ${elapsed}s)" +fi diff --git a/cli-tests/t_setup.out b/cli-tests/t_setup.out new file mode 100644 index 0000000..e1606ba --- /dev/null +++ b/cli-tests/t_setup.out @@ -0,0 +1,49 @@ + +# fscrypt setup creates fscrypt.conf +Defaulting to policy_version 2 because kernel supports it. +Customizing passphrase hashing difficulty for this system... +Created global config file at "FSCRYPT_CONF". +Skipping creating MNT_ROOT/.fscrypt because it already exists. + +# fscrypt setup creates fscrypt.conf and /.fscrypt +Defaulting to policy_version 2 because kernel supports it. +Customizing passphrase hashing difficulty for this system... +Created global config file at "FSCRYPT_CONF". +Metadata directories created at "MNT_ROOT/.fscrypt". + +# fscrypt setup when fscrypt.conf already exists (cancel) +Replace "FSCRYPT_CONF"? [y/N] [ERROR] fscrypt setup: operation canceled + +# fscrypt setup when fscrypt.conf already exists (cancel 2) +Replace "FSCRYPT_CONF"? [y/N] [ERROR] fscrypt setup: operation canceled + +# fscrypt setup when fscrypt.conf already exists (accept) +Replace "FSCRYPT_CONF"? [y/N] Defaulting to policy_version 2 because kernel supports it. +Customizing passphrase hashing difficulty for this system... +Created global config file at "FSCRYPT_CONF". +Skipping creating MNT_ROOT/.fscrypt because it already exists. + +# fscrypt setup --quiet when fscrypt.conf already exists +[ERROR] fscrypt setup: operation would be destructive + +Use --force to automatically run destructive operations. + +# fscrypt setup --quiet --force when fscrypt.conf already exists + +# fscrypt setup filesystem +Metadata directories created at "MNT/.fscrypt". + +# fscrypt setup filesystem (already set up) +[ERROR] fscrypt setup: filesystem MNT: already setup for use + with fscrypt + +# no config file +[ERROR] fscrypt setup: global config file does not exist + +Run "sudo fscrypt setup" to create the file. + +# bad config file +[ERROR] fscrypt setup: invalid character 'b' looking for beginning of value: + global config file has invalid data + +Run "sudo fscrypt setup" to recreate the file. diff --git a/cli-tests/t_setup.sh b/cli-tests/t_setup.sh new file mode 100755 index 0000000..a8a62a3 --- /dev/null +++ b/cli-tests/t_setup.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +# Test 'fscrypt setup'. + +cd "$(dirname "$0")" +. common.sh + +# global setup + +_print_header "fscrypt setup creates fscrypt.conf" +rm -f "$FSCRYPT_CONF" +fscrypt setup --time=1ms + +_print_header "fscrypt setup creates fscrypt.conf and /.fscrypt" +_rm_metadata "$MNT_ROOT" +rm -f "$FSCRYPT_CONF" +fscrypt setup --time=1ms +[ -e "$MNT_ROOT/.fscrypt" ] + +_print_header "fscrypt setup when fscrypt.conf already exists (cancel)" +_expect_failure "echo | fscrypt setup --time=1ms" + +_print_header "fscrypt setup when fscrypt.conf already exists (cancel 2)" +_expect_failure "echo N | fscrypt setup --time=1ms" + +_print_header "fscrypt setup when fscrypt.conf already exists (accept)" +echo y | fscrypt setup --time=1ms + +_print_header "fscrypt setup --quiet when fscrypt.conf already exists" +_expect_failure "fscrypt setup --quiet --time=1ms" + +_print_header "fscrypt setup --quiet --force when fscrypt.conf already exists" +fscrypt setup --quiet --force --time=1ms + + +# filesystem setup + +_print_header "fscrypt setup filesystem" +_rm_metadata "$MNT" +fscrypt setup "$MNT" +[ -e "$MNT/.fscrypt" ] + +_print_header "fscrypt setup filesystem (already set up)" +_expect_failure "fscrypt setup '$MNT'" + +_print_header "no config file" +rm -f "$FSCRYPT_CONF" +_expect_failure "fscrypt setup '$MNT'" + +_print_header "bad config file" +echo bad > "$FSCRYPT_CONF" +_expect_failure "fscrypt setup '$MNT'" diff --git a/cli-tests/t_status.out b/cli-tests/t_status.out new file mode 100644 index 0000000..b036712 --- /dev/null +++ b/cli-tests/t_status.out @@ -0,0 +1,44 @@ + +# Get status of setup mountpoint via global status +ext4 supported Yes +ext4 supported Yes + +# Get status of setup mountpoint +ext4 filesystem "MNT" has 0 protectors and 0 policies + +ext4 filesystem "MNT" has 0 protectors and 0 policies + + +# Get status of unencrypted directory on setup mountpoint +[ERROR] fscrypt status: get encryption policy MNT/dir: file + or directory not encrypted +[ERROR] fscrypt status: get encryption policy MNT/dir: file + or directory not encrypted + +# Remove fscrypt metadata from MNT + +# Check enabled / setup count again + +# Get status of not-setup mounntpoint via global status +ext4 supported No +ext4 supported No + +# Get status of not-setup mountpoint +[ERROR] fscrypt status: filesystem MNT: not setup for use + with fscrypt + +Run "fscrypt setup MOUNTPOINT" to use fscrypt on this filesystem. +[ERROR] fscrypt status: filesystem MNT: not setup for use + with fscrypt + +Run "fscrypt setup MOUNTPOINT" to use fscrypt on this filesystem. + +# Get status of unencrypted directory on not-setup mountpoint +[ERROR] fscrypt status: filesystem MNT: not setup for use + with fscrypt + +Run "fscrypt setup MOUNTPOINT" to use fscrypt on this filesystem. +[ERROR] fscrypt status: filesystem MNT: not setup for use + with fscrypt + +Run "fscrypt setup MOUNTPOINT" to use fscrypt on this filesystem. diff --git a/cli-tests/t_status.sh b/cli-tests/t_status.sh new file mode 100755 index 0000000..cfc3616 --- /dev/null +++ b/cli-tests/t_status.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +# Test getting global, filesystem, and unencrypted directory status +# when the filesystem is or isn't set up for fscrypt. + +cd "$(dirname "$0")" +. common.sh + +dir="$MNT/dir" +mkdir "$dir" + +filter_mnt_status() +{ + awk '$1 == "'"$MNT"'" { print $3, $4, $5 }' +} + +# Initially, $MNT has encryption enabled and fscrypt setup. + +enabled_count1=$(_get_enabled_fs_count) +setup_count1=$(_get_setup_fs_count) + + +_print_header "Get status of setup mountpoint via global status" +fscrypt status | filter_mnt_status +_user_do "fscrypt status" | filter_mnt_status + +_print_header "Get status of setup mountpoint" +fscrypt status "$MNT" +_user_do "fscrypt status '$MNT'" + +_print_header "Get status of unencrypted directory on setup mountpoint" +_expect_failure "fscrypt status '$dir'" +_user_do_and_expect_failure "fscrypt status '$dir'" + +_print_header "Remove fscrypt metadata from $MNT" +_rm_metadata "$MNT" + +# Now, $MNT has encryption enabled but fscrypt *not* setup. + +_print_header "Check enabled / setup count again" +enabled_count2=$(_get_enabled_fs_count) +setup_count2=$(_get_setup_fs_count) +(( enabled_count2 == enabled_count1 )) || _fail "wrong enabled count" +(( setup_count2 == setup_count1 - 1 )) || _fail "wrong setup count" + +_print_header "Get status of not-setup mounntpoint via global status" +fscrypt status | filter_mnt_status +_user_do "fscrypt status" | filter_mnt_status + +_print_header "Get status of not-setup mountpoint" +_expect_failure "fscrypt status '$MNT'" +_user_do_and_expect_failure "fscrypt status '$MNT'" + +_print_header "Get status of unencrypted directory on not-setup mountpoint" +_expect_failure "fscrypt status '$dir'" +_user_do_and_expect_failure "fscrypt status '$dir'" diff --git a/cli-tests/t_unlock.out b/cli-tests/t_unlock.out new file mode 100644 index 0000000..29a10dd --- /dev/null +++ b/cli-tests/t_unlock.out @@ -0,0 +1,101 @@ + +# Encrypt directory with --skip-unlock + +# => Check dir status +"MNT/dir" is encrypted with fscrypt. + +Policy: desc1 +Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:2 +Unlocked: No + +Protected with 1 protector: +PROTECTOR LINKED DESCRIPTION +desc2 No custom protector "prot" +touch: cannot touch 'MNT/dir/file': Required key not available + +# => Get policy status via mount: +desc1 No desc2 + +# Unlock directory +Enter custom passphrase for protector "prot": "MNT/dir" is now unlocked and ready for use. + +# => Check dir status +"MNT/dir" is encrypted with fscrypt. + +Policy: desc1 +Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:2 +Unlocked: Yes + +Protected with 1 protector: +PROTECTOR LINKED DESCRIPTION +desc2 No custom protector "prot" + +# => Get policy status via mount: +desc1 Yes desc2 + +# Lock by cycling mount + +# => Check dir status +"MNT/dir" is encrypted with fscrypt. + +Policy: desc1 +Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:2 +Unlocked: No + +Protected with 1 protector: +PROTECTOR LINKED DESCRIPTION +desc2 No custom protector "prot" +mkdir: cannot create directory 'MNT/dir/subdir': Required key not available + +# => Get policy status via mount: +desc1 No desc2 + +# Try to unlock with wrong passphrase +[ERROR] fscrypt unlock: incorrect key provided +"MNT/dir" is encrypted with fscrypt. + +Policy: desc1 +Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:2 +Unlocked: No + +Protected with 1 protector: +PROTECTOR LINKED DESCRIPTION +desc2 No custom protector "prot" + +# Unlock directory +Enter custom passphrase for protector "prot": "MNT/dir" is now unlocked and ready for use. + +# => Check dir status +"MNT/dir" is encrypted with fscrypt. + +Policy: desc1 +Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:2 +Unlocked: Yes + +Protected with 1 protector: +PROTECTOR LINKED DESCRIPTION +desc2 No custom protector "prot" +contents + +# => Get policy status via mount: +desc1 Yes desc2 + +# Try to unlock with corrupt policy metadata +[ERROR] fscrypt unlock: MNT/dir: system error: missing + policy metadata for encrypted directory + +This file or directory has either been encrypted with another tool (such as +e4crypt) or the corresponding filesystem metadata has been deleted. + +# Try to unlock with missing policy metadata +[ERROR] fscrypt unlock: MNT/dir: system error: missing + policy metadata for encrypted directory + +This file or directory has either been encrypted with another tool (such as +e4crypt) or the corresponding filesystem metadata has been deleted. + +# Try to unlock with missing protector metadata +[ERROR] fscrypt unlock: could not load any protectors + +You may need to mount a linked filesystem. Run with --verbose for more +information. diff --git a/cli-tests/t_unlock.sh b/cli-tests/t_unlock.sh new file mode 100755 index 0000000..3dfba41 --- /dev/null +++ b/cli-tests/t_unlock.sh @@ -0,0 +1,69 @@ +#!/bin/bash + +# Test unlocking a directory. + +cd "$(dirname "$0")" +. common.sh + +dir="$MNT/dir" +mkdir "$dir" + +_print_header "Encrypt directory with --skip-unlock" +echo hunter2 | fscrypt encrypt --quiet --name=prot --skip-unlock "$dir" +_print_header "=> Check dir status" +fscrypt status "$dir" +_expect_failure "touch '$dir/file'" +policy=$(fscrypt status "$dir" | awk '/Policy:/{print $2}') +_print_header "=> Get policy status via mount:" +fscrypt status "$MNT" | grep "^$policy" + +_print_header "Unlock directory" +echo hunter2 | fscrypt unlock "$dir" +_print_header "=> Check dir status" +fscrypt status "$dir" +echo contents > "$dir/file" +_print_header "=> Get policy status via mount:" +fscrypt status "$MNT" | grep "^$policy" + +_print_header "Lock by cycling mount" +umount "$MNT" +mount "$DEV" "$MNT" +_print_header "=> Check dir status" +fscrypt status "$dir" +_expect_failure "mkdir '$dir/subdir'" +_print_header "=> Get policy status via mount:" +fscrypt status "$MNT" | grep "^$policy" + +_print_header "Try to unlock with wrong passphrase" +_expect_failure "echo bad | fscrypt unlock --quiet '$dir'" +fscrypt status "$dir" + +_print_header "Unlock directory" +echo hunter2 | fscrypt unlock "$dir" +_print_header "=> Check dir status" +fscrypt status "$dir" +cat "$dir/file" +_print_header "=> Get policy status via mount:" +fscrypt status "$MNT" | grep "^$policy" + +_print_header "Try to unlock with corrupt policy metadata" +umount "$MNT" +mount "$DEV" "$MNT" +echo bad > "$MNT/.fscrypt/policies/$policy" +_expect_failure "echo hunter2 | fscrypt unlock '$dir'" + +_reset_filesystems + +_print_header "Try to unlock with missing policy metadata" +mkdir "$dir" +echo hunter2 | fscrypt encrypt --quiet --name=prot --skip-unlock "$dir" +rm "$MNT"/.fscrypt/policies/* +_expect_failure "echo hunter2 | fscrypt unlock '$dir'" + +_reset_filesystems + +_print_header "Try to unlock with missing protector metadata" +mkdir "$dir" +echo hunter2 | fscrypt encrypt --quiet --name=prot --skip-unlock "$dir" +rm "$MNT"/.fscrypt/protectors/* +_expect_failure "echo hunter2 | fscrypt unlock '$dir'" diff --git a/cli-tests/t_v1_policy.out b/cli-tests/t_v1_policy.out new file mode 100644 index 0000000..747cf81 --- /dev/null +++ b/cli-tests/t_v1_policy.out @@ -0,0 +1,98 @@ + +# Set policy_version 1 + +# Try to encrypt as root +[ERROR] fscrypt encrypt: user must be specified when run as root + +When running this command as root, you usually still want to provision/remove +keys for a normal user's keyring and use a normal user's login passphrase as a +protector (so the corresponding files will be accessible for that user). This +can be done with --user=USERNAME. To use the root user's keyring or passphrase, +use --user=root. + +# Try to use --user=root as user +[ERROR] fscrypt encrypt: setting uids: operation not permitted: could not access + user keyring + +You can only use --user=USERNAME to access the user keyring of another user if +you are running as root. + +# Try to encrypt without user keyring in session keyring +[ERROR] fscrypt encrypt: user keyring not linked into session keyring + +This is usually the result of a bad PAM configuration. Either correct the +problem in your PAM stack, enable pam_keyinit.so, or run "keyctl link @u @s". + +# Encrypt a directory + +# Get dir status as user +"MNT/dir" is encrypted with fscrypt. + +Policy: desc1 +Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:1 +Unlocked: Yes + +Protected with 1 protector: +PROTECTOR LINKED DESCRIPTION +desc2 No custom protector "prot" + +# Get dir status as root +"MNT/dir" is encrypted with fscrypt. + +Policy: desc1 +Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:1 +Unlocked: Yes + +Protected with 1 protector: +PROTECTOR LINKED DESCRIPTION +desc2 No custom protector "prot" + +# Create files in v1-encrypted directory + +# Try to lock v1-encrypted directory as user +[ERROR] fscrypt lock: inode cache can only be dropped as root + +Either this command should be run as root to properly clear the inode cache, or +it should be run with --drop-caches=false (this may leave encrypted files and +directories in an accessible state). +"MNT/dir" is encrypted with fscrypt. + +Policy: desc1 +Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:1 +Unlocked: Yes + +Protected with 1 protector: +PROTECTOR LINKED DESCRIPTION +desc2 No custom protector "prot" + +# Try to lock v1-encrypted directory as root without --user +[ERROR] fscrypt lock: user must be specified when run as root + +When running this command as root, you usually still want to provision/remove +keys for a normal user's keyring and use a normal user's login passphrase as a +protector (so the corresponding files will be accessible for that user). This +can be done with --user=USERNAME. To use the root user's keyring or passphrase, +use --user=root. +"MNT/dir" is encrypted with fscrypt. + +Policy: desc1 +Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:1 +Unlocked: Yes + +Protected with 1 protector: +PROTECTOR LINKED DESCRIPTION +desc2 No custom protector "prot" + +# Lock v1-encrypted directory +Encrypted data removed from filesystem cache. +"MNT/dir" is now locked. +"MNT/dir" is encrypted with fscrypt. + +Policy: desc1 +Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:1 +Unlocked: No + +Protected with 1 protector: +PROTECTOR LINKED DESCRIPTION +desc2 No custom protector "prot" +cat: MNT/dir/file: No such file or directory diff --git a/cli-tests/t_v1_policy.sh b/cli-tests/t_v1_policy.sh new file mode 100755 index 0000000..1ebfae5 --- /dev/null +++ b/cli-tests/t_v1_policy.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +# Test using v1 encryption policies (deprecated). + +cd "$(dirname "$0")" +. common.sh + +_setup_session_keyring + +dir="$MNT/dir" +mkdir "$dir" +chown "$TEST_USER" "$dir" + +_print_header "Set policy_version 1" +sed -i 's/"policy_version": "2"/"policy_version": "1"/' "$FSCRYPT_CONF" + +_print_header "Try to encrypt as root" +_expect_failure "echo hunter2 | fscrypt encrypt --quiet --name=prot '$dir'" + +_print_header "Try to use --user=root as user" +_user_do_and_expect_failure "echo hunter2 | fscrypt encrypt --quiet --name=prot --user=root '$dir'" + +_print_header "Try to encrypt without user keyring in session keyring" +_user_do "keyctl unlink @u @s" +_user_do_and_expect_failure "echo hunter2 | fscrypt encrypt --quiet --name=prot '$dir'" +_user_do "keyctl link @u @s" + +_print_header "Encrypt a directory" +_user_do "echo hunter2 | fscrypt encrypt --quiet --name=prot '$dir'" + +_print_header "Get dir status as user" +_user_do "fscrypt status '$dir'" + +_print_header "Get dir status as root" +fscrypt status "$dir" + +_print_header "Create files in v1-encrypted directory" +echo contents > "$dir/file" +mkdir "$dir/subdir" +ln -s target "$dir/symlink" + +# Due to the limitations of the v1 key management mechanism, 'fscrypt lock' only +# works when run as root and with the --user argument. + +_print_header "Try to lock v1-encrypted directory as user" +_user_do_and_expect_failure "fscrypt lock '$dir'" +_user_do "fscrypt status '$dir'" + +_print_header "Try to lock v1-encrypted directory as root without --user" +_expect_failure "fscrypt lock '$dir'" +_user_do "fscrypt status '$dir'" + +_print_header "Lock v1-encrypted directory" +fscrypt lock "$dir" --user="$TEST_USER" +_user_do "fscrypt status '$dir'" +_expect_failure "cat '$dir/file'" diff --git a/cli-tests/t_v1_policy_fs_keyring.out b/cli-tests/t_v1_policy_fs_keyring.out new file mode 100644 index 0000000..ca32ec1 --- /dev/null +++ b/cli-tests/t_v1_policy_fs_keyring.out @@ -0,0 +1,75 @@ + +# Enable v1 policies with fs keyring + +# Try to encrypt directory as user +[ERROR] fscrypt encrypt: root is required to add/remove v1 encryption policy + keys to/from filesystem + +Either this command should be run as root, or you should set +'"use_fs_keyring_for_v1_policies": false' in /etc/fscrypt.conf, or you should +re-create your encrypted directories using v2 encryption policies rather than v1 +(this requires setting '"policy_version": "2"' in the "options" section of +/etc/fscrypt.conf). +[ERROR] fscrypt status: get encryption policy MNT/dir: file + or directory not encrypted + +# Encrypt directory as user with --skip-unlock +"MNT/dir" is encrypted with fscrypt. + +Policy: desc1 +Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:1 +Unlocked: No + +Protected with 1 protector: +PROTECTOR LINKED DESCRIPTION +desc2 No custom protector "prot" +mkdir: cannot create directory 'MNT/dir/subdir': Required key not available + +# Try to unlock directory as user +[ERROR] fscrypt unlock: root is required to add/remove v1 encryption policy keys + to/from filesystem + +Either this command should be run as root, or you should set +'"use_fs_keyring_for_v1_policies": false' in /etc/fscrypt.conf, or you should +re-create your encrypted directories using v2 encryption policies rather than v1 +(this requires setting '"policy_version": "2"' in the "options" section of +/etc/fscrypt.conf). + +# Unlock directory as root +Enter custom passphrase for protector "prot": "MNT/dir" is now unlocked and ready for use. +"MNT/dir" is encrypted with fscrypt. + +Policy: desc1 +Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:1 +Unlocked: Yes + +Protected with 1 protector: +PROTECTOR LINKED DESCRIPTION +desc2 No custom protector "prot" + +# Try to lock directory as user +[ERROR] fscrypt lock: root is required to add/remove v1 encryption policy keys + to/from filesystem + +Either this command should be run as root, or you should set +'"use_fs_keyring_for_v1_policies": false' in /etc/fscrypt.conf, or you should +re-create your encrypted directories using v2 encryption policies rather than v1 +(this requires setting '"policy_version": "2"' in the "options" section of +/etc/fscrypt.conf). + +# Lock directory as root +"MNT/dir" is now locked. +cat: MNT/dir/file: No such file or directory +"MNT/dir" is encrypted with fscrypt. + +Policy: desc1 +Options: padding:32 contents:AES_256_XTS filenames:AES_256_CTS policy_version:1 +Unlocked: No + +Protected with 1 protector: +PROTECTOR LINKED DESCRIPTION +desc2 No custom protector "prot" + +# Check that user can access file when directory is unlocked by root +Enter custom passphrase for protector "prot": "MNT/dir" is now unlocked and ready for use. +contents diff --git a/cli-tests/t_v1_policy_fs_keyring.sh b/cli-tests/t_v1_policy_fs_keyring.sh new file mode 100755 index 0000000..bf1191a --- /dev/null +++ b/cli-tests/t_v1_policy_fs_keyring.sh @@ -0,0 +1,49 @@ +#!/bin/bash + +# Test using v1 encryption policies (deprecated) with +# use_fs_keyring_for_v1_policies = true. + +# This works similar to v2 policies, except locking and unlocking (including +# 'fscrypt encrypt' without --skip-unlock) will only work as root. + +cd "$(dirname "$0")" +. common.sh + +_print_header "Enable v1 policies with fs keyring" +sed -e 's/"use_fs_keyring_for_v1_policies": false/"use_fs_keyring_for_v1_policies": true/' \ + -e 's/"policy_version": "2"/"policy_version": "1"/' \ + -i "$FSCRYPT_CONF" + +dir="$MNT/dir" +mkdir "$dir" +chown "$TEST_USER" "$dir" + +_print_header "Try to encrypt directory as user" +_user_do_and_expect_failure "echo hunter2 | fscrypt encrypt --quiet --name=prot '$dir'" +_expect_failure "fscrypt status '$dir'" + +_print_header "Encrypt directory as user with --skip-unlock" +_user_do "echo hunter2 | fscrypt encrypt --quiet --name=prot --skip-unlock '$dir'" +fscrypt status "$dir" +_expect_failure "mkdir '$dir/subdir'" + +_print_header "Try to unlock directory as user" +_user_do_and_expect_failure "echo hunter2 | fscrypt unlock '$dir'" + +_print_header "Unlock directory as root" +echo hunter2 | fscrypt unlock "$dir" +mkdir "$dir/subdir" +echo contents > "$dir/file" +fscrypt status "$dir" + +_print_header "Try to lock directory as user" +_user_do_and_expect_failure "fscrypt lock '$dir'" + +_print_header "Lock directory as root" +fscrypt lock "$dir" +_expect_failure "cat '$dir/file'" +fscrypt status "$dir" + +_print_header "Check that user can access file when directory is unlocked by root" +echo hunter2 | fscrypt unlock "$dir" +_user_do "cat '$dir/file'" |