Add support for verity in crypt_volume_key_get and use it in status

Other APIs use the root hash in place of keys when using verity
devices, so do the same for crypt_volume_key_get to allow users
to retrieve the root hash of an active verity device.
Use it in veritysetup status to print the root hash.

[Patch slightly modified by Milan Broz]
This commit is contained in:
Luca Boccassi
2019-11-27 16:26:54 +00:00
committed by Milan Broz
parent 35c49ababf
commit 188cb114af
6 changed files with 45 additions and 16 deletions

View File

@@ -1360,6 +1360,7 @@ int crypt_deactivate(struct crypt_device *cd, const char *name);
* *
* @note For TCRYPT cipher chain is the volume key concatenated * @note For TCRYPT cipher chain is the volume key concatenated
* for all ciphers in chain. * for all ciphers in chain.
* @note For VERITY the volume key means root hash used for activation.
*/ */
int crypt_volume_key_get(struct crypt_device *cd, int crypt_volume_key_get(struct crypt_device *cd,
int keyslot, int keyslot,

View File

@@ -97,7 +97,7 @@ struct crypt_device {
} loopaes; } loopaes;
struct { /* used in CRYPT_VERITY */ struct { /* used in CRYPT_VERITY */
struct crypt_params_verity hdr; struct crypt_params_verity hdr;
char *root_hash; const char *root_hash;
unsigned int root_hash_size; unsigned int root_hash_size;
char *uuid; char *uuid;
struct device *fec_device; struct device *fec_device;
@@ -1126,7 +1126,7 @@ static void crypt_free_type(struct crypt_device *cd)
free(CONST_CAST(void*)cd->u.verity.hdr.hash_device); free(CONST_CAST(void*)cd->u.verity.hdr.hash_device);
free(CONST_CAST(void*)cd->u.verity.hdr.fec_device); free(CONST_CAST(void*)cd->u.verity.hdr.fec_device);
free(CONST_CAST(void*)cd->u.verity.hdr.salt); free(CONST_CAST(void*)cd->u.verity.hdr.salt);
free(cd->u.verity.root_hash); free(CONST_CAST(void*)cd->u.verity.root_hash);
free(cd->u.verity.uuid); free(cd->u.verity.uuid);
device_free(cd, cd->u.verity.fec_device); device_free(cd, cd->u.verity.fec_device);
} else if (isINTEGRITY(cd->type)) { } else if (isINTEGRITY(cd->type)) {
@@ -1314,6 +1314,7 @@ static int _init_by_name_verity(struct crypt_device *cd, const char *name)
r = dm_query_device(cd, name, r = dm_query_device(cd, name,
DM_ACTIVE_DEVICE | DM_ACTIVE_DEVICE |
DM_ACTIVE_VERITY_HASH_DEVICE | DM_ACTIVE_VERITY_HASH_DEVICE |
DM_ACTIVE_VERITY_ROOT_HASH |
DM_ACTIVE_VERITY_PARAMS, &dmd); DM_ACTIVE_VERITY_PARAMS, &dmd);
if (r < 0) if (r < 0)
return r; return r;
@@ -1345,6 +1346,7 @@ static int _init_by_name_verity(struct crypt_device *cd, const char *name)
cd->u.verity.hdr.fec_roots = tgt->u.verity.vp->fec_roots; cd->u.verity.hdr.fec_roots = tgt->u.verity.vp->fec_roots;
MOVE_REF(cd->u.verity.fec_device, tgt->u.verity.fec_device); MOVE_REF(cd->u.verity.fec_device, tgt->u.verity.fec_device);
MOVE_REF(cd->metadata_device, tgt->u.verity.hash_device); MOVE_REF(cd->metadata_device, tgt->u.verity.hash_device);
MOVE_REF(cd->u.verity.root_hash, tgt->u.verity.root_hash);
} }
out: out:
dm_targets_free(cd, &dmd); dm_targets_free(cd, &dmd);
@@ -4333,18 +4335,17 @@ int crypt_activate_by_volume_key(struct crypt_device *cd,
return -EINVAL; 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, r = VERITY_activate(cd, name, volume_key, volume_key_size, cd->u.verity.fec_device,
&cd->u.verity.hdr, flags|CRYPT_ACTIVATE_READONLY); &cd->u.verity.hdr, flags|CRYPT_ACTIVATE_READONLY);
if (r == -EPERM) { if (!r) {
free(cd->u.verity.root_hash);
cd->u.verity.root_hash = NULL;
} if (!r) {
cd->u.verity.root_hash_size = volume_key_size; cd->u.verity.root_hash_size = volume_key_size;
if (!cd->u.verity.root_hash) cd->u.verity.root_hash = malloc(volume_key_size);
cd->u.verity.root_hash = malloc(volume_key_size);
if (cd->u.verity.root_hash) if (cd->u.verity.root_hash)
memcpy(cd->u.verity.root_hash, volume_key, volume_key_size); 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)
@@ -4534,7 +4535,7 @@ int crypt_volume_key_get(struct crypt_device *cd,
struct volume_key *vk = NULL; struct volume_key *vk = NULL;
int key_len, r = -EINVAL; int key_len, r = -EINVAL;
if (!cd || !volume_key || !volume_key_size || (!isTCRYPT(cd->type) && !passphrase)) if (!cd || !volume_key || !volume_key_size || (!isTCRYPT(cd->type) && !isVERITY(cd->type) && !passphrase))
return -EINVAL; return -EINVAL;
if (isLUKS2(cd->type) && keyslot != CRYPT_ANY_SLOT) if (isLUKS2(cd->type) && keyslot != CRYPT_ANY_SLOT)
@@ -4564,10 +4565,18 @@ int crypt_volume_key_get(struct crypt_device *cd,
passphrase, passphrase_size, &vk); passphrase, passphrase_size, &vk);
} else if (isTCRYPT(cd->type)) { } else if (isTCRYPT(cd->type)) {
r = TCRYPT_get_volume_key(cd, &cd->u.tcrypt.hdr, &cd->u.tcrypt.params, &vk); r = TCRYPT_get_volume_key(cd, &cd->u.tcrypt.hdr, &cd->u.tcrypt.params, &vk);
} else if (isVERITY(cd->type)) {
/* volume_key == root hash */
if (cd->u.verity.root_hash) {
memcpy(volume_key, cd->u.verity.root_hash, cd->u.verity.root_hash_size);
*volume_key_size = cd->u.verity.root_hash_size;
r = 0;
} else
log_err(cd, _("Cannot retrieve root hash for verity device."));
} else } else
log_err(cd, _("This operation is not supported for %s crypt device."), cd->type ?: "(none)"); log_err(cd, _("This operation is not supported for %s crypt device."), cd->type ?: "(none)");
if (r >= 0) { if (r >= 0 && vk) {
memcpy(volume_key, vk->key, vk->keylength); memcpy(volume_key, vk->key, vk->keylength);
*volume_key_size = vk->keylength; *volume_key_size = vk->keylength;
} }

