Coverage Report

Created: 2026-06-08 06:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cryptsetup/lib/luks2/luks2_digest.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 * LUKS - Linux Unified Key Setup v2, digest handling
4
 *
5
 * Copyright (C) 2015-2025 Red Hat, Inc. All rights reserved.
6
 * Copyright (C) 2015-2025 Milan Broz
7
 */
8
9
#include "luks2_internal.h"
10
11
extern const digest_handler PBKDF2_digest;
12
13
static const digest_handler *digest_handlers[LUKS2_DIGEST_MAX] = {
14
  &PBKDF2_digest,
15
  NULL
16
};
17
18
static const digest_handler *LUKS2_digest_handler_type(const char *type)
19
0
{
20
0
  int i;
21
22
0
  for (i = 0; i < LUKS2_DIGEST_MAX && digest_handlers[i]; i++) {
23
0
    if (!strcmp(digest_handlers[i]->name, type))
24
0
      return digest_handlers[i];
25
0
  }
26
27
0
  return NULL;
28
0
}
29
30
static const digest_handler *LUKS2_digest_handler(struct crypt_device *cd, int digest)
31
0
{
32
0
  struct luks2_hdr *hdr;
33
0
  json_object *jobj1, *jobj2;
34
35
0
  if (digest < 0)
36
0
    return NULL;
37
38
0
  if (!(hdr = crypt_get_hdr(cd, CRYPT_LUKS2)))
39
0
    return NULL;
40
41
0
  if (!(jobj1 = LUKS2_get_digest_jobj(hdr, digest)))
42
0
    return NULL;
43
44
0
  if (!json_object_object_get_ex(jobj1, "type", &jobj2))
45
0
    return NULL;
46
47
0
  return LUKS2_digest_handler_type(json_object_get_string(jobj2));
48
0
}
49
50
static int LUKS2_digest_find_free(struct luks2_hdr *hdr)
51
0
{
52
0
  int digest = 0;
53
54
0
  while (LUKS2_get_digest_jobj(hdr, digest) && digest < LUKS2_DIGEST_MAX)
55
0
    digest++;
56
57
0
  return digest < LUKS2_DIGEST_MAX ? digest : -1;
58
0
}
59
60
int LUKS2_digest_create(struct crypt_device *cd,
61
  const char *type,
62
  struct luks2_hdr *hdr,
63
  const struct volume_key *vk)
64
0
{
65
0
  int digest;
66
0
  const digest_handler *dh;
67
68
0
  dh = LUKS2_digest_handler_type(type);
69
0
  if (!dh)
70
0
    return -EINVAL;
71
72
0
  digest = LUKS2_digest_find_free(hdr);
73
0
  if (digest < 0)
74
0
    return -EINVAL;
75
76
0
  log_dbg(cd, "Creating new digest %d (%s).", digest, type);
77
78
0
  return dh->store(cd, digest, crypt_volume_key_get_key(vk), crypt_volume_key_length(vk)) ?: digest;
79
0
}
80
81
int LUKS2_digest_by_keyslot(struct luks2_hdr *hdr, int keyslot)
82
0
{
83
0
  char keyslot_name[16];
84
0
  json_object *jobj_digests, *jobj_digest_keyslots;
85
86
0
  if (snprintf(keyslot_name, sizeof(keyslot_name), "%u", keyslot) < 1)
87
0
    return -ENOMEM;
88
89
0
  json_object_object_get_ex(hdr->jobj, "digests", &jobj_digests);
90
91
0
  json_object_object_foreach(jobj_digests, key, val) {
92
0
    json_object_object_get_ex(val, "keyslots", &jobj_digest_keyslots);
93
0
    if (LUKS2_array_jobj(jobj_digest_keyslots, keyslot_name))
94
0
      return atoi(key);
95
0
  }
96
97
0
  return -ENOENT;
98
0
}
99
100
static int digest_verify(struct crypt_device *cd,
101
  const digest_handler *h,
102
  int digest,
103
  const struct volume_key *vk)
