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