Coverage Report

Created: 2026-03-10 06:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cryptsetup/lib/luks2/luks2_reencrypt_digest.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 * LUKS - Linux Unified Key Setup v2, reencryption digest helpers
4
 *
5
 * Copyright (C) 2022-2025 Red Hat, Inc. All rights reserved.
6
 * Copyright (C) 2022-2025 Ondrej Kozina
7
 * Copyright (C) 2022-2025 Milan Broz
8
 */
9
10
#include "luks2_internal.h"
11
12
0
#define MAX_STR 64
13
14
struct jtype {
15
  enum { JNONE = 0, JSTR, JU64, JX64, JU32 } type;
16
  json_object *jobj;
17
  const char *id;
18
};
19
20
static size_t sr(struct jtype *j, uint8_t *ptr)
21
0
{
22
0
  json_object *jobj;
23
0
  size_t len = 0;
24
0
  uint64_t u64;
25
0
  uint32_t u32;
26
27
0
  if (!json_object_is_type(j->jobj, json_type_object))
28
0
    return 0;
29
30
0
  if (!json_object_object_get_ex(j->jobj, j->id, &jobj))
31
0
    return 0;
32
33
0
  switch(j->type) {
34
0
  case JSTR: /* JSON string */
35
0
    if (!json_object_is_type(jobj, json_type_string))
36
0
      return 0;
37
0
    len = strlen(json_object_get_string(jobj));
38
0
    if (len > MAX_STR)
39
0
      return 0;
40
0
    if (ptr)
41
0
      memcpy(ptr, json_object_get_string(jobj), len);
42
0
    break;
43
0
  case JU64: /* Unsigned 64bit integer stored as string */
44
0
    if (!json_object_is_type(jobj, json_type_string))
45
0
      break;
46
0
    len = sizeof(u64);
47
0
    if (ptr) {
48
0
      u64 = cpu_to_be64(crypt_jobj_get_uint64(jobj));
49
0
      memcpy(ptr, &u64, len);
50
0
    }
51
0
    break;
52
0
  case JX64: /* Unsigned 64bit segment size (allows "dynamic") */
53
0
    if (!json_object_is_type(jobj, json_type_string))
54
0
      break;
55
0
    if (!strcmp(json_object_get_string(jobj), "dynamic")) {
56
0
      len = strlen("dynamic");
57
0
      if (ptr)
58
0
        memcpy(ptr, json_object_get_string(jobj), len);
59
0
    } else {
60
0
      len = sizeof(u64);
61
0
      u64 = cpu_to_be64(crypt_jobj_get_uint64(jobj));
62
0
      if (ptr)
63
0
        memcpy(ptr, &u64, len);
64
0
    }
65
0
    break;
66
0
  case JU32: /* Unsigned 32bit integer, stored as JSON int */
67
0
    if (!json_object_is_type(jobj, json_type_int))
68
0
      return 0;
69
0
    len =  sizeof(u32);
70
0
    if (ptr) {
71
0
      u32 = cpu_to_be32(crypt_jobj_get_uint32(jobj));
72
0
      memcpy(ptr, &u32, len);
73
0
    }
74
0
    break;
75
0
  case JNONE:
76
0
    return 0;
77
0
  };
78
79
0
  return len;
80
0
}
81
82
static size_t srs(struct jtype j[], uint8_t *ptr)
83
0
{
84
0
  size_t l, len = 0;
85
86
0
  while(j->jobj) {
87
0
    l = sr(j, ptr);
88
0
    if (!l)
89
0
      return 0;
90
0
    len += l;
91
0
    if (ptr)
92
0
      ptr += l;
93
0
    j++;
94
0
  }
95
0
  return len;
96
0
}
97
98
static size_t segment_linear_serialize(json_object *jobj_segment, uint8_t *buffer)
99
0
{
100
0
  struct jtype j[] = {
101
0
    { JSTR, jobj_segment, "type" },
102
0
    { JU64, jobj_segment, "offset" },
103
0
    { JX64, jobj_segment, "size" },
104
0
    {}
105
0
  };
106
0
  return srs(j, buffer);
107
0
}
108
109
static size_t segment_crypt_serialize(json_object *jobj_segment, uint8_t *buffer)
110
0
{
111
0
  struct jtype j[] = {
112
0
    { JSTR, jobj_segment, "type" },
113
0
    { JU64, jobj_segment, "offset" },
114
0
    { JX64, jobj_segment, "size" },
115
0
    { JU64, jobj_segment, "iv_tweak" },
116
0
    { JSTR, jobj_segment, "encryption" },
117
0
    { JU32, jobj_segment, "sector_size" },
118
0
    {}
119
0
  };
120
0
  return srs(j, buffer);
121
0
}
122
123
static size_t segment_serialize(json_object *jobj_segment, uint8_t *buffer)
124
0
{
125
0
  json_object *jobj_type;
126
0
  const char *segment_type;
127
128
0
  if (!json_object_object_get_ex(jobj_segment, "type", &jobj_type))
129
0
    return 0;
130
131
0
  if (!(segment_type = json_object_get_string(jobj_type)))
132
0
    return 0;
133
134
0
  if (!strcmp(segment_type, "crypt"))
135
0
    return segment_crypt_serialize(jobj_segment, buffer);
136
0
  else if (!strcmp(segment_type, "linear"))
137
0
    return segment_linear_serialize(jobj_segment, buffer);
138
139
0
  return 0;
140
0
}
141
142
static size_t backup_segments_serialize(struct luks2_hdr *hdr, uint8_t *buffer)
143
0
{
144
0
  json_object *jobj_segment;
145
0
  size_t l, len = 0;
146
147
0
  jobj_segment = LUKS2_get_segment_by_flag(hdr, "backup-previous");
148
0
  if (!jobj_segment || !(l = segment_serialize(jobj_segment, buffer)))
149
0
    return 0;
150
0
  len += l;
151
0
  if (buffer)
152
0
    buffer += l;
153
154
0
  jobj_segment = LUKS2_get_segment_by_flag(hdr, "backup-final");
155
0
  if (!jobj_segment || !(l = segment_serialize(jobj_segment, buffer)))
156
0
    return 0;
157
0
  len += l;
158
0
  if (buffer)
159
0
    buffer += l;
160
161
0
  jobj_segment = LUKS2_get_segment_by_flag(hdr, "backup-moved-segment");
162
0
  if (jobj_segment) {
163
0
    if (!(l = segment_serialize(jobj_segment, buffer)))
164
0
      return 0;
165
0
    len += l;
166
0
  }
167
168
0
  return len;
169
0
}
170
171
static size_t reenc_keyslot_serialize(struct luks2_hdr *hdr, uint8_t *buffer)
172
0
{
173
0
  json_object *jobj_keyslot, *jobj_area, *jobj_type;
174
0
  const char *area_type;
175
0
  int keyslot_reencrypt;
176
177
0
  keyslot_reencrypt = LUKS2_find_keyslot(hdr, "reencrypt");
178
0
  if (keyslot_reencrypt < 0)
179
0
    return 0;
180
181
0
  if (!(jobj_keyslot = LUKS2_get_keyslot_jobj(hdr, keyslot_reencrypt)))
182
0
    return 0;
183
184
0
  if (!json_object_object_get_ex(jobj_keyslot, "area", &jobj_area))
185
0
    return 0;
186
187
0
  if (!json_object_object_get_ex(jobj_area, "type", &jobj_type))
188
0
    return 0;
189
190
0
  if (!(area_type = json_object_get_string(jobj_type)))
191
0
    return 0;
192
193
0
  struct jtype j[] = {
194
0
    { JSTR, jobj_keyslot, "mode" },
195
0
    { JSTR, jobj_keyslot, "direction" },
196
0
    { JSTR, jobj_area,    "type" },
197
0
    { JU64, jobj_area,    "offset" },
198
0
    { JU64, jobj_area,    "size" },
199
0
    {}
200
0
  };
201
0
  struct jtype j_datashift[] = {
202
0
    { JSTR, jobj_keyslot, "mode" },
203
0
    { JSTR, jobj_keyslot, "direction" },
204
0
    { JSTR, jobj_area,    "type" },
205
0
    { JU64, jobj_area,    "offset" },
206
0
    { JU64, jobj_area,    "size" },
207
0
    { JU64, jobj_area,    "shift_size" },
208
0
    {}
209
0
  };
210
0
  struct jtype j_checksum[] = {
211
0
    { JSTR, jobj_keyslot, "mode" },
212
0
    { JSTR, jobj_keyslot, "direction" },
213
0
    { JSTR, jobj_area,    "type" },
214
0
    { JU64, jobj_area,    "offset" },
215
0
    { JU64, jobj_area,    "size" },
216
0
    { JSTR, jobj_area,    "hash" },
217
0
    { JU32, jobj_area,    "sector_size" },
218
0
    {}
219
0
  };
220
0
  struct jtype j_datashift_checksum[] = {
221
0
    { JSTR, jobj_keyslot, "mode" },
222
0
    { JSTR, jobj_keyslot, "direction" },
223
0
    { JSTR, jobj_area,    "type" },
224
0
    { JU64, jobj_area,    "offset" },
225
0
    { JU64, jobj_area,    "size" },
226
0
    { JSTR, jobj_area,    "hash" },
227
0
    { JU32, jobj_area,    "sector_size" },
228
0
    { JU64, jobj_area,    "shift_size" },
229
0
    {}
230
0
  };
231
232
0
  if (!strcmp(area_type, "datashift-checksum"))
233
0
    return srs(j_datashift_checksum, buffer);
234
0
  else if (!strcmp(area_type, "datashift") ||
235
0
     !strcmp(area_type, "datashift-journal"))
236
0
    return srs(j_datashift, buffer);
237
0
  else if (!strcmp(area_type, "checksum"))
238
0
    return srs(j_checksum, buffer);
239
240
0
  return srs(j, buffer);
241
0
}
242
243
static size_t blob_serialize(const void *blob, size_t length, uint8_t *buffer)
244
0
{
245
0
  if (buffer)
246
0
    crypt_safe_memcpy(buffer, blob, length);
247
248
0
  return length;
249
0
}
250
251
static int reencrypt_assembly_verification_data(struct crypt_device *cd,
252
  struct luks2_hdr *hdr,
253
  struct volume_key *vks,
254
  uint8_t version,
255
  struct volume_key **r_verification_data)
