joholl / rpi4-uboot-tpm

How to use a TPM in U-Boot on Raspberry Pi 4
Apache License 2.0
82 stars 17 forks source link

tpm2 init is not working with uboot with these instructions. #1

Closed svundru closed 4 years ago

svundru commented 4 years ago

I tried these instructions(https://github.com/joholl/rpi4-uboot-tpm ) on raspberry pi 4. tpm2 init gives me error message "Could not set TPM 0 (rc = 1). any pointers would be appreciated.

joholl commented 4 years ago

Sorry for the late response.

First and foremost, check your U-Boot commit. In July 2020, the TPM TIS driver compatible changed, breaking all custom device trees using the TPM, including this one. The compatible changed from tis,tpm2-spi to tcg,tpm_tis-spi.

Thus, if your U-Boot is newer than July 2020, you have to change the compatible in the device tree. Adding tcg,tpm_tis-spi should suffice.

https://github.com/joholl/rpi4-uboot-tpm/blob/3d256c604658c131ecd3810136b7d3d7a273ee70/tpm-soft-spi.dts#L35

If that does not solve your problem, you can increase the log level in the U-Boot configuration menu (make menuconfig). If you need, write the output into a file. To catch driver issues, search for tpm and look out for the compatible. Basically, U-Boot looks at the device tree (loaded by the closed-source Raspberry Pi bootloader). When it sees the compatible, it searches for drivers with the same compatible and loads them.

If you cannot find the compatible in your logging output, maybe the Raspberry Pi bootloader is not loading your device tree overlay (tpm-soft-spi.dtbo). In this case, check if you added the correct lines to /boot/config.txt.

Thank you for reporting this issue. I have fixed it in 3d256c604. Please let me know if that fixed your problem.

svundru commented 4 years ago

Thanks for the response. I did this change after few trail and error and it is working for me now. I have another question, I am planning to add TPM2SetPrimaryPolicy() command to my uboot, this is not part of default u-boot. This command needs a auth session. Do you have any idea if someone on u-boot already working on these commands or is there a development brnach with these commands implemented on u-boot?

svundru commented 4 years ago

Also how do this soft spi driver from ST micro TPM2?

joholl commented 4 years ago

To my knowledge there is no official support. However, you are lucky, I have a patch lying around because I needed this command myself. I did not have the time to upstream it, yet. I added a patch at the end. I hope this compiles, as I did not test it.

What do you mean by your second question?

diff --git a/cmd/tpm-v2.c b/cmd/tpm-v2.c
index e6742656f5..658ad48f3e 100644
--- a/cmd/tpm-v2.c
+++ b/cmd/tpm-v2.c
@@ -354,6 +354,55 @@ static int do_tpm_pcr_setauthvalue(struct cmd_tbl *cmdtp, int flag,
                            key, key_sz));
 }