View File

@@ -57,7 +57,7 @@ int VERITY_verify(struct crypt_device *cd,
int VERITY_create(struct crypt_device *cd, int VERITY_create(struct crypt_device *cd,
struct crypt_params_verity *verity_hdr, struct crypt_params_verity *verity_hdr,
char *root_hash, const char *root_hash,
size_t root_hash_size); size_t root_hash_size);
int VERITY_FEC_process(struct crypt_device *cd, int VERITY_FEC_process(struct crypt_device *cd,

View File

@@ -418,7 +418,7 @@ int VERITY_verify(struct crypt_device *cd,
/* Create verity hash */ /* Create verity hash */
int VERITY_create(struct crypt_device *cd, int VERITY_create(struct crypt_device *cd,
struct crypt_params_verity *verity_hdr, struct crypt_params_verity *verity_hdr,
char *root_hash, const char *root_hash,
size_t root_hash_size) size_t root_hash_size)
{ {
unsigned pgsize = (unsigned)crypt_getpagesize(); unsigned pgsize = (unsigned)crypt_getpagesize();
@@ -439,7 +439,7 @@ int VERITY_create(struct crypt_device *cd,
verity_hdr->data_block_size, verity_hdr->data_block_size,
verity_hdr->data_size, verity_hdr->data_size,
VERITY_hash_offset_block(verity_hdr), VERITY_hash_offset_block(verity_hdr),
root_hash, CONST_CAST(char*)root_hash,
root_hash_size, root_hash_size,
verity_hdr->salt, verity_hdr->salt,
verity_hdr->salt_size); verity_hdr->salt_size);

View File

@@ -225,7 +225,8 @@ static int action_status(int arg)
struct crypt_params_verity vp = {}; struct crypt_params_verity vp = {};
struct crypt_device *cd = NULL; struct crypt_device *cd = NULL;
struct stat st; struct stat st;
char *backing_file; char *backing_file, *root_hash;
size_t root_hash_size;
unsigned i, path = 0; unsigned i, path = 0;
int r = 0; int r = 0;
@@ -311,6 +312,19 @@ static int action_status(int arg)
vp.fec_area_offset * vp.hash_block_size / 512); vp.fec_area_offset * vp.hash_block_size / 512);
log_std(" FEC roots: %u\n", vp.fec_roots); log_std(" FEC roots: %u\n", vp.fec_roots);
} }
root_hash_size = crypt_get_volume_key_size(cd);
if (root_hash_size > 0 && (root_hash = malloc(root_hash_size))) {
r = crypt_volume_key_get(cd, CRYPT_ANY_SLOT, root_hash, &root_hash_size, NULL, 0);
if (!r) {
log_std(" root hash: ");
for (i = 0; i < root_hash_size; i++)
log_std("%02hhx", (const char)root_hash[i]);
log_std("\n");
}
free(root_hash);
}
if (cad.flags & (CRYPT_ACTIVATE_IGNORE_CORRUPTION| if (cad.flags & (CRYPT_ACTIVATE_IGNORE_CORRUPTION|
CRYPT_ACTIVATE_RESTART_ON_CORRUPTION| CRYPT_ACTIVATE_RESTART_ON_CORRUPTION|
CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS| CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS|

View File

@@ -1570,7 +1570,8 @@ static void VerityTest(void)
{ {
const char *salt_hex = "20c28ffc129c12360ba6ceea2b6cf04e89c2b41cfe6b8439eb53c1897f50df7b"; const char *salt_hex = "20c28ffc129c12360ba6ceea2b6cf04e89c2b41cfe6b8439eb53c1897f50df7b";
const char *root_hex = "ab018b003a967fc782effb293b6dccb60b4f40c06bf80d16391acf686d28b5d6"; const char *root_hex = "ab018b003a967fc782effb293b6dccb60b4f40c06bf80d16391acf686d28b5d6";
char salt[256], root_hash[256]; char salt[256], root_hash[256], root_hash_out[256];
size_t root_hash_out_size = 256;
struct crypt_active_device cad; struct crypt_active_device cad;
struct crypt_params_verity params = { struct crypt_params_verity params = {
.data_device = DEVICE_EMPTY, .data_device = DEVICE_EMPTY,
@@ -1657,6 +1658,10 @@ static void VerityTest(void)
CRYPT_FREE(cd); CRYPT_FREE(cd);
OK_(crypt_init_by_name(&cd, CDEVICE_1)); OK_(crypt_init_by_name(&cd, CDEVICE_1));
memset(root_hash_out, 0, root_hash_out_size);
OK_(crypt_volume_key_get(cd, CRYPT_ANY_SLOT, root_hash_out, &root_hash_out_size, NULL, 0));
EQ_(32, root_hash_out_size);
OK_(memcmp(root_hash, root_hash_out, root_hash_out_size));
OK_(crypt_deactivate(cd, CDEVICE_1)); OK_(crypt_deactivate(cd, CDEVICE_1));
/* hash fail */ /* hash fail */