256
0
{
257
0
  uint8_t *ptr;
258
0
  int digest_new, digest_old, r = -EINVAL;
259
0
  struct volume_key *verification_data = NULL, *vk_old = NULL, *vk_new = NULL;
260
0
  size_t keyslot_data_len, segments_data_len, data_len = 2;
261
0
  void *data = NULL;
262
263
  /*
264
   * This works up to (including) version v207.
265
   */
266
0
  assert(version < (UINT8_MAX - 0x2F));
267
268
  /* Keys - calculate length */
269
0
  digest_new = LUKS2_reencrypt_digest_new(hdr);
270
0
  digest_old = LUKS2_reencrypt_digest_old(hdr);
271
272
0
  if (digest_old >= 0) {
273
0
    vk_old = crypt_volume_key_by_id(vks, digest_old);
274
0
    if (!vk_old) {
275
0
      log_dbg(cd, "Key (digest id %d) required but not unlocked.", digest_old);
276
0
      return -EINVAL;
277
0
    }
278
0
    data_len += blob_serialize(crypt_volume_key_get_key(vk_old), crypt_volume_key_length(vk_old), NULL);
279
0
  }
280
281
0
  if (digest_new >= 0 && digest_old != digest_new) {
282
0
    vk_new = crypt_volume_key_by_id(vks, digest_new);
283
0
    if (!vk_new) {
284
0
      log_dbg(cd, "Key (digest id %d) required but not unlocked.", digest_new);
285
0
      return -EINVAL;
286
0
    }
287
0
    data_len += blob_serialize(crypt_volume_key_get_key(vk_new), crypt_volume_key_length(vk_new), NULL);
288
0
  }
289
290
0
  if (data_len == 2)
291
0
    return -EINVAL;
292
293
  /* Metadata - calculate length */
294
0
  if (!(keyslot_data_len = reenc_keyslot_serialize(hdr, NULL)))
295
0
    return -EINVAL;
296
0
  data_len += keyslot_data_len;
297
298
0
  if (!(segments_data_len = backup_segments_serialize(hdr, NULL)))
299
0
    return -EINVAL;
300
0
  data_len += segments_data_len;
301
302
  /* Alloc and fill serialization data */
303
0
  data = crypt_safe_alloc(data_len);
304
0
  if (!data)
305
0
    return -ENOMEM;
306
307
0
  ptr = (uint8_t*)data;
308
309
0
  *ptr++ = 0x76;
310
0
  *ptr++ = 0x30 + version;
311
312
0
  if (vk_old)
313
0
    ptr += blob_serialize(crypt_volume_key_get_key(vk_old),
314
0
              crypt_volume_key_length(vk_old), ptr);
315
316
0
  if (vk_new)
317
0
    ptr += blob_serialize(crypt_volume_key_get_key(vk_new),
318
0
              crypt_volume_key_length(vk_new), ptr);
319
320
0
  if (!reenc_keyslot_serialize(hdr, ptr))
321
0
    goto bad;
322
0
  ptr += keyslot_data_len;
323
324
0
  if (!backup_segments_serialize(hdr, ptr))
325
0
    goto bad;
326
0
  ptr += segments_data_len;
327
328
0
  assert((size_t)(ptr - (uint8_t*)data) == data_len);
329
330
0
  verification_data = crypt_alloc_volume_key_by_safe_alloc(&data);
331
0
  if (!verification_data) {
332
0
    r = -ENOMEM;
333
0
    goto bad;
334
0
  }
335
0
  *r_verification_data = verification_data;
336
337
0
  return 0;
338
0
bad:
339
0
  crypt_safe_free(data);
340
0
  crypt_free_volume_key(verification_data);
341
0
  return r;
342
0
}
343
344
int LUKS2_keyslot_reencrypt_digest_create(struct crypt_device *cd,
345
  struct luks2_hdr *hdr,
346
  uint8_t version,
347
  struct volume_key *vks)
