Skip to content
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

Add a lot of policy and NV commands to TPMDirect #272

Merged
merged 2 commits into from
Feb 26, 2022
Merged

Add a lot of policy and NV commands to TPMDirect #272

merged 2 commits into from
Feb 26, 2022

Conversation

chrisfenner
Copy link
Member

@chrisfenner chrisfenner commented Feb 19, 2022

This PR introduces a helper called PolicyCalculator for calculating TPM policies. Every Policy TPM command now implements an interface called PolicyCommand for updating a PolicyCalculator. This allows TPM policies to be found without using trial sessions in a TPM.

This PR updates existing TPM command Execute functions to simply return error values when the response structure is empty. To support the reflection logic (and future likely auditing logic), all the empty response structure definitions still have to exist, but we just won't return them to callers, who will 100% of the time assign them to _.

This PR fixes a couple of typos and missed error conditions. The most interesting of these fixes is that Execute will now remind the user when they forgot to add an authorization to an AuthHandle, instead of panicking.

This PR also adds the following 22 commands into TPMDirect, approximately doubling the number of supported commands in TPMDirect to 47 out of the 122 commands in the latest TPM specification:

  • Shutdown
  • Startup
  • VerifySignature
  • PCR_Extend
  • PCR_Event
  • PolicySigned
  • PolicyOR
  • PolicyCommandCode
  • PolicyCPHash
  • PolicyAuthorize
  • PolicyGetDigest
  • PolicyNVWritten
  • PolicyAuthorizeNV
  • NV_DefineSpace
  • NV_UndefineSpace
  • NV_UndefineSpaceSpecial
  • NV_ReadPublic
  • NV_Write
  • NV_WriteLock
  • NV_Read
  • LoadExternal
  • CreateLoaded

LoadExternal was added because VerifySignature isn't very useful without it, and CreateLoaded was added because it (like LoadExternal) has an "optional" command parameter that needs to be handled correctly. "Optional" parameters are 2Bs that can contain nothing, even if what they normally contain does not have a legal empty serialization: LoadExternal accepts one "optional" and CreateLoaded returns one "optional" - together, their implementation validates the special logic required for these parameters.

This change modifies the templates in the templates package to have type tpmt.Public instead of tpm2b.Public. This is so that they can be used for the contents of tpm2b.Template as needed by CreateLoaded.

This change introduces 2 actual go interfaces for some very special types where, to preserve backwards compatibility, the TPM spec introduced new alternative serializations of existing types for CreateLoaded:

  • the contents of tpm2b.Template can be either classic tpmt.Public or a slightly modified version, which I have generified as tpmu.Template
  • the contents of tpms.SensitiveCreate can be either classic tpm2b.SensitiveData or the label/context pairing in tpm2b.Derive, which I have generified as tpmu.SensitiveCreate.

These special pseudo-unions need to be assignable from both the "classic" types as well as the special ones depending on the context of CreateLoaded. Making them into interfaces allows callers to write both of these:

tpm2.CreateLoaded{
	InPublic: tpm2b.Template{
		Template: tpmt.Public{
			...

and

tpm2.CreateLoaded{
	InPublic: tpm2b.Template{
		Template: tpmt.Template{
			...

This increases the boilerplate for the types, doesn't offer unmarshalling logic, and would be frustrating to scale over time if this weren't a highly special case for this one command. However in this one case, it greatly improves the ergonomics over the alternatives I can think of (for example, making tpm2b.Template contain two pointer members and documenting for users that they should only fill one in).

Fun fact about this change: to add the first 20 commands (as well as some other helper functionality), we only needed 300 lines of new structure types, and 600 lines of new command types and methods, and all 900 of these lines were extremely rote, boilerplate implementations. Extrapolating this data (45 lines per command), it should take around 3500 more lines of boilerplate code to implement the rest of the spec. CreateLoaded and LoadExternal required a bit more changes to the marshalling logic, because they introduce "optional" parameters (no other commands have these).

@chrisfenner chrisfenner marked this pull request as ready for review February 19, 2022 21:22
@chrisfenner chrisfenner requested a review from a team as a code owner February 19, 2022 21:22
@chrisfenner
Copy link
Member Author

@josephlr @alexmwu @jkl73 Feel free to take a look here at your convenience; I'm not in any particular hurry to merge this.

@chrisfenner chrisfenner added the tpmdirect Issues specific to the tpmdirect development work label Feb 19, 2022
@chrisfenner chrisfenner merged commit 340f1e8 into google:tpmdirect Feb 26, 2022
@chrisfenner
Copy link
Member Author

I made the mistake of having both google/go-tpm and my own fork as remotes with same branch names in the same repo at the same time, and accidentally pushed the work to the google tpmdirect branch when I meant to update this PR. I apologize for the mistake, it won't happen again. Feel free to raise any issues with these changes using the tpmdirect Issues specific to the tpmdirect development work label.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
tpmdirect Issues specific to the tpmdirect development work
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant