Support trusted & encrypted keyring for plain device.

This commit is contained in:
Milan Broz
2024-11-22 14:05:40 +01:00
parent 42e85571df
commit 4b7920975c
7 changed files with 108 additions and 13 deletions

View File

@@ -64,6 +64,7 @@ struct volume_key *crypt_generate_volume_key(struct crypt_device *cd, size_t key
void crypt_free_volume_key(struct volume_key *vk);
int crypt_volume_key_set_description(struct volume_key *key,
const char *key_description, key_type_t keyring);
int crypt_volume_key_set_description_by_name(struct volume_key *vk, const char *key_name);
void crypt_volume_key_set_id(struct volume_key *vk, int id);
int crypt_volume_key_get_id(const struct volume_key *vk);
void crypt_volume_key_add_next(struct volume_key **vks, struct volume_key *vk);

View File

@@ -5336,7 +5336,14 @@ int crypt_activate_by_keyslot_context(struct crypt_device *cd,
} else if (isTCRYPT(cd->type)) {
r = 0;
} else if (name && isPLAIN(cd->type)) {
if (kc->get_passphrase && kc->type != CRYPT_KC_TYPE_TOKEN) {
if (kc->type == CRYPT_KC_TYPE_VK_KEYRING) {
vk = crypt_alloc_volume_key(cd->u.plain.key_size, NULL);
if (!vk)
return -ENOMEM;
r = crypt_volume_key_set_description_by_name(vk, kc->u.vk_kr.key_description);
if (r < 0)
log_err(cd, _("Cannot use keyring key %s."), kc->u.vk_kr.key_description);
} else if (kc->get_passphrase && kc->type != CRYPT_KC_TYPE_TOKEN) {
r = kc->get_passphrase(cd, kc, &passphrase, &passphrase_size);
if (r < 0)
return r;
@@ -7295,7 +7302,10 @@ int crypt_use_keyring_for_vk(struct crypt_device *cd)
uint32_t dmc_flags;
/* dm backend must be initialized */
if (!cd || !isLUKS2(cd->type))
if (!cd)
return 0;
if (!isPLAIN(cd->type) && !isLUKS2(cd->type))
return 0;
if (!_vk_via_keyring || !kernel_keyring_support())

View File

@@ -277,6 +277,36 @@ const char *key_type_name(key_type_t type)
return NULL;
}
key_type_t keyring_type_and_name(const char *key_name, const char **name)
{
char type[16], *name_tmp;
size_t type_len;
if (!key_name || key_name[0] != '%')
return INVALID_KEY;
key_name++;
if (!*key_name || *key_name == ':')
return INVALID_KEY;
name_tmp = strchr(key_name, ':');
if (!name_tmp)
return INVALID_KEY;
name_tmp++;
type_len = name_tmp - key_name - 1;
if (type_len >= sizeof(type) - 1)
return INVALID_KEY;
memcpy(type, key_name, type_len);
type[type_len] = '\0';
if (name)
*name = name_tmp;
return key_type_by_name(type);
}
key_serial_t keyring_find_key_id_by_name(const char *key_name)
{
key_serial_t id = 0;
@@ -425,6 +455,11 @@ const char *key_type_name(key_type_t type)
return NULL;
}
key_type_t keyring_type_and_name(const char *key_name, const char **name)
{
return INVALID_KEY;
}
key_serial_t keyring_find_key_id_by_name(const char *key_name)
{
return 0;

View File

@@ -21,6 +21,7 @@ typedef enum { LOGON_KEY = 0, USER_KEY, BIG_KEY, TRUSTED_KEY, ENCRYPTED_KEY, INV
const char *key_type_name(key_type_t ktype);
key_type_t key_type_by_name(const char *name);
key_type_t keyring_type_and_name(const char *key_name, const char **name);
key_serial_t keyring_find_key_id_by_name(const char *key_name);
key_serial_t keyring_find_keyring_id_by_name(const char *keyring_name);

View File

@@ -57,6 +57,17 @@ int crypt_volume_key_set_description(struct volume_key *vk,
return 0;
}
int crypt_volume_key_set_description_by_name(struct volume_key *vk, const char *key_name)
{
const char *key_description = NULL;
key_type_t keyring = keyring_type_and_name(key_name, &key_description);
if (keyring == INVALID_KEY)
return -EINVAL;
return crypt_volume_key_set_description(vk, key_description, keyring);
}
void crypt_volume_key_set_id(struct volume_key *vk, int id)
{
if (vk && id >= 0)

View File

@@ -42,18 +42,35 @@ create <name> <device> (*OBSOLETE syntax*)
Opens (creates a mapping with) <name> backed by device <device>.
*WARNING:* You should always specify options *--cipher*, *--key-size* and
(if no keyfile is used) then also *--hash* to avoid incompatibility as
(if no keyfile or keyring is used) then also *--hash* to avoid incompatibility as
default values can be different in older cryptsetup versions. +
The plain format also allows retrieving a volume key from a kernel keyring
specified by *--volume-key-keyring*. Key in kernel keyring must be configured
before issuing cryptsetup commands, as cryptsetup does not upload any keys to
the keyring in plain mode. For subsequent commands (like resize), the user must
ensure that the key in the keyring is unchanged. Otherwise, reloading the key
can cause data corruption after an unexpected key change.
*<options>* can be [--hash, --cipher, --verify-passphrase, --sector-size,
--key-file, --keyfile-size, --keyfile-offset, --key-size, --offset,
--skip, --device-size, --size, --readonly, --shared, --allow-discards,
--refresh, --timeout, --verify-passphrase, --iv-large-sectors].
--refresh, --timeout, --verify-passphrase, --iv-large-sectors, --volume-key-keyring].
Example: 'cryptsetup open --type plain --cipher aes-cbc-essiv:sha256 --key-size 256 --hash sha256 /dev/sda10 e1' maps the raw
encrypted device /dev/sda10 to the mapped (decrypted) device
/dev/mapper/e1, which can then be mounted, fsck-ed or have a filesystem
created on it.
*EXAMPLES:*
To map the encrypted device /dev/sda10 to the decrypted device /dev/mapper/e1, you can use
*cryptsetup open --type plain --cipher aes-cbc-essiv:sha256 --key-size 256 --hash sha256 /dev/sda10 e1*
The decrypted device can then be used as a normal block device to mount a filesystem.
To map a device with a volume key in the preconfigured trusted or encrypted keyring, you need to specify
keyring with the key and remove hash specification, for example, to use *%trusted:mykey*:
*cryptsetup open --type plain /dev/sda10 e1 --volume-key-keyring=%trusted:mykey --cipher aes-xts-plain64 --key-size 256*
Note that the key size must match the preconfigured key in the keyring.
=== LUKS
*open <device> <name>* +

View File

@@ -224,7 +224,8 @@ static int action_open_plain(void)
.offset = ARG_UINT64(OPT_OFFSET_ID),
.sector_size = ARG_UINT32(OPT_SECTOR_SIZE_ID) ?: SECTOR_SIZE
};
char *password = NULL;
struct crypt_keyslot_context *kc = NULL;
char *password = NULL, *vk_description_activation = NULL;
const char *activated_name = NULL;
size_t passwordLen, key_size_max, signatures = 0,
key_size = (ARG_UINT32(OPT_KEY_SIZE_ID) ?: DEFAULT_PLAIN_KEYBITS) / 8;
@@ -249,12 +250,12 @@ static int action_open_plain(void)
cipher, cipher_mode, key_size * 8);
compat_warning = true;
}
if (!ARG_SET(OPT_HASH_ID) && !ARG_SET(OPT_KEY_FILE_ID)) {
if (!ARG_SET(OPT_HASH_ID) && !ARG_SET(OPT_KEY_FILE_ID) && !ARG_SET(OPT_VOLUME_KEY_KEYRING_ID)) {
log_err(_("WARNING: Using default options for hash (%s) that could be incompatible with older versions."), params.hash);
compat_warning = true;
}
if (compat_warning)
log_err(_("For plain mode, always use options --cipher, --key-size and if no keyfile is used, then also --hash."));
log_err(_("For plain mode, always use options --cipher, --key-size and if no keyfile or keyring is used, then also --hash."));
/* FIXME: temporary hack, no hashing for keyfiles in plain mode */
if (ARG_SET(OPT_KEY_FILE_ID) && !tools_is_stdin(ARG_STR(OPT_KEY_FILE_ID))) {
@@ -264,6 +265,12 @@ static int action_open_plain(void)
"in plain mode with keyfile specified.\n"));
}
if (ARG_SET(OPT_VOLUME_KEY_KEYRING_ID)) {
r = tools_parse_vk_description(ARG_STR(OPT_VOLUME_KEY_KEYRING_ID), &vk_description_activation);
if (r < 0)
goto out;
}
if (params.hash && !strcmp(params.hash, "plain"))
params.hash = NULL;
@@ -349,7 +356,14 @@ static int action_open_plain(void)
set_activation_flags(&activate_flags);
if (!tools_is_stdin(ARG_STR(OPT_KEY_FILE_ID))) {
if (ARG_SET(OPT_VOLUME_KEY_KEYRING_ID)) {
r = crypt_keyslot_context_init_by_vk_in_keyring(cd, vk_description_activation, &kc);
if (r < 0)
goto out;
r = crypt_activate_by_keyslot_context(cd, activated_name, CRYPT_ANY_SLOT,
kc, CRYPT_ANY_SLOT, NULL, activate_flags | CRYPT_ACTIVATE_KEYRING_KEY);
} else if (!tools_is_stdin(ARG_STR(OPT_KEY_FILE_ID))) {
/* If no hash, key is read directly, read size is always key_size
* (possible --keyfile_size is ignored.
* If hash is specified, --keyfile_size is applied.
@@ -372,6 +386,8 @@ static int action_open_plain(void)
CRYPT_ANY_SLOT, password, passwordLen, activate_flags);
}
out:
free(vk_description_activation);
crypt_keyslot_context_free(kc);
crypt_free(cd);
crypt_free(cd1);
crypt_safe_free(password);
@@ -3336,7 +3352,7 @@ static const char *verify_tcryptdump(void)
return NULL;
}
static const char * verify_open(void)
static const char *verify_open(void)
{
if (ARG_SET(OPT_PERSISTENT_ID) && ARG_SET(OPT_TEST_PASSPHRASE_ID))
return _("Option --persistent is not allowed with --test-passphrase.");
@@ -3378,6 +3394,10 @@ static const char * verify_open(void)
if (ARG_SET(OPT_UNBOUND_ID) && !ARG_SET(OPT_TEST_PASSPHRASE_ID))
return _("Option --unbound cannot be used without --test-passphrase.");
if (ARG_SET(OPT_VOLUME_KEY_KEYRING_ID) && (ARG_SET(OPT_HASH_ID) ||
ARG_SET(OPT_VOLUME_KEY_FILE_ID)) && !strcmp_or_null(device_type, "plain"))
return _("Option --volume-key-keyring cannot be combined with --hash or --volume-key-file.");
/* "open --type tcrypt" and "tcryptDump" checks are identical */
return verify_tcryptdump();
}