[Concept,20/24] luks: Show the JSON information for LUKSv2

Message ID 20251031065439.3251464-21-sjg@u-boot.org
State New
Headers
Series luks: Provide basic support for unlocking a LUKS1 partition |

Commit Message

Simon Glass Oct. 31, 2025, 6:54 a.m. UTC
  From: Simon Glass <sjg@chromium.org>

Extract the full information for version 2, which is JSON format. Show
this with the 'luks info' command.

Use the mmc12 disk to check this.

Require the JSON for LUKS.

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <sjg@chromium.org>
---

 doc/usage/cmd/luks.rst |  29 ++++++++++
 drivers/block/Kconfig  |   1 +
 drivers/block/luks.c   |  23 ++++++++
 test/boot/luks.c       | 118 ++++++++++++++++++++++++++++++++++++++---
 4 files changed, 165 insertions(+), 6 deletions(-)
  

Patch

diff --git a/doc/usage/cmd/luks.rst b/doc/usage/cmd/luks.rst
index b88fcd96439..c3b03eeff2e 100644
--- a/doc/usage/cmd/luks.rst
+++ b/doc/usage/cmd/luks.rst
@@ -106,6 +106,35 @@  Display LUKS header information for a LUKS2 partition::
     Label:
     Checksum alg:   sha256
 
+    JSON metadata (12288 bytes):
+    {
+      "keyslots": {
+        "0": {
+          "type": "luks2",
+          "key_size": 64,
+          "kdf": {
+            "type": "argon2id",
+            "time": 6,
+            "memory": 1048576,
+            "cpus": 4,
+            ...
+          },
+          ...
+        }
+      },
+      "tokens": {},
+      "segments": {
+        "0": {
+          "type": "crypt",
+          "offset": "16777216",
+          "encryption": "aes-xts-plain64",
+          ...
+        }
+      },
+      "digests": { ... },
+      "config": { ... }
+    }
+
 Display LUKS header information for a LUKS1 partition::
 
     => luks info mmc 1:1
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index b07012ec7c9..34cd2ee8e59 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -278,6 +278,7 @@  config BLK_LUKS
 	select SHA256
 	select PBKDF2
 	select PKCS5_MBEDTLS if MBEDTLS_LIB_CRYPTO
+	select JSON
 	help
 	  This provides support for detecting and decrypting LUKS (Linux Unified
 	  Key Setup) encrypted partitions. LUKS is a disk encryption specification
diff --git a/drivers/block/luks.c b/drivers/block/luks.c
index 597359b98ff..c43cb9a3dd3 100644
--- a/drivers/block/luks.c
+++ b/drivers/block/luks.c
@@ -8,6 +8,7 @@ 
 #include <blk.h>
 #include <dm.h>
 #include <hexdump.h>
+#include <json.h>
 #include <log.h>
 #include <luks.h>
 #include <memalign.h>
@@ -103,6 +104,28 @@  int luks_show_info(struct udevice *blk, struct disk_partition *pinfo)
 		printf("UUID:           %.40s\n", luks2_hdr->uuid);
 		printf("Label:          %.48s\n", luks2_hdr->label);
 		printf("Checksum alg:   %.32s\n", luks2_hdr->csum_alg);