104
0
{
105
0
  int r;
106
107
0
  r = h->verify(cd, digest, crypt_volume_key_get_key(vk), crypt_volume_key_length(vk));
108
0
  if (r < 0) {
109
0
    log_dbg(cd, "Digest %d (%s) verify failed with %d.", digest, h->name, r);
110
0
    return r;
111
0
  }
112
113
0
  return digest;
114
0
}
115
116
int LUKS2_digest_verify_by_digest(struct crypt_device *cd,
117
  int digest,
118
  const struct volume_key *vk)
119
0
{
120
0
  const digest_handler *h;
121
0
  int key_size, r;
122
123
0
  h = LUKS2_digest_handler(cd, digest);
124
0
  if (!h)
125
0
    return -EINVAL;
126
127
0
  r = digest_verify(cd, h, digest, vk);
128
0
  if (r < 0)
129
0
    return r;
130
131
0
  key_size = LUKS2_get_volume_key_size_by_digest(crypt_get_hdr(cd, CRYPT_LUKS2), digest);
132
133
0
  if (key_size > 0 && (size_t)key_size != crypt_volume_key_length(vk))
134
0
    return -EPERM;
135
136
0
  return r;
137
0
}
138
139
static int digest_verify_by_keyslot(struct crypt_device *cd,
140
  struct luks2_hdr *hdr,
141
  const struct volume_key *vk,
142
  int keyslot,
143
  bool check_key_size)
144
0
{
145
0
  const digest_handler *h;
146
0
  int digest, key_size, r;
147
148
0
  digest = LUKS2_digest_by_keyslot(hdr, keyslot);
149
0
  if (digest < 0)
150
0
    return digest;
151
152
0
  h = LUKS2_digest_handler(cd, digest);
153
0
  if (!h)
154
0
    return -EINVAL;
155
156
0
  log_dbg(cd, "Verifying key from keyslot %d, digest %d.", keyslot, digest);
157
158
0
  r = digest_verify(cd, h, digest, vk);
159
0
  if (r < 0 || !check_key_size)
160
0
    return r;
161
162
0
  key_size = LUKS2_get_keyslot_stored_key_size(hdr, keyslot);
163
0
  if (key_size < 0)
164
0
    return -EINVAL;
165
166
0
  if ((size_t)key_size != crypt_volume_key_length(vk))
167
0
    return -EPERM;
168
169
0
  return r;
170
0
}
171
172
int LUKS2_digest_verify(struct crypt_device *cd,
173
  struct luks2_hdr *hdr,
174
  const struct volume_key *vk,
175
  int keyslot)
176
0
{
177
0
  return digest_verify_by_keyslot(cd, hdr, vk, keyslot, /* check_key_size= */ true);
178
0
}
179
180
int LUKS2_reencrypt_keyslot_digest_verify(struct crypt_device *cd,
181
  struct luks2_hdr *hdr,
182
  const struct volume_key *vk,
183
  int keyslot)
184
0
{
185
0
  return digest_verify_by_keyslot(cd, hdr, vk, keyslot, /* check_key_size= */ false);
186
0
}
187
188
int LUKS2_digest_dump(struct crypt_device *cd, int digest)
189
0
{
190
0
  const digest_handler *h;
191
192
0
  if (!(h = LUKS2_digest_handler(cd, digest)))
193
0
    return -EINVAL;
194
195
0
  return h->dump(cd, digest);
196
0
}
197
198
int LUKS2_digest_verify_by_any_matching(struct crypt_device *cd,
199
    const struct volume_key *vk,
200
    bool exclude_default_segment)
201
0
{
202
0
  int digest, default_segment_digest = -1;
203
204
0
  if (exclude_default_segment)
205
0
    default_segment_digest = LUKS2_digest_by_segment(crypt_get_hdr(cd, CRYPT_LUKS2), CRYPT_DEFAULT_SEGMENT);
206
207
0
  for (digest = 0; digest < LUKS2_DIGEST_MAX; digest++) {
208
0
    if (digest != default_segment_digest &&
209
0
        LUKS2_digest_verify_by_digest(cd, digest, vk) == digest)
210
0
      return digest;
211
0
  }
212
213
0
  return -ENOENT;
214
0
}
215
216
int LUKS2_digest_verify_by_segment(struct crypt_device *cd,
217
  struct luks2_hdr *hdr,
218
  int segment,
219
  const struct volume_key *vk)
