mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-05 16:00:05 +01:00
Allow activation via keyslot context.
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
@@ -81,6 +86,11 @@ struct crypt_keyslot_context {
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
280
lib/setup.c
280
lib/setup.c
@@ -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);
|
||||
}
|
||||
|
||||
int crypt_activate_by_token(struct crypt_device *cd,
|
||||
|
||||
Reference in New Issue
Block a user