summaryrefslogtreecommitdiffstats
path: root/lib/luks2/luks2_segment.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/luks2/luks2_segment.c')
-rw-r--r--lib/luks2/luks2_segment.c244
1 files changed, 235 insertions, 9 deletions
diff --git a/lib/luks2/luks2_segment.c b/lib/luks2/luks2_segment.c
index 63e7c14..af87f4f 100644
--- a/lib/luks2/luks2_segment.c
+++ b/lib/luks2/luks2_segment.c
@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, internal segment handling
*
- * Copyright (C) 2018-2023 Red Hat, Inc. All rights reserved.
- * Copyright (C) 2018-2023 Ondrej Kozina
+ * Copyright (C) 2018-2024 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2018-2024 Ondrej Kozina
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -91,6 +91,33 @@ uint64_t json_segment_get_size(json_object *jobj_segment, unsigned blockwise)
return blockwise ? crypt_jobj_get_uint64(jobj) >> SECTOR_SHIFT : crypt_jobj_get_uint64(jobj);
}
+static uint64_t json_segment_get_opal_size(json_object *jobj_segment, unsigned blockwise)
+{
+ json_object *jobj;
+
+ if (!jobj_segment ||
+ !json_object_object_get_ex(jobj_segment, "opal_segment_size", &jobj))
+ return 0;
+
+ return blockwise ? crypt_jobj_get_uint64(jobj) >> SECTOR_SHIFT : crypt_jobj_get_uint64(jobj);
+}
+
+static bool json_segment_set_size(json_object *jobj_segment, const uint64_t *size_bytes)
+{
+ json_object *jobj;
+
+ if (!jobj_segment)
+ return false;
+
+ jobj = size_bytes ? crypt_jobj_new_uint64(*size_bytes) : json_object_new_string("dynamic");
+ if (!jobj)
+ return false;
+
+ json_object_object_add(jobj_segment, "size", jobj);
+
+ return true;
+}
+
const char *json_segment_get_cipher(json_object *jobj_segment)
{
json_object *jobj;
@@ -116,6 +143,37 @@ uint32_t json_segment_get_sector_size(json_object *jobj_segment)
return i < 0 ? SECTOR_SIZE : i;
}
+int json_segment_get_opal_segment_id(json_object *jobj_segment, uint32_t *ret_opal_segment_id)
+{
+ json_object *jobj_segment_id;
+
+ assert(ret_opal_segment_id);
+
+ if (!json_object_object_get_ex(jobj_segment, "opal_segment_number", &jobj_segment_id))
+ return -EINVAL;
+
+ *ret_opal_segment_id = json_object_get_int(jobj_segment_id);
+
+ return 0;
+}
+
+int json_segment_get_opal_key_size(json_object *jobj_segment, size_t *ret_key_size)
+{
+ json_object *jobj_key_size;
+
+ assert(ret_key_size);
+
+ if (!jobj_segment)
+ return -EINVAL;
+
+ if (!json_object_object_get_ex(jobj_segment, "opal_key_size", &jobj_key_size))
+ return -EINVAL;
+
+ *ret_key_size = json_object_get_int(jobj_key_size);
+
+ return 0;
+}
+
static json_object *json_segment_get_flags(json_object *jobj_segment)
{
json_object *jobj;
@@ -245,24 +303,94 @@ json_object *json_segment_create_linear(uint64_t offset, const uint64_t *length,
return jobj;
}
+static bool json_add_crypt_fields(json_object *jobj_segment, uint64_t iv_offset,
+ const char *cipher, const char *integrity,
+ uint32_t sector_size, unsigned reencryption)
+{
+ json_object *jobj_integrity;
+
+ assert(cipher);
+
+ json_object_object_add(jobj_segment, "iv_tweak", crypt_jobj_new_uint64(iv_offset));
+ json_object_object_add(jobj_segment, "encryption", json_object_new_string(cipher));
+ json_object_object_add(jobj_segment, "sector_size", json_object_new_int(sector_size));
+
+ if (integrity) {
+ jobj_integrity = json_object_new_object();
+ if (!jobj_integrity)
+ return false;
+
+ json_object_object_add(jobj_integrity, "type", json_object_new_string(integrity));
+ json_object_object_add(jobj_integrity, "journal_encryption", json_object_new_string("none"));
+ json_object_object_add(jobj_integrity, "journal_integrity", json_object_new_string("none"));
+ json_object_object_add(jobj_segment, "integrity", jobj_integrity);
+ }
+
+ if (reencryption)
+ LUKS2_segment_set_flag(jobj_segment, "in-reencryption");
+
+ return true;
+}
+
json_object *json_segment_create_crypt(uint64_t offset,
uint64_t iv_offset, const uint64_t *length,
- const char *cipher, uint32_t sector_size,
- unsigned reencryption)
+ const char *cipher, const char *integrity,
+ uint32_t sector_size, unsigned reencryption)
{
json_object *jobj = _segment_create_generic("crypt", offset, length);
+
if (!jobj)
return NULL;
- json_object_object_add(jobj, "iv_tweak", crypt_jobj_new_uint64(iv_offset));
- json_object_object_add(jobj, "encryption", json_object_new_string(cipher));
- json_object_object_add(jobj, "sector_size", json_object_new_int(sector_size));
- if (reencryption)
- LUKS2_segment_set_flag(jobj, "in-reencryption");
+ if (json_add_crypt_fields(jobj, iv_offset, cipher, integrity, sector_size, reencryption))
+ return jobj;
+
+ json_object_put(jobj);
+ return NULL;
+}
+
+static void json_add_opal_fields(json_object *jobj_segment, const uint64_t *length,
+ uint32_t segment_number, uint32_t key_size)
+{
+ assert(jobj_segment);
+ assert(length);
+
+ json_object_object_add(jobj_segment, "opal_segment_number", json_object_new_int(segment_number));
+ json_object_object_add(jobj_segment, "opal_key_size", json_object_new_int(key_size));
+ json_object_object_add(jobj_segment, "opal_segment_size", crypt_jobj_new_uint64(*length));
+}
+
+json_object *json_segment_create_opal(uint64_t offset, const uint64_t *length,
+ uint32_t segment_number, uint32_t key_size)
+{
+ json_object *jobj = _segment_create_generic("hw-opal", offset, length);
+ if (!jobj)
+ return NULL;
+
+ json_add_opal_fields(jobj, length, segment_number, key_size);
return jobj;
}
+json_object *json_segment_create_opal_crypt(uint64_t offset, const uint64_t *length,
+ uint32_t segment_number, uint32_t key_size,
+ uint64_t iv_offset, const char *cipher,
+ const char *integrity, uint32_t sector_size,
+ unsigned reencryption)
+{
+ json_object *jobj = _segment_create_generic("hw-opal-crypt", offset, length);
+ if (!jobj)
+ return NULL;
+
+ json_add_opal_fields(jobj, length, segment_number, key_size);
+
+ if (json_add_crypt_fields(jobj, iv_offset, cipher, integrity, sector_size, reencryption))
+ return jobj;
+
+ json_object_put(jobj);
+ return NULL;
+}
+
uint64_t LUKS2_segment_offset(struct luks2_hdr *hdr, int segment, unsigned blockwise)
{
return json_segment_get_offset(LUKS2_get_segment_jobj(hdr, segment), blockwise);
@@ -288,11 +416,85 @@ uint64_t LUKS2_segment_size(struct luks2_hdr *hdr, int segment, unsigned blockwi
return json_segment_get_size(LUKS2_get_segment_jobj(hdr, segment), blockwise);
}
+uint64_t LUKS2_opal_segment_size(struct luks2_hdr *hdr, int segment, unsigned blockwise)
+{
+ return json_segment_get_opal_size(LUKS2_get_segment_jobj(hdr, segment), blockwise);
+}
+
+bool LUKS2_segment_set_size(struct luks2_hdr *hdr, int segment, const uint64_t *segment_size_bytes)
+{
+ return json_segment_set_size(LUKS2_get_segment_jobj(hdr, segment), segment_size_bytes);
+}
+
int LUKS2_segment_is_type(struct luks2_hdr *hdr, int segment, const char *type)
{
return !strcmp(json_segment_type(LUKS2_get_segment_jobj(hdr, segment)) ?: "", type);
}
+static bool json_segment_is_hw_opal_only(json_object *jobj_segment)
+{
+ const char *type = json_segment_type(jobj_segment);
+
+ if (!type)
+ return false;
+
+ return !strcmp(type, "hw-opal");
+}
+
+static bool json_segment_is_hw_opal_crypt(json_object *jobj_segment)
+{
+ const char *type = json_segment_type(jobj_segment);
+
+ if (!type)
+ return false;
+
+ return !strcmp(type, "hw-opal-crypt");
+}
+
+static bool json_segment_is_hw_opal(json_object *jobj_segment)
+{
+ return json_segment_is_hw_opal_crypt(jobj_segment) ||
+ json_segment_is_hw_opal_only(jobj_segment);
+}
+
+bool LUKS2_segment_is_hw_opal_only(struct luks2_hdr *hdr, int segment)
+{
+ return json_segment_is_hw_opal_only(LUKS2_get_segment_jobj(hdr, segment));
+}
+
+bool LUKS2_segment_is_hw_opal_crypt(struct luks2_hdr *hdr, int segment)
+{
+ return json_segment_is_hw_opal_crypt(LUKS2_get_segment_jobj(hdr, segment));
+}
+
+bool LUKS2_segment_is_hw_opal(struct luks2_hdr *hdr, int segment)
+{
+ return json_segment_is_hw_opal(LUKS2_get_segment_jobj(hdr, segment));
+}
+
+int LUKS2_get_opal_segment_number(struct luks2_hdr *hdr, int segment, uint32_t *ret_opal_segment_number)
+{
+ json_object *jobj_segment = LUKS2_get_segment_jobj(hdr, segment);
+
+ assert(ret_opal_segment_number);
+
+ if (!json_segment_is_hw_opal(jobj_segment))
+ return -ENOENT;
+
+ return json_segment_get_opal_segment_id(jobj_segment, ret_opal_segment_number);
+}
+
+int LUKS2_get_opal_key_size(struct luks2_hdr *hdr, int segment)
+{
+ size_t key_size = 0;
+ json_object *jobj_segment = LUKS2_get_segment_jobj(hdr, segment);
+
+ if (json_segment_get_opal_key_size(jobj_segment, &key_size) < 0)
+ return 0;
+
+ return key_size;
+}
+
int LUKS2_last_segment_by_type(struct luks2_hdr *hdr, const char *type)
{
json_object *jobj_segments;
@@ -424,3 +626,27 @@ bool json_segment_cmp(json_object *jobj_segment_1, json_object *jobj_segment_2)
return true;
}
+
+bool LUKS2_segments_dynamic_size(struct luks2_hdr *hdr)
+{
+ json_object *jobj_segments, *jobj_size;
+
+ assert(hdr);
+
+ jobj_segments = LUKS2_get_segments_jobj(hdr);
+ if (!jobj_segments)
+ return false;
+
+ json_object_object_foreach(jobj_segments, key, val) {
+ UNUSED(key);
+
+ if (json_segment_is_backup(val))
+ continue;
+
+ if (json_object_object_get_ex(val, "size", &jobj_size) &&
+ !strcmp(json_object_get_string(jobj_size), "dynamic"))
+ return true;
+ }
+
+ return false;
+}