grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 3/5] protectors: Add TPM2 Key Protector


From: Hernan Gatta
Subject: [PATCH 3/5] protectors: Add TPM2 Key Protector
Date: Mon, 24 Jan 2022 06:12:16 -0800

From: Hernan Gatta <hegatta@microsoft.com>

The TPM2 key protector is a module that enables the automatic retrieval of a
fully-encrypted disk's unlocking key from a TPM 2.0.

The theory of operation is such that the module accepts various arguments, most
of which are optional therefore possess reasonable defaults. One of these
arguments is the keyfile parameter, which is mandatory.

The value of this parameter must be a path to a sealed key file (e.g.,
(hd0,gpt1)/boot/grub2/sealed_key). This sealed key file is created via the
grub-protect tool. The tool utilizes the TPM's sealing functionality to seal
(i.e., encrypt) an unlocking key using a Storage Root Key (SRK) to the values of
various Platform Configuration Registers (PCRs). These PCRs reflect the state of
the system as it boots. If the values are as expected, the system may be
considered trustworthy, at which point the TPM allows for a caller to utilize
the private component of the SRK to unseal (i.e., decrypt) the sealed key file.
The caller, in this case, is this key protector.

Signed-off-by: Hernan Gatta <hegatta@linux.microsoft.com>
---
 grub-core/Makefile.core.def |   9 +
 grub-core/tpm2/module.c     | 742 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 751 insertions(+)
 create mode 100644 grub-core/tpm2/module.c

diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index e4ae78b..8691440 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -2498,6 +2498,15 @@ module = {
 };
 
 module = {
+  name = tpm2;
+  common = tpm2/buffer.c;
+  common = tpm2/module.c;
+  common = tpm2/mu.c;
+  common = tpm2/tpm2.c;
+  efi = tpm2/tcg2.c;
+};
+
+module = {
   name = tr;
   common = commands/tr.c;
 };
