google / go-tpm

Apache License 2.0
540 stars 156 forks source link

Basic Sealing and Unsealing #246

Open tobuh opened 3 years ago

tobuh commented 3 years ago

I know the example for complete seal and unsealing workflow, including policies. However, just simple tpm2.Seal() und tpm2.Unseal() does not work. For example, I would expect the following to work:

rwc, err := tpm2.OpenTPM("/dev/tpm0")
if err != nil {
  log.Fatal(err)
}
defer rwc.Close()

secret := []byte("test")

srkHandle := tpmutil.Handle(0x81000001)

privSeal, pubSeal, err := tpm2.Seal(rwc, srkHandle, "", "", nil, secret)
if err != nil {
  log.Fatal(err.Error())
}

sealHandle, _, err := tpm2.Load(rwc, srkHandle, "", pubSeal, privSeal)
if err != nil {
  log.Fatal(err.Error())
}
unsealed, err := tpm2.Unseal(rwc, sealHandle, "")
if err != nil {
  log.Fatal(err.Error())
}

log.Print(string(unsealed))

But I receive this error: error code 0x2f : authValue or authPolicy is not available for selected entity

I would expect something similar (and compatible) to this:

echo test | tpm2_create -u test.pub -r test.priv -i- -C 0x81000001
tpm2_load -C 0x81000001 -u test.pub -r test.priv -c test.ctx
tpm2_unseal -c test.ctx

Is there something I do wrong?

chrisfenner commented 3 years ago

I don't think the current implementation of Seal supports unsealing without policy:

https://github.com/google/go-tpm/blob/d3310770bfec97b19d08524b63c458c3487d0d93/tpm2/tpm2.go#L575-L580

Since userWithAuth is not set, the sealed data blob can only be authorized by policy (which is unsatisfiable if nil was passed)

I propose that we improve Seal by adding userWithAuth if a nil policy was provided, as there is otherwise no way to unseal the data. However, opaquely relaxing the security properties of the API is something we should be careful about. What say ye, @twitchy-jsonp / @josephlr ?

chrisfenner commented 3 years ago

Alternative: deprecate go-tpm's Seal entirely because there is no TPM2_Seal command. Instead, we should expose a flexible enough TPM2_Create to allow the creation of sealed data blobs.

(Why is there no TPM2_Seal command? Because a sealed blob is just another type of TPM object, which can always be created either by the TPM itself with TPM2_Create or off-box, encrypted and imported under a Storage key with TPM2_Import.)

tobuh commented 3 years ago

@chrisfenner Thanks for the reply and the explanations.

I don't think there are any security issues added, as currently it would be possible to unseal by:

tpm2_load -C 0x81000001 -u test.pub -r test.priv -c test.ctx
tpm2_startauthsession --policy-session -S session.dat
tpm2_policypassword -S session.dat
tpm2_unseal -c test.ctx -p session:session.dat+""

So there is no security difference from my perspective. It is also a question of usability. And I think it is always a good idea to be as compatible as possible to tpm2-tools.

Remark: I manually added FlagUserWithAuth, but it does not seem to work that simple.

josephlr commented 3 years ago

@chrisfenner I think deprecating Seal in this library would be the best bet. It has issues that we can't likely fix in a backwards compatible way. In go-tpm-tools, we had to use CreateKeyWithSensitive rather than Seal to get things to work correctly. We should just recommend users use that method instead. Something like:

inPublic := tpm2.Public{
    Type:       tpm2.AlgKeyedHash,
    NameAlg:    sessionHashAlgTpm,
    Attributes: tpm2.FlagFixedTPM | tpm2.FlagFixedParent | tpm2.FlagUserWithAuth,
    AuthPolicy: nil,
}
private, public, _, _, _, err := tpm2.CreateKeyWithSensitive(rw, parentHandle, PCRSelection{}, "", "", inPublic, sensitive)
// Check err
// Store private/public

And I think it is always a good idea to be as compatible as possible to tpm2-tools.

@tobuh I would say that this library seeks to (eventually) have parity with the TCG's ESAPI which is part of tpm2-tss (which is in turn used by tpm2-tools).

If you want a higher-level API that makes this sealing stuff easier, we have go-tpm-tools which tries to provide a smaller, easier to use API (but with reduced functionality). Would go-tpm-tools/client.Seal work for your use case?