Merge branch 'upstream' into tizen
[platform/upstream/cryptsetup.git] / lib / luks2 / luks2_keyslot_reenc.c
1 /*
2  * LUKS - Linux Unified Key Setup v2, reencryption keyslot handler
3  *
4  * Copyright (C) 2016-2023 Red Hat, Inc. All rights reserved.
5  * Copyright (C) 2016-2023 Ondrej Kozina
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21
22 #include "luks2_internal.h"
23
24 static int reenc_keyslot_open(struct crypt_device *cd __attribute__((unused)),
25         int keyslot __attribute__((unused)),
26         const char *password __attribute__((unused)),
27         size_t password_len __attribute__((unused)),
28         char *volume_key __attribute__((unused)),
29         size_t volume_key_len __attribute__((unused)))
30 {
31         return -ENOENT;
32 }
33
34 static json_object *reencrypt_keyslot_area_jobj(struct crypt_device *cd,
35                 const struct crypt_params_reencrypt *params,
36                 size_t alignment,
37                 uint64_t area_offset,
38                 uint64_t area_length)
39 {
40         json_object *jobj_area = json_object_new_object();
41
42         if (!jobj_area || !params || !params->resilience)
43                 return NULL;
44
45         json_object_object_add(jobj_area, "offset", crypt_jobj_new_uint64(area_offset));
46         json_object_object_add(jobj_area, "size", crypt_jobj_new_uint64(area_length));
47         json_object_object_add(jobj_area, "type", json_object_new_string(params->resilience));
48
49         if (!strcmp(params->resilience, "checksum")) {
50                 log_dbg(cd, "Setting reencrypt keyslot for checksum protection.");
51                 json_object_object_add(jobj_area, "hash", json_object_new_string(params->hash));
52                 json_object_object_add(jobj_area, "sector_size", json_object_new_int64(alignment));
53         } else if (!strcmp(params->resilience, "journal")) {
54                 log_dbg(cd, "Setting reencrypt keyslot for journal protection.");
55         } else if (!strcmp(params->resilience, "none")) {
56                 log_dbg(cd, "Setting reencrypt keyslot for none protection.");
57         } else if (!strcmp(params->resilience, "datashift")) {
58                 log_dbg(cd, "Setting reencrypt keyslot for datashift protection.");
59                 json_object_object_add(jobj_area, "shift_size",
60                                        crypt_jobj_new_uint64(params->data_shift << SECTOR_SHIFT));
61         } else if (!strcmp(params->resilience, "datashift-checksum")) {
62                 log_dbg(cd, "Setting reencrypt keyslot for datashift and checksum protection.");
63                 json_object_object_add(jobj_area, "hash", json_object_new_string(params->hash));
64                 json_object_object_add(jobj_area, "sector_size", json_object_new_int64(alignment));
65                 json_object_object_add(jobj_area, "shift_size",
66                                        crypt_jobj_new_uint64(params->data_shift << SECTOR_SHIFT));
67         } else if (!strcmp(params->resilience, "datashift-journal")) {
68                 log_dbg(cd, "Setting reencrypt keyslot for datashift and journal protection.");
69                 json_object_object_add(jobj_area, "shift_size",
70                                        crypt_jobj_new_uint64(params->data_shift << SECTOR_SHIFT));
71         } else {
72                 json_object_put(jobj_area);
73                 return NULL;
74         }
75
76         return jobj_area;
77 }
78
79 static json_object *reencrypt_keyslot_area_jobj_update_block_size(struct crypt_device *cd,
80                 json_object *jobj_area, size_t alignment)
81 {
82         json_object *jobj_type, *jobj_area_new = NULL;
83
84         if (!jobj_area ||
85             !json_object_object_get_ex(jobj_area, "type", &jobj_type) ||
86             (strcmp(json_object_get_string(jobj_type), "checksum") &&
87              strcmp(json_object_get_string(jobj_type), "datashift-checksum")))
88                 return NULL;
89
90         if (json_object_copy(jobj_area, &jobj_area_new))
91                 return NULL;
92
93         log_dbg(cd, "Updating reencrypt resilience checksum block size.");
94
95         json_object_object_add(jobj_area_new, "sector_size", json_object_new_int64(alignment));
96
97         return jobj_area_new;
98 }
99
100 static int reenc_keyslot_alloc(struct crypt_device *cd,
101         struct luks2_hdr *hdr,
102         int keyslot,
103         const struct crypt_params_reencrypt *params,
104         size_t alignment)
105 {
106         int r;
107         json_object *jobj_keyslots, *jobj_keyslot, *jobj_area;
108         uint64_t area_offset, area_length;
109
110         log_dbg(cd, "Allocating reencrypt keyslot %d.", keyslot);
111
112         if (!params || !params->resilience || params->direction > CRYPT_REENCRYPT_BACKWARD)
113                 return -EINVAL;
114
115         if (keyslot < 0 || keyslot >= LUKS2_KEYSLOTS_MAX)
116                 return -ENOMEM;
117
118         if (!json_object_object_get_ex(hdr->jobj, "keyslots", &jobj_keyslots))
119                 return -EINVAL;
120
121         /* only plain datashift resilience mode does not require additional storage */
122         if (!strcmp(params->resilience, "datashift"))
123                 r = LUKS2_find_area_gap(cd, hdr, 1, &area_offset, &area_length);
124         else
125                 r = LUKS2_find_area_max_gap(cd, hdr, &area_offset, &area_length);
126         if (r < 0)
127                 return r;
128
129         jobj_area = reencrypt_keyslot_area_jobj(cd, params, alignment, area_offset, area_length);
130         if (!jobj_area)
131                 return -EINVAL;
132
133         jobj_keyslot = json_object_new_object();
134         if (!jobj_keyslot) {
135                 json_object_put(jobj_area);
136                 return -ENOMEM;
137         }
138         json_object_object_add(jobj_keyslot, "area", jobj_area);
139
140         json_object_object_add(jobj_keyslot, "type", json_object_new_string("reencrypt"));
141         json_object_object_add(jobj_keyslot, "key_size", json_object_new_int(1)); /* useless but mandatory */
142         json_object_object_add(jobj_keyslot, "mode", json_object_new_string(crypt_reencrypt_mode_to_str(params->mode)));
143         if (params->direction == CRYPT_REENCRYPT_FORWARD)
144                 json_object_object_add(jobj_keyslot, "direction", json_object_new_string("forward"));
145         else
146                 json_object_object_add(jobj_keyslot, "direction", json_object_new_string("backward"));
147
148         json_object_object_add_by_uint(jobj_keyslots, keyslot, jobj_keyslot);
149         if (LUKS2_check_json_size(cd, hdr)) {
150                 log_dbg(cd, "New keyslot too large to fit in free metadata space.");
151                 json_object_object_del_by_uint(jobj_keyslots, keyslot);
152                 return -ENOSPC;
153         }
154
155         JSON_DBG(cd, hdr->jobj, "JSON:");
156
157         return 0;
158 }
159
160 static int reenc_keyslot_store_data(struct crypt_device *cd,
161         json_object *jobj_keyslot,
162         const void *buffer, size_t buffer_len)
163 {
164         int devfd, r;
165         json_object *jobj_area, *jobj_offset, *jobj_length;
166         uint64_t area_offset, area_length;
167         struct device *device = crypt_metadata_device(cd);
168
169         if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
170             !json_object_object_get_ex(jobj_area, "offset", &jobj_offset) ||
171             !json_object_object_get_ex(jobj_area, "size", &jobj_length))
172                 return -EINVAL;
173
174         area_offset = crypt_jobj_get_uint64(jobj_offset);
175         area_length = crypt_jobj_get_uint64(jobj_length);
176
177         if (!area_offset || !area_length || ((uint64_t)buffer_len > area_length))
178                 return -EINVAL;
179
180         devfd = device_open_locked(cd, device, O_RDWR);
181         if (devfd >= 0) {
182                 if (write_lseek_blockwise(devfd, device_block_size(cd, device),
183                                           device_alignment(device), CONST_CAST(void *)buffer,
184                                           buffer_len, area_offset) < 0)
185                         r = -EIO;
186                 else
187                         r = 0;
188         } else
189                 r = -EINVAL;
190
191         if (r)
192                 log_err(cd, _("IO error while encrypting keyslot."));
193
194         return r;
195 }
196
197 static int reenc_keyslot_store(struct crypt_device *cd,
198         int keyslot,
199         const char *password __attribute__((unused)),
200         size_t password_len __attribute__((unused)),
201         const char *buffer,
202         size_t buffer_len)
203 {
204         struct luks2_hdr *hdr;
205         json_object *jobj_keyslot;
206         int r = 0;
207
208         if (!cd || !buffer || !buffer_len)
209                 return -EINVAL;
210
211         if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
212                 return -EINVAL;
213
214         log_dbg(cd, "Reencrypt keyslot %d store.", keyslot);
215
216         jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
217         if (!jobj_keyslot)
218                 return -EINVAL;
219
220         r = LUKS2_device_write_lock(cd, hdr, crypt_metadata_device(cd));
221         if (r)
222                 return r;
223
224         r = reenc_keyslot_store_data(cd, jobj_keyslot, buffer, buffer_len);
225         if (r < 0) {
226                 device_write_unlock(cd, crypt_metadata_device(cd));
227                 return r;
228         }
229
230         r = LUKS2_hdr_write(cd, hdr);
231
232         device_write_unlock(cd, crypt_metadata_device(cd));
233
234         return r < 0 ? r : keyslot;
235 }
236
237 static int reenc_keyslot_wipe(struct crypt_device *cd,
238         int keyslot)
239 {
240         struct luks2_hdr *hdr;
241
242         if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
243                 return -EINVAL;
244
245         /* remove reencryption verification data */
246         LUKS2_digest_assign(cd, hdr, keyslot, CRYPT_ANY_DIGEST, 0, 0);
247
248         return 0;
249 }
250
251 static int reenc_keyslot_dump(struct crypt_device *cd, int keyslot)
252 {
253         json_object *jobj_keyslot, *jobj_area, *jobj_direction, *jobj_mode, *jobj_resilience,
254                     *jobj1;
255
256         jobj_keyslot = LUKS2_get_keyslot_jobj(crypt_get_hdr(cd, CRYPT_LUKS2), keyslot);
257         if (!jobj_keyslot)
258                 return -EINVAL;
259
260         if (!json_object_object_get_ex(jobj_keyslot, "direction", &jobj_direction) ||
261             !json_object_object_get_ex(jobj_keyslot, "mode", &jobj_mode) ||
262             !json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
263             !json_object_object_get_ex(jobj_area, "type", &jobj_resilience))
264                 return -EINVAL;
265
266         log_std(cd, "\t%-12s%s\n", "Mode:", json_object_get_string(jobj_mode));
267         log_std(cd, "\t%-12s%s\n", "Direction:", json_object_get_string(jobj_direction));
268         log_std(cd, "\t%-12s%s\n", "Resilience:", json_object_get_string(jobj_resilience));
269
270         if (!strcmp(json_object_get_string(jobj_resilience), "checksum")) {
271                 json_object_object_get_ex(jobj_area, "hash", &jobj1);
272                 log_std(cd, "\t%-12s%s\n", "Hash:", json_object_get_string(jobj1));
273                 json_object_object_get_ex(jobj_area, "sector_size", &jobj1);
274                 log_std(cd, "\t%-12s%d [bytes]\n", "Hash data:", json_object_get_int(jobj1));
275         } else if (!strcmp(json_object_get_string(jobj_resilience), "datashift")) {
276                 json_object_object_get_ex(jobj_area, "shift_size", &jobj1);
277                 log_std(cd, "\t%-12s%" PRIu64 "[bytes]\n", "Shift size:", crypt_jobj_get_uint64(jobj1));
278         }
279
280         json_object_object_get_ex(jobj_area, "offset", &jobj1);
281         log_std(cd, "\tArea offset:%" PRIu64 " [bytes]\n", crypt_jobj_get_uint64(jobj1));
282
283         json_object_object_get_ex(jobj_area, "size", &jobj1);
284         log_std(cd, "\tArea length:%" PRIu64 " [bytes]\n", crypt_jobj_get_uint64(jobj1));
285
286         return 0;
287 }
288
289 static int reenc_keyslot_validate(struct crypt_device *cd, json_object *jobj_keyslot)
290 {
291         json_object *jobj_mode, *jobj_area, *jobj_type, *jobj_shift_size, *jobj_hash,
292                     *jobj_sector_size, *jobj_direction, *jobj_key_size;
293         const char *mode, *type, *direction;
294         uint32_t sector_size;
295         uint64_t shift_size;
296
297         /* mode (string: encrypt,reencrypt,decrypt)
298          * direction (string:)
299          * area {
300          *   type: (string: datashift, journal, checksum, none, datashift-journal, datashift-checksum)
301          *      hash: (string: checksum and datashift-checksum types)
302          *      sector_size (uint32:  checksum and datashift-checksum types)
303          *      shift_size (uint64: all datashift based types)
304          * }
305          */
306
307         /* area and area type are validated in general validation code */
308         if (!jobj_keyslot || !json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
309             !json_object_object_get_ex(jobj_area, "type", &jobj_type))
310                 return -EINVAL;
311
312         jobj_key_size = json_contains(cd, jobj_keyslot, "", "reencrypt keyslot", "key_size", json_type_int);
313         jobj_mode = json_contains_string(cd, jobj_keyslot, "", "reencrypt keyslot", "mode");
314         jobj_direction = json_contains_string(cd, jobj_keyslot, "", "reencrypt keyslot", "direction");
315
316         if (!jobj_mode || !jobj_direction || !jobj_key_size)
317                 return -EINVAL;
318
319         if (!validate_json_uint32(jobj_key_size) || crypt_jobj_get_uint32(jobj_key_size) != 1) {
320                 log_dbg(cd, "Illegal reencrypt key size.");
321                 return -EINVAL;
322         }
323
324         mode = json_object_get_string(jobj_mode);
325         type = json_object_get_string(jobj_type);
326         direction = json_object_get_string(jobj_direction);
327
328         if (strcmp(mode, "reencrypt") && strcmp(mode, "encrypt") &&
329             strcmp(mode, "decrypt")) {
330                 log_dbg(cd, "Illegal reencrypt mode %s.", mode);
331                 return -EINVAL;
332         }
333
334         if (strcmp(direction, "forward") && strcmp(direction, "backward")) {
335                 log_dbg(cd, "Illegal reencrypt direction %s.", direction);
336                 return -EINVAL;
337         }
338
339         if (!strcmp(type, "checksum") || !strcmp(type, "datashift-checksum")) {
340                 jobj_hash = json_contains_string(cd, jobj_area, "type:checksum",
341                                           "Keyslot area", "hash");
342                 jobj_sector_size = json_contains(cd, jobj_area, "type:checksum",
343                                                  "Keyslot area", "sector_size", json_type_int);
344                 if (!jobj_hash || !jobj_sector_size)
345                         return -EINVAL;
346                 if (!validate_json_uint32(jobj_sector_size))
347                         return -EINVAL;
348                 sector_size = crypt_jobj_get_uint32(jobj_sector_size);
349                 if (sector_size < SECTOR_SIZE || NOTPOW2(sector_size)) {
350                         log_dbg(cd, "Invalid sector_size (%" PRIu32 ") for checksum resilience mode.",
351                                 sector_size);
352                         return -EINVAL;
353                 }
354         } else if (!strcmp(type, "datashift") ||
355                    !strcmp(type, "datashift-checksum") ||
356                    !strcmp(type, "datashift-journal")) {
357                 if (!(jobj_shift_size = json_contains_string(cd, jobj_area, "type:datashift",
358                                                       "Keyslot area", "shift_size")))
359                         return -EINVAL;
360
361                 shift_size = crypt_jobj_get_uint64(jobj_shift_size);
362                 if (!shift_size)
363                         return -EINVAL;
364
365                 if (MISALIGNED_512(shift_size)) {
366                         log_dbg(cd, "Shift size field has to be aligned to 512 bytes.");
367                         return -EINVAL;
368                 }
369         }
370
371         return 0;
372 }
373
374 static int reenc_keyslot_update_needed(struct crypt_device *cd,
375         json_object *jobj_keyslot,
376         const struct crypt_params_reencrypt *params,
377         size_t alignment)
378 {
379         const char *type;
380         json_object *jobj_area, *jobj_type, *jobj;
381
382         if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
383             !json_object_object_get_ex(jobj_area, "type", &jobj_type) ||
384             !(type = json_object_get_string(jobj_type)))
385                 return -EINVAL;
386
387         /*
388          * If no resilience mode change is requested and effective
389          * resilience mode is 'checksum' then check alignment matches
390          * stored checksum block size.
391          */
392         if (!params || !params->resilience) {
393                 if (!strcmp(json_object_get_string(jobj_type), "checksum") ||
394                     !strcmp(json_object_get_string(jobj_type), "datashift-checksum"))
395                         return (json_object_object_get_ex(jobj_area, "sector_size", &jobj) ||
396                                 alignment != crypt_jobj_get_uint32(jobj));
397                 return 0;
398         }
399
400         if (strcmp(params->resilience, type))
401                 return 1;
402
403         if (!strcmp(type, "checksum") ||
404             !strcmp(type, "datashift-checksum")) {
405                 if (!params->hash)
406                         return -EINVAL;
407                 if (!json_object_object_get_ex(jobj_area, "hash", &jobj) ||
408                         strcmp(json_object_get_string(jobj), params->hash) ||
409                         !json_object_object_get_ex(jobj_area, "sector_size", &jobj) ||
410                         crypt_jobj_get_uint32(jobj) != alignment)
411                         return 1;
412         }
413
414         if (!strncmp(type, "datashift", 9)) {
415                 if (!json_object_object_get_ex(jobj_area, "shift_size", &jobj))
416                         return -EINVAL;
417                 if ((params->data_shift << SECTOR_SHIFT) != crypt_jobj_get_uint64(jobj))
418                         return 1;
419         }
420
421         /* nothing to compare with 'none' and 'journal' */
422         return 0;
423 }
424
425 static int load_checksum_protection(struct crypt_device *cd,
426         json_object *jobj_area,
427         uint64_t area_length,
428         struct reenc_protection *rp)
429 {
430         int r;
431         json_object *jobj_hash, *jobj_block_size;
432
433         if (!jobj_area || !rp ||
434             !json_object_object_get_ex(jobj_area, "hash", &jobj_hash) ||
435             !json_object_object_get_ex(jobj_area, "sector_size", &jobj_block_size))
436                 return -EINVAL;
437
438         r = snprintf(rp->p.csum.hash, sizeof(rp->p.csum.hash), "%s", json_object_get_string(jobj_hash));
439         if (r < 0 || (size_t)r >= sizeof(rp->p.csum.hash))
440                 return -EINVAL;
441
442         if (crypt_hash_init(&rp->p.csum.ch, rp->p.csum.hash)) {
443                 log_err(cd, _("Hash algorithm %s is not available."), rp->p.csum.hash);
444                 return -EINVAL;
445         }
446
447         r = crypt_hash_size(rp->p.csum.hash);
448         if (r <= 0) {
449                 crypt_hash_destroy(rp->p.csum.ch);
450                 rp->p.csum.ch = NULL;
451                 log_dbg(cd, "Invalid hash size");
452                 return -EINVAL;
453         }
454
455         rp->p.csum.hash_size = r;
456         rp->p.csum.block_size = crypt_jobj_get_uint32(jobj_block_size);
457         rp->p.csum.checksums_len = area_length;
458
459         rp->type = REENC_PROTECTION_CHECKSUM;
460         return 0;
461 }
462
463 static int reenc_keyslot_load_resilience_primary(struct crypt_device *cd,
464         const char *type,
465         json_object *jobj_area,
466         uint64_t area_length,
467         struct reenc_protection *rp)
468 {
469         json_object *jobj;
470
471         if (!strcmp(type, "checksum")) {
472                 log_dbg(cd, "Initializing checksum resilience mode.");
473                 return load_checksum_protection(cd, jobj_area, area_length, rp);
474         } else if (!strcmp(type, "journal")) {
475                 log_dbg(cd, "Initializing journal resilience mode.");
476                 rp->type = REENC_PROTECTION_JOURNAL;
477         } else if (!strcmp(type, "none")) {
478                 log_dbg(cd, "Initializing none resilience mode.");
479                 rp->type = REENC_PROTECTION_NONE;
480         } else if (!strcmp(type, "datashift") ||
481                    !strcmp(type, "datashift-checksum") ||
482                    !strcmp(type, "datashift-journal")) {
483                 log_dbg(cd, "Initializing datashift resilience mode.");
484                 if (!json_object_object_get_ex(jobj_area, "shift_size", &jobj))
485                         return -EINVAL;
486                 rp->type = REENC_PROTECTION_DATASHIFT;
487                 rp->p.ds.data_shift = crypt_jobj_get_uint64(jobj);
488         } else
489                 return -EINVAL;
490
491         return 0;
492 }
493
494 static int reenc_keyslot_load_resilience_secondary(struct crypt_device *cd,
495         const char *type,
496         json_object *jobj_area,
497         uint64_t area_length,
498         struct reenc_protection *rp)
499 {
500         if (!strcmp(type, "datashift-checksum")) {
501                 log_dbg(cd, "Initializing checksum resilience mode.");
502                 return load_checksum_protection(cd, jobj_area, area_length, rp);
503         } else if (!strcmp(type, "datashift-journal")) {
504                 log_dbg(cd, "Initializing journal resilience mode.");
505                 rp->type = REENC_PROTECTION_JOURNAL;
506         } else
507                 rp->type = REENC_PROTECTION_NOT_SET;
508
509         return 0;
510 }
511
512 static int reenc_keyslot_load_resilience(struct crypt_device *cd,
513         json_object *jobj_keyslot,
514         struct reenc_protection *rp,
515         bool primary)
516 {
517         const char *type;
518         int r;
519         json_object *jobj_area, *jobj_type;
520         uint64_t dummy, area_length;
521
522         if (!rp || !json_object_object_get_ex(jobj_keyslot, "area", &jobj_area) ||
523             !json_object_object_get_ex(jobj_area, "type", &jobj_type))
524                 return -EINVAL;
525
526         r = LUKS2_keyslot_jobj_area(jobj_keyslot, &dummy, &area_length);
527         if (r < 0)
528                 return r;
529
530         type = json_object_get_string(jobj_type);
531         if (!type)
532                 return -EINVAL;
533
534         if (primary)
535                 return reenc_keyslot_load_resilience_primary(cd, type, jobj_area, area_length, rp);
536         else
537                 return reenc_keyslot_load_resilience_secondary(cd, type, jobj_area, area_length, rp);
538 }
539
540 static bool reenc_keyslot_update_is_valid(struct crypt_device *cd,
541         json_object *jobj_area,
542         const struct crypt_params_reencrypt *params)
543 {
544         const char *type;
545         json_object *jobj_type, *jobj;
546
547         if (!json_object_object_get_ex(jobj_area, "type", &jobj_type) ||
548             !(type = json_object_get_string(jobj_type)))
549                 return false;
550
551         /* do not allow switch to/away from datashift resilience type */
552         if ((strcmp(params->resilience, "datashift") && !strcmp(type, "datashift")) ||
553             (!strcmp(params->resilience, "datashift") && strcmp(type, "datashift")))
554                 return false;
555
556         /* do not allow switch to/away from datashift- resilience subvariants */
557         if ((strncmp(params->resilience, "datashift-", 10) &&
558              !strncmp(type, "datashift-", 10)) ||
559             (!strncmp(params->resilience, "datashift-", 10) &&
560              strncmp(type, "datashift-", 10)))
561                 return false;
562
563         /* datashift value is also immutable */
564         if (!strncmp(type, "datashift", 9)) {
565                 if (!json_object_object_get_ex(jobj_area, "shift_size", &jobj))
566                         return false;
567                 return (params->data_shift << SECTOR_SHIFT) == crypt_jobj_get_uint64(jobj);
568         }
569
570         return true;
571 }
572
573 static int reenc_keyslot_update(struct crypt_device *cd,
574         json_object *jobj_keyslot,
575         const struct crypt_params_reencrypt *params,
576         size_t alignment)
577 {
578         int r;
579         json_object *jobj_area, *jobj_area_new;
580         uint64_t area_offset, area_length;
581
582         if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
583                 return -EINVAL;
584
585         r = LUKS2_keyslot_jobj_area(jobj_keyslot, &area_offset, &area_length);
586         if (r < 0)
587                 return r;
588
589         if (!params || !params->resilience)
590                 jobj_area_new = reencrypt_keyslot_area_jobj_update_block_size(cd, jobj_area, alignment);
591         else {
592                 if (!reenc_keyslot_update_is_valid(cd, jobj_area, params)) {
593                         log_err(cd, _("Invalid reencryption resilience mode change requested."));
594                         return -EINVAL;
595                 }
596
597                 jobj_area_new = reencrypt_keyslot_area_jobj(cd, params, alignment,
598                                                             area_offset, area_length);
599         }
600
601         if (!jobj_area_new)
602                 return -EINVAL;
603
604         /* increase refcount for validation purposes */
605         json_object_get(jobj_area);
606
607         json_object_object_add(jobj_keyslot, "area", jobj_area_new);
608
609         r = reenc_keyslot_validate(cd, jobj_keyslot);
610         if (r) {
611                 /* replace invalid object with previous valid one */
612                 json_object_object_add(jobj_keyslot, "area", jobj_area);
613                 return -EINVAL;
614         }
615
616         /* previous area object is no longer needed */
617         json_object_put(jobj_area);
618
619         return 0;
620 }
621
622 int LUKS2_keyslot_reencrypt_allocate(struct crypt_device *cd,
623         struct luks2_hdr *hdr,
624         int keyslot,
625         const struct crypt_params_reencrypt *params,
626         size_t alignment)
627 {
628         int r;
629
630         if (keyslot == CRYPT_ANY_SLOT)
631                 return -EINVAL;
632
633         r = reenc_keyslot_alloc(cd, hdr, keyslot, params, alignment);
634         if (r < 0)
635                 return r;
636
637         r = LUKS2_keyslot_priority_set(cd, hdr, keyslot, CRYPT_SLOT_PRIORITY_IGNORE, 0);
638         if (r < 0)
639                 return r;
640
641         r = reenc_keyslot_validate(cd, LUKS2_get_keyslot_jobj(hdr, keyslot));
642         if (r) {
643                 log_dbg(cd, "Keyslot validation failed.");
644                 return r;
645         }
646
647         return 0;
648 }
649
650 int LUKS2_keyslot_reencrypt_update_needed(struct crypt_device *cd,
651         struct luks2_hdr *hdr,
652         int keyslot,
653         const struct crypt_params_reencrypt *params,
654         size_t alignment)
655 {
656         int r;
657         json_object *jobj_type, *jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
658
659         if (!jobj_keyslot ||
660             !json_object_object_get_ex(jobj_keyslot, "type", &jobj_type) ||
661             strcmp(json_object_get_string(jobj_type), "reencrypt"))
662                 return -EINVAL;
663
664         r = reenc_keyslot_update_needed(cd, jobj_keyslot, params, alignment);
665         if (!r)
666                 log_dbg(cd, "No update of reencrypt keyslot needed.");
667
668         return r;
669 }
670
671 int LUKS2_keyslot_reencrypt_update(struct crypt_device *cd,
672         struct luks2_hdr *hdr,
673         int keyslot,
674         const struct crypt_params_reencrypt *params,
675         size_t alignment,
676         struct volume_key *vks)
677 {
678         int r;
679         uint8_t version;
680         uint64_t max_size, moved_segment_size;
681         json_object *jobj_type, *jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
682         struct reenc_protection check_rp = {};
683
684         if (!jobj_keyslot ||
685             !json_object_object_get_ex(jobj_keyslot, "type", &jobj_type) ||
686             strcmp(json_object_get_string(jobj_type), "reencrypt"))
687                 return -EINVAL;
688
689         if (LUKS2_config_get_reencrypt_version(hdr, &version))
690                 return -EINVAL;
691
692         /* verify existing reencryption metadata before updating */
693         r = LUKS2_reencrypt_digest_verify(cd, hdr, vks);
694         if (r < 0)
695                 return r;
696
697         r = reenc_keyslot_update(cd, jobj_keyslot, params, alignment);
698         if (r < 0)
699                 return r;
700
701         r = reenc_keyslot_load_resilience(cd, jobj_keyslot, &check_rp, false);
702         if (r < 0)
703                 return r;
704
705         if (check_rp.type != REENC_PROTECTION_NOT_SET) {
706                 r = LUKS2_reencrypt_max_hotzone_size(cd, hdr, &check_rp, keyslot, &max_size);
707                 LUKS2_reencrypt_protection_erase(&check_rp);
708                 if (r < 0)
709                         return r;
710                 moved_segment_size = json_segment_get_size(LUKS2_get_segment_by_flag(hdr, "backup-moved-segment"), 0);
711                 if (!moved_segment_size)
712                         return -EINVAL;
713                 if (moved_segment_size > max_size) {
714                         log_err(cd, _("Can not update resilience type. "
715                                       "New type only provides %" PRIu64 " bytes, "
716                                       "required space is: %" PRIu64 " bytes."),
717                                 max_size, moved_segment_size);
718                         return -EINVAL;
719                 }
720         }
721
722         r = LUKS2_keyslot_reencrypt_digest_create(cd, hdr, version, vks);
723         if (r < 0)
724                 log_err(cd, _("Failed to refresh reencryption verification digest."));
725
726         return r ?: LUKS2_hdr_write(cd, hdr);
727 }
728
729 int LUKS2_keyslot_reencrypt_load(struct crypt_device *cd,
730         struct luks2_hdr *hdr,
731         int keyslot,
732         struct reenc_protection *rp,
733         bool primary)
734 {
735         json_object *jobj_type, *jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot);
736
737         if (!jobj_keyslot ||
738             !json_object_object_get_ex(jobj_keyslot, "type", &jobj_type) ||
739             strcmp(json_object_get_string(jobj_type), "reencrypt"))
740                 return -EINVAL;
741
742         return reenc_keyslot_load_resilience(cd, jobj_keyslot, rp, primary);
743 }
744
745 const keyslot_handler reenc_keyslot = {
746         .name  = "reencrypt",
747         .open  = reenc_keyslot_open,
748         .store = reenc_keyslot_store, /* initialization only or also per every chunk write */
749         .wipe  = reenc_keyslot_wipe,
750         .dump  = reenc_keyslot_dump,
751         .validate  = reenc_keyslot_validate
752 };