mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-05 16:00:05 +01:00
Add tests for linking VK to a keyring and changing VK type.
Test various combinations of arguments for the options --link-vk-to-keyring and --volume-key-type. Add API tests for the crypt_set_keyring_to_link and crypt_set_vk_keyring_type functions.
This commit is contained in:
@@ -489,6 +489,16 @@ static key_serial_t keyctl_unlink(key_serial_t key, key_serial_t keyring)
|
||||
return syscall(__NR_keyctl, KEYCTL_UNLINK, key, keyring);
|
||||
}
|
||||
|
||||
static long keyctl_update(key_serial_t id, const void *payload, size_t plen)
|
||||
{
|
||||
return syscall(__NR_keyctl, KEYCTL_UPDATE, id, payload, plen);
|
||||
}
|
||||
|
||||
static long keyctl_read(key_serial_t id, char *buffer, size_t buflen)
|
||||
{
|
||||
return syscall(__NR_keyctl, KEYCTL_READ, id, buffer, buflen);
|
||||
}
|
||||
|
||||
static key_serial_t request_key(const char *type,
|
||||
const char *description,
|
||||
const char *callout_info,
|
||||
@@ -497,14 +507,20 @@ static key_serial_t request_key(const char *type,
|
||||
return syscall(__NR_request_key, type, description, callout_info, keyring);
|
||||
}
|
||||
|
||||
static key_serial_t _kernel_key_by_segment(struct crypt_device *_cd, int segment)
|
||||
static key_serial_t _kernel_key_by_segment_and_type(struct crypt_device *_cd, int segment,
|
||||
const char* type)
|
||||
{
|
||||
char key_description[1024];
|
||||
|
||||
if (snprintf(key_description, sizeof(key_description), "cryptsetup:%s-d%u", crypt_get_uuid(_cd), segment) < 1)
|
||||
return -1;
|
||||
|
||||
return request_key("logon", key_description, NULL, 0);
|
||||
return request_key(type, key_description, NULL, 0);
|
||||
}
|
||||
|
||||
static key_serial_t _kernel_key_by_segment(struct crypt_device *_cd, int segment)
|
||||
{
|
||||
return _kernel_key_by_segment_and_type(cd, segment, "logon");
|
||||
}
|
||||
|
||||
static int _volume_key_in_keyring(struct crypt_device *_cd, int segment)
|
||||
@@ -512,14 +528,20 @@ static int _volume_key_in_keyring(struct crypt_device *_cd, int segment)
|
||||
return _kernel_key_by_segment(_cd, segment) >= 0 ? 0 : -1;
|
||||
}
|
||||
|
||||
static int _drop_keyring_key(struct crypt_device *_cd, int segment)
|
||||
static int _drop_keyring_key_from_keyring_type(struct crypt_device *_cd, int segment,
|
||||
key_serial_t keyring, const char* type)
|
||||
{
|
||||
key_serial_t kid = _kernel_key_by_segment(_cd, segment);
|
||||
key_serial_t kid = _kernel_key_by_segment_and_type(_cd, segment, type);
|
||||
|
||||
if (kid < 0)
|
||||
return -1;
|
||||
|
||||
return keyctl_unlink(kid, KEY_SPEC_THREAD_KEYRING);
|
||||
return keyctl_unlink(kid, keyring);
|
||||
}
|
||||
|
||||
static int _drop_keyring_key(struct crypt_device *_cd, int segment)
|
||||
{
|
||||
return _drop_keyring_key_from_keyring_type(cd, segment, KEY_SPEC_THREAD_KEYRING, "logon");
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -5120,17 +5142,21 @@ static void VolumeKeyGet(void)
|
||||
_cleanup_dmdevices();
|
||||
}
|
||||
|
||||
static void KeyslotContext(void)
|
||||
static void KeyslotContextAndKeyringLink(void)
|
||||
{
|
||||
#ifdef KERNEL_KEYRING
|
||||
const char *cipher = "aes";
|
||||
const char *cipher_mode = "xts-plain64";
|
||||
struct crypt_keyslot_context *kc;
|
||||
uint64_t r_payload_offset;
|
||||
char key[128];
|
||||
size_t key_size = 128;
|
||||
key_serial_t kid;
|
||||
key_serial_t kid, linked_kid;
|
||||
int suspend_status;
|
||||
struct crypt_active_device cad;
|
||||
char key_description[1024];
|
||||
char vk_buf[1024];
|
||||
long vk_len;
|
||||
|
||||
OK_(get_luks2_offsets(0, 0, 0, NULL, &r_payload_offset));
|
||||
OK_(create_dmdevice_over_loop(L_DEVICE_1S, r_payload_offset + 1));
|
||||
@@ -5192,7 +5218,81 @@ static void KeyslotContext(void)
|
||||
OK_(crypt_deactivate(cd, CDEVICE_1));
|
||||
crypt_keyslot_context_free(kc);
|
||||
|
||||
// test resume
|
||||
// test linking to a keyring and setting key type
|
||||
crypt_set_keyring_to_link(cd, "@u");
|
||||
OK_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, PASSPHRASE, strlen(PASSPHRASE), 0));
|
||||
NOTFAIL_((linked_kid = _kernel_key_by_segment_and_type(cd, 0, "logon")), "VK was not linked to user keyring.");
|
||||
OK_(crypt_deactivate(cd, CDEVICE_1));
|
||||
NOTFAIL_(keyctl_unlink(linked_kid, KEY_SPEC_USER_KEYRING), "VK was not linked to user keyring after deactivation.");
|
||||
FAIL_(keyctl_unlink(linked_kid, KEY_SPEC_USER_KEYRING), "VK was not unlinked linked from user keyring after deactivation.");
|
||||
|
||||
crypt_set_vk_keyring_type(cd, "user");
|
||||
OK_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, PASSPHRASE, strlen(PASSPHRASE), 0));
|
||||
NOTFAIL_((linked_kid = _kernel_key_by_segment_and_type(cd, 0, "user")), "VK was not linked to user keyring.");
|
||||
OK_(crypt_deactivate(cd, CDEVICE_1));
|
||||
NOTFAIL_(keyctl_unlink(linked_kid, KEY_SPEC_USER_KEYRING), "VK was not linked to user keyring after deactivation.");
|
||||
FAIL_(keyctl_unlink(linked_kid, KEY_SPEC_USER_KEYRING), "VK was not unlinked linked from user keyring after deactivation.");
|
||||
|
||||
crypt_set_keyring_to_link(cd, "@s");
|
||||
OK_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, PASSPHRASE, strlen(PASSPHRASE), 0));
|
||||
NOTFAIL_(_kernel_key_by_segment_and_type(cd, 0, "user"), "VK was not linked to session keyring.");
|
||||
OK_(crypt_deactivate(cd, CDEVICE_1));
|
||||
NOTFAIL_(_kernel_key_by_segment_and_type(cd, 0, "user"), "VK was not linked to session keyring after deactivation.");
|
||||
OK_(_drop_keyring_key_from_keyring_type(cd, 0, KEY_SPEC_SESSION_KEYRING, "user"));
|
||||
|
||||
// test repated activation
|
||||
FAIL_(_kernel_key_by_segment_and_type(cd, 0, "user"), "VK was still linked to session keyring after removal.");
|
||||
OK_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, PASSPHRASE, strlen(PASSPHRASE), 0));
|
||||
NOTFAIL_(_kernel_key_by_segment_and_type(cd, 0, "user"), "VK was not linked to session keyring after repeated activation.");
|
||||
OK_(crypt_deactivate(cd, CDEVICE_1));
|
||||
NOTFAIL_(_kernel_key_by_segment_and_type(cd, 0, "user"), "VK was not linked to session keyring after deactivation.");
|
||||
OK_(_drop_keyring_key_from_keyring_type(cd, 0, KEY_SPEC_SESSION_KEYRING, "user"));
|
||||
FAIL_(_kernel_key_by_segment_and_type(cd, 0, "user"), "failed to unlink the key from session keyring");
|
||||
|
||||
// change key type to default (logon)
|
||||
crypt_set_vk_keyring_type(cd, NULL);
|
||||
OK_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, PASSPHRASE, strlen(PASSPHRASE), 0));
|
||||
NOTFAIL_(_kernel_key_by_segment_and_type(cd, 0, "logon"), "VK was not linked to session keyring after resetting key type.");
|
||||
OK_(crypt_deactivate(cd, CDEVICE_1));
|
||||
NOTFAIL_(_kernel_key_by_segment_and_type(cd, 0, "logon"), "VK was not linked to session keyring after deactivation.");
|
||||
OK_(_drop_keyring_key_from_keyring_type(cd, 0, KEY_SPEC_SESSION_KEYRING, "logon"));
|
||||
FAIL_(_kernel_key_by_segment_and_type(cd, 0, "user"), "failed to unlink the key from session keyring");
|
||||
|
||||
// disable linking to session keyring
|
||||
crypt_set_keyring_to_link(cd, NULL);
|
||||
OK_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, PASSPHRASE, strlen(PASSPHRASE), 0));
|
||||
NOTFAIL_(_kernel_key_by_segment_and_type(cd, 0, "logon"), "VK was not found in thread keyring");
|
||||
OK_(crypt_deactivate(cd, CDEVICE_1));
|
||||
FAIL_(_kernel_key_by_segment_and_type(cd, 0, "logon"), "failed to unlink the key from thread keyring");
|
||||
|
||||
// link VK to keyring and re-activate by the linked VK
|
||||
crypt_set_vk_keyring_type(cd, "user");
|
||||
crypt_set_keyring_to_link(cd, "@s");
|
||||
OK_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, PASSPHRASE, strlen(PASSPHRASE), 0));
|
||||
NOTFAIL_(_kernel_key_by_segment_and_type(cd, 0, "user"), "VK was not linked to session keyring.");
|
||||
OK_(crypt_deactivate(cd, CDEVICE_1));
|
||||
OK_(snprintf(key_description, sizeof(key_description), "%%user:cryptsetup:%s-d0", crypt_get_uuid(cd)) < 1);
|
||||
OK_(crypt_keyslot_context_init_by_vk_in_keyring(cd, key_description, &kc));
|
||||
EQ_(crypt_activate_by_keyslot_context(cd, CDEVICE_1, CRYPT_ANY_SLOT, kc, 0), 0);
|
||||
OK_(crypt_deactivate(cd, CDEVICE_1));
|
||||
NOTFAIL_(_kernel_key_by_segment_and_type(cd, 0, "user"), "VK was not linked to session keyring after deactivation.");
|
||||
OK_(_drop_keyring_key_from_keyring_type(cd, 0, KEY_SPEC_SESSION_KEYRING, "user"));
|
||||
FAIL_(crypt_activate_by_keyslot_context(cd, CDEVICE_1, CRYPT_ANY_SLOT, kc, 0), "activation via VK in keyring after dropping the key");
|
||||
|
||||
// load VK back to keyring by activating
|
||||
OK_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, PASSPHRASE, strlen(PASSPHRASE), 0));
|
||||
OK_(crypt_deactivate(cd, CDEVICE_1));
|
||||
|
||||
// activate by bad VK in keyring (test if VK digest is verified)
|
||||
NOTFAIL_((linked_kid = _kernel_key_by_segment_and_type(cd, 0, "user")), "VK was not linked to session keyring after activation.");
|
||||
GE_((vk_len = keyctl_read(linked_kid, vk_buf, sizeof(vk_buf))), 0);
|
||||
vk_buf[0] = ~vk_buf[0];
|
||||
OK_(keyctl_update(linked_kid, vk_buf, vk_len));
|
||||
FAIL_(crypt_activate_by_keyslot_context(cd, CDEVICE_1, CRYPT_ANY_SLOT, kc, 0), 0);
|
||||
OK_(_drop_keyring_key_from_keyring_type(cd, 0, KEY_SPEC_SESSION_KEYRING, "user"));
|
||||
crypt_keyslot_context_free(kc);
|
||||
|
||||
// After this point put resume tests only!
|
||||
OK_(crypt_keyslot_context_init_by_passphrase(cd, PASSPHRASE, strlen(PASSPHRASE), &kc));
|
||||
EQ_(crypt_activate_by_keyslot_context(cd, CDEVICE_1, CRYPT_ANY_SLOT, kc, 0), 0);
|
||||
suspend_status = crypt_suspend(cd, CDEVICE_1);
|
||||
@@ -5237,9 +5337,29 @@ static void KeyslotContext(void)
|
||||
OK_(crypt_deactivate(cd, CDEVICE_1));
|
||||
crypt_keyslot_context_free(kc);
|
||||
|
||||
// resume by VK keyring context
|
||||
crypt_set_vk_keyring_type(cd, "user");
|
||||
crypt_set_keyring_to_link(cd, "@s");
|
||||
OK_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, PASSPHRASE, strlen(PASSPHRASE), 0));
|
||||
NOTFAIL_(_kernel_key_by_segment_and_type(cd, 0, "user"), "VK was not linked to session keyring.");
|
||||
OK_(crypt_suspend(cd, CDEVICE_1));
|
||||
OK_(snprintf(key_description, sizeof(key_description), "%%user:cryptsetup:%s-d0", crypt_get_uuid(cd)) < 1);
|
||||
OK_(crypt_keyslot_context_init_by_vk_in_keyring(cd, key_description, &kc));
|
||||
EQ_(crypt_resume_by_keyslot_context(cd, CDEVICE_1, CRYPT_ANY_SLOT, kc), 0);
|
||||
OK_(crypt_deactivate(cd, CDEVICE_1));
|
||||
EQ_(crypt_activate_by_keyslot_context(cd, CDEVICE_1, CRYPT_ANY_SLOT, kc, 0), 0);
|
||||
OK_(crypt_deactivate(cd, CDEVICE_1));
|
||||
NOTFAIL_(_kernel_key_by_segment_and_type(cd, 0, "user"), "VK was not linked to session keyring after deactivation.");
|
||||
OK_(_drop_keyring_key_from_keyring_type(cd, 0, KEY_SPEC_SESSION_KEYRING, "user"));
|
||||
FAIL_(crypt_activate_by_keyslot_context(cd, CDEVICE_1, CRYPT_ANY_SLOT, kc, 0), "activation via VK in keyring after dropping the key");
|
||||
crypt_keyslot_context_free(kc);
|
||||
|
||||
NOTFAIL_(keyctl_unlink(kid, KEY_SPEC_THREAD_KEYRING), "Test or kernel keyring are broken.");
|
||||
CRYPT_FREE(cd);
|
||||
_cleanup_dmdevices();
|
||||
#else
|
||||
printf("WARNING: cryptsetup compiled with kernel keyring service disabled, skipping test.\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
static int _crypt_load_check(struct crypt_device *_cd)
|
||||
@@ -5369,7 +5489,7 @@ int main(int argc, char *argv[])
|
||||
#endif
|
||||
RUN_(LuksKeyslotAdd, "Adding keyslot via new API");
|
||||
RUN_(VolumeKeyGet, "Getting volume key via keyslot context API");
|
||||
RUN_(KeyslotContext, "Activate via keyslot context API");
|
||||
RUN_(KeyslotContextAndKeyringLink, "Activate via keyslot context API and linking VK to a keyring");
|
||||
RUN_(Luks2Repair, "LUKS2 repair"); // test disables metadata locking. Run always last!
|
||||
|
||||
_cleanup();
|
||||
|
||||
@@ -287,6 +287,23 @@ function add_scsi_device() {
|
||||
[ -b $DEV ] || fail "Cannot find $DEV."
|
||||
}
|
||||
|
||||
# $1 key name
|
||||
# $2 keyring to link VK to
|
||||
# $3 key type (optional)
|
||||
test_vk_link() {
|
||||
KEY_TYPE=${3:-logon}
|
||||
KEY_TYPE_ARG=""
|
||||
if [ ! -z "$3" ]; then
|
||||
KEY_TYPE_ARG="--volume-key-type $3"
|
||||
fi
|
||||
|
||||
echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --link-vk-to-keyring "$2" $KEY_TYPE_ARG || fail
|
||||
keyctl search "$2" $KEY_TYPE $1 > /dev/null 2>&1 || fail "VK is not linked to the specified keyring after activation."
|
||||
$CRYPTSETUP close $DEV_NAME
|
||||
keyctl search "$2" $KEY_TYPE $1 > /dev/null 2>&1 || fail "VK is not linked to the specified keyring after deactivation."
|
||||
keyctl unlink "%$KEY_TYPE:$1" "$2" || fail
|
||||
}
|
||||
|
||||
export LANG=C
|
||||
|
||||
[ ! -x "$CRYPTSETUP" ] && skip "Cannot find $CRYPTSETUP, test skipped."
|
||||
@@ -1215,5 +1232,49 @@ dmsetup create $DEV_NAME --uuid CRYPT-LUKS2-3d20686f551748cb89911ad32379821b-tes
|
||||
$CRYPTSETUP status $DEV_NAME | grep -q "n/a" || fail
|
||||
$CRYPTSETUP close $DEV_NAME ||fail
|
||||
|
||||
if [ $HAVE_KEYRING -gt 0 -a -d /proc/sys/kernel/keys ]; then
|
||||
prepare "[45] Link VK to a keyring and use custom VK type." wipe
|
||||
|
||||
echo $PWD1 | $CRYPTSETUP -q luksFormat $FAST_PBKDF_OPT --type luks2 $LOOPDEV 2> /dev/null || fail
|
||||
UUID=$($CRYPTSETUP luksDump $LOOPDEV | grep 'UUID:' | awk '{print $2}')
|
||||
KEY_NAME="cryptsetup:$UUID-d0"
|
||||
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
|
||||
KID=$(echo -n test | keyctl padd user my_token @us)
|
||||
keyctl unlink $KID >/dev/null 2>&1 @us && USER_SESSION_KEYRING_WORKS=1
|
||||
|
||||
|
||||
test_vk_link $KEY_NAME "@u"
|
||||
test_vk_link $KEY_NAME "@u" "user"
|
||||
[[ ! -z "$SESSION_KEYRING_WORKS" ]] && test_vk_link $KEY_NAME "@s"
|
||||
[[ ! -z "$SESSION_KEYRING_WORKS" ]] && test_vk_link $KEY_NAME "@s" "user"
|
||||
[[ ! -z "$USER_SESSION_KEYRING_WORKS" ]] && test_vk_link $KEY_NAME "@us"
|
||||
[[ ! -z "$USER_SESSION_KEYRING_WORKS" ]] && test_vk_link $KEY_NAME "@us" "user"
|
||||
test_vk_link $KEY_NAME "%:$TEST_KEYRING_NAME"
|
||||
test_vk_link $KEY_NAME "%:$TEST_KEYRING_NAME" "user"
|
||||
# explicitly specify keyring key type
|
||||
test_vk_link $KEY_NAME "%keyring:$TEST_KEYRING_NAME"
|
||||
|
||||
# test numeric keyring name -5 is user session (@us) keyring
|
||||
echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --link-vk-to-keyring -5 --volume-key-type logon || fail
|
||||
keyctl search @us logon $KEY_NAME > /dev/null 2>&1 || fail "VK is not linked to the specified keyring after activation."
|
||||
$CRYPTSETUP close $DEV_NAME
|
||||
keyctl search @us logon $KEY_NAME > /dev/null 2>&1 || fail "VK is not linked to the specified keyring after deactivation."
|
||||
keyctl unlink "%logon:$KEY_NAME" @us || fail
|
||||
|
||||
# test malformed keyring descriptions and key types
|
||||
echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --link-vk-to-keyring "%user:$TEST_KEYRING_NAME" > /dev/null 2>&1 && fail
|
||||
echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --link-vk-to-keyring "$TEST_KEYRING_NAME" > /dev/null 2>&1 && fail
|
||||
echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --link-vk-to-keyring "%$TEST_KEYRING_NAME" > /dev/null 2>&1 && fail
|
||||
echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --link-vk-to-keyring ":$TEST_KEYRING_NAME" > /dev/null 2>&1 && fail
|
||||
echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --link-vk-to-keyring "@uuu" > /dev/null 2>&1 && fail
|
||||
echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --link-vk-to-keyring "@usu" > /dev/null 2>&1 && fail
|
||||
|
||||
echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --volume-key-type 0 > /dev/null 2>&1 && fail
|
||||
echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --volume-key-type blah > /dev/null 2>&1 && fail
|
||||
echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --volume-key-type userlogon > /dev/null 2>&1 && fail
|
||||
fi
|
||||
|
||||
remove_mapping
|
||||
exit 0
|
||||
|
||||
Reference in New Issue
Block a user