220
0
{
221
0
  const digest_handler *h;
222
0
  int digest, key_size, r;
223
0
  unsigned s;
224
225
0
  if (segment == CRYPT_ANY_SEGMENT) {
226
0
    for (s = 0; s < json_segments_count(LUKS2_get_segments_jobj(hdr)); s++) {
227
0
      if ((r = LUKS2_digest_verify_by_segment(cd, hdr, s, vk)) >= 0)
228
0
        return r;
229
0
    }
230
231
0
    return -EPERM;
232
0
  }
233
234
0
  digest = LUKS2_digest_by_segment(hdr, segment);
235
0
  if (digest < 0)
236
0
    return digest;
237
238
0
  h = LUKS2_digest_handler(cd, digest);
239
0
  if (!h)
240
0
    return -EINVAL;
241
242
0
  r = digest_verify(cd, h, digest, vk);
243
0
  if (r < 0)
244
0
    return r;
245
246
0
  if (segment == CRYPT_DEFAULT_SEGMENT)
247
    /* use default segment key size or fallback to the cached key size */
248
0
    key_size = crypt_get_volume_key_size(cd);
249
0
  else
250
0
    key_size = LUKS2_get_volume_key_size(hdr, segment);
251
252
0
  if (key_size > 0 && (size_t)key_size != crypt_volume_key_length(vk))
253
0
    return -EPERM;
254
255
0
  return r;
256
0
}
257
258
/* FIXME: segment can have more digests */
259
int LUKS2_digest_by_segment(struct luks2_hdr *hdr, int segment)
260
0
{
261
0
  char segment_name[16];
262
0
  json_object *jobj_digests, *jobj_digest_segments;
263
264
0
  if (segment == CRYPT_DEFAULT_SEGMENT)
265
0
    segment = LUKS2_get_default_segment(hdr);
266
267
0
  json_object_object_get_ex(hdr->jobj, "digests", &jobj_digests);
268
269
0
  if (snprintf(segment_name, sizeof(segment_name), "%u", segment) < 1)
270
0
    return -EINVAL;
271
272
0
  json_object_object_foreach(jobj_digests, key, val) {
273
0
    json_object_object_get_ex(val, "segments", &jobj_digest_segments);
274
0
    if (!LUKS2_array_jobj(jobj_digest_segments, segment_name))
275
0
      continue;
276
277
0
    return atoi(key);
278
0
  }
279
280
0
  return -ENOENT;
281
0
}
282
283
static int assign_one_digest(struct crypt_device *cd, struct luks2_hdr *hdr,
284
           int keyslot, int digest, int assign)
285
0
{
286
0
  json_object *jobj1, *jobj_digest, *jobj_digest_keyslots;
287
0
  char num[16];
288
289
0
  log_dbg(cd, "Keyslot %i %s digest %i.", keyslot, assign ? "assigned to" : "unassigned from", digest);
290
291
0
  jobj_digest = LUKS2_get_digest_jobj(hdr, digest);
292
0
  if (!jobj_digest)
293
0
    return -EINVAL;
294
295
0
  json_object_object_get_ex(jobj_digest, "keyslots", &jobj_digest_keyslots);
296
0
  if (!jobj_digest_keyslots)
297
0
    return -EINVAL;
298
299
0
  if (snprintf(num, sizeof(num), "%d", keyslot) < 0)
300
0
    return -EINVAL;
301
302
0
  if (assign) {
303
0
    jobj1 = LUKS2_array_jobj(jobj_digest_keyslots, num);
304
0
    if (!jobj1)
305
0
      json_object_array_add(jobj_digest_keyslots, json_object_new_string(num));
306
0
  } else {
307
0
    jobj1 = LUKS2_array_remove(jobj_digest_keyslots, num);
308
0
    if (jobj1)
309
0
      json_object_object_add(jobj_digest, "keyslots", jobj1);
310
0
  }
311
312
0
  return 0;
313
0
}
314
315
int LUKS2_digest_assign(struct crypt_device *cd, struct luks2_hdr *hdr,
316
      int keyslot, int digest, int assign, int commit)
