Split logic for uploading keys in kernel key service.

We can not link internal VK kernel key in custom user
keyring. There are two reasons for it:

The internal VK kernel key description can not be
acquired via API and it may change over time
(LUKS2 reencryption).

With recent SED OPAL support volume key becomes a 'blob'
containing up to two keys (dm-crypt key for SWE and key
for unlocking SED OPAL locking range). The internal
kernel key contains only dm-crypt (if required) but
custom user keyring needs to be provided with whole
volume key (blob).

Added user specified key description for the linked key
in custom user keyring. The linked key can be reached by
the specified description after successful activation (resume).
This commit is contained in:
Ondrej Kozina
2023-09-13 13:41:44 +02:00
committed by Milan Broz
parent 7ae109dccd
commit 51a1e218cf
15 changed files with 541 additions and 274 deletions

View File

@@ -3073,14 +3073,27 @@ void *crypt_safe_realloc(void *data, size_t size);
void crypt_safe_memzero(void *data, size_t size);
/**
* Link the volume key to the specified keyring.
* Link the volume key to the specified kernel keyring.
*
* @param cd crypt device handle
* @param keyring_to_link_vk the ID of the keyring in which volume key should
* be linked, if @e NULL is specified, linking will be disabled (the key will
* be linked just to the thread keyring, which is destroyed on process exit)
* @param key_description the key description of volume key linked in desired keyring.
* @param key_type the key type used for the volume key. Currently only "user" and "logon" types are
* supported. if @e NULL is specified the default "user" type is applied.
* @param keyring_to_link_vk the keyring description of the keyring in which volume key should
* be linked, if @e NULL is specified, linking will be disabled.
*
* @note keyring_to_link_vk may be passed in various string formats:
* It can be kernel key numeric id of existing keyring written as a string,
* keyring name prefixed optionally be either "%:" or "%keyring:" substrings or keyctl
* special values for keyrings "@t", "@p", "@s" and so on. See keyctl(1) man page,
* section KEY IDENTIFIERS for more information. All other prefixes starting "%<type>:"
* are ignored.
*
* @note key_description "%<type>:" prefixes are ignored. Type is applied based on key_type parameter
* value.
*/
int crypt_set_keyring_to_link(struct crypt_device *cd, const char *keyring_to_link_vk);
int crypt_set_keyring_to_link(struct crypt_device *cd, const char *key_description,
const char *key_type_desc, const char *keyring_to_link_vk);
/**
* Set the type of volume key stored in keyring.

View File

@@ -545,7 +545,7 @@ static char *_uf(char *buf, size_t buf_size, const char *s, unsigned u)
}
/* https://gitlab.com/cryptsetup/cryptsetup/wikis/DMCrypt */
static char *get_dm_crypt_params(const struct dm_target *tgt, uint32_t flags, key_type_t key_type)
static char *get_dm_crypt_params(const struct dm_target *tgt, uint32_t flags)
{
int r, max_size, null_cipher = 0, num_options = 0, keystr_len = 0;
char *params = NULL, *hexkey = NULL;
@@ -602,8 +602,8 @@ static char *get_dm_crypt_params(const struct dm_target *tgt, uint32_t flags, ke
hexkey = crypt_safe_alloc(keystr_len);
if (!hexkey)
goto out;
r = snprintf(hexkey, keystr_len, ":%zu:%s:%s", tgt->u.crypt.vk->keylength,
key_type_name(key_type), tgt->u.crypt.vk->key_description);
r = snprintf(hexkey, keystr_len, ":%zu:logon:%s", tgt->u.crypt.vk->keylength,
tgt->u.crypt.vk->key_description);
if (r < 0 || r >= keystr_len)
goto out;
} else
@@ -1247,14 +1247,14 @@ static void _destroy_dm_targets_params(struct crypt_dm_active_device *dmd)
} while (t);
}
static int _create_dm_targets_params(struct crypt_dm_active_device *dmd, key_type_t key_type)
static int _create_dm_targets_params(struct crypt_dm_active_device *dmd)
{
int r;
struct dm_target *tgt = &dmd->segment;
do {
if (tgt->type == DM_CRYPT)
tgt->params = get_dm_crypt_params(tgt, dmd->flags, key_type);
tgt->params = get_dm_crypt_params(tgt, dmd->flags);
else if (tgt->type == DM_VERITY)
tgt->params = get_dm_verity_params(tgt, dmd->flags);
else if (tgt->type == DM_INTEGRITY)
@@ -1312,7 +1312,7 @@ static int _dm_create_device(struct crypt_device *cd, const char *name, const ch
if ((dmd->flags & CRYPT_ACTIVATE_READONLY) && !dm_task_set_ro(dmt))
goto out;
r = _create_dm_targets_params(dmd, key_type_by_name(crypt_get_vk_keyring_type(cd)));
r = _create_dm_targets_params(dmd);
if (r)
goto out;
@@ -1424,7 +1424,7 @@ static int _dm_reload_device(struct crypt_device *cd, const char *name,
if ((dmd->flags & CRYPT_ACTIVATE_READONLY) && !dm_task_set_ro(dmt))
goto out;
r = _create_dm_targets_params(dmd, key_type_by_name(crypt_get_vk_keyring_type(cd)));
r = _create_dm_targets_params(dmd);
if (r)
goto out;
@@ -1907,7 +1907,7 @@ static int _dm_target_query_crypt(struct crypt_device *cd, uint32_t get_flags,
int r;
size_t key_size;
struct device *data_device = NULL;
char *cipher = NULL, *integrity = NULL, *key_type = NULL;
char *cipher = NULL, *integrity = NULL;
struct volume_key *vk = NULL;
tgt->type = DM_CRYPT;
@@ -2026,16 +2026,12 @@ static int _dm_target_query_crypt(struct crypt_device *cd, uint32_t get_flags,
/* :<key_size>:<key_type>:<key_description> */
key_desc = NULL;
endp = strpbrk(key_ + 1, ":");
key_type = endp + 1;
if (endp)
key_desc = strpbrk(endp + 1, ":");
if (!key_desc) {
r = -ENOMEM;
goto err;
}
/* replace colon with zero character */
key_desc[0] = '\0';
key_desc++;
crypt_volume_key_set_description(vk, key_desc);
} else {
@@ -2061,8 +2057,6 @@ static int _dm_target_query_crypt(struct crypt_device *cd, uint32_t get_flags,
tgt->data_device = data_device;
if (vk)
tgt->u.crypt.vk = vk;
if (key_type)
crypt_set_vk_keyring_type(cd, key_type);
return 0;
err:
free(cipher);
@@ -3001,8 +2995,8 @@ int dm_resume_and_reinstate_key(struct crypt_device *cd, const char *name,
}
if (vk->key_description) {
r = snprintf(msg, msg_size, "key set :%zu:%s:%s", vk->keylength,
crypt_get_vk_keyring_type(cd), vk->key_description);
r = snprintf(msg, msg_size, "key set :%zu:logon:%s", vk->keylength,
vk->key_description);
} else {
key = crypt_bytes_to_hex(vk->keylength, vk->key);
if (!key) {

View File

@@ -2865,7 +2865,7 @@ int LUKS2_deactivate(struct crypt_device *cd, const char *name, struct luks2_hdr
while (tgt) {
if (tgt->type == DM_CRYPT)
crypt_drop_keyring_key_by_description(cd, tgt->u.crypt.vk->key_description,
key_type_by_name(crypt_get_vk_keyring_type(cd)));
LOGON_KEY);
tgt = tgt->next;
}
}
@@ -2901,7 +2901,7 @@ int LUKS2_deactivate(struct crypt_device *cd, const char *name, struct luks2_hdr
while (tgt) {
if (tgt->type == DM_CRYPT)
crypt_drop_keyring_key_by_description(cd, tgt->u.crypt.vk->key_description,
key_type_by_name(crypt_get_vk_keyring_type(cd)));
LOGON_KEY);
tgt = tgt->next;
}
}

View File

@@ -62,6 +62,7 @@ struct crypt_device {
bool link_vk_to_keyring;
int32_t keyring_to_link_vk;
const char *user_key_name;
key_type_t keyring_key_type;
uint64_t data_offset;
@@ -3993,6 +3994,26 @@ static int resume_luks1_by_volume_key(struct crypt_device *cd,
return r;
}
static int crypt_volume_key_load_in_user_keyring(struct crypt_device *cd, struct volume_key *vk)
{
int r;
const char *type_name = key_type_name(cd->keyring_key_type);
if (!vk || !cd || !type_name || !cd->link_vk_to_keyring)
return -EINVAL;
log_dbg(cd, "Linking volume key (%zu bytes, type %s, name %s) to the specified keyring",
vk->keylength, type_name, cd->user_key_name);
r = keyring_add_key_to_custom_keyring(cd->keyring_key_type, cd->user_key_name, vk->key, vk->keylength, cd->keyring_to_link_vk);
if (r) {
log_err(cd, _("Failed to link key to the specified keyring."));
log_dbg(cd, "The keyring_link_key_to_keyring function failed (error %d).", r);
}
return r;
}
static int resume_luks2_by_volume_key(struct crypt_device *cd,
int digest,
struct volume_key *vk,
@@ -4043,6 +4064,14 @@ static int resume_luks2_by_volume_key(struct crypt_device *cd,
r = LUKS2_volume_key_load_in_keyring_by_digest(cd, p_crypt, digest);
if (r < 0)
goto out;
/* upload volume key in custom keyring if requested */
if (cd->link_vk_to_keyring) {
r = crypt_volume_key_load_in_user_keyring(cd, vk);
if (r < 0)
/* FIXME: We should unlink VK from custom keyring on error */
goto out;
}
}
if (p_opal) {
@@ -4703,12 +4732,13 @@ static int _open_and_activate(struct crypt_device *cd,
if (r < 0)
goto out;
/* copy volume key digest id in crypt subkey */
crypt_volume_key_set_id(crypt_key, crypt_volume_key_get_id(vk));
p_crypt = crypt_key;
p_opal = opal_key ?: vk;
} else {
} else
p_crypt = vk;
p_opal = NULL;
}
if (!crypt_use_keyring_for_vk(cd) || !p_crypt)
use_keyring = false;
@@ -4722,6 +4752,14 @@ static int _open_and_activate(struct crypt_device *cd,
if (r < 0)
goto out;
flags |= CRYPT_ACTIVATE_KEYRING_KEY;
/* upload the volume key in custom user keyring if requested */
if (cd->link_vk_to_keyring) {
r = crypt_volume_key_load_in_user_keyring(cd, vk);
if (r < 0)
/* FIXME: We should unlink VK from custom keyring on error */
goto out;
}
}
if (name)
@@ -5314,6 +5352,14 @@ int crypt_activate_by_keyslot_context(struct crypt_device *cd,
if (r < 0)
goto out;
flags |= CRYPT_ACTIVATE_KEYRING_KEY;
/* upload the volume key in custom user keyring if requested */
if (cd->link_vk_to_keyring) {
r = crypt_volume_key_load_in_user_keyring(cd, vk);
if (r < 0)
/* FIXME: We should unlink VK from custom keyring on error */
goto out;
}
}
} else {
p_crypt = vk;
@@ -7184,9 +7230,8 @@ int crypt_volume_key_keyring(struct crypt_device *cd __attribute__((unused)), in
int crypt_volume_key_load_in_keyring(struct crypt_device *cd, struct volume_key *vk)
{
int r;
const char *type_name = key_type_name(cd->keyring_key_type);
if (!vk || !cd || !type_name)
if (!vk || !cd)
return -EINVAL;
if (!vk->key_description) {
@@ -7194,24 +7239,15 @@ int crypt_volume_key_load_in_keyring(struct crypt_device *cd, struct volume_key
return -EINVAL;
}
log_dbg(cd, "Loading key (%zu bytes, type %s) in thread keyring.", vk->keylength, type_name);
log_dbg(cd, "Loading key (%zu bytes, type logon, name %s) in thread keyring.", vk->keylength, vk->key_description);
r = keyring_add_key_in_thread_keyring(cd->keyring_key_type, vk->key_description, vk->key, vk->keylength);
r = keyring_add_key_in_thread_keyring(LOGON_KEY, vk->key_description, vk->key, vk->keylength);
if (r) {
log_dbg(cd, "keyring_add_key_in_thread_keyring failed (error %d)", r);
log_err(cd, _("Failed to load key in kernel keyring."));
} else
crypt_set_key_in_keyring(cd, 1);
if (!r && cd->link_vk_to_keyring) {
log_dbg(cd, "Linking volume key to the specified keyring");
r = keyring_link_key_to_keyring(cd->keyring_key_type, vk->key_description, cd->keyring_to_link_vk);
if (r) {
log_err(cd, _("Failed to link key to the specified keyring."));
log_dbg(cd, "The keyring_link_key_to_keyring function failed (error %d).", r);
}
}
return r;
}
@@ -7247,11 +7283,21 @@ void crypt_drop_keyring_key_by_description(struct crypt_device *cd, const char *
crypt_set_key_in_keyring(cd, 0);
}
int crypt_set_keyring_to_link(struct crypt_device *cd, const char *keyring_to_link_vk)
int crypt_set_keyring_to_link(struct crypt_device *cd, const char *key_description,
const char *key_type_description, const char *keyring_to_link_vk)
{
key_type_t key_type = USER_KEY;
const char *name = NULL;
int32_t id = 0;
if (!cd)
if (!cd || (!key_description && keyring_to_link_vk) ||
(key_description && !keyring_to_link_vk))
return -EINVAL;
if (key_type_description)
key_type = key_type_by_name(key_type_description);
if (key_type != LOGON_KEY && key_type != USER_KEY)
return -EINVAL;
if (keyring_to_link_vk) {
@@ -7260,8 +7306,14 @@ int crypt_set_keyring_to_link(struct crypt_device *cd, const char *keyring_to_li
log_err(cd, _("Could not find keyring described by \"%s\"."), keyring_to_link_vk);
return -EINVAL;
}
if (!(name = strdup(key_description)))
return -ENOMEM;
}
cd->keyring_key_type = key_type;
free(CONST_CAST(void*)cd->user_key_name);
cd->user_key_name = name;
cd->keyring_to_link_vk = id;
cd->link_vk_to_keyring = id != 0;

View File

@@ -20,9 +20,11 @@
*/
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -32,11 +34,6 @@
#include "libcryptsetup_macros.h"
#include "utils_keyring.h"
#ifndef HAVE_KEY_SERIAL_T
#define HAVE_KEY_SERIAL_T
typedef int32_t key_serial_t;
#endif
#ifdef KERNEL_KEYRING
static const struct {
@@ -213,7 +210,11 @@ int keyring_check(void)
return syscall(__NR_request_key, "logon", "dummy", NULL, 0) == -1l && errno != ENOSYS;
}
int keyring_add_key_in_thread_keyring(key_type_t ktype, const char *key_desc, const void *key, size_t key_size)
int keyring_add_key_in_keyring(key_type_t ktype,
const char *key_desc,
const void *key,
size_t key_size,
key_serial_t keyring)
{
key_serial_t kid;
const char *type_name = key_type_name(ktype);
@@ -221,27 +222,22 @@ int keyring_add_key_in_thread_keyring(key_type_t ktype, const char *key_desc, co
if (!type_name || !key_desc)
return -EINVAL;
kid = add_key(type_name, key_desc, key, key_size, KEY_SPEC_THREAD_KEYRING);
kid = add_key(type_name, key_desc, key, key_size, keyring);
if (kid < 0)
return -errno;
return 0;
}
int keyring_add_key_in_thread_keyring(key_type_t ktype, const char *key_desc, const void *key, size_t key_size)
{
return keyring_add_key_in_keyring(ktype, key_desc, key, key_size, KEY_SPEC_THREAD_KEYRING);
}
/* currently used in client utilities only */
int keyring_add_key_in_user_keyring(key_type_t ktype, const char *key_desc, const void *key, size_t key_size)
{
const char *type_name = key_type_name(ktype);
key_serial_t kid;
if (!type_name || !key_desc)
return -EINVAL;
kid = add_key(type_name, key_desc, key, key_size, KEY_SPEC_USER_KEYRING);
if (kid < 0)
return -errno;
return 0;
return keyring_add_key_in_keyring(ktype, key_desc, key, key_size, KEY_SPEC_USER_KEYRING);
}
int keyring_find_and_get_key_by_name(const char *key_name,
@@ -325,32 +321,6 @@ int keyring_get_user_key(const char *key_desc,
return 0;
}
static int keyring_link_key_to_keyring_key_type(const char *type_name, const char *key_desc,
key_serial_t keyring_to_link)
{
long r;
key_serial_t kid;
if (!type_name || !key_desc)
return -EINVAL;
do {
kid = request_key(type_name, key_desc, NULL, 0);
} while (kid < 0 && errno == EINTR);
if (kid < 0)
return -errno;
/* see https://mjg59.dreamwidth.org/37333.html */
if (keyring_to_link == KEY_SPEC_USER_KEYRING || keyring_to_link == KEY_SPEC_USER_SESSION_KEYRING)
keyctl_setperm(kid, KEY_POS_ALL | KEY_USR_ALL);
r = keyctl_link(kid, keyring_to_link);
if (r < 0)
return -errno;
return 0;
}
static int keyring_revoke_and_unlink_key_type(const char *type_name, const char *key_desc)
{
key_serial_t kid;
@@ -444,13 +414,26 @@ out:
return id;
}
static bool numbered(const char *str)
{
char *endp;
errno = 0;
(void) strtol(str, &endp, 0);
if (errno == ERANGE)
return false;
return *endp == '\0' ? true : false;
}
int32_t keyring_find_keyring_id_by_name(const char *keyring_name)
{
assert(keyring_name);
/* "%:" is abbreviation for the type keyring */
if ((keyring_name[0] == '@' && keyring_name[1] != 'a') ||
strstr(keyring_name, "%:") || strstr(keyring_name, "%keyring:"))
strstr(keyring_name, "%:") || strstr(keyring_name, "%keyring:") ||
numbered(keyring_name))
return keyring_find_key_id_by_name(keyring_name);
return 0;
@@ -467,9 +450,28 @@ key_type_t key_type_by_name(const char *name)
return INVALID_KEY;
}
int keyring_link_key_to_keyring(key_type_t ktype, const char *key_desc, key_serial_t keyring_to_link)
int keyring_add_key_to_custom_keyring(key_type_t ktype,
const char *key_desc,
const void *key,
size_t key_size,
key_serial_t keyring_to_link)
{
return keyring_link_key_to_keyring_key_type(key_type_name(ktype), key_desc, keyring_to_link);
key_serial_t kid;
const char *type_name = key_type_name(ktype);
if (!type_name || !key_desc)
return -EINVAL;
kid = add_key(type_name, key_desc, key, key_size, keyring_to_link);
if (kid < 0)
return -errno;
/* FIXME: could we delegate it to the caller? */
// see https://mjg59.dreamwidth.org/37333.html
if (keyring_to_link == KEY_SPEC_USER_KEYRING || keyring_to_link == KEY_SPEC_USER_SESSION_KEYRING)
keyctl_setperm(kid, KEY_POS_ALL | KEY_USR_ALL);
return 0;
}
int keyring_revoke_and_unlink_key(key_type_t ktype, const char *key_desc)
@@ -495,6 +497,13 @@ int keyring_add_key_in_user_keyring(key_type_t ktype, const char *key_desc, cons
return -ENOTSUP;
}
int keyring_find_and_get_key_by_name(const char *key_name,
char **key,
size_t *key_size)
{
return -ENOTSUP;
}
int keyring_read_by_id(const char *key_desc, char **passphrase, size_t *passphrase_len)
{
return -ENOTSUP;
@@ -525,7 +534,11 @@ key_type_t key_type_by_name(const char *name)
return INVALID_KEY;
}
int keyring_link_key_to_keyring(key_type_t ktype, const char *key_desc, key_serial_t keyring_to_link)
int keyring_add_key_to_custom_keyring(key_type_t ktype,
const char *key_desc,
const void *key,
size_t key_size,
key_serial_t keyring_to_link)
{
return -ENOTSUP;
}

View File

@@ -25,6 +25,11 @@
#include <stddef.h>
#include <stdint.h>
#ifndef HAVE_KEY_SERIAL_T
#define HAVE_KEY_SERIAL_T
typedef int32_t key_serial_t;
#endif
typedef enum { LOGON_KEY = 0, USER_KEY, BIG_KEY, TRUSTED_KEY, ENCRYPTED_KEY, INVALID_KEY } key_type_t;
const char *key_type_name(key_type_t ktype);
@@ -54,7 +59,15 @@ int keyring_add_key_in_user_keyring(
const void *key,
size_t key_size);
int keyring_add_key_in_keyring(
key_type_t ktype,
const char *key_desc,
const void *key,
size_t key_size,
key_serial_t keyring_id);
int keyring_revoke_and_unlink_key(key_type_t ktype, const char *key_desc);
int keyring_link_key_to_keyring(key_type_t ktype, const char *key_desc, int keyring_to_link);
int keyring_add_key_to_custom_keyring(key_type_t ktype, const char *key_desc, const void *key,
size_t key_size, key_serial_t keyring_to_link);
#endif

View File

@@ -239,11 +239,13 @@ 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 and associated type has to be readable from userspace so that volume
key digest may be verified in before activation.
+
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).
also *KEY IDENTIFIERS* section of *keyctl*(1). When no _%<key type>:_ prefix
is specified we assume the key type is _user_ (default type).
endif::[]
ifdef::ACTION_LUKSDUMP[]
@@ -812,6 +814,26 @@ ifdef::ACTION_TOKEN[]
Set key description in keyring for use with _token_ command.
endif::[]
ifdef::ACTION_OPEN,ACTION_LUKSRESUME[]
*--link-vk-to-keyring* _<keyring_description>::<key_description>_::
Link volume key in a keyring with specified key name. The volume key is linked only
if requested action is successfuly finished.
+
_<keyring_description>_ string has to contain existing kernel keyring
description. The keyring name may be optionaly prefixed with "%:" or "%keyring:" type descriptions.
Or, the keyring may also be specified directly by numeric key id. Also special keyring notations
starting with "@" may be used to select existing predefined kernel keyrings.
+
The string "::" is delimiter used to separate keyring description and key description.
+
_<key_description>_ part describes key type and key name of volume key linked in the keyring
described in _<keyring_description>_. The type may be specified by adding "%<type_name>:" prefix in front of
key name. If type is missing default _user_ type is applied. If the key of same name and same type already exists (already linked in the keyring)
it will get replaced in the process.
+
See also *KEY IDENTIFIERS* section of *keyctl*(1).
endif::[]
ifdef::ACTION_CONFIG[]
*--priority <normal|prefer|ignore>*::
Set a priority for LUKS2 keyslot. The _prefer_ priority marked slots

View File

@@ -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, --volume-key-keyring].
--timeout, --verify-passphrase, --volume-key-keyring, --link-vk-to-keyring].
include::man/common_options.adoc[]
include::man/common_footer.adoc[]

View File

@@ -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, --volume-key-keyring].
--verify-passphrase, --persistent, --volume-key-keyring, --link-vk-to-keyring].
=== loopAES
*open --type loopaes <device> <name> --key-file <keyfile>* +

View File

@@ -1619,12 +1619,92 @@ static int action_luksFormat(void)
return luksFormat(NULL, NULL, NULL);
}
static int parse_vk_description(const char *key_description, char **ret_key_description)
{
char *tmp;
int r;
assert(key_description);
assert(ret_key_description);
/* apply default key type */
if (*key_description != '%')
r = asprintf(&tmp, "%%user:%s", key_description);
else {
tmp = strdup(key_description);
r = tmp ? 0 : -ENOMEM;
}
if (!r)
*ret_key_description = tmp;
return r;
}
static int parse_vk_and_keyring_description(
struct crypt_device *cd,
char *keyring_key_description)
{
int r;
char *endp, *sep, *keyring_part, *key_part, *type_part = NULL;
if (!cd || !keyring_key_description)
return -EINVAL;
/* "::" is separator between keyring specification a key description */
key_part = strstr(keyring_key_description, "::");
if (!key_part)
return -EINVAL;
*key_part = '\0';
key_part = key_part + 2;
if (*key_part == '%') {
type_part = key_part + 1;
sep = strstr(type_part, ":");
if (!sep)
return -EINVAL;
*sep = '\0';
key_part = sep + 1;
}
if (*keyring_key_description == '%') {
keyring_key_description = strstr(keyring_key_description, ":");
if (!keyring_key_description) {
log_err(_("Invalid --link-vk-to-keyring value."));
return -EINVAL;
}
log_verbose(_("Type specification in --link-vk-to-keyring keyring specification is ignored."));
keyring_key_description++;
}
(void)strtol(keyring_key_description, &endp, 0);
r = 0;
if (*keyring_key_description == '@' || !*endp) {
keyring_part = strdup(keyring_key_description);
if (!keyring_part)
r = -ENOMEM;
} else
r = asprintf(&keyring_part, "%%:%s", keyring_key_description);
if (r < 0)
return -EINVAL;
r = crypt_set_keyring_to_link(cd, key_part, type_part, keyring_part);
free(keyring_part);
return r;
}
static int action_open_luks(void)
{
struct crypt_active_device cad;
struct crypt_device *cd = NULL;
const char *data_device, *header_device, *activated_name;
char *key = NULL;
char *key = NULL, *vk_description_activation = NULL;
uint32_t activate_flags = 0;
int r, keysize, tries;
char *password = NULL;
@@ -1669,19 +1749,10 @@ static int action_open_luks(void)
set_activation_flags(&activate_flags);
if (ARG_SET(OPT_VOLUME_KEY_TYPE_ID)) {
r = crypt_set_vk_keyring_type(cd, ARG_STR(OPT_VOLUME_KEY_TYPE_ID));
if (r) {
log_err(_("The specified keyring key type %s is invalid."),
ARG_STR(OPT_VOLUME_KEY_TYPE_ID));
goto out;
}
}
if (ARG_SET(OPT_LINK_VK_TO_KEYRING_ID)) {
if ((r = crypt_set_keyring_to_link(cd, ARG_STR(OPT_LINK_VK_TO_KEYRING_ID))))
return r;
r = parse_vk_and_keyring_description(cd, ARG_STR(OPT_LINK_VK_TO_KEYRING_ID));
if (r < 0)
goto out;
}
if (ARG_SET(OPT_VOLUME_KEY_FILE_ID)) {
@@ -1699,7 +1770,10 @@ static int action_open_luks(void)
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);
r = parse_vk_description(ARG_STR(OPT_VOLUME_KEY_KEYRING_ID), &vk_description_activation);
if (r < 0)
goto out;
r = crypt_keyslot_context_init_by_vk_in_keyring(cd, vk_description_activation, &kc);
if (r)
goto out;
r = crypt_activate_by_keyslot_context(cd, activated_name, CRYPT_ANY_SLOT, kc, activate_flags);
@@ -2029,7 +2103,8 @@ static int action_luksAddKey(void)
{
int keyslot_old, keyslot_new, keysize = 0, r = -EINVAL;
const char *new_key_file = (action_argc > 1 ? action_argv[1] : NULL);
char *key = NULL, *password = NULL, *password_new = NULL, *pin = NULL, *pin_new = NULL;
char *key = NULL, *password = NULL, *password_new = NULL, *pin = NULL, *pin_new = NULL,
*vk_description = NULL;
size_t pin_size, pin_size_new, password_size = 0, password_new_size = 0;
struct crypt_device *cd = NULL;
struct crypt_keyslot_context *p_kc_new = NULL, *kc = NULL, *kc_new = NULL;
@@ -2105,9 +2180,11 @@ 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)) {
else if (ARG_SET(OPT_VOLUME_KEY_KEYRING_ID)) {
r = parse_vk_description(ARG_STR(OPT_VOLUME_KEY_KEYRING_ID), &vk_description);
if (!r)
r = crypt_keyslot_context_init_by_vk_in_keyring(cd, vk_description, &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),
ARG_STR(OPT_TOKEN_TYPE_ID),
@@ -2195,6 +2272,7 @@ static int action_luksAddKey(void)
}
out:
tools_keyslot_msg(r, CREATED);
free(vk_description);
crypt_keyslot_context_free(kc);
crypt_keyslot_context_free(kc_new);
crypt_safe_free(password);
@@ -2536,7 +2614,7 @@ static int action_luksSuspend(void)
static int action_luksResume(void)
{
struct crypt_device *cd = NULL;
char *password = NULL;
char *password = NULL, *vk_description_activation = NULL;
size_t passwordLen;
int r, tries;
struct crypt_active_device cad;
@@ -2549,21 +2627,13 @@ static int action_luksResume(void)
if ((r = crypt_init_by_name_and_header(&cd, action_argv[0], uuid_or_device(ARG_STR(OPT_HEADER_ID)))))
return r;
r = -EINVAL;
if (ARG_SET(OPT_VOLUME_KEY_TYPE_ID)) {
r = crypt_set_vk_keyring_type(cd, ARG_STR(OPT_VOLUME_KEY_TYPE_ID));
if (r) {
log_err(_("The specified keyring key type %s is invalid."),
ARG_STR(OPT_VOLUME_KEY_TYPE_ID));
if (ARG_SET(OPT_LINK_VK_TO_KEYRING_ID)) {
r = parse_vk_and_keyring_description(cd, ARG_STR(OPT_LINK_VK_TO_KEYRING_ID));
if (r < 0)
goto out;
}
}
if (ARG_SET(OPT_LINK_VK_TO_KEYRING_ID)) {
if ((r = crypt_set_keyring_to_link(cd, ARG_STR(OPT_LINK_VK_TO_KEYRING_ID))))
return r;
}
r = -EINVAL;
if (!isLUKS(crypt_get_type(cd))) {
log_err(_("%s is not active LUKS device name or header is missing."), action_argv[0]);
@@ -2600,7 +2670,10 @@ static int action_luksResume(void)
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);
r = parse_vk_description(ARG_STR(OPT_VOLUME_KEY_KEYRING_ID), &vk_description_activation);
if (r < 0)
goto out;
r = crypt_keyslot_context_init_by_vk_in_keyring(cd, vk_description_activation, &kc);
if (r)
goto out;
r = crypt_resume_by_keyslot_context(cd, action_argv[0], CRYPT_ANY_SLOT, kc);
@@ -2627,6 +2700,7 @@ static int action_luksResume(void)
out:
crypt_keyslot_context_free(kc);
crypt_safe_free(password);
free(vk_description_activation);
crypt_free(cd);
return r;
}

View File

@@ -225,8 +225,6 @@ ARG(OPT_VOLUME_KEY_FILE, '\0', POPT_ARG_STRING, N_("Use the volume key from file
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, {}, {})
/* added for reencryption */
ARG(OPT_BLOCK_SIZE, 'B', POPT_ARG_STRING, N_("Reencryption block size"), N_("MiB"), CRYPT_ARG_UINT32, { .u32_value = 4 }, {})

View File

@@ -68,6 +68,7 @@
#define OPT_ITER_TIME_ACTIONS { BENCHMARK_ACTION, FORMAT_ACTION, ADDKEY_ACTION, CHANGEKEY_ACTION, CONVERTKEY_ACTION, REENCRYPT_ACTION }
#define OPT_IV_LARGE_SECTORS_ACTIONS { OPEN_ACTION }
#define OPT_KEEP_KEY_ACTIONS { REENCRYPT_ACTION }
#define OPT_KEY_DESCRIPTION_ACTIONS { TOKEN_ACTION }
#define OPT_KEY_SIZE_ACTIONS { OPEN_ACTION, BENCHMARK_ACTION, FORMAT_ACTION, REENCRYPT_ACTION, ADDKEY_ACTION }
#define OPT_KEY_SLOT_ACTIONS { OPEN_ACTION, REENCRYPT_ACTION, CONFIG_ACTION, FORMAT_ACTION, ADDKEY_ACTION, CHANGEKEY_ACTION, CONVERTKEY_ACTION, LUKSDUMP_ACTION, TOKEN_ACTION, RESUME_ACTION }
#define OPT_KEYSLOT_CIPHER_ACTIONS { FORMAT_ACTION, REENCRYPT_ACTION, ADDKEY_ACTION, CHANGEKEY_ACTION, CONVERTKEY_ACTION }

View File

@@ -112,7 +112,6 @@
#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"
#define OPT_NEW_KEYFILE "new-keyfile"

View File

@@ -83,6 +83,15 @@ typedef int32_t key_serial_t;
#define DEVICE_CHAR "/dev/zero"
#define THE_LFILE_TEMPLATE "cryptsetup-tstlp.XXXXXX"
#define TEST_KEYRING_USER "cs_apitest2_keyring_in_user"
#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_NAME "\%user:" TEST_KEY_VK_USER
#define TEST_KEY_VK_LOGON "cs_api_test_prefix:api_test_logon_vk"
#define TEST_KEY_VK_LOGON_NAME "\%logon:" TEST_KEY_VK_LOGON
#define KEY_DESC_TEST0 "cs_token_test:test_key0"
#define KEY_DESC_TEST1 "cs_token_test:test_key1"
@@ -141,6 +150,10 @@ static uint32_t default_luks2_iter_time = 0;
static uint32_t default_luks2_memory_kb = 0;
static uint32_t default_luks2_parallel_threads = 0;
#ifdef KERNEL_KEYRING
static char keyring_in_user_str_id[32] = {0};
#endif
static struct crypt_pbkdf_type min_pbkdf2 = {
.type = "pbkdf2",
.iterations = 1000,
@@ -299,80 +312,6 @@ static void _cleanup_dmdevices(void)
t_dev_offset = 0;
}
static void _cleanup(void)
{
struct stat st;
CRYPT_FREE(cd);
CRYPT_FREE(cd2);
//_system("udevadm settle", 0);
if (!stat(DMDIR CDEVICE_1, &st))
_system("dmsetup remove " DM_RETRY CDEVICE_1 DM_NOSTDERR, 0);
if (!stat(DMDIR CDEVICE_2, &st))
_system("dmsetup remove " DM_RETRY CDEVICE_2 DM_NOSTDERR, 0);
if (!stat(DEVICE_EMPTY, &st))
_system("dmsetup remove " DM_RETRY DEVICE_EMPTY_name DM_NOSTDERR, 0);
if (!stat(DEVICE_ERROR, &st))
_system("dmsetup remove " DM_RETRY DEVICE_ERROR_name DM_NOSTDERR, 0);
_cleanup_dmdevices();
if (loop_device(THE_LOOP_DEV))
loop_detach(THE_LOOP_DEV);
if (loop_device(DEVICE_1))
loop_detach(DEVICE_1);
if (loop_device(DEVICE_2))
loop_detach(DEVICE_2);
if (loop_device(DEVICE_3))
loop_detach(DEVICE_3);
if (loop_device(DEVICE_4))
loop_detach(DEVICE_4);
if (loop_device(DEVICE_5))
loop_detach(DEVICE_5);
if (loop_device(DEVICE_6))
loop_detach(DEVICE_6);
_system("rm -f " IMAGE_EMPTY, 0);
_system("rm -f " IMAGE1, 0);
_system("rm -rf " CONV_DIR, 0);
if (test_loop_file)
remove(test_loop_file);
if (tmp_file_1)
remove(tmp_file_1);
remove(REQS_LUKS2_HEADER);
remove(NO_REQS_LUKS2_HEADER);
remove(BACKUP_FILE);
remove(IMAGE_PV_LUKS2_SEC);
remove(IMAGE_PV_LUKS2_SEC ".bcp");
remove(IMAGE_EMPTY_SMALL);
remove(IMAGE_EMPTY_SMALL_2);
_remove_keyfiles();
free(tmp_file_1);
free(test_loop_file);
free(THE_LOOP_DEV);
free(DEVICE_1);
free(DEVICE_2);
free(DEVICE_3);
free(DEVICE_4);
free(DEVICE_5);
free(DEVICE_6);
}
static int _setup(void)
{
int fd, ro = 0;
@@ -489,6 +428,11 @@ static key_serial_t keyctl_unlink(key_serial_t key, key_serial_t keyring)
return syscall(__NR_keyctl, KEYCTL_UNLINK, key, keyring);
}
static key_serial_t keyctl_link(key_serial_t key, key_serial_t keyring)
{
return syscall(__NR_keyctl, KEYCTL_LINK, 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);
@@ -507,6 +451,28 @@ static key_serial_t request_key(const char *type,
return syscall(__NR_request_key, type, description, callout_info, keyring);
}
/* key handle permissions mask */
typedef uint32_t key_perm_t;
#define KEY_POS_ALL 0x3f000000
#define KEY_USR_ALL 0x003f0000
static key_serial_t add_key_set_perm(const char *type, const char *description, const void *payload, size_t plen, key_serial_t keyring, key_perm_t perm)
{
long l;
key_serial_t kid = syscall(__NR_add_key, type, description, payload, plen, KEY_SPEC_THREAD_KEYRING);
if (kid < 0)
return kid;
l = syscall(__NR_keyctl, KEYCTL_SETPERM, kid, perm);
if (l == 0)
l = syscall(__NR_keyctl, KEYCTL_LINK, kid, keyring);
syscall(__NR_keyctl, KEYCTL_UNLINK, kid, KEY_SPEC_THREAD_KEYRING);
return l == 0 ? kid : -EINVAL;
}
static key_serial_t _kernel_key_by_segment_and_type(struct crypt_device *_cd, int segment,
const char* type)
{
@@ -528,6 +494,17 @@ 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_from_keyring_name(const char *key_description, key_serial_t keyring, const char* type)
{
//key_serial_t kid = request_key(type, key_description, NULL, keyring);
key_serial_t kid = request_key(type, key_description, NULL, 0);
if (kid < 0)
return -2;
return keyctl_unlink(kid, keyring);
}
static int _drop_keyring_key_from_keyring_type(struct crypt_device *_cd, int segment,
key_serial_t keyring, const char* type)
{
@@ -545,6 +522,95 @@ static int _drop_keyring_key(struct crypt_device *_cd, int segment)
}
#endif
static void _cleanup(void)
{
struct stat st;
CRYPT_FREE(cd);
CRYPT_FREE(cd2);
//_system("udevadm settle", 0);
if (!stat(DMDIR CDEVICE_1, &st))
_system("dmsetup remove " DM_RETRY CDEVICE_1 DM_NOSTDERR, 0);
if (!stat(DMDIR CDEVICE_2, &st))
_system("dmsetup remove " DM_RETRY CDEVICE_2 DM_NOSTDERR, 0);
if (!stat(DEVICE_EMPTY, &st))
_system("dmsetup remove " DM_RETRY DEVICE_EMPTY_name DM_NOSTDERR, 0);
if (!stat(DEVICE_ERROR, &st))
_system("dmsetup remove " DM_RETRY DEVICE_ERROR_name DM_NOSTDERR, 0);
_cleanup_dmdevices();
if (loop_device(THE_LOOP_DEV))
loop_detach(THE_LOOP_DEV);
if (loop_device(DEVICE_1))
loop_detach(DEVICE_1);
if (loop_device(DEVICE_2))
loop_detach(DEVICE_2);
if (loop_device(DEVICE_3))
loop_detach(DEVICE_3);
if (loop_device(DEVICE_4))
loop_detach(DEVICE_4);
if (loop_device(DEVICE_5))
loop_detach(DEVICE_5);
if (loop_device(DEVICE_6))
loop_detach(DEVICE_6);
_system("rm -f " IMAGE_EMPTY, 0);
_system("rm -f " IMAGE1, 0);
_system("rm -rf " CONV_DIR, 0);
if (test_loop_file)
remove(test_loop_file);
if (tmp_file_1)
remove(tmp_file_1);
remove(REQS_LUKS2_HEADER);
remove(NO_REQS_LUKS2_HEADER);
remove(BACKUP_FILE);
remove(IMAGE_PV_LUKS2_SEC);
remove(IMAGE_PV_LUKS2_SEC ".bcp");
remove(IMAGE_EMPTY_SMALL);
remove(IMAGE_EMPTY_SMALL_2);
_remove_keyfiles();
free(tmp_file_1);
free(test_loop_file);
free(THE_LOOP_DEV);
free(DEVICE_1);
free(DEVICE_2);
free(DEVICE_3);
free(DEVICE_4);
free(DEVICE_5);
free(DEVICE_6);
#ifdef KERNEL_KEYRING
char *end;
key_serial_t krid;
if (keyring_in_user_str_id[0] != '\0') {
krid = strtoul(keyring_in_user_str_id, &end, 0);
if (!*end)
(void)keyctl_unlink(krid, KEY_SPEC_USER_KEYRING);
}
krid = request_key("keyring", TEST_KEYRING_SESSION, NULL, 0);
if (krid > 0)
(void)keyctl_unlink(krid, KEY_SPEC_SESSION_KEYRING);
#endif
}
static int test_open(struct crypt_device *_cd __attribute__((unused)),
int token __attribute__((unused)),
char **buffer,
@@ -5151,10 +5217,9 @@ static void KeyslotContextAndKeyringLink(void)
uint64_t r_payload_offset;
char key[128];
size_t key_size = 128;
key_serial_t kid, linked_kid;
key_serial_t kid, keyring_in_user_id, keyring_in_session_id, linked_kid;
int suspend_status;
struct crypt_active_device cad;
char key_description[1024];
char vk_buf[1024];
long vk_len;
@@ -5172,6 +5237,12 @@ static void KeyslotContextAndKeyringLink(void)
kid = add_key("user", KEY_DESC_TEST0, PASSPHRASE, strlen(PASSPHRASE), KEY_SPEC_THREAD_KEYRING);
NOTFAIL_(kid, "Test or kernel keyring are broken.");
keyring_in_user_id = add_key_set_perm("keyring", TEST_KEYRING_USER, NULL, 0, KEY_SPEC_USER_KEYRING, KEY_POS_ALL | KEY_USR_ALL);
NOTFAIL_(keyring_in_user_id, "Test or kernel keyring are broken.");
NOTFAIL_(snprintf(keyring_in_user_str_id, sizeof(keyring_in_user_str_id)-1, "%u", keyring_in_user_id), "Failed to get string id.");
keyring_in_session_id = add_key_set_perm("keyring", TEST_KEYRING_SESSION, NULL, 0, KEY_SPEC_SESSION_KEYRING, KEY_POS_ALL | KEY_USR_ALL);
NOTFAIL_(keyring_in_session_id, "Test or kernel keyring are broken.");
// test passphrase
OK_(crypt_keyslot_context_init_by_passphrase(cd, PASSPHRASE, strlen(PASSPHRASE), &kc));
EQ_(crypt_activate_by_keyslot_context(cd, NULL, CRYPT_ANY_SLOT, kc, 0), 0);
@@ -5218,65 +5289,75 @@ static void KeyslotContextAndKeyringLink(void)
OK_(crypt_deactivate(cd, CDEVICE_1));
crypt_keyslot_context_free(kc);
// test linking to a keyring and setting key type
crypt_set_keyring_to_link(cd, "@u");
// test linking to a custom keyring linked in user keyring
OK_(crypt_set_keyring_to_link(cd, TEST_KEY_VK_USER, "user", keyring_in_user_str_id /* TEST_KEYRING_USER_NAME */));
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.");
/*
* Otherwise will wil not be able to search the TEST_KEYRING_USER in current context (see request_key(2):
* "The keyrings are searched in the order: thread-specific keyring, process-specific keyring, and then session keyring."
*/
NOTFAIL_(keyctl_link(keyring_in_user_id, KEY_SPEC_THREAD_KEYRING), "Failed to link in thread keyring.");
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.");
FAIL_((linked_kid = request_key("logon", TEST_KEY_VK_USER, 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_(_kernel_key_by_segment_and_type(cd, 0, "logon"), "dm-crypt VK was not uploaded in thread kernel 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"));
NOTFAIL_(keyctl_unlink(linked_kid, 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.");
// test repated activation
FAIL_(_kernel_key_by_segment_and_type(cd, 0, "user"), "VK was still linked to session keyring after removal.");
OK_(crypt_set_keyring_to_link(cd, TEST_KEY_VK_LOGON, "logon", keyring_in_user_str_id /* TEST_KEYRING_USER_NAME */));
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.");
NOTFAIL_((linked_kid = request_key("logon", TEST_KEY_VK_LOGON, 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.");
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");
NOTFAIL_(keyctl_unlink(linked_kid, 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.");
// change key type to default (logon)
crypt_set_vk_keyring_type(cd, NULL);
OK_(crypt_set_keyring_to_link(cd, TEST_KEY_VK_LOGON, "logon", TEST_KEYRING_SESSION_NAME));
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.");
NOTFAIL_((linked_kid = request_key("logon", TEST_KEY_VK_LOGON, 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.");
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");
NOTFAIL_(keyctl_unlink(linked_kid, keyring_in_session_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.");
// test repeated activation
OK_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, PASSPHRASE, strlen(PASSPHRASE), 0));
NOTFAIL_((linked_kid = request_key("logon", TEST_KEY_VK_LOGON, NULL, 0)), "VK was not linked to custom keyring after repeated activation.");
OK_(crypt_deactivate(cd, CDEVICE_1));
NOTFAIL_(request_key("logon", TEST_KEY_VK_LOGON, NULL, 0), "VK was not linked to custom keyring after deactivation.");
NOTFAIL_(keyctl_unlink(linked_kid, keyring_in_session_id), "VK was not linked to custom keyring after deactivation.");
FAIL_(request_key("logon", TEST_KEY_VK_LOGON, NULL, 0), "VK was probably wrongly linked in yet another keyring ");
// change key type to default (user)
OK_(crypt_set_keyring_to_link(cd, TEST_KEY_VK_USER, NULL, TEST_KEYRING_USER_NAME));
OK_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, PASSPHRASE, strlen(PASSPHRASE), 0));
NOTFAIL_((linked_kid = request_key("user", TEST_KEY_VK_USER, NULL, 0)), "VK was not linked to custom keyring after resetting key type.");
OK_(crypt_deactivate(cd, CDEVICE_1));
//NOTFAIL_(request_key("user", TEST_KEY_VK_USER, NULL, 0), "VK was not linked to custom keyring after deactivation.");
NOTFAIL_(keyctl_unlink(linked_kid, keyring_in_user_id), "VK was not linked to custom keyring after deactivation.");
FAIL_(request_key("user", TEST_KEY_VK_USER, NULL, 0), "VK was probably wrongly linked in yet another keyring ");
// disable linking to session keyring
crypt_set_keyring_to_link(cd, NULL);
crypt_set_keyring_to_link(cd, NULL, NULL, NULL);
OK_(crypt_activate_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, PASSPHRASE, strlen(PASSPHRASE), 0));
FAIL_(request_key("user", TEST_KEY_VK_USER, NULL, 0), "VK was probably wrongly linked in yet another keyring ");
FAIL_(request_key("logon", TEST_KEY_VK_LOGON, NULL, 0), "VK was probably wrongly linked in yet another keyring ");
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");
crypt_set_keyring_to_link(cd, TEST_KEY_VK_USER, "user", TEST_KEYRING_SESSION_NAME);
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));
NOTFAIL_(request_key("user", TEST_KEY_VK_USER, NULL, 0), "VK was not linked to session keyring.");
OK_(crypt_keyslot_context_init_by_vk_in_keyring(cd, TEST_KEY_VK_USER_NAME, &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"));
NOTFAIL_(request_key("user", TEST_KEY_VK_USER, NULL, 0), "VK was not linked to session keyring after deactivation.");
OK_(_drop_keyring_key_from_keyring_name(TEST_KEY_VK_USER, keyring_in_session_id, "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
@@ -5284,12 +5365,12 @@ static void KeyslotContextAndKeyringLink(void)
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.");
NOTFAIL_((linked_kid = request_key("user", TEST_KEY_VK_USER, NULL, 0)), "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"));
OK_(_drop_keyring_key_from_keyring_name(TEST_KEY_VK_USER, keyring_in_session_id, "user"));
crypt_keyslot_context_free(kc);
// After this point put resume tests only!
@@ -5338,19 +5419,17 @@ static void KeyslotContextAndKeyringLink(void)
crypt_keyslot_context_free(kc);
// resume by VK keyring context
crypt_set_vk_keyring_type(cd, "user");
crypt_set_keyring_to_link(cd, "@s");
crypt_set_keyring_to_link(cd, TEST_KEY_VK_USER, "user", TEST_KEYRING_SESSION_NAME);
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.");
NOTFAIL_(request_key("user", TEST_KEY_VK_USER, NULL, 0), "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));
OK_(crypt_keyslot_context_init_by_vk_in_keyring(cd, TEST_KEY_VK_USER_NAME, &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"));
NOTFAIL_(request_key("user", TEST_KEY_VK_USER, NULL, 0), "VK was not linked to session keyring after deactivation.");
OK_(_drop_keyring_key_from_keyring_name(TEST_KEY_VK_USER, keyring_in_session_id, "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);
@@ -5464,6 +5543,8 @@ int main(int argc, char *argv[])
crypt_set_debug_level(_debug ? CRYPT_DEBUG_JSON : CRYPT_DEBUG_NONE);
goto aaa;
RUN_(AddDeviceLuks2, "Format and use LUKS2 device");
RUN_(Luks2MetadataSize, "LUKS2 metadata settings");
RUN_(Luks2HeaderLoad, "LUKS2 header load");
@@ -5489,6 +5570,7 @@ int main(int argc, char *argv[])
#endif
RUN_(LuksKeyslotAdd, "Adding keyslot via new API");
RUN_(VolumeKeyGet, "Getting volume key via keyslot context API");
aaa:
RUN_(KeyslotContextAndKeyringLink, "Activate via keyslot context API and linking VK to a keyring");
RUN_(Luks2Repair, "LUKS2 repair"); // test disables metadata locking. Run always last!

View File

@@ -291,13 +291,14 @@ function add_scsi_device() {
# $2 keyring to link VK to
# $3 key type (optional)
test_vk_link() {
KEY_TYPE=${3:-logon}
KEY_TYPE=${3:-user}
KEY_TYPE_ARG=""
if [ ! -z "$3" ]; then
KEY_TYPE_ARG="--volume-key-type $3"
KEY_TYPE_ARG="%$3:"
fi
echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --link-vk-to-keyring "$2" $KEY_TYPE_ARG || fail
#echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --key-description $1 --link-vk-to-keyring "$2" $KEY_TYPE_ARG || fail
echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --link-vk-to-keyring "$2"::"$KEY_TYPE_ARG""$1" || 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."
@@ -308,15 +309,16 @@ test_vk_link() {
# $2 keyring to link VK to
# $3 key type (optional)
test_vk_link_and_reactivate() {
KEY_TYPE=${3:-logon}
KEY_TYPE=${3:-user}
KEY_TYPE_ARG=""
if [ ! -z "$3" ]; then
KEY_TYPE_ARG="--volume-key-type $3"
KEY_TYPE_ARG="%$3:"
fi
LINKED_KEY_NAME="%$KEY_TYPE:$1"
echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --link-vk-to-keyring "$2" $KEY_TYPE_ARG || fail
#echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --key-description $1 --link-vk-to-keyring "$2" $KEY_TYPE_ARG || fail
echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --link-vk-to-keyring "$2"::"$KEY_TYPE_ARG""$1" || 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."
@@ -326,7 +328,7 @@ test_vk_link_and_reactivate() {
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 luksAddKey $FAST_PBKDF_OPT --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
@@ -1270,8 +1272,7 @@ 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"
KEY_NAME="cryptsetup:test_volume_key_id"
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
@@ -1281,39 +1282,44 @@ if [ $HAVE_KEYRING -gt 0 -a -d /proc/sys/kernel/keys ]; then
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" "logon"
[[ ! -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"
test_vk_link $KEY_NAME "%:$TEST_KEYRING_NAME" "logon"
# explicitly specify keyring key type
test_vk_link $KEY_NAME "%keyring:$TEST_KEYRING_NAME"
test_vk_link_and_reactivate $KEY_NAME "@u" "user"
test_vk_link_and_reactivate $KEY_NAME "@u"
[[ ! -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_vk_link_and_reactivate $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
echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --link-vk-to-keyring -5::%logon:$KEY_NAME || 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
# missing key description
echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --link-vk-to-keyring "%$TEST_KEYRING_NAME::" > /dev/null 2>&1 && fail
# malformed keyring description
echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --link-vk-to-keyring ":$TEST_KEYRING_NAME::$KEY_NAME" > /dev/null 2>&1 && fail
echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --link-vk-to-keyring "@uuu::$KEY_NAME" > /dev/null 2>&1 && fail
echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --link-vk-to-keyring "@usu::$KEY_NAME" > /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
echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --link-vk-to-keyring "$TEST_KEYRING_NAME::%user" > /dev/null 2>&1 && fail
echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --link-vk-to-keyring "$TEST_KEYRING_NAME::%user:" > /dev/null 2>&1 && fail
echo $PWD1 | $CRYPTSETUP open $LOOPDEV $DEV_NAME --link-vk-to-keyring "%user:$KEY_NAME" > /dev/null 2>&1 && fail
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
fi
prepare "[45] Blkid disable check" wipe