This function allow to an another module to iterate over a LUKS2 keyslots.

Signed-off-by: Yann Diorcet <diorcet.y...@gmail.com>
---
 grub-core/disk/luks2.c | 202 ++++++++++++++++++-----------------------
 include/grub/luks2.h   | 149 ++++++++++++++++++++++++++++++
 2 files changed, 236 insertions(+), 115 deletions(-)
 create mode 100644 include/grub/luks2.h

diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c
index abe751d64..3ca06be02 100644
--- a/grub-core/disk/luks2.c
+++ b/grub-core/disk/luks2.c
@@ -28,6 +28,8 @@
 #include <grub/i18n.h>
 #include <grub/safemath.h>
 
+#include <grub/luks2.h>
+
 #include <base64.h>
 #include <json.h>
 
@@ -39,13 +41,6 @@ GRUB_MOD_LICENSE ("GPLv3+");
 /* From tss2_types.h */
 #define TPM_MAX_PCRS                      24
 
-enum grub_luks2_kdf_type
-{
-  LUKS2_KDF_TYPE_ARGON2I,
-  LUKS2_KDF_TYPE_PBKDF2
-};
-typedef enum grub_luks2_kdf_type grub_luks2_kdf_type_t;
-
 /* On disk LUKS header */
 struct grub_luks2_header
 {
@@ -65,114 +60,6 @@ struct grub_luks2_header
 } GRUB_PACKED;
 typedef struct grub_luks2_header grub_luks2_header_t;
 
-struct grub_luks2_keyslot
-{
-  /* The integer key to the associative array of keyslots. */
-  grub_uint64_t idx;
-  grub_int64_t key_size;
-  grub_int64_t priority;
-  struct
-  {
-    const char   *encryption;
-    grub_uint64_t offset;
-    grub_uint64_t size;
-    grub_int64_t  key_size;
-  } area;
-  struct
-  {
-    const char  *hash;
-    grub_int64_t stripes;
-  } af;
-  struct
-  {
-    grub_luks2_kdf_type_t type;
-    const char           *salt;
-    union
-    {
-      struct
-      {
-       grub_int64_t time;
-       grub_int64_t memory;
-       grub_int64_t cpus;
-      } argon2i;
-      struct
-      {
-       const char   *hash;
-       grub_int64_t iterations;
-      } pbkdf2;
-    } u;
-  } kdf;
-};
-typedef struct grub_luks2_keyslot grub_luks2_keyslot_t;
-
-struct grub_luks2_segment
-{
-  grub_uint64_t idx;
-  grub_uint64_t offset;
-  const char   *size;
-  const char   *encryption;
-  grub_int64_t sector_size;
-};
-typedef struct grub_luks2_segment grub_luks2_segment_t;
-
-struct grub_luks2_digest
-{
-  grub_uint64_t idx;
-  /* Both keyslots and segments are interpreted as bitfields here */
-  grub_uint64_t        keyslots;
-  grub_uint64_t        segments;
-  const char   *salt;
-  const char   *digest;
-  const char   *hash;
-  grub_int64_t iterations;
-};
-typedef struct grub_luks2_digest grub_luks2_digest_t;
-
-
-enum grub_luks2_token_type
-{
-  LUKS2_TOKEN_TYPE_NONE,
-  LUKS2_TOKEN_TYPE_SYSTEMD_TPM2
-};
-
-typedef enum grub_luks2_token_type grub_luks2_token_type_t;
-
-enum grub_luks2_token_systemd_tpm2_algo_type
-{
-  LUKS2_TOKEN_SYSTEMD_TPM2_ALGO_TYPE_ECC,
-  LUKS2_TOKEN_SYSTEMD_TPM2_ALGO_TYPE_RSA
-};
-
-typedef enum grub_luks2_token_systemd_tpm2_algo_type 
grub_luks2_token_systemd_tpm2_algo_type_t;
-
-enum grub_luks2_token_systemd_tpm2_pcr_bank_type
-{
-  LUKS2_TOKEN_SYSTEMD_TPM2_PCR_BANK_TYPE_SHA256,
-  LUKS2_TOKEN_SYSTEMD_TPM2_PCR_BANK_TYPE_SHA1
-};
-
-typedef enum grub_luks2_token_systemd_tpm2_pcr_bank_type 
grub_luks2_token_systemd_tpm2_pcr_bank_type_t;
-
-struct grub_luks2_token
-{
-  grub_uint64_t idx;
-  grub_luks2_token_type_t type;
-  grub_uint64_t        keyslots;
-  union
-  {
-    struct
-    {
-      grub_uint32_t pcr_mask;
-      grub_luks2_token_systemd_tpm2_pcr_bank_type_t pcr_bank;
-      grub_luks2_token_systemd_tpm2_algo_type_t primary_alg;
-      const char *base64_blob;
-      const char *hex_policy_hash;
-      const char *base64_srk;
-    } systemd_tpm2;
-  } u;
-};
-typedef struct grub_luks2_token grub_luks2_token_t;
-
 gcry_err_code_t AF_merge (const gcry_md_spec_t * hash, grub_uint8_t * src,
                          grub_uint8_t * dst, grub_size_t blocksize,
                          grub_size_t blocknumbers);