+static int do_tpm2_setprimarypolicy(struct cmd_tbl *cmdtp, int flag,
+                   int argc, char * const argv[])
+{
+   u32 handle;
+   void *auth_policy = map_sysmem(simple_strtoul(argv[2], NULL, 0), 0);
+   const char *pw = (argc == 3) ? NULL : argv[3];
+   const ssize_t pw_sz = pw ? strlen(pw) : 0;
+   struct udevice *dev;
+   int ret;
+   u32 rc;
+
+   ret = get_tpm(&dev);
+   if (ret) {
+       rc = ret;
+       goto unmap_auth_policy;
+   }
+
+   if (argc < 3 || argc > 4) {
+       rc = CMD_RET_USAGE;
+       goto unmap_auth_policy;
+   }
+
+   if (pw_sz > TPM2_DIGEST_LEN) {
+       rc = -EINVAL;
+       goto unmap_auth_policy;
+   }
+
+   if (!strcasecmp("TPM2_RH_LOCKOUT", argv[1]))
+       handle = TPM2_RH_LOCKOUT;
+   else if (!strcasecmp("TPM2_RH_ENDORSEMENT", argv[1]))
+       handle = TPM2_RH_ENDORSEMENT;
+   else if (!strcasecmp("TPM2_RH_OWNER", argv[1]))
+       handle = TPM2_RH_OWNER;
+   else if (!strcasecmp("TPM2_RH_PLATFORM", argv[1]))
+       handle = TPM2_RH_PLATFORM;
+   else {
+       rc = CMD_RET_USAGE;
+       goto unmap_auth_policy;
+   }
+
+unmap_auth_policy:
+   unmap_sysmem(auth_policy);
+
+   return report_return_code(tpm2_setprimarypolicy(dev, pw, pw_sz, handle,
+                 auth_policy));
+}
+
 static struct cmd_tbl tpm2_commands[] = {
    U_BOOT_CMD_MKENT(device, 0, 1, do_tpm_device, "", ""),
    U_BOOT_CMD_MKENT(info, 0, 1, do_tpm_info, "", ""),
@@ -367,6 +416,8 @@ static struct cmd_tbl tpm2_commands[] = {
    U_BOOT_CMD_MKENT(dam_reset, 0, 1, do_tpm_dam_reset, "", ""),
    U_BOOT_CMD_MKENT(dam_parameters, 0, 1, do_tpm_dam_parameters, "", ""),
    U_BOOT_CMD_MKENT(change_auth, 0, 1, do_tpm_change_auth, "", ""),
+   U_BOOT_CMD_MKENT(setprimarypolicy, 0, 1,
+            do_tpm2_setprimarypolicy, "", ""),
    U_BOOT_CMD_MKENT(pcr_setauthpolicy, 0, 1,
             do_tpm_pcr_setauthpolicy, "", ""),
    U_BOOT_CMD_MKENT(pcr_setauthvalue, 0, 1,
@@ -435,6 +486,10 @@ U_BOOT_CMD(tpm2, CONFIG_SYS_MAXARGS, 1, do_tpm, "Issue a TPMv2.x command",
 "    <hierarchy>: the hierarchy\n"
 "    <new_pw>: new password for <hierarchy>\n"
 "    <old_pw>: optional previous password of <hierarchy>\n"
+"setprimarypolicy <hierarchy> <authpolicy_addr> [<password>]\n"
+"    <hierarchy>: handle to the hierarchy\n"
+"    <authpolicy_addr>: memory address to a 32-byte SHA256 authPolicy digest\n"
+"    <password>: optional password of <hierarchy>\n"
 "pcr_setauthpolicy|pcr_setauthvalue <pcr> <key> [<password>]\n"
 "    Change the <key> to access PCR #<pcr>.\n"
 "    hierarchy and may be empty.\n"
diff --git a/include/tpm-v2.h b/include/tpm-v2.h
index d53d2e4023..ef2b15d0f4 100644
--- a/include/tpm-v2.h
+++ b/include/tpm-v2.h
@@ -339,4 +339,20 @@ u32 tpm2_pcr_setauthvalue(struct udevice *dev, const char *pw,
              const ssize_t pw_sz, u32 index, const char *key,
              const ssize_t key_sz);

+/**
+/**
+ * Issue a TPM_SetPrimaryPolicy command.
+ *
+ * @dev        TPM device
+ * @pw     Password
+ * @pw_sz  Length of the password
+ * @auth_handle    Handle of the entity whose authPolicy is to be set
+ * @auth_policy    New authPolicy digest
+ *
+ * @return code of the operation
+ */
+u32 tpm2_setprimarypolicy(struct udevice *dev, const char *pw,
+             const ssize_t pw_sz, u32 auth_handle,
+             const uint8_t *auth_policy);
+
 #endif /* __TPM_V2_H */
diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c
index 5a039f65d1..e76df55026 100644
--- a/lib/tpm-v2.c
+++ b/lib/tpm-v2.c
@@ -422,3 +422,50 @@ u32 tpm2_pcr_setauthvalue(struct udevice *dev, const char *pw,

    return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
 }
+
+u32 tpm2_setprimarypolicy(struct udevice *dev, const char *pw,
+             const ssize_t pw_sz, u32 auth_handle,
+             const uint8_t *auth_policy)
+{
+   u8 command_v2[COMMAND_BUFFER_SIZE] = {
+       tpm_u16(TPM2_ST_SESSIONS),      /* TAG */
+       tpm_u32(63 + pw_sz),            /* Length */
+       tpm_u32(TPM2_CC_SETPRIMARYPOLICY),  /* Command code */
+
+       /* HANDLE */
+       tpm_u32(auth_handle),           /* authHandle */
+
+       /* AUTH_SESSION */
+       tpm_u32(9 + pw_sz),         /* Authorization size */
+       tpm_u32(TPM2_RS_PW),            /* session handle */
+       tpm_u16(0),             /* Size of <nonce> */
+                           /* <nonce> (if any) */
+       0,                  /* Attributes: Cont/Excl/Rst */
+       tpm_u16(pw_sz),             /* Size of <hmac/password> */
+       /* STRING(pw)                   <hmac/password> (if any) */
+
+       /* TPM2B_DIGEST                 authPolicy */
+       /* tpm_u16(TPM2_ALG_SHA256)         hashAlg */
+   };
+   unsigned int offset = 27;
+   int ret;
+
+   /*
+    * Fill the command structure starting from the first buffer:
+    *     - the password (if any)
+    *     - the timeout in seconds
+    */
+   ret = pack_byte_string(command_v2, sizeof(command_v2), "swsw",
+                  offset, pw, pw_sz,
+                  offset + pw_sz, TPM2_DIGEST_LEN,
+                  offset + pw_sz + sizeof(u16), auth_policy,
+                  TPM2_DIGEST_LEN,
+                  offset + pw_sz + sizeof(u16) + TPM2_DIGEST_LEN,
+                  TPM2_ALG_SHA256);
+   offset += pw_sz + sizeof(u16) + TPM2_DIGEST_LEN + sizeof(u16);
+
+   if (ret)
+       return TPM_LIB_ERROR;
+
+   return tpm_sendrecv_command(dev, command_v2, NULL, NULL);
+}
svundru commented 4 years ago

Thanks for the quick response. I will integrate this and let you know how it goes.

Regarding my second question, I tried the following device tree change on infineion TPM2 and that worked for me. I need to make the ST micro TPM2 chip work on uboot with my raspbery pi. what changes I need to make to device tree and soft spi driver code to make it work on ST Micro TPM2 ? compatible = "infineon,slb9670", "tis,tpm2-spi", "tcg,tpm_tis-spi"; devuce

joholl commented 4 years ago

As long as your TPM uses SPI, it should probably work you. I have tested this with an Infineon SLB9670 only.

svundru commented 4 years ago

Thanks, I will try on ST micro TPM2.

svundru commented 4 years ago

I see the following compilation error:

CC cmd/tpm-v2.o cmd/tpm-v2.c: In function ‘do_tpm2_setprimarypolicy’: cmd/tpm-v2.c:393:12: error: ‘TPM2_RH_ACT0’ undeclared (first use in this function); did you mean ‘TPM2_RC_FMT1’? handle = TPM2_RH_ACT0; ^~~~ TPM2_RC_FMT1 cmd/tpm-v2.c:393:12: note: each undeclared identifier is reported only once for each function it appears in scripts/Makefile.build:265: recipe for target 'cmd/tpm-v2.o' failed make[1]: [cmd/tpm-v2.o] Error 1 Makefile:1780: recipe for target 'cmd' failed make: [cmd] Error 2

joholl commented 4 years ago

I see, my bad. I edited the patch. Should be fixed now. You can simply remove the case for the act.

svundru commented 4 years ago

thx, I see more compile errors:

CC lib/tpm-v2.o In file included from lib/tpm-v2.c:12:0: lib/tpm-v2.c: In function ‘tpm2_setprimarypolicy’: lib/tpm-v2.c:477:11: error: ‘TPM2_CC_SETPRIMARYPOLICY’ undeclared (first use in this function); did you mean ‘TPM2_CC_GET_CAPABILITY’? tpm_u32(TPM2_CC_SETPRIMARYPOLICY), / Command code / ^ lib/tpm-utils.h:16:20: note: in definition of macro ‘__MSB’

define __MSB(x) ((x) >> 8)

                ^

lib/tpm-utils.h:19:20: note: in expansion of macro ‘tpm_u16’

define tpm_u32(x) tpm_u16((x) >> 16), tpm_u16((x) & 0xFFFF)

                ^~~~~~~

lib/tpm-v2.c:477:3: note: in expansion of macro ‘tpm_u32’ tpm_u32(TPM2_CC_SETPRIMARYPOLICY), / Command code / ^~~ lib/tpm-v2.c:477:11: note: each undeclared identifier is reported only once for each function it appears in tpm_u32(TPM2_CC_SETPRIMARYPOLICY), / Command code / ^ lib/tpm-utils.h:16:20: note: in definition of macro ‘__MSB’

define __MSB(x) ((x) >> 8)

                ^

lib/tpm-utils.h:19:20: note: in expansion of macro ‘tpm_u16’

define tpm_u32(x) tpm_u16((x) >> 16), tpm_u16((x) & 0xFFFF)

                ^~~~~~~

lib/tpm-v2.c:477:3: note: in expansion of macro ‘tpm_u32’ tpm_u32(TPM2_CC_SETPRIMARYPOLICY), / Command code / ^~~ scripts/Makefile.build:265: recipe for target 'lib/tpm-v2.o' failed make[1]: [lib/tpm-v2.o] Error 1 Makefile:1780: recipe for target 'lib' failed make: [lib] Error 2

svundru commented 4 years ago

it compiles with this diff: --- a/include/tpm-v2.h +++ b/include/tpm-v2.h @@ -82,6 +82,7 @@ enum tpm2_command_codes { TPM2_CC_CLEARCONTROL = 0x0127, TPM2_CC_CLEARCONTROL = 0x0127, TPM2_CC_HIERCHANGEAUTH = 0x0129, TPM2_CC_PCR_SETAUTHPOL = 0x012C,

joholl commented 4 years ago

Nice, I hope I could help. Closing this issue.

svundru commented 4 years ago

what does it takes to make these instructions work on Raspberry pi model 3 with infenion TPM2?

joholl commented 4 years ago

Should be the same. I tested this with an Infineon SLB9670, so the only variable would be the Raspberry Pi 3. You should be able to use 64-bit software there, as well.

svundru commented 4 years ago

Ok, thanks. I will work on RPI3 to see if it works for me.