mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-06 00:10:04 +01:00
Allow resume by keyslot context.
This commit is contained in:
@@ -332,7 +332,7 @@ static int get_luks2_volume_key_by_keyring(struct crypt_device *cd,
|
||||
int keyslot,
|
||||
struct volume_key **r_vk)
|
||||
{
|
||||
return get_luks2_key_by_passphrase(cd, kc, keyslot, CRYPT_DEFAULT_SEGMENT, r_vk);
|
||||
return get_luks2_key_by_keyring(cd, kc, keyslot, CRYPT_DEFAULT_SEGMENT, r_vk);
|
||||
}
|
||||
|
||||
static int get_luks1_volume_key_by_keyring(struct crypt_device *cd,
|
||||
|
||||
@@ -1009,6 +1009,23 @@ int crypt_resume_by_token_pin(struct crypt_device *cd,
|
||||
const char *pin,
|
||||
size_t pin_size,
|
||||
void *usrptr);
|
||||
|
||||
/**
|
||||
* Resume crypt device using keyslot context.
|
||||
*
|
||||
* @param cd crypt device handle
|
||||
* @param name name of device to resume
|
||||
* @param keyslot requested keyslot to check or @e CRYPT_ANY_SLOT, keyslot is
|
||||
* ignored for unlock methods not based on passphrase
|
||||
* @param kc keyslot context providing volume key or passphrase.
|
||||
*
|
||||
* @return unlocked key slot number for passphrase-based unlock, zero for other
|
||||
* unlock methods (e.g. volume key context) or negative errno on error.
|
||||
*/
|
||||
int crypt_resume_by_keyslot_context(struct crypt_device *cd,
|
||||
const char *name,
|
||||
int keyslot,
|
||||
struct crypt_keyslot_context *kc);
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
||||
@@ -173,5 +173,6 @@ CRYPTSETUP_2.7 {
|
||||
crypt_get_hw_encryption_type;
|
||||
crypt_get_hw_encryption_key_size;
|
||||
crypt_keyslot_context_init_by_keyring;
|
||||
crypt_resume_by_keyslot_context;
|
||||
crypt_wipe_hw_opal;
|
||||
} CRYPTSETUP_2.6;
|
||||
|
||||
@@ -578,6 +578,8 @@ int LUKS2_keyslot_open(struct crypt_device *cd,
|
||||
int r_prio, r = -EINVAL;
|
||||
|
||||
hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
|
||||
if (!hdr)
|
||||
return -EINVAL;
|
||||
|
||||
if (keyslot == CRYPT_ANY_SLOT) {
|
||||
r_prio = LUKS2_keyslot_open_priority(cd, hdr, CRYPT_SLOT_PRIORITY_PREFER,
|
||||
|
||||
186
lib/setup.c
186
lib/setup.c
@@ -4078,21 +4078,19 @@ static int resume_by_volume_key(struct crypt_device *cd,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int crypt_resume_by_passphrase(struct crypt_device *cd,
|
||||
int crypt_resume_by_keyslot_context(struct crypt_device *cd,
|
||||
const char *name,
|
||||
int keyslot,
|
||||
const char *passphrase,
|
||||
size_t passphrase_size)
|
||||
struct crypt_keyslot_context *kc)
|
||||
{
|
||||
struct volume_key *vk = NULL;
|
||||
int r;
|
||||
struct volume_key *vk = NULL;
|
||||
int unlocked_keyslot = -EINVAL;
|
||||
|
||||
/* FIXME: check context uuid matches the dm-crypt device uuid */
|
||||
|
||||
if (!passphrase || !name)
|
||||
if (!name)
|
||||
return -EINVAL;
|
||||
|
||||
log_dbg(cd, "Resuming volume %s.", name);
|
||||
log_dbg(cd, "Resuming volume %s [keyslot %d] using %s.", name, keyslot, keyslot_context_type_string(kc));
|
||||
|
||||
if ((r = onlyLUKS(cd)))
|
||||
return r;
|
||||
@@ -4106,24 +4104,50 @@ int crypt_resume_by_passphrase(struct crypt_device *cd,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (isLUKS1(cd->type) && kc->get_luks1_volume_key)
|
||||
r = kc->get_luks1_volume_key(cd, kc, keyslot, &vk);
|
||||
else if (isLUKS2(cd->type) && kc->get_luks2_volume_key)
|
||||
r = kc->get_luks2_volume_key(cd, kc, keyslot, &vk);
|
||||
else
|
||||
r = -EINVAL;
|
||||
if (r < 0)
|
||||
goto out;
|
||||
unlocked_keyslot = r;
|
||||
|
||||
if (isLUKS1(cd->type)) {
|
||||
r = LUKS_open_key_with_hdr(keyslot, passphrase, passphrase_size,
|
||||
&cd->u.luks1.hdr, &vk, cd);
|
||||
if (r >= 0)
|
||||
crypt_volume_key_set_id(vk, 0);
|
||||
|
||||
r = LUKS_verify_volume_key(&cd->u.luks1.hdr, vk);
|
||||
crypt_volume_key_set_id(vk, 0);
|
||||
} else if (isLUKS2(cd->type)) {
|
||||
r = LUKS2_digest_verify_by_segment(cd, &cd->u.luks2.hdr, CRYPT_DEFAULT_SEGMENT, vk);
|
||||
crypt_volume_key_set_id(vk, 0);
|
||||
} else
|
||||
r = LUKS2_keyslot_open(cd, keyslot, CRYPT_DEFAULT_SEGMENT, passphrase, passphrase_size, &vk);
|
||||
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
keyslot = r;
|
||||
r = -EINVAL;
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
r = resume_by_volume_key(cd, vk, name);
|
||||
|
||||
crypt_free_volume_key(vk);
|
||||
return r < 0 ? r : keyslot;
|
||||
return r < 0 ? r : unlocked_keyslot;
|
||||
out:
|
||||
crypt_free_volume_key(vk);
|
||||
return r;
|
||||
}
|
||||
|
||||
int crypt_resume_by_passphrase(struct crypt_device *cd,
|
||||
const char *name,
|
||||
int keyslot,
|
||||
const char *passphrase,
|
||||
size_t passphrase_size)
|
||||
{
|
||||
int r;
|
||||
struct crypt_keyslot_context kc;
|
||||
|
||||
crypt_keyslot_unlock_by_passphrase_init_internal(&kc, passphrase, passphrase_size);
|
||||
r = crypt_resume_by_keyslot_context(cd, name, keyslot, &kc);
|
||||
crypt_keyslot_context_destroy_internal(&kc);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int crypt_resume_by_keyfile_device_offset(struct crypt_device *cd,
|
||||
@@ -4133,55 +4157,14 @@ int crypt_resume_by_keyfile_device_offset(struct crypt_device *cd,
|
||||
size_t keyfile_size,
|
||||
uint64_t keyfile_offset)
|
||||
{
|
||||
struct volume_key *vk = NULL;
|
||||
char *passphrase_read = NULL;
|
||||
size_t passphrase_size_read;
|
||||
int r;
|
||||
struct crypt_keyslot_context kc;
|
||||
|
||||
/* FIXME: check context uuid matches the dm-crypt device uuid */
|
||||
crypt_keyslot_unlock_by_keyfile_init_internal(&kc, keyfile, keyfile_size, keyfile_offset);
|
||||
r = crypt_resume_by_keyslot_context(cd, name, keyslot, &kc);
|
||||
crypt_keyslot_context_destroy_internal(&kc);
|
||||
|
||||
if (!name || !keyfile)
|
||||
return -EINVAL;
|
||||
|
||||
log_dbg(cd, "Resuming volume %s.", name);
|
||||
|
||||
if ((r = onlyLUKS(cd)))
|
||||
return r;
|
||||
|
||||
r = dm_status_suspended(cd, name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!r) {
|
||||
log_err(cd, _("Volume %s is not suspended."), name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = crypt_keyfile_device_read(cd, keyfile,
|
||||
&passphrase_read, &passphrase_size_read,
|
||||
keyfile_offset, keyfile_size, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (isLUKS1(cd->type)) {
|
||||
r = LUKS_open_key_with_hdr(keyslot, passphrase_read, passphrase_size_read,
|
||||
&cd->u.luks1.hdr, &vk, cd);
|
||||
if (r >= 0)
|
||||
crypt_volume_key_set_id(vk, 0);
|
||||
} else
|
||||
r = LUKS2_keyslot_open(cd, keyslot, CRYPT_DEFAULT_SEGMENT,
|
||||
passphrase_read, passphrase_size_read, &vk);
|
||||
|
||||
crypt_safe_free(passphrase_read);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
keyslot = r;
|
||||
|
||||
r = resume_by_volume_key(cd, vk, name);
|
||||
|
||||
crypt_free_volume_key(vk);
|
||||
return r < 0 ? r : keyslot;
|
||||
return r;
|
||||
}
|
||||
|
||||
int crypt_resume_by_keyfile(struct crypt_device *cd,
|
||||
@@ -4210,46 +4193,16 @@ int crypt_resume_by_volume_key(struct crypt_device *cd,
|
||||
const char *volume_key,
|
||||
size_t volume_key_size)
|
||||
{
|
||||
struct volume_key *vk = NULL;
|
||||
int r;
|
||||
struct crypt_keyslot_context kc;
|
||||
|
||||
if (!name || !volume_key)
|
||||
return -EINVAL;
|
||||
crypt_keyslot_unlock_by_key_init_internal(&kc, volume_key, volume_key_size);
|
||||
r = crypt_resume_by_keyslot_context(cd, name, CRYPT_ANY_SLOT /* unused */, &kc);
|
||||
crypt_keyslot_context_destroy_internal(&kc);
|
||||
|
||||
log_dbg(cd, "Resuming volume %s by volume key.", name);
|
||||
|
||||
if ((r = onlyLUKS(cd)))
|
||||
return r;
|
||||
|
||||
r = dm_status_suspended(cd, name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!r) {
|
||||
log_err(cd, _("Volume %s is not suspended."), name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
vk = crypt_alloc_volume_key(volume_key_size, volume_key);
|
||||
if (!vk)
|
||||
return -ENOMEM;
|
||||
|
||||
if (isLUKS1(cd->type)) {
|
||||
r = LUKS_verify_volume_key(&cd->u.luks1.hdr, vk);
|
||||
if (r >= 0)
|
||||
crypt_volume_key_set_id(vk, 0);
|
||||
} else if (isLUKS2(cd->type)) {
|
||||
r = LUKS2_digest_verify_by_segment(cd, &cd->u.luks2.hdr, CRYPT_DEFAULT_SEGMENT, vk);
|
||||
crypt_volume_key_set_id(vk, r);
|
||||
} else
|
||||
r = -EINVAL;
|
||||
if (r == -EPERM || r == -ENOENT)
|
||||
log_err(cd, _("Volume key does not match the volume."));
|
||||
|
||||
if (r >= 0)
|
||||
r = resume_by_volume_key(cd, vk, name);
|
||||
|
||||
crypt_free_volume_key(vk);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -4257,35 +4210,14 @@ int crypt_resume_by_token_pin(struct crypt_device *cd, const char *name,
|
||||
const char *type, int token, const char *pin, size_t pin_size,
|
||||
void *usrptr)
|
||||
{
|
||||
struct volume_key *vk = NULL;
|
||||
int r, keyslot;
|
||||
int r;
|
||||
struct crypt_keyslot_context kc;
|
||||
|
||||
if (!name)
|
||||
return -EINVAL;
|
||||
crypt_keyslot_unlock_by_token_init_internal(&kc, token, type, pin, pin_size, usrptr);
|
||||
r = crypt_resume_by_keyslot_context(cd, name, CRYPT_ANY_SLOT, &kc);
|
||||
crypt_keyslot_context_destroy_internal(&kc);
|
||||
|
||||
log_dbg(cd, "Resuming volume %s by token (%s type) %d.",
|
||||
name, type ?: "any", token);
|
||||
|
||||
if ((r = _onlyLUKS2(cd, CRYPT_CD_QUIET, 0)))
|
||||
return r;
|
||||
|
||||
r = dm_status_suspended(cd, name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!r) {
|
||||
log_err(cd, _("Volume %s is not suspended."), name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = LUKS2_token_unlock_key(cd, &cd->u.luks2.hdr, CRYPT_ANY_SLOT, token, type,
|
||||
pin, pin_size, CRYPT_DEFAULT_SEGMENT, usrptr, &vk);
|
||||
keyslot = r;
|
||||
if (r >= 0)
|
||||
r = resume_by_volume_key(cd, vk, name);
|
||||
|
||||
crypt_free_volume_key(vk);
|
||||
return r < 0 ? r : keyslot;
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -5129,6 +5129,8 @@ static void KeyslotContext(void)
|
||||
char key[128];
|
||||
size_t key_size = 128;
|
||||
key_serial_t kid;
|
||||
int suspend_status;
|
||||
struct crypt_active_device cad;
|
||||
|
||||
OK_(get_luks2_offsets(0, 0, 0, NULL, &r_payload_offset));
|
||||
OK_(create_dmdevice_over_loop(L_DEVICE_1S, r_payload_offset + 1));
|
||||
@@ -5190,6 +5192,51 @@ static void KeyslotContext(void)
|
||||
OK_(crypt_deactivate(cd, CDEVICE_1));
|
||||
crypt_keyslot_context_free(kc);
|
||||
|
||||
// test resume
|
||||
OK_(crypt_keyslot_context_init_by_passphrase(cd, PASSPHRASE, strlen(PASSPHRASE), &kc));
|
||||
EQ_(crypt_activate_by_keyslot_context(cd, CDEVICE_1, CRYPT_ANY_SLOT, kc, 0), 0);
|
||||
suspend_status = crypt_suspend(cd, CDEVICE_1);
|
||||
if (suspend_status == -ENOTSUP) {
|
||||
printf("WARNING: Suspend/Resume not supported, skipping test.\n");
|
||||
OK_(crypt_deactivate(cd, CDEVICE_1));
|
||||
|
||||
NOTFAIL_(keyctl_unlink(kid, KEY_SPEC_THREAD_KEYRING), "Test or kernel keyring are broken.");
|
||||
CRYPT_FREE(cd);
|
||||
_cleanup_dmdevices();
|
||||
return;
|
||||
}
|
||||
OK_(suspend_status);
|
||||
OK_(crypt_get_active_device(cd, CDEVICE_1, &cad));
|
||||
EQ_(CRYPT_ACTIVATE_SUSPENDED, cad.flags & CRYPT_ACTIVATE_SUSPENDED);
|
||||
OK_(crypt_resume_by_keyslot_context(cd, CDEVICE_1, CRYPT_ANY_SLOT, kc));
|
||||
OK_(crypt_get_active_device(cd, CDEVICE_1, &cad));
|
||||
EQ_(0, cad.flags & CRYPT_ACTIVATE_SUSPENDED);
|
||||
OK_(crypt_deactivate(cd, CDEVICE_1));
|
||||
crypt_keyslot_context_free(kc);
|
||||
|
||||
OK_(crypt_keyslot_context_init_by_volume_key(cd, key, key_size, &kc));
|
||||
EQ_(crypt_activate_by_keyslot_context(cd, CDEVICE_1, CRYPT_ANY_SLOT, kc, 0), 0);
|
||||
OK_(crypt_suspend(cd, CDEVICE_1));
|
||||
EQ_(crypt_resume_by_keyslot_context(cd, CDEVICE_1, CRYPT_ANY_SLOT, kc), 0);
|
||||
OK_(crypt_deactivate(cd, CDEVICE_1));
|
||||
crypt_keyslot_context_free(kc);
|
||||
|
||||
OK_(crypt_keyslot_context_init_by_keyfile(cd, KEYFILE1, 0, 0, &kc));
|
||||
EQ_(crypt_activate_by_keyslot_context(cd, CDEVICE_1, CRYPT_ANY_SLOT, kc, 0), 1);
|
||||
OK_(crypt_suspend(cd, CDEVICE_1));
|
||||
OK_(crypt_get_active_device(cd, CDEVICE_1, &cad));
|
||||
EQ_(CRYPT_ACTIVATE_SUSPENDED, cad.flags & CRYPT_ACTIVATE_SUSPENDED);
|
||||
EQ_(crypt_resume_by_keyslot_context(cd, CDEVICE_1, CRYPT_ANY_SLOT, kc), 1);
|
||||
OK_(crypt_deactivate(cd, CDEVICE_1));
|
||||
crypt_keyslot_context_free(kc);
|
||||
|
||||
OK_(crypt_keyslot_context_init_by_keyring(cd, KEY_DESC_TEST0, &kc));
|
||||
EQ_(crypt_activate_by_keyslot_context(cd, CDEVICE_1, CRYPT_ANY_SLOT, kc, 0), 0);
|
||||
OK_(crypt_suspend(cd, CDEVICE_1));
|
||||
EQ_(crypt_resume_by_keyslot_context(cd, CDEVICE_1, CRYPT_ANY_SLOT, kc), 0);
|
||||
OK_(crypt_deactivate(cd, CDEVICE_1));
|
||||
crypt_keyslot_context_free(kc);
|
||||
|
||||
NOTFAIL_(keyctl_unlink(kid, KEY_SPEC_THREAD_KEYRING), "Test or kernel keyring are broken.");
|
||||
CRYPT_FREE(cd);
|
||||
_cleanup_dmdevices();
|
||||
|
||||
Reference in New Issue
Block a user