diff -rupN cryptsetup-2.3.3.old/lib/luks2/luks2.h cryptsetup-2.3.3/lib/luks2/luks2.h --- cryptsetup-2.3.3.old/lib/luks2/luks2.h 2022-01-17 15:03:03.689201103 +0100 +++ cryptsetup-2.3.3/lib/luks2/luks2.h 2022-01-17 15:06:42.149966321 +0100 @@ -606,4 +606,8 @@ void crypt_reencrypt_unlock(struct crypt int luks2_check_device_size(struct crypt_device *cd, struct luks2_hdr *hdr, uint64_t check_size, uint64_t *dev_size, bool activation, bool dynamic); +int LUKS2_reencrypt_digest_verify(struct crypt_device *cd, + struct luks2_hdr *hdr, + struct volume_key *vks); + #endif diff -rupN cryptsetup-2.3.3.old/lib/luks2/luks2_internal.h cryptsetup-2.3.3/lib/luks2/luks2_internal.h --- cryptsetup-2.3.3.old/lib/luks2/luks2_internal.h 2022-01-17 15:03:03.689201103 +0100 +++ cryptsetup-2.3.3/lib/luks2/luks2_internal.h 2022-01-17 15:51:20.125346606 +0100 @@ -128,6 +128,12 @@ int placeholder_keyslot_alloc(struct cry /* validate all keyslot implementations in hdr json */ int LUKS2_keyslots_validate(struct crypt_device *cd, json_object *hdr_jobj); +int LUKS2_keyslot_jobj_area(json_object *jobj_keyslot, uint64_t *offset, uint64_t *length); + +int LUKS2_keyslot_reencrypt_digest_create(struct crypt_device *cd, + struct luks2_hdr *hdr, + struct volume_key *vks); + typedef struct { const char *name; keyslot_alloc_func alloc; diff -rupN cryptsetup-2.3.3.old/lib/luks2/luks2_json_metadata.c cryptsetup-2.3.3/lib/luks2/luks2_json_metadata.c --- cryptsetup-2.3.3.old/lib/luks2/luks2_json_metadata.c 2022-01-17 15:03:03.689201103 +0100 +++ cryptsetup-2.3.3/lib/luks2/luks2_json_metadata.c 2022-01-17 15:05:48.165777220 +0100 @@ -1371,24 +1371,63 @@ int LUKS2_config_set_flags(struct crypt_ */ /* LUKS2 library requirements */ -static const struct { +struct requirement_flag { uint32_t flag; + uint32_t version; const char *description; -} requirements_flags[] = { - { CRYPT_REQUIREMENT_OFFLINE_REENCRYPT, "offline-reencrypt" }, - { CRYPT_REQUIREMENT_ONLINE_REENCRYPT, "online-reencrypt" }, - { 0, NULL } }; -static uint32_t get_requirement_by_name(const char *requirement) +static const struct requirement_flag unknown_requirement_flag = { CRYPT_REQUIREMENT_UNKNOWN, 0, NULL }; + +static const struct requirement_flag requirements_flags[] = { + { CRYPT_REQUIREMENT_OFFLINE_REENCRYPT,1, "offline-reencrypt" }, + { CRYPT_REQUIREMENT_ONLINE_REENCRYPT, 2, "online-reencrypt-v2" }, + { CRYPT_REQUIREMENT_ONLINE_REENCRYPT, 1, "online-reencrypt" }, + { 0, 0, NULL } +}; + +static const struct requirement_flag *get_requirement_by_name(const char *requirement) { int i; for (i = 0; requirements_flags[i].description; i++) if (!strcmp(requirement, requirements_flags[i].description)) - return requirements_flags[i].flag; + return requirements_flags + i; + + return &unknown_requirement_flag; +} + +static const struct requirement_flag *stored_requirement_name_by_id(struct crypt_device *cd, struct luks2_hdr *hdr, uint32_t req_id) +{ + json_object *jobj_config, *jobj_requirements, *jobj_mandatory, *jobj; + int i, len; + const struct requirement_flag *req; + + assert(hdr); + if (!hdr) + return NULL; + + if (!json_object_object_get_ex(hdr->jobj, "config", &jobj_config)) + return NULL; + + if (!json_object_object_get_ex(jobj_config, "requirements", &jobj_requirements)) + return NULL; + + if (!json_object_object_get_ex(jobj_requirements, "mandatory", &jobj_mandatory)) + return NULL; + + len = (int) json_object_array_length(jobj_mandatory); + if (len <= 0) + return 0; + + for (i = 0; i < len; i++) { + jobj = json_object_array_get_idx(jobj_mandatory, i); + req = get_requirement_by_name(json_object_get_string(jobj)); + if (req->flag == req_id) + return req; + } - return CRYPT_REQUIREMENT_UNKNOWN; + return NULL; } /* @@ -1398,7 +1437,7 @@ int LUKS2_config_get_requirements(struct { json_object *jobj_config, *jobj_requirements, *jobj_mandatory, *jobj; int i, len; - uint32_t req; + const struct requirement_flag *req; assert(hdr); if (!hdr || !reqs) @@ -1425,8 +1464,8 @@ int LUKS2_config_get_requirements(struct jobj = json_object_array_get_idx(jobj_mandatory, i); req = get_requirement_by_name(json_object_get_string(jobj)); log_dbg(cd, "%s - %sknown", json_object_get_string(jobj), - reqs_unknown(req) ? "un" : ""); - *reqs |= req; + reqs_unknown(req->flag) ? "un" : ""); + *reqs |= req->flag; } return 0; @@ -1436,6 +1475,8 @@ int LUKS2_config_set_requirements(struct { json_object *jobj_config, *jobj_requirements, *jobj_mandatory, *jobj; int i, r = -EINVAL; + const struct requirement_flag *req; + uint32_t req_id; if (!hdr) return -EINVAL; @@ -1445,8 +1486,14 @@ int LUKS2_config_set_requirements(struct return -ENOMEM; for (i = 0; requirements_flags[i].description; i++) { - if (reqs & requirements_flags[i].flag) { - jobj = json_object_new_string(requirements_flags[i].description); + req_id = reqs & requirements_flags[i].flag; + if (req_id) { + /* retain already stored version of requirement flag */ + req = stored_requirement_name_by_id(cd, hdr, req_id); + if (req) + jobj = json_object_new_string(req->description); + else + jobj = json_object_new_string(requirements_flags[i].description); if (!jobj) { r = -ENOMEM; goto err; diff -rupN cryptsetup-2.3.3.old/lib/luks2/luks2_keyslot.c cryptsetup-2.3.3/lib/luks2/luks2_keyslot.c --- cryptsetup-2.3.3.old/lib/luks2/luks2_keyslot.c 2022-01-17 15:03:03.689201103 +0100 +++ cryptsetup-2.3.3/lib/luks2/luks2_keyslot.c 2022-01-17 15:05:48.165777220 +0100 @@ -281,19 +281,9 @@ crypt_keyslot_info LUKS2_keyslot_info(st return CRYPT_SLOT_ACTIVE; } -int LUKS2_keyslot_area(struct luks2_hdr *hdr, - int keyslot, - uint64_t *offset, - uint64_t *length) +int LUKS2_keyslot_jobj_area(json_object *jobj_keyslot, uint64_t *offset, uint64_t *length) { - json_object *jobj_keyslot, *jobj_area, *jobj; - - if(LUKS2_keyslot_info(hdr, keyslot) == CRYPT_SLOT_INVALID) - return -EINVAL; - - jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot); - if (!jobj_keyslot) - return -ENOENT; + json_object *jobj_area, *jobj; if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area)) return -EINVAL; @@ -309,6 +299,23 @@ int LUKS2_keyslot_area(struct luks2_hdr return 0; } +int LUKS2_keyslot_area(struct luks2_hdr *hdr, + int keyslot, + uint64_t *offset, + uint64_t *length) +{ + json_object *jobj_keyslot; + + if (LUKS2_keyslot_info(hdr, keyslot) == CRYPT_SLOT_INVALID) + return -EINVAL; + + jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot); + if (!jobj_keyslot) + return -ENOENT; + + return LUKS2_keyslot_jobj_area(jobj_keyslot, offset, length); +} + static int _open_and_verify(struct crypt_device *cd, struct luks2_hdr *hdr, const keyslot_handler *h, diff -rupN cryptsetup-2.3.3.old/lib/luks2/luks2_keyslot_reenc.c cryptsetup-2.3.3/lib/luks2/luks2_keyslot_reenc.c --- cryptsetup-2.3.3.old/lib/luks2/luks2_keyslot_reenc.c 2022-01-17 15:03:03.689201103 +0100 +++ cryptsetup-2.3.3/lib/luks2/luks2_keyslot_reenc.c 2022-01-17 15:59:15.897013127 +0100 @@ -179,6 +179,7 @@ static int reenc_keyslot_store(struct cr int reenc_keyslot_update(struct crypt_device *cd, const struct luks2_reenc_context *rh) { + int r; json_object *jobj_keyslot, *jobj_area, *jobj_area_type; struct luks2_hdr *hdr; @@ -208,11 +209,23 @@ int reenc_keyslot_update(struct crypt_de } else log_dbg(cd, "No update of reencrypt keyslot needed."); - return 0; + r = LUKS2_keyslot_reencrypt_digest_create(cd, hdr, rh->vks); + if (r < 0) + log_err(cd, "Failed to refresh reencryption verification digest."); + + return r; } static int reenc_keyslot_wipe(struct crypt_device *cd, int keyslot) { + struct luks2_hdr *hdr; + + if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2))) + return -EINVAL; + + /* remove reencryption verification data */ + LUKS2_digest_assign(cd, hdr, keyslot, CRYPT_ANY_DIGEST, 0, 0); + return 0; } diff -rupN cryptsetup-2.3.3.old/lib/luks2/luks2_reencrypt.c cryptsetup-2.3.3/lib/luks2/luks2_reencrypt.c --- cryptsetup-2.3.3.old/lib/luks2/luks2_reencrypt.c 2022-01-17 15:03:03.689201103 +0100 +++ cryptsetup-2.3.3/lib/luks2/luks2_reencrypt.c 2022-01-17 15:57:08.906568302 +0100 @@ -2390,6 +2390,10 @@ static int reencrypt_init(struct crypt_d if (r < 0) goto err; + r = LUKS2_keyslot_reencrypt_digest_create(cd, hdr, *vks); + if (r < 0) + goto err; + if (name && params->mode != CRYPT_REENCRYPT_ENCRYPT) { r = reencrypt_verify_and_upload_keys(cd, hdr, LUKS2_reencrypt_digest_old(hdr), LUKS2_reencrypt_digest_new(hdr), *vks); if (r) @@ -2520,20 +2524,28 @@ static int reencrypt_context_update(stru static int reencrypt_load(struct crypt_device *cd, struct luks2_hdr *hdr, uint64_t device_size, const struct crypt_params_reencrypt *params, + struct volume_key *vks, struct luks2_reenc_context **rh) { int r; struct luks2_reenc_context *tmp = NULL; crypt_reencrypt_info ri = LUKS2_reenc_status(hdr); + if (ri == CRYPT_REENCRYPT_NONE) { + log_err(cd, _("Device not marked for LUKS2 reencryption.")); + return -EINVAL; + } else if (ri == CRYPT_REENCRYPT_INVALID) + return -EINVAL; + + r = LUKS2_reencrypt_digest_verify(cd, hdr, vks); + if (r < 0) + return r; + if (ri == CRYPT_REENCRYPT_CLEAN) r = reencrypt_load_clean(cd, hdr, device_size, &tmp, params); else if (ri == CRYPT_REENCRYPT_CRASH) r = reencrypt_load_crashed(cd, hdr, device_size, &tmp); - else if (ri == CRYPT_REENCRYPT_NONE) { - log_err(cd, _("Device not marked for LUKS2 reencryption.")); - return -EINVAL; - } else + else r = -EINVAL; if (r < 0 || !tmp) { @@ -2781,7 +2793,7 @@ static int reencrypt_load_by_passphrase( rparams.device_size = required_size; } - r = reencrypt_load(cd, hdr, device_size, &rparams, &rh); + r = reencrypt_load(cd, hdr, device_size, &rparams, *vks, &rh); if (r < 0 || !rh) goto err; @@ -3001,13 +3013,6 @@ static reenc_status_t reencrypt_step(str { int r; - /* update reencrypt keyslot protection parameters in memory only */ - r = reenc_keyslot_update(cd, rh); - if (r < 0) { - log_dbg(cd, "Keyslot update failed."); - return REENC_ERR; - } - /* in memory only */ r = reencrypt_make_segments(cd, hdr, rh, device_size); if (r) @@ -3272,6 +3277,15 @@ int crypt_reencrypt(struct crypt_device rs = REENC_OK; + /* update reencrypt keyslot protection parameters in memory only */ + if (!quit && (rh->device_size > rh->progress)) { + r = reenc_keyslot_update(cd, rh); + if (r < 0) { + log_dbg(cd, "Keyslot update failed."); + return reencrypt_teardown(cd, hdr, rh, REENC_ERR, quit, progress); + } + } + while (!quit && (rh->device_size > rh->progress)) { rs = reencrypt_step(cd, hdr, rh, rh->device_size, rh->online); if (rs != REENC_OK) @@ -3304,7 +3318,7 @@ static int reencrypt_recovery(struct cry int r; struct luks2_reenc_context *rh = NULL; - r = reencrypt_load(cd, hdr, device_size, NULL, &rh); + r = reencrypt_load(cd, hdr, device_size, NULL, vks, &rh); if (r < 0) { log_err(cd, _("Failed to load LUKS2 reencryption context.")); return r; diff -rupN cryptsetup-2.3.3.old/lib/luks2/luks2_reencrypt_digest.c cryptsetup-2.3.3/lib/luks2/luks2_reencrypt_digest.c --- cryptsetup-2.3.3.old/lib/luks2/luks2_reencrypt_digest.c 1970-01-01 01:00:00.000000000 +0100 +++ cryptsetup-2.3.3/lib/luks2/luks2_reencrypt_digest.c 2022-01-17 15:05:48.166777223 +0100 @@ -0,0 +1,381 @@ +/* + * LUKS - Linux Unified Key Setup v2, reencryption digest helpers + * + * Copyright (C) 2022, Red Hat, Inc. All rights reserved. + * Copyright (C) 2022, Ondrej Kozina + * Copyright (C) 2022, Milan Broz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "luks2_internal.h" +#include + +#define MAX_STR 64 + +struct jtype { + enum { JNONE = 0, JSTR, JU64, JX64, JU32 } type; + json_object *jobj; + const char *id; +}; + +static size_t sr(struct jtype *j, uint8_t *ptr) +{ + json_object *jobj; + size_t len = 0; + uint64_t u64; + uint32_t u32; + + if (!json_object_is_type(j->jobj, json_type_object)) + return 0; + + if (!json_object_object_get_ex(j->jobj, j->id, &jobj)) + return 0; + + switch(j->type) { + case JSTR: /* JSON string */ + if (!json_object_is_type(jobj, json_type_string)) + return 0; + len = strlen(json_object_get_string(jobj)); + if (len > MAX_STR) + return 0; + if (ptr) + memcpy(ptr, json_object_get_string(jobj), len); + break; + case JU64: /* Unsigned 64bit integer stored as string */ + if (!json_object_is_type(jobj, json_type_string)) + break; + len = sizeof(u64); + if (ptr) { + u64 = cpu_to_be64(crypt_jobj_get_uint64(jobj)); + memcpy(ptr, &u64, len); + } + break; + case JX64: /* Unsigned 64bit segment size (allows "dynamic") */ + if (!json_object_is_type(jobj, json_type_string)) + break; + if (!strcmp(json_object_get_string(jobj), "dynamic")) { + len = strlen("dynamic"); + if (ptr) + memcpy(ptr, json_object_get_string(jobj), len); + } else { + len = sizeof(u64); + u64 = cpu_to_be64(crypt_jobj_get_uint64(jobj)); + if (ptr) + memcpy(ptr, &u64, len); + } + break; + case JU32: /* Unsigned 32bit integer, stored as JSON int */ + if (!json_object_is_type(jobj, json_type_int)) + return 0; + len = sizeof(u32); + if (ptr) { + u32 = cpu_to_be32(crypt_jobj_get_uint32(jobj)); + memcpy(ptr, &u32, len); + } + break; + case JNONE: + return 0; + }; + + return len; +} + +static size_t srs(struct jtype j[], uint8_t *ptr) +{ + size_t l, len = 0; + + while(j->jobj) { + l = sr(j, ptr); + if (!l) + return 0; + len += l; + if (ptr) + ptr += l; + j++; + } + return len; +} + +static size_t segment_linear_serialize(json_object *jobj_segment, uint8_t *buffer) +{ + struct jtype j[] = { + { JSTR, jobj_segment, "type" }, + { JU64, jobj_segment, "offset" }, + { JX64, jobj_segment, "size" }, + {} + }; + return srs(j, buffer); +} + +static size_t segment_crypt_serialize(json_object *jobj_segment, uint8_t *buffer) +{ + struct jtype j[] = { + { JSTR, jobj_segment, "type" }, + { JU64, jobj_segment, "offset" }, + { JX64, jobj_segment, "size" }, + { JU64, jobj_segment, "iv_tweak" }, + { JSTR, jobj_segment, "encryption" }, + { JU32, jobj_segment, "sector_size" }, + {} + }; + return srs(j, buffer); +} + +static size_t segment_serialize(json_object *jobj_segment, uint8_t *buffer) +{ + json_object *jobj_type; + const char *segment_type; + + if (!json_object_object_get_ex(jobj_segment, "type", &jobj_type)) + return 0; + + if (!(segment_type = json_object_get_string(jobj_type))) + return 0; + + if (!strcmp(segment_type, "crypt")) + return segment_crypt_serialize(jobj_segment, buffer); + else if (!strcmp(segment_type, "linear")) + return segment_linear_serialize(jobj_segment, buffer); + + return 0; +} + +static size_t backup_segments_serialize(struct luks2_hdr *hdr, uint8_t *buffer) +{ + json_object *jobj_segment; + size_t l, len = 0; + + jobj_segment = LUKS2_get_segment_by_flag(hdr, "backup-previous"); + if (!jobj_segment || !(l = segment_serialize(jobj_segment, buffer))) + return 0; + len += l; + if (buffer) + buffer += l; + + jobj_segment = LUKS2_get_segment_by_flag(hdr, "backup-final"); + if (!jobj_segment || !(l = segment_serialize(jobj_segment, buffer))) + return 0; + len += l; + if (buffer) + buffer += l; + + jobj_segment = LUKS2_get_segment_by_flag(hdr, "backup-moved-segment"); + if (jobj_segment) { + if (!(l = segment_serialize(jobj_segment, buffer))) + return 0; + len += l; + } + + return len; +} + +static size_t reenc_keyslot_serialize(struct luks2_hdr *hdr, uint8_t *buffer) +{ + json_object *jobj_keyslot, *jobj_area, *jobj_type; + const char *area_type; + int keyslot_reencrypt; + + keyslot_reencrypt = LUKS2_find_keyslot(hdr, "reencrypt"); + if (keyslot_reencrypt < 0) + return 0; + + if (!(jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot_reencrypt))) + return 0; + + if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area)) + return 0; + + if (!json_object_object_get_ex(jobj_area, "type", &jobj_type)) + return 0; + + if (!(area_type = json_object_get_string(jobj_type))) + return 0; + + struct jtype j[] = { + { JSTR, jobj_keyslot, "mode" }, + { JSTR, jobj_keyslot, "direction" }, + { JSTR, jobj_area, "type" }, + { JU64, jobj_area, "offset" }, + { JU64, jobj_area, "size" }, + {} + }; + struct jtype j_datashift[] = { + { JSTR, jobj_keyslot, "mode" }, + { JSTR, jobj_keyslot, "direction" }, + { JSTR, jobj_area, "type" }, + { JU64, jobj_area, "offset" }, + { JU64, jobj_area, "size" }, + { JU64, jobj_area, "shift_size" }, + {} + }; + struct jtype j_checksum[] = { + { JSTR, jobj_keyslot, "mode" }, + { JSTR, jobj_keyslot, "direction" }, + { JSTR, jobj_area, "type" }, + { JU64, jobj_area, "offset" }, + { JU64, jobj_area, "size" }, + { JSTR, jobj_area, "hash" }, + { JU32, jobj_area, "sector_size" }, + {} + }; + + if (!strcmp(area_type, "datashift")) + return srs(j_datashift, buffer); + else if (!strcmp(area_type, "checksum")) + return srs(j_checksum, buffer); + + return srs(j, buffer); +} + +static size_t blob_serialize(void *blob, size_t length, uint8_t *buffer) +{ + if (buffer) + memcpy(buffer, blob, length); + + return length; +} + +static int reencrypt_assembly_verification_data(struct crypt_device *cd, + struct luks2_hdr *hdr, + struct volume_key *vks, + struct volume_key **verification_data) +{ + uint8_t *ptr; + int digest_new, digest_old; + struct volume_key *data = NULL, *vk_old = NULL, *vk_new = NULL; + size_t keyslot_data_len, segments_data_len, data_len = 2; + + /* Keys - calculate length */ + digest_new = LUKS2_reencrypt_digest_new(hdr); + digest_old = LUKS2_reencrypt_digest_old(hdr); + + if (digest_old >= 0) { + vk_old = crypt_volume_key_by_id(vks, digest_old); + if (!vk_old) + return -EINVAL; + data_len += blob_serialize(vk_old->key, vk_old->keylength, NULL); + } + + if (digest_new >= 0 && digest_old != digest_new) { + vk_new = crypt_volume_key_by_id(vks, digest_new); + if (!vk_new) + return -EINVAL; + data_len += blob_serialize(vk_new->key, vk_new->keylength, NULL); + } + + if (data_len == 2) + return -EINVAL; + + /* Metadata - calculate length */ + if (!(keyslot_data_len = reenc_keyslot_serialize(hdr, NULL))) + return -EINVAL; + data_len += keyslot_data_len; + + if (!(segments_data_len = backup_segments_serialize(hdr, NULL))) + return -EINVAL; + data_len += segments_data_len; + + /* Alloc and fill serialization data */ + data = crypt_alloc_volume_key(data_len, NULL); + if (!data) + return -ENOMEM; + + ptr = (uint8_t*)data->key; + + /* v2 */ + *ptr++ = 0x76; + *ptr++ = 0x32; + + if (vk_old) + ptr += blob_serialize(vk_old->key, vk_old->keylength, ptr); + + if (vk_new) + ptr += blob_serialize(vk_new->key, vk_new->keylength, ptr); + + if (!reenc_keyslot_serialize(hdr, ptr)) + goto bad; + ptr += keyslot_data_len; + + if (!backup_segments_serialize(hdr, ptr)) + goto bad; + ptr += segments_data_len; + + assert((size_t)(ptr - (uint8_t*)data->key) == data_len); + + *verification_data = data; + + return 0; +bad: + crypt_free_volume_key(data); + return -EINVAL; +} + +int LUKS2_keyslot_reencrypt_digest_create(struct crypt_device *cd, + struct luks2_hdr *hdr, + struct volume_key *vks) +{ + int digest_reencrypt, keyslot_reencrypt, r; + struct volume_key *data; + + keyslot_reencrypt = LUKS2_find_keyslot(hdr, "reencrypt"); + if (keyslot_reencrypt < 0) + return keyslot_reencrypt; + + r = reencrypt_assembly_verification_data(cd, hdr, vks, &data); + if (r < 0) + return r; + + r = LUKS2_digest_create(cd, "pbkdf2", hdr, data); + crypt_free_volume_key(data); + if (r < 0) + return r; + + digest_reencrypt = r; + + r = LUKS2_digest_assign(cd, hdr, keyslot_reencrypt, CRYPT_ANY_DIGEST, 0, 0); + if (r < 0) + return r; + + return LUKS2_digest_assign(cd, hdr, keyslot_reencrypt, digest_reencrypt, 1, 0); +} + +int LUKS2_reencrypt_digest_verify(struct crypt_device *cd, + struct luks2_hdr *hdr, + struct volume_key *vks) +{ + int r, keyslot_reencrypt; + struct volume_key *data; + + keyslot_reencrypt = LUKS2_find_keyslot(hdr, "reencrypt"); + if (keyslot_reencrypt < 0) + return keyslot_reencrypt; + + r = reencrypt_assembly_verification_data(cd, hdr, vks, &data); + if (r < 0) + return r; + + r = LUKS2_digest_verify(cd, hdr, data, keyslot_reencrypt); + crypt_free_volume_key(data); + + if (r < 0) { + if (r == -ENOENT) + log_dbg(cd, "Reencryption digest is missing."); + log_err(cd, _("Reencryption metadata is invalid.")); + } else + log_dbg(cd, "Reencryption metadata verified."); + + return r; +} diff -rupN cryptsetup-2.3.3.old/lib/Makemodule.am cryptsetup-2.3.3/lib/Makemodule.am --- cryptsetup-2.3.3.old/lib/Makemodule.am 2022-01-17 15:03:03.687201096 +0100 +++ cryptsetup-2.3.3/lib/Makemodule.am 2022-01-17 15:05:48.164777216 +0100 @@ -104,6 +104,7 @@ libcryptsetup_la_SOURCES = \ lib/luks2/luks2_keyslot_luks2.c \ lib/luks2/luks2_keyslot_reenc.c \ lib/luks2/luks2_reencrypt.c \ + lib/luks2/luks2_reencrypt_digest.c \ lib/luks2/luks2_segment.c \ lib/luks2/luks2_token_keyring.c \ lib/luks2/luks2_token.c \ diff -rupN cryptsetup-2.3.3.old/lib/setup.c cryptsetup-2.3.3/lib/setup.c --- cryptsetup-2.3.3.old/lib/setup.c 2022-01-17 15:03:03.686201093 +0100 +++ cryptsetup-2.3.3/lib/setup.c 2022-01-17 16:00:07.797194917 +0100 @@ -4032,6 +4032,12 @@ static int _open_and_activate_reencrypt_ keyslot = r; } + if (r >= 0) { + r = LUKS2_reencrypt_digest_verify(cd, hdr, vks); + if (r < 0) + goto err; + } + log_dbg(cd, "Entering clean reencryption state mode."); if (r >= 0) @@ -4059,8 +4065,9 @@ static int _open_and_activate_luks2(stru uint32_t flags) { crypt_reencrypt_info ri; - int r; + int r, rv; struct luks2_hdr *hdr = &cd->u.luks2.hdr; + struct volume_key *vks = NULL; ri = LUKS2_reenc_status(hdr); if (ri == CRYPT_REENCRYPT_INVALID) @@ -4070,9 +4077,17 @@ static int _open_and_activate_luks2(stru if (name) r = _open_and_activate_reencrypt_device(cd, hdr, keyslot, name, passphrase, passphrase_size, flags); - else + else { r = _open_all_keys(cd, hdr, keyslot, passphrase, - passphrase_size, flags, NULL); + passphrase_size, flags, &vks); + if (r < 0) + return r; + + rv = LUKS2_reencrypt_digest_verify(cd, hdr, vks); + crypt_free_volume_key(vks); + if (rv < 0) + return rv; + } } else r = _open_and_activate(cd, keyslot, name, passphrase, passphrase_size, flags); diff -rupN cryptsetup-2.3.3.old/po/POTFILES.in cryptsetup-2.3.3/po/POTFILES.in --- cryptsetup-2.3.3.old/po/POTFILES.in 2022-01-17 15:03:03.694201121 +0100 +++ cryptsetup-2.3.3/po/POTFILES.in 2022-01-17 15:05:48.166777223 +0100 @@ -37,6 +37,7 @@ lib/luks2/luks2_keyslot_luks2.c lib/luks2/luks2_keyslot_reenc.c lib/luks2/luks2_luks1_convert.c lib/luks2/luks2_reencrypt.c +lib/luks2/luks2_reencrypt_digest.c lib/luks2/luks2_segment.c lib/luks2/luks2_token.c lib/luks2/luks2_token_keyring.c