Allow activation via keyslot context.

This commit is contained in:
Daniel Zatovic
2023-04-20 10:03:49 +02:00
parent 28e1c95c22
commit 58385d68d8
6 changed files with 255 additions and 111 deletions

View File

@@ -204,6 +204,13 @@ static int get_volume_key_by_key(struct crypt_device *cd,
return get_key_by_key(cd, kc, -2 /* unused */, -2 /* unused */, r_vk);
}
static int get_generic_volume_key_by_key(struct crypt_device *cd,
struct crypt_keyslot_context *kc,
struct volume_key **r_vk)
{
return get_key_by_key(cd, kc, -2 /* unused */, -2 /* unused */, r_vk);
}
static int get_luks2_key_by_token(struct crypt_device *cd,
struct crypt_keyslot_context *kc,
int keyslot,
@@ -211,12 +218,17 @@ static int get_luks2_key_by_token(struct crypt_device *cd,
struct volume_key **r_vk)
{
int r;
struct luks2_hdr *hdr;
assert(cd);
assert(kc && kc->type == CRYPT_KC_TYPE_TOKEN);
assert(r_vk);
r = LUKS2_token_unlock_key(cd, crypt_get_hdr(cd, CRYPT_LUKS2), keyslot, kc->u.t.id, kc->u.t.type,
hdr = crypt_get_hdr(cd, CRYPT_LUKS2);
if (!hdr)
return -EINVAL;
r = LUKS2_token_unlock_key(cd, hdr, keyslot, kc->u.t.id, kc->u.t.type,
kc->u.t.pin, kc->u.t.pin_size, segment, kc->u.t.usrptr, r_vk);
if (r < 0)
kc->error = r;
@@ -283,6 +295,11 @@ void crypt_keyslot_unlock_by_key_init_internal(struct crypt_keyslot_context *kc,
kc->get_luks2_volume_key = get_volume_key_by_key;
kc->get_luks1_volume_key = get_volume_key_by_key;
kc->get_passphrase = NULL; /* keyslot key context does not provide passphrase */
kc->get_plain_volume_key = get_generic_volume_key_by_key;
kc->get_bitlk_volume_key = get_generic_volume_key_by_key;
kc->get_fvault2_volume_key = get_generic_volume_key_by_key;
kc->get_verity_volume_key = get_generic_volume_key_by_key;
kc->get_integrity_volume_key = get_generic_volume_key_by_key;
unlock_method_init_internal(kc);
}
@@ -299,6 +316,11 @@ void crypt_keyslot_unlock_by_passphrase_init_internal(struct crypt_keyslot_conte
kc->get_luks2_volume_key = get_luks2_volume_key_by_passphrase;
kc->get_luks1_volume_key = get_luks1_volume_key_by_passphrase;
kc->get_passphrase = get_passphrase_by_passphrase;
kc->get_plain_volume_key = NULL;
kc->get_bitlk_volume_key = NULL;
kc->get_fvault2_volume_key = NULL;
kc->get_verity_volume_key = NULL;
kc->get_integrity_volume_key = NULL;
unlock_method_init_internal(kc);
}
@@ -317,6 +339,11 @@ void crypt_keyslot_unlock_by_keyfile_init_internal(struct crypt_keyslot_context
kc->get_luks2_volume_key = get_luks2_volume_key_by_keyfile;
kc->get_luks1_volume_key = get_luks1_volume_key_by_keyfile;
kc->get_passphrase = get_passphrase_by_keyfile;
kc->get_plain_volume_key = NULL;
kc->get_bitlk_volume_key = NULL;
kc->get_fvault2_volume_key = NULL;
kc->get_verity_volume_key = NULL;
kc->get_integrity_volume_key = NULL;
unlock_method_init_internal(kc);
}
@@ -339,6 +366,11 @@ void crypt_keyslot_unlock_by_token_init_internal(struct crypt_keyslot_context *k
kc->get_luks2_volume_key = get_luks2_volume_key_by_token;
kc->get_luks1_volume_key = NULL; /* LUKS1 is not supported */
kc->get_passphrase = get_passphrase_by_token;
kc->get_plain_volume_key = NULL;
kc->get_bitlk_volume_key = NULL;
kc->get_fvault2_volume_key = NULL;
kc->get_verity_volume_key = NULL;
kc->get_integrity_volume_key = NULL;
unlock_method_init_internal(kc);
}

View File

@@ -40,6 +40,11 @@ typedef int (*keyslot_context_get_volume_key) (
int keyslot,
struct volume_key **r_vk);
typedef int (*keyslot_context_get_generic_volume_key) (
struct crypt_device *cd,
struct crypt_keyslot_context *kc,
struct volume_key **r_vk);
typedef int (*keyslot_context_get_passphrase) (
struct crypt_device *cd,
struct crypt_keyslot_context *kc,
@@ -78,10 +83,15 @@ struct crypt_keyslot_context {
char *i_passphrase;
size_t i_passphrase_size;
keyslot_context_get_key get_luks2_key;
keyslot_context_get_volume_key get_luks1_volume_key;
keyslot_context_get_volume_key get_luks2_volume_key;
keyslot_context_get_passphrase get_passphrase;
keyslot_context_get_key get_luks2_key;
keyslot_context_get_volume_key get_luks1_volume_key;
keyslot_context_get_volume_key get_luks2_volume_key;
keyslot_context_get_generic_volume_key get_plain_volume_key;
keyslot_context_get_generic_volume_key get_bitlk_volume_key;
keyslot_context_get_generic_volume_key get_fvault2_volume_key;
keyslot_context_get_generic_volume_key get_verity_volume_key;
keyslot_context_get_generic_volume_key get_integrity_volume_key;
keyslot_context_get_passphrase get_passphrase;
};
void crypt_keyslot_context_destroy_internal(struct crypt_keyslot_context *method);

View File

@@ -1541,6 +1541,25 @@ int crypt_persistent_flags_get(struct crypt_device *cd,
* @{
*/
/**
* Activate device or check using keyslot context.
*
* @param cd crypt device handle
* @param name name of device to create, if @e NULL only check passphrase
* @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.
* @param flags activation flags
*
* @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_activate_by_keyslot_context(struct crypt_device *cd,
const char *name,
int keyslot,
struct crypt_keyslot_context *kc,
uint32_t flags);
/**
* Activate device or check passphrase.
*

View File

@@ -168,6 +168,7 @@ CRYPTSETUP_2.6 {
CRYPTSETUP_2.7 {
global:
crypt_activate_by_keyslot_context;
crypt_format_luks2_opal;
crypt_get_hw_encryption_type;
crypt_get_hw_encryption_key_size;

View File

@@ -174,6 +174,18 @@ int LUKS2_digest_verify_by_segment(struct crypt_device *cd,
int segment,
const struct volume_key *vk)
{
int r = -EINVAL;
unsigned s;
if (segment == CRYPT_ANY_SEGMENT) {
for (s = 0; s < json_segments_count(LUKS2_get_segments_jobj(hdr)); s++) {
if ((r = LUKS2_digest_verify_by_digest(cd, LUKS2_digest_by_segment(hdr, s), vk)) >= 0)
return r;
}
return -EPERM;
}
return LUKS2_digest_verify_by_digest(cd, LUKS2_digest_by_segment(hdr, segment), vk);
}

View File

@@ -5070,16 +5070,23 @@ out:
static int _activate_loopaes(struct crypt_device *cd,
const char *name,
char *buffer,
const char *buffer,
size_t buffer_size,
uint32_t flags)
{
int r;
unsigned int key_count = 0;
struct volume_key *vk = NULL;
char *buffer_copy;
buffer_copy = crypt_safe_alloc(buffer_size);
if (!buffer_copy)
return -ENOMEM;
memcpy(buffer_copy, buffer, buffer_size);
r = LOOPAES_parse_keyfile(cd, &vk, cd->u.loopaes.hdr.hash, &key_count,
buffer, buffer_size);
buffer_copy, buffer_size);
crypt_safe_free(buffer_copy);
if (!r && name)
r = LOOPAES_activate(cd, name, cd->u.loopaes.cipher, key_count,
@@ -5115,91 +5122,7 @@ static int _activate_check_status(struct crypt_device *cd, const char *name, uns
}
// activation/deactivation of device mapping
int crypt_activate_by_passphrase(struct crypt_device *cd,
const char *name,
int keyslot,
const char *passphrase,
size_t passphrase_size,
uint32_t flags)
{
int r;
if (!cd || !passphrase || (!name && (flags & CRYPT_ACTIVATE_REFRESH)))
return -EINVAL;
log_dbg(cd, "%s volume %s [keyslot %d] using passphrase.",
name ? "Activating" : "Checking", name ?: "passphrase",
keyslot);
r = _activate_check_status(cd, name, flags & CRYPT_ACTIVATE_REFRESH);
if (r < 0)
return r;
return _activate_by_passphrase(cd, name, keyslot, passphrase, passphrase_size, flags);
}
int crypt_activate_by_keyfile_device_offset(struct crypt_device *cd,
const char *name,
int keyslot,
const char *keyfile,
size_t keyfile_size,
uint64_t keyfile_offset,
uint32_t flags)
{
char *passphrase_read = NULL;
size_t passphrase_size_read;
int r;
if (!cd || !keyfile ||
((flags & CRYPT_ACTIVATE_KEYRING_KEY) && !crypt_use_keyring_for_vk(cd)))
return -EINVAL;
log_dbg(cd, "%s volume %s [keyslot %d] using keyfile %s.",
name ? "Activating" : "Checking", name ?: "passphrase", keyslot, keyfile);
r = _activate_check_status(cd, name, flags & CRYPT_ACTIVATE_REFRESH);
if (r < 0)
return r;
r = crypt_keyfile_device_read(cd, keyfile,
&passphrase_read, &passphrase_size_read,
keyfile_offset, keyfile_size, 0);
if (r < 0)
goto out;
if (isLOOPAES(cd->type))
r = _activate_loopaes(cd, name, passphrase_read, passphrase_size_read, flags);
else
r = _activate_by_passphrase(cd, name, keyslot, passphrase_read, passphrase_size_read, flags);
out:
crypt_safe_free(passphrase_read);
return r;
}
int crypt_activate_by_keyfile(struct crypt_device *cd,
const char *name,
int keyslot,
const char *keyfile,
size_t keyfile_size,
uint32_t flags)
{
return crypt_activate_by_keyfile_device_offset(cd, name, keyslot, keyfile,
keyfile_size, 0, flags);
}
int crypt_activate_by_keyfile_offset(struct crypt_device *cd,
const char *name,
int keyslot,
const char *keyfile,
size_t keyfile_size,
size_t keyfile_offset,
uint32_t flags)
{
return crypt_activate_by_keyfile_device_offset(cd, name, keyslot, keyfile,
keyfile_size, keyfile_offset, flags);
}
int crypt_activate_by_volume_key(struct crypt_device *cd,
static int _activate_by_volume_key(struct crypt_device *cd,
const char *name,
const char *volume_key,
size_t volume_key_size,
@@ -5275,7 +5198,9 @@ int crypt_activate_by_volume_key(struct crypt_device *cd,
if (!vk)
return -ENOMEM;
r = LUKS2_digest_verify_by_segment(cd, &cd->u.luks2.hdr, CRYPT_DEFAULT_SEGMENT, vk);
r = LUKS2_digest_verify_by_segment(cd, &cd->u.luks2.hdr,
flags & CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY ? CRYPT_ANY_SEGMENT : CRYPT_DEFAULT_SEGMENT,
vk);
if (r == -EPERM || r == -ENOENT)
log_err(cd, _("Volume key does not match the volume."));
if (r > 0)
@@ -5353,6 +5278,164 @@ int crypt_activate_by_volume_key(struct crypt_device *cd,
return r;
}
int crypt_activate_by_keyslot_context(struct crypt_device *cd,
const char *name,
int keyslot,
struct crypt_keyslot_context *kc,
uint32_t flags)
{
struct volume_key *vk = NULL;
size_t passphrase_size;
const char *passphrase = NULL;
int unlocked_keyslot, r = -EINVAL;
log_dbg(cd, "%s volume %s using %s.",
name ? "Activating" : "Checking", name ?: "passphrase", keyslot_context_type_string(kc));
if (!cd || !kc)
return -EINVAL;
if (!name && (flags & CRYPT_ACTIVATE_REFRESH))
return -EINVAL;
if ((flags & CRYPT_ACTIVATE_KEYRING_KEY) && !crypt_use_keyring_for_vk(cd))
return -EINVAL;
if ((flags & CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY) && name)
return -EINVAL;
r = _check_header_data_overlap(cd, name);
if (r < 0)
return r;
r = _activate_check_status(cd, name, flags & CRYPT_ACTIVATE_REFRESH);
if (r < 0)
return r;
/* for TCRYPT and token skip passphrase activation */
if (kc->get_passphrase && kc->type != CRYPT_KC_TYPE_TOKEN && !isTCRYPT(cd->type)) {
r = kc->get_passphrase(cd, kc, &passphrase, &passphrase_size);
if (r < 0)
return r;
if (passphrase) {
if (isLOOPAES(cd->type))
return _activate_loopaes(cd, name, passphrase, passphrase_size, flags);
else
return _activate_by_passphrase(cd, name, keyslot, passphrase, passphrase_size, flags);
}
}
/* only passphrase unlock is supported with loopaes */
if (isLOOPAES(cd->type))
return -EINVAL;
/* activate by volume key */
r = -EINVAL;
if (isLUKS1(cd->type)){
if (kc->get_luks1_volume_key)
r = kc->get_luks1_volume_key(cd, kc, keyslot, &vk);
} else if (isLUKS2(cd->type)) {
if (flags & CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY && kc->get_luks2_key)
r = kc->get_luks2_key(cd, kc, keyslot, CRYPT_ANY_SEGMENT, &vk);
else if (kc->get_luks2_volume_key)
r = kc->get_luks2_volume_key(cd, kc, keyslot, &vk);
} else if (isTCRYPT(cd->type)) {
r = 0;
} else if (isPLAIN(cd->type)) {
r = kc->get_plain_volume_key(cd, kc, &vk);
} else if (isBITLK(cd->type)) {
r = kc->get_bitlk_volume_key(cd, kc, &vk);
} else if (isFVAULT2(cd->type)) {
r = kc->get_fvault2_volume_key(cd, kc, &vk);
} else if (isVERITY(cd->type)) {
r = kc->get_verity_volume_key(cd, kc, &vk);
} else if (isINTEGRITY(cd->type)) {
r = kc->get_integrity_volume_key(cd, kc, &vk);
}
if (r < 0 && (r != -ENOENT || kc->type == CRYPT_KC_TYPE_TOKEN))
goto out;
unlocked_keyslot = r;
if (r == -ENOENT) {
crypt_free_volume_key(vk);
vk = NULL;
}
if ((r = _activate_by_volume_key(cd, name, vk ? vk->key : NULL, vk ? vk->keylength : 0, flags)) >= 0)
r = unlocked_keyslot >= 0 ? unlocked_keyslot : r;
out:
crypt_free_volume_key(vk);
return r;
}
int crypt_activate_by_passphrase(struct crypt_device *cd,
const char *name,
int keyslot,
const char *passphrase,
size_t passphrase_size,
uint32_t flags)
{
int r;
struct crypt_keyslot_context kc;
crypt_keyslot_unlock_by_passphrase_init_internal(&kc, passphrase, passphrase_size);
r = crypt_activate_by_keyslot_context(cd, name, keyslot, &kc, flags);
crypt_keyslot_context_destroy_internal(&kc);
return r;
}
int crypt_activate_by_keyfile_device_offset(struct crypt_device *cd,
const char *name,
int keyslot,
const char *keyfile,
size_t keyfile_size,
uint64_t keyfile_offset,
uint32_t flags)
{
int r;
struct crypt_keyslot_context kc;
crypt_keyslot_unlock_by_keyfile_init_internal(&kc, keyfile, keyfile_size, keyfile_offset);
r = crypt_activate_by_keyslot_context(cd, name, keyslot, &kc, flags);
crypt_keyslot_context_destroy_internal(&kc);
return r;
}
int crypt_activate_by_keyfile(struct crypt_device *cd,
const char *name,
int keyslot,
const char *keyfile,
size_t keyfile_size,
uint32_t flags)
{
return crypt_activate_by_keyfile_device_offset(cd, name, keyslot, keyfile,
keyfile_size, 0, flags);
}
int crypt_activate_by_keyfile_offset(struct crypt_device *cd,
const char *name,
int keyslot,
const char *keyfile,
size_t keyfile_size,
size_t keyfile_offset,
uint32_t flags)
{
return crypt_activate_by_keyfile_device_offset(cd, name, keyslot, keyfile,
keyfile_size, keyfile_offset, flags);
}
int crypt_activate_by_volume_key(struct crypt_device *cd,
const char *name,
const char *volume_key,
size_t volume_key_size,
uint32_t flags)
{
int r;
struct crypt_keyslot_context kc;
crypt_keyslot_unlock_by_key_init_internal(&kc, volume_key, volume_key_size);
r = crypt_activate_by_keyslot_context(cd, name, CRYPT_ANY_SLOT /* unused */, &kc, flags);
crypt_keyslot_context_destroy_internal(&kc);
return r;
}
int crypt_activate_by_signed_key(struct crypt_device *cd,
const char *name,
const char *volume_key,
@@ -6618,26 +6701,13 @@ int crypt_activate_by_token_pin(struct crypt_device *cd, const char *name,
void *usrptr, uint32_t flags)
{
int r;
struct crypt_keyslot_context kc;
log_dbg(cd, "%s volume %s using token (%s type) %d.",
name ? "Activating" : "Checking", name ?: "passphrase",
type ?: "any", token);
crypt_keyslot_unlock_by_token_init_internal(&kc, token, type, pin, pin_size, usrptr);
r = crypt_activate_by_keyslot_context(cd, name, CRYPT_ANY_SLOT, &kc, flags);
crypt_keyslot_context_destroy_internal(&kc);
if ((r = _onlyLUKS2(cd, CRYPT_CD_QUIET | CRYPT_CD_UNRESTRICTED, 0)))
return r;
if ((flags & CRYPT_ACTIVATE_KEYRING_KEY) && !crypt_use_keyring_for_vk(cd))
return -EINVAL;
if ((flags & CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY) && name)
return -EINVAL;
r = _activate_check_status(cd, name, flags & CRYPT_ACTIVATE_REFRESH);
if (r < 0)
return r;
return LUKS2_token_open_and_activate(cd, &cd->u.luks2.hdr, CRYPT_ANY_SLOT, token,
name, type, pin, pin_size, flags, usrptr);
return r;
}
int crypt_activate_by_token(struct crypt_device *cd,