summaryrefslogtreecommitdiffstats
path: root/lib/luks2/luks2_json_format.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/luks2/luks2_json_format.c')
-rw-r--r--lib/luks2/luks2_json_format.c227
1 files changed, 148 insertions, 79 deletions
diff --git a/lib/luks2/luks2_json_format.c b/lib/luks2/luks2_json_format.c
index 4456358..100e026 100644
--- a/lib/luks2/luks2_json_format.c
+++ b/lib/luks2/luks2_json_format.c
@@ -1,8 +1,8 @@
/*
* LUKS - Linux Unified Key Setup v2, LUKS2 header format code
*
- * Copyright (C) 2015-2023 Red Hat, Inc. All rights reserved.
- * Copyright (C) 2015-2023 Milan Broz
+ * Copyright (C) 2015-2024 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2015-2024 Milan Broz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -204,76 +204,33 @@ int LUKS2_generate_hdr(
struct crypt_device *cd,
struct luks2_hdr *hdr,
const struct volume_key *vk,
- const char *cipherName,
- const char *cipherMode,
+ const char *cipher_spec,
const char *integrity,
const char *uuid,
unsigned int sector_size, /* in bytes */
uint64_t data_offset, /* in bytes */
- uint64_t align_offset, /* in bytes */
- uint64_t required_alignment,
- uint64_t metadata_size,
- uint64_t keyslots_size)
+ uint64_t metadata_size_bytes,
+ uint64_t keyslots_size_bytes,
+ uint64_t device_size_bytes,
+ uint32_t opal_segment_number,
+ uint32_t opal_key_size)
{
- struct json_object *jobj_segment, *jobj_integrity, *jobj_keyslots, *jobj_segments, *jobj_config;
- char cipher[128];
+ struct json_object *jobj_segment, *jobj_keyslots, *jobj_segments, *jobj_config;
uuid_t partitionUuid;
int r, digest;
- uint64_t mdev_size;
- if (!metadata_size)
- metadata_size = LUKS2_HDR_16K_LEN;
- hdr->hdr_size = metadata_size;
+ assert(cipher_spec || (opal_key_size > 0 && device_size_bytes));
- if (data_offset && data_offset < get_min_offset(hdr)) {
- log_err(cd, _("Requested data offset is too small."));
- return -EINVAL;
- }
-
- /* Increase keyslot size according to data offset */
- if (!keyslots_size && data_offset)
- keyslots_size = data_offset - get_min_offset(hdr);
-
- /* keyslots size has to be 4 KiB aligned */
- keyslots_size -= (keyslots_size % 4096);
-
- if (keyslots_size > LUKS2_MAX_KEYSLOTS_SIZE)
- keyslots_size = LUKS2_MAX_KEYSLOTS_SIZE;
-
- if (!keyslots_size) {
- assert(LUKS2_DEFAULT_HDR_SIZE > 2 * LUKS2_HDR_OFFSET_MAX);
- keyslots_size = LUKS2_DEFAULT_HDR_SIZE - get_min_offset(hdr);
- /* Decrease keyslots_size due to metadata device being too small */
- if (!device_size(crypt_metadata_device(cd), &mdev_size) &&
- ((keyslots_size + get_min_offset(hdr)) > mdev_size) &&
- device_fallocate(crypt_metadata_device(cd), keyslots_size + get_min_offset(hdr)) &&
- (get_min_offset(hdr) <= mdev_size))
- keyslots_size = mdev_size - get_min_offset(hdr);
- }
-
- /* Decrease keyslots_size if we have smaller data_offset */
- if (data_offset && (keyslots_size + get_min_offset(hdr)) > data_offset) {
- keyslots_size = data_offset - get_min_offset(hdr);
- log_dbg(cd, "Decreasing keyslot area size to %" PRIu64
- " bytes due to the requested data offset %"
- PRIu64 " bytes.", keyslots_size, data_offset);
- }
-
- /* Data offset has priority */
- if (!data_offset && required_alignment) {
- data_offset = size_round_up(get_min_offset(hdr) + keyslots_size,
- (size_t)required_alignment);
- data_offset += align_offset;
- }
+ hdr->hdr_size = metadata_size_bytes;
log_dbg(cd, "Formatting LUKS2 with JSON metadata area %" PRIu64
" bytes and keyslots area %" PRIu64 " bytes.",
- metadata_size - LUKS2_HDR_BIN_LEN, keyslots_size);
+ metadata_size_bytes - LUKS2_HDR_BIN_LEN, keyslots_size_bytes);
- if (keyslots_size < (LUKS2_HDR_OFFSET_MAX - 2*LUKS2_HDR_16K_LEN))
+ if (keyslots_size_bytes < (LUKS2_HDR_OFFSET_MAX - 2*LUKS2_HDR_16K_LEN))
log_std(cd, _("WARNING: keyslots area (%" PRIu64 " bytes) is very small,"
" available LUKS2 keyslot count is very limited.\n"),
- keyslots_size);
+ keyslots_size_bytes);
hdr->seqid = 1;
hdr->version = 2;
@@ -291,54 +248,81 @@ int LUKS2_generate_hdr(
uuid_unparse(partitionUuid, hdr->uuid);
- if (*cipherMode != '\0')
- r = snprintf(cipher, sizeof(cipher), "%s-%s", cipherName, cipherMode);
- else
- r = snprintf(cipher, sizeof(cipher), "%s", cipherName);
- if (r < 0 || (size_t)r >= sizeof(cipher))
- return -EINVAL;
-
hdr->jobj = json_object_new_object();
+ if (!hdr->jobj) {
+ r = -ENOMEM;
+ goto err;
+ }
jobj_keyslots = json_object_new_object();
+ if (!jobj_keyslots) {
+ r = -ENOMEM;
+ goto err;
+ }
+
json_object_object_add(hdr->jobj, "keyslots", jobj_keyslots);
json_object_object_add(hdr->jobj, "tokens", json_object_new_object());
jobj_segments = json_object_new_object();
+ if (!jobj_segments) {
+ r = -ENOMEM;
+ goto err;
+ }
+
json_object_object_add(hdr->jobj, "segments", jobj_segments);
json_object_object_add(hdr->jobj, "digests", json_object_new_object());
jobj_config = json_object_new_object();
+ if (!jobj_config) {
+ r = -ENOMEM;
+ goto err;
+ }
+
json_object_object_add(hdr->jobj, "config", jobj_config);
digest = LUKS2_digest_create(cd, "pbkdf2", hdr, vk);
- if (digest < 0)
+ if (digest < 0) {
+ r = -EINVAL;
goto err;
+ }
- if (LUKS2_digest_segment_assign(cd, hdr, 0, digest, 1, 0) < 0)
+ if (LUKS2_digest_segment_assign(cd, hdr, 0, digest, 1, 0) < 0) {
+ r = -EINVAL;
goto err;
+ }
- jobj_segment = json_segment_create_crypt(data_offset, 0, NULL, cipher, sector_size, 0);
- if (!jobj_segment)
- goto err;
+ if (!opal_key_size)
+ jobj_segment = json_segment_create_crypt(data_offset, 0,
+ NULL, cipher_spec,
+ integrity, sector_size,
+ 0);
+ else if (opal_key_size && cipher_spec)
+ jobj_segment = json_segment_create_opal_crypt(data_offset, &device_size_bytes,
+ opal_segment_number, opal_key_size, 0,
+ cipher_spec, integrity,
+ sector_size, 0);
+ else
+ jobj_segment = json_segment_create_opal(data_offset, &device_size_bytes,
+ opal_segment_number, opal_key_size);
- if (integrity) {
- jobj_integrity = json_object_new_object();
- 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 (!jobj_segment) {
+ r = -EINVAL;
+ goto err;
}
- json_object_object_add_by_uint(jobj_segments, 0, jobj_segment);
+ if (json_object_object_add_by_uint(jobj_segments, 0, jobj_segment)) {
+ json_object_put(jobj_segment);
+ r = -ENOMEM;
+ goto err;
+ }
- json_object_object_add(jobj_config, "json_size", crypt_jobj_new_uint64(metadata_size - LUKS2_HDR_BIN_LEN));
- json_object_object_add(jobj_config, "keyslots_size", crypt_jobj_new_uint64(keyslots_size));
+ json_object_object_add(jobj_config, "json_size", crypt_jobj_new_uint64(metadata_size_bytes - LUKS2_HDR_BIN_LEN));
+ json_object_object_add(jobj_config, "keyslots_size", crypt_jobj_new_uint64(keyslots_size_bytes));
JSON_DBG(cd, hdr->jobj, "Header JSON:");
return 0;
err:
json_object_put(hdr->jobj);
hdr->jobj = NULL;
- return -EINVAL;
+ return r;
}
int LUKS2_wipe_header_areas(struct crypt_device *cd,
@@ -379,6 +363,14 @@ int LUKS2_wipe_header_areas(struct crypt_device *cd,
offset = get_min_offset(hdr);
length = LUKS2_keyslots_size(hdr);
+ /*
+ * Skip keyslots area wipe in case it is not defined.
+ * Otherwise we would wipe whole data device (length == 0)
+ * starting at offset get_min_offset(hdr).
+ */
+ if (!length)
+ return 0;
+
log_dbg(cd, "Wiping keyslots area (0x%06" PRIx64 " - 0x%06" PRIx64") with random data.",
offset, length + offset);
@@ -409,3 +401,80 @@ int LUKS2_set_keyslots_size(struct luks2_hdr *hdr, uint64_t data_offset)
json_object_object_add(jobj_config, "keyslots_size", crypt_jobj_new_uint64(keyslots_size));
return 0;
}
+
+int LUKS2_hdr_get_storage_params(struct crypt_device *cd,
+ uint64_t alignment_offset_bytes,
+ uint64_t alignment_bytes,
+ uint64_t *ret_metadata_size_bytes,
+ uint64_t *ret_keyslots_size_bytes,
+ uint64_t *ret_data_offset_bytes)
+{
+ uint64_t data_offset_bytes, keyslots_size_bytes, metadata_size_bytes, mdev_size_bytes;
+
+ assert(cd);
+ assert(ret_metadata_size_bytes);
+ assert(ret_keyslots_size_bytes);
+ assert(ret_data_offset_bytes);
+
+ metadata_size_bytes = crypt_get_metadata_size_bytes(cd);
+ keyslots_size_bytes = crypt_get_keyslots_size_bytes(cd);
+ data_offset_bytes = crypt_get_data_offset_sectors(cd) * SECTOR_SIZE;
+
+ if (!metadata_size_bytes)
+ metadata_size_bytes = LUKS2_HDR_16K_LEN;
+
+ if (data_offset_bytes && data_offset_bytes < 2 * metadata_size_bytes) {
+ log_err(cd, _("Requested data offset is too small."));
+ return -EINVAL;
+ }
+
+ /* Increase keyslot size according to data offset */
+ if (!keyslots_size_bytes && data_offset_bytes)
+ keyslots_size_bytes = data_offset_bytes - 2 * metadata_size_bytes;
+
+ /* keyslots size has to be 4 KiB aligned */
+ keyslots_size_bytes -= (keyslots_size_bytes % 4096);
+
+ if (keyslots_size_bytes > LUKS2_MAX_KEYSLOTS_SIZE)
+ keyslots_size_bytes = LUKS2_MAX_KEYSLOTS_SIZE;
+
+ if (!keyslots_size_bytes) {
+ assert(LUKS2_DEFAULT_HDR_SIZE > 2 * LUKS2_HDR_OFFSET_MAX);
+ keyslots_size_bytes = LUKS2_DEFAULT_HDR_SIZE - 2 * metadata_size_bytes;
+ /* Decrease keyslots_size due to metadata device being too small */
+ if (!device_size(crypt_metadata_device(cd), &mdev_size_bytes) &&
+ ((keyslots_size_bytes + 2 * metadata_size_bytes) > mdev_size_bytes) &&
+ device_fallocate(crypt_metadata_device(cd), keyslots_size_bytes + 2 * metadata_size_bytes) &&
+ ((2 * metadata_size_bytes) <= mdev_size_bytes))
+ keyslots_size_bytes = mdev_size_bytes - 2 * metadata_size_bytes;
+ }
+
+ /* Decrease keyslots_size if we have smaller data_offset */
+ if (data_offset_bytes && (keyslots_size_bytes + 2 * metadata_size_bytes) > data_offset_bytes) {
+ keyslots_size_bytes = data_offset_bytes - 2 * metadata_size_bytes;
+ log_dbg(cd, "Decreasing keyslot area size to %" PRIu64
+ " bytes due to the requested data offset %"
+ PRIu64 " bytes.", keyslots_size_bytes, data_offset_bytes);
+ }
+
+ /* Data offset has priority */
+ if (!data_offset_bytes && alignment_bytes) {
+ data_offset_bytes = size_round_up(2 * metadata_size_bytes + keyslots_size_bytes,
+ (size_t)alignment_bytes);
+ data_offset_bytes += alignment_offset_bytes;
+ }
+
+ if (crypt_get_metadata_size_bytes(cd) && (crypt_get_metadata_size_bytes(cd) != metadata_size_bytes))
+ log_std(cd, _("WARNING: LUKS2 metadata size changed to %" PRIu64 " bytes.\n"),
+ metadata_size_bytes);
+
+ if (crypt_get_keyslots_size_bytes(cd) && (crypt_get_keyslots_size_bytes(cd) != keyslots_size_bytes))
+ log_std(cd, _("WARNING: LUKS2 keyslots area size changed to %" PRIu64 " bytes.\n"),
+ keyslots_size_bytes);
+
+ *ret_metadata_size_bytes = metadata_size_bytes;
+ *ret_keyslots_size_bytes = keyslots_size_bytes;
+ *ret_data_offset_bytes = data_offset_bytes;
+
+ return 0;
+}