mirror of
https://gitlab.com/cryptsetup/cryptsetup.git
synced 2025-12-05 16:00:05 +01:00
Add --root-hash-signature parameter to veritysetup
Optional parameter root hash signature is added that can be added to veritysetup. The signature file is opened and the signature is added to the keyring. The kernel will use the signature to validate the roothash. Usage: veritysetup open <data_device> name <hash_device> <root_hash> --root-hash-signature=<roothash_p7_sig_file> Signed-off-by: Jaskaran Khurana <jaskarankhurana@linux.microsoft.com> Signed-off-by: Luca Boccassi <luca.boccassi@microsoft.com> [Original patch rewritten by Milan Broz]
This commit is contained in:
committed by
Milan Broz
parent
d7667e9e6e
commit
f247038e65
@@ -1290,6 +1290,31 @@ int crypt_activate_by_volume_key(struct crypt_device *cd,
|
|||||||
size_t volume_key_size,
|
size_t volume_key_size,
|
||||||
uint32_t flags);
|
uint32_t flags);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activate VERITY device using provided key and optional signature).
|
||||||
|
*
|
||||||
|
* @param cd crypt device handle
|
||||||
|
* @param name name of device to create
|
||||||
|
* @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 flags activation flags
|
||||||
|
*
|
||||||
|
* @return @e 0 on success or negative errno value otherwise.
|
||||||
|
*
|
||||||
|
* @note For VERITY the volume key means root hash required for activation.
|
||||||
|
* Because kernel dm-verity is always read only, you have to provide
|
||||||
|
* CRYPT_ACTIVATE_READONLY flag always.
|
||||||
|
*/
|
||||||
|
int crypt_activate_by_signed_key(struct crypt_device *cd,
|
||||||
|
const char *name,
|
||||||
|
const char *volume_key,
|
||||||
|
size_t volume_key_size,
|
||||||
|
const char *signature,
|
||||||
|
size_t signature_size,
|
||||||
|
uint32_t flags);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activate device using passphrase stored in kernel keyring.
|
* Activate device using passphrase stored in kernel keyring.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ CRYPTSETUP_2.0 {
|
|||||||
crypt_activate_by_keyfile_offset;
|
crypt_activate_by_keyfile_offset;
|
||||||
crypt_activate_by_keyfile_device_offset;
|
crypt_activate_by_keyfile_device_offset;
|
||||||
crypt_activate_by_volume_key;
|
crypt_activate_by_volume_key;
|
||||||
|
crypt_activate_by_signed_key;
|
||||||
crypt_activate_by_keyring;
|
crypt_activate_by_keyring;
|
||||||
crypt_deactivate;
|
crypt_deactivate;
|
||||||
crypt_deactivate_by_name;
|
crypt_deactivate_by_name;
|
||||||
|
|||||||
@@ -203,6 +203,9 @@ static void _dm_set_verity_compat(struct crypt_device *cd,
|
|||||||
_dm_flags |= DM_VERITY_FEC_SUPPORTED;
|
_dm_flags |= DM_VERITY_FEC_SUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_dm_satisfies_version(1, 5, 0, verity_maj, verity_min, verity_patch))
|
||||||
|
_dm_flags |= DM_VERITY_SIGNATURE_SUPPORTED;
|
||||||
|
|
||||||
_dm_verity_checked = true;
|
_dm_verity_checked = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -677,7 +680,7 @@ static char *get_dm_verity_params(const struct dm_target *tgt, uint32_t flags)
|
|||||||
int max_size, r, num_options = 0;
|
int max_size, r, num_options = 0;
|
||||||
struct crypt_params_verity *vp;
|
struct crypt_params_verity *vp;
|
||||||
char *params = NULL, *hexroot = NULL, *hexsalt = NULL;
|
char *params = NULL, *hexroot = NULL, *hexsalt = NULL;
|
||||||
char features[256], fec_features[256];
|
char features[256], fec_features[256], verity_verify_args[512+32];
|
||||||
|
|
||||||
if (!tgt || !tgt->u.verity.vp)
|
if (!tgt || !tgt->u.verity.vp)
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -707,6 +710,13 @@ static char *get_dm_verity_params(const struct dm_target *tgt, uint32_t flags)
|
|||||||
} else
|
} else
|
||||||
*fec_features = '\0';
|
*fec_features = '\0';
|
||||||
|
|
||||||
|
if (tgt->u.verity.root_hash_sig_key_desc) {
|
||||||
|
num_options += 2;
|
||||||
|
snprintf(verity_verify_args, sizeof(verity_verify_args)-1,
|
||||||
|
" root_hash_sig_key_desc %s", tgt->u.verity.root_hash_sig_key_desc);
|
||||||
|
} else
|
||||||
|
*verity_verify_args = '\0';
|
||||||
|
|
||||||
if (num_options)
|
if (num_options)
|
||||||
snprintf(features, sizeof(features)-1, " %d%s%s%s%s", num_options,
|
snprintf(features, sizeof(features)-1, " %d%s%s%s%s", num_options,
|
||||||
(flags & CRYPT_ACTIVATE_IGNORE_CORRUPTION) ? " ignore_corruption" : "",
|
(flags & CRYPT_ACTIVATE_IGNORE_CORRUPTION) ? " ignore_corruption" : "",
|
||||||
@@ -732,19 +742,22 @@ static char *get_dm_verity_params(const struct dm_target *tgt, uint32_t flags)
|
|||||||
max_size = strlen(hexroot) + strlen(hexsalt) +
|
max_size = strlen(hexroot) + strlen(hexsalt) +
|
||||||
strlen(device_block_path(tgt->data_device)) +
|
strlen(device_block_path(tgt->data_device)) +
|
||||||
strlen(device_block_path(tgt->u.verity.hash_device)) +
|
strlen(device_block_path(tgt->u.verity.hash_device)) +
|
||||||
strlen(vp->hash_name) + strlen(features) + strlen(fec_features) + 128;
|
strlen(vp->hash_name) + strlen(features) + strlen(fec_features) + 128 +
|
||||||
|
strlen(verity_verify_args);
|
||||||
|
|
||||||
params = crypt_safe_alloc(max_size);
|
params = crypt_safe_alloc(max_size);
|
||||||
if (!params)
|
if (!params)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
r = snprintf(params, max_size,
|
r = snprintf(params, max_size,
|
||||||
"%u %s %s %u %u %" PRIu64 " %" PRIu64 " %s %s %s%s%s",
|
"%u %s %s %u %u %" PRIu64 " %" PRIu64 " %s %s %s%s%s%s",
|
||||||
vp->hash_type, device_block_path(tgt->data_device),
|
vp->hash_type, device_block_path(tgt->data_device),
|
||||||
device_block_path(tgt->u.verity.hash_device),
|
device_block_path(tgt->u.verity.hash_device),
|
||||||
vp->data_block_size, vp->hash_block_size,
|
vp->data_block_size, vp->hash_block_size,
|
||||||
vp->data_size, tgt->u.verity.hash_offset,
|
vp->data_size, tgt->u.verity.hash_offset,
|
||||||
vp->hash_name, hexroot, hexsalt, features, fec_features);
|
vp->hash_name, hexroot, hexsalt, features, fec_features,
|
||||||
|
verity_verify_args);
|
||||||
|
|
||||||
if (r < 0 || r >= max_size) {
|
if (r < 0 || r >= max_size) {
|
||||||
crypt_safe_free(params);
|
crypt_safe_free(params);
|
||||||
params = NULL;
|
params = NULL;
|
||||||
@@ -1484,6 +1497,7 @@ static void _dm_target_free_query_path(struct crypt_device *cd, struct dm_target
|
|||||||
crypt_free_verity_params(tgt->u.verity.vp);
|
crypt_free_verity_params(tgt->u.verity.vp);
|
||||||
device_free(cd, tgt->u.verity.hash_device);
|
device_free(cd, tgt->u.verity.hash_device);
|
||||||
free(CONST_CAST(void*)tgt->u.verity.root_hash);
|
free(CONST_CAST(void*)tgt->u.verity.root_hash);
|
||||||
|
free(CONST_CAST(void*)tgt->u.verity.root_hash_sig_key_desc);
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case DM_LINEAR:
|
case DM_LINEAR:
|
||||||
/* fall through */
|
/* fall through */
|
||||||
@@ -1991,6 +2005,7 @@ static int _dm_target_query_verity(struct crypt_device *cd,
|
|||||||
int r;
|
int r;
|
||||||
struct device *data_device = NULL, *hash_device = NULL, *fec_device = NULL;
|
struct device *data_device = NULL, *hash_device = NULL, *fec_device = NULL;
|
||||||
char *hash_name = NULL, *root_hash = NULL, *salt = NULL, *fec_dev_str = NULL;
|
char *hash_name = NULL, *root_hash = NULL, *salt = NULL, *fec_dev_str = NULL;
|
||||||
|
char *root_hash_sig_key_desc = NULL;
|
||||||
|
|
||||||
if (get_flags & DM_ACTIVE_VERITY_PARAMS) {
|
if (get_flags & DM_ACTIVE_VERITY_PARAMS) {
|
||||||
vp = crypt_zalloc(sizeof(*vp));
|
vp = crypt_zalloc(sizeof(*vp));
|
||||||
@@ -2174,6 +2189,12 @@ static int _dm_target_query_verity(struct crypt_device *cd,
|
|||||||
if (vp)
|
if (vp)
|
||||||
vp->fec_roots = val32;
|
vp->fec_roots = val32;
|
||||||
i++;
|
i++;
|
||||||
|
} else if (!strcasecmp(arg, "root_hash_sig_key_desc")) {
|
||||||
|
str = strsep(¶ms, " ");
|
||||||
|
if (!str)
|
||||||
|
goto err;
|
||||||
|
root_hash_sig_key_desc = strdup(str);
|
||||||
|
i++;
|
||||||
} else /* unknown option */
|
} else /* unknown option */
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
@@ -2199,6 +2220,9 @@ static int _dm_target_query_verity(struct crypt_device *cd,
|
|||||||
vp->salt = salt;
|
vp->salt = salt;
|
||||||
if (vp && fec_dev_str)
|
if (vp && fec_dev_str)
|
||||||
vp->fec_device = fec_dev_str;
|
vp->fec_device = fec_dev_str;
|
||||||
|
if (root_hash_sig_key_desc)
|
||||||
|
tgt->u.verity.root_hash_sig_key_desc = root_hash_sig_key_desc;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
err:
|
err:
|
||||||
device_free(cd, data_device);
|
device_free(cd, data_device);
|
||||||
@@ -2890,8 +2914,8 @@ err:
|
|||||||
|
|
||||||
int dm_verity_target_set(struct dm_target *tgt, uint64_t seg_offset, uint64_t seg_size,
|
int dm_verity_target_set(struct dm_target *tgt, uint64_t seg_offset, uint64_t seg_size,
|
||||||
struct device *data_device, struct device *hash_device, struct device *fec_device,
|
struct device *data_device, struct device *hash_device, struct device *fec_device,
|
||||||
const char *root_hash, uint32_t root_hash_size, uint64_t hash_offset_block,
|
const char *root_hash, uint32_t root_hash_size, const char *root_hash_sig_key_desc,
|
||||||
uint64_t hash_blocks, struct crypt_params_verity *vp)
|
uint64_t hash_offset_block, uint64_t hash_blocks, struct crypt_params_verity *vp)
|
||||||
{
|
{
|
||||||
if (!data_device || !hash_device || !vp)
|
if (!data_device || !hash_device || !vp)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -2906,6 +2930,7 @@ int dm_verity_target_set(struct dm_target *tgt, uint64_t seg_offset, uint64_t se
|
|||||||
tgt->u.verity.fec_device = fec_device;
|
tgt->u.verity.fec_device = fec_device;
|
||||||
tgt->u.verity.root_hash = root_hash;
|
tgt->u.verity.root_hash = root_hash;
|
||||||
tgt->u.verity.root_hash_size = root_hash_size;
|
tgt->u.verity.root_hash_size = root_hash_size;
|
||||||
|
tgt->u.verity.root_hash_sig_key_desc = root_hash_sig_key_desc;
|
||||||
tgt->u.verity.hash_offset = hash_offset_block;
|
tgt->u.verity.hash_offset = hash_offset_block;
|
||||||
tgt->u.verity.fec_offset = vp->fec_area_offset / vp->hash_block_size;
|
tgt->u.verity.fec_offset = vp->fec_area_offset / vp->hash_block_size;
|
||||||
tgt->u.verity.hash_blocks = hash_blocks;
|
tgt->u.verity.hash_blocks = hash_blocks;
|
||||||
|
|||||||
128
lib/setup.c
128
lib/setup.c
@@ -3759,6 +3759,27 @@ out:
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int kernel_keyring_support(void)
|
||||||
|
{
|
||||||
|
static unsigned _checked = 0;
|
||||||
|
|
||||||
|
if (!_checked) {
|
||||||
|
_kernel_keyring_supported = keyring_check();
|
||||||
|
_checked = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _kernel_keyring_supported;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dmcrypt_keyring_bug(void)
|
||||||
|
{
|
||||||
|
uint64_t kversion;
|
||||||
|
|
||||||
|
if (kernel_version(&kversion))
|
||||||
|
return 1;
|
||||||
|
return kversion < version(4,15,0,0);
|
||||||
|
}
|
||||||
|
|
||||||
int create_or_reload_device(struct crypt_device *cd, const char *name,
|
int create_or_reload_device(struct crypt_device *cd, const char *name,
|
||||||
const char *type, struct crypt_dm_active_device *dmd)
|
const char *type, struct crypt_dm_active_device *dmd)
|
||||||
{
|
{
|
||||||
@@ -4234,7 +4255,6 @@ int crypt_activate_by_keyfile_offset(struct crypt_device *cd,
|
|||||||
return crypt_activate_by_keyfile_device_offset(cd, name, keyslot, keyfile,
|
return crypt_activate_by_keyfile_device_offset(cd, name, keyslot, keyfile,
|
||||||
keyfile_size, keyfile_offset, flags);
|
keyfile_size, keyfile_offset, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
int crypt_activate_by_volume_key(struct crypt_device *cd,
|
int crypt_activate_by_volume_key(struct crypt_device *cd,
|
||||||
const char *name,
|
const char *name,
|
||||||
const char *volume_key,
|
const char *volume_key,
|
||||||
@@ -4329,24 +4349,7 @@ int crypt_activate_by_volume_key(struct crypt_device *cd,
|
|||||||
if (!r && name)
|
if (!r && name)
|
||||||
r = LUKS2_activate(cd, name, vk, flags);
|
r = LUKS2_activate(cd, name, vk, flags);
|
||||||
} else if (isVERITY(cd->type)) {
|
} else if (isVERITY(cd->type)) {
|
||||||
/* volume_key == root hash */
|
r = crypt_activate_by_signed_key(cd, name, volume_key, volume_key_size, NULL, 0, flags);
|
||||||
if (!volume_key || !volume_key_size) {
|
|
||||||
log_err(cd, _("Incorrect root hash specified for verity device."));
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(CONST_CAST(void*)cd->u.verity.root_hash);
|
|
||||||
cd->u.verity.root_hash = NULL;
|
|
||||||
|
|
||||||
r = VERITY_activate(cd, name, volume_key, volume_key_size, 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);
|
|
||||||
}
|
|
||||||
} else if (isTCRYPT(cd->type)) {
|
} else if (isTCRYPT(cd->type)) {
|
||||||
if (!name)
|
if (!name)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -4376,6 +4379,72 @@ int crypt_activate_by_volume_key(struct crypt_device *cd,
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int crypt_activate_by_signed_key(struct crypt_device *cd,
|
||||||
|
const char *name,
|
||||||
|
const char *volume_key,
|
||||||
|
size_t volume_key_size,
|
||||||
|
const char *signature,
|
||||||
|
size_t signature_size,
|
||||||
|
uint32_t flags)
|
||||||
|
{
|
||||||
|
char description[512];
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (!cd || !isVERITY(cd->type))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (!volume_key || !volume_key_size || (!name && signature)) {
|
||||||
|
log_err(cd, _("Incorrect root hash specified for verity device."));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_dbg(cd, "%s volume %s by signed key.", name ? "Activating" : "Checking", name ?: "");
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
int crypt_deactivate_by_name(struct crypt_device *cd, const char *name, uint32_t flags)
|
int crypt_deactivate_by_name(struct crypt_device *cd, const char *name, uint32_t flags)
|
||||||
{
|
{
|
||||||
struct crypt_device *fake_cd = NULL;
|
struct crypt_device *fake_cd = NULL;
|
||||||
@@ -5785,27 +5854,6 @@ out:
|
|||||||
* Keyring handling
|
* Keyring handling
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int kernel_keyring_support(void)
|
|
||||||
{
|
|
||||||
static unsigned _checked = 0;
|
|
||||||
|
|
||||||
if (!_checked) {
|
|
||||||
_kernel_keyring_supported = keyring_check();
|
|
||||||
_checked = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _kernel_keyring_supported;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int dmcrypt_keyring_bug(void)
|
|
||||||
{
|
|
||||||
uint64_t kversion;
|
|
||||||
|
|
||||||
if (kernel_version(&kversion))
|
|
||||||
return 1;
|
|
||||||
return kversion < version(4,15,0,0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int crypt_use_keyring_for_vk(struct crypt_device *cd)
|
int crypt_use_keyring_for_vk(struct crypt_device *cd)
|
||||||
{
|
{
|
||||||
uint32_t dmc_flags;
|
uint32_t dmc_flags;
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ static inline uint32_t act2dmflags(uint32_t act_flags)
|
|||||||
#define DM_INTEGRITY_FIX_PADDING_SUPPORTED (1 << 19) /* supports the parameter fix_padding that fixes a bug that caused excessive padding */
|
#define DM_INTEGRITY_FIX_PADDING_SUPPORTED (1 << 19) /* supports the parameter fix_padding that fixes a bug that caused excessive padding */
|
||||||
#define DM_BITLK_EBOIV_SUPPORTED (1 << 20) /* EBOIV for BitLocker supported */
|
#define DM_BITLK_EBOIV_SUPPORTED (1 << 20) /* EBOIV for BitLocker supported */
|
||||||
#define DM_BITLK_ELEPHANT_SUPPORTED (1 << 21) /* Elephant diffuser for BitLocker supported */
|
#define DM_BITLK_ELEPHANT_SUPPORTED (1 << 21) /* Elephant diffuser for BitLocker supported */
|
||||||
|
#define DM_VERITY_SIGNATURE_SUPPORTED (1 << 22) /* Verity option root_hash_sig_key_desc supported */
|
||||||
|
|
||||||
typedef enum { DM_CRYPT = 0, DM_VERITY, DM_INTEGRITY, DM_LINEAR, DM_ERROR, DM_ZERO, DM_UNKNOWN } dm_target_type;
|
typedef enum { DM_CRYPT = 0, DM_VERITY, DM_INTEGRITY, DM_LINEAR, DM_ERROR, DM_ZERO, DM_UNKNOWN } dm_target_type;
|
||||||
enum tdirection { TARGET_SET = 1, TARGET_QUERY };
|
enum tdirection { TARGET_SET = 1, TARGET_QUERY };
|
||||||
@@ -113,6 +114,7 @@ struct dm_target {
|
|||||||
|
|
||||||
const char *root_hash;
|
const char *root_hash;
|
||||||
uint32_t root_hash_size;
|
uint32_t root_hash_size;
|
||||||
|
const char *root_hash_sig_key_desc;
|
||||||
|
|
||||||
uint64_t hash_offset; /* hash offset in blocks (not header) */
|
uint64_t hash_offset; /* hash offset in blocks (not header) */
|
||||||
uint64_t hash_blocks; /* size of hash device (in hash blocks) */
|
uint64_t hash_blocks; /* size of hash device (in hash blocks) */
|
||||||
@@ -182,8 +184,8 @@ int dm_crypt_target_set(struct dm_target *tgt, uint64_t seg_offset, uint64_t seg
|
|||||||
uint32_t tag_size, uint32_t sector_size);
|
uint32_t tag_size, uint32_t sector_size);
|
||||||
int dm_verity_target_set(struct dm_target *tgt, uint64_t seg_offset, uint64_t seg_size,
|
int dm_verity_target_set(struct dm_target *tgt, uint64_t seg_offset, uint64_t seg_size,
|
||||||
struct device *data_device, struct device *hash_device, struct device *fec_device,
|
struct device *data_device, struct device *hash_device, struct device *fec_device,
|
||||||
const char *root_hash, uint32_t root_hash_size, uint64_t hash_offset_block,
|
const char *root_hash, uint32_t root_hash_size, const char *root_hash_sig_key_desc,
|
||||||
uint64_t hash_blocks, struct crypt_params_verity *vp);
|
uint64_t hash_offset_block, uint64_t hash_blocks, struct crypt_params_verity *vp);
|
||||||
int dm_integrity_target_set(struct crypt_device *cd,
|
int dm_integrity_target_set(struct crypt_device *cd,
|
||||||
struct dm_target *tgt, uint64_t seg_offset, uint64_t seg_size,
|
struct dm_target *tgt, uint64_t seg_offset, uint64_t seg_size,
|
||||||
struct device *meta_device,
|
struct device *meta_device,
|
||||||
|
|||||||
@@ -235,6 +235,7 @@ int VERITY_activate(struct crypt_device *cd,
|
|||||||
const char *name,
|
const char *name,
|
||||||
const char *root_hash,
|
const char *root_hash,
|
||||||
size_t root_hash_size,
|
size_t root_hash_size,
|
||||||
|
const char *signature_description,
|
||||||
struct device *fec_device,
|
struct device *fec_device,
|
||||||
struct crypt_params_verity *verity_hdr,
|
struct crypt_params_verity *verity_hdr,
|
||||||
uint32_t activation_flags)
|
uint32_t activation_flags)
|
||||||
@@ -252,6 +253,11 @@ int VERITY_activate(struct crypt_device *cd,
|
|||||||
name ?: "[none]", verity_hdr->hash_name);
|
name ?: "[none]", verity_hdr->hash_name);
|
||||||
|
|
||||||
if (verity_hdr->flags & CRYPT_VERITY_CHECK_HASH) {
|
if (verity_hdr->flags & CRYPT_VERITY_CHECK_HASH) {
|
||||||
|
if (signature_description) {
|
||||||
|
log_err(cd, _("Root hash signature verification is not supported."));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
log_dbg(cd, "Verification of data in userspace required.");
|
log_dbg(cd, "Verification of data in userspace required.");
|
||||||
r = VERITY_verify(cd, verity_hdr, root_hash, root_hash_size);
|
r = VERITY_verify(cd, verity_hdr, root_hash, root_hash_size);
|
||||||
|
|
||||||
@@ -291,7 +297,8 @@ int VERITY_activate(struct crypt_device *cd,
|
|||||||
|
|
||||||
r = dm_verity_target_set(&dmd.segment, 0, dmd.size, crypt_data_device(cd),
|
r = dm_verity_target_set(&dmd.segment, 0, dmd.size, crypt_data_device(cd),
|
||||||
crypt_metadata_device(cd), fec_device, root_hash,
|
crypt_metadata_device(cd), fec_device, root_hash,
|
||||||
root_hash_size, VERITY_hash_offset_block(verity_hdr),
|
root_hash_size, signature_description,
|
||||||
|
VERITY_hash_offset_block(verity_hdr),
|
||||||
VERITY_hash_blocks(cd, verity_hdr), verity_hdr);
|
VERITY_hash_blocks(cd, verity_hdr), verity_hdr);
|
||||||
|
|
||||||
if (r)
|
if (r)
|
||||||
@@ -302,6 +309,10 @@ int VERITY_activate(struct crypt_device *cd,
|
|||||||
log_err(cd, _("Kernel doesn't support dm-verity mapping."));
|
log_err(cd, _("Kernel doesn't support dm-verity mapping."));
|
||||||
r = -ENOTSUP;
|
r = -ENOTSUP;
|
||||||
}
|
}
|
||||||
|
if (r < 0 && signature_description && !(dmv_flags & DM_VERITY_SIGNATURE_SUPPORTED)) {
|
||||||
|
log_err(cd, _("Kernel doesn't support dm-verity signature option."));
|
||||||
|
r = -ENOTSUP;
|
||||||
|
}
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ int VERITY_activate(struct crypt_device *cd,
|
|||||||
const char *name,
|
const char *name,
|
||||||
const char *root_hash,
|
const char *root_hash,
|
||||||
size_t root_hash_size,
|
size_t root_hash_size,
|
||||||
|
const char *signature_description,
|
||||||
struct device *fec_device,
|
struct device *fec_device,
|
||||||
struct crypt_params_verity *verity_hdr,
|
struct crypt_params_verity *verity_hdr,
|
||||||
uint32_t activation_flags);
|
uint32_t activation_flags);
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ The <root_hash> is a hexadecimal string.
|
|||||||
|
|
||||||
\fB<options>\fR can be [\-\-hash-offset, \-\-no-superblock,
|
\fB<options>\fR can be [\-\-hash-offset, \-\-no-superblock,
|
||||||
\-\-ignore-corruption or \-\-restart-on-corruption, \-\-ignore-zero-blocks,
|
\-\-ignore-corruption or \-\-restart-on-corruption, \-\-ignore-zero-blocks,
|
||||||
\-\-check-at-most-once]
|
\-\-check-at-most-once, \-\-root-hash-signature]
|
||||||
|
|
||||||
If option \-\-no-superblock is used, you have to use as the same options
|
If option \-\-no-superblock is used, you have to use as the same options
|
||||||
as in initial format operation.
|
as in initial format operation.
|
||||||
@@ -165,6 +165,10 @@ This is the offset, in bytes, from the start of the FEC device to the beginning
|
|||||||
Number of generator roots. This equals to the number of parity bytes in the encoding data.
|
Number of generator roots. This equals to the number of parity bytes in the encoding data.
|
||||||
In RS(M, N) encoding, the number of roots is M-N. M is 255 and M-N is between 2 and 24 (including).
|
In RS(M, N) encoding, the number of roots is M-N. M is 255 and M-N is between 2 and 24 (including).
|
||||||
.TP
|
.TP
|
||||||
|
.B "\-\-root-hash-signature=FILE"
|
||||||
|
Path to roothash signature file used to verify the root hash (in kernel).
|
||||||
|
This feature requires Linux kernel version 5.4 or more recent.
|
||||||
|
.TP
|
||||||
.SH RETURN CODES
|
.SH RETURN CODES
|
||||||
Veritysetup returns 0 on success and a non-zero value on error.
|
Veritysetup returns 0 on success and a non-zero value on error.
|
||||||
|
|
||||||
|
|||||||
@@ -44,12 +44,15 @@ veritysetup_SOURCES = \
|
|||||||
lib/utils_io.c \
|
lib/utils_io.c \
|
||||||
lib/utils_blkid.c \
|
lib/utils_blkid.c \
|
||||||
src/utils_tools.c \
|
src/utils_tools.c \
|
||||||
|
src/utils_password.c \
|
||||||
src/veritysetup.c \
|
src/veritysetup.c \
|
||||||
src/cryptsetup.h
|
src/cryptsetup.h
|
||||||
|
|
||||||
veritysetup_LDADD = $(LDADD) \
|
veritysetup_LDADD = $(LDADD) \
|
||||||
libcryptsetup.la \
|
libcryptsetup.la \
|
||||||
@POPT_LIBS@ \
|
@POPT_LIBS@ \
|
||||||
|
@PWQUALITY_LIBS@ \
|
||||||
|
@PASSWDQC_LIBS@ \
|
||||||
@BLKID_LIBS@
|
@BLKID_LIBS@
|
||||||
|
|
||||||
sbin_PROGRAMS += veritysetup
|
sbin_PROGRAMS += veritysetup
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ static int opt_restart_on_corruption = 0;
|
|||||||
static int opt_ignore_corruption = 0;
|
static int opt_ignore_corruption = 0;
|
||||||
static int opt_ignore_zero_blocks = 0;
|
static int opt_ignore_zero_blocks = 0;
|
||||||
static int opt_check_at_most_once = 0;
|
static int opt_check_at_most_once = 0;
|
||||||
|
static const char *opt_root_hash_signature = NULL;
|
||||||
|
|
||||||
static const char **action_argv;
|
static const char **action_argv;
|
||||||
static int action_argc;
|
static int action_argc;
|
||||||
@@ -141,7 +142,9 @@ static int _activate(const char *dm_device,
|
|||||||
uint32_t activate_flags = CRYPT_ACTIVATE_READONLY;
|
uint32_t activate_flags = CRYPT_ACTIVATE_READONLY;
|
||||||
char *root_hash_bytes = NULL;
|
char *root_hash_bytes = NULL;
|
||||||
ssize_t hash_size;
|
ssize_t hash_size;
|
||||||
int r;
|
struct stat st;
|
||||||
|
char *signature = NULL;
|
||||||
|
int signature_size = 0, r;
|
||||||
|
|
||||||
if ((r = crypt_init_data_device(&cd, hash_device, data_device)))
|
if ((r = crypt_init_data_device(&cd, hash_device, data_device)))
|
||||||
goto out;
|
goto out;
|
||||||
@@ -177,11 +180,28 @@ static int _activate(const char *dm_device,
|
|||||||
r = -EINVAL;
|
r = -EINVAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
r = crypt_activate_by_volume_key(cd, dm_device,
|
|
||||||
|
if (opt_root_hash_signature) {
|
||||||
|
// FIXME: check max file size
|
||||||
|
if (stat(opt_root_hash_signature, &st) || !S_ISREG(st.st_mode) || !st.st_size) {
|
||||||
|
log_err(_("Invalid signature file %s."), opt_root_hash_signature);
|
||||||
|
r = -EINVAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
signature_size = st.st_size;
|
||||||
|
r = tools_read_mk(opt_root_hash_signature, &signature, signature_size);
|
||||||
|
if (r < 0) {
|
||||||
|
log_err(_("Cannot read signature file %s."), opt_root_hash_signature);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r = crypt_activate_by_signed_key(cd, dm_device,
|
||||||
root_hash_bytes,
|
root_hash_bytes,
|
||||||
hash_size,
|
hash_size,
|
||||||
|
signature, signature_size,
|
||||||
activate_flags);
|
activate_flags);
|
||||||
out:
|
out:
|
||||||
|
crypt_safe_free(signature);
|
||||||
crypt_free(cd);
|
crypt_free(cd);
|
||||||
free(root_hash_bytes);
|
free(root_hash_bytes);
|
||||||
free(CONST_CAST(char*)params.salt);
|
free(CONST_CAST(char*)params.salt);
|
||||||
@@ -453,6 +473,7 @@ int main(int argc, const char **argv)
|
|||||||
{ "hash", 'h', POPT_ARG_STRING, &hash_algorithm, 0, N_("Hash algorithm"), N_("string") },
|
{ "hash", 'h', POPT_ARG_STRING, &hash_algorithm, 0, N_("Hash algorithm"), N_("string") },
|
||||||
{ "salt", 's', POPT_ARG_STRING, &salt_string, 0, N_("Salt"), N_("hex string") },
|
{ "salt", 's', POPT_ARG_STRING, &salt_string, 0, N_("Salt"), N_("hex string") },
|
||||||
{ "uuid", '\0', POPT_ARG_STRING, &opt_uuid, 0, N_("UUID for device to use"), NULL },
|
{ "uuid", '\0', POPT_ARG_STRING, &opt_uuid, 0, N_("UUID for device to use"), NULL },
|
||||||
|
{ "root-hash-signature",'\0', POPT_ARG_STRING, &opt_root_hash_signature, 0, N_("Path to roothash signature file used to verify the root hash"), NULL },
|
||||||
{ "restart-on-corruption", 0,POPT_ARG_NONE,&opt_restart_on_corruption, 0, N_("Restart kernel if corruption is detected"), NULL },
|
{ "restart-on-corruption", 0,POPT_ARG_NONE,&opt_restart_on_corruption, 0, N_("Restart kernel if corruption is detected"), NULL },
|
||||||
{ "ignore-corruption", 0, POPT_ARG_NONE, &opt_ignore_corruption, 0, N_("Ignore corruption, log it only"), NULL },
|
{ "ignore-corruption", 0, POPT_ARG_NONE, &opt_ignore_corruption, 0, N_("Ignore corruption, log it only"), NULL },
|
||||||
{ "ignore-zero-blocks", 0, POPT_ARG_NONE, &opt_ignore_zero_blocks, 0, N_("Do not verify zeroed blocks"), NULL },
|
{ "ignore-zero-blocks", 0, POPT_ARG_NONE, &opt_ignore_zero_blocks, 0, N_("Do not verify zeroed blocks"), NULL },
|
||||||
@@ -559,6 +580,11 @@ int main(int argc, const char **argv)
|
|||||||
_("Option --ignore-corruption, --restart-on-corruption or --ignore-zero-blocks is allowed only for open operation.\n"),
|
_("Option --ignore-corruption, --restart-on-corruption or --ignore-zero-blocks is allowed only for open operation.\n"),
|
||||||
poptGetInvocationName(popt_context));
|
poptGetInvocationName(popt_context));
|
||||||
|
|
||||||
|
if (opt_root_hash_signature && strcmp(aname, "open"))
|
||||||
|
usage(popt_context, EXIT_FAILURE,
|
||||||
|
_("Option --root-hash-signature can be used only for open operation.\n"),
|
||||||
|
poptGetInvocationName(popt_context));
|
||||||
|
|
||||||
if (opt_ignore_corruption && opt_restart_on_corruption)
|
if (opt_ignore_corruption && opt_restart_on_corruption)
|
||||||
usage(popt_context, EXIT_FAILURE,
|
usage(popt_context, EXIT_FAILURE,
|
||||||
_("Option --ignore-corruption and --restart-on-corruption cannot be used together.\n"),
|
_("Option --ignore-corruption and --restart-on-corruption cannot be used together.\n"),
|
||||||
|
|||||||
Reference in New Issue
Block a user