diff options
author | Daniel Zatovic <daniel.zatovic@gmail.com> | 2023-12-05 15:48:28 +0100 |
---|---|---|
committer | Daniel Zaťovič <daniel.zatovic@gmail.com> | 2024-01-19 16:26:30 +0000 |
commit | f354a0b038dc906990239328c99d318782b2f4e1 (patch) | |
tree | 6e3ba2c45af7ab4a8c17ebd7347b9fbec12838a3 | |
parent | 5814b39cddc9006b4e96e1c89f4ca7efaf56d975 (diff) | |
download | cryptsetup-f354a0b038dc906990239328c99d318782b2f4e1.tar.gz |
Add tests for storing multiple VKs in a custom keyring.
-rw-r--r-- | tests/api-test-2.c | 100 | ||||
-rwxr-xr-x | tests/compat-test2 | 64 |
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 = ¶ms2, + }; + 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, ¶ms2)); + 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 |