348
0
{
349
0
  int digest_reencrypt, keyslot_reencrypt, r;
350
0
  struct volume_key *data;
351
352
0
  keyslot_reencrypt = LUKS2_find_keyslot(hdr, "reencrypt");
353
0
  if (keyslot_reencrypt < 0)
354
0
    return keyslot_reencrypt;
355
356
0
  r = reencrypt_assembly_verification_data(cd, hdr, vks, version, &data);
357
0
  if (r < 0)
358
0
    return r;
359
360
0
  r = LUKS2_digest_create(cd, "pbkdf2", hdr, data);
361
0
  crypt_free_volume_key(data);
362
0
  if (r < 0)
363
0
    return r;
364
365
0
  digest_reencrypt = r;
366
367
0
  r = LUKS2_digest_assign(cd, hdr, keyslot_reencrypt, CRYPT_ANY_DIGEST, 0, 0);
368
0
  if (r < 0)
369
0
    return r;
370
371
0
  return LUKS2_digest_assign(cd, hdr, keyslot_reencrypt, digest_reencrypt, 1, 0);
372
0
}
373
374
int LUKS2_reencrypt_digest_verify(struct crypt_device *cd,
375
  struct luks2_hdr *hdr,
376
  struct volume_key *vks)
377
0
{
378
0
  int r, keyslot_reencrypt;
379
0
  struct volume_key *data;
380
0
  uint8_t version;
381
382
0
  log_dbg(cd, "Verifying reencryption metadata.");
383
384
0
  keyslot_reencrypt = LUKS2_find_keyslot(hdr, "reencrypt");
385
0
  if (keyslot_reencrypt < 0)
386
0
    return keyslot_reencrypt;
387
388
0
  if (LUKS2_config_get_reencrypt_version(hdr, &version))
389
0
    return -EINVAL;
390
391
0
  r = reencrypt_assembly_verification_data(cd, hdr, vks, version, &data);
392
0
  if (r < 0)
393
0
    return r;
394
395
0
  r = LUKS2_digest_verify(cd, hdr, data, keyslot_reencrypt);
396
0
  crypt_free_volume_key(data);
397
398
0
  if (r < 0) {
399
0
    if (r == -ENOENT)
400
0
      log_dbg(cd, "Reencryption digest is missing.");
401
0
    log_err(cd, _("Reencryption metadata is invalid."));
402
0
  } else
403
0
    log_dbg(cd, "Reencryption metadata verified.");
404
405
0
  return r;
406
0
}