Add crypt_resume_by_volume_key() function.

If user has volume key available, LUKS device can be resumed
directly using provided volume key.
No keyslot derivation is needed, only key digest is checked.

Fixes: #502.
This commit is contained in:
Milan Broz
2019-11-24 18:04:41 +01:00
parent 2746fd708f
commit 48b203a134
5 changed files with 98 additions and 1 deletions

View File

@@ -828,6 +828,20 @@ int crypt_resume_by_keyfile(struct crypt_device *cd,
int keyslot,
const char *keyfile,
size_t keyfile_size);
/**
* Resume crypt device using provided volume key.
*
* @param cd crypt device handle
* @param name name of device to resume
* @param volume_key provided volume key
* @param volume_key_size size of volume_key
*
* @return @e 0 on success or negative errno value otherwise.
*/
int crypt_resume_by_volume_key(struct crypt_device *cd,
const char *name,
const char *volume_key,
size_t volume_key_size);
/** @} */
/**

View File

@@ -24,6 +24,7 @@ CRYPTSETUP_2.0 {
crypt_resume_by_keyfile;
crypt_resume_by_keyfile_offset;
crypt_resume_by_keyfile_device_offset;
crypt_resume_by_volume_key;
crypt_free;
crypt_keyslot_add_by_passphrase;

View File

@@ -3144,7 +3144,7 @@ int crypt_resume_by_keyfile_device_offset(struct crypt_device *cd,
}
r = dm_resume_and_reinstate_key(cd, name, vk);
if (r)
if (r < 0)
log_err(cd, _("Error during resuming device %s."), name);
out:
crypt_safe_free(passphrase_read);
@@ -3175,6 +3175,65 @@ int crypt_resume_by_keyfile_offset(struct crypt_device *cd,
keyfile, keyfile_size, keyfile_offset);
}
int crypt_resume_by_volume_key(struct crypt_device *cd,
const char *name,
const char *volume_key,
size_t volume_key_size)
{
struct volume_key *vk = NULL;
int r;
if (!name || !volume_key)
return -EINVAL;
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);
else if (isLUKS2(cd->type))
r = LUKS2_digest_verify_by_segment(cd, &cd->u.luks2.hdr, CRYPT_DEFAULT_SEGMENT, vk);
else
r = -EINVAL;
if (r == -EPERM || r == -ENOENT)
log_err(cd, _("Volume key does not match the volume."));
if (r < 0)
goto out;
r = 0;
if (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 < 0)
goto out;
r = dm_resume_and_reinstate_key(cd, name, vk);
if (r < 0)
log_err(cd, _("Error during resuming device %s."), name);
out:
if (r < 0)
crypt_drop_keyring_key(cd, vk);
crypt_free_volume_key(vk);
return r;
}
/*
* Keyslot manipulation
*/
@@ -4472,6 +4531,9 @@ int crypt_volume_key_verify(struct crypt_device *cd,
r = LUKS_verify_volume_key(&cd->u.luks1.hdr, vk);
else if (isLUKS2(cd->type))
r = LUKS2_digest_verify_by_segment(cd, &cd->u.luks2.hdr, CRYPT_DEFAULT_SEGMENT, vk);
else
r = -EINVAL;
if (r == -EPERM)
log_err(cd, _("Volume key does not match the volume."));

View File

@@ -538,6 +538,8 @@ static void UseLuks2Device(void)
static void SuspendDevice(void)
{
struct crypt_active_device cad;
char key[128];
size_t key_size;
int suspend_status;
OK_(crypt_init(&cd, DEVICE_1));
@@ -593,6 +595,14 @@ static void SuspendDevice(void)
OK_(crypt_init_by_name_and_header(&cd, CDEVICE_1, DEVICE_1));
OK_(crypt_resume_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEY1, strlen(KEY1)));
/* Resume by volume key */
OK_(crypt_suspend(cd, CDEVICE_1));
key_size = sizeof(key);
memset(key, 0, key_size);
FAIL_(crypt_resume_by_volume_key(cd, CDEVICE_1, key, key_size), "wrong key");
OK_(crypt_volume_key_get(cd, CRYPT_ANY_SLOT, key, &key_size, KEY1, strlen(KEY1)));
OK_(crypt_resume_by_volume_key(cd, CDEVICE_1, key, key_size));
OK_(crypt_deactivate(cd, CDEVICE_1));
CRYPT_FREE(cd);

View File

@@ -679,6 +679,8 @@ static void UseLuksDevice(void)
static void SuspendDevice(void)
{
struct crypt_active_device cad;
char key[128];
size_t key_size;
int suspend_status;
OK_(crypt_init(&cd, DEVICE_1));
@@ -733,6 +735,14 @@ static void SuspendDevice(void)
OK_(crypt_init_by_name_and_header(&cd, CDEVICE_1, DEVICE_1));
OK_(crypt_resume_by_passphrase(cd, CDEVICE_1, CRYPT_ANY_SLOT, KEY1, strlen(KEY1)));
/* Resume by volume key */
OK_(crypt_suspend(cd, CDEVICE_1));
key_size = sizeof(key);
memset(key, 0, key_size);
FAIL_(crypt_resume_by_volume_key(cd, CDEVICE_1, key, key_size), "wrong key");
OK_(crypt_volume_key_get(cd, CRYPT_ANY_SLOT, key, &key_size, KEY1, strlen(KEY1)));
OK_(crypt_resume_by_volume_key(cd, CDEVICE_1, key, key_size));
OK_(crypt_deactivate(cd, CDEVICE_1));
CRYPT_FREE(cd);