From a34d0aa8d83b79bc010de9ddf6601f75f890c1a1 Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Mon, 25 Nov 2024 10:47:45 +0100 Subject: [PATCH] libdevmapper: Support dm-crypt integrity_key_size option This patch implement support for setting specific integrity key size option in dm-crypt, available since dm-crypt version 1.28.0. This can be used for setting non-standard HMAC key length. Mostly based on code from Ingo Franzki --- lib/bitlk/bitlk.c | 2 +- lib/fvault2/fvault2.c | 3 +-- lib/libdevmapper.c | 24 ++++++++++++++++++++---- lib/loopaes/loopaes.c | 5 ++--- lib/luks1/keyencryption.c | 2 +- lib/luks1/keymanage.c | 3 +-- lib/luks2/luks2_json_metadata.c | 4 ++-- lib/luks2/luks2_reencrypt.c | 3 +-- lib/setup.c | 5 ++--- lib/tcrypt/tcrypt.c | 5 +---- lib/utils_dm.h | 7 +++++-- lib/utils_storage_wrappers.c | 11 ++--------- 12 files changed, 39 insertions(+), 35 deletions(-) diff --git a/lib/bitlk/bitlk.c b/lib/bitlk/bitlk.c index 7b6fb23bb..df3783a4b 100644 --- a/lib/bitlk/bitlk.c +++ b/lib/bitlk/bitlk.c @@ -1365,7 +1365,7 @@ static int _activate(struct crypt_device *cd, crypt_get_cipher_spec(cd), segments[i].iv_offset, segments[i].iv_offset, - NULL, 0, + NULL, 0, 0, params->sector_size); if (r) goto out; diff --git a/lib/fvault2/fvault2.c b/lib/fvault2/fvault2.c index 3df23f6ee..0d35fe2d4 100644 --- a/lib/fvault2/fvault2.c +++ b/lib/fvault2/fvault2.c @@ -835,8 +835,7 @@ static int _activate( r = dm_crypt_target_set(&dm_dev.segment, 0, dm_dev.size, crypt_data_device(cd), vol_key, cipher, crypt_get_iv_offset(cd), crypt_get_data_offset(cd), - crypt_get_integrity(cd), crypt_get_integrity_tag_size(cd), - crypt_get_sector_size(cd)); + NULL, 0, 0, crypt_get_sector_size(cd)); if (!r) r = dm_create_device(cd, name, CRYPT_FVAULT2, &dm_dev); diff --git a/lib/libdevmapper.c b/lib/libdevmapper.c index f4a4091f1..9b5503805 100644 --- a/lib/libdevmapper.c +++ b/lib/libdevmapper.c @@ -160,6 +160,9 @@ static void _dm_set_crypt_compat(struct crypt_device *cd, if (_dm_satisfies_version(1, 26, 0, crypt_maj, crypt_min, crypt_patch)) _dm_flags |= DM_CRYPT_HIGH_PRIORITY_SUPPORTED; + if (_dm_satisfies_version(1, 28, 0, crypt_maj, crypt_min, crypt_patch)) + _dm_flags |= DM_CRYPT_INTEGRITY_KEY_SIZE_OPT_SUPPORTED; + _dm_crypt_checked = true; } @@ -540,6 +543,7 @@ static char *get_dm_crypt_params(const struct dm_target *tgt, uint32_t flags) int r, max_size, null_cipher = 0, num_options = 0, keystr_len = 0; char *params = NULL, *hexkey = NULL; char sector_feature[32], features[512], integrity_dm[256], cipher_dm[256]; + char int_ksize_feature[64]; if (!tgt) return NULL; @@ -567,9 +571,11 @@ static char *get_dm_crypt_params(const struct dm_target *tgt, uint32_t flags) num_options++; if (tgt->u.crypt.sector_size != SECTOR_SIZE) num_options++; + if (tgt->u.crypt.integrity && tgt->u.crypt.integrity_key_size) + num_options++; - if (num_options) { /* MAX length int32 + 15 + 15 + 23 + 18 + 19 + 17 + 14 + 13 + int32 + integrity_str */ - r = snprintf(features, sizeof(features), " %d%s%s%s%s%s%s%s%s%s", num_options, + if (num_options) { /* MAX length int32 + 15 + 15 + 23 + 18 + 19 + 17 + 14 + 13 + int32 + integrity_str + 21 + int32 */ + r = snprintf(features, sizeof(features), " %d%s%s%s%s%s%s%s%s%s%s", num_options, (flags & CRYPT_ACTIVATE_ALLOW_DISCARDS) ? " allow_discards" : "", (flags & CRYPT_ACTIVATE_SAME_CPU_CRYPT) ? " same_cpu_crypt" : "", (flags & CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS) ? " submit_from_crypt_cpus" : "", @@ -579,7 +585,9 @@ static char *get_dm_crypt_params(const struct dm_target *tgt, uint32_t flags) (flags & CRYPT_ACTIVATE_HIGH_PRIORITY) ? " high_priority" : "", (tgt->u.crypt.sector_size != SECTOR_SIZE) ? _uf(sector_feature, sizeof(sector_feature), "sector_size", tgt->u.crypt.sector_size) : "", - integrity_dm); + integrity_dm, + (tgt->u.crypt.integrity && tgt->u.crypt.integrity_key_size) ? + _uf(int_ksize_feature, sizeof(int_ksize_feature), "integrity_key_size", tgt->u.crypt.integrity_key_size) : ""); if (r < 0 || (size_t)r >= sizeof(features)) goto out; } else @@ -1748,6 +1756,10 @@ int dm_create_device(struct crypt_device *cd, const char *name, log_err(cd, _("The device size is not multiple of the requested sector size.")); r = -EINVAL; } + if (dmd->segment.u.crypt.integrity_key_size && !(dmt_flags & DM_CRYPT_INTEGRITY_KEY_SIZE_OPT_SUPPORTED)) { + log_err(cd, _("Requested integrity_key_size option is not supported.")); + r = -EINVAL; + } } if (dmd->segment.type == DM_INTEGRITY && (dmd->flags & CRYPT_ACTIVATE_RECALCULATE) && @@ -2065,6 +2077,8 @@ static int _dm_target_query_crypt(struct crypt_device *cd, uint32_t get_flags, if (!rintegrity) goto err; rintegrity++; + } else if (sscanf(arg, "integrity_key_size:%u", &val) == 1) { + tgt->u.crypt.integrity_key_size = val; } else if (sscanf(arg, "sector_size:%u", &val) == 1) { tgt->u.crypt.sector_size = val; } else /* unknown option */ @@ -3142,7 +3156,8 @@ int dm_is_dm_kernel_name(const char *name) int dm_crypt_target_set(struct dm_target *tgt, uint64_t seg_offset, uint64_t seg_size, struct device *data_device, struct volume_key *vk, const char *cipher, - uint64_t iv_offset, uint64_t data_offset, const char *integrity, uint32_t tag_size, + uint64_t iv_offset, uint64_t data_offset, + const char *integrity, uint32_t integrity_key_size, uint32_t tag_size, uint32_t sector_size) { char *dm_integrity = NULL; @@ -3168,6 +3183,7 @@ int dm_crypt_target_set(struct dm_target *tgt, uint64_t seg_offset, uint64_t seg tgt->u.crypt.offset = data_offset; tgt->u.crypt.tag_size = tag_size; tgt->u.crypt.sector_size = sector_size; + tgt->u.crypt.integrity_key_size = integrity_key_size; return 0; } diff --git a/lib/loopaes/loopaes.c b/lib/loopaes/loopaes.c index 8aec3de39..b3720f9c4 100644 --- a/lib/loopaes/loopaes.c +++ b/lib/loopaes/loopaes.c @@ -213,9 +213,8 @@ int LOOPAES_activate(struct crypt_device *cd, return -ENOMEM; r = dm_crypt_target_set(&dmd.segment, 0, dmd.size, crypt_data_device(cd), - vk, cipher, crypt_get_iv_offset(cd), - crypt_get_data_offset(cd), crypt_get_integrity(cd), - crypt_get_integrity_tag_size(cd), crypt_get_sector_size(cd)); + vk, cipher, crypt_get_iv_offset(cd), crypt_get_data_offset(cd), + NULL, 0, 0, crypt_get_sector_size(cd)); if (r) { free(cipher); diff --git a/lib/luks1/keyencryption.c b/lib/luks1/keyencryption.c index 63e47fc3e..46d7f3009 100644 --- a/lib/luks1/keyencryption.c +++ b/lib/luks1/keyencryption.c @@ -88,7 +88,7 @@ static int LUKS_endec_template(char *src, size_t srcLength, r = dm_crypt_target_set(&dmd.segment, 0, dmd.size, crypt_metadata_device(ctx), vk, cipher_spec, 0, sector, - NULL, 0, SECTOR_SIZE); + NULL, 0, 0, SECTOR_SIZE); if (r) goto out; diff --git a/lib/luks1/keymanage.c b/lib/luks1/keymanage.c index 5d8fe9665..d427e4ece 100644 --- a/lib/luks1/keymanage.c +++ b/lib/luks1/keymanage.c @@ -1204,8 +1204,7 @@ int LUKS1_activate(struct crypt_device *cd, r = dm_crypt_target_set(&dmd.segment, 0, dmd.size, crypt_data_device(cd), vk, crypt_get_cipher_spec(cd), crypt_get_iv_offset(cd), - crypt_get_data_offset(cd), crypt_get_integrity(cd), - crypt_get_integrity_tag_size(cd), crypt_get_sector_size(cd)); + crypt_get_data_offset(cd), NULL, 0, 0, crypt_get_sector_size(cd)); if (!r) r = create_or_reload_device(cd, name, CRYPT_LUKS1, &dmd); diff --git a/lib/luks2/luks2_json_metadata.c b/lib/luks2/luks2_json_metadata.c index 3056ed87f..d3ee9ebd7 100644 --- a/lib/luks2/luks2_json_metadata.c +++ b/lib/luks2/luks2_json_metadata.c @@ -2519,7 +2519,7 @@ int LUKS2_assembly_multisegment_dmd(struct crypt_device *cd, crypt_data_device(cd), vk, json_segment_get_cipher(jobj), json_segment_get_iv_offset(jobj), - segment_offset, "none", 0, + segment_offset, "none", 0, 0, json_segment_get_sector_size(jobj)); if (r) { log_err(cd, _("Failed to set dm-crypt segment.")); @@ -2715,7 +2715,7 @@ int LUKS2_activate(struct crypt_device *cd, crypt_key, crypt_get_cipher_spec(cd), crypt_get_iv_offset(cd), crypt_get_data_offset(cd), crypt_get_integrity(cd) ?: "none", - crypt_get_integrity_tag_size(cd), + 0 /* FIXME */, crypt_get_integrity_tag_size(cd), crypt_get_sector_size(cd)); } else r = dm_linear_target_set(&dmd.segment, 0, diff --git a/lib/luks2/luks2_reencrypt.c b/lib/luks2/luks2_reencrypt.c index 7901f3981..7e938714e 100644 --- a/lib/luks2/luks2_reencrypt.c +++ b/lib/luks2/luks2_reencrypt.c @@ -2114,8 +2114,7 @@ static int reencrypt_make_targets(struct crypt_device *cd, json_segment_get_cipher(jobj), json_segment_get_iv_offset(jobj), segment_offset, - "none", - 0, + "none", 0, 0, json_segment_get_sector_size(jobj)); if (r) { log_err(cd, _("Failed to set dm-crypt segment.")); diff --git a/lib/setup.c b/lib/setup.c index b1f08bdb3..919fd3cbb 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -609,8 +609,7 @@ int PLAIN_activate(struct crypt_device *cd, r = dm_crypt_target_set(&dmd.segment, 0, dmd.size, crypt_data_device(cd), vk, crypt_get_cipher_spec(cd), crypt_get_iv_offset(cd), - crypt_get_data_offset(cd), crypt_get_integrity(cd), - crypt_get_integrity_tag_size(cd), crypt_get_sector_size(cd)); + crypt_get_data_offset(cd), NULL, 0, 0, crypt_get_sector_size(cd)); if (r < 0) return r; @@ -3701,7 +3700,7 @@ int crypt_resize(struct crypt_device *cd, const char *name, uint64_t new_size) r = dm_crypt_target_set(&dmd.segment, 0, new_size, crypt_data_device(cd), tgt->u.crypt.vk, crypt_get_cipher_spec(cd), crypt_get_iv_offset(cd), crypt_get_data_offset(cd), - crypt_get_integrity(cd), crypt_get_integrity_tag_size(cd), + crypt_get_integrity(cd), 0 /* FIXME */, crypt_get_integrity_tag_size(cd), crypt_get_sector_size(cd)); if (r < 0) goto out; diff --git a/lib/tcrypt/tcrypt.c b/lib/tcrypt/tcrypt.c index e2203cc0e..4a9d38de0 100644 --- a/lib/tcrypt/tcrypt.c +++ b/lib/tcrypt/tcrypt.c @@ -887,10 +887,7 @@ int TCRYPT_activate(struct crypt_device *cd, } r = dm_crypt_target_set(&dmd.segment, 0, dmd.size, ptr_dev, vk, - cipher_spec, iv_offset, offset, - crypt_get_integrity(cd), - crypt_get_integrity_tag_size(cd), - crypt_get_sector_size(cd)); + cipher_spec, iv_offset, offset, NULL, 0, 0, crypt_get_sector_size(cd)); if (r) break; diff --git a/lib/utils_dm.h b/lib/utils_dm.h index 3b762b9a7..62d2227c4 100644 --- a/lib/utils_dm.h +++ b/lib/utils_dm.h @@ -64,6 +64,7 @@ static inline uint32_t act2dmflags(uint32_t act_flags) #define DM_INTEGRITY_RESET_RECALC_SUPPORTED (1 << 27) /* dm-integrity automatic recalculation supported */ #define DM_VERITY_TASKLETS_SUPPORTED (1 << 28) /* dm-verity tasklets supported */ #define DM_CRYPT_HIGH_PRIORITY_SUPPORTED (1 << 29) /* dm-crypt high priority workqueue flag supported */ +#define DM_CRYPT_INTEGRITY_KEY_SIZE_OPT_SUPPORTED (1 << 30) /* dm-crypt support for integrity_key_size option */ typedef enum { DM_CRYPT = 0, DM_VERITY, DM_INTEGRITY, DM_LINEAR, DM_ERROR, DM_ZERO, DM_UNKNOWN } dm_target_type; enum tdirection { TARGET_EMPTY = 0, TARGET_SET, TARGET_QUERY }; @@ -109,6 +110,7 @@ struct dm_target { uint64_t iv_offset; /* IV initialisation sector */ uint32_t tag_size; /* additional on-disk tag size */ uint32_t sector_size; /* encryption sector size */ + uint32_t integrity_key_size; /* for wrapped key HMAC */ } crypt; struct { struct device *hash_device; @@ -183,8 +185,9 @@ void dm_targets_free(struct crypt_device *cd, struct crypt_dm_active_device *dmd int dm_crypt_target_set(struct dm_target *tgt, uint64_t seg_offset, uint64_t seg_size, struct device *data_device, struct volume_key *vk, const char *cipher, - uint64_t iv_offset, uint64_t data_offset, const char *integrity, - uint32_t tag_size, uint32_t sector_size); + uint64_t iv_offset, uint64_t data_offset, + const char *integrity, uint32_t integrity_key_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, struct device *data_device, struct device *hash_device, struct device *fec_device, const char *root_hash, uint32_t root_hash_size, const char* root_hash_sig_key_desc, diff --git a/lib/utils_storage_wrappers.c b/lib/utils_storage_wrappers.c index 52f065c59..c23edf230 100644 --- a/lib/utils_storage_wrappers.c +++ b/lib/utils_storage_wrappers.c @@ -106,15 +106,8 @@ static int crypt_storage_dmcrypt_init( if (vk->key_description) dmd.flags |= CRYPT_ACTIVATE_KEYRING_KEY; - r = dm_crypt_target_set(&dmd.segment, 0, dmd.size, - device, - vk, - cipher_spec, - iv_start, - device_offset, - NULL, - 0, - sector_size); + r = dm_crypt_target_set(&dmd.segment, 0, dmd.size, device, vk, cipher_spec, iv_start, + device_offset, NULL, 0, 0, sector_size); if (r) return r;