317
0
{
318
0
  json_object *jobj_digests;
319
0
  int r = 0;
320
321
0
  if (digest == CRYPT_ANY_DIGEST) {
322
0
    json_object_object_get_ex(hdr->jobj, "digests", &jobj_digests);
323
324
0
    json_object_object_foreach(jobj_digests, key, val) {
325
0
      UNUSED(val);
326
0
      r = assign_one_digest(cd, hdr, keyslot, atoi(key), assign);
327
0
      if (r < 0)
328
0
        break;
329
0
    }
330
0
  } else
331
0
    r = assign_one_digest(cd, hdr, keyslot, digest, assign);
332
333
0
  if (r < 0)
334
0
    return r;
335
336
0
  return commit ? LUKS2_hdr_write(cd, hdr) : 0;
337
0
}
338
339
static int assign_all_segments(struct luks2_hdr *hdr, int digest, int assign)
340
0
{
341
0
  json_object *jobj1, *jobj_digest, *jobj_digest_segments;
342
343
0
  jobj_digest = LUKS2_get_digest_jobj(hdr, digest);
344
0
  if (!jobj_digest)
345
0
    return -EINVAL;
346
347
0
  json_object_object_get_ex(jobj_digest, "segments", &jobj_digest_segments);
348
0
  if (!jobj_digest_segments)
349
0
    return -EINVAL;
350
351
0
  if (assign) {
352
0
    json_object_object_foreach(LUKS2_get_segments_jobj(hdr), key, value) {
353
0
      UNUSED(value);
354
0
      jobj1 = LUKS2_array_jobj(jobj_digest_segments, key);
355
0
      if (!jobj1)
356
0
        json_object_array_add(jobj_digest_segments, json_object_new_string(key));
357
0
    }
358
0
  } else {
359
0
    jobj1 = json_object_new_array();
360
0
    if (!jobj1)
361
0
      return -ENOMEM;
362
0
    json_object_object_add(jobj_digest, "segments", jobj1);
363
0
  }
364
365
0
  return 0;
366
0
}
367
368
static int assign_one_segment(struct crypt_device *cd, struct luks2_hdr *hdr,
369
           int segment, int digest, int assign)
370
0
{
371
0
  json_object *jobj1, *jobj_digest, *jobj_digest_segments;
372
0
  char num[16];
373
374
0
  log_dbg(cd, "Segment %i %s digest %i.", segment, assign ? "assigned to" : "unassigned from", digest);
375
376
0
  jobj_digest = LUKS2_get_digest_jobj(hdr, digest);
377
0
  if (!jobj_digest)
378
0
    return -EINVAL;
379
380
0
  json_object_object_get_ex(jobj_digest, "segments", &jobj_digest_segments);
381
0
  if (!jobj_digest_segments)
382
0
    return -EINVAL;
383
384
0
  if (snprintf(num, sizeof(num), "%d", segment) < 0)
385
0
    return -EINVAL;
386
387
0
  if (assign) {
388
0
    jobj1 = LUKS2_array_jobj(jobj_digest_segments, num);
389
0
    if (!jobj1)
390
0
      json_object_array_add(jobj_digest_segments, json_object_new_string(num));
391
0
  } else {
392
0
    jobj1 = LUKS2_array_remove(jobj_digest_segments, num);
393
0
    if (jobj1)
394
0
      json_object_object_add(jobj_digest, "segments", jobj1);
395
0
  }
396
397
0
  return 0;
398
0
}
399
400
int LUKS2_digest_segment_assign(struct crypt_device *cd, struct luks2_hdr *hdr,
401
      int segment, int digest, int assign, int commit)