+
+		if (IS_ENABLED(CONFIG_JSON)) {
+			u64 json_size;
+			char *json_start;
+			int blocks;
+
+			/* Read the full header to get JSON area */
+			blocks = (hdr_size + desc->blksz - 1) / desc->blksz;
+			ALLOC_CACHE_ALIGN_BUFFER(unsigned char, full_hdr, blocks * desc->blksz);
+
+			if (blk_read(blk, pinfo->start, blocks, full_hdr) != blocks) {
+				printf("Error: failed to read full LUKS2 header\n");
+				return -EIO;
+			}
+
+			/* JSON starts after the 4096-byte binary header */
+			json_start = (char *)(full_hdr + 4096);
+			json_size = hdr_size - 4096;
+
+			printf("\nJSON metadata (%llx bytes):\n", json_size);
+			json_print_pretty(json_start, (int)json_size);
+		}
 	} else {
 		printf("Unknown LUKS version\n");
 		return -EPROTONOSUPPORT;
diff --git a/test/boot/luks.c b/test/boot/luks.c
index fadd3819ffe..70ee0fb0824 100644
--- a/test/boot/luks.c
+++ b/test/boot/luks.c
@@ -20,19 +20,49 @@ 
 
 DECLARE_GLOBAL_DATA_PTR;
 
-/* Common function to setup mmc11 device */
-static int setup_mmc11(struct unit_test_state *uts, struct udevice **mmcp)
+/**
+ * setup_mmc_device() - Set up an MMC device for testing
+ *
+ * This function binds and probes an MMC device specified by its device tree
+ * node name. It is used to prepare MMC devices containing test disk images
+ * with various configurations (e.g., LUKS1, LUKS2 encryption).
+ *
+ * @uts: Unit test state
+ * @node_name: Name of the device tree node (e.g., "mmc11", "mmc12")
+ * @mmcp: Returns pointer to the MMC device
+ * Return: 0 if OK, -ve on error
+ */
+static int setup_mmc_device(struct unit_test_state *uts, const char *node_name,
+			    struct udevice **mmcp)
 {
+	struct udevice *mmc;
 	ofnode root, node;
 
-	/* Enable the mmc11 node */
+	/* Enable the specified mmc node */
 	root = oftree_root(oftree_default());
-	node = ofnode_find_subnode(root, "mmc11");
+	node = ofnode_find_subnode(root, node_name);
 	ut_assert(ofnode_valid(node));
-	ut_assertok(lists_bind_fdt(gd->dm_root, node, mmcp, NULL, false));
+	ut_assertok(lists_bind_fdt(gd->dm_root, node, &mmc, NULL, false));
 
 	/* Probe the device */
-	ut_assertok(device_probe(*mmcp));
+	ut_assertok(device_probe(mmc));
+	*mmcp = mmc;
+
+	return 0;
+}
+
+/* Setup mmc11 device */
+static int setup_mmc11(struct unit_test_state *uts, struct udevice **mmcp)
+{
+	ut_assertok(setup_mmc_device(uts, "mmc11", mmcp));
+
+	return 0;
+}
+
+/* Setup mmc12 device */
+static int setup_mmc12(struct unit_test_state *uts, struct udevice **mmcp)
+{
+	ut_assertok(setup_mmc_device(uts, "mmc12", mmcp));
 
 	return 0;
 }
@@ -107,3 +137,79 @@  static int bootstd_test_luks_info(struct unit_test_state *uts)
 	return 0;
 }
 BOOTSTD_TEST(bootstd_test_luks_info, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);
+
+/* Test LUKSv2 detection on mmc12 partitions */
+static int bootstd_test_luks2_detect(struct unit_test_state *uts)
+{
+	struct disk_partition info;
+	struct blk_desc *desc;
+	struct udevice *mmc;
+	int ret;
+
+	ut_assertok(setup_mmc12(uts, &mmc));
+	desc = blk_get_by_device(mmc);
+	ut_assertnonnull(desc);
+	ut_assertnonnull(desc->bdev);
+
+	/* Check partition 1 - should NOT be LUKS */
+	ut_assertok(part_get_info(desc, 1, &info));
+	ret = luks_detect(desc->bdev, &info);
+	ut_assert(ret < 0);  /* Should fail - not LUKS */
+
+	/* Check partition 2 - should BE LUKS */
+	ut_assertok(part_get_info(desc, 2, &info));
+	ut_assertok(luks_detect(desc->bdev, &info));
+
+	/* Verify it's LUKS version 2 */
+	ut_asserteq(2, luks_get_version(desc->bdev, &info));
+
+	return 0;
+}
+BOOTSTD_TEST(bootstd_test_luks2_detect, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);
+
+/* Test LUKSv2 command on mmc12 partitions */
+static int bootstd_test_luks2_cmd(struct unit_test_state *uts)
+{
+	struct udevice *mmc;
+
+	ut_assertok(setup_mmc12(uts, &mmc));
+
+	/* Test partition 1 - should NOT be LUKS */
+	ut_asserteq(1, run_command("luks detect mmc c:1", 0));
+	ut_assert_nextlinen("Not a LUKS partition (error -");
+	ut_assert_console_end();
+
+	/* Test partition 2 - should BE LUKS */
+	ut_assertok(run_command("luks detect mmc c:2", 0));
+	ut_assert_nextline("LUKS2 encrypted partition detected");
+	ut_assert_console_end();
+
+	return 0;
+}
+BOOTSTD_TEST(bootstd_test_luks2_cmd, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);
+
+/* Test LUKSv2 info command on mmc12 partition 2 */
+static int bootstd_test_luks2_info(struct unit_test_state *uts)
+{
+	struct udevice *mmc;
+
+	ut_assertok(setup_mmc12(uts, &mmc));
+
+	/* Test partition 2 LUKS info */
+	ut_assertok(run_command("luks info mmc c:2", 0));
+	ut_assert_nextline("Version:        2");
+	ut_assert_nextlinen("Header size:");
+	ut_assert_nextlinen("Sequence ID:");
+	ut_assert_nextlinen("UUID:");
+	ut_assert_nextlinen("Label:");
+	ut_assert_nextlinen("Checksum alg:");
+
+	/* Verify JSON metadata section is present (skip empty line first) */
+	ut_assert_skip_to_line("");
+	ut_assert_nextlinen("JSON metadata (");
+	ut_assert_nextline("{");
+	/* JSON output varies and there is little value in checking it here */
+
+	return 0;
+}
+BOOTSTD_TEST(bootstd_test_luks2_info, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);