diff --git a/lib/fvault2/fvault2.c b/lib/fvault2/fvault2.c index ae7d9d1a..59f4570f 100644 --- a/lib/fvault2/fvault2.c +++ b/lib/fvault2/fvault2.c @@ -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; diff --git a/lib/fvault2/fvault2.h b/lib/fvault2/fvault2.h index fb842cdc..ad6ad5ee 100644 --- a/lib/fvault2/fvault2.h +++ b/lib/fvault2/fvault2.h @@ -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, diff --git a/lib/internal.h b/lib/internal.h index b393a85f..84a8744f 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -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, diff --git a/lib/libdevmapper.c b/lib/libdevmapper.c index 43e23e35..14a3752d 100644 --- a/lib/libdevmapper.c +++ b/lib/libdevmapper.c @@ -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; diff --git a/lib/loopaes/loopaes.c b/lib/loopaes/loopaes.c index 68331d39..e2c6821d 100644 --- a/lib/loopaes/loopaes.c +++ b/lib/loopaes/loopaes.c @@ -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; } diff --git a/lib/luks1/keymanage.c b/lib/luks1/keymanage.c index f0739b9b..37929810 100644 --- a/lib/luks1/keymanage.c +++ b/lib/luks1/keymanage.c @@ -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; } diff --git a/lib/luks2/luks2_keyslot.c b/lib/luks2/luks2_keyslot.c index d0286d82..7f262e76 100644 --- a/lib/luks2/luks2_keyslot.c +++ b/lib/luks2/luks2_keyslot.c @@ -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, diff --git a/lib/luks2/luks2_keyslot_luks2.c b/lib/luks2/luks2_keyslot_luks2.c index 2007dd53..a20fa186 100644 --- a/lib/luks2/luks2_keyslot_luks2.c +++ b/lib/luks2/luks2_keyslot_luks2.c @@ -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; } diff --git a/lib/luks2/luks2_reencrypt_digest.c b/lib/luks2/luks2_reencrypt_digest.c index d5a1fae3..9db88a48 100644 --- a/lib/luks2/luks2_reencrypt_digest.c +++ b/lib/luks2/luks2_reencrypt_digest.c @@ -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, diff --git a/lib/setup.c b/lib/setup.c index bbf99437..08e361a6 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -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) diff --git a/lib/tcrypt/tcrypt.c b/lib/tcrypt/tcrypt.c index 568dc5a1..fc1fb4d9 100644 --- a/lib/tcrypt/tcrypt.c +++ b/lib/tcrypt/tcrypt.c @@ -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; } diff --git a/lib/volumekey.c b/lib/volumekey.c index 6eedba34..c1a77e5c 100644 --- a/lib/volumekey.c +++ b/lib/volumekey.c @@ -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; }