mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-17 13:50:06 +01:00
Allow activation, resume and luksAddKey using VK stored in keyring.
Add --volume-key-keyring option, which takes a name of a key in keyring, which will be used as a VK during device activation. The key can be specified in keyctl-compatible syntax "%<key_type>:<key_name>".
This commit is contained in:
@@ -235,6 +235,17 @@ partially predictable volume key which will compromise security.
|
||||
endif::[]
|
||||
endif::[]
|
||||
|
||||
ifdef::ACTION_OPEN,ACTION_LUKSRESUME,ACTION_LUKSADDKEY[]
|
||||
*--volume-key-keyring* _<key description>_::
|
||||
Use a volume key stored in a keyring.
|
||||
This allows one to open _luks_ and device types without giving a passphrase.
|
||||
The volume key has to be of user type, in order to validate the digest.
|
||||
+
|
||||
The _<key description>_ uses keyctl-compatible syntax. This can either be a
|
||||
numeric key ID or a string name in the format _%<key type>:<key name>_. See
|
||||
also *KEY IDENTIFIERS* section of *keyctl*(1).
|
||||
endif::[]
|
||||
|
||||
ifdef::ACTION_LUKSDUMP[]
|
||||
*--dump-json-metadata*::
|
||||
For _luksDump_ (LUKS2 only) this option prints content of LUKS2 header
|
||||
|
||||
@@ -19,9 +19,9 @@ cryptsetup-luksAddKey - add a new passphrase
|
||||
Adds a keyslot protected by a new passphrase. An existing passphrase
|
||||
must be supplied interactively, via --key-file or LUKS2 token (plugin).
|
||||
Alternatively to existing passphrase user may pass directly volume key
|
||||
(via --volume-key-file). The new passphrase to be added can be specified
|
||||
interactively, read from the file given as the positional argument (also
|
||||
via --new-keyfile parameter) or via LUKS2 token.
|
||||
(via --volume-key-file or --volume-key-keyring). The new passphrase to be added
|
||||
can be specified interactively, read from the file given as the positional
|
||||
argument (also via --new-keyfile parameter) or via LUKS2 token.
|
||||
|
||||
*NOTE:* with --unbound option the action creates new unbound LUKS2
|
||||
keyslot. The keyslot cannot be used for device activation. If you don't
|
||||
@@ -34,11 +34,11 @@ algorithm is always the same for all keyslots.
|
||||
|
||||
*<options>* can be [--key-file, --keyfile-offset, --keyfile-size,
|
||||
--new-keyfile, --new-keyfile-offset, --new-keyfile-size, --key-slot,
|
||||
--new-key-slot, --volume-key-file, --force-password, --hash, --header,
|
||||
--disable-locks, --iter-time, --pbkdf, --pbkdf-force-iterations,
|
||||
--pbkdf-memory, --pbkdf-parallel, --unbound, --type, --keyslot-cipher,
|
||||
--keyslot-key-size, --key-size, --timeout, --token-id, --token-type,
|
||||
--token-only, --new-token-id, --verify-passphrase].
|
||||
--new-key-slot, --volume-key-file, --volume-key-keyring, --force-password,
|
||||
--hash, --header, --disable-locks, --iter-time, --pbkdf,
|
||||
--pbkdf-force-iterations, --pbkdf-memory, --pbkdf-parallel, --unbound, --type,
|
||||
--keyslot-cipher, --keyslot-key-size, --key-size, --timeout, --token-id,
|
||||
--token-type, --token-only, --new-token-id, --verify-passphrase].
|
||||
|
||||
include::man/common_options.adoc[]
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ interactively for a passphrase if no token is usable (LUKS2 only) or
|
||||
*<options>* can be [--key-file, --keyfile-size, --keyfile-offset,
|
||||
--key-slot, --header, --disable-keyring, --disable-locks, --token-id,
|
||||
--token-only, --token-type, --disable-external-tokens, --type, --tries,
|
||||
--timeout, --verify-passphrase].
|
||||
--timeout, --verify-passphrase, --volume-key-keyring].
|
||||
|
||||
include::man/common_options.adoc[]
|
||||
include::man/common_footer.adoc[]
|
||||
|
||||
@@ -74,7 +74,7 @@ matching PIN protected token.
|
||||
--volume-key-file, --token-id, --token-only, --token-type,
|
||||
--disable-external-tokens, --disable-keyring, --disable-locks, --type,
|
||||
--refresh, --serialize-memory-hard-pbkdf, --unbound, --tries, --timeout,
|
||||
--verify-passphrase, --persistent].
|
||||
--verify-passphrase, --persistent, --volume-key-keyring].
|
||||
|
||||
=== loopAES
|
||||
*open --type loopaes <device> <name> --key-file <keyfile>* +
|
||||
|
||||
@@ -1616,6 +1616,7 @@ static int action_open_luks(void)
|
||||
char *password = NULL;
|
||||
size_t passwordLen;
|
||||
struct stat st;
|
||||
struct crypt_keyslot_context *kc = NULL;
|
||||
|
||||
if (ARG_SET(OPT_REFRESH_ID)) {
|
||||
activated_name = action_argc > 1 ? action_argv[1] : action_argv[0];
|
||||
@@ -1683,6 +1684,13 @@ static int action_open_luks(void)
|
||||
goto out;
|
||||
r = crypt_activate_by_volume_key(cd, activated_name,
|
||||
key, keysize, activate_flags);
|
||||
} else if (ARG_SET(OPT_VOLUME_KEY_KEYRING_ID)) {
|
||||
r = crypt_keyslot_context_init_by_vk_in_keyring(cd, ARG_STR(OPT_VOLUME_KEY_KEYRING_ID), &kc);
|
||||
if (r)
|
||||
goto out;
|
||||
r = crypt_activate_by_keyslot_context(cd, activated_name, CRYPT_ANY_SLOT, kc, activate_flags);
|
||||
if (r)
|
||||
goto out;
|
||||
} else {
|
||||
r = crypt_activate_by_token_pin(cd, activated_name, ARG_STR(OPT_TOKEN_TYPE_ID),
|
||||
ARG_INT32(OPT_TOKEN_ID_ID), NULL, 0, NULL, activate_flags);
|
||||
@@ -1719,6 +1727,7 @@ out:
|
||||
(crypt_get_active_device(cd, activated_name, &cad) ||
|
||||
crypt_persistent_flags_set(cd, CRYPT_FLAGS_ACTIVATION, cad.flags & activate_flags)))
|
||||
log_err(_("Device activated but cannot make flags persistent."));
|
||||
crypt_keyslot_context_free(kc);
|
||||
|
||||
crypt_safe_free(key);
|
||||
crypt_safe_free(password);
|
||||
@@ -2082,6 +2091,8 @@ static int action_luksAddKey(void)
|
||||
ARG_UINT32(OPT_KEYFILE_SIZE_ID),
|
||||
ARG_UINT64(OPT_KEYFILE_OFFSET_ID),
|
||||
&kc);
|
||||
else if (ARG_SET(OPT_VOLUME_KEY_KEYRING_ID))
|
||||
r = crypt_keyslot_context_init_by_vk_in_keyring(cd, ARG_STR(OPT_VOLUME_KEY_KEYRING_ID), &kc);
|
||||
else if (ARG_SET(OPT_TOKEN_ID_ID) || ARG_SET(OPT_TOKEN_TYPE_ID) || ARG_SET(OPT_TOKEN_ONLY_ID)) {
|
||||
r = crypt_keyslot_context_init_by_token(cd,
|
||||
ARG_INT32(OPT_TOKEN_ID_ID),
|
||||
@@ -2516,6 +2527,7 @@ static int action_luksResume(void)
|
||||
int r, tries;
|
||||
struct crypt_active_device cad;
|
||||
const char *req_type = luksType(device_type);
|
||||
struct crypt_keyslot_context *kc = NULL;
|
||||
|
||||
if (req_type && !isLUKS(req_type))
|
||||
return -EINVAL;
|
||||
@@ -2573,6 +2585,14 @@ static int action_luksResume(void)
|
||||
if (r >= 0 || quit || ARG_SET(OPT_TOKEN_ONLY_ID))
|
||||
goto out;
|
||||
|
||||
if (ARG_SET(OPT_VOLUME_KEY_KEYRING_ID)) {
|
||||
r = crypt_keyslot_context_init_by_vk_in_keyring(cd, ARG_STR(OPT_VOLUME_KEY_KEYRING_ID), &kc);
|
||||
if (r)
|
||||
goto out;
|
||||
r = crypt_resume_by_keyslot_context(cd, action_argv[0], CRYPT_ANY_SLOT, kc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
tries = set_tries_tty();
|
||||
do {
|
||||
r = tools_get_key(NULL, &password, &passwordLen,
|
||||
@@ -2591,6 +2611,7 @@ static int action_luksResume(void)
|
||||
password = NULL;
|
||||
} while ((r == -EPERM || r == -ERANGE) && (--tries > 0));
|
||||
out:
|
||||
crypt_keyslot_context_free(kc);
|
||||
crypt_safe_free(password);
|
||||
crypt_free(cd);
|
||||
return r;
|
||||
|
||||
@@ -119,6 +119,8 @@ ARG(OPT_LUKS2_METADATA_SIZE, '\0', POPT_ARG_STRING, N_("LUKS2 header metadata ar
|
||||
|
||||
ARG(OPT_VOLUME_KEY_FILE, '\0', POPT_ARG_STRING, N_("Use the volume key from file."), NULL, CRYPT_ARG_STRING, {}, {})
|
||||
|
||||
ARG(OPT_VOLUME_KEY_KEYRING, '\0', POPT_ARG_STRING, N_("Use the specified keyring key as a volume key."), NULL, CRYPT_ARG_STRING, {}, {})
|
||||
|
||||
ARG(OPT_VOLUME_KEY_TYPE, '\0', POPT_ARG_STRING, N_("Specify the type of the volume key stored in keyring"), NULL, CRYPT_ARG_STRING, {}, {})
|
||||
|
||||
ARG(OPT_NEW_KEYFILE, '\0', POPT_ARG_STRING, N_("Read the key for a new slot from a file"), NULL, CRYPT_ARG_STRING, {}, OPT_NEW_KEYFILE_ACTIONS)
|
||||
|
||||
@@ -110,6 +110,7 @@
|
||||
#define OPT_LUKS2_METADATA_SIZE "luks2-metadata-size"
|
||||
#define OPT_MASTER_KEY_FILE "master-key-file"
|
||||
#define OPT_VOLUME_KEY_FILE "volume-key-file"
|
||||
#define OPT_VOLUME_KEY_KEYRING "volume-key-keyring"
|
||||
#define OPT_VOLUME_KEY_TYPE "volume-key-type"
|
||||
#define OPT_NEW "new"
|
||||
#define OPT_NEW_KEY_SLOT "new-key-slot"
|
||||
|
||||
@@ -304,6 +304,40 @@ test_vk_link() {
|
||||
keyctl unlink "%$KEY_TYPE:$1" "$2" || fail
|
||||
}
|
||||
|
||||
# $1 key name
|
||||
# $2 keyring to link VK to
|
||||
# $3 key type (optional)
|
||||
test_vk_link_and_reactivate() {
|
||||
KEY_TYPE=${3:-logon}
|
||||
KEY_TYPE_ARG=""
|
||||
if [ ! -z "$3" ]; then
|
||||
KEY_TYPE_ARG="--volume-key-type $3"
|
||||
fi
|
||||
|
||||
LINKED_KEY_NAME="%$KEY_TYPE:$1"
|
||||
|
||||
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 || fail
|
||||
keyctl search "$2" $KEY_TYPE $1 > /dev/null 2>&1 || fail "VK is not linked to the specified keyring after deactivation."
|
||||
$CRYPTSETUP open $LOOPDEV $DEV_NAME --volume-key-keyring $LINKED_KEY_NAME || fail "Failed to unlock volume via a VK in keyring."
|
||||
$CRYPTSETUP luksSuspend $DEV_NAME || fail "Failed to suspend device."
|
||||
$CRYPTSETUP luksResume $DEV_NAME --volume-key-keyring $LINKED_KEY_NAME || fail "Failed to resume via a VK in keyring."
|
||||
|
||||
echo $PWD1 | $CRYPTSETUP luksOpen $LOOPDEV --test-passphrase 2>/dev/null || fail
|
||||
echo $PWD2 | $CRYPTSETUP luksOpen $LOOPDEV --test-passphrase 2>/dev/null && fail
|
||||
echo $PWD2 | $CRYPTSETUP luksAddKey $FAST_PBKDF2 --volume-key-keyring $LINKED_KEY_NAME $LOOPDEV --new-key-slot 1 || fail "Failed to add passphrase by VK in keyring."
|
||||
echo $PWD2 | $CRYPTSETUP luksOpen $LOOPDEV --test-passphrase 2>/dev/null || fail
|
||||
$CRYPTSETUP luksKillSlot -q $LOOPDEV 1 2>/dev/null || fail
|
||||
|
||||
$CRYPTSETUP close $DEV_NAME || fail
|
||||
# zero-out the key in keyring
|
||||
keyctl pipe $LINKED_KEY_NAME | tr -c '\0' '\0' | keyctl pupdate $LINKED_KEY_NAME
|
||||
$CRYPTSETUP open $LOOPDEV $DEV_NAME --volume-key-keyring $LINKED_KEY_NAME > /dev/null 2>&1 && fail "Unlocked volume via a bad VK in keyring."
|
||||
keyctl search "$2" $KEY_TYPE $1 > /dev/null 2>&1 || fail "VK is not linked to the specified keyring after bad activation."
|
||||
keyctl unlink "%$KEY_TYPE:$1" "$2" || fail
|
||||
}
|
||||
|
||||
export LANG=C
|
||||
|
||||
[ ! -x "$CRYPTSETUP" ] && skip "Cannot find $CRYPTSETUP, test skipped."
|
||||
@@ -1244,7 +1278,6 @@ if [ $HAVE_KEYRING -gt 0 -a -d /proc/sys/kernel/keys ]; then
|
||||
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"
|
||||
@@ -1256,6 +1289,13 @@ if [ $HAVE_KEYRING -gt 0 -a -d /proc/sys/kernel/keys ]; then
|
||||
# explicitly specify keyring key type
|
||||
test_vk_link $KEY_NAME "%keyring:$TEST_KEYRING_NAME"
|
||||
|
||||
test_vk_link_and_reactivate $KEY_NAME "@u" "user"
|
||||
[[ ! -z "$SESSION_KEYRING_WORKS" ]] && test_vk_link_and_reactivate $KEY_NAME "@s" "user"
|
||||
[[ ! -z "$USER_SESSION_KEYRING_WORKS" ]] && test_vk_link_and_reactivate $KEY_NAME "@us" "user"
|
||||
test_vk_link_and_reactivate $KEY_NAME "%:$TEST_KEYRING_NAME" "user"
|
||||
# explicitly specify keyring key type
|
||||
test_vk_link_and_reactivate $KEY_NAME "%keyring:$TEST_KEYRING_NAME" "user"
|
||||
|
||||
# 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."
|
||||
|
||||
Reference in New Issue
Block a user