mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-05 16:00:05 +01:00
Switch crypt_activate_by_signed_key to keyslot context based activation.
It introduces new keyslot context type CRYPT_KC_TYPE_SIGNED_KEY.
This commit is contained in:
committed by
Daniel Zatovic
parent
e5bd99665e
commit
e43de57fac
@@ -211,6 +211,48 @@ static int get_generic_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_signed_key_by_key(struct crypt_device *cd,
|
||||
struct crypt_keyslot_context *kc,
|
||||
struct volume_key **r_vk,
|
||||
struct volume_key **r_signature)
|
||||
{
|
||||
struct volume_key *vk, *vk_sig;
|
||||
|
||||
assert(kc && ((kc->type == CRYPT_KC_TYPE_KEY) ||
|
||||
(kc->type == CRYPT_KC_TYPE_SIGNED_KEY)));
|
||||
assert(r_vk);
|
||||
assert(r_signature);
|
||||
|
||||
/* return key with no signature */
|
||||
if (kc->type == CRYPT_KC_TYPE_KEY) {
|
||||
*r_signature = NULL;
|
||||
return get_key_by_key(cd, kc, -2 /* unused */, -2 /* unused */, r_vk);
|
||||
}
|
||||
|
||||
if (!kc->u.ks.volume_key || !kc->u.ks.signature) {
|
||||
kc->error = -EINVAL;
|
||||
return kc->error;
|
||||
}
|
||||
|
||||
vk = crypt_alloc_volume_key(kc->u.ks.volume_key_size, kc->u.ks.volume_key);
|
||||
if (!vk) {
|
||||
kc->error = -ENOMEM;
|
||||
return kc->error;
|
||||
}
|
||||
|
||||
vk_sig = crypt_alloc_volume_key(kc->u.ks.signature_size, kc->u.ks.signature);
|
||||
if (!vk_sig) {
|
||||
crypt_free_volume_key(vk);
|
||||
kc->error = -ENOMEM;
|
||||
return kc->error;
|
||||
}
|
||||
|
||||
*r_vk = vk;
|
||||
*r_signature = vk_sig;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_luks2_key_by_token(struct crypt_device *cd,
|
||||
struct crypt_keyslot_context *kc,
|
||||
int keyslot,
|
||||
@@ -445,11 +487,36 @@ void crypt_keyslot_unlock_by_key_init_internal(struct crypt_keyslot_context *kc,
|
||||
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_verity_volume_key = get_generic_signed_key_by_key;
|
||||
kc->get_integrity_volume_key = get_generic_volume_key_by_key;
|
||||
unlock_method_init_internal(kc);
|
||||
}
|
||||
|
||||
void crypt_keyslot_unlock_by_signed_key_init_internal(struct crypt_keyslot_context *kc,
|
||||
const char *volume_key,
|
||||
size_t volume_key_size,
|
||||
const char *signature,
|
||||
size_t signature_size)
|
||||
{
|
||||
assert(kc);
|
||||
|
||||
kc->type = CRYPT_KC_TYPE_SIGNED_KEY;
|
||||
kc->u.ks.volume_key = volume_key;
|
||||
kc->u.ks.volume_key_size = volume_key_size;
|
||||
kc->u.ks.signature = signature;
|
||||
kc->u.ks.signature_size = signature_size;
|
||||
kc->get_luks2_key = NULL;
|
||||
kc->get_luks2_volume_key = NULL;
|
||||
kc->get_luks1_volume_key = NULL;
|
||||
kc->get_passphrase = NULL;
|
||||
kc->get_plain_volume_key = NULL;
|
||||
kc->get_bitlk_volume_key = NULL;
|
||||
kc->get_fvault2_volume_key = NULL;
|
||||
kc->get_verity_volume_key = get_generic_signed_key_by_key;
|
||||
kc->get_integrity_volume_key = NULL;
|
||||
unlock_method_init_internal(kc);
|
||||
}
|
||||
|
||||
void crypt_keyslot_unlock_by_passphrase_init_internal(struct crypt_keyslot_context *kc,
|
||||
const char *passphrase,
|
||||
size_t passphrase_size)
|
||||
@@ -648,6 +715,30 @@ int crypt_keyslot_context_init_by_volume_key(struct crypt_device *cd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_keyslot_context_init_by_signed_key(struct crypt_device *cd,
|
||||
const char *volume_key,
|
||||
size_t volume_key_size,
|
||||
const char *signature,
|
||||
size_t signature_size,
|
||||
struct crypt_keyslot_context **kc)
|
||||
{
|
||||
struct crypt_keyslot_context *tmp;
|
||||
|
||||
if (!kc)
|
||||
return -EINVAL;
|
||||
|
||||
tmp = malloc(sizeof(*tmp));
|
||||
if (!tmp)
|
||||
return -ENOMEM;
|
||||
|
||||
crypt_keyslot_unlock_by_signed_key_init_internal(tmp, volume_key, volume_key_size,
|
||||
signature, signature_size);
|
||||
|
||||
*kc = tmp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypt_keyslot_context_init_by_keyring(struct crypt_device *cd,
|
||||
const char *key_description,
|
||||
struct crypt_keyslot_context **kc)
|
||||
@@ -729,6 +820,8 @@ const char *keyslot_context_type_string(const struct crypt_keyslot_context *kc)
|
||||
return "keyring";
|
||||
case CRYPT_KC_TYPE_VK_KEYRING:
|
||||
return "volume key in keyring";
|
||||
case CRYPT_KC_TYPE_SIGNED_KEY:
|
||||
return "signed key";
|
||||
default:
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
@@ -45,6 +45,12 @@ typedef int (*keyslot_context_get_generic_volume_key) (
|
||||
struct crypt_keyslot_context *kc,
|
||||
struct volume_key **r_vk);
|
||||
|
||||
typedef int (*keyslot_context_get_generic_signed_key) (
|
||||
struct crypt_device *cd,
|
||||
struct crypt_keyslot_context *kc,
|
||||
struct volume_key **r_vk,
|
||||
struct volume_key **r_signature);
|
||||
|
||||
typedef int (*keyslot_context_get_passphrase) (
|
||||
struct crypt_device *cd,
|
||||
struct crypt_keyslot_context *kc,
|
||||
@@ -76,6 +82,12 @@ struct crypt_keyslot_context {
|
||||
const char *volume_key;
|
||||
size_t volume_key_size;
|
||||
} k;
|
||||
struct {
|
||||
const char *volume_key;
|
||||
size_t volume_key_size;
|
||||
const char *signature;
|
||||
size_t signature_size;
|
||||
} ks;
|
||||
struct {
|
||||
const char *key_description;
|
||||
} kr;
|
||||
@@ -97,7 +109,7 @@ struct crypt_keyslot_context {
|
||||
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_signed_key get_verity_volume_key;
|
||||
keyslot_context_get_generic_volume_key get_integrity_volume_key;
|
||||
keyslot_context_get_passphrase get_passphrase;
|
||||
};
|
||||
@@ -108,6 +120,12 @@ void crypt_keyslot_unlock_by_key_init_internal(struct crypt_keyslot_context *kc,
|
||||
const char *volume_key,
|
||||
size_t volume_key_size);
|
||||
|
||||
void crypt_keyslot_unlock_by_signed_key_init_internal(struct crypt_keyslot_context *kc,
|
||||
const char *volume_key,
|
||||
size_t volume_key_size,
|
||||
const char *signature,
|
||||
size_t signature_size);
|
||||
|
||||
void crypt_keyslot_unlock_by_passphrase_init_internal(struct crypt_keyslot_context *kc,
|
||||
const char *passphrase,
|
||||
size_t passphrase_size);
|
||||
|
||||
@@ -1279,6 +1279,28 @@ int crypt_keyslot_context_init_by_volume_key(struct crypt_device *cd,
|
||||
size_t volume_key_size,
|
||||
struct crypt_keyslot_context **kc);
|
||||
|
||||
/**
|
||||
* Initialize keyslot context via signed key.
|
||||
*
|
||||
* @param cd crypt device handle initialized to device context
|
||||
*
|
||||
* @param volume_key provided volume key
|
||||
* @param volume_key_size size of volume_key
|
||||
* @param signature buffer with signature for the key
|
||||
* @param signature_size bsize of signature buffer
|
||||
* @param kc returns crypt keyslot context handle type CRYPT_KC_TYPE_SIGNED_KEY
|
||||
*
|
||||
* @return zero on success or negative errno otherwise.
|
||||
*
|
||||
* @note currently supported only with VERITY devices.
|
||||
*/
|
||||
int crypt_keyslot_context_init_by_signed_key(struct crypt_device *cd,
|
||||
const char *volume_key,
|
||||
size_t volume_key_size,
|
||||
const char *signature,
|
||||
size_t signature_size,
|
||||
struct crypt_keyslot_context **kc);
|
||||
|
||||
/**
|
||||
* Initialize keyslot context via passphrase stored in a keyring.
|
||||
*
|
||||
@@ -1361,6 +1383,8 @@ int crypt_keyslot_context_set_pin(struct crypt_device *cd,
|
||||
* (@link crypt_keyslot_context_init_by_vk_in_keyring @endlink)
|
||||
*/
|
||||
#define CRYPT_KC_TYPE_VK_KEYRING INT16_C(6)
|
||||
/** keyslot context initialized by signed key (@link crypt_keyslot_context_init_by_signed_key @endlink) */
|
||||
#define CRYPT_KC_TYPE_SIGNED_KEY INT16_C(7)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
|
||||
@@ -175,6 +175,7 @@ CRYPTSETUP_2.7 {
|
||||
crypt_get_vk_keyring_type;
|
||||
crypt_keyslot_context_init_by_keyring;
|
||||
crypt_keyslot_context_init_by_vk_in_keyring;
|
||||
crypt_keyslot_context_init_by_signed_key;
|
||||
crypt_resume_by_keyslot_context;
|
||||
crypt_set_keyring_to_link;
|
||||
crypt_set_vk_keyring_type;
|
||||
|
||||
92
lib/setup.c
92
lib/setup.c
@@ -5130,9 +5130,9 @@ static int _activate_by_volume_key(struct crypt_device *cd,
|
||||
assert(crypt_volume_key_get_id(vk) == LUKS2_digest_by_segment(&cd->u.luks2.hdr, CRYPT_DEFAULT_SEGMENT));
|
||||
r = LUKS2_activate(cd, name, vk, external_key, flags);
|
||||
} else if (isVERITY(cd->type)) {
|
||||
assert(!external_key);
|
||||
assert(crypt_volume_key_get_id(vk) == KEY_VERIFIED);
|
||||
r = crypt_activate_by_signed_key(cd, name, vk->key, vk->keylength, NULL, 0, flags);
|
||||
r = VERITY_activate(cd, name, vk, external_key, cd->u.verity.fec_device,
|
||||
&cd->u.verity.hdr, flags);
|
||||
} else if (isTCRYPT(cd->type)) {
|
||||
assert(!external_key);
|
||||
r = TCRYPT_activate(cd, name, &cd->u.tcrypt.hdr,
|
||||
@@ -5163,7 +5163,8 @@ int crypt_activate_by_keyslot_context(struct crypt_device *cd,
|
||||
uint32_t flags)
|
||||
{
|
||||
bool use_keyring;
|
||||
struct volume_key *p_ext_key, *crypt_key = NULL, *opal_key = NULL, *vk = NULL, *p_crypt = NULL;
|
||||
struct volume_key *p_ext_key, *crypt_key = NULL, *opal_key = NULL, *vk = NULL,
|
||||
*vk_sign = NULL, *p_crypt = NULL;
|
||||
size_t passphrase_size;
|
||||
const char *passphrase = NULL;
|
||||
int unlocked_keyslot, r = -EINVAL;
|
||||
@@ -5179,10 +5180,14 @@ int crypt_activate_by_keyslot_context(struct crypt_device *cd,
|
||||
return -EINVAL;
|
||||
if ((flags & CRYPT_ACTIVATE_ALLOW_UNBOUND_KEY) && name)
|
||||
return -EINVAL;
|
||||
if (kc->type == CRYPT_KC_TYPE_KEYRING && !kernel_keyring_support()) {
|
||||
if ((kc->type == CRYPT_KC_TYPE_KEYRING) && !kernel_keyring_support()) {
|
||||
log_err(cd, _("Kernel keyring is not supported by the kernel."));
|
||||
return -EINVAL;
|
||||
}
|
||||
if ((kc->type == CRYPT_KC_TYPE_SIGNED_KEY) && !kernel_keyring_support()) {
|
||||
log_err(cd, _("Kernel keyring missing: required for passing signature to kernel."));
|
||||
return -EINVAL;
|
||||
}
|
||||
r = _check_header_data_overlap(cd, name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -5195,6 +5200,7 @@ int crypt_activate_by_keyslot_context(struct crypt_device *cd,
|
||||
r = kc->get_passphrase(cd, kc, &passphrase, &passphrase_size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
/* TODO: Only loopaes should by activated by passphrase method */
|
||||
if (passphrase) {
|
||||
if (isLOOPAES(cd->type))
|
||||
return _activate_loopaes(cd, name, passphrase, passphrase_size, flags);
|
||||
@@ -5227,9 +5233,16 @@ int crypt_activate_by_keyslot_context(struct crypt_device *cd,
|
||||
} else if (isFVAULT2(cd->type)) {
|
||||
if (kc->get_fvault2_volume_key)
|
||||
r = kc->get_fvault2_volume_key(cd, kc, &vk);
|
||||
} else if (isVERITY(cd->type)) {
|
||||
} else if (isVERITY(cd->type) && (name || kc->type != CRYPT_KC_TYPE_SIGNED_KEY)) {
|
||||
if (kc->get_verity_volume_key)
|
||||
r = kc->get_verity_volume_key(cd, kc, &vk);
|
||||
r = kc->get_verity_volume_key(cd, kc, &vk, &vk_sign);
|
||||
if (r >= 0)
|
||||
r = VERITY_verify_params(cd, &cd->u.verity.hdr, vk_sign != NULL,
|
||||
cd->u.verity.fec_device, vk);
|
||||
|
||||
free(CONST_CAST(void*)cd->u.verity.root_hash);
|
||||
cd->u.verity.root_hash = NULL;
|
||||
flags |= CRYPT_ACTIVATE_READONLY;
|
||||
} else if (isINTEGRITY(cd->type)) {
|
||||
if (kc->get_integrity_volume_key)
|
||||
r = kc->get_integrity_volume_key(cd, kc, &vk);
|
||||
@@ -5255,12 +5268,6 @@ int crypt_activate_by_keyslot_context(struct crypt_device *cd,
|
||||
if (r < 0)
|
||||
goto out;
|
||||
|
||||
if (!name && isVERITY(cd->type)) {
|
||||
r = crypt_activate_by_signed_key(cd, name, vk->key, vk->keylength, NULL, 0, flags);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (isLUKS2(cd->type)) {
|
||||
if (LUKS2_segment_is_hw_opal(&cd->u.luks2.hdr, CRYPT_DEFAULT_SEGMENT)) {
|
||||
r = LUKS2_split_crypt_and_opal_keys(cd, &cd->u.luks2.hdr,
|
||||
@@ -5296,7 +5303,7 @@ int crypt_activate_by_keyslot_context(struct crypt_device *cd,
|
||||
}
|
||||
} else {
|
||||
p_crypt = vk;
|
||||
p_ext_key = NULL;
|
||||
p_ext_key = vk_sign;
|
||||
}
|
||||
|
||||
if (name)
|
||||
@@ -5311,6 +5318,7 @@ out:
|
||||
crypt_free_volume_key(vk);
|
||||
crypt_free_volume_key(crypt_key);
|
||||
crypt_free_volume_key(opal_key);
|
||||
crypt_free_volume_key(vk_sign);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -5396,8 +5404,8 @@ int crypt_activate_by_signed_key(struct crypt_device *cd,
|
||||
size_t signature_size,
|
||||
uint32_t flags)
|
||||
{
|
||||
char description[512];
|
||||
int r;
|
||||
struct crypt_keyslot_context kc;
|
||||
|
||||
if (!cd || !isVERITY(cd->type))
|
||||
return -EINVAL;
|
||||
@@ -5407,57 +5415,13 @@ int crypt_activate_by_signed_key(struct crypt_device *cd,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (name)
|
||||
log_dbg(cd, "Activating volume %s by %skey.", name, signature ? "signed " : "");
|
||||
else
|
||||
log_dbg(cd, "Checking volume by key.");
|
||||
|
||||
if (cd->u.verity.hdr.flags & CRYPT_VERITY_ROOT_HASH_SIGNATURE && !signature) {
|
||||
log_err(cd, _("Root hash signature required."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = _activate_check_status(cd, name, flags & CRYPT_ACTIVATE_REFRESH);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (signature && !kernel_keyring_support()) {
|
||||
log_err(cd, _("Kernel keyring missing: required for passing signature to kernel."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* volume_key == root hash */
|
||||
free(CONST_CAST(void*)cd->u.verity.root_hash);
|
||||
cd->u.verity.root_hash = NULL;
|
||||
|
||||
if (signature) {
|
||||
r = snprintf(description, sizeof(description)-1, "cryptsetup:%s%s%s",
|
||||
crypt_get_uuid(cd) ?: "", crypt_get_uuid(cd) ? "-" : "", name);
|
||||
if (r < 0)
|
||||
return -EINVAL;
|
||||
|
||||
log_dbg(cd, "Adding signature into keyring %s", description);
|
||||
r = keyring_add_key_in_thread_keyring(USER_KEY, description, signature, signature_size);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to load key in kernel keyring."));
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
r = VERITY_activate(cd, name, volume_key, volume_key_size,
|
||||
signature ? description : NULL,
|
||||
cd->u.verity.fec_device,
|
||||
&cd->u.verity.hdr, flags | CRYPT_ACTIVATE_READONLY);
|
||||
|
||||
if (!r) {
|
||||
cd->u.verity.root_hash_size = volume_key_size;
|
||||
cd->u.verity.root_hash = malloc(volume_key_size);
|
||||
if (cd->u.verity.root_hash)
|
||||
memcpy(CONST_CAST(void*)cd->u.verity.root_hash, volume_key, volume_key_size);
|
||||
}
|
||||
|
||||
if (signature)
|
||||
crypt_drop_keyring_key_by_description(cd, description, USER_KEY);
|
||||
crypt_keyslot_unlock_by_signed_key_init_internal(&kc, volume_key, volume_key_size,
|
||||
signature, signature_size);
|
||||
else
|
||||
crypt_keyslot_unlock_by_key_init_internal(&kc, volume_key, volume_key_size);
|
||||
r = crypt_activate_by_keyslot_context(cd, name, -2 /* unused */, &kc, flags);
|
||||
crypt_keyslot_context_destroy_internal(&kc);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -251,91 +251,131 @@ int VERITY_UUID_generate(char **uuid_string)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int VERITY_verify_params(struct crypt_device *cd,
|
||||
struct crypt_params_verity *hdr,
|
||||
bool signed_root_hash,
|
||||
struct device *fec_device,
|
||||
struct volume_key *root_hash)
|
||||
{
|
||||
bool userspace_verification;
|
||||
int v, r;
|
||||
unsigned int fec_errors = 0;
|
||||
|
||||
assert(cd);
|
||||
assert(hdr);
|
||||
assert(root_hash);
|
||||
|
||||
log_dbg(cd, "Verifying VERITY device using hash %s.",
|
||||
hdr->hash_name);
|
||||
|
||||
userspace_verification = hdr->flags & CRYPT_VERITY_CHECK_HASH;
|
||||
|
||||
if (userspace_verification && signed_root_hash) {
|
||||
log_err(cd, _("Root hash signature verification is not supported."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((hdr->flags & CRYPT_VERITY_ROOT_HASH_SIGNATURE) && !signed_root_hash) {
|
||||
log_err(cd, _("Root hash signature required."));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!userspace_verification)
|
||||
return 0;
|
||||
|
||||
log_dbg(cd, "Verification of VERITY data in userspace required.");
|
||||
r = VERITY_verify(cd, hdr, root_hash->key, root_hash->keylength);
|
||||
|
||||
if ((r == -EPERM || r == -EFAULT) && fec_device) {
|
||||
v = r;
|
||||
log_dbg(cd, "Verification failed, trying to repair with FEC device.");
|
||||
r = VERITY_FEC_process(cd, hdr, fec_device, 1, &fec_errors);
|
||||
if (r < 0)
|
||||
log_err(cd, _("Errors cannot be repaired with FEC device."));
|
||||
else if (fec_errors) {
|
||||
log_err(cd, _("Found %u repairable errors with FEC device."),
|
||||
fec_errors);
|
||||
/* If root hash failed, we cannot be sure it was properly repaired */
|
||||
}
|
||||
if (v == -EFAULT)
|
||||
r = -EPERM;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Activate verity device in kernel device-mapper */
|
||||
int VERITY_activate(struct crypt_device *cd,
|
||||
const char *name,
|
||||
const char *root_hash,
|
||||
size_t root_hash_size,
|
||||
const char *signature_description,
|
||||
struct volume_key *root_hash,
|
||||
struct volume_key *signature,
|
||||
struct device *fec_device,
|
||||
struct crypt_params_verity *verity_hdr,
|
||||
uint32_t activation_flags)
|
||||
{
|
||||
uint32_t dmv_flags;
|
||||
unsigned int fec_errors = 0;
|
||||
int r, v;
|
||||
struct crypt_dm_active_device dmd = {
|
||||
.size = verity_hdr->data_size * verity_hdr->data_block_size / 512,
|
||||
.flags = activation_flags,
|
||||
.uuid = crypt_get_uuid(cd),
|
||||
};
|
||||
int r;
|
||||
char *description = NULL;
|
||||
struct crypt_dm_active_device dmd = { 0 };
|
||||
|
||||
log_dbg(cd, "Trying to activate VERITY device %s using hash %s.",
|
||||
name ?: "[none]", verity_hdr->hash_name);
|
||||
assert(name);
|
||||
assert(root_hash);
|
||||
assert(verity_hdr);
|
||||
|
||||
if (verity_hdr->flags & CRYPT_VERITY_CHECK_HASH) {
|
||||
if (signature_description) {
|
||||
log_err(cd, _("Root hash signature verification is not supported."));
|
||||
return -EINVAL;
|
||||
}
|
||||
dmd.size = verity_hdr->data_size * verity_hdr->data_block_size / 512;
|
||||
dmd.flags = activation_flags;
|
||||
dmd.uuid = crypt_get_uuid(cd);
|
||||
|
||||
log_dbg(cd, "Verification of data in userspace required.");
|
||||
r = VERITY_verify(cd, verity_hdr, root_hash, root_hash_size);
|
||||
|
||||
if ((r == -EPERM || r == -EFAULT) && fec_device) {
|
||||
v = r;
|
||||
log_dbg(cd, "Verification failed, trying to repair with FEC device.");
|
||||
r = VERITY_FEC_process(cd, verity_hdr, fec_device, 1, &fec_errors);
|
||||
if (r < 0)
|
||||
log_err(cd, _("Errors cannot be repaired with FEC device."));
|
||||
else if (fec_errors) {
|
||||
log_err(cd, _("Found %u repairable errors with FEC device."),
|
||||
fec_errors);
|
||||
/* If root hash failed, we cannot be sure it was properly repaired */
|
||||
}
|
||||
if (v == -EFAULT)
|
||||
r = -EPERM;
|
||||
}
|
||||
log_dbg(cd, "Activating VERITY device %s using hash %s.",
|
||||
name, verity_hdr->hash_name);
|
||||
|
||||
if (signature) {
|
||||
r = asprintf(&description, "cryptsetup:%s%s%s",
|
||||
crypt_get_uuid(cd) ?: "", crypt_get_uuid(cd) ? "-" : "", name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
return -EINVAL;
|
||||
|
||||
if (!name)
|
||||
return 0;
|
||||
log_dbg(cd, "Adding signature into keyring %s", description);
|
||||
r = keyring_add_key_in_thread_keyring(USER_KEY, description, signature->key, signature->keylength);
|
||||
if (r) {
|
||||
log_err(cd, _("Failed to load key in kernel keyring."));
|
||||
free(description);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
r = device_block_adjust(cd, crypt_metadata_device(cd), DEV_OK,
|
||||
0, NULL, NULL);
|
||||
if (r)
|
||||
return r;
|
||||
goto out;
|
||||
|
||||
r = device_block_adjust(cd, crypt_data_device(cd), DEV_EXCL,
|
||||
0, &dmd.size, &dmd.flags);
|
||||
if (r)
|
||||
return r;
|
||||
goto out;
|
||||
|
||||
if (fec_device) {
|
||||
r = device_block_adjust(cd, fec_device, DEV_OK,
|
||||
0, NULL, NULL);
|
||||
if (r)
|
||||
return r;
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = dm_verity_target_set(&dmd.segment, 0, dmd.size, crypt_data_device(cd),
|
||||
crypt_metadata_device(cd), fec_device, root_hash,
|
||||
root_hash_size, signature_description,
|
||||
crypt_metadata_device(cd), fec_device, root_hash->key,
|
||||
root_hash->keylength, description,
|
||||
VERITY_hash_offset_block(verity_hdr),
|
||||
VERITY_FEC_blocks(cd, fec_device, verity_hdr), verity_hdr);
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
goto out;
|
||||
|
||||
r = dm_create_device(cd, name, CRYPT_VERITY, &dmd);
|
||||
if (r < 0 && (dm_flags(cd, DM_VERITY, &dmv_flags) || !(dmv_flags & DM_VERITY_SUPPORTED))) {
|
||||
log_err(cd, _("Kernel does not support dm-verity mapping."));
|
||||
r = -ENOTSUP;
|
||||
}
|
||||
if (r < 0 && signature_description && !(dmv_flags & DM_VERITY_SIGNATURE_SUPPORTED)) {
|
||||
if (r < 0 && signature && !(dmv_flags & DM_VERITY_SIGNATURE_SUPPORTED)) {
|
||||
log_err(cd, _("Kernel does not support dm-verity signature option."));
|
||||
r = -ENOTSUP;
|
||||
}
|
||||
@@ -351,6 +391,8 @@ int VERITY_activate(struct crypt_device *cd,
|
||||
|
||||
r = 0;
|
||||
out:
|
||||
crypt_drop_keyring_key_by_description(cd, description, USER_KEY);
|
||||
free(description);
|
||||
dm_targets_free(cd, &dmd);
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define VERITY_MAX_HASH_TYPE 1
|
||||
#define VERITY_BLOCK_SIZE_OK(x) ((x) % 512 || (x) < 512 || \
|
||||
@@ -31,6 +32,7 @@
|
||||
struct crypt_device;
|
||||
struct crypt_params_verity;
|
||||
struct device;
|
||||
struct volume_key;
|
||||
|
||||
int VERITY_read_sb(struct crypt_device *cd,
|
||||
uint64_t sb_offset,
|
||||
@@ -44,13 +46,18 @@ int VERITY_write_sb(struct crypt_device *cd,
|
||||
|
||||
int VERITY_activate(struct crypt_device *cd,
|
||||
const char *name,
|
||||
const char *root_hash,
|
||||
size_t root_hash_size,
|
||||
const char *signature_description,
|
||||
struct volume_key *root_hash,
|
||||
struct volume_key *signature,
|
||||
struct device *fec_device,
|
||||
struct crypt_params_verity *verity_hdr,
|
||||
uint32_t activation_flags);
|
||||
|
||||
int VERITY_verify_params(struct crypt_device *cd,
|
||||
struct crypt_params_verity *hdr,
|
||||
bool signed_root_hash,
|
||||
struct device *fec_device,
|
||||
struct volume_key *root_hash);
|
||||
|
||||
int VERITY_verify(struct crypt_device *cd,
|
||||
struct crypt_params_verity *verity_hdr,
|
||||
const char *root_hash,
|
||||
|
||||
Reference in New Issue
Block a user