Harden and limit access to volume key internals.

The volume key structure may often be in configuration
where 'key' member does not contain real data. Some
examples:

- volume key acquired by querring device-mapper where key
  was originaly passed by kernel keyring reference.

- volume key allocated by crypt_alloc_volume_key(size, NULL)

With this patch access to internal 'uninitialized' data result
in failed assert().

For use cases where key data are not needed (keyring reference wrapper,
key length info only) we do not have to allocate and lock the safe
buffer in memory.

Further improvements might to completely hide the volume key internals
and access only via setter and getter functions.
This commit is contained in:
Ondrej Kozina
2025-02-03 16:59:19 +01:00
committed by Milan Broz
parent f86ab28ad6
commit 6ee76934fa
12 changed files with 288 additions and 127 deletions

View File

@@ -513,6 +513,7 @@ static int _read_volume_header(
int r = 0;
struct device *dev = crypt_metadata_device(cd);
struct volume_header *vol_header = NULL;
void *enc_key = NULL;
assert(sizeof(*vol_header) == FVAULT2_VOL_HEADER_SIZE);
@@ -557,8 +558,8 @@ static int _read_volume_header(
goto out;
}
*enc_md_key = crypt_alloc_volume_key(FVAULT2_XTS_KEY_SIZE, NULL);
if (*enc_md_key == NULL) {
enc_key = crypt_safe_alloc(FVAULT2_XTS_KEY_SIZE);
if (!enc_key) {
r = -ENOMEM;
goto out;
}
@@ -566,9 +567,15 @@ static int _read_volume_header(
*block_size = le32_to_cpu(vol_header->block_size);
*disklbl_blkoff = le64_to_cpu(vol_header->disklbl_blkoff);
uuid_unparse(vol_header->ph_vol_uuid, ph_vol_uuid);
crypt_safe_memcpy((*enc_md_key)->key, vol_header->key_data, FVAULT2_AES_KEY_SIZE);
crypt_safe_memcpy((*enc_md_key)->key + FVAULT2_AES_KEY_SIZE,
crypt_safe_memcpy(enc_key, vol_header->key_data, FVAULT2_AES_KEY_SIZE);
crypt_safe_memcpy((char *)enc_key + FVAULT2_AES_KEY_SIZE,
vol_header->ph_vol_uuid, FVAULT2_AES_KEY_SIZE);
*enc_md_key = crypt_alloc_volume_key_by_safe_alloc(&enc_key);
if (*enc_md_key == NULL) {
crypt_safe_free(enc_key);
r = -ENOMEM;
}
out:
free(vol_header);
return r;
@@ -892,14 +899,14 @@ int FVAULT2_get_volume_key(
const char *passphrase,
size_t passphrase_len,
const struct fvault2_params *params,
struct volume_key **vol_key)
struct volume_key **r_vol_key)
{
int r = 0;
uint8_t family_uuid_bin[FVAULT2_UUID_BIN_SIZE];
struct crypt_hash *hash = NULL;
void *passphrase_key = NULL, *kek = NULL;
void *passphrase_key = NULL, *kek = NULL, *vol_key= NULL;
*vol_key = NULL;
*r_vol_key = NULL;
if (uuid_parse(params->family_uuid, family_uuid_bin) < 0) {
log_dbg(cd, "Could not parse logical volume family UUID: %s.",
@@ -931,38 +938,39 @@ int FVAULT2_get_volume_key(
if (r < 0)
goto out;
*vol_key = crypt_alloc_volume_key(FVAULT2_XTS_KEY_SIZE, NULL);
if (*vol_key == NULL) {
vol_key = crypt_safe_alloc(FVAULT2_XTS_KEY_SIZE);
if (vol_key == NULL) {
r = -ENOMEM;
goto out;
}
r = _unwrap_key(kek, FVAULT2_AES_KEY_SIZE, params->wrapped_vk,
FVAULT2_WRAPPED_KEY_SIZE, (*vol_key)->key, FVAULT2_AES_KEY_SIZE);
FVAULT2_WRAPPED_KEY_SIZE, vol_key, FVAULT2_AES_KEY_SIZE);
if (r < 0)
goto out;
r = crypt_hash_init(&hash, "sha256");
if (r < 0)
goto out;
r = crypt_hash_write(hash, (*vol_key)->key, FVAULT2_AES_KEY_SIZE);
r = crypt_hash_write(hash, vol_key, FVAULT2_AES_KEY_SIZE);
if (r < 0)
goto out;
r = crypt_hash_write(hash, (char *)family_uuid_bin,
FVAULT2_UUID_BIN_SIZE);
if (r < 0)
goto out;
r = crypt_hash_final(hash, (*vol_key)->key + FVAULT2_AES_KEY_SIZE,
r = crypt_hash_final(hash, (char *)vol_key + FVAULT2_AES_KEY_SIZE,
FVAULT2_AES_KEY_SIZE);
if (r < 0)
goto out;
*r_vol_key = crypt_alloc_volume_key_by_safe_alloc(&vol_key);
if (!*r_vol_key)
r = -ENOMEM;
out:
crypt_safe_free(passphrase_key);
crypt_safe_free(kek);
if (r < 0) {
crypt_free_volume_key(*vol_key);
*vol_key = NULL;
}
crypt_safe_free(vol_key);
if (hash != NULL)
crypt_hash_destroy(hash);
return r;

View File

@@ -41,7 +41,7 @@ int FVAULT2_get_volume_key(
const char *passphrase,
size_t passphrase_len,
const struct fvault2_params *params,
struct volume_key **vol_key);
struct volume_key **r_vol_key);
int FVAULT2_dump(
struct crypt_device *cd,

View File

@@ -56,7 +56,7 @@ struct volume_key {
key_type_t keyring_key_type; /* kernel keyring key type */
bool uploaded; /* uploaded to keyring, can drop it */
struct volume_key *next;
char key[];
char *key;
};
typedef enum {
@@ -66,6 +66,7 @@ typedef enum {
} key_quality_info;
struct volume_key *crypt_alloc_volume_key(size_t keylength, const char *key);
struct volume_key *crypt_alloc_volume_key_by_safe_alloc(void **safe_alloc);
struct volume_key *crypt_generate_volume_key(struct crypt_device *cd, size_t keylength,
key_quality_info quality);
void crypt_free_volume_key(struct volume_key *vk);
@@ -81,6 +82,7 @@ int crypt_volume_key_get_id(const struct volume_key *vk);
void crypt_volume_key_add_next(struct volume_key **vks, struct volume_key *vk);
struct volume_key *crypt_volume_key_next(struct volume_key *vk);
struct volume_key *crypt_volume_key_by_id(struct volume_key *vk, int id);
void crypt_volume_key_pass_safe_alloc(struct volume_key *vk, void **safe_alloc);
struct crypt_pbkdf_type *crypt_get_pbkdf(struct crypt_device *cd);
int init_pbkdf_type(struct crypt_device *cd,

View File

@@ -596,7 +596,7 @@ static char *get_dm_crypt_params(const struct dm_target *tgt, uint32_t flags)
if (crypt_is_cipher_null(cipher_dm))
null_cipher = 1;
if (null_cipher)
if (null_cipher || crypt_volume_key_length(tgt->u.crypt.vk) == 0)
hexkey = crypt_bytes_to_hex(0, NULL);
else if (flags & CRYPT_ACTIVATE_KEYRING_KEY) {
if (!crypt_volume_key_description(tgt->u.crypt.vk) ||
@@ -2004,6 +2004,7 @@ static int _dm_target_query_crypt(struct crypt_device *cd, uint32_t get_flags,
struct device *data_device = NULL;
char *cipher = NULL, *integrity = NULL;
struct volume_key *vk = NULL;
void *key = NULL;
tgt->type = DM_CRYPT;
tgt->direction = TARGET_QUERY;
@@ -2138,15 +2139,21 @@ static int _dm_target_query_crypt(struct crypt_device *cd, uint32_t get_flags,
if (r < 0)
goto err;
} else if (key_size) {
key = crypt_safe_alloc(key_size);
if (!key) {
r = -ENOMEM;
goto err;
}
buffer[2] = '\0';
for(i = 0; i < crypt_volume_key_length(vk); i++) {
crypt_safe_memcpy(buffer, &key_[i * 2], 2);
vk->key[i] = strtoul(buffer, &endp, 16);
*((char *)key + i) = strtoul(buffer, &endp, 16);
if (endp != &buffer[2]) {
r = -EINVAL;
goto err;
}
}
crypt_volume_key_pass_safe_alloc(vk, &key);
}
}
}
@@ -2165,6 +2172,7 @@ err:
free(cipher);
free(integrity);
device_free(cd, data_device);
crypt_safe_free(key);
crypt_free_volume_key(vk);
return r;
}
@@ -3097,9 +3105,12 @@ int dm_resume_and_reinstate_key(struct crypt_device *cd, const char *name,
if (crypt_volume_key_description(vk)) {
r = snprintf(msg, msg_size, "key set :%zu:logon:%s", crypt_volume_key_length(vk),
crypt_volume_key_description(vk));
} else {
key = crypt_bytes_to_hex(crypt_volume_key_length(vk),
crypt_volume_key_get_key(vk));
} else {
if (!crypt_volume_key_length(vk))
key = crypt_bytes_to_hex(0, NULL);
else
key = crypt_bytes_to_hex(crypt_volume_key_length(vk),
crypt_volume_key_get_key(vk));
if (!key) {
r = -ENOMEM;
goto out;

View File

@@ -69,6 +69,7 @@ static int hash_keys(struct crypt_device *cd,
char tweak, *key_ptr;
unsigned int i;
int r = 0;
void *key = NULL;
hash_name = hash_override ?: get_hash(key_len_output);
tweak = get_tweak(keys_count);
@@ -79,24 +80,30 @@ static int hash_keys(struct crypt_device *cd,
return -EINVAL;
}
*vk = crypt_alloc_volume_key((size_t)key_len_output * keys_count, NULL);
if (!*vk)
key = crypt_safe_alloc((size_t)key_len_output * keys_count);
if (!key)
return -ENOMEM;
for (i = 0; i < keys_count; i++) {
key_ptr = &(*vk)->key[i * key_len_output];
key_ptr = &((char *)key)[i * key_len_output];
r = hash_key(input_keys[i], key_len_input, key_ptr,
key_len_output, hash_name);
if (r < 0)
break;
goto err;
key_ptr[0] ^= tweak;
}
if (r < 0 && *vk) {
crypt_free_volume_key(*vk);
*vk = NULL;
*vk = crypt_alloc_volume_key_by_safe_alloc(&key);
if (!*vk) {
r = -ENOMEM;
goto err;
}
return 0;
err:
crypt_safe_free(key);
*vk = NULL;
return r;
}

View File

@@ -866,8 +866,9 @@ int LUKS_set_key(unsigned int keyIndex,
struct luks_phdr *hdr, struct volume_key *vk,
struct crypt_device *ctx)
{
struct volume_key *derived_key;
struct volume_key *derived_vk = NULL;
char *AfKey = NULL;
void *derived_key = NULL;
size_t AFEKSize;
struct crypt_pbkdf_type *pbkdf;
int r;
@@ -899,9 +900,11 @@ int LUKS_set_key(unsigned int keyIndex,
log_dbg(ctx, "Key slot %d use %" PRIu32 " password iterations.", keyIndex,
hdr->keyblock[keyIndex].passwordIterations);
derived_key = crypt_alloc_volume_key(hdr->keyBytes, NULL);
if (!derived_key)
return -ENOMEM;
derived_key = crypt_safe_alloc(hdr->keyBytes);
if (!derived_key) {
r = -ENOMEM;
goto out;
}
r = crypt_random_get(ctx, hdr->keyblock[keyIndex].passwordSalt,
LUKS_SALTSIZE, CRYPT_RND_SALT);
@@ -910,7 +913,7 @@ int LUKS_set_key(unsigned int keyIndex,
r = crypt_pbkdf(CRYPT_KDF_PBKDF2, hdr->hashSpec, password, passwordLen,
hdr->keyblock[keyIndex].passwordSalt, LUKS_SALTSIZE,
derived_key->key, hdr->keyBytes,
derived_key, hdr->keyBytes,
hdr->keyblock[keyIndex].passwordIterations, 0, 0);
if (r < 0) {
if ((crypt_backend_flags() & CRYPT_BACKEND_PBKDF2_INT) &&
@@ -919,6 +922,12 @@ int LUKS_set_key(unsigned int keyIndex,
goto out;
}
derived_vk = crypt_alloc_volume_key_by_safe_alloc(&derived_key);
if (!derived_vk) {
r = -ENOMEM;
goto out;
}
/*
* AF splitting, the volume key stored in vk->key is split to AfKey
*/
@@ -943,7 +952,7 @@ int LUKS_set_key(unsigned int keyIndex,
r = LUKS_encrypt_to_storage(AfKey,
AFEKSize,
hdr->cipherName, hdr->cipherMode,
derived_key,
derived_vk,
hdr->keyblock[keyIndex].keyMaterialOffset,
ctx);
if (r < 0)
@@ -961,7 +970,8 @@ int LUKS_set_key(unsigned int keyIndex,
r = 0;
out:
crypt_safe_free(AfKey);
crypt_free_volume_key(derived_key);
crypt_safe_free(derived_key);
crypt_free_volume_key(derived_vk);
return r;
}
@@ -989,12 +999,13 @@ static int LUKS_open_key(unsigned int keyIndex,
const char *password,
size_t passwordLen,
struct luks_phdr *hdr,
struct volume_key **vk,
struct volume_key **r_vk,
struct crypt_device *ctx)
{
crypt_keyslot_info ki = LUKS_keyslot_info(hdr, keyIndex);
struct volume_key *derived_key;
struct volume_key *derived_vk = NULL, *vk = NULL;
char *AfKey = NULL;
void *key = NULL, *derived_key = NULL;
size_t AFEKSize;
int r;
@@ -1004,12 +1015,12 @@ static int LUKS_open_key(unsigned int keyIndex,
if (ki < CRYPT_SLOT_ACTIVE)
return -ENOENT;
derived_key = crypt_alloc_volume_key(hdr->keyBytes, NULL);
derived_key = crypt_safe_alloc(hdr->keyBytes);
if (!derived_key)
return -ENOMEM;
*vk = crypt_alloc_volume_key(hdr->keyBytes, NULL);
if (!*vk) {
key = crypt_safe_alloc(hdr->keyBytes);
if (!key) {
r = -ENOMEM;
goto out;
}
@@ -1023,39 +1034,57 @@ static int LUKS_open_key(unsigned int keyIndex,
r = crypt_pbkdf(CRYPT_KDF_PBKDF2, hdr->hashSpec, password, passwordLen,
hdr->keyblock[keyIndex].passwordSalt, LUKS_SALTSIZE,
derived_key->key, hdr->keyBytes,
derived_key, hdr->keyBytes,
hdr->keyblock[keyIndex].passwordIterations, 0, 0);
if (r < 0) {
log_err(ctx, _("Cannot open keyslot (using hash %s)."), hdr->hashSpec);
goto out;
}
derived_vk = crypt_alloc_volume_key_by_safe_alloc(&derived_key);
if (!derived_vk) {
r = -ENOMEM;
goto out;
}
log_dbg(ctx, "Reading key slot %d area.", keyIndex);
r = LUKS_decrypt_from_storage(AfKey,
AFEKSize,
hdr->cipherName, hdr->cipherMode,
derived_key,
derived_vk,
hdr->keyblock[keyIndex].keyMaterialOffset,
ctx);
if (r < 0)
goto out;
r = AF_merge(AfKey, (*vk)->key, (*vk)->keylength, hdr->keyblock[keyIndex].stripes, hdr->hashSpec);
r = AF_merge(AfKey, key, hdr->keyBytes, hdr->keyblock[keyIndex].stripes, hdr->hashSpec);
if (r < 0)
goto out;
r = LUKS_verify_volume_key(hdr, *vk);
vk = crypt_alloc_volume_key_by_safe_alloc(&key);
if (!vk) {
r = -ENOMEM;
goto out;
}
r = LUKS_verify_volume_key(hdr, vk);
if (r < 0)
goto out;
/* Allow only empty passphrase with null cipher */
if (!r && crypt_is_cipher_null(hdr->cipherName) && passwordLen)
if (crypt_is_cipher_null(hdr->cipherName) && passwordLen)
r = -EPERM;
else
*r_vk = vk;
out:
if (r < 0) {
crypt_free_volume_key(*vk);
*vk = NULL;
crypt_free_volume_key(vk);
*r_vk = NULL;
}
crypt_safe_free(AfKey);
crypt_free_volume_key(derived_key);
crypt_safe_free(key);
crypt_safe_free(derived_key);
crypt_free_volume_key(derived_vk);
return r;
}

View File

@@ -339,31 +339,43 @@ static int _open_and_verify(struct crypt_device *cd,
int keyslot,
const char *password,
size_t password_len,
struct volume_key **vk)
struct volume_key **r_vk)
{
int r, key_size = LUKS2_get_keyslot_stored_key_size(hdr, keyslot);
struct volume_key *vk = NULL;
void *key = NULL;
if (key_size < 0)
return -EINVAL;
*vk = crypt_alloc_volume_key(key_size, NULL);
if (!*vk)
key = crypt_safe_alloc(key_size);
if (!key)
return -ENOMEM;
r = h->open(cd, keyslot, password, password_len, (*vk)->key, (*vk)->keylength);
if (r < 0)
log_dbg(cd, "Keyslot %d (%s) open failed with %d.", keyslot, h->name, r);
else
r = LUKS2_digest_verify(cd, hdr, *vk, keyslot);
r = h->open(cd, keyslot, password, password_len, key, key_size);
if (r < 0) {
crypt_free_volume_key(*vk);
*vk = NULL;
log_dbg(cd, "Keyslot %d (%s) open failed with %d.", keyslot, h->name, r);
goto err;
}
crypt_volume_key_set_id(*vk, r);
vk = crypt_alloc_volume_key_by_safe_alloc(&key);
if (!vk) {
r = -ENOMEM;
goto err;
}
return r < 0 ? r : keyslot;
r = LUKS2_digest_verify(cd, hdr, vk, keyslot);
if (r < 0)
goto err;
crypt_volume_key_set_id(vk, r);
*r_vk = vk;
return keyslot;
err:
crypt_safe_free(key);
crypt_free_volume_key(vk);
return r;
}
static int LUKS2_open_and_verify(struct crypt_device *cd,

View File

@@ -193,7 +193,6 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
const char *password, size_t passwordLen,
const char *volume_key, size_t volume_key_len)
{
struct volume_key *derived_key;
char *salt = NULL, cipher[MAX_CIPHER_LEN], cipher_mode[MAX_CIPHER_LEN];
char *AfKey = NULL;
const char *af_hash = NULL;
@@ -202,6 +201,8 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
uint64_t area_offset;
struct crypt_pbkdf_type pbkdf;
int r;
struct volume_key *derived_vk = NULL;
void *derived_key = NULL;
if (!json_object_object_get_ex(jobj_keyslot, "kdf", &jobj_kdf) ||
!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af) ||
@@ -239,7 +240,7 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
/*
* Allocate derived key storage.
*/
derived_key = crypt_alloc_volume_key(keyslot_key_len, NULL);
derived_key = crypt_safe_alloc(keyslot_key_len);
if (!derived_key) {
free(salt);
return -ENOMEM;
@@ -250,7 +251,7 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
log_dbg(cd, "Running keyslot key derivation.");
r = crypt_pbkdf(pbkdf.type, pbkdf.hash, password, passwordLen,
salt, LUKS_SALTSIZE,
derived_key->key, derived_key->keylength,
derived_key, keyslot_key_len,
pbkdf.iterations, pbkdf.max_memory_kb,
pbkdf.parallel_threads);
free(salt);
@@ -260,16 +261,15 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
log_err(cd, _("PBKDF2 iteration value overflow."));
if (r == -ENOMEM)
log_err(cd, _("Not enough memory for keyslot key derivation."));
crypt_free_volume_key(derived_key);
return r;
goto out;
}
// FIXME: verity key_size to AFEKSize
AFEKSize = AF_split_sectors(volume_key_len, LUKS_STRIPES) * SECTOR_SIZE;
AfKey = crypt_safe_alloc(AFEKSize);
if (!AfKey) {
crypt_free_volume_key(derived_key);
return -ENOMEM;
r = -ENOMEM;
goto out;
}
r = crypt_hash_size(af_hash);
@@ -278,15 +278,23 @@ static int luks2_keyslot_set_key(struct crypt_device *cd,
else
r = AF_split(cd, volume_key, AfKey, volume_key_len, LUKS_STRIPES, af_hash);
if (r == 0) {
log_dbg(cd, "Updating keyslot area [0x%04" PRIx64 "].", area_offset);
/* FIXME: sector_offset should be size_t, fix LUKS_encrypt... accordingly */
r = luks2_encrypt_to_storage(AfKey, AFEKSize, cipher, cipher_mode,
derived_key, (unsigned)(area_offset / SECTOR_SIZE), cd);
if (r < 0)
goto out;
derived_vk = crypt_alloc_volume_key_by_safe_alloc(&derived_key);
if (!derived_vk) {
r = -ENOMEM;
goto out;
}
log_dbg(cd, "Updating keyslot area [0x%04" PRIx64 "].", area_offset);
/* FIXME: sector_offset should be size_t, fix LUKS_encrypt... accordingly */
r = luks2_encrypt_to_storage(AfKey, AFEKSize, cipher, cipher_mode,
derived_vk, (unsigned)(area_offset / SECTOR_SIZE), cd);
out:
crypt_safe_free(AfKey);
crypt_free_volume_key(derived_key);
crypt_safe_free(derived_key);
crypt_free_volume_key(derived_vk);
if (r < 0)
return r;
@@ -298,7 +306,6 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
const char *password, size_t passwordLen,
char *volume_key, size_t volume_key_len)
{
struct volume_key *derived_key = NULL;
struct crypt_pbkdf_type pbkdf, *cd_pbkdf;
char *AfKey = NULL;
size_t AFEKSize;
@@ -309,6 +316,8 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
size_t keyslot_key_len;
bool try_serialize_lock = false;
int r;
struct volume_key *derived_vk = NULL;
void *derived_key = NULL;
if (!json_object_object_get_ex(jobj_keyslot, "af", &jobj_af) ||
!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
@@ -339,7 +348,7 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
/*
* Allocate derived key storage space.
*/
derived_key = crypt_alloc_volume_key(keyslot_key_len, NULL);
derived_key = crypt_safe_alloc(keyslot_key_len);
if (!derived_key) {
r = -ENOMEM;
goto out;
@@ -376,20 +385,27 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
log_dbg(cd, "Running keyslot key derivation.");
r = crypt_pbkdf(pbkdf.type, pbkdf.hash, password, passwordLen,
salt, LUKS_SALTSIZE,
derived_key->key, derived_key->keylength,
derived_key, keyslot_key_len,
pbkdf.iterations, pbkdf.max_memory_kb,
pbkdf.parallel_threads);
if (try_serialize_lock)
crypt_serialize_unlock(cd);
if (r == 0) {
log_dbg(cd, "Reading keyslot area [0x%04" PRIx64 "].", area_offset);
/* FIXME: sector_offset should be size_t, fix LUKS_decrypt... accordingly */
r = luks2_decrypt_from_storage(AfKey, AFEKSize, cipher, cipher_mode,
derived_key, (unsigned)(area_offset / SECTOR_SIZE), cd);
if (r < 0)
goto out;
derived_vk = crypt_alloc_volume_key_by_safe_alloc(&derived_key);
if (!derived_vk) {
r = -ENOMEM;
goto out;
}
log_dbg(cd, "Reading keyslot area [0x%04" PRIx64 "].", area_offset);
/* FIXME: sector_offset should be size_t, fix LUKS_decrypt... accordingly */
r = luks2_decrypt_from_storage(AfKey, AFEKSize, cipher, cipher_mode,
derived_vk, (unsigned)(area_offset / SECTOR_SIZE), cd);
if (r == 0) {
r = crypt_hash_size(af_hash);
if (r < 0)
@@ -399,8 +415,9 @@ static int luks2_keyslot_get_key(struct crypt_device *cd,
}
out:
free(salt);
crypt_free_volume_key(derived_key);
crypt_free_volume_key(derived_vk);
crypt_safe_free(AfKey);
crypt_safe_free(derived_key);
return r;
}

View File

@@ -252,12 +252,13 @@ static int reencrypt_assembly_verification_data(struct crypt_device *cd,
struct luks2_hdr *hdr,
struct volume_key *vks,
uint8_t version,
struct volume_key **verification_data)
struct volume_key **r_verification_data)
{
uint8_t *ptr;
int digest_new, digest_old;
struct volume_key *data = NULL, *vk_old = NULL, *vk_new = NULL;
int digest_new, digest_old, r = -EINVAL;
struct volume_key *verification_data = NULL, *vk_old = NULL, *vk_new = NULL;
size_t keyslot_data_len, segments_data_len, data_len = 2;
void *data = NULL;
/*
* This works up to (including) version v207.
@@ -299,11 +300,11 @@ static int reencrypt_assembly_verification_data(struct crypt_device *cd,
data_len += segments_data_len;
/* Alloc and fill serialization data */
data = crypt_alloc_volume_key(data_len, NULL);
data = crypt_safe_alloc(data_len);
if (!data)
return -ENOMEM;
ptr = (uint8_t*)data->key;
ptr = (uint8_t*)data;
*ptr++ = 0x76;
*ptr++ = 0x30 + version;
@@ -324,14 +325,20 @@ static int reencrypt_assembly_verification_data(struct crypt_device *cd,
goto bad;
ptr += segments_data_len;
assert((size_t)(ptr - (uint8_t*)data->key) == data_len);
assert((size_t)(ptr - (uint8_t*)data) == data_len);
*verification_data = data;
verification_data = crypt_alloc_volume_key_by_safe_alloc(&data);
if (!verification_data) {
r = -ENOMEM;
goto bad;
}
*r_verification_data = verification_data;
return 0;
bad:
crypt_free_volume_key(data);
return -EINVAL;
crypt_safe_free(data);
crypt_free_volume_key(verification_data);
return r;
}
int LUKS2_keyslot_reencrypt_digest_create(struct crypt_device *cd,

View File

@@ -289,16 +289,17 @@ static int process_key(struct crypt_device *cd, const char *hash_name,
struct volume_key **vk)
{
int r;
void *key = NULL;
if (!key_size)
return -EINVAL;
*vk = crypt_alloc_volume_key(key_size, NULL);
if (!*vk)
return -ENOMEM;
if (hash_name) {
r = crypt_plain_hash(cd, hash_name, (*vk)->key, key_size, pass, passLen);
key = crypt_safe_alloc(key_size);
if (!key)
return -ENOMEM;
r = crypt_plain_hash(cd, hash_name, key, key_size, pass, passLen);
if (r < 0) {
if (r == -ENOENT)
log_err(cd, _("Hash algorithm %s not supported."),
@@ -306,17 +307,27 @@ static int process_key(struct crypt_device *cd, const char *hash_name,
else
log_err(cd, _("Key processing error (using hash %s)."),
hash_name);
crypt_free_volume_key(*vk);
*vk = NULL;
crypt_safe_free(key);
return -EINVAL;
}
} else if (passLen > key_size) {
crypt_safe_memcpy((*vk)->key, pass, key_size);
*vk = crypt_alloc_volume_key_by_safe_alloc(&key);
} else if (passLen >= key_size) {
*vk = crypt_alloc_volume_key(key_size, pass);
} else {
crypt_safe_memcpy((*vk)->key, pass, passLen);
key = crypt_safe_alloc(key_size);
if (!key)
return -ENOMEM;
crypt_safe_memcpy(key, pass, passLen);
*vk = crypt_alloc_volume_key_by_safe_alloc(&key);
}
return 0;
r = *vk ? 0 : -ENOMEM;
crypt_safe_free(key);
return r;
}
static int isPLAIN(const char *type)

View File

@@ -737,6 +737,7 @@ int TCRYPT_activate(struct crypt_device *cd,
enum devcheck device_check;
uint64_t offset, iv_offset;
struct volume_key *vk = NULL;
void *key = NULL;
struct device *ptr_dev = crypt_data_device(cd), *device = NULL, *part_device = NULL;
struct crypt_dm_active_device dmd = {
.flags = flags
@@ -865,8 +866,16 @@ int TCRYPT_activate(struct crypt_device *cd,
dmd.flags = flags | CRYPT_ACTIVATE_PRIVATE;
}
key = crypt_safe_alloc(crypt_volume_key_length(vk));
if (!key) {
r = -ENOMEM;
break;
}
TCRYPT_copy_key(&algs->cipher[i-1], algs->mode,
vk->key, hdr->d.keys);
key, hdr->d.keys);
crypt_volume_key_pass_safe_alloc(vk, &key);
if (algs->chain_count != i) {
if (snprintf(dm_dev_name, sizeof(dm_dev_name), "%s/%s_%d", dm_get_dir(), name, i) < 0) {
@@ -910,6 +919,7 @@ int TCRYPT_activate(struct crypt_device *cd,
}
out:
crypt_safe_free(key);
crypt_free_volume_key(vk);
device_free(cd, device);
device_free(cd, part_device);
@@ -1107,6 +1117,7 @@ int TCRYPT_get_volume_key(struct crypt_device *cd,
{
const struct tcrypt_algs *algs;
unsigned int i, key_index;
void *key = NULL;
if (!hdr->d.version) {
log_err(cd, _("This function is not supported without TCRYPT header load."));
@@ -1117,16 +1128,22 @@ int TCRYPT_get_volume_key(struct crypt_device *cd,
if (!algs)
return -EINVAL;
*vk = crypt_alloc_volume_key(params->key_size, NULL);
if (!*vk)
key = crypt_safe_alloc(params->key_size);
if (!key)
return -ENOMEM;
for (i = 0, key_index = 0; i < algs->chain_count; i++) {
TCRYPT_copy_key(&algs->cipher[i], algs->mode,
&(*vk)->key[key_index], hdr->d.keys);
&((char *)key)[key_index], hdr->d.keys);
key_index += algs->cipher[i].key_size;
}
*vk = crypt_alloc_volume_key_by_safe_alloc(&key);
if (!*vk) {
crypt_safe_free(key);
return -ENOMEM;
}
return 0;
}

View File

@@ -20,7 +20,7 @@ struct volume_key *crypt_alloc_volume_key(size_t keylength, const char *key)
if (keylength > (SIZE_MAX - sizeof(*vk)))
return NULL;
vk = crypt_safe_alloc(sizeof(*vk) + keylength);
vk = crypt_zalloc(sizeof(*vk));
if (!vk)
return NULL;
@@ -29,21 +29,57 @@ struct volume_key *crypt_alloc_volume_key(size_t keylength, const char *key)
vk->id = KEY_NOT_VERIFIED;
/* keylength 0 is valid => no key */
if (vk->keylength) {
if (key)
crypt_safe_memcpy(&vk->key, key, keylength);
else
crypt_safe_memzero(&vk->key, keylength);
if (vk->keylength && key) {
vk->key = crypt_safe_alloc(keylength);
if (!vk->key) {
free(vk);
return NULL;
}
crypt_safe_memcpy(vk->key, key, keylength);
}
return vk;
}
const char *crypt_volume_key_get_key(const struct volume_key *vk)
struct volume_key *crypt_alloc_volume_key_by_safe_alloc(void **safe_alloc)
{
size_t keylength;
struct volume_key *vk;
if (!safe_alloc)
return NULL;
keylength = crypt_safe_alloc_size(*safe_alloc);
if (!keylength)
return NULL;
vk = crypt_alloc_volume_key(keylength, NULL);
if (!vk)
return NULL;
vk->key = *safe_alloc;
*safe_alloc = NULL;
return vk;
}
void crypt_volume_key_pass_safe_alloc(struct volume_key *vk, void **safe_alloc)
{
assert(vk);
assert(vk->keylength);
assert(safe_alloc);
assert(crypt_safe_alloc_size(*safe_alloc) == vk->keylength);
return (const char *)vk->key;
crypt_safe_free(vk->key);
vk->key = *safe_alloc;
*safe_alloc = NULL;
}
const char *crypt_volume_key_get_key(const struct volume_key *vk)
{
assert(vk && vk->key);
return vk->key;
}
size_t crypt_volume_key_length(const struct volume_key *vk)
@@ -149,8 +185,9 @@ void crypt_free_volume_key(struct volume_key *vk)
while (vk) {
free(CONST_CAST(void*)vk->key_description);
crypt_safe_free(vk->key);
vk_next = vk->next;
crypt_safe_free(vk);
free(vk);
vk = vk_next;
}
}
@@ -159,18 +196,19 @@ struct volume_key *crypt_generate_volume_key(struct crypt_device *cd, size_t key
key_quality_info quality)
{
int r;
struct volume_key *vk;
void *key;
struct volume_key *vk = NULL;
vk = crypt_alloc_volume_key(keylength, NULL);
if (!vk)
key = crypt_safe_alloc(keylength);
if (!key)
return NULL;
switch (quality) {
case KEY_QUALITY_KEY:
r = crypt_random_get(cd, vk->key, keylength, CRYPT_RND_KEY);
r = crypt_random_get(cd, key, keylength, CRYPT_RND_KEY);
break;
case KEY_QUALITY_NORMAL:
r = crypt_random_get(cd, vk->key, keylength, CRYPT_RND_NORMAL);
r = crypt_random_get(cd, key, keylength, CRYPT_RND_NORMAL);
break;
case KEY_QUALITY_EMPTY:
r = 0;
@@ -179,10 +217,12 @@ struct volume_key *crypt_generate_volume_key(struct crypt_device *cd, size_t key
abort();
}
if (r) {
crypt_free_volume_key(vk);
vk = NULL;
}
if (!r)
vk = crypt_alloc_volume_key(keylength, NULL);
if (vk)
vk->key = key;
else
crypt_safe_free(key);
return vk;
}