diff --git a/configure.ac b/configure.ac index 142c4da0..f5d95e2f 100644 --- a/configure.ac +++ b/configure.ac @@ -145,6 +145,14 @@ AC_DEFUN([NO_FIPS], [ fi ]) +dnl LUKS2 online reencryption +AC_ARG_ENABLE([luks2-reencryption], + AS_HELP_STRING([--disable-luks2-reencryption], [disable LUKS2 online reencryption extension]), + [], [enable_luks2_reencryption=yes]) +if test "x$enable_luks2_reencryption" = "xyes"; then + AC_DEFINE(USE_LUKS2_REENCRYPTION, 1, [Use LUKS2 online reencryption extension]) +fi + dnl ========================================================================== dnl pwquality library (cryptsetup CLI only) AC_ARG_ENABLE([pwquality], diff --git a/lib/luks2/luks2_keyslot.c b/lib/luks2/luks2_keyslot.c index 99db9385..8409d531 100644 --- a/lib/luks2/luks2_keyslot.c +++ b/lib/luks2/luks2_keyslot.c @@ -27,7 +27,9 @@ extern const keyslot_handler reenc_keyslot; static const keyslot_handler *keyslot_handlers[LUKS2_KEYSLOTS_MAX] = { &luks2_keyslot, +#if USE_LUKS2_REENCRYPTION &reenc_keyslot, +#endif NULL }; diff --git a/lib/luks2/luks2_reencrypt.c b/lib/luks2/luks2_reencrypt.c index 985d6d34..54ace512 100644 --- a/lib/luks2/luks2_reencrypt.c +++ b/lib/luks2/luks2_reencrypt.c @@ -91,7 +91,7 @@ struct luks2_reencrypt { struct crypt_lock_handle *reenc_lock; }; - +#if USE_LUKS2_REENCRYPTION static int reencrypt_keyslot_update(struct crypt_device *cd, const struct luks2_reencrypt *rh) { @@ -195,7 +195,7 @@ static uint64_t reencrypt_get_data_offset_old(struct luks2_hdr *hdr) { return reencrypt_data_offset(hdr, 0); } - +#endif static int reencrypt_digest(struct luks2_hdr *hdr, unsigned new) { int segment = LUKS2_get_segment_id_by_flag(hdr, new ? "backup-final" : "backup-previous"); @@ -254,7 +254,7 @@ static const char *reencrypt_resilience_hash(struct luks2_hdr *hdr) return json_object_get_string(jobj_hash); } - +#if USE_LUKS2_REENCRYPTION static uint32_t reencrypt_alignment(struct luks2_hdr *hdr) { json_object *jobj_keyslot, *jobj_area, *jobj_type, *jobj_hash, *jobj_sector_size; @@ -670,7 +670,7 @@ static int reencrypt_make_post_segments(struct crypt_device *cd, return rh->jobj_segs_post ? 0 : -EINVAL; } - +#endif static uint64_t reencrypt_data_shift(struct luks2_hdr *hdr) { json_object *jobj_keyslot, *jobj_area, *jobj_data_shift; @@ -776,7 +776,7 @@ void LUKS2_reencrypt_free(struct crypt_device *cd, struct luks2_reencrypt *rh) crypt_unlock_internal(cd, rh->reenc_lock); free(rh); } - +#if USE_LUKS2_REENCRYPTION static size_t reencrypt_get_alignment(struct crypt_device *cd, struct luks2_hdr *hdr) { @@ -2669,7 +2669,7 @@ static int reencrypt_load(struct crypt_device *cd, struct luks2_hdr *hdr, return 0; } - +#endif static int reencrypt_lock_internal(struct crypt_device *cd, const char *uuid, struct crypt_lock_handle **reencrypt_lock) { int r; @@ -2731,7 +2731,7 @@ void LUKS2_reencrypt_unlock(struct crypt_device *cd, struct crypt_lock_handle *r { crypt_unlock_internal(cd, reencrypt_lock); } - +#if USE_LUKS2_REENCRYPTION static int reencrypt_lock_and_verify(struct crypt_device *cd, struct luks2_hdr *hdr, struct crypt_lock_handle **reencrypt_lock) { @@ -3000,7 +3000,7 @@ static int reencrypt_recovery_by_passphrase(struct crypt_device *cd, LUKS2_reencrypt_unlock(cd, reencrypt_lock); return r; } - +#endif static int reencrypt_init_by_passphrase(struct crypt_device *cd, const char *name, const char *passphrase, @@ -3011,6 +3011,7 @@ static int reencrypt_init_by_passphrase(struct crypt_device *cd, const char *cipher_mode, const struct crypt_params_reencrypt *params) { +#if USE_LUKS2_REENCRYPTION int r; crypt_reencrypt_info ri; struct volume_key *vks = NULL; @@ -3066,6 +3067,10 @@ out: crypt_drop_keyring_key(cd, vks); crypt_free_volume_key(vks); return r < 0 ? r : LUKS2_find_keyslot(hdr, "reencrypt"); +#else + log_err(cd, _("This operation is not supported for this device type.")); + return -ENOTSUP; +#endif } int crypt_reencrypt_init_by_keyring(struct crypt_device *cd, @@ -3118,6 +3123,7 @@ int crypt_reencrypt_init_by_passphrase(struct crypt_device *cd, return reencrypt_init_by_passphrase(cd, name, passphrase, passphrase_size, keyslot_old, keyslot_new, cipher, cipher_mode, params); } +#if USE_LUKS2_REENCRYPTION static reenc_status_t reencrypt_step(struct crypt_device *cd, struct luks2_hdr *hdr, struct luks2_reencrypt *rh, @@ -3351,10 +3357,11 @@ static int reencrypt_teardown(struct crypt_device *cd, struct luks2_hdr *hdr, return r; } - +#endif int crypt_reencrypt(struct crypt_device *cd, int (*progress)(uint64_t size, uint64_t offset, void *usrptr)) { +#if USE_LUKS2_REENCRYPTION int r; crypt_reencrypt_info ri; struct luks2_hdr *hdr; @@ -3421,8 +3428,13 @@ int crypt_reencrypt(struct crypt_device *cd, r = reencrypt_teardown(cd, hdr, rh, rs, quit, progress); return r; +#else + log_err(cd, _("This operation is not supported for this device type.")); + return -ENOTSUP; +#endif } +#if USE_LUKS2_REENCRYPTION static int reencrypt_recovery(struct crypt_device *cd, struct luks2_hdr *hdr, uint64_t device_size, @@ -3458,7 +3470,7 @@ err: return r; } - +#endif /* * use only for calculation of minimal data device size. * The real data offset is taken directly from segments! @@ -3514,7 +3526,7 @@ int LUKS2_reencrypt_check_device_size(struct crypt_device *cd, struct luks2_hdr return 0; } - +#if USE_LUKS2_REENCRYPTION /* returns keyslot number on success (>= 0) or negative errnor otherwise */ int LUKS2_reencrypt_locked_recovery_by_passphrase(struct crypt_device *cd, int keyslot_old, @@ -3564,7 +3576,7 @@ err: return r < 0 ? r : keyslot; } - +#endif crypt_reencrypt_info LUKS2_reencrypt_get_params(struct luks2_hdr *hdr, struct crypt_params_reencrypt *params) { diff --git a/lib/setup.c b/lib/setup.c index c8936bc2..376b9202 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -3857,21 +3857,6 @@ out: return r; } -static int load_all_keys(struct crypt_device *cd, struct luks2_hdr *hdr, struct volume_key *vks) -{ - int r; - struct volume_key *vk = vks; - - while (vk) { - r = LUKS2_volume_key_load_in_keyring_by_digest(cd, hdr, vk, crypt_volume_key_get_id(vk)); - if (r < 0) - return r; - vk = crypt_volume_key_next(vk); - } - - return 0; -} - /* See fixmes in _open_and_activate_luks2 */ int update_reencryption_flag(struct crypt_device *cd, int enable, bool commit); @@ -3919,6 +3904,22 @@ out: return r < 0 ? r : keyslot; } +#if USE_LUKS2_REENCRYPTION +static int load_all_keys(struct crypt_device *cd, struct luks2_hdr *hdr, struct volume_key *vks) +{ + int r; + struct volume_key *vk = vks; + + while (vk) { + r = LUKS2_volume_key_load_in_keyring_by_digest(cd, hdr, vk, crypt_volume_key_get_id(vk)); + if (r < 0) + return r; + vk = crypt_volume_key_next(vk); + } + + return 0; +} + static int _open_all_keys(struct crypt_device *cd, struct luks2_hdr *hdr, int keyslot, @@ -4095,6 +4096,28 @@ static int _open_and_activate_luks2(struct crypt_device *cd, return r; } +#else +static int _open_and_activate_luks2(struct crypt_device *cd, + int keyslot, + const char *name, + const char *passphrase, + size_t passphrase_size, + uint32_t flags) +{ + crypt_reencrypt_info ri; + + ri = LUKS2_reencrypt_status(&cd->u.luks2.hdr); + if (ri == CRYPT_REENCRYPT_INVALID) + return -EINVAL; + + if (ri > CRYPT_REENCRYPT_NONE) { + log_err(cd, _("This operation is not supported for this device type.")); + return -ENOTSUP; + } + + return _open_and_activate(cd, keyslot, name, passphrase, passphrase_size, flags); +} +#endif static int _activate_by_passphrase(struct crypt_device *cd, const char *name, diff --git a/tests/api-test-2.c b/tests/api-test-2.c index a57a4dd8..c0bfc9ad 100644 --- a/tests/api-test-2.c +++ b/tests/api-test-2.c @@ -3692,6 +3692,7 @@ static void Luks2Flags(void) CRYPT_FREE(cd); } +#if KERNEL_KEYRING && USE_LUKS2_REENCRYPTION static int test_progress(uint64_t size, uint64_t offset, void *usrptr) { while (--test_progress_steps) @@ -3702,7 +3703,6 @@ static int test_progress(uint64_t size, uint64_t offset, void *usrptr) static void Luks2Reencryption(void) { /* reencryption currently depends on kernel keyring support */ -#if KERNEL_KEYRING /* NOTES: * - reencryption requires luks2 parameters. can we avoid it? */ @@ -4404,8 +4404,8 @@ static void Luks2Reencryption(void) crypt_free(cd); _cleanup_dmdevices(); -#endif } +#endif static void Luks2Repair(void) { @@ -4521,7 +4521,9 @@ int main(int argc, char *argv[]) RUN_(Luks2Integrity, "LUKS2 with data integrity"); RUN_(Luks2Refresh, "Active device table refresh"); RUN_(Luks2Flags, "LUKS2 persistent flags"); +#if KERNEL_KEYRING && USE_LUKS2_REENCRYPTION RUN_(Luks2Reencryption, "LUKS2 reencryption"); +#endif RUN_(Luks2Repair, "LUKS2 repair"); // test disables metadata locking. Run always last! _cleanup(); diff --git a/tests/luks2-reencryption-test b/tests/luks2-reencryption-test index 7cf246cd..92f223d2 100755 --- a/tests/luks2-reencryption-test +++ b/tests/luks2-reencryption-test @@ -115,6 +115,7 @@ function fail() function skip() { [ -n "$1" ] && echo "$1" + remove_mapping exit 77 } @@ -726,6 +727,7 @@ echo -n "[512 sector]" echo $PWD1 | $CRYPTSETUP -q luksFormat --type luks2 -s 128 -c aes-cbc-essiv:sha256 --offset 8192 $FAST_PBKDF_ARGON $DEV || fail wipe $PWD1 check_hash $PWD1 $HASH1 +echo $PWD1 | $CRYPTSETUP reencrypt $DEV -q $FAST_PBKDF_ARGON 2>&1 | tail -1 | grep -q "not supported" && skip " No reenryption support, test skipped." echo $PWD1 | $CRYPTSETUP reencrypt $DEV -q $FAST_PBKDF_ARGON || fail check_hash $PWD1 $HASH1 echo $PWD1 | $CRYPTSETUP reencrypt $DEV -q -s 256 -c twofish-cbc-essiv:sha256 --resilience journal $FAST_PBKDF_ARGON || fail