For the moment only the system-tpm2 token type is supported. Signed-off-by: Yann Diorcet <diorcet.y...@gmail.com> --- grub-core/disk/luks2.c | 152 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 149 insertions(+), 3 deletions(-)
diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c index 8036d76ff..abe751d64 100644 --- a/grub-core/disk/luks2.c +++ b/grub-core/disk/luks2.c @@ -36,6 +36,9 @@ GRUB_MOD_LICENSE ("GPLv3+"); #define LUKS_MAGIC_1ST "LUKS\xBA\xBE" #define LUKS_MAGIC_2ND "SKUL\xBA\xBE" +/* From tss2_types.h */ +#define TPM_MAX_PCRS 24 + enum grub_luks2_kdf_type { LUKS2_KDF_TYPE_ARGON2I, @@ -125,6 +128,51 @@ struct grub_luks2_digest }; 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); @@ -258,11 +306,88 @@ luks2_parse_digest (grub_luks2_digest_t *out, const grub_json_t *digest) return GRUB_ERR_NONE; } +static grub_err_t +luks2_parse_token (grub_luks2_token_t *out, const grub_json_t *token) +{ + grub_json_t keyslots, pcrs, o; + grub_size_t i, size; + grub_uint64_t bit; + const char *type; + const char *pcr_bank; + const char *alg; + + if (grub_json_getstring (&type, token, "type")) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid digest type"); + else if (grub_strcmp (type, "systemd-tpm2")) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Unsupported digest type %s", type); + out->type = LUKS2_TOKEN_TYPE_SYSTEMD_TPM2; + + if (grub_json_getvalue (&keyslots, token, "keyslots") || + grub_json_getvalue (&pcrs, token, "tpm2-pcrs") || + grub_json_getstring (&pcr_bank, token, "tpm2-pcr-bank") || + grub_json_getstring (&out->u.systemd_tpm2.base64_blob, token, "tpm2-blob") || + grub_json_getstring (&out->u.systemd_tpm2.hex_policy_hash, token, "tpm2-policy-hash")) + { + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Missing token parameters"); + } + + if (grub_json_getsize (&size, &pcrs)) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "token references no pcrs"); + + out->u.systemd_tpm2.pcr_mask = 0; + for (i = 0; i < size; i++) + { + if (grub_json_getchild (&o, &pcrs, i) || + grub_json_getuint64 (&bit, &o, NULL) || bit >= TPM_MAX_PCRS) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid pcr"); + out->u.systemd_tpm2.pcr_mask |= (1 << bit); + } + + if (grub_strcmp (pcr_bank, "sha256") == 0) + out->u.systemd_tpm2.pcr_bank = LUKS2_TOKEN_SYSTEMD_TPM2_PCR_BANK_TYPE_SHA256; + else if (grub_strcmp (pcr_bank, "sha1") == 0) + out->u.systemd_tpm2.pcr_bank = LUKS2_TOKEN_SYSTEMD_TPM2_PCR_BANK_TYPE_SHA1; + else + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Unsupported pcr-bank type %s", pcr_bank); + + // Default is hardcoded ECC + if (grub_json_getstring (&alg, token, "tpm2-primary-alg") == GRUB_ERR_NONE) + { + if (grub_strcmp (alg, "ecc") == 0) + out->u.systemd_tpm2.primary_alg = LUKS2_TOKEN_SYSTEMD_TPM2_ALGO_TYPE_ECC; + else if (grub_strcmp (alg, "rsa") == 0) + out->u.systemd_tpm2.primary_alg = LUKS2_TOKEN_SYSTEMD_TPM2_ALGO_TYPE_RSA; + else + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Unsupported algo type %s", alg); + } + else + out->u.systemd_tpm2.primary_alg = LUKS2_TOKEN_SYSTEMD_TPM2_ALGO_TYPE_ECC; + + if (grub_json_getsize (&size, &keyslots)) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "token references no keyslots"); + out->keyslots = 0; + for (i = 0; i < size; i++) + { + if (grub_json_getchild (&o, &keyslots, i) || + grub_json_getuint64 (&bit, &o, NULL)) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid keyslot"); + out->keyslots |= (1 << bit); + } + + /* Optional SRK */ + if (grub_json_getstring (&out->u.systemd_tpm2.base64_srk, token, "tpm2_srk")) + { + out->u.systemd_tpm2.base64_srk = NULL; + } + + return GRUB_ERR_NONE; +} + static grub_err_t luks2_get_keyslot (grub_luks2_keyslot_t *k, grub_luks2_digest_t *d, grub_luks2_segment_t *s, - const grub_json_t *root, grub_size_t keyslot_json_idx) + grub_luks2_token_t *t, const grub_json_t *root, grub_size_t keyslot_json_idx) { - grub_json_t keyslots, keyslot, digests, digest, segments, segment; + grub_json_t keyslots, keyslot, digests, digest, segments, segment, tokens, token; grub_size_t json_idx, size; /* Get nth keyslot */ @@ -309,6 +434,27 @@ luks2_get_keyslot (grub_luks2_keyslot_t *k, grub_luks2_digest_t *d, grub_luks2_s if (json_idx == size) return grub_error (GRUB_ERR_FILE_NOT_FOUND, "No segment for digest \"%" PRIuGRUB_UINT64_T "\"", d->idx); + if (t == NULL) + return GRUB_ERR_NONE; + + /* Get token that matches the keyslot. */ + if (grub_json_getvalue (&tokens, root, "tokens") || + grub_json_getsize (&size, &tokens)) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Could not get tokens"); + for (json_idx = 0; json_idx < size; json_idx++) + { + if (grub_json_getchild (&token, &tokens, json_idx) || + grub_json_getuint64 (&t->idx, &token, NULL) || + grub_json_getchild (&token, &token, 0) || + luks2_parse_token (t, &token)) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Could not parse token index %" PRIuGRUB_SIZE, json_idx); + + if ((t->keyslots & (1 << k->idx))) + break; + } + if (json_idx == size) + return grub_error (GRUB_ERR_FILE_NOT_FOUND, "No token for keyslot \"%" PRIuGRUB_UINT64_T "\"", k->idx); + return GRUB_ERR_NONE; } @@ -626,7 +772,7 @@ luks2_recover_key (grub_disk_t source, typeof (source->total_sectors) max_crypt_sectors = 0; grub_errno = GRUB_ERR_NONE; - ret = luks2_get_keyslot (&keyslot, &digest, &segment, json, json_idx); + ret = luks2_get_keyslot (&keyslot, &digest, &segment, NULL, json, json_idx); if (ret) { /* -- 2.39.5 _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel