Commit fb6b4739 authored by Milan Broz's avatar Milan Broz

Clean up keyring handling.

Move all keyring functions to one place and separate LUKS2 specific
code to generic handling.

Also fix possible mismatch if volume key is in keyring but it is not native
LUKS2 device (libarary cannot process such a device properly).
parent 32700cc5
......@@ -191,6 +191,9 @@ int crypt_get_integrity_tag_size(struct crypt_device *cd);
int crypt_key_in_keyring(struct crypt_device *cd);
void crypt_set_key_in_keyring(struct crypt_device *cd, unsigned key_in_keyring);
int crypt_volume_key_load_in_keyring(struct crypt_device *cd, struct volume_key *vk);
int crypt_use_keyring_for_vk(const struct crypt_device *cd);
void crypt_drop_keyring_key(struct crypt_device *cd, const char *key_description);
static inline uint64_t version(uint16_t major, uint16_t minor, uint16_t patch, uint16_t release)
{
......
......@@ -352,11 +352,10 @@ int LUKS2_config_set_requirements(struct crypt_device *cd, struct luks2_hdr *hdr
int LUKS2_unmet_requirements(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t reqs_mask, int quiet);
int crypt_use_keyring_for_vk(const struct crypt_device *cd);
int crypt_volume_key_load_in_keyring_by_keyslot(struct crypt_device *cd, struct volume_key *vk, int keyslot);
void crypt_drop_keyring_key(struct crypt_device *cd, const char *key_description);
int crypt_get_passphrase_from_keyring(const char *key_description,
char **passphrase, size_t *passphrase_len);
int LUKS2_key_description_by_segment(struct crypt_device *cd,
struct luks2_hdr *hdr, struct volume_key *vk, int segment);
int LUKS2_volume_key_load_in_keyring_by_keyslot(struct crypt_device *cd,
struct luks2_hdr *hdr, struct volume_key *vk, int keyslot);
struct luks_phdr;
int LUKS2_luks1_to_luks2(struct crypt_device *cd,
......
......@@ -341,3 +341,58 @@ void LUKS2_digests_erase_unused(struct crypt_device *cd,
}
}
}
/* Key description helpers */
static char *get_key_description_by_digest(struct crypt_device *cd, int digest)
{
char *desc, digest_str[3];
int r;
size_t len;
if (!crypt_get_uuid(cd))
return NULL;
r = snprintf(digest_str, sizeof(digest_str), "d%u", digest);
if (r < 0 || (size_t)r >= sizeof(digest_str))
return NULL;
/* "cryptsetup:<uuid>-<digest_str>" + \0 */
len = strlen(crypt_get_uuid(cd)) + strlen(digest_str) + 13;
desc = malloc(len);
if (!desc)
return NULL;
r = snprintf(desc, len, "%s:%s-%s", "cryptsetup", crypt_get_uuid(cd), digest_str);
if (r < 0 || (size_t)r >= len) {
free(desc);
return NULL;
}
return desc;
}
int LUKS2_key_description_by_segment(struct crypt_device *cd,
struct luks2_hdr *hdr, struct volume_key *vk, int segment)
{
char *desc = get_key_description_by_digest(cd, LUKS2_digest_by_segment(cd, hdr, segment));
int r;
r = crypt_volume_key_set_description(vk, desc);
free(desc);
return r;
}
int LUKS2_volume_key_load_in_keyring_by_keyslot(struct crypt_device *cd,
struct luks2_hdr *hdr, struct volume_key *vk, int keyslot)
{
char *desc = get_key_description_by_digest(cd, LUKS2_digest_by_keyslot(cd, hdr, keyslot));
int r;
r = crypt_volume_key_set_description(vk, desc);
if (!r)
r = crypt_volume_key_load_in_keyring(cd, vk);
free(desc);
return r;
}
......@@ -404,7 +404,7 @@ int LUKS2_token_open_and_activate(struct crypt_device *cd,
keyslot = r;
if ((name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use_keyring_for_vk(cd))
r = crypt_volume_key_load_in_keyring_by_keyslot(cd, vk, keyslot);
r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd, hdr, vk, keyslot);
if (r >= 0 && name)
r = LUKS2_activate(cd, name, vk, flags);
......@@ -448,7 +448,7 @@ int LUKS2_token_open_and_activate_any(struct crypt_device *cd,
keyslot = r;
if (r >= 0 && (name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use_keyring_for_vk(cd))
r = crypt_volume_key_load_in_keyring_by_keyslot(cd, vk, keyslot);
r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd, hdr, vk, keyslot);
if (r >= 0 && name)
r = LUKS2_activate(cd, name, vk, flags);
......
......@@ -31,6 +31,7 @@ static int keyring_open(struct crypt_device *cd,
{
json_object *jobj_token, *jobj_key;
struct luks2_hdr *hdr;
int r;
if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
return -EINVAL;
......@@ -41,8 +42,14 @@ static int keyring_open(struct crypt_device *cd,
json_object_object_get_ex(jobj_token, "key_description", &jobj_key);
if (crypt_get_passphrase_from_keyring(json_object_get_string(jobj_key), buffer, buffer_len))
r = keyring_get_passphrase(json_object_get_string(jobj_key), buffer, buffer_len);
if (r == -ENOTSUP) {
log_dbg("Kernel keyring features disabled.");
return -EINVAL;
} else if (r < 0) {
log_dbg("keyring_get_passphrase failed (error %d)", r);
return -EINVAL;
}
return 0;
}
......
......@@ -2020,83 +2020,6 @@ int crypt_repair(struct crypt_device *cd,
return r;
}
static char *crypt_get_key_description_by_digest(struct crypt_device *cd, int digest)
{
char *desc, digest_str[3];
int r;
size_t len;
if (!crypt_get_uuid(cd))
return NULL;
r = snprintf(digest_str, sizeof(digest_str), "d%u", digest);
if (r < 0 || (size_t)r >= sizeof(digest_str))
return NULL;
/* "cryptsetup:<uuid>-<digest_str>" + \0 */
len = strlen(crypt_get_uuid(cd)) + strlen(digest_str) + 13;
desc = malloc(len);
if (!desc)
return NULL;
r = snprintf(desc, len, "%s:%s-%s", "cryptsetup", crypt_get_uuid(cd), digest_str);
if (r < 0 || (size_t)r >= len) {
free(desc);
return NULL;
}
return desc;
}
static int crypt_set_key_description_by_segment(struct crypt_device *cd, struct volume_key *vk, int segment)
{
char *desc = crypt_get_key_description_by_digest(cd, LUKS2_digest_by_segment(cd, &cd->u.luks2.hdr, segment));
int r;
r = crypt_volume_key_set_description(vk, desc);
free(desc);
return r;
}
/* internal only */
static int crypt_volume_key_load_in_keyring(struct crypt_device *cd, struct volume_key *vk)
{
int r;
if (!vk || !cd)
return -EINVAL;
if (!vk->key_description) {
log_dbg("Invalid key description");
return -EINVAL;
}
log_dbg("Loading key (%zu bytes) in thread keyring.", vk->keylength);
r = keyring_add_key_in_thread_keyring(vk->key_description, vk->key, vk->keylength);
if (r) {
log_dbg("keyring_add_key_in_thread_keyring failed (error %d)", r);
log_err(cd, _("Failed to load key in kernel keyring.\n"));
} else
crypt_set_key_in_keyring(cd, 1);
return r;
}
int crypt_volume_key_load_in_keyring_by_keyslot(struct crypt_device *cd, struct volume_key *vk, int keyslot)
{
char *desc = crypt_get_key_description_by_digest(cd, LUKS2_digest_by_keyslot(cd, &cd->u.luks2.hdr, keyslot));
int r;
r = crypt_volume_key_set_description(vk, desc);
if (!r)
r = crypt_volume_key_load_in_keyring(cd, vk);
free(desc);
return r;
}
int crypt_resize(struct crypt_device *cd, const char *name, uint64_t new_size)
{
struct crypt_dm_active_device dmd = {};
......@@ -2136,7 +2059,12 @@ int crypt_resize(struct crypt_device *cd, const char *name, uint64_t new_size)
}
if (crypt_key_in_keyring(cd)) {
r = crypt_set_key_description_by_segment(cd, dmd.u.crypt.vk, CRYPT_DEFAULT_SEGMENT);
if (!isLUKS2(cd->type)) {
r = -EINVAL;
goto out;
}
r = LUKS2_key_description_by_segment(cd, &cd->u.luks2.hdr,
dmd.u.crypt.vk, CRYPT_DEFAULT_SEGMENT);
if (r)
goto out;
......@@ -2336,37 +2264,6 @@ void crypt_free(struct crypt_device *cd)
free(cd);
}
/* internal only */
int crypt_key_in_keyring(struct crypt_device *cd)
{
return cd ? cd->key_in_keyring : 0;
}
/* internal only */
void crypt_set_key_in_keyring(struct crypt_device *cd, unsigned key_in_keyring)
{
if (!cd)
return;
cd->key_in_keyring = key_in_keyring;
}
/* internal only */
void crypt_drop_keyring_key(struct crypt_device *cd, const char *key_description)
{
int r;
if (!key_description)
return;
log_dbg("Requesting keyring key for revoke and unlink.");
r = keyring_revoke_and_unlink_key(key_description);
if (r)
log_dbg("keyring_revoke_and_unlink failed (error %d)", r);
crypt_set_key_in_keyring(cd, 0);
}
static char *crypt_get_device_key_description(const char *name)
{
char *tmp = NULL;
......@@ -2486,7 +2383,12 @@ int crypt_resume_by_passphrase(struct crypt_device *cd,
keyslot = r;
if (crypt_use_keyring_for_vk(cd)) {
r = crypt_volume_key_load_in_keyring_by_keyslot(cd, vk, keyslot);
if (!isLUKS2(cd->type)) {
r = -EINVAL;
goto out;
}
r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd,
&cd->u.luks2.hdr, vk, keyslot);
if (r < 0)
goto out;
}
......@@ -2552,7 +2454,12 @@ int crypt_resume_by_keyfile_device_offset(struct crypt_device *cd,
keyslot = r;
if (crypt_use_keyring_for_vk(cd)) {
r = crypt_volume_key_load_in_keyring_by_keyslot(cd, vk, keyslot);
if (!isLUKS2(cd->type)) {
r = -EINVAL;
goto out;
}
r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd,
&cd->u.luks2.hdr, vk, keyslot);
if (r < 0)
goto out;
}
......@@ -3017,8 +2924,10 @@ static int _activate_by_passphrase(struct crypt_device *cd,
if (r >= 0) {
keyslot = r;
if ((name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use_keyring_for_vk(cd)) {
r = crypt_volume_key_load_in_keyring_by_keyslot(cd, vk, keyslot);
if ((name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) &&
crypt_use_keyring_for_vk(cd)) {
r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd,
&cd->u.luks2.hdr, vk, keyslot);
if (r < 0)
goto out;
flags |= CRYPT_ACTIVATE_KEYRING_KEY;
......@@ -3155,8 +3064,10 @@ int crypt_activate_by_keyfile_device_offset(struct crypt_device *cd,
goto out;
keyslot = r;
if ((name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use_keyring_for_vk(cd)) {
r = crypt_volume_key_load_in_keyring_by_keyslot(cd, vk, keyslot);
if ((name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) &&
crypt_use_keyring_for_vk(cd)) {
r = LUKS2_volume_key_load_in_keyring_by_keyslot(cd,
&cd->u.luks2.hdr, vk, keyslot);
if (r < 0)
goto out;
flags |= CRYPT_ACTIVATE_KEYRING_KEY;
......@@ -3292,8 +3203,10 @@ int crypt_activate_by_volume_key(struct crypt_device *cd,
if (r == -EPERM || r == -ENOENT)
log_err(cd, _("Volume key does not match the volume.\n"));
if (!r && (name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) && crypt_use_keyring_for_vk(cd)) {
r = crypt_set_key_description_by_segment(cd, vk, CRYPT_DEFAULT_SEGMENT);
if (!r && (name || (flags & CRYPT_ACTIVATE_KEYRING_KEY)) &&
crypt_use_keyring_for_vk(cd)) {
r = LUKS2_key_description_by_segment(cd,
&cd->u.luks2.hdr, vk, CRYPT_DEFAULT_SEGMENT);
if (!r)
r = crypt_volume_key_load_in_keyring(cd, vk);
if (!r)
......@@ -4115,44 +4028,6 @@ void *crypt_get_hdr(struct crypt_device *cd, const char *type)
return NULL;
}
static int kernel_keyring_support(void)
{
static unsigned _checked = 0;
if (!_checked) {
_kernel_keyring_supported = keyring_check();
_checked = 1;
}
return _kernel_keyring_supported;
}
static int dmcrypt_keyring_bug(void)
{
uint64_t kversion;
if (kernel_version(&kversion))
return 1;
return kversion < version(4,15,0,0);
}
int crypt_use_keyring_for_vk(const struct crypt_device *cd)
{
uint32_t dmc_flags;
/* dm backend must be initialised */
if (!cd || !isLUKS2(cd->type))
return 0;
if (!_vk_via_keyring || !kernel_keyring_support())
return 0;
if (dm_flags(DM_CRYPT, &dmc_flags))
return dmcrypt_keyring_bug() ? 0 : 1;
return (dmc_flags & DM_KERNEL_KEYRING_SUPPORTED);
}
/*
* Token handling
*/
......@@ -4308,70 +4183,6 @@ int crypt_metadata_locking(struct crypt_device *cd, int enable)
return 0;
}
int crypt_volume_key_keyring(struct crypt_device *cd, int enable)
{
_vk_via_keyring = enable ? 1 : 0;
return 0;
}
/* internal only */
int crypt_get_passphrase_from_keyring(const char *key_description,
char **passphrase,
size_t *passphrase_len)
{
int r;
log_dbg("Looking for passphrase with key description: %s", key_description);
r = keyring_get_passphrase(key_description, passphrase, passphrase_len);
if (r) {
if (r == -ENOTSUP)
log_dbg("Kernel keyring features disabled.");
else
log_dbg("keyring_get_passphrase failed (error %d)", r);
}
return r;
}
int crypt_activate_by_keyring(struct crypt_device *cd,
const char *name,
const char *key_description,
int keyslot,
uint32_t flags)
{
char *passphrase;
size_t passphrase_size;
int r;
if (!cd || !key_description)
return -EINVAL;
log_dbg("%s volume %s [keyslot %d] using passphrase in keyring key %s.",
name ? "Activating" : "Checking", name ?: "passphrase", keyslot, key_description);
if (!kernel_keyring_support()) {
log_err(cd, _("Kernel keyring is not supported by the kernel.\n"));
return -EINVAL;
}
r = _activate_check_status(cd, name);
if (r < 0)
return r;
if (crypt_get_passphrase_from_keyring(key_description, &passphrase, &passphrase_size)) {
log_err(cd, _("Failed to read passphrase from keyring key %s"), key_description);
return -EINVAL;
}
r = _activate_by_passphrase(cd, name, keyslot, passphrase, passphrase_size, flags);
crypt_memzero(passphrase, passphrase_size);
free(passphrase);
return r;
}
int crypt_persistent_flags_set(struct crypt_device *cd, crypt_flags_type type, uint32_t flags)
{
int r;
......@@ -4479,6 +4290,149 @@ out:
return keyslot;
}
/*
* Keyring handling
*/
static int kernel_keyring_support(void)
{
static unsigned _checked = 0;
if (!_checked) {
_kernel_keyring_supported = keyring_check();
_checked = 1;
}
return _kernel_keyring_supported;
}
static int dmcrypt_keyring_bug(void)
{
uint64_t kversion;
if (kernel_version(&kversion))
return 1;
return kversion < version(4,15,0,0);
}
int crypt_use_keyring_for_vk(const struct crypt_device *cd)
{
uint32_t dmc_flags;
/* dm backend must be initialised */
if (!cd || !isLUKS2(cd->type))
return 0;
if (!_vk_via_keyring || !kernel_keyring_support())
return 0;
if (dm_flags(DM_CRYPT, &dmc_flags))
return dmcrypt_keyring_bug() ? 0 : 1;
return (dmc_flags & DM_KERNEL_KEYRING_SUPPORTED);
}
int crypt_volume_key_keyring(struct crypt_device *cd, int enable)
{
_vk_via_keyring = enable ? 1 : 0;
return 0;
}
/* internal only */
int crypt_volume_key_load_in_keyring(struct crypt_device *cd, struct volume_key *vk)
{
int r;
if (!vk || !cd)
return -EINVAL;
if (!vk->key_description) {
log_dbg("Invalid key description");
return -EINVAL;
}
log_dbg("Loading key (%zu bytes) in thread keyring.", vk->keylength);
r = keyring_add_key_in_thread_keyring(vk->key_description, vk->key, vk->keylength);
if (r) {
log_dbg("keyring_add_key_in_thread_keyring failed (error %d)", r);
log_err(cd, _("Failed to load key in kernel keyring.\n"));
} else
crypt_set_key_in_keyring(cd, 1);
return r;
}
/* internal only */
int crypt_key_in_keyring(struct crypt_device *cd)
{
return cd ? cd->key_in_keyring : 0;
}
/* internal only */
void crypt_set_key_in_keyring(struct crypt_device *cd, unsigned key_in_keyring)
{
if (!cd)
return;
cd->key_in_keyring = key_in_keyring;
}
/* internal only */
void crypt_drop_keyring_key(struct crypt_device *cd, const char *key_description)
{
int r;
if (!key_description)
return;
log_dbg("Requesting keyring key for revoke and unlink.");
r = keyring_revoke_and_unlink_key(key_description);
if (r)
log_dbg("keyring_revoke_and_unlink failed (error %d)", r);
crypt_set_key_in_keyring(cd, 0);
}
int crypt_activate_by_keyring(struct crypt_device *cd,
const char *name,
const char *key_description,
int keyslot,
uint32_t flags)
{
char *passphrase;
size_t passphrase_size;
int r;
if (!cd || !key_description)
return -EINVAL;
log_dbg("%s volume %s [keyslot %d] using passphrase in keyring.",
name ? "Activating" : "Checking", name ?: "passphrase", keyslot);
if (!kernel_keyring_support()) {
log_err(cd, _("Kernel keyring is not supported by the kernel.\n"));
return -EINVAL;
}
r = _activate_check_status(cd, name);
if (r < 0)
return r;
r = keyring_get_passphrase(key_description, &passphrase, &passphrase_size);
if (r < 0) {
log_err(cd, _("Failed to read passphrase from keyring (error %d)."), r);
return -EINVAL;
}
r = _activate_by_passphrase(cd, name, keyslot, passphrase, passphrase_size, flags);
crypt_memzero(passphrase, passphrase_size);
free(passphrase);
return r;
}
static void __attribute__((destructor)) libcryptsetup_exit(void)
{
crypt_backend_destroy();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment