aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Zatovic <daniel.zatovic@gmail.com>2023-12-05 15:48:28 +0100
committerDaniel Zaťovič <daniel.zatovic@gmail.com>2024-01-19 16:26:30 +0000
commitf354a0b038dc906990239328c99d318782b2f4e1 (patch)
tree6e3ba2c45af7ab4a8c17ebd7347b9fbec12838a3
parent5814b39cddc9006b4e96e1c89f4ca7efaf56d975 (diff)
downloadcryptsetup-f354a0b038dc906990239328c99d318782b2f4e1.tar.gz
Add tests for storing multiple VKs in a custom keyring.
-rw-r--r--tests/api-test-2.c100
-rwxr-xr-xtests/compat-test264
2 files changed, 161 insertions, 3 deletions
diff --git a/tests/api-test-2.c b/tests/api-test-2.c
index 2acce22e..6a4344a1 100644
--- a/tests/api-test-2.c
+++ b/tests/api-test-2.c
@@ -89,10 +89,14 @@ typedef int32_t key_serial_t;
#define TEST_KEYRING_USER_NAME "%keyring:" TEST_KEYRING_USER
#define TEST_KEYRING_SESSION "cs_apitest2_keyring_in_session"
#define TEST_KEYRING_SESSION_NAME "%keyring:" TEST_KEYRING_SESSION
-#define TEST_KEY_VK_USER "api_test_user_vk"
+#define TEST_KEY_VK_USER "api_test_user_vk1"
#define TEST_KEY_VK_USER_NAME "\%user:" TEST_KEY_VK_USER
-#define TEST_KEY_VK_LOGON "cs_api_test_prefix:api_test_logon_vk"
+#define TEST_KEY_VK_LOGON "cs_api_test_prefix:api_test_logon_vk1"
#define TEST_KEY_VK_LOGON_NAME "\%logon:" TEST_KEY_VK_LOGON
+#define TEST_KEY_VK_USER2 "api_test_user_vk2"
+#define TEST_KEY_VK_USER2_NAME "\%user:" TEST_KEY_VK_USER
+#define TEST_KEY_VK_LOGON2 "cs_api_test_prefix:api_test_logon_vk2"
+#define TEST_KEY_VK_LOGON2_NAME "\%logon:" TEST_KEY_VK_LOGON
#define KEY_DESC_TEST0 "cs_token_test:test_key0"
#define KEY_DESC_TEST1 "cs_token_test:test_key1"
@@ -5267,12 +5271,39 @@ static void KeyslotContextAndKeyringLink(void)
uint64_t r_payload_offset;
char key[128];
size_t key_size = 128;
- key_serial_t kid, keyring_in_user_id, keyring_in_session_id, linked_kid;
+ key_serial_t kid, keyring_in_user_id, keyring_in_session_id, linked_kid, linked_kid2;
int suspend_status;
struct crypt_active_device cad;
char vk_buf[1024];
long vk_len;
+ struct crypt_pbkdf_type pbkdf = {
+ .type = CRYPT_KDF_ARGON2I,
+ .hash = "sha256",
+ .parallel_threads = 1,
+ .max_memory_kb = 128,
+ .iterations = 4,
+ .flags = CRYPT_PBKDF_NO_BENCHMARK
+ };
+ struct crypt_params_luks2 params2 = {
+ .pbkdf = &pbkdf,
+ .sector_size = 4096
+ };
+ struct crypt_params_reencrypt rparams = {
+ .direction = CRYPT_REENCRYPT_FORWARD,
+ .resilience = "checksum",
+ .hash = "sha256",
+ .luks2 = &params2,
+ };
+ uint64_t r_header_size;
+
+ if (_fips_mode) {
+ pbkdf.type = CRYPT_KDF_PBKDF2;
+ pbkdf.parallel_threads = 0;
+ pbkdf.max_memory_kb = 0;
+ pbkdf.iterations = 1000;
+ }
+
OK_(get_luks2_offsets(0, 0, 0, NULL, &r_payload_offset));
OK_(create_dmdevice_over_loop(L_DEVICE_1S, r_payload_offset + 1));
@@ -5485,6 +5516,69 @@ static void KeyslotContextAndKeyringLink(void)
NOTFAIL_(keyctl_unlink(kid, KEY_SPEC_THREAD_KEYRING), "Test or kernel keyring are broken.");
CRYPT_FREE(cd);
+
+ // test storing two VKs in keyring during reencryption
+ OK_(get_luks2_offsets(1, 0, 0, &r_header_size, NULL));
+ OK_(create_dmdevice_over_loop(L_DEVICE_OK, r_header_size + 16));
+
+ OK_(crypt_init(&cd, DMDIR L_DEVICE_OK));
+ OK_(crypt_format(cd, CRYPT_LUKS2, "aes", "cbc-essiv:sha256", NULL, NULL, 32, &params2));
+ OK_(crypt_set_pbkdf_type(cd, &pbkdf));
+ EQ_(crypt_keyslot_add_by_volume_key(cd, 1, NULL, 64, PASSPHRASE, strlen(PASSPHRASE)), 1);
+ EQ_(crypt_keyslot_add_by_key(cd, 0, NULL, 32, PASSPHRASE, strlen(PASSPHRASE), CRYPT_VOLUME_KEY_NO_SEGMENT), 0);
+ rparams.flags = CRYPT_REENCRYPT_INITIALIZE_ONLY;
+ EQ_(crypt_reencrypt_init_by_passphrase(cd, NULL, PASSPHRASE, strlen(PASSPHRASE), 1, 0, "aes", "xts-plain64", &rparams), 2);
+
+ // when no key name is specified, don't allow specifying type and keyring
+ EQ_(crypt_set_keyring_to_link(cd, NULL, NULL, NULL, keyring_in_user_str_id), -EINVAL);
+ EQ_(crypt_set_keyring_to_link(cd, NULL, NULL, "user", NULL), -EINVAL);
+ EQ_(crypt_set_keyring_to_link(cd, NULL, NULL, "user", keyring_in_user_str_id), -EINVAL);
+
+ // key names have to be specified starting from the first
+ EQ_(crypt_set_keyring_to_link(cd, NULL, TEST_KEY_VK_USER, "user", keyring_in_user_str_id), -EINVAL);
+ EQ_(crypt_set_keyring_to_link(cd, TEST_KEY_VK_USER, NULL, "user", keyring_in_user_str_id), -EAGAIN);
+
+ EQ_(crypt_set_keyring_to_link(cd, TEST_KEY_VK_USER, TEST_KEY_VK_USER2, "user", keyring_in_user_str_id), 0);
+ EQ_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, PASSPHRASE, strlen(PASSPHRASE), 0), 0);
+ FAIL_((linked_kid = request_key("logon", TEST_KEY_VK_USER, NULL, 0)), "VK was linked to custom keyring under wrong key type.");
+ FAIL_((linked_kid2 = request_key("logon", TEST_KEY_VK_USER2, NULL, 0)), "VK was linked to custom keyring under wrong key type.");
+ NOTFAIL_((linked_kid = request_key("user", TEST_KEY_VK_USER, NULL, 0)), "VK was not linked to custom keyring.");
+ NOTFAIL_((linked_kid2 = request_key("user", TEST_KEY_VK_USER2, NULL, 0)), "VK was not linked to custom keyring.");
+ NOTFAIL_(_kernel_key_by_segment_and_type(cd, 0, "logon"), "dm-crypt VK was not uploaded in thread kernel keyring.");
+ NOTFAIL_(_kernel_key_by_segment_and_type(cd, 1, "logon"), "dm-crypt VK was not uploaded in thread kernel keyring.");
+
+ OK_(crypt_deactivate(cd, CDEVICE_1));
+ NOTFAIL_(keyctl_unlink(linked_kid, keyring_in_user_id), "VK was not linked to custom keyring after deactivation.");
+ NOTFAIL_(keyctl_unlink(linked_kid2, keyring_in_user_id), "VK was not linked to custom keyring after deactivation.");
+ FAIL_(_kernel_key_by_segment_and_type(cd, 0, "logon"), "dm-crypt VK remain linked in thread keyring.");
+ // BUG: Reencryption code does not unlink the second VK
+ // FAIL_(_kernel_key_by_segment_and_type(cd, 1, "logon"), "dm-crypt VK remain linked in thread keyring.");
+
+ // check that VKs are linked without calling crypt_activate_by_passphrase again, when activate is called on the same context
+ EQ_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, PASSPHRASE, strlen(PASSPHRASE), 0), 0);
+ NOTFAIL_((linked_kid = request_key("user", TEST_KEY_VK_USER, NULL, 0)), "VK was not linked to custom keyring.");
+ NOTFAIL_((linked_kid2 = request_key("user", TEST_KEY_VK_USER2, NULL, 0)), "VK was not linked to custom keyring.");
+ OK_(crypt_deactivate(cd, CDEVICE_1));
+ NOTFAIL_(keyctl_unlink(linked_kid, keyring_in_user_id), "VK was not linked to custom keyring after deactivation.");
+ NOTFAIL_(keyctl_unlink(linked_kid2, keyring_in_user_id), "VK was not linked to custom keyring after deactivation.");
+
+ // verify that the VK is no longer stored in a custom keyring
+ EQ_(crypt_set_keyring_to_link(cd, NULL, NULL, NULL, NULL), 0);
+ EQ_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, PASSPHRASE, strlen(PASSPHRASE), 0), 0);
+ FAIL_((linked_kid = request_key("user", TEST_KEY_VK_USER, NULL, 0)), "VK was not linked to custom keyring.");
+ FAIL_((linked_kid2 = request_key("user", TEST_KEY_VK_USER2, NULL, 0)), "VK was not linked to custom keyring.");
+ OK_(crypt_deactivate(cd, CDEVICE_1));
+
+ // test that after reencryption finishes (and there is only one VK), only one VK name is used
+ EQ_(crypt_set_keyring_to_link(cd, TEST_KEY_VK_USER, TEST_KEY_VK_USER2, "user", keyring_in_user_str_id), 0);
+ rparams.flags = CRYPT_REENCRYPT_RESUME_ONLY;
+ EQ_(crypt_reencrypt_init_by_passphrase(cd, NULL, PASSPHRASE, strlen(PASSPHRASE), 1, 0, "aes", "xts-plain64", &rparams), 2);
+ OK_(crypt_reencrypt_run(cd, NULL, NULL));
+ EQ_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, PASSPHRASE, strlen(PASSPHRASE), 0), 0);
+ NOTFAIL_((linked_kid = request_key("user", TEST_KEY_VK_USER, NULL, 0)), "VK was not linked to custom keyring.");
+ FAIL_((linked_kid2 = request_key("user", TEST_KEY_VK_USER2, NULL, 0)), "VK was not linked to custom keyring.");
+
+ CRYPT_FREE(cd);
_cleanup_dmdevices();
#else
printf("WARNING: cryptsetup compiled with kernel keyring service disabled, skipping test.\n");
diff --git a/tests/compat-test2 b/tests/compat-test2
index 62d654f0..8bd305a8 100755
--- a/tests/compat-test2
+++ b/tests/compat-test2
@@ -352,6 +352,39 @@ test_vk_link_and_reactivate() {
keyctl unlink $KEYCTL_KEY_NAME "$2" || fail
}
+# $1 first key name
+# $2 second key name
+# $3 keyring to link VK to
+# $4 key type (optional)
+test_reencrypt_vk_link() {
+ KEY_TYPE=${4:-user}
+ if [ -z "$4" ]; then
+ KEY_DESC=$1
+ else
+ KEY_DESC="%$4:$1"
+ fi
+ if [ -z "$4" ]; then
+ KEY_DESC2=$2
+ else
+ KEY_DESC2="%$4:$2"
+ fi
+
+ KEYCTL_KEY_NAME="%$KEY_TYPE:$1"
+ KEYCTL_KEY_NAME2="%$KEY_TYPE:$2"
+
+ echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --link-vk-to-keyring "$3"::"$KEY_DESC" --link-vk-to-keyring "$3"::"$KEY_DESC2" || fail
+ keyctl search "$3" $KEY_TYPE $1 > /dev/null 2>&1 || fail "VK is not linked to the specified keyring after activation."
+
+ keyctl search "$3" $KEY_TYPE $1 > /dev/null 2>&1 || fail "VK is not linked to the specified keyring after activation."
+ keyctl search "$3" $KEY_TYPE $2 > /dev/null 2>&1 || fail "VK is not linked to the specified keyring after activation."
+ $CRYPTSETUP close $DEV_NAME || fail
+ keyctl search "$3" $KEY_TYPE $1 > /dev/null 2>&1 || fail "VK is not linked to the specified keyring after deactivation."
+ keyctl search "$3" $KEY_TYPE $2 > /dev/null 2>&1 || fail "VK is not linked to the specified keyring after deactivation."
+
+ keyctl unlink $KEYCTL_KEY_NAME "$3" || fail
+ keyctl unlink $KEYCTL_KEY_NAME2 "$3" || fail
+}
+
function expect_run()
{
export INFOSTRING="$(basename ${BASH_SOURCE[1]})-line-${BASH_LINENO[0]}"
@@ -1367,6 +1400,8 @@ if [ $HAVE_KEYRING -gt 0 -a -d /proc/sys/kernel/keys ]; then
echo $PWD1 | $CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV 2> /dev/null || fail
KEY_NAME="cryptsetup:test_volume_key_id"
+ KEY_NAME2="cryptsetup:test_volume_key_id2"
+ KEY_NAME3="cryptsetup:test_volume_key_id3"
test_and_prepare_keyring
KID=$(echo -n test | keyctl padd user my_token @s)
keyctl unlink $KID >/dev/null 2>&1 @s && SESSION_KEYRING_WORKS=1
@@ -1414,6 +1449,35 @@ if [ $HAVE_KEYRING -gt 0 -a -d /proc/sys/kernel/keys ]; then
echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --link-vk-to-keyring "@t::%0:$KEY_NAME" > /dev/null 2>&1 && fail
echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --link-vk-to-keyring "@t::%blah:$KEY_NAME" > /dev/null 2>&1 && fail
echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --link-vk-to-keyring "@t::%userlogon:$KEY_NAME" > /dev/null 2>&1 && fail
+
+ # test that only one VK name is used, when the device is not in reencryption
+ echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --link-vk-to-keyring "@u::%user:$KEY_NAME" --link-vk-to-keyring "@u::%user:$KEY_NAME2" > /dev/null 2>&1 || fail
+ keyctl unlink "%user:$KEY_NAME" @u || fail
+ keyctl unlink "%user:$KEY_NAME2" @u > /dev/null 2>&1 && fail
+ $CRYPTSETUP close $DEV_NAME || fail
+
+ # test linkning multiple VKs during reencryption
+ echo $PWD1 | $CRYPTSETUP -q reencrypt $LOOPDEV --init-only
+
+ test_reencrypt_vk_link $KEY_NAME $KEY_NAME2 "@u"
+ test_reencrypt_vk_link $KEY_NAME $KEY_NAME2 "@u" "user"
+ [[ ! -z "$SESSION_KEYRING_WORKS" ]] && test_reencrypt_vk_link $KEY_NAME $KEY_NAME2 "@s"
+ [[ ! -z "$SESSION_KEYRING_WORKS" ]] && test_reencrypt_vk_link $KEY_NAME $KEY_NAME2 "@s" "logon"
+ [[ ! -z "$SESSION_KEYRING_WORKS" ]] && test_reencrypt_vk_link $KEY_NAME $KEY_NAME2 "@s" "user"
+ test_reencrypt_vk_link $KEY_NAME $KEY_NAME2 "%:$TEST_KEYRING_NAME"
+ test_reencrypt_vk_link $KEY_NAME $KEY_NAME2 "%:$TEST_KEYRING_NAME" "user"
+ test_reencrypt_vk_link $KEY_NAME $KEY_NAME2 "%:$TEST_KEYRING_NAME" "logon"
+ # explicitly specify keyring key type
+ test_reencrypt_vk_link $KEY_NAME $KEY_NAME2 "%keyring:$TEST_KEYRING_NAME"
+
+ # the keyring and key type have to be the same for both keys
+ echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --link-vk-to-keyring "@s::%user:$KEY_NAME" --link-vk-to-keyring "@u::%user:$KEY_NAME2" > /dev/null 2>&1 && fail
+ echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --link-vk-to-keyring "@u::%logon:$KEY_NAME" --link-vk-to-keyring "@u::%user:$KEY_NAME2" > /dev/null 2>&1 && fail
+ echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --link-vk-to-keyring "@s::%logon:$KEY_NAME" --link-vk-to-keyring "@u::%user:$KEY_NAME2" > /dev/null 2>&1 && fail
+
+ # supply one/three key name(s) when two names are required
+ echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --link-vk-to-keyring "@s::%logon:$KEY_NAME" > /dev/null 2>&1 && fail
+ echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --link-vk-to-keyring "@s::%logon:$KEY_NAME" --link-vk-to-keyring "@s::%logon:$KEY_NAME2" --link-vk-to-keyring "@s::%logon:$KEY_NAME3" > /dev/null 2>&1 && fail
fi
prepare "[45] Blkid disable check" wipe