Blame SOURCES/cryptsetup-2.3.7-Fix-CVE-2021-4122-LUKS2-reencryption-crash-recovery-.patch

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