Allow unbound keyslots to be assigned to existing digest.

If passed key matches any existing digest we will not create
new digest but assign the keyslot to already existing one.

Because reencryption should be able to create more than one
keyslot assigned to new key digest.

TODO: Tests for the new feature
This commit is contained in:
Ondrej Kozina
2018-09-13 13:51:50 +02:00
committed by Milan Broz
parent a848179286
commit 7569519530
4 changed files with 50 additions and 23 deletions

View File

@@ -957,6 +957,9 @@ int crypt_keyslot_add_by_volume_key(struct crypt_device *cd,
/** create keyslot with new volume key and assign it to current dm-crypt segment */
#define CRYPT_VOLUME_KEY_SET (1 << 1)
/** Assign key to first matching digest before creating new digest */
#define CRYPT_VOLUME_KEY_DIGEST_REUSE (1 << 2)
/**
* Add key slot using provided key.
*

View File

@@ -281,6 +281,10 @@ void json_segment_remove_flag(json_object *jobj_segment, const char *flag);
/*
* Generic LUKS2 digest
*/
int LUKS2_digest_any_matching(struct crypt_device *cd,
struct luks2_hdr *hdr,
const struct volume_key *vk);
int LUKS2_digest_by_segment(struct luks2_hdr *hdr, int segment);
int LUKS2_digest_verify_by_segment(struct crypt_device *cd,

View File

@@ -110,30 +110,38 @@ int LUKS2_digest_by_keyslot(struct luks2_hdr *hdr, int keyslot)
return -ENOENT;
}
static int _digest_verify(struct crypt_device *cd,
int digest,
const struct volume_key *vk)
{
const digest_handler *h;
int r;
h = LUKS2_digest_handler(cd, digest);
if (!h)
return -EINVAL;
r = h->verify(cd, digest, vk->key, vk->keylength);
if (r < 0)
log_dbg(cd, "Digest %d (%s) verify failed with %d.", digest, h->name, r);
return r;
}
int LUKS2_digest_verify(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct volume_key *vk,
int keyslot)
{
const digest_handler *h;
int digest, r;
digest = LUKS2_digest_by_keyslot(hdr, keyslot);
if (digest < 0)
return digest;
log_dbg(cd, "Verifying key from keyslot %d, digest %d.", keyslot, digest);
h = LUKS2_digest_handler(cd, digest);
if (!h)
return -EINVAL;
r = _digest_verify(cd, digest, vk);
r = h->verify(cd, digest, vk->key, vk->keylength);
if (r < 0) {
log_dbg(cd, "Digest %d (%s) verify failed with %d.", digest, h->name, r);
return r;
}
return digest;
return r < 0 ? r : digest;
}
int LUKS2_digest_dump(struct crypt_device *cd, int digest)
@@ -151,7 +159,6 @@ int LUKS2_digest_verify_by_segment(struct crypt_device *cd,
int segment,
const struct volume_key *vk)
{
const digest_handler *h;
int digest, r;
digest = LUKS2_digest_by_segment(hdr, segment);
@@ -160,17 +167,24 @@ int LUKS2_digest_verify_by_segment(struct crypt_device *cd,
log_dbg(cd, "Verifying key digest %d.", digest);
h = LUKS2_digest_handler(cd, digest);
if (!h)
return -EINVAL;
r = _digest_verify(cd, digest, vk);
r = h->verify(cd, digest, vk->key, vk->keylength);
if (r < 0) {
log_dbg(cd, "Digest %d (%s) verify failed with %d.", digest, h->name, r);
return r;
return r < 0 ? r : digest;
}
int LUKS2_digest_any_matching(struct crypt_device *cd,
struct luks2_hdr *hdr,
const struct volume_key *vk)
{
int digest;
for (digest = 0; digest < LUKS2_DIGEST_MAX; digest++) {
if (_digest_verify(cd, digest, vk) < 0)
continue;
return digest;
}
return digest;
return -ENOENT;
}
/* FIXME: segment can have more digests */

View File

@@ -5281,9 +5281,15 @@ int crypt_keyslot_add_by_key(struct crypt_device *cd,
if (digest >= 0)
flags &= ~CRYPT_VOLUME_KEY_SET;
/* if key matches any existing digest, do not create new digest */
if (digest < 0 && (flags & CRYPT_VOLUME_KEY_DIGEST_REUSE))
digest = LUKS2_digest_any_matching(cd, &cd->u.luks2.hdr, vk);
/* no segment flag or new vk flag requires new key digest */
if (flags & (CRYPT_VOLUME_KEY_NO_SEGMENT | CRYPT_VOLUME_KEY_SET))
digest = LUKS2_digest_create(cd, "pbkdf2", &cd->u.luks2.hdr, vk);
if (flags & (CRYPT_VOLUME_KEY_NO_SEGMENT | CRYPT_VOLUME_KEY_SET)) {
if (digest < 0 || !(flags & CRYPT_VOLUME_KEY_DIGEST_REUSE))
digest = LUKS2_digest_create(cd, "pbkdf2", &cd->u.luks2.hdr, vk);
}
r = digest;
if (r < 0) {