@@ -701,6 +588,91 @@ luks2_decrypt_key (grub_uint8_t *out_key,
   return ret;
 }
 
+extern grub_err_t
+luks2_iterate_keyslot(grub_disk_t source, grub_uint32_t flags, 
luks2_iterate_fct_t fct)
+{
+  char *json_header = NULL, *ptr;
+  grub_size_t json_idx, size;
+  grub_luks2_header_t header;
+  grub_luks2_keyslot_t keyslot;
+  grub_luks2_digest_t digest;
+  grub_luks2_segment_t segment;
+  grub_luks2_token_t token;
+  grub_json_t *json = NULL, keyslots;
+  grub_err_t ret;
+  grub_size_t sz;
+
+  ret = luks2_read_header (source, &header);
+  if (ret)
+    return ret;
+
+  if (grub_sub (grub_be_to_cpu64 (header.hdr_size), sizeof (header), &sz))
+    return grub_error (GRUB_ERR_OUT_OF_RANGE, "underflow detected while 
calculating json header size");
+
+  json_header = grub_zalloc (sz);
+  if (!json_header)
+      return GRUB_ERR_OUT_OF_MEMORY;
+
+  /* Read the JSON area. */
+  ret = grub_disk_read (source, 0, grub_be_to_cpu64 (header.hdr_offset) + 
sizeof (header),
+                       grub_be_to_cpu64 (header.hdr_size) - sizeof (header), 
json_header);
+  if (ret)
+      goto err;
+
+  ptr = grub_memchr (json_header, 0, grub_be_to_cpu64 (header.hdr_size) - 
sizeof (header));
+  if (!ptr)
+    goto err;
+
+  ret = grub_json_parse (&json, json_header, grub_be_to_cpu64 
(header.hdr_size));
+  if (ret)
+    {
+      ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid LUKS2 JSON header");
+      goto err;
+    }
+
+  if (grub_json_getvalue (&keyslots, json, "keyslots") ||
+      grub_json_getsize (&size, &keyslots))
+    {
+      ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "Could not get keyslots");
+      goto err;
+    }
+
+  if (grub_disk_native_sectors (source) == GRUB_DISK_SIZE_UNKNOWN)
+    {
+      /* FIXME: Allow use of source disk, and maybe cause errors in read. */
+      grub_dprintf ("luks2", "Source disk %s has an unknown size, "
+                            "conservatively returning error\n", source->name);
+      ret = grub_error (GRUB_ERR_BUG, "Unknown size of luks2 source device");
+      goto err;
+    }
+
+  /* Try all keyslot */
+  for (json_idx = 0; json_idx < size; json_idx++)
+    {
+      grub_errno = GRUB_ERR_NONE;
+      ret = luks2_get_keyslot (&keyslot, &digest, &segment, (flags & 
LUKS2_ITERATE_FLAGS_WITH_TOKEN) ? &token: NULL, json, json_idx);
+      if (ret)
+       {
+         /*
+          * luks2_get_keyslot() can fail for a variety of reasons that do not
+          * necessarily mean the next keyslot should not be tried (e.g. a new
+          * kdf type). So always try the next slot.
+          */
+         grub_dprintf ("luks2", "Failed to get keyslot %" PRIuGRUB_UINT64_T 
"\n", keyslot.idx);
+         continue;
+       }
+      if (grub_errno != GRUB_ERR_NONE)
+         grub_dprintf ("luks2", "Ignoring unhandled error %d from 
luks2_get_keyslot\n", grub_errno);
+
+
+    fct(&keyslot, &digest, &segment, (flags & LUKS2_ITERATE_FLAGS_WITH_TOKEN) 
? &token: NULL);
+  }
+err:
+  grub_free (json_header);
+  grub_json_free (json);
+  return ret;
+}
+
 static grub_err_t
 luks2_recover_key (grub_disk_t source,
                   grub_cryptodisk_t crypt,
diff --git a/include/grub/luks2.h b/include/grub/luks2.h
new file mode 100644
index 000000000..5e7c77565
--- /dev/null
+++ b/include/grub/luks2.h
@@ -0,0 +1,149 @@
+/* luks2.h - On disk structures for LUKS2. */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2006,2007  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_LUKS2_H
+#define GRUB_LUKS2_H   1
+
+#include <grub/disk.h>
+#include <grub/err.h>
+
+enum grub_luks2_kdf_type
+{
+  LUKS2_KDF_TYPE_ARGON2I,
+  LUKS2_KDF_TYPE_PBKDF2
+};
+typedef enum grub_luks2_kdf_type grub_luks2_kdf_type_t;
+
+struct grub_luks2_keyslot
+{
+  /* The integer key to the associative array of keyslots. */
+  grub_uint64_t idx;
+  grub_int64_t key_size;
+  grub_int64_t priority;
+  struct
+  {
+    const char   *encryption;
+    grub_uint64_t offset;
+    grub_uint64_t size;
+    grub_int64_t  key_size;
+  } area;
+  struct
+  {
+    const char  *hash;
+    grub_int64_t stripes;
+  } af;
+  struct
+  {
+    grub_luks2_kdf_type_t type;
+    const char           *salt;
+    union
+    {
+      struct
+      {
+       grub_int64_t time;
+       grub_int64_t memory;
+       grub_int64_t cpus;
+      } argon2i;
+      struct
+      {
+       const char   *hash;
+       grub_int64_t iterations;
+      } pbkdf2;
+    } u;
+  } kdf;
+};
+typedef struct grub_luks2_keyslot grub_luks2_keyslot_t;
+
+struct grub_luks2_segment
+{
+  grub_uint64_t idx;
+  grub_uint64_t offset;
+  const char   *size;
+  const char   *encryption;
+  grub_int64_t sector_size;
+};
+typedef struct grub_luks2_segment grub_luks2_segment_t;
+
+struct grub_luks2_digest
+{
+  grub_uint64_t idx;
+  /* Both keyslots and segments are interpreted as bitfields here */
+  grub_uint64_t        keyslots;
+  grub_uint64_t        segments;
+  const char   *salt;
+  const char   *digest;
+  const char   *hash;
+  grub_int64_t iterations;
+};
+typedef struct grub_luks2_digest grub_luks2_digest_t;
+
+
+enum grub_luks2_token_type
+{
+  LUKS2_TOKEN_TYPE_NONE,
+  LUKS2_TOKEN_TYPE_SYSTEMD_TPM2
+};
+
+typedef enum grub_luks2_token_type grub_luks2_token_type_t;
+
+enum grub_luks2_token_systemd_tpm2_algo_type
+{
+  LUKS2_TOKEN_SYSTEMD_TPM2_ALGO_TYPE_ECC,
+  LUKS2_TOKEN_SYSTEMD_TPM2_ALGO_TYPE_RSA
+};
+
+typedef enum grub_luks2_token_systemd_tpm2_algo_type 
grub_luks2_token_systemd_tpm2_algo_type_t;
+
+enum grub_luks2_token_systemd_tpm2_pcr_bank_type
+{
+  LUKS2_TOKEN_SYSTEMD_TPM2_PCR_BANK_TYPE_SHA256,
+  LUKS2_TOKEN_SYSTEMD_TPM2_PCR_BANK_TYPE_SHA1
+};
+
+typedef enum grub_luks2_token_systemd_tpm2_pcr_bank_type 
grub_luks2_token_systemd_tpm2_pcr_bank_type_t;
+
+struct grub_luks2_token
+{
+  grub_uint64_t idx;
+  grub_luks2_token_type_t type;
+  grub_uint64_t        keyslots;
+  union
+  {
+    struct
+    {
+      grub_uint32_t pcr_mask;
+      grub_luks2_token_systemd_tpm2_pcr_bank_type_t pcr_bank;
+      grub_luks2_token_systemd_tpm2_algo_type_t primary_alg;
+      const char *base64_blob;
+      const char *hex_policy_hash;
+      const char *base64_srk;
+    } systemd_tpm2;
+  } u;
+};
+typedef struct grub_luks2_token grub_luks2_token_t;
+
+typedef void (*luks2_iterate_fct_t)(grub_luks2_keyslot_t *k, 
grub_luks2_digest_t *d, grub_luks2_segment_t *s, grub_luks2_token_t *t);
+
+#define LUKS2_ITERATE_FLAGS_NONE 0
+#define LUKS2_ITERATE_FLAGS_WITH_TOKEN 1 << 0
+
+extern grub_err_t
+luks2_iterate_keyslot(grub_disk_t source, grub_uint32_t flags, 
luks2_iterate_fct_t fct);
+
+#endif /* ! GRUB_LUKS2_H */
\ No newline at end of file
-- 
2.39.5


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to