diff --git a/grub-core/tpm2/module.c b/grub-core/tpm2/module.c
new file mode 100644
index 0000000..cd97452
--- /dev/null
+++ b/grub-core/tpm2/module.c
@@ -0,0 +1,742 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2022 Microsoft Corporation
+ *
+ *  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/>.
+ */
+
+#include <grub/dl.h>
+#include <grub/file.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/protector.h>
+#include <grub/tpm2/buffer.h>
+#include <grub/tpm2/mu.h>
+#include <grub/tpm2/tpm2.h>
+#include <grub/types.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+typedef enum grub_tpm2_protector_args
+{
+  GRUB_TPM2_PROTECTOR_ARG_MODE       = 1 << 0,
+  GRUB_TPM2_PROTECTOR_ARG_PCRS       = 1 << 1,
+  GRUB_TPM2_PROTECTOR_ARG_ASYMMETRIC = 1 << 2,
+  GRUB_TPM2_PROTECTOR_ARG_BANK       = 1 << 3,
+  GRUB_TPM2_PROTECTOR_ARG_KEYFILE    = 1 << 4,
+  GRUB_TPM2_PROTECTOR_ARG_SRK        = 1 << 5,
+  GRUB_TPM2_PROTECTOR_ARG_NV         = 1 << 6
+} grub_tpm2_protector_args_t;
+
+typedef enum grub_tpm2_protector_mode
+{
+  GRUB_TPM2_PROTECTOR_MODE_SRK = 1,
+  GRUB_TPM2_PROTECTOR_MODE_NV  = 2
+} grub_tpm2_protector_mode_t;
+
+struct grub_tpm2_protector_context
+{
+  grub_tpm2_protector_args_t args;
+  grub_tpm2_protector_mode_t mode;
+  grub_uint8_t pcrs[TPM_MAX_PCRS];
+  grub_uint8_t pcr_count;
+  TPM_ALG_ID asymmetric;
+  TPM_ALG_ID bank;
+  const char *keyfile;
+  TPM_HANDLE srk;
+  TPM_HANDLE nv;
+};
+
+static grub_err_t
+grub_tpm2_protector_parse_mode (struct grub_tpm2_protector_context *ctx,
+                                const char *value)
+{
+  if (grub_strcmp (value, "srk") == 0)
+    ctx->mode = GRUB_TPM2_PROTECTOR_MODE_SRK;
+  else if (grub_strcmp (value, "nv") == 0)
+    ctx->mode = GRUB_TPM2_PROTECTOR_MODE_NV;
+  else
+    return GRUB_ERR_OUT_OF_RANGE;
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_tpm2_protector_parse_pcrs (struct grub_tpm2_protector_context *ctx,
+                                char *value)
+{
+  grub_err_t err;
+  char *current_pcr = value;
+  char *next_pcr;
+  unsigned long pcr;
+  grub_uint8_t i;
+
+  if (grub_strlen (value) == 0)
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  ctx->pcr_count = 0;
+  for (i = 0; i < TPM_MAX_PCRS; i++)
+    {
+      next_pcr = grub_strchr (current_pcr, ',');
+      if (next_pcr)
+        *next_pcr = '\0';
+      if (next_pcr == current_pcr)
+        return GRUB_ERR_BAD_ARGUMENT;
+
+      grub_errno = GRUB_ERR_NONE;
+      pcr = grub_strtoul (current_pcr, NULL, 10);
+      if (grub_errno != GRUB_ERR_NONE)
+        {
+          err = grub_errno;
+          grub_errno = GRUB_ERR_NONE;
+          return err;
+        }
+
+      if (pcr > GRUB_UCHAR_MAX)
+        return GRUB_ERR_OUT_OF_RANGE;
+
+      ctx->pcrs[i] = (grub_uint8_t)pcr;
+      ctx->pcr_count++;
+
+      if (!next_pcr)
+        break;
+
+      current_pcr = next_pcr + 1;
+      if (*current_pcr == '\0')
+        return GRUB_ERR_BAD_ARGUMENT;
+    }
+
+  if (i == TPM_MAX_PCRS)
+    return GRUB_ERR_OUT_OF_RANGE;
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_tpm2_protector_parse_asymmetric (struct grub_tpm2_protector_context *ctx,
+                                      const char *value)
+{
+  if (grub_strcasecmp (value, "ECC") == 0)
+    ctx->asymmetric = TPM_ALG_ECC;
+  else if (grub_strcasecmp (value, "RSA") == 0)
+    ctx->asymmetric = TPM_ALG_RSA;
+  else
+    return GRUB_ERR_OUT_OF_RANGE;
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_tpm2_protector_parse_bank (struct grub_tpm2_protector_context *ctx,
+                                const char *value)
+{
+  if (grub_strcasecmp (value, "SHA1") == 0)
+    ctx->bank = TPM_ALG_SHA1;
+  else if (grub_strcasecmp (value, "SHA256") == 0)
+    ctx->bank = TPM_ALG_SHA256;
+  else if (grub_strcasecmp (value, "SHA384") == 0)
+    ctx->bank = TPM_ALG_SHA384;
+  else
+    return GRUB_ERR_OUT_OF_RANGE;
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_tpm2_protector_parse_keyfile (struct grub_tpm2_protector_context *ctx,
+                                   const char *value)
+{
+  if (grub_strlen (value) == 0)
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  ctx->keyfile = value;
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_tpm2_protector_parse_tpm_handle (const char *value, TPM_HANDLE *handle)
+{
+  grub_err_t err;
+  unsigned long num;
+
+  grub_errno = GRUB_ERR_NONE;
+  num = grub_strtoul (value, NULL, 0);
+  if (grub_errno != GRUB_ERR_NONE)
+    {
+      err = grub_errno;
+      grub_errno = GRUB_ERR_NONE;
+      return err;
+    }
+
+  if (num > GRUB_UINT_MAX)
+    return GRUB_ERR_OUT_OF_RANGE;
+
+  *handle = (TPM_HANDLE)num;
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_tpm2_protector_parse_srk (struct grub_tpm2_protector_context *ctx,
+                               const char *value)
+{
+  return grub_tpm2_protector_parse_tpm_handle (value, &ctx->srk);
+}
+
+static grub_err_t
+grub_tpm2_protector_parse_nvindex (struct grub_tpm2_protector_context *ctx,
+                                   const char *value)
+{
+  return grub_tpm2_protector_parse_tpm_handle (value, &ctx->nv);
+}
+
+static grub_err_t
+grub_tpm2_protector_match_arg (struct grub_tpm2_protector_context *ctx,
+                               const char *key, char *value)
+{
+  grub_err_t err;
+
+  if (grub_strlen (key) == 0 || grub_strlen (value) == 0)
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  if (grub_strcmp (key, "mode") == 0)
+  {
+    if (ctx->args & GRUB_TPM2_PROTECTOR_ARG_MODE)
+      return GRUB_ERR_BAD_ARGUMENT;
+
+    err = grub_tpm2_protector_parse_mode (ctx, value);
+    if (!err)
+      ctx->args |= GRUB_TPM2_PROTECTOR_ARG_MODE;
+
+    return err;
+  }
+
+  if (grub_strcmp (key, "pcrs") == 0)
+  {
+    if (ctx->args & GRUB_TPM2_PROTECTOR_ARG_PCRS)
+      return GRUB_ERR_BAD_ARGUMENT;
+
+    err = grub_tpm2_protector_parse_pcrs (ctx, value);
+    if (!err)
+      ctx->args |= GRUB_TPM2_PROTECTOR_ARG_PCRS;
+
+    return err;
+  }
+
+  if (grub_strcmp (key, "asymmetric") == 0)
+  {
+    if (ctx->args & GRUB_TPM2_PROTECTOR_ARG_ASYMMETRIC)
+      return GRUB_ERR_BAD_ARGUMENT;
+
+    err = grub_tpm2_protector_parse_asymmetric (ctx, value);
+    if (!err)
+      ctx->args |= GRUB_TPM2_PROTECTOR_ARG_ASYMMETRIC;
+
+    return err;
+  }
+
+  if (grub_strcmp (key, "bank") == 0)
+  {
+    if (ctx->args & GRUB_TPM2_PROTECTOR_ARG_BANK)
+      return GRUB_ERR_BAD_ARGUMENT;
+
+    err = grub_tpm2_protector_parse_bank (ctx, value);
+    if (!err)
+      ctx->args |= GRUB_TPM2_PROTECTOR_ARG_BANK;
+
+    return err;
+  }
+
+  if (grub_strcmp (key, "keyfile") == 0)
+  {
+    if (ctx->args & GRUB_TPM2_PROTECTOR_ARG_KEYFILE)
+      return GRUB_ERR_BAD_ARGUMENT;
+
+    err = grub_tpm2_protector_parse_keyfile (ctx, value);
+    if (!err)
+      ctx->args |= GRUB_TPM2_PROTECTOR_ARG_KEYFILE;
+
+    return err;
+  }
+
+  if (grub_strcmp (key, "srk") == 0)
+  {
+    if (ctx->args & GRUB_TPM2_PROTECTOR_ARG_SRK)
+      return GRUB_ERR_BAD_ARGUMENT;
+
+    err = grub_tpm2_protector_parse_srk (ctx, value);
+    if (!err)
+      ctx->args |= GRUB_TPM2_PROTECTOR_ARG_SRK;
+
+    return err;
+  }
+
+  if (grub_strcmp (key, "nvindex") == 0)
+  {
+    if (ctx->args & GRUB_TPM2_PROTECTOR_ARG_NV)
+      return GRUB_ERR_BAD_ARGUMENT;
+
+    err = grub_tpm2_protector_parse_nvindex (ctx, value);
+    if (!err)
+      ctx->args |= GRUB_TPM2_PROTECTOR_ARG_NV;
+
+    return err;
+  }
+
+  return GRUB_ERR_OUT_OF_RANGE;
+}
+
+static grub_err_t
+grub_tpm2_protector_parse_arg (struct grub_tpm2_protector_context *ctx,
+                               char *arg)
+{
+  char *key = arg;
+  char *value = NULL;
+
+  if (grub_strlen (arg) == 0)
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  value = grub_strchr (arg, '=');
+  if (!value)
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  *value = '\0';
+  value++;
+
+  if (*value == '\0')
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  return grub_tpm2_protector_match_arg (ctx, key, value);
+}
+
+static grub_err_t
+grub_tpm2_protector_parse_args (struct grub_tpm2_protector_context *ctx,
+                                char *args)
+{
+  grub_err_t err;
+  char *cur_arg;
+  char *next_arg;
+
+  if (args == NULL)
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  if (grub_strlen (args) == 0)
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  cur_arg = args;
+  for (;;)
+    {
+      next_arg = grub_strchr (cur_arg, ':');
+      if (next_arg == cur_arg)
+        return GRUB_ERR_BAD_ARGUMENT;
+      if (next_arg)
+        *next_arg = '\0';
+
+      err = grub_tpm2_protector_parse_arg (ctx, cur_arg);
+      if (err)
+        return err;
+
+      if (!next_arg)
+        break;
+
+      cur_arg = next_arg + 1;
+      if (*cur_arg == '\0')
+        return GRUB_ERR_BAD_ARGUMENT;
+    }
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_tpm2_protector_check_args (struct grub_tpm2_protector_context *ctx)
+{
+  if (!(ctx->args & GRUB_TPM2_PROTECTOR_ARG_MODE))
+    ctx->mode = GRUB_TPM2_PROTECTOR_MODE_SRK;
+
+  if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_SRK && !ctx->keyfile)
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_SRK && ctx->nv)
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_NV && ctx->srk)
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_NV && !ctx->nv)
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_NV && ctx->asymmetric)
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_NV && ctx->bank)
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  if (!(ctx->args & GRUB_TPM2_PROTECTOR_ARG_PCRS))
+    {
+      ctx->pcrs[0] = 7;
+      ctx->pcr_count = 1;
+    }
+
+  if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_SRK)
+    {
+      if (!ctx->srk)
+        ctx->srk = TPM2_SRK_HANDLE;
+
+      if (!ctx->asymmetric)
+        ctx->asymmetric = TPM_ALG_RSA;
+
+      if (!ctx->bank)
+        ctx->bank = TPM_ALG_SHA256;
+    }
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_tpm2_protector_srk_read_keyfile (const char *filepath, void **buffer,
+                                      grub_size_t *buffer_size)
+{
+  grub_file_t sealed_key_file;
+  grub_off_t sealed_key_size;
+  void *sealed_key_buffer;
+  grub_off_t sealed_key_read;
+
+  sealed_key_file = grub_file_open (filepath, GRUB_FILE_TYPE_NONE);
+  if (!sealed_key_file)
+    {
+      /* grub_file_open sets grub_errno on error, and if we do no unset it,
+       * future calls to grub_file_open will fail (and so will anybody up the
+       * stack who checks the value, if any). */
+      grub_errno = GRUB_ERR_NONE;
+      return GRUB_ERR_FILE_NOT_FOUND;
+    }
+
+  sealed_key_size = grub_file_size (sealed_key_file);
+  if (!sealed_key_size)
+    {
+      grub_file_close (sealed_key_file);
+      return GRUB_ERR_OUT_OF_RANGE;
+    }
+
+  sealed_key_buffer = grub_malloc (sealed_key_size);
+  if (!sealed_key_buffer)
+    {
+      grub_file_close (sealed_key_file);
+      return GRUB_ERR_OUT_OF_MEMORY;
+    }
+
+  sealed_key_read = grub_file_read (sealed_key_file, sealed_key_buffer,
+                                    sealed_key_size);
+  if (sealed_key_read != sealed_key_size)
+    {
+      grub_free (sealed_key_buffer);
+      grub_file_close (sealed_key_file);
+      return GRUB_ERR_FILE_READ_ERROR;
+    }
+
+  grub_file_close (sealed_key_file);
+
+  *buffer = sealed_key_buffer;
+  *buffer_size = sealed_key_size;
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_tpm2_protector_srk_unmarshal_keyfile (void *sealed_key,
+                                           grub_size_t sealed_key_size,
+                                           TPM2_SEALED_KEY *sk)
+{
+  struct grub_tpm2_buffer buf;
+
+  grub_tpm2_buffer_init (&buf);
+  if (sealed_key_size > buf.cap)
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  grub_memcpy (buf.data, sealed_key, sealed_key_size);
+  buf.size = sealed_key_size;
+
+  grub_tpm2_mu_TPM2B_PUBLIC_Unmarshal (&buf, &sk->public);
+  grub_tpm2_mu_TPM2B_Unmarshal (&buf, (TPM2B *)&sk->private);
+
+  return buf.error ? GRUB_ERR_BAD_ARGUMENT : GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_tpm2_protector_srk_get (const struct grub_tpm2_protector_context *ctx,
+                             TPM_HANDLE *srk)
+{
+  TPM_RC rc;
+  TPM2B_PUBLIC public;
+  TPMS_AUTH_COMMAND authCommand = { 0 };
+  TPM2B_SENSITIVE_CREATE inSensitive = { 0 };
+  TPM2B_PUBLIC inPublic = { 0 };
+  TPM2B_DATA outsideInfo = { 0 };
+  TPML_PCR_SELECTION creationPcr = { 0 };
+  TPM2B_PUBLIC outPublic = { 0 };
+  TPM2B_CREATION_DATA creationData = { 0 };
+  TPM2B_DIGEST creationHash = { 0 };
+  TPMT_TK_CREATION creationTicket = { 0 };
+  TPM2B_NAME srkName = { 0 };
+  TPM_HANDLE srkHandle;
+
+  /* Find SRK */
+  rc = TPM2_ReadPublic (ctx->srk, NULL, &public);
+  if (rc == TPM_RC_SUCCESS)
+    {
+      *srk = ctx->srk;
+      return GRUB_ERR_NONE;
+    }
+
+  /* The handle exists but its public area could not be read. */
+  if ((rc & ~TPM_RC_N_MASK) != TPM_RC_HANDLE)
+    return GRUB_ERR_BAD_DEVICE;
+
+  /* Create SRK */
+  authCommand.sessionHandle = TPM_RS_PW;
+  inPublic.publicArea.type = ctx->asymmetric;
+  inPublic.publicArea.nameAlg  = TPM_ALG_SHA256;
+  inPublic.publicArea.objectAttributes.restricted = 1;
+  inPublic.publicArea.objectAttributes.userWithAuth = 1;
+  inPublic.publicArea.objectAttributes.decrypt = 1;
+  inPublic.publicArea.objectAttributes.fixedTPM = 1;
+  inPublic.publicArea.objectAttributes.fixedParent = 1;
+  inPublic.publicArea.objectAttributes.sensitiveDataOrigin = 1;
+  inPublic.publicArea.objectAttributes.noDA = 1;
+
+  if (ctx->asymmetric == TPM_ALG_RSA)
+    {
+      inPublic.publicArea.parameters.rsaDetail.symmetric.algorithm = 
TPM_ALG_AES;
+      inPublic.publicArea.parameters.rsaDetail.symmetric.keyBits.aes = 128;
+      inPublic.publicArea.parameters.rsaDetail.symmetric.mode.aes = 
TPM_ALG_CFB;
+      inPublic.publicArea.parameters.rsaDetail.scheme.scheme = TPM_ALG_NULL;
+      inPublic.publicArea.parameters.rsaDetail.keyBits = 2048;
+      inPublic.publicArea.parameters.rsaDetail.exponent = 0;
+    }
+  else if (ctx->asymmetric == TPM_ALG_ECC)
+    {
+      inPublic.publicArea.parameters.eccDetail.symmetric.algorithm = 
TPM_ALG_AES;
+      inPublic.publicArea.parameters.eccDetail.symmetric.keyBits.aes = 128;
+      inPublic.publicArea.parameters.eccDetail.symmetric.mode.aes = 
TPM_ALG_CFB;
+      inPublic.publicArea.parameters.eccDetail.scheme.scheme = TPM_ALG_NULL;
+      inPublic.publicArea.parameters.eccDetail.curveID = TPM_ECC_NIST_P256;
+      inPublic.publicArea.parameters.eccDetail.kdf.scheme = TPM_ALG_NULL;
+    }
+  else
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  rc = TPM2_CreatePrimary (TPM_RH_OWNER, &authCommand, &inSensitive, &inPublic,
+                           &outsideInfo, &creationPcr, &srkHandle, &outPublic,
+                           &creationData, &creationHash, &creationTicket,
+                           &srkName, NULL);
+  if (rc != TPM_RC_SUCCESS)
+    return GRUB_ERR_BAD_DEVICE;
+
+  *srk = srkHandle;
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_tpm2_protector_srk_recover (const struct grub_tpm2_protector_context *ctx,
+                                 grub_uint8_t **key, grub_size_t *key_size)
+{
+  TPM_RC rc;
+  TPM2_SEALED_KEY sealed_key;
+  void *sealed_key_bytes;
+  grub_size_t sealed_key_size;
+  TPM_HANDLE srk_handle;
+  TPM2B_NONCE nonceCaller = { 0 };
+  TPM2B_ENCRYPTED_SECRET salt = { 0 };
+  TPMT_SYM_DEF symmetric = { 0 };
+  TPM2B_NONCE nonceTPM = { 0 };
+  TPMI_SH_AUTH_SESSION session;
+  TPML_PCR_SELECTION pcrSel = {
+    .count = 1,
+    .pcrSelections = {
+      {
+        .hash = ctx->bank,
+        .sizeOfSelect = 3,
+        .pcrSelect = { 0 }
+      },
+    }
+  };
+  TPMS_AUTH_COMMAND authCmd = { 0 };
+  TPM_HANDLE sealed_key_handle;
+  TPM2B_NAME name;
+  TPMS_AUTH_RESPONSE authResponse;
+  TPM2B_SENSITIVE_DATA data;
+  grub_uint8_t *key_out;
+  grub_uint8_t i;
+  grub_err_t err;
+
+  /* Retrieve Sealed Key */
+  err = grub_tpm2_protector_srk_read_keyfile (ctx->keyfile, &sealed_key_bytes,
+                                              &sealed_key_size);
+  if (err)
+    return err;
+
+  err = grub_tpm2_protector_srk_unmarshal_keyfile (sealed_key_bytes,
+                                                   sealed_key_size,
+                                                   &sealed_key);
+  if (err)
+    goto exit1;
+
+  /* Get SRK */
+  err = grub_tpm2_protector_srk_get (ctx, &srk_handle);
+  if (err)
+    goto exit1;
+
+  err = GRUB_ERR_BAD_DEVICE;
+
+  /* Start Auth Session */
+  nonceCaller.size = TPM_SHA256_DIGEST_SIZE;
+  symmetric.algorithm = TPM_ALG_NULL;
+
+  rc = TPM2_StartAuthSession (TPM_RH_NULL, TPM_RH_NULL, 0, &nonceCaller, &salt,
+                              TPM_SE_POLICY, &symmetric, TPM_ALG_SHA256,
+                              &session, &nonceTPM, 0);
+  if (rc)
+    goto exit2;
+
+  /* Policy PCR */
+  for (i = 0; i < ctx->pcr_count; i++)
+    pcrSel
+      .pcrSelections[0]
+      .pcrSelect[TPM2_PCR_TO_SELECT(ctx->pcrs[i])]
+        |= TPM2_PCR_TO_BIT(ctx->pcrs[i]);
+
+  rc = TPM2_PolicyPCR (session, NULL, NULL, &pcrSel, NULL);
+  if (rc)
+    goto exit3;
+
+  /* Load Sealed Key */
+  authCmd.sessionHandle = TPM_RS_PW;
+  rc = TPM2_Load (srk_handle, &authCmd, &sealed_key.private, 
&sealed_key.public,
+                  &sealed_key_handle, &name, &authResponse);
+  if (rc)
+    goto exit3;
+
+  /* Unseal Sealed Key */
+  authCmd.sessionHandle = session;
+  grub_memset (&authResponse, 0, sizeof (authResponse));
+
+  rc = TPM2_Unseal (sealed_key_handle, &authCmd, &data, &authResponse);
+  if (rc)
+    goto exit4;
+
+  /* Epilogue */
+  key_out = grub_malloc (data.size);
+  if (!key_out)
+    {
+      err = GRUB_ERR_OUT_OF_MEMORY;
+      goto exit4;
+    }
+
+  grub_memcpy (key_out, data.buffer, data.size);
+
+  *key = key_out;
+  *key_size = data.size;
+
+  err = GRUB_ERR_NONE;
+
+exit4:
+  TPM2_FlushContext (sealed_key_handle);
+
+exit3:
+  TPM2_FlushContext (session);
+
+exit2:
+  TPM2_FlushContext (srk_handle);
+
+exit1:
+  grub_free (sealed_key_bytes);
+  return err;
+}
+
+static grub_err_t
+grub_tpm2_protector_nv_recover (const struct grub_tpm2_protector_context *ctx,
+                                grub_uint8_t **key, grub_size_t *key_size)
+{
+  (void)ctx;
+  (void)key;
+  (void)key_size;
+
+  return GRUB_ERR_NOT_IMPLEMENTED_YET;
+}
+
+static grub_err_t
+grub_tpm2_protector_recover (const struct grub_tpm2_protector_context *ctx,
+                             grub_uint8_t **key, grub_size_t *key_size)
+{
+  switch (ctx->mode)
+    {
+    case GRUB_TPM2_PROTECTOR_MODE_SRK:
+      return grub_tpm2_protector_srk_recover (ctx, key, key_size);
+    case GRUB_TPM2_PROTECTOR_MODE_NV:
+      return grub_tpm2_protector_nv_recover (ctx, key, key_size);
+    default:
+      return GRUB_ERR_BAD_ARGUMENT;
+    }
+}
+
+static grub_err_t
+grub_tpm2_protector_recover_key (char *args, grub_uint8_t **key,
+                                 grub_size_t *key_size)
+{
+  grub_err_t err;
+  struct grub_tpm2_protector_context ctx = { 0 };
+
+  grub_dprintf ("tpm2", "Args: %s\n", args);
+
+  if (!args || !key)
+    return GRUB_ERR_BAD_ARGUMENT;
+
+  err = grub_tpm2_protector_parse_args (&ctx, args);
+  if (err) {
+    grub_dprintf("tpm2", "Failed to parse arguments\n");
+    return err;
+  }
+
+  err = grub_tpm2_protector_check_args (&ctx);
+  if (err) {
+    grub_dprintf("tpm2", "Invalid arguments\n");
+    return err;
+  }
+
+  err = grub_tpm2_protector_recover (&ctx, key, key_size);
+  if (err) {
+    grub_dprintf("tpm2", "Failed to recover key\n");
+    return err;
+  }
+
+  return GRUB_ERR_NONE;
+}
+
+struct grub_key_protector grub_tpm2_key_protector = {
+  .name = "tpm2",
+  .flags = GRUB_KEY_PROTECTOR_FLAG_NONE,
+  .recover_key = grub_tpm2_protector_recover_key
+};
+
+GRUB_MOD_INIT(tpm2)
+{
+  grub_key_protector_register (&grub_tpm2_key_protector);
+}
+
+GRUB_MOD_FINI(tpm2)
+{
+  grub_key_protector_unregister (&grub_tpm2_key_protector);
+}
-- 
1.8.3.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]