This function allow to an another module to iterate over a LUKS2 keyslots.
Signed-off-by: Yann Diorcet <[email protected]>
---
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
[email protected]
https://lists.gnu.org/mailman/listinfo/grub-devel