402
0
{
403
0
  json_object *jobj_digests;
404
0
  int r = 0;
405
406
0
  if (segment == CRYPT_DEFAULT_SEGMENT)
407
0
    segment = LUKS2_get_default_segment(hdr);
408
409
0
  if (digest == CRYPT_ANY_DIGEST) {
410
0
    json_object_object_get_ex(hdr->jobj, "digests", &jobj_digests);
411
412
0
    json_object_object_foreach(jobj_digests, key, val) {
413
0
      UNUSED(val);
414
0
      if (segment == CRYPT_ANY_SEGMENT)
415
0
        r = assign_all_segments(hdr, atoi(key), assign);
416
0
      else
417
0
        r = assign_one_segment(cd, hdr, segment, atoi(key), assign);
418
0
      if (r < 0)
419
0
        break;
420
0
    }
421
0
  } else {
422
0
    if (segment == CRYPT_ANY_SEGMENT)
423
0
      r = assign_all_segments(hdr, digest, assign);
424
0
    else
425
0
      r = assign_one_segment(cd, hdr, segment, digest, assign);
426
0
  }
427
428
0
  if (r < 0)
429
0
    return r;
430
431
0
  return commit ? LUKS2_hdr_write(cd, hdr) : 0;
432
0
}
433
434
static int digest_unused(json_object *jobj_digest)
435
0
{
436
0
  json_object *jobj;
437
438
0
  json_object_object_get_ex(jobj_digest, "segments", &jobj);
439
0
  if (!jobj || !json_object_is_type(jobj, json_type_array) || json_object_array_length(jobj) > 0)
440
0
    return 0;
441
442
0
  json_object_object_get_ex(jobj_digest, "keyslots", &jobj);
443
0
  if (!jobj || !json_object_is_type(jobj, json_type_array))
444
0
    return 0;
445
446
0
  return json_object_array_length(jobj) > 0 ? 0 : 1;
447
0
}
448
449
void LUKS2_digests_erase_unused(struct crypt_device *cd,
450
  struct luks2_hdr *hdr)
451
0
{
452
0
  json_object *jobj_digests;
453
454
0
  json_object_object_get_ex(hdr->jobj, "digests", &jobj_digests);
455
0
  if (!jobj_digests || !json_object_is_type(jobj_digests, json_type_object))
456
0
    return;
457
458
0
  json_object_object_foreach(jobj_digests, key, val) {
459
0
    if (digest_unused(val)) {
460
0
      log_dbg(cd, "Erasing unused digest %d.", atoi(key));
461
0
      json_object_object_del(jobj_digests, key);
462
0
    }
463
0
  }
464
0
}
465
466
/* Key description helpers */
467
static char *get_key_description_by_digest(struct crypt_device *cd, int digest)
468
0
{
469
0
  char *desc, digest_str[3];
470
0
  int r;
471
0
  size_t len;
472
473
0
  if (!crypt_get_uuid(cd))
474
0
    return NULL;
475
476
0
  r = snprintf(digest_str, sizeof(digest_str), "d%u", digest);
477
0
  if (r < 0 || (size_t)r >= sizeof(digest_str))
478
0
    return NULL;
479
480
  /* "cryptsetup:<uuid>-<digest_str>" + \0 */
481
0
  len = strlen(crypt_get_uuid(cd)) + strlen(digest_str) + 13;
482
483
0
  desc = malloc(len);
484
0
  if (!desc)
485
0
         return NULL;
486
487
0
  r = snprintf(desc, len, "%s:%s-%s", "cryptsetup", crypt_get_uuid(cd), digest_str);
488
0
  if (r < 0 || (size_t)r >= len) {
489
0
         free(desc);
490
0
         return NULL;
491
0
  }
492
493
0
  return desc;
494
0
}
495
496
int LUKS2_key_description_by_segment(struct crypt_device *cd,
497
    struct luks2_hdr *hdr, struct volume_key *vk, int segment)
498
0
{
499
0
  char *desc = get_key_description_by_digest(cd, LUKS2_digest_by_segment(hdr, segment));
500
0
  int r;
501
502
0
  r = crypt_volume_key_set_description(vk, desc, LOGON_KEY);
503
0
  free(desc);
504
0
  return r;
505
0
}
506
507
int LUKS2_volume_key_load_in_keyring_by_digest(struct crypt_device *cd,
508
    struct volume_key *vk, int digest)
509
0
{
510
0
  char *desc = get_key_description_by_digest(cd, digest);
511
0
  int r;
512
513
0
  r = crypt_volume_key_set_description(vk, desc, LOGON_KEY);
514
0
  if (!r)
515
0
    r = crypt_volume_key_load_in_keyring(cd, vk);
516
517
0
  free(desc);
518
0
  return r;
519
0
}