On Mon, 24 Jan 2022 06:12:16 -0800 Hernan Gatta <[email protected]> wrote:
> From: Hernan Gatta <[email protected]> > > 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. > There are a lot of points in this code where an error can be returned. In this case, all I'm going to get is a non-descript error code (almost always GRUB_ERR_BAD_ARGUMENT). So as a user, how am I to know where the error is actually coming from? For this reason, I like the use of grub_error(error_code, error_format_string, fmtstr_args...), which will set grub_errno and an error message, which can be retrieved up the stack and presented to the user. I'm not sure that every return of a naked error code should be replaced by grub_error(), depends on how granular of an error message you want to see. I would error on the side of more granular. For instance, its really nice that GCC will tell me which format code type specifier and a argument its choking on, rather than a catch all "I'm failing to compile your code because you have an incorrect format code somewhere in your format string". > Signed-off-by: Hernan Gatta <[email protected]> > --- > 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) Minor nit, why wouldn't this be better as an "else if"? Seems unnecessary to check all the "if" statements if we've already found a match. > + { > + 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) Ditto, for the rest of these ifs. > + { > + 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"); It's nice that this is here to at least let the user know that the failure was because of invalid arguments as opposed to a failure in the parsing. Even still, which argument was invalid? why was it invalid? As a user, this might be frustrating to diagnose. This is why a message specific to the error would be appreciated. Glenn > + 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); > +} _______________________________________________ Grub-devel mailing list [email protected] https://lists.gnu.org/mailman/listinfo/grub-devel
