Skip to content

Create individual packages for Windows and Linux TPM transport #369

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Sep 19, 2024

Conversation

chrisfenner
Copy link
Member

@chrisfenner chrisfenner commented Sep 18, 2024

#364 called to attention some long-standing technical debt around TPM transport. In particular, the stack looks like:

(Linux or Windows) OpenTPM function
calls the legacy OpenTPM function
calls the tpmutil OpenTPM function

At the bottom of the stack, tpmutil does some runtime introspection to see what type of TPM it wants to open (e.g., on Linux, the device could be either a device file or a socket). This runtime support is convenient, but also breaks dead-code elimination (for example, tinygo will fail to compile the UDS support code, and users have no way of leaving that out without patches).

In principle, we've found within Google that "open my TPM" should be as un-smart as possible, to avoid awkward edge cases (for example, what happens if the logic finds two different TPMs on the system; which should it prefer; should it invisibly succeed and surprise the user?). Instead, the preferred pattern is to require the user to explicitly say which TPM they are trying to open.

This change introduces 3 packages as a replacement for transport.OpenTPM (which this change marks as now Deprecated):

  • transport/linuxtpm.Open(path) opens Linux device TPMs (e.g., /dev/tpm0 or /dev/tpmrm0)
  • transport/windowstpm.Open() opens the TPM from TBS.dll

I reverted the proposed transport/linuxudstpm.Open() because upon testing it against IBM's swtpm project (very helpful notes: https://ejaaskel.dev/yocto-emulation-setting-up-qemu-with-tpm/), I got the following errors which imply that the UDS protocol is not simply "send TPM commands the same as you would to the device file":

Test failure:

helper.go:43: GetCapability() = unexpected EOF

Simulator logs:

 Ctrl Cmd: length 22
 80 01 00 00 00 16 00 00 01 7A 00 00 00 06 00 00
 01 05 00 00 00 01
Error: Unknown command: 0x80010000
 Ctrl Rsp: length 4
 00 00 00 0A

The legacy transport.OpenTPM function failed with the same issue.

Intentionally, the now-deprecated transport.OpenTPM is not touched. This would create an import cycle.

TESTED:
windowstpm.Open on a Windows system with a TPM.
linuxtpm.Open with both /dev/tpm0 and /dev/tpmrm0 on a Linux system with a TPM
linuxudstpm.Open with the IBM simulator running with

swtpm socket --tpmstate dir=/tmp/mytpm1   --ctrl type=unixio,path=/tmp/mytpm1/swtpm-sock --server type=unixio,path=/tmp/mytpm1/tpm-sock  --tpm2   --log level=20 --flags not-need-init,startup-clear

google#364 called to attention some
long-standing technical debt around TPM transport. In particular, the
stack looks like:

(Linux or Windows) `OpenTPM` function
calls the legacy `OpenTPM` function
calls the tpmutil `OpenTPM` function

At the bottom of the stack, tpmutil does some runtime introspection to
see what type of TPM it wants to open (e.g., on Linux, the device could
be either a device file or a socket). This runtime support is
convenient, but also breaks dead-code elimination (for example, tinygo
will fail to compile the UDS support code, and users have no way of
leaving that out without patches).

In principle, we've found within Google that "open my TPM" should be as
un-smart as possible, to avoid awkward edge cases (for example, what
happens if the logic finds two different TPMs on the system; which
should it prefer; should it invisibly succeed and surprise the user?).
Instead, the preferred pattern is to require the user to explicitly say
which TPM they are trying to open.

This change introduces 3 packages as a replacement for
`transport.OpenTPM` (which this change marks as now Deprecated):

`transport/linuxtpm.Open(path)` opens Linux device TPMs (e.g., /dev/tpm0 or
/dev/tpmrm0)
`transport/linuxudstpm.Open(path)` opens Linux Unix Domain Socket TPMs
`transport/windowstpm.Open()` opens the TPM from TBS.dll

Intentionally, the now-deprecated `transport.OpenTPM` is not touched.
This would create an import cycle.
Copy link
Contributor

@alexmwu alexmwu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really nice clean up!

Copy link

@leongross leongross left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested it out in said u-root commands from PR #364 with tinygo and the prior issues seem to be resolved. Thanks a lot for taking care of the improved implementation. This will help us a lot!

@chrisfenner chrisfenner merged commit d96ccf7 into google:main Sep 19, 2024
4 checks passed
@chrisfenner chrisfenner deleted the new-transports branch September 19, 2024 18:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants