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

Reply via email to