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

tpm2: try a transient primary key if the sealed key object fails to load for any reason #207

Open
chrisccoulson opened this issue Aug 15, 2022 · 2 comments

Comments

@chrisccoulson
Copy link
Collaborator

chrisccoulson commented Aug 15, 2022

The TPM unsealing code will fall back to trying with a transient primary key if the initial unsealing attempt with the persistent primary key fails in some cases - if the TPM2_Load command fails with a handle error, indicating that the supplied parent handle is not a valid storage key.

But it fails immediately if TPM2_Load returns a TPM_RC_INTEGRITY error for the inPrivate parameter, which may indicate that although the parent handle corresponds to a valid storage key, it may not be the correct parent key. This might happen if other software that uses the TPM evicts the primary key we create during install and then creates a new one with a non-standard template.

The unsealing code should probably adopt a belt and braces approach to error handling here and fall back to trying with a transient primary key if the TPM2_Load command fails for any reason, rather than implementing handling that is specific to each error type. I would also extend the existing error handling to work like this:

  • Initial try with the persistent shared SRK at the well-known handle (0x81000001).
  • If that fails, try every persistent key on the TPM.
  • If that fails, try creating a transient SRK.
@sespiros
Copy link
Collaborator

sespiros commented Sep 6, 2022

Latest secboot version in snapd:

	github.com/snapcore/secboot v0.0.0-20211018143212-802bb19ca263

In the case of a TPM_RC_INTEGRITY error, the first if case will be followed, as isLoadInvalidParamError catches all errors for all parameters, and unsealing will proceed using a transient SRK normally:

secboot/tpm2/unseal.go

Lines 80 to 86 in 802bb19

// Load the key data
keyObject, err := k.load(tpm, srk, session)
if isLoadInvalidParamError(err) || isImportInvalidParamError(err) {
// The supplied key data is invalid or is not protected by the supplied SRK.
lastError = InvalidKeyDataError{
fmt.Sprintf("cannot load sealed key object into TPM: %v. Either the sealed key object is bad or the TPM owner has changed", err)}
continue

secboot/tpm2/utils.go

Lines 48 to 52 in 802bb19

// isLoadInvalidParamError indicates whether the specified error is a TPM error associated with an invalid param
// supplied to a TPM2_Load command.
func isLoadInvalidParamError(err error) bool {
return tpm2.IsTPMParameterError(err, tpm2.AnyErrorCode, tpm2.CommandLoad, tpm2.AnyParameterIndex)
}

@chrisccoulson
Copy link
Collaborator Author

Thanks for taking a look at this - so I've actually misunderstood my own code and probably the issue that started me looking at this. I think it would probably still be a good idea to implement trying with other persistent keys on the TPM.

sespiros added a commit to sespiros/secboot that referenced this issue Sep 23, 2022
loadForUnseal() will now try all the persistent SRKs stored in NV
before falling back to creating a transient SRK. Any errors during
that process are returned as an ErrTPMProvisioning error to the
caller.

This resolves snapcore#207.
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

No branches or pull requests

2 participants