[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v3 00/12] Automatic Disk Unlock with TPM2
From: |
Gary Lin |
Subject: |
[PATCH v3 00/12] Automatic Disk Unlock with TPM2 |
Date: |
Wed, 12 Apr 2023 14:15:41 +0800 |
GIT repo for v3: https://github.com/lcp/grub2/tree/tpm2-unlock-v3
This patch series is based on "Automatic TPM Disk Unlock"(*1) posted by
Hernan Gatta to introduce the key protector framework and TPM2 stack
to GRUB2, and this could be a useful feature for the systems to
implement full disk encryption.
To support TPM 2.0 Key File format(*2), patch 1~6 are grabbed from
Daniel Axtens's "appended signature secure boot support" (*3) to import
libtasn1 into grub2. Besides, the libtasn1 version is upgraded to
4.19.0 instead of 4.16.0 in the original patch.
Patch 7 adds the document for libtasn1 and the steps to upgrade the
library.
Patch 8~12 are Hernan Gatta's patches with the follow-up fixes and
improvements:
- Converting 8 spaces into 1 tab
- Merging the minor build fix from Michael Chang
- Replacing "lu" with "PRIuGRUB_SIZE" for grub_dprintf
- Adding "enable = efi" to the tpm2 module in grub-core/Makefile.core.def
- Rebasing "cryptodisk: Support key protectors" to the git master
- Removing the measurement on the sealed key
- Based ont the patch from Olaf Kirch <OKir@suse.com>
- Adjusting the input parameters of TPM2_EvictControl to match the order
in "TCG TPM2 Part3 Commands"
- Declaring the input arguments of TPM2 functions as const
- Resending TPM2 commands on TPM_RC_RETRY
- Adding checks for the parameters of TPM2 commands
- Packing the missing authorization command for TPM2_PCR_Read
- Tweaking the TPM2 command functions to allow some parameters to be
NULL so that we don't have to declare empty variables
- Only enabling grub-protect for "efi" since the TPM2 stack currently
relies on the EFI TCG2 protocol to send TPM2 commands
- Using grub_cpu_to_be*() in the TPM2 stack instead of grub_swap_bytes*()
which may cause problems in big-indian machines
- Changing the short name of "--protector" of "cryptomount" from "-k" to
"-P" to avoid the conflict with "--key-file"
- Supporting TPM 2.0 Key File Format besides the raw sealed key
- Adding the external libtasn1 dependency to grub-protect to write the
TPM 2.0 Key files
To utilize the TPM2 key protector to unlock the encrypted partition
(sdb1), here are the sample steps:
1. Add an extra random key for LUKS (luks-key)
$ dd if=/dev/urandom of=luks-key bs=1 count=32
$ sudo cryptsetup luksAddKey /dev/sdb1 luks-key --pbkdf=pbkdf2
2. Seal the key
$ sudo grub-protect --action=add \
--protector=tpm2 \
--tpm2key \
--tpm2-keyfile=luks-key \
--tpm2-outfile=/boot/efi/boot/grub2/sealed.tpm
3. Unseal the key with the proper commands in grub.cfg:
tpm2_key_protector_init --tpm2key=(hd0,gpt1)/boot/grub2/sealed.tpm
cryptomount -u SDB1_UUID -P tpm2
(*1) https://lists.gnu.org/archive/html/grub-devel/2022-02/msg00006.html
(*2) https://www.hansenpartnership.com/draft-bottomley-tpm2-keys.html
(*3) https://lists.gnu.org/archive/html/grub-devel/2021-06/msg00044.html
v3:
- Adding the document for libtasn1
- Improving the error condition checks
ex: "if (!ptr)" ==> "if (ptr == NULL)"
"if (err)" ==> "if (err != GRUB_ERR_NONE)"
"if (rc)" ==> "if (rc != TPM_RC_SUCCESS)"
- Supporting the "TPMPolicy" and "TPMAuthPolicy" sequence in the TPM 2.0
key File
- Refactoring the key recover function to support "TPMPolicy" and
"TPMAuthPolicy" sequence
- Using TPMS_PCR_SELECTION_SelectPCR() to set the PCR bit mask
- Also dropping TPM2_PCR_TO_SELECT() and TPM2_PCR_TO_BIT() which are
not necessary anymore
- Removing the redundant variable, 'crd', from
grub_cryptodisk_scan_device_real()
- Fixing the spaces/tabs in cryptodisk.c
- Fixing the comment format in cryptodisk.h
- Adding the defensive check for "cargs->protectors" in
grub_cryptodisk_scan_device()
- Improving 'grub-protect' for the better support of TPM 2.0 Key File
- Adding more comments
Daniel Axtens (6):
posix_wrap: tweaks in preparation for libtasn1
libtasn1: import libtasn1-4.19.0
libtasn1: disable code not needed in grub
libtasn1: changes for grub compatibility
libtasn1: compile into asn1 module
test_asn1: test module for libtasn1
Gary Lin (1):
libtasn1: Add the documentation
Hernan Gatta (5):
protectors: Add key protectors framework
tpm2: Add TPM Software Stack (TSS)
protectors: Add TPM2 Key Protector
cryptodisk: Support key protectors
util/grub-protect: Add new tool
.gitignore | 2 +
Makefile.util.def | 29 +
configure.ac | 9 +
docs/grub-dev.texi | 27 +
grub-core/Makefile.am | 1 +
grub-core/Makefile.core.def | 42 +
grub-core/disk/cryptodisk.c | 172 +-
grub-core/kern/protectors.c | 75 +
...asn1-disable-code-not-needed-in-grub.patch | 311 ++
...tasn1-changes-for-grub-compatibility.patch | 209 ++
grub-core/lib/libtasn1/COPYING | 16 +
grub-core/lib/libtasn1/README.md | 98 +
grub-core/lib/libtasn1/lib/coding.c | 1433 ++++++++++
grub-core/lib/libtasn1/lib/decoding.c | 2504 +++++++++++++++++
grub-core/lib/libtasn1/lib/element.c | 1110 ++++++++
grub-core/lib/libtasn1/lib/element.h | 42 +
grub-core/lib/libtasn1/lib/errors.c | 103 +
grub-core/lib/libtasn1/lib/gstr.c | 74 +
grub-core/lib/libtasn1/lib/gstr.h | 50 +
grub-core/lib/libtasn1/lib/int.h | 221 ++
grub-core/lib/libtasn1/lib/parser_aux.c | 1179 ++++++++
grub-core/lib/libtasn1/lib/parser_aux.h | 172 ++
grub-core/lib/libtasn1/lib/structure.c | 1227 ++++++++
grub-core/lib/libtasn1/lib/structure.h | 46 +
.../tests/CVE-2018-1000654-1_asn1_tab.h | 32 +
.../tests/CVE-2018-1000654-2_asn1_tab.h | 36 +
.../libtasn1_wrap/tests/CVE-2018-1000654.c | 61 +
.../lib/libtasn1_wrap/tests/Test_overflow.c | 138 +
.../lib/libtasn1_wrap/tests/Test_simple.c | 207 ++
.../lib/libtasn1_wrap/tests/Test_strings.c | 150 +
.../libtasn1_wrap/tests/object-id-decoding.c | 116 +
.../libtasn1_wrap/tests/object-id-encoding.c | 120 +
.../lib/libtasn1_wrap/tests/octet-string.c | 211 ++
.../lib/libtasn1_wrap/tests/reproducers.c | 81 +
grub-core/lib/libtasn1_wrap/wrap.c | 26 +
grub-core/lib/libtasn1_wrap/wrap_tests.c | 75 +
grub-core/lib/libtasn1_wrap/wrap_tests.h | 38 +
grub-core/lib/posix_wrap/limits.h | 1 +
grub-core/lib/posix_wrap/stdlib.h | 8 +
grub-core/lib/posix_wrap/sys/types.h | 1 +
grub-core/tpm2/args.c | 131 +
grub-core/tpm2/buffer.c | 145 +
grub-core/tpm2/module.c | 1040 +++++++
grub-core/tpm2/mu.c | 807 ++++++
grub-core/tpm2/tcg2.c | 143 +
grub-core/tpm2/tpm2.c | 761 +++++
grub-core/tpm2/tpm2key.asn | 31 +
grub-core/tpm2/tpm2key.c | 431 +++
grub-core/tpm2/tpm2key_asn1_tab.c | 41 +
include/grub/cryptodisk.h | 16 +
include/grub/libtasn1.h | 645 +++++
include/grub/protector.h | 48 +
include/grub/tpm2/buffer.h | 65 +
include/grub/tpm2/internal/args.h | 39 +
include/grub/tpm2/internal/functions.h | 117 +
include/grub/tpm2/internal/structs.h | 675 +++++
include/grub/tpm2/internal/types.h | 372 +++
include/grub/tpm2/mu.h | 292 ++
include/grub/tpm2/tcg2.h | 34 +
include/grub/tpm2/tpm2.h | 34 +
include/grub/tpm2/tpm2key.h | 83 +
tests/test_asn1.in | 12 +
util/grub-protect.c | 1508 ++++++++++
63 files changed, 17892 insertions(+), 31 deletions(-)
create mode 100644 grub-core/kern/protectors.c
create mode 100644
grub-core/lib/libtasn1-patches/0001-libtasn1-disable-code-not-needed-in-grub.patch
create mode 100644
grub-core/lib/libtasn1-patches/0002-libtasn1-changes-for-grub-compatibility.patch
create mode 100644 grub-core/lib/libtasn1/COPYING
create mode 100644 grub-core/lib/libtasn1/README.md
create mode 100644 grub-core/lib/libtasn1/lib/coding.c
create mode 100644 grub-core/lib/libtasn1/lib/decoding.c
create mode 100644 grub-core/lib/libtasn1/lib/element.c
create mode 100644 grub-core/lib/libtasn1/lib/element.h
create mode 100644 grub-core/lib/libtasn1/lib/errors.c
create mode 100644 grub-core/lib/libtasn1/lib/gstr.c
create mode 100644 grub-core/lib/libtasn1/lib/gstr.h
create mode 100644 grub-core/lib/libtasn1/lib/int.h
create mode 100644 grub-core/lib/libtasn1/lib/parser_aux.c
create mode 100644 grub-core/lib/libtasn1/lib/parser_aux.h
create mode 100644 grub-core/lib/libtasn1/lib/structure.c
create mode 100644 grub-core/lib/libtasn1/lib/structure.h
create mode 100644
grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-1_asn1_tab.h
create mode 100644
grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654-2_asn1_tab.h
create mode 100644 grub-core/lib/libtasn1_wrap/tests/CVE-2018-1000654.c
create mode 100644 grub-core/lib/libtasn1_wrap/tests/Test_overflow.c
create mode 100644 grub-core/lib/libtasn1_wrap/tests/Test_simple.c
create mode 100644 grub-core/lib/libtasn1_wrap/tests/Test_strings.c
create mode 100644 grub-core/lib/libtasn1_wrap/tests/object-id-decoding.c
create mode 100644 grub-core/lib/libtasn1_wrap/tests/object-id-encoding.c
create mode 100644 grub-core/lib/libtasn1_wrap/tests/octet-string.c
create mode 100644 grub-core/lib/libtasn1_wrap/tests/reproducers.c
create mode 100644 grub-core/lib/libtasn1_wrap/wrap.c
create mode 100644 grub-core/lib/libtasn1_wrap/wrap_tests.c
create mode 100644 grub-core/lib/libtasn1_wrap/wrap_tests.h
create mode 100644 grub-core/tpm2/args.c
create mode 100644 grub-core/tpm2/buffer.c
create mode 100644 grub-core/tpm2/module.c
create mode 100644 grub-core/tpm2/mu.c
create mode 100644 grub-core/tpm2/tcg2.c
create mode 100644 grub-core/tpm2/tpm2.c
create mode 100644 grub-core/tpm2/tpm2key.asn
create mode 100644 grub-core/tpm2/tpm2key.c
create mode 100644 grub-core/tpm2/tpm2key_asn1_tab.c
create mode 100644 include/grub/libtasn1.h
create mode 100644 include/grub/protector.h
create mode 100644 include/grub/tpm2/buffer.h
create mode 100644 include/grub/tpm2/internal/args.h
create mode 100644 include/grub/tpm2/internal/functions.h
create mode 100644 include/grub/tpm2/internal/structs.h
create mode 100644 include/grub/tpm2/internal/types.h
create mode 100644 include/grub/tpm2/mu.h
create mode 100644 include/grub/tpm2/tcg2.h
create mode 100644 include/grub/tpm2/tpm2.h
create mode 100644 include/grub/tpm2/tpm2key.h
create mode 100644 tests/test_asn1.in
create mode 100644 util/grub-protect.c
Range-diff against v2:
-: --------- > 1: f2a39b639 posix_wrap: tweaks in preparation for libtasn1
-: --------- > 2: 493f2dc86 libtasn1: import libtasn1-4.19.0
-: --------- > 3: c1c345915 libtasn1: disable code not needed in grub
-: --------- > 4: 5d84feb27 libtasn1: changes for grub compatibility
-: --------- > 5: 21441d802 libtasn1: compile into asn1 module
-: --------- > 6: 7064cf0bc test_asn1: test module for libtasn1
-: --------- > 7: 5485acfb8 libtasn1: Add the documentation
1: 623072114 ! 8: 327bb228f protectors: Add key protectors framework
@@ grub-core/kern/protectors.c (new)
+grub_err_t
+grub_key_protector_register (struct grub_key_protector *protector)
+{
-+ if (!protector || !protector->name || !grub_strlen(protector->name))
++ if (protector == NULL || protector->name == NULL ||
grub_strlen(protector->name) == 0)
+ return GRUB_ERR_BAD_ARGUMENT;
+
+ if (grub_key_protectors &&
@@ grub-core/kern/protectors.c (new)
+grub_err_t
+grub_key_protector_unregister (struct grub_key_protector *protector)
+{
-+ if (!protector)
++ if (protector == NULL)
+ return GRUB_ERR_BAD_ARGUMENT;
+
+ grub_list_remove (GRUB_AS_LIST (protector));
@@ grub-core/kern/protectors.c (new)
+{
+ struct grub_key_protector *kp = NULL;
+
-+ if (!grub_key_protectors)
++ if (grub_key_protectors == NULL)
+ return GRUB_ERR_OUT_OF_RANGE;
+
-+ if (!protector || !grub_strlen (protector))
++ if (protector == NULL || grub_strlen (protector) == 0)
+ return GRUB_ERR_BAD_ARGUMENT;
+
+ kp = grub_named_list_find (GRUB_AS_NAMED_LIST (grub_key_protectors),
+ protector);
-+ if (!kp)
++ if (kp == NULL)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("A key protector with name '%s' could not be found. "
+ "Is the name spelled correctly and is the "
2: 444c0038f ! 9: ced33130b tpm2: Add TPM Software Stack (TSS)
@@ include/grub/tpm2/tpm2.h (new)
+#include <grub/tpm2/internal/structs.h>
+#include <grub/tpm2/internal/functions.h>
+
-+/* Defined in: TCG TPM Specification, v1.59, Part 2, Section 10.6.1. */
-+#define TPM2_PCR_TO_SELECT(x) ((x) / 8)
-+#define TPM2_PCR_TO_BIT(x) (1 << ((x) % 8))
-+
+/* Well-Known Windows SRK handle */
+#define TPM2_SRK_HANDLE 0x81000001
+
3: b579f35d3 ! 10: 2249db295 protectors: Add TPM2 Key Protector
@@ Commit message
The theory of operation is such that the module accepts various
arguments, most of which are optional and therefore possess reasonable
- defaults. One of these arguments is the keyfile parameter, which is
- mandatory. There are two supported key formats:
+ defaults. One of these arguments is the keyfile/tpm2key parameter,
which
+ is mandatory. There are two supported key formats:
1. Raw Sealed Key (--keyfile)
- The raw sealed key glues TPM2B_PUBLIC and TPM2B_PRIVATE, which are
- returned from TPM2_Create, into one file, and is defined as a C
- struct:
-
- typedef struct TPM2_SEALED_KEY {
- TPM2B_PUBLIC public;
- TPM2B_PRIVATE private;
- } TPM2_SEALED_KEY;
+ When sealing a key with TPM2_Create, the public portion of the
sealed
+ key is stored in TPM2B_PUBLIC, and the private portion is in
+ TPM2B_PRIVATE. The raw sealed key glues the fully marshalled
+ TPM2B_PUBLIC and TPM2B_PRIVATE into one file.
2. TPM 2.0 Key (--tpm2key)
The following is the ASN.1 definition of TPM 2.0 Key File:
+ TPMPolicy ::= SEQUENCE {
+ CommandCode [0] EXPLICIT INTEGER
+ CommandPolicy [1] EXPLICIT OCTET STRING
+ }
+
+ TPMAuthPolicy ::= SEQUENCE {
+ Name [0] EXPLICIT UTF8STRING OPTIONAL
+ Policy [1] EXPLICIT SEQUENCE OF TPMPolicy
+ }
+
TPMKey ::= SEQUENCE {
- type OBJECT IDENTIFIER
- emptyAuth [0] EXPLICIT BOOLEAN OPTIONAL
- policy [1] EXPLICIT SEQUENCE OF TPMPolicy OPTIONAL
- secret [2] EXPLICIT OCTET STRING OPTIONAL
- authPolicy [3] EXPLICIT SEQUENCE OF TPMAuthPolicy OPTIONAL
- parent INTEGER
- pubkey OCTET STRING
- privkey OCTET STRING
- }
+ type OBJECT IDENTIFIER
+ emptyAuth [0] EXPLICIT BOOLEAN OPTIONAL
+ policy [1] EXPLICIT SEQUENCE OF TPMPolicy OPTIONAL
+ secret [2] EXPLICIT OCTET STRING OPTIONAL
+ authPolicy [3] EXPLICIT SEQUENCE OF TPMAuthPolicy OPTIONAL
+ parent INTEGER
+ pubkey OCTET STRING
+ privkey OCTET STRING
+ }
The TPM2 key protector only expects a "sealed" key in DER encoding,
so 'type' is always 2.23.133.10.1.5, 'emptyAuth' is 'TRUE', and
- 'secret' is empty. TPM2B_PUBLIC is stored in 'pubkey' and
- TPM2B_PRIVATE is stored in 'privkey'. 'policy' and 'authPolicy' are
- ignored for the time being and will be used for the advanced features
- in the future.
+ 'secret' is empty. 'policy' and 'authPolicy' are the possible policy
+ command sequences to construst the policy digest to unseal the key.
+ Similar to the raw sealed key, the public portion (TPM2B_PUBLIC) of
+ the sealed key is stored in 'pubkey', and the private portion
+ (TPM2B_PRIVATE) is in 'privkey'.
For more details:
https://www.hansenpartnership.com/draft-bottomley-tpm2-keys.html
@@ Commit message
- tpm2_key_protector_clear: Clears any state set by
tpm2_key_protector_init.
The way this is expected to be used requires the user to, either
- interactively or, normally, via a boot script, initialize (i.e.,
- configure) the key protector and then specify that it be used by the
- 'cryptomount' command (modifications to this command are in a different
- patch).
+ interactively or, normally, via a boot script, initialize/configure
+ the key protector and then specify that it be used by the 'cryptomount'
+ command (modifications to this command are in a different patch).
For instance, to unseal the raw sealed key file:
@@ Commit message
tpm2_key_protector_init --tpm2key=(hd0,gpt1)/efi/grub2/sealed-2.tpm
--pcrs=7,11
cryptomount DISK2 -P tpm2
- If a user does not initialize the key protector and attempts to use it
anyway,
- the protector returns an error.
+ If a user does not initialize the key protector and attempts to use it
+ anyway, the protector returns an error.
+
+ Before unsealing the key, the TPM2 key protector follows the
"TPMPolicy"
+ sequences to enforce the TPM policy commands to construct a valid
policy
+ digest to unseal the key.
+
+ For the TPM 2.0 Key files, 'authPolicy' may contain multiple
"TPMPolicy"
+ sequences, the TPM2 key protector iterates 'authPolicy' to find a valid
+ sequence to unseal key. If 'authPolicy' is empty or all sequences in
+ 'authPolicy' fail, the protector tries the one from 'policy'. In case
+ 'policy' is also empty, the protector creates a "TPMPolicy" sequence
+ based on the given PCR selection.
+
+ For the raw sealed key, the TPM2 key protector treats the key file as a
+ TPM 2.0 Key file without 'authPolicy' and 'policy', so the "TPMPolicy"
+ sequence is always based on the PCR selection from the command
+ parameters.
+
+ Currently, there is only one supported policy command: TPM2_PolicyPCR.
+ The command set can be extended to support advanced features, such as
+ as authorized policy, in the future.
Signed-off-by: Hernan Gatta <hegatta@linux.microsoft.com>
Signed-off-by: Gary Lin <glin@suse.com>
@@ grub-core/tpm2/args.c (new)
+ pcrs[i] = (grub_uint8_t)pcr;
+ *pcr_count += 1;
+
-+ if (!next_pcr)
++ if (next_pcr == NULL)
+ break;
+
+ current_pcr = next_pcr + 1;
@@ grub-core/tpm2/args.c (new)
+ *bank = TPM_ALG_SHA256;
+ else if (grub_strcasecmp (value, "SHA384") == 0)
+ *bank = TPM_ALG_SHA384;
++ else if (grub_strcasecmp (value, "SHA512") == 0)
++ *bank = TPM_ALG_SHA512;
+ else
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("Value '%s' is not a valid PCR bank"), value);
@@ grub-core/tpm2/module.c (new)
+#include <grub/extcmd.h>
+#include <grub/file.h>
+#include <grub/libtasn1.h>
++#include <grub/list.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/protector.h>
+#include <grub/tpm2/buffer.h>
+#include <grub/tpm2/internal/args.h>
++#include <grub/tpm2/internal/types.h>
+#include <grub/tpm2/mu.h>
+#include <grub/tpm2/tpm2.h>
+#include <grub/tpm2/tpm2key.h>
@@ grub-core/tpm2/module.c (new)
+ /* Using GRUB_FILE_TYPE_SIGNATURE ensures we do not hash the keyfile
into PCR9
+ * otherwise we'll never be able to predict the value of PCR9 at unseal
time */
+ file = grub_file_open (filepath, GRUB_FILE_TYPE_SIGNATURE);
-+ if (!file)
++ if (file == NULL)
+ {
+ grub_dprintf ("tpm2", "Could not open file: %s\n", filepath);
+ /* grub_file_open sets grub_errno on error, and if we do no unset
it,
@@ grub-core/tpm2/module.c (new)
+ }
+
+ file_size = grub_file_size (file);
-+ if (!file_size)
++ if (file_size == 0)
+ {
+ grub_dprintf ("tpm2", "Could not read file size: %s\n", filepath);
+ grub_file_close (file);
@@ grub-core/tpm2/module.c (new)
+ }
+
+ read_buffer = grub_malloc (file_size);
-+ if (!read_buffer)
++ if (read_buffer == NULL)
+ {
+ grub_dprintf ("tpm2", "Could not allocate buffer for %s.\n",
filepath);
+ grub_file_close (file);
@@ grub-core/tpm2/module.c (new)
+static grub_err_t
+grub_tpm2_protector_srk_unmarshal_tpm2key (void *sealed_key,
+ grub_size_t sealed_key_size,
++ tpm2key_policy_t *policy_seq,
++ tpm2key_authpolicy_t *authpol_seq,
+ grub_uint32_t *parent,
+ TPM2_SEALED_KEY *sk)
+{
@@ grub-core/tpm2/module.c (new)
+ struct grub_tpm2_buffer buf;
+ grub_err_t err;
+
++ /*
++ * Start to parse the tpm2key file
++ * TPMKey ::= SEQUENCE {
++ * type OBJECT IDENTIFIER,
++ * emptyAuth [0] EXPLICIT BOOLEAN OPTIONAL,
++ * policy [1] EXPLICIT SEQUENCE OF TPMPolicy OPTIONAL,
++ * secret [2] EXPLICIT OCTET STRING OPTIONAL,
++ * authPolicy [3] EXPLICIT SEQUENCE OF TPMAuthPolicy OPTIONAL,
++ * parent INTEGER,
++ * pubkey OCTET STRING,
++ * privkey OCTET STRING
++ * }
++ */
+ err = grub_tpm2key_start_parsing (&tpm2key, sealed_key,
sealed_key_size);
+ if (err != GRUB_ERR_NONE)
+ return err;
+
++ /*
++ * Retrieve the policy sequence from 'policy'
++ * policy_seq will be NULL when 'policy' is not available
++ */
++ err = grub_tpm2key_get_policy_seq (tpm2key, policy_seq);
++ if (err != GRUB_ERR_NONE)
++ goto error;
++
++ /*
++ * Retrieve the authpolicy sequence from 'authPolicy'
++ * authpol_seq will be NULL when 'authPolicy' is not available
++ */
++ err = grub_tpm2key_get_authpolicy_seq (tpm2key, authpol_seq);
++ if (err != GRUB_ERR_NONE)
++ goto error;
++
++ /* Retrieve the parent handle */
+ err = grub_tpm2key_get_parent (tpm2key, &parent_tmp);
+ if (err != GRUB_ERR_NONE)
+ goto error;
+ *parent = parent_tmp;
+
++ /* Retrieve the public part of the sealed key */
+ err = grub_tpm2key_get_pubkey (tpm2key, &sealed_pub, &sealed_pub_size);
+ if (err != GRUB_ERR_NONE)
+ goto error;
+
++ /* Retrieve the private part of the sealed key */
+ err = grub_tpm2key_get_privkey (tpm2key, &sealed_priv,
&sealed_priv_size);
+ if (err != GRUB_ERR_NONE)
+ goto error;
+
++ /* Unmarshal the sealed key */
+ grub_tpm2_buffer_init (&buf);
+ if (sealed_pub_size + sealed_priv_size > buf.cap)
+ {
@@ grub-core/tpm2/module.c (new)
+ err = GRUB_ERR_NONE;
+
+error:
++ /* End the parsing */
+ grub_tpm2key_end_parsing (tpm2key);
+ grub_free (sealed_pub);
+ grub_free (sealed_priv);
@@ grub-core/tpm2/module.c (new)
+}
+
+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)
++grub_tpm2_protector_policypcr (TPMI_SH_AUTH_SESSION session,
++ struct grub_tpm2_buffer *cmd_buf)
+{
++ TPM2B_DIGEST pcr_digest;
++ TPML_PCR_SELECTION pcr_sel;
+ TPM_RC rc;
-+ TPM2_SEALED_KEY sealed_key;
-+ void *file_bytes;
-+ grub_size_t file_size;
-+ TPM_HANDLE parent_handle = 0;
-+ TPM_HANDLE srk_handle;
-+ TPM2B_NONCE nonceCaller = { 0 };
-+ TPMT_SYM_DEF symmetric = { 0 };
-+ TPMI_SH_AUTH_SESSION session;
-+ TPML_PCR_SELECTION pcrSel = {
++ grub_err_t err;
++
++ grub_tpm2_mu_TPM2B_DIGEST_Unmarshal (cmd_buf, &pcr_digest);
++ grub_tpm2_mu_TPML_PCR_SELECTION_Unmarshal (cmd_buf, &pcr_sel);
++ if (cmd_buf->error)
++ {
++ err = GRUB_ERR_BAD_ARGUMENT;
++ return grub_error (err, N_("Failed to unmarshal the buffer for "
++ "TPM2_PolicyPCR"));
++ }
++
++ rc = TPM2_PolicyPCR (session, NULL, &pcr_digest, &pcr_sel, NULL);
++ if (rc != TPM_RC_SUCCESS)
++ {
++ err = GRUB_ERR_BAD_DEVICE;
++ grub_error (err, N_("Failed to submit PCR policy (TPM2_PolicyPCR "
++ "failed with TSS/TPM error %u)"), rc);
++ return err;
++ }
++
++ return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_tpm2_protector_enforce_policy (tpm2key_policy_t policy,
TPMI_SH_AUTH_SESSION session)
++{
++ struct grub_tpm2_buffer buf;
++ grub_err_t err;
++
++ grub_tpm2_buffer_init (&buf);
++ if (policy->cmd_policy_len > buf.cap)
++ {
++ return GRUB_ERR_BAD_ARGUMENT;
++ }
++
++ grub_memcpy (buf.data, policy->cmd_policy, policy->cmd_policy_len);
++ buf.size = policy->cmd_policy_len;
++
++ switch (policy->cmd_code)
++ {
++ case TPM_CC_PolicyPCR:
++ err = grub_tpm2_protector_policypcr (session, &buf);
++ break;
++ default:
++ err = GRUB_ERR_BAD_ARGUMENT;
++ grub_error (err, N_("Unknown TPM Command: %x"), policy->cmd_code);
++ }
++
++ return err;
++}
++
++static grub_err_t
++grub_tpm2_protector_enforce_policy_seq (tpm2key_policy_t policy_seq,
++ TPMI_SH_AUTH_SESSION session)
++{
++ tpm2key_policy_t policy;
++ grub_err_t err;
++
++ FOR_LIST_ELEMENTS (policy, policy_seq)
++ {
++ err = grub_tpm2_protector_enforce_policy (policy, session);
++ if (err != GRUB_ERR_NONE)
++ return err;
++ }
++
++ return GRUB_ERR_NONE;
++}
++
++static grub_err_t
++grub_tpm2_protector_simple_policy_seq (const struct
grub_tpm2_protector_context *ctx,
++ tpm2key_policy_t *policy_seq)
++{
++ tpm2key_policy_t policy = NULL;
++ struct grub_tpm2_buffer buf;
++ TPML_PCR_SELECTION pcr_sel = {
+ .count = 1,
+ .pcrSelections = {
+ {
@@ grub-core/tpm2/module.c (new)
+ },
+ }
+ };
++ grub_uint8_t i;
++ grub_err_t err;
++
++ if (policy_seq == NULL)
++ return GRUB_ERR_BAD_ARGUMENT;
++
++ grub_tpm2_buffer_init (&buf);
++
++ for (i = 0; i < ctx->pcr_count; i++)
++ TPMS_PCR_SELECTION_SelectPCR (&pcr_sel.pcrSelections[0],
ctx->pcrs[i]);
++
++ grub_tpm2_buffer_pack_u16 (&buf, 0);
++ grub_tpm2_mu_TPML_PCR_SELECTION_Marshal (&buf, &pcr_sel);
++
++ if (buf.error)
++ return GRUB_ERR_BAD_ARGUMENT;
++
++ policy = grub_malloc (sizeof(struct tpm2key_policy));
++ if (policy == NULL)
++ {
++ err = GRUB_ERR_OUT_OF_MEMORY;
++ goto error;
++ }
++ policy->cmd_code = TPM_CC_PolicyPCR;
++ policy->cmd_policy = grub_malloc (buf.size);
++ if (policy->cmd_policy == NULL)
++ {
++ err = GRUB_ERR_OUT_OF_MEMORY;
++ goto error;
++ }
++ grub_memcpy (policy->cmd_policy, buf.data, buf.size);
++ policy->cmd_policy_len = buf.size;
++
++ grub_list_push (GRUB_AS_LIST_P (policy_seq), GRUB_AS_LIST (policy));
++
++ return GRUB_ERR_NONE;
++
++error:
++ grub_free (policy);
++
++ return err;
++}
++
++static grub_err_t
++grub_tpm2_protector_unseal (tpm2key_policy_t policy_seq, TPM_HANDLE
sealed_handle,
++ grub_uint8_t **key, grub_size_t *key_size)
++{
+ TPMS_AUTH_COMMAND authCmd = { 0 };
-+ TPM_HANDLE sealed_key_handle;
-+ TPM2B_NAME name;
+ TPM2B_SENSITIVE_DATA data;
++ TPM2B_NONCE nonceCaller = { 0 };
++ TPMT_SYM_DEF symmetric = { 0 };
++ TPMI_SH_AUTH_SESSION session;
+ grub_uint8_t *key_out;
-+ grub_uint8_t i;
++ TPM_RC rc;
++ grub_err_t err;
++
++ 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, NULL,
&nonceCaller, NULL,
++ TPM_SE_POLICY, &symmetric, TPM_ALG_SHA256,
++ &session, NULL, NULL);
++ if (rc != TPM_RC_SUCCESS)
++ {
++ grub_error (err, N_("Failed to start auth session
(TPM2_StartAuthSession "
++ "failed with TSS/TPM error %u)"), rc);
++ goto error;
++ }
++
++ /* Enforce the policy command sequence */
++ err = grub_tpm2_protector_enforce_policy_seq (policy_seq, session);
++ if (err != GRUB_ERR_NONE)
++ goto error;
++
++ /* Unseal Sealed Key */
++ authCmd.sessionHandle = session;
++ rc = TPM2_Unseal (sealed_handle, &authCmd, &data, NULL);
++ if (rc != TPM_RC_SUCCESS)
++ {
++ grub_error (err, N_("Failed to unseal sealed key (TPM2_Unseal
failed "
++ "with TSS/TPM error %u)"), rc);
++ goto error;
++ }
++
++ /* Epilogue */
++ key_out = grub_malloc (data.size);
++ if (key_out == NULL)
++ {
++ err = GRUB_ERR_OUT_OF_MEMORY;
++ grub_error (err, N_("No memory left to allocate unlock key
buffer"));
++ goto error;
++ }
++
++ grub_memcpy (key_out, data.buffer, data.size);
++
++ *key = key_out;
++ *key_size = data.size;
++
++ err = GRUB_ERR_NONE;
++
++error:
++ TPM2_FlushContext (session);
++
++ return err;
++}
++
++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)
++{
++ TPMS_AUTH_COMMAND authCmd = { 0 };
++ TPM2_SEALED_KEY sealed_key;
++ TPM2B_NAME name;
++ void *file_bytes;
++ grub_size_t file_size;
++ TPM_HANDLE parent_handle = 0;
++ TPM_HANDLE srk_handle;
++ TPM_HANDLE sealed_handle;
++ tpm2key_policy_t policy_seq = NULL;
++ tpm2key_authpolicy_t authpol = NULL;
++ tpm2key_authpolicy_t authpol_seq = NULL;
++ TPM_RC rc;
+ grub_err_t err;
+
-+ /* Retrieve Sealed Key */
++ /*
++ * Retrieve sealed key, parent handle, policy sequence, and authpolicy
++ * sequence from the key file
++ */
+ if (ctx->tpm2key)
+ {
+ err = grub_tpm2_protector_srk_read_file (ctx->tpm2key, &file_bytes,
+ &file_size);
-+ if (err)
++ if (err != GRUB_ERR_NONE)
+ return grub_error (err, N_("Failed to read key file %s"), ctx->tpm2key);
+
+ err = grub_tpm2_protector_srk_unmarshal_tpm2key (file_bytes,
+ file_size,
++ &policy_seq,
++ &authpol_seq,
+ &parent_handle,
+ &sealed_key);
-+ if (err)
++ if (err != GRUB_ERR_NONE)
+ {
+ grub_error (err, N_("Failed to unmarshal key, ensure the key file is
in "
-+ "TPM wire format"));
++ "TPM 2.0 Key File format"));
+ goto exit1;
+ }
+ }
@@ grub-core/tpm2/module.c (new)
+ {
+ err = grub_tpm2_protector_srk_read_file (ctx->keyfile, &file_bytes,
+ &file_size);
-+ if (err)
++ if (err != GRUB_ERR_NONE)
+ return grub_error (err, N_("Failed to read key file %s"), ctx->keyfile);
+
+ parent_handle = TPM_RH_OWNER;
+ err = grub_tpm2_protector_srk_unmarshal_keyfile (file_bytes,
+ file_size,
+ &sealed_key);
-+ if (err)
++ if (err != GRUB_ERR_NONE)
+ {
+ grub_error (err, N_("Failed to unmarshal key, ensure the key file is
in "
-+ "TPM wire format"));
++ "TPM wire format"));
+ goto exit1;
+ }
+ }
+
-+ /* Get SRK */
-+ err = grub_tpm2_protector_srk_get (ctx, parent_handle, &srk_handle);
-+ if (err)
++ /*
++ * Create a basic policy sequence based on the given PCR selection if
the
++ * key file doesn't provide any policy or authpolicy sequence
++ */
++ if (policy_seq == NULL)
+ {
-+ grub_error (err, N_("Failed to retrieve the SRK"));
-+ goto exit1;
++ err = grub_tpm2_protector_simple_policy_seq (ctx, &policy_seq);
++ if (err != GRUB_ERR_NONE)
++ 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, NULL,
&nonceCaller, NULL,
-+ TPM_SE_POLICY, &symmetric, TPM_ALG_SHA256,
-+ &session, NULL, NULL);
-+ if (rc)
++ /*
++ * Append the standalone policy sequence into the authpolicy sequence as
++ * the fallback
++ */
++ authpol = grub_malloc (sizeof (struct tpm2key_authpolicy));
++ if (authpol == NULL)
+ {
-+ grub_error (err, N_("Failed to start auth session
(TPM2_StartAuthSession "
-+ "failed with TSS/TPM error %u)"), rc);
-+ goto exit2;
++ /*
++ * Free policy_seq here since it's not included in authpol_seq
++ * yet, and grub_tpm2key_free_policy_seq() won't be able to
++ * free it.
++ */
++ grub_tpm2key_free_policy_seq (policy_seq);
++ err = GRUB_ERR_OUT_OF_MEMORY;
++ goto exit1;
+ }
++ authpol->policy_seq = policy_seq;
++ grub_list_push (GRUB_AS_LIST_P (&authpol_seq), GRUB_AS_LIST (authpol));
+
-+ /* 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)
++ /* Get the SRK to unseal the sealed key */
++ err = grub_tpm2_protector_srk_get (ctx, parent_handle, &srk_handle);
++ if (err != GRUB_ERR_NONE)
+ {
-+ grub_error (err, N_("Failed to submit PCR policy (TPM2_PolicyPCR
failed "
-+ "with TSS/TPM error %u)"), rc);
-+ goto exit3;
++ grub_error (err, N_("Failed to retrieve the SRK"));
++ goto exit1;
+ }
+
-+ /* Load Sealed Key */
++ /* Load the sealed key and associate it with the SRK */
+ authCmd.sessionHandle = TPM_RS_PW;
+ rc = TPM2_Load (srk_handle, &authCmd, &sealed_key.private,
&sealed_key.public,
-+ &sealed_key_handle, &name, NULL);
-+ if (rc)
-+ {
-+ grub_error (err, N_("Failed to load sealed key (TPM2_Load failed
with "
-+ "TSS/TPM error %u)"), rc);
-+ goto exit3;
-+ }
-+
-+ /* Unseal Sealed Key */
-+ authCmd.sessionHandle = session;
-+ rc = TPM2_Unseal (sealed_key_handle, &authCmd, &data, NULL);
-+ if (rc)
++ &sealed_handle, &name, NULL);
++ if (rc != TPM_RC_SUCCESS)
+ {
-+ grub_error (err, N_("Failed to unseal sealed key (TPM2_Unseal
failed "
++ grub_error (err, N_("Failed to load sealed key (TPM2_Load failed "
+ "with TSS/TPM error %u)"), rc);
-+ goto exit4;
++ goto exit2;
+ }
+
-+ /* Epilogue */
-+ key_out = grub_malloc (data.size);
-+ if (!key_out)
++ /* Iterate the authpolicy sequence to find one that unseals the key */
++ FOR_LIST_ELEMENTS (authpol, authpol_seq)
+ {
-+ err = GRUB_ERR_OUT_OF_MEMORY;
-+ grub_error (err, N_("No memory left to allocate unlock key
buffer"));
-+ goto exit4;
++ err = grub_tpm2_protector_unseal (authpol->policy_seq,
sealed_handle,
++ key, key_size);
++ if (err == GRUB_ERR_NONE)
++ break;
+ }
+
-+ 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);
++ TPM2_FlushContext (sealed_handle);
+
+exit2:
+ TPM2_FlushContext (srk_handle);
+
+exit1:
++ grub_tpm2key_free_authpolicy_seq (authpol_seq);
+ grub_free (file_bytes);
+ return err;
+}
@@ grub-core/tpm2/module.c (new)
+static grub_err_t
+grub_tpm2_protector_recover_key (grub_uint8_t **key, grub_size_t
*key_size)
+{
-+ grub_err_t err;
-+
+ /* Expect a call to tpm2_protector_init before anybody tries to use us
*/
+ if (grub_tpm2_protector_ctx.mode == GRUB_TPM2_PROTECTOR_MODE_UNSET)
+ return grub_error (GRUB_ERR_INVALID_COMMAND,
+ N_("Cannot use TPM2 key protector without initializing "
+ "it, call tpm2_protector_init first"));
+
-+ if (!key)
++ if (key == NULL || key_size == NULL)
+ return GRUB_ERR_BAD_ARGUMENT;
+
-+ err = grub_tpm2_protector_recover (&grub_tpm2_protector_ctx, key,
key_size);
-+ if (err)
-+ return err;
-+
-+ return GRUB_ERR_NONE;
++ return grub_tpm2_protector_recover (&grub_tpm2_protector_ctx, key,
key_size);
+}
+
-+
+static grub_err_t
+grub_tpm2_protector_check_args (struct grub_tpm2_protector_context *ctx)
+{
@@ grub-core/tpm2/module.c (new)
+ ctx->mode = GRUB_TPM2_PROTECTOR_MODE_SRK;
+
+ /* Checks for SRK mode */
-+ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_SRK && !ctx->keyfile
-+ && !ctx->tpm2key)
++ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_SRK && ctx->keyfile == NULL
++ && ctx->tpm2key == NULL)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("In SRK mode, a key file must be specified: "
+ "--tpm2key/-T or --keyfile/-k"));
+
++ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_SRK && ctx->keyfile
++ && ctx->tpm2key)
++ return grub_error (GRUB_ERR_BAD_ARGUMENT,
++ N_("In SRK mode, please specify a key file with "
++ "only --tpm2key/-T or --keyfile/-k"));
++
+ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_SRK && ctx->nv)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("In SRK mode, an NV Index cannot be specified"));
+
+ /* Checks for NV mode */
-+ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_NV && !ctx->nv)
++ if (ctx->mode == GRUB_TPM2_PROTECTOR_MODE_NV && ctx->nv == 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("In NV Index mode, an NV Index must be specified: "
+ "--nvindex or -n"));
@@ grub-core/tpm2/module.c (new)
+ "specified"));
+
+ /* Defaults assignment */
-+ if (!ctx->bank)
++ if (ctx->bank == TPM_ALG_ERROR)
+ ctx->bank = TPM_ALG_SHA256;
+
-+ if (!ctx->pcr_count)
++ if (ctx->pcr_count == 0)
+ {
+ ctx->pcrs[0] = 7;
+ ctx->pcr_count = 1;
@@ grub-core/tpm2/module.c (new)
+ return GRUB_ERR_BAD_ARGUMENT;
+
+ *file = grub_strdup (value);
-+ if (!*file)
++ if (*file == NULL)
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+ N_("No memory to duplicate file path"));
+
@@ grub-core/tpm2/module.c (new)
+
+static grub_err_t
+grub_tpm2_protector_init_cmd_handler (grub_extcmd_context_t ctxt, int
argc,
-+ char **args __attribute__ ((unused)))
++ char **args __attribute__ ((unused)))
+{
+ struct grub_arg_list *state = ctxt->state;
+ grub_err_t err;
@@ grub-core/tpm2/module.c (new)
+ {
+ err = grub_tpm2_protector_parse_mode (state[OPTION_MODE].arg,
+ &grub_tpm2_protector_ctx.mode);
-+ if (err)
++ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+
@@ grub-core/tpm2/module.c (new)
+ err = grub_tpm2_protector_parse_pcrs (state[OPTION_PCRS].arg,
+ grub_tpm2_protector_ctx.pcrs,
+ &grub_tpm2_protector_ctx.pcr_count);
-+ if (err)
++ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+
@@ grub-core/tpm2/module.c (new)
+ {
+ err = grub_tpm2_protector_parse_bank (state[OPTION_BANK].arg,
+ &grub_tpm2_protector_ctx.bank);
-+ if (err)
++ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+
@@ grub-core/tpm2/module.c (new)
+ {
+ err = grub_tpm2_protector_parse_file (state[OPTION_TPM2KEY].arg,
+ &grub_tpm2_protector_ctx.tpm2key);
-+ if (err)
++ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+
@@ grub-core/tpm2/module.c (new)
+ {
+ err = grub_tpm2_protector_parse_file (state[OPTION_KEYFILE].arg,
+ &grub_tpm2_protector_ctx.keyfile);
-+ if (err)
++ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+
@@ grub-core/tpm2/module.c (new)
+ {
+ err = grub_tpm2_protector_parse_tpm_handle (state[OPTION_SRK].arg,
+ &grub_tpm2_protector_ctx.srk);
-+ if (err)
++ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+
@@ grub-core/tpm2/module.c (new)
+ {
+ err = grub_tpm2_protector_parse_asymmetric
(state[OPTION_ASYMMETRIC].arg,
+
&grub_tpm2_protector_ctx.asymmetric);
-+ if (err)
++ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+
@@ grub-core/tpm2/module.c (new)
+ {
+ err = grub_tpm2_protector_parse_tpm_handle
(state[OPTION_NVINDEX].arg,
+ &grub_tpm2_protector_ctx.nv);
-+ if (err)
++ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+
@@ grub-core/tpm2/tpm2key.c (new)
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
++#include <grub/libtasn1.h>
++#include <grub/list.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
-+#include <grub/libtasn1.h>
++#include <grub/tpm2/buffer.h>
+#include <grub/tpm2/tpm2key.h>
+
+extern asn1_static_node tpm2key_asn1_tab[];
@@ grub-core/tpm2/tpm2key.c (new)
+grub_tpm2key_get_privkey (asn1_node tpm2key, void **data, grub_size_t
*size)
+{
+ return tpm2key_get_octstring (tpm2key, "privkey", data, size);
++}
++
++/*
++ * Expected strings for CommandCode and CommandPolicy:
++ * policy.?XX.CommandCode
++ * policy.?XX.CommandPolicy
++ * authPolicy.?XX.Policy.?YY.CommandCode
++ * authPolicy.?XX.Policy.?YY.CommandPolicy
++ */
++#define CMD_CODE_MAX (sizeof ("authPolicy.?XX.Policy.?YY.CommandCode"))
++#define CMD_POL_MAX (sizeof ("authPolicy.?XX.Policy.?YY.CommandPolicy"))
++
++static int
++tpm2key_get_policy_seq (asn1_node tpm2key, const char *prefix,
++ tpm2key_policy_t *policy_seq)
++{
++ tpm2key_policy_t tmp_seq = NULL;
++ tpm2key_policy_t policy = NULL;
++ int policy_n;
++ char cmd_code[CMD_CODE_MAX];
++ char cmd_pol[CMD_POL_MAX];
++ grub_size_t cmd_policy_len;
++ int i;
++ int ret;
++
++ ret = asn1_number_of_elements (tpm2key, prefix, &policy_n);
++ if (ret != ASN1_SUCCESS)
++ return ret;
++
++ /*
++ * Limit the number of policy commands to two digits (99)
++ * Although there is no upper bound for the number of policy commands,
++ * in practice, it takes one or two policy commands to unseal the key,
++ * so the 99 commands limit is more than enough.
++ */
++ if (policy_n > 100 || policy_n < 1)
++ return ASN1_VALUE_NOT_VALID;
++
++ /*
++ * Iterate the policy commands backwards since grub_list_push() prepends
++ * the item into the list.
++ */
++ for (i = policy_n; i >= 1; i--) {
++ policy = grub_zalloc (sizeof (struct tpm2key_policy));
++ if (policy == NULL)
++ {
++ ret = ASN1_MEM_ALLOC_ERROR;
++ goto error;
++ }
++ grub_snprintf (cmd_code, CMD_CODE_MAX, "%s.?%d.CommandCode", prefix,
i);
++ grub_snprintf (cmd_pol, CMD_POL_MAX, "%s.?%d.CommandPolicy", prefix,
i);
++
++ /* CommandCode [0] EXPLICIT INTEGER */
++ ret = asn1_read_uint32 (tpm2key, cmd_code, &policy->cmd_code);
++ if (ret != ASN1_SUCCESS)
++ return ret;
++
++ /* CommandPolicy [1] EXPLICIT OCTET STRING */
++ ret = tpm2key_get_octstring (tpm2key, cmd_pol, &policy->cmd_policy,
++ &cmd_policy_len);
++ if (ret != ASN1_SUCCESS)
++ {
++ goto error;
++ }
++ else if (cmd_policy_len > GRUB_TPM2_BUFFER_CAPACITY)
++ {
++ /*
++ * CommandPolicy is the marshalled parameters for the TPM command so
++ * it should not be larger than the maximum TPM2 buffer.
++ */
++ ret = ASN1_VALUE_NOT_VALID;
++ goto error;
++ }
++ policy->cmd_policy_len = (grub_uint16_t)cmd_policy_len;
++
++ /* Prepend the policy command into the sequence */
++ grub_list_push (GRUB_AS_LIST_P (&tmp_seq), GRUB_AS_LIST (policy));
++ }
++
++ *policy_seq = tmp_seq;
++
++ return ASN1_SUCCESS;
++
++error:
++ if (policy)
++ {
++ grub_free (policy->cmd_policy);
++ grub_free (policy);
++ }
++ grub_tpm2key_free_policy_seq (tmp_seq);
++
++ return ret;
++}
++
++grub_err_t
++grub_tpm2key_get_policy_seq (asn1_node tpm2key, tpm2key_policy_t
*policy_seq)
++{
++ int ret;
++
++ ret = tpm2key_get_policy_seq (tpm2key, "policy", policy_seq);
++ if (ret == ASN1_ELEMENT_NOT_FOUND)
++ {
++ /* "policy" is optional, so it may not be available */
++ *policy_seq = NULL;
++ return GRUB_ERR_NONE;
++ }
++ else if (ret != ASN1_SUCCESS)
++ {
++ return GRUB_ERR_READ_ERROR;
++ }
++
++ return GRUB_ERR_NONE;
++}
++
++void
++grub_tpm2key_free_policy_seq (tpm2key_policy_t policy_seq)
++{
++ tpm2key_policy_t policy;
++ tpm2key_policy_t next;
++
++ if (policy_seq == NULL)
++ return;
++
++ FOR_LIST_ELEMENTS_SAFE (policy, next, policy_seq)
++ {
++ grub_free (policy->cmd_policy);
++ grub_free (policy);
++ }
++}
++
++#define AUTHPOLICY_POL_MAX (sizeof ("authPolicy.?XX.Policy"))
++
++grub_err_t
++grub_tpm2key_get_authpolicy_seq (asn1_node tpm2key, tpm2key_authpolicy_t
*authpol_seq)
++{
++ tpm2key_authpolicy_t tmp_seq = NULL;
++ tpm2key_authpolicy_t authpol = NULL;
++ int authpol_n;
++ char authpol_pol[AUTHPOLICY_POL_MAX];
++ int i;
++ int ret;
++ grub_err_t err;
++
++ ret = asn1_number_of_elements (tpm2key, "authPolicy", &authpol_n);
++ if (ret == ASN1_ELEMENT_NOT_FOUND)
++ {
++ /* "authPolicy" is optional, so it may not be available */
++ *authpol_seq = NULL;
++ return GRUB_ERR_NONE;
++ }
++ else if (ret != ASN1_SUCCESS)
++ {
++ return GRUB_ERR_READ_ERROR;
++ }
++
++ /* Limit the number of authPolicy elements to two digits (99) */
++ if (authpol_n > 100 || authpol_n < 1)
++ return GRUB_ERR_OUT_OF_RANGE;
++
++ /*
++ * Iterate the authPolicy elements backwards since grub_list_push()
prepends
++ * the item into the list.
++ */
++ for (i = authpol_n; i >= 1; i--) {
++ authpol = grub_zalloc (sizeof (struct tpm2key_authpolicy));
++ if (authpol == NULL)
++ {
++ err = GRUB_ERR_OUT_OF_MEMORY;
++ goto error;
++ }
++ grub_snprintf (authpol_pol, AUTHPOLICY_POL_MAX,
"authPolicy.?%d.Policy", i);
++
++ ret = tpm2key_get_policy_seq (tpm2key, authpol_pol,
&authpol->policy_seq);
++ if (ret != ASN1_SUCCESS)
++ {
++ err = GRUB_ERR_READ_ERROR;
++ goto error;
++ }
++
++ /* Prepend the authPolicy element into the sequence */
++ grub_list_push (GRUB_AS_LIST_P (&tmp_seq), GRUB_AS_LIST (authpol));
++ }
++
++ *authpol_seq = tmp_seq;
++
++error:
++ if (authpol)
++ {
++ grub_tpm2key_free_policy_seq (authpol->policy_seq);
++ grub_free (authpol);
++ }
++
++ grub_tpm2key_free_authpolicy_seq (tmp_seq);
++
++ return err;
++}
++
++void
++grub_tpm2key_free_authpolicy_seq (tpm2key_authpolicy_t authpol_seq)
++{
++ tpm2key_authpolicy_t authpol;
++ tpm2key_authpolicy_t next;
++
++ if (authpol_seq == NULL)
++ return;
++
++ FOR_LIST_ELEMENTS_SAFE (authpol, next, authpol_seq)
++ {
++ grub_tpm2key_free_policy_seq (authpol->policy_seq);
++ grub_free (authpol);
++ }
+}
## grub-core/tpm2/tpm2key_asn1_tab.c (new) ##
@@
++/*
++ * This file is generated by 'asn1Parser tpm2key.asn' and the '#include'
++ * headers are replaced with the ones in grub2.
++ * - 'grub/mm.h' for the definition of 'NULL'
++ * - 'grub/libtasn1.h' for the definition of 'asn1_static_node'
++ */
++
+#include <grub/mm.h>
+#include <grub/libtasn1.h>
+
@@ include/grub/tpm2/tpm2key.h (new)
+#include <grub/types.h>
+#include <grub/libtasn1.h>
+
++/*
++ * TPMPolicy ::= SEQUENCE {
++ * CommandCode [0] EXPLICIT INTEGER,
++ * CommandPolicy [1] EXPLICIT OCTET STRING
++ * }
++ */
++struct tpm2key_policy {
++ struct tpm2key_policy *next;
++ struct tpm2key_policy **prev;
++ grub_uint32_t cmd_code;
++ void *cmd_policy;
++ grub_uint16_t cmd_policy_len;
++};
++typedef struct tpm2key_policy *tpm2key_policy_t;
++
++/*
++ * TPMAuthPolicy ::= SEQUENCE {
++ * Name [0] EXPLICIT UTF8String OPTIONAL,
++ * Policy [1] EXPLICIT SEQUENCE OF TPMPolicy
++ * }
++ *
++ * Name is not a necessary part to unseal the key. Ignore it.
++ */
++struct tpm2key_authpolicy {
++ struct tpm2key_authpolicy *next;
++ struct tpm2key_authpolicy **prev;
++ /* char *name; */
++ tpm2key_policy_t policy_seq;
++};
++typedef struct tpm2key_authpolicy *tpm2key_authpolicy_t;
++
+grub_err_t
+grub_tpm2key_start_parsing (asn1_node *parsed_tpm2key, void *data,
grub_size_t size);
+
@@ include/grub/tpm2/tpm2key.h (new)
+grub_err_t
+grub_tpm2key_get_privkey (asn1_node tpm2key, void **data, grub_size_t
*size);
+
++grub_err_t
++grub_tpm2key_get_policy_seq (asn1_node tpm2key, tpm2key_policy_t
*policy_seq);
++
++void
++grub_tpm2key_free_policy_seq (tpm2key_policy_t policy_seq);
++
++grub_err_t
++grub_tpm2key_get_authpolicy_seq (asn1_node tpm2key, tpm2key_authpolicy_t
*authpol_seq);
++
++void
++grub_tpm2key_free_authpolicy_seq (tpm2key_authpolicy_t authpol_seq);
++
+#endif /* GRUB_TPM2_TPM2KEY_HEADER */
4: 609f2c6e4 ! 11: 9ad473fd8 cryptodisk: Support key protectors
@@ grub-core/disk/cryptodisk.c: static const struct grub_arg_option
options[] =
};
@@ grub-core/disk/cryptodisk.c: grub_cryptodisk_scan_device_real (const
char *name,
- {
grub_err_t ret = GRUB_ERR_NONE;
grub_cryptodisk_t dev;
-- grub_cryptodisk_dev_t cr;
-+ grub_cryptodisk_dev_t cr, crd = NULL;
+ grub_cryptodisk_dev_t cr;
+ int i;
struct cryptodisk_read_hook_ctx read_hook_data = {0};
int askpass = 0;
@@ grub-core/disk/cryptodisk.c: grub_cryptodisk_scan_device_real (const
char *name,
goto error_no_close;
if (!dev)
continue;
-+ crd = cr;
+ break;
+ }
@@ grub-core/disk/cryptodisk.c: grub_cryptodisk_scan_device_real (const
char *name,
+ if (!dev)
+ {
+ grub_error (GRUB_ERR_BAD_MODULE,
-+ "no cryptodisk module can handle this device");
++ "no cryptodisk module can handle this device");
+ goto error_no_close;
+ }
@@ grub-core/disk/cryptodisk.c: grub_cryptodisk_scan_device_real (const
char *name,
+ if (cargs->protectors)
+ {
+ for (i = 0; cargs->protectors[i]; i++)
-+ {
-+ if (cargs->key_cache[i].invalid)
-+ continue;
-+
-+ if (!cargs->key_cache[i].key)
-+ {
-+ ret = grub_key_protector_recover_key (cargs->protectors[i],
-+
&cargs->key_cache[i].key,
-+
&cargs->key_cache[i].key_len);
-+ if (ret)
-+ {
-+ if (grub_errno)
-+ {
-+ grub_print_error ();
-+ grub_errno = GRUB_ERR_NONE;
-+ }
++ {
++ if (cargs->key_cache[i].invalid)
++ continue;
+
-+ grub_dprintf ("cryptodisk",
-+ "failed to recover a key from key
protector "
-+ "%s, will not try it again for any other "
-+ "disks, if any, during this invocation of
"
-+ "cryptomount\n",
-+ cargs->protectors[i]);
++ if (!cargs->key_cache[i].key)
++ {
++ ret = grub_key_protector_recover_key (cargs->protectors[i],
++ &cargs->key_cache[i].key,
++
&cargs->key_cache[i].key_len);
++ if (ret != GRUB_ERR_NONE)
++ {
++ if (grub_errno)
++ {
++ grub_print_error ();
++ grub_errno = GRUB_ERR_NONE;
++ }
+
-+ cargs->key_cache[i].invalid = 1;
-+ continue;
-+ }
-+ }
++ grub_dprintf ("cryptodisk",
++ "failed to recover a key from key protector "
++ "%s, will not try it again for any other "
++ "disks, if any, during this invocation of "
++ "cryptomount\n",
++ cargs->protectors[i]);
+
-+ cargs->key_data = cargs->key_cache[i].key;
-+ cargs->key_len = cargs->key_cache[i].key_len;
++ cargs->key_cache[i].invalid = 1;
++ continue;
++ }
++ }
+
-+ ret = crd->recover_key (source, dev, cargs);
-+ if (ret)
-+ {
-+ part = grub_partition_get_name (source->partition);
-+ grub_dprintf ("cryptodisk",
-+ "recovered a key from key protector %s but it
"
-+ "failed to unlock %s%s%s (%s)\n",
-+ cargs->protectors[i], source->name,
-+ source->partition != NULL ? "," : "",
-+ part != NULL ? part : N_("UNKNOWN"),
dev->uuid);
-+ grub_free (part);
-+ continue;
-+ }
-+ else
-+ {
-+ ret = grub_cryptodisk_insert (dev, name, source);
-+ if (ret != GRUB_ERR_NONE)
-+ goto error;
-+ goto cleanup;
-+ }
-+ }
++ cargs->key_data = cargs->key_cache[i].key;
++ cargs->key_len = cargs->key_cache[i].key_len;
- ret = grub_cryptodisk_insert (dev, name, source);
- if (ret != GRUB_ERR_NONE)
++ ret = cr->recover_key (source, dev, cargs);
++ if (ret != GRUB_ERR_NONE)
++ {
++ part = grub_partition_get_name (source->partition);
++ grub_dprintf ("cryptodisk",
++ "recovered a key from key protector %s but it "
++ "failed to unlock %s%s%s (%s)\n",
++ cargs->protectors[i], source->name,
++ source->partition != NULL ? "," : "",
++ part != NULL ? part : N_("UNKNOWN"), dev->uuid);
++ grub_free (part);
++ continue;
++ }
++ else
++ {
++ ret = grub_cryptodisk_insert (dev, name, source);
++ if (ret != GRUB_ERR_NONE)
++ goto error;
++ goto cleanup;
++ }
++ }
++
+ part = grub_partition_get_name (source->partition);
+ grub_error (GRUB_ERR_ACCESS_DENIED,
-+ N_("no key protector provided a usable key for %s%s%s
(%s)"),
-+ source->name, source->partition != NULL ? "," : "",
-+ part != NULL ? part : N_("UNKNOWN"), dev->uuid);
++ N_("no key protector provided a usable key for %s%s%s (%s)"),
++ source->name, source->partition != NULL ? "," : "",
++ part != NULL ? part : N_("UNKNOWN"), dev->uuid);
+ grub_free (part);
goto error;
+ }
@@ grub-core/disk/cryptodisk.c: grub_cryptodisk_scan_device_real (const
char *name,
+ askpass = 1;
+ part = grub_partition_get_name (source->partition);
+ grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "),
source->name,
-+ source->partition != NULL ? "," : "",
-+ part != NULL ? part : N_("UNKNOWN"), dev->uuid);
++ source->partition != NULL ? "," : "",
++ part != NULL ? part : N_("UNKNOWN"), dev->uuid);
+ grub_free (part);
+
+ cargs->key_data = grub_malloc (GRUB_CRYPTODISK_MAX_PASSPHRASE);
+ if (cargs->key_data == NULL)
-+ goto error;
++ goto error;
+
+ if (!grub_password_get ((char *) cargs->key_data,
GRUB_CRYPTODISK_MAX_PASSPHRASE))
-+ {
-+ grub_error (GRUB_ERR_BAD_ARGUMENT, "passphrase not supplied");
-+ goto error;
-+ }
++ {
++ grub_error (GRUB_ERR_BAD_ARGUMENT, "passphrase not supplied");
++ goto error;
++ }
+ cargs->key_len = grub_strlen ((char *) cargs->key_data);
+ }
+
-+ ret = crd->recover_key (source, dev, cargs);
++ ret = cr->recover_key (source, dev, cargs);
+ if (ret != GRUB_ERR_NONE)
+ goto error;
+
@@ grub-core/disk/cryptodisk.c: grub_cryptodisk_scan_device (const char
*name,
+{
+ int i;
+
-+ if (!cargs->key_cache)
++ if (cargs->key_cache == NULL || cargs->protectors == NULL)
+ return;
+
+ for (i = 0; cargs->protectors[i]; i++)
@@ grub-core/disk/cryptodisk.c: grub_cmd_cryptomount (grub_extcmd_context_t
ctxt, i
+ if (state[OPTION_PASSWORD].set && state[OPTION_PROTECTOR].set) /*
password and key protector */
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
-+ "a password and a key protector cannot both be
set");
++ "a password and a key protector cannot both be set");
+
if (state[OPTION_PASSWORD].set) /* password */
{
@@ grub-core/disk/cryptodisk.c: grub_cmd_cryptomount (grub_extcmd_context_t
ctxt, i
+ {
+ cargs.key_cache = grub_zalloc (state[OPTION_PROTECTOR].set * sizeof
(*cargs.key_cache));
+ if (!cargs.key_cache)
-+ return grub_error (GRUB_ERR_OUT_OF_MEMORY,
-+ "no memory for key protector key cache");
++ return grub_error (GRUB_ERR_OUT_OF_MEMORY,
++ "no memory for key protector key cache");
+ cargs.protectors = state[OPTION_PROTECTOR].args;
+ }
+
@@ grub-core/disk/cryptodisk.c: grub_cmd_cryptomount (grub_extcmd_context_t
ctxt, i
dev = grub_cryptodisk_get_by_uuid (args[0]);
if (dev)
{
-+ grub_cryptodisk_clear_key_cache (&cargs);
++ grub_cryptodisk_clear_key_cache (&cargs);
grub_dprintf ("cryptodisk",
"already mounted as crypto%lu\n", dev->id);
return GRUB_ERR_NONE;
@@ grub-core/disk/cryptodisk.c: grub_cmd_cryptomount (grub_extcmd_context_t
ctxt, i
disk = grub_disk_open (diskname);
if (!disk)
{
-+ grub_cryptodisk_clear_key_cache (&cargs);
++ grub_cryptodisk_clear_key_cache (&cargs);
if (disklast)
*disklast = ')';
return grub_errno;
@@ grub-core/disk/cryptodisk.c: grub_cmd_cryptomount (grub_extcmd_context_t
ctxt, i
{
grub_dprintf ("cryptodisk", "already mounted as crypto%lu\n",
dev->id);
grub_disk_close (disk);
-+ grub_cryptodisk_clear_key_cache (&cargs);
++ grub_cryptodisk_clear_key_cache (&cargs);
if (disklast)
*disklast = ')';
return GRUB_ERR_NONE;
@@ include/grub/cryptodisk.h: typedef gcry_err_code_t
+ grub_uint8_t *key;
+ grub_size_t key_len;
+
-+ /* The key protector associated with this cache entry failed, so avoid
it
-+ * even if the cached entry (an instance of this structure) is empty. */
++ /*
++ * The key protector associated with this cache entry failed, so avoid
it
++ * even if the cached entry (an instance of this structure) is empty.
++ */
+ int invalid;
+};
+
5: 8547f130d ! 12: aa6210c44 util/grub-protect: Add new tool
@@ util/grub-protect.c (new)
+ void *buf;
+
+ f = fopen (filepath, "rb");
-+ if (!f)
++ if (f == NULL)
+ return GRUB_ERR_FILE_NOT_FOUND;
+
+ if (fseek (f, 0, SEEK_END))
@@ util/grub-protect.c (new)
+ }
+
+ len = ftell (f);
-+ if (!len)
++ if (len == 0)
+ {
+ err = GRUB_ERR_FILE_READ_ERROR;
+ goto exit1;
@@ util/grub-protect.c (new)
+ rewind (f);
+
+ buf = grub_malloc (len);
-+ if (!buf)
++ if (buf == NULL)
+ {
+ err = GRUB_ERR_OUT_OF_MEMORY;
+ goto exit1;
@@ util/grub-protect.c (new)
+ FILE *f;
+
+ f = fopen (filepath, "wb");
-+ if (!f)
++ if (f == NULL)
+ return GRUB_ERR_FILE_NOT_FOUND;
+
+ if (fwrite (buffer, buffer_size, 1, f) != 1)
@@ util/grub-protect.c (new)
+ int n;
+
+ grub_path = grub_canonicalize_file_name (filepath);
-+ if (!grub_path)
++ if (grub_path == NULL)
+ goto exit1;
+
+ devices = grub_guess_root_devices (grub_path);
-+ if (!devices || !devices[0])
++ if (devices == NULL || devices[0] == NULL)
+ goto exit2;
+
+ disk = devices[0];
@@ util/grub-protect.c (new)
+ grub_util_pull_device (disk);
+
+ grub_dev = grub_util_get_grub_dev (disk);
-+ if (!grub_dev)
++ if (grub_dev == NULL)
+ goto exit3;
+
+ dev = grub_device_open (grub_dev);
-+ if (!dev)
++ if (dev == NULL)
+ goto exit4;
+
+ efi_drive = grub_util_guess_efi_drive (disk);
-+ if (!efi_drive)
++ if (efi_drive == NULL)
+ goto exit5;
+
+ partition = grub_partition_get_name (dev->disk->partition);
-+ if (!partition)
++ if (partition == NULL)
+ goto exit6;
+
+ grub_drive_len = grub_strlen (efi_drive) + grub_strlen (partition) + 3;
+ grub_drive = grub_malloc (grub_drive_len + 1);
-+ if (!grub_drive)
++ if (grub_drive == NULL)
+ goto exit7;
+
+ n = grub_snprintf (grub_drive, grub_drive_len + 1, "(%s,%s)", efi_drive,
@@ util/grub-protect.c (new)
+grub_err_t
+grub_tcg2_get_max_output_size (grub_size_t *size)
+{
-+ if (!size)
++ if (size == NULL)
+ return GRUB_ERR_BAD_ARGUMENT;
+
+ *size = GRUB_TPM2_BUFFER_CAPACITY;
@@ util/grub-protect.c (new)
+ return GRUB_ERR_NONE;
+
+ err = close (grub_protector_tpm2_fd);
-+ if (err)
++ if (err != GRUB_ERR_NONE)
+ {
+ fprintf (stderr, _("Could not close TPM device (Error: %u).\n"),
errno);
+ return GRUB_ERR_IO;
@@ util/grub-protect.c (new)
+
+ /* PCR Read */
+ for (i = 0; i < args->tpm2_pcr_count; i++)
-+ pcr_sel
-+ .pcrSelections[0]
-+ .pcrSelect[TPM2_PCR_TO_SELECT(args->tpm2_pcrs[i])]
-+ |= TPM2_PCR_TO_BIT(args->tpm2_pcrs[i]);
++ TPMS_PCR_SELECTION_SelectPCR (&pcr_sel.pcrSelections[0],
args->tpm2_pcrs[i]);
+
+ rc = TPM2_PCR_Read (NULL, &pcr_sel, NULL, &pcr_sel_out, &pcr_values,
NULL);
+ if (rc != TPM_RC_SUCCESS)
@@ util/grub-protect.c (new)
+
+ pcr_concat_len = pcr_digest_len * args->tpm2_pcr_count;
+ pcr_concat = grub_malloc (pcr_concat_len);
-+ if (!pcr_concat)
++ if (pcr_concat == NULL)
+ {
+ err = GRUB_ERR_OUT_OF_MEMORY;
+ fprintf (stderr, _("Failed to allocate PCR concatenation
buffer.\n"));
@@ util/grub-protect.c (new)
+extern asn1_static_node tpm2key_asn1_tab[];
+
+static grub_err_t
-+grub_protect_tpm2_export_tpm2key (const char *filepath,
++grub_protect_tpm2_export_tpm2key (const struct grub_protect_args *args,
+ TPM2_SEALED_KEY *sealed_key)
+{
+ const char *sealed_key_oid = "2.23.133.10.1.5";
+ asn1_node asn1_def = NULL;
+ asn1_node tpm2key = NULL;
+ grub_uint32_t parent;
++ grub_uint32_t cmd_code;
++ struct grub_tpm2_buffer pol_buf;
++ TPML_PCR_SELECTION pcr_sel = {
++ .count = 1,
++ .pcrSelections = {
++ {
++ .hash = args->tpm2_bank,
++ .sizeOfSelect = 3,
++ .pcrSelect = { 0 }
++ },
++ }
++ };
+ struct grub_tpm2_buffer pub_buf;
+ struct grub_tpm2_buffer priv_buf;
+ void *der_buf = NULL;
+ int der_buf_size = 0;
++ int i;
+ int ret;
+ grub_err_t err;
+
++ for (i = 0; i < args->tpm2_pcr_count; i++)
++ TPMS_PCR_SELECTION_SelectPCR (&pcr_sel.pcrSelections[0],
args->tpm2_pcrs[i]);
++
++ /*
++ * Prepare the parameters for TPM_CC_PolicyPCR:
++ * empty pcrDigest and the user selected PCRs
++ */
++ grub_tpm2_buffer_init (&pol_buf);
++ grub_tpm2_buffer_pack_u16 (&pol_buf, 0);
++ grub_tpm2_mu_TPML_PCR_SELECTION_Marshal (&pol_buf, &pcr_sel);
++
+ grub_tpm2_buffer_init (&pub_buf);
+ grub_tpm2_mu_TPM2B_PUBLIC_Marshal (&pub_buf, &sealed_key->public);
+ grub_tpm2_buffer_init (&priv_buf);
+ grub_tpm2_mu_TPM2B_Marshal (&priv_buf, sealed_key->private.size,
+ sealed_key->private.buffer);
-+ if (pub_buf.error || priv_buf.error)
++ if (pub_buf.error != 0 || priv_buf.error != 0)
+ return GRUB_ERR_BAD_ARGUMENT;
+
+ ret = asn1_array2tree (tpm2key_asn1_tab, &asn1_def, NULL);
@@ util/grub-protect.c (new)
+ goto error;
+ }
+
-+ /* Remove 'policy' */
-+ ret = asn1_write_value (tpm2key, "policy", NULL, 0);
++ /* Set 'policy' */
++ ret = asn1_write_value (tpm2key, "policy", "NEW", 1);
++ if (ret != ASN1_SUCCESS)
++ {
++ err = GRUB_ERR_BAD_ARGUMENT;
++ goto error;
++ }
++ cmd_code = grub_cpu_to_be32 (TPM_CC_PolicyPCR);
++ ret = asn1_write_value (tpm2key, "policy.?LAST.CommandCode", &cmd_code,
++ sizeof (cmd_code));
++ if (ret != ASN1_SUCCESS)
++ {
++ err = GRUB_ERR_BAD_ARGUMENT;
++ goto error;
++ }
++ ret = asn1_write_value (tpm2key, "policy.?LAST.CommandPolicy",
&pol_buf.data,
++ pol_buf.size);
+ if (ret != ASN1_SUCCESS)
+ {
+ err = GRUB_ERR_BAD_ARGUMENT;
@@ util/grub-protect.c (new)
+ goto error;
+ }
+
-+ err = grub_protect_write_file (filepath, der_buf, der_buf_size);
-+ if (err)
++ err = grub_protect_write_file (args->tpm2_outfile, der_buf,
der_buf_size);
++ if (err != GRUB_ERR_NONE)
+ fprintf (stderr, _("Could not write tpm2key file (Error: %u).\n"),
+ errno);
+
@@ util/grub-protect.c (new)
+ grub_tpm2_mu_TPM2B_PUBLIC_Marshal (&buf, &sealed_key->public);
+ grub_tpm2_mu_TPM2B_Marshal (&buf, sealed_key->private.size,
+ sealed_key->private.buffer);
-+ if (buf.error)
++ if (buf.error != 0)
+ return GRUB_ERR_BAD_ARGUMENT;
+
+ err = grub_protect_write_file (filepath, buf.data, buf.size);
-+ if (err)
++ if (err != GRUB_ERR_NONE)
+ fprintf (stderr, _("Could not write sealed key file (Error: %u).\n"),
+ errno);
+
@@ util/grub-protect.c (new)
+ grub_protect_get_grub_drive_for_file (args->tpm2_outfile, &grub_drive);
+
+ err = grub_protect_tpm2_open_device (args->tpm2_device);
-+ if (err)
++ if (err != GRUB_ERR_NONE)
+ return err;
+
+ err = grub_protect_read_file (args->tpm2_keyfile, (void **)&key,
&key_size);
-+ if (err)
++ if (err != GRUB_ERR_NONE)
+ goto exit1;
+
+ if (key_size > TPM_MAX_SYM_DATA)
@@ util/grub-protect.c (new)
+ }
+
+ err = grub_protect_tpm2_get_srk (args, &srk);
-+ if (err)
++ if (err != GRUB_ERR_NONE)
+ goto exit2;
+
+ err = grub_protect_tpm2_get_policy_digest (args, &policy_digest);
-+ if (err)
++ if (err != GRUB_ERR_NONE)
+ goto exit3;
+
+ err = grub_protect_tpm2_seal (&policy_digest, srk, key, key_size,
+ &sealed_key);
-+ if (err)
++ if (err != GRUB_ERR_NONE)
+ goto exit3;
+
+ if (args->tpm2_tpm2key)
-+ err = grub_protect_tpm2_export_tpm2key (args->tpm2_outfile,
&sealed_key);
++ err = grub_protect_tpm2_export_tpm2key (args, &sealed_key);
+ else
+ err = grub_protect_tpm2_export_sealed_key (args->tpm2_outfile,
&sealed_key);
-+ if (err)
++ if (err != GRUB_ERR_NONE)
+ goto exit3;
+
+ if (grub_drive)
@@ util/grub-protect.c (new)
+ TPMS_AUTH_COMMAND authCommand = { 0 };
+ grub_err_t err;
+
-+ if (!args->tpm2_evict)
++ if (args->tpm2_evict == 0)
+ {
+ printf (_("--tpm2-evict not specified, nothing to do.\n"));
+ return GRUB_ERR_NONE;
+ }
+
+ err = grub_protect_tpm2_open_device (args->tpm2_device);
-+ if (err)
++ if (err != GRUB_ERR_NONE)
+ return err;
+
+ /* Find SRK */
@@ util/grub-protect.c (new)
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
-+ if (!args->tpm2_keyfile)
++ if (args->tpm2_keyfile == NULL)
+ {
+ fprintf (stderr, _("--tpm2-keyfile must be specified.\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
-+ if (!args->tpm2_outfile)
++ if (args->tpm2_outfile == NULL)
+ {
+ fprintf (stderr, _("--tpm2-outfile must be specified.\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
-+ if (!args->tpm2_device)
++ if (args->tpm2_device == NULL)
+ args->tpm2_device = "/dev/tpm0";
+
-+ if (!args->tpm2_pcr_count)
++ if (args->tpm2_pcr_count == 0)
+ {
+ args->tpm2_pcrs[0] = 7;
+ args->tpm2_pcr_count = 1;
+ }
+
-+ if (!args->tpm2_srk)
++ if (args->tpm2_srk == 0)
+ args->tpm2_srk = TPM2_SRK_HANDLE;
+
-+ if (!args->tpm2_asymmetric)
++ if (args->tpm2_asymmetric == TPM_ALG_ERROR)
+ args->tpm2_asymmetric = TPM_ALG_RSA;
+
-+ if (!args->tpm2_bank)
++ if (args->tpm2_bank == TPM_ALG_ERROR)
+ args->tpm2_bank = TPM_ALG_SHA256;
+
+ break;
@@ util/grub-protect.c (new)
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
-+ if (!args->tpm2_device)
++ if (args->tpm2_device == NULL)
+ args->tpm2_device = "/dev/tpm0";
+
-+ if (!args->tpm2_srk)
++ if (args->tpm2_srk == 0)
+ args->tpm2_srk = TPM2_SRK_HANDLE;
+
+ break;
@@ util/grub-protect.c (new)
+
+ err = grub_tpm2_protector_parse_pcrs (arg, args->tpm2_pcrs,
+ &args->tpm2_pcr_count);
-+ if (err)
++ if (err != GRUB_ERR_NONE)
+ {
-+ if (grub_errno)
++ if (grub_errno != GRUB_ERR_NONE)
+ grub_print_error ();
+ return EINVAL;
+ }
@@ util/grub-protect.c (new)
+ }
+
+ err = grub_tpm2_protector_parse_tpm_handle (arg, &args->tpm2_srk);
-+ if (err)
++ if (err != GRUB_ERR_NONE)
+ {
-+ if (grub_errno)
++ if (grub_errno != GRUB_ERR_NONE)
+ grub_print_error ();
+ return EINVAL;
+ }
@@ util/grub-protect.c (new)
+ }
+
+ err = grub_tpm2_protector_parse_asymmetric (arg,
&args->tpm2_asymmetric);
-+ if (err)
++ if (err != GRUB_ERR_NONE)
+ {
-+ if (grub_errno)
++ if (grub_errno != GRUB_ERR_NONE)
+ grub_print_error ();
+ return EINVAL;
+ }
@@ util/grub-protect.c (new)
+ }
+
+ err = grub_tpm2_protector_parse_bank (arg, &args->tpm2_bank);
-+ if (err)
++ if (err != GRUB_ERR_NONE)
+ {
-+ if (grub_errno)
++ if (grub_errno != GRUB_ERR_NONE)
+ grub_print_error ();
+ return EINVAL;
+ }
@@ util/grub-protect.c (new)
+ grub_protect_init (&argc, &argv);
+
+ err = grub_protect_args_verify (&args);
-+ if (err)
++ if (err != GRUB_ERR_NONE)
+ goto exit;
+
+ err = grub_protect_dispatch (&args);
-+ if (err)
++ if (err != GRUB_ERR_NONE)
+ goto exit;
+
+exit:
--
2.35.3
- [PATCH v3 00/12] Automatic Disk Unlock with TPM2,
Gary Lin <=
- [PATCH v3 05/12] libtasn1: compile into asn1 module, Gary Lin, 2023/04/12
- [PATCH v3 04/12] libtasn1: changes for grub compatibility, Gary Lin, 2023/04/12
- [PATCH v3 06/12] test_asn1: test module for libtasn1, Gary Lin, 2023/04/12
- [PATCH v3 07/12] libtasn1: Add the documentation, Gary Lin, 2023/04/12
- [PATCH v3 03/12] libtasn1: disable code not needed in grub, Gary Lin, 2023/04/12
- [PATCH v3 08/12] protectors: Add key protectors framework, Gary Lin, 2023/04/12
- [PATCH v3 09/12] tpm2: Add TPM Software Stack (TSS), Gary Lin, 2023/04/12
- [PATCH v3 02/12] libtasn1: import libtasn1-4.19.0, Gary Lin, 2023/04/12
- [PATCH v3 01/12] posix_wrap: tweaks in preparation for libtasn1, Gary Lin, 2023/04/12
- [PATCH v3 10/12] protectors: Add TPM2 Key Protector, Gary Lin, 2023/04/12