google / go-tpm-tools

Go packages built on go-tpm providing a high-level API for using TPMs
Apache License 2.0
225 stars 71 forks source link

Support seal/unseal operation with a password #34

Open jkl73 opened 5 years ago

jkl73 commented 5 years ago

Current seal/unseal operations in tpm2tools only check PCRs. We should support the operation with a user specified password. So users can seal the secret to not only PCRs but also a password.

Foxboron commented 3 years ago

I'm contemplating hacking a bit on this as I need the signer interface. Is there any preferred ways to approach this?

jkl73 commented 3 years ago

Hi, the reason we didn't implement this in the first place is that, even though it is possible to add a password as an authorization, we think it is better to encrypt the data by yourself with a password (so no TPM needed, maybe using AEAD), and then seal the encrypted blob using the seal operation with the TPM. We fell like they can achieve the same result (though one advantage of TPM password auth is that it can provide certain dictionary attack protection, TPM will lock out for some time after few wrong password attempts). What's your use case?

Foxboron commented 3 years ago

I'm trying to seal private RSA key material in the TPM to create a x509 cert from it. Having PCR support and password support would make things better since the private key material never leaves the TPM.

A POC for this code is here without the PCR sealing and stuff.

https://github.com/Foxboron/go-uefi/blob/morten/tpm/cmd/gotpm/main.go

It's for having better key generation backends for sbctl, https://github.com/Foxboron/sbctl

jkl73 commented 3 years ago

IIUC, you wan to create a Secure Boot key using TPM. In the POC, since you created a primary key using tpm2.HandleEndorsement, you have already made sure that the private key won't leave the TPM.

Sealing the key with the PCR/password ensure that you can sign new EFI binaries iff the machine is in a good know state/you have the correct password. Is that what you want?

Foxboron commented 3 years ago

Sealing the key with the PCR/password ensure that you can sign new EFI binaries iff the machine is in a good know state/you have the correct password. Is that what you want?

Correct :)

Foxboron commented 3 years ago
 func NewKey(rw io.ReadWriter, parent tpmutil.Handle, template tpm2.Public) (k *Key, err error) {
+       return NewKeyWithPcr(rw, parent, template, tpm2.PCRSelection{})
+}
+
+func NewKeyWithPcr(rw io.ReadWriter, parent tpmutil.Handle, template tpm2.Public, pcr tpm2.PCRSelection) (k *Key, err error) {
+       return NewKeyWithPassword(rw, parent, template, pcr, "", "")
+}
+
+func NewKeyWithPassword(rw io.ReadWriter, parent tpmutil.Handle, template tpm2.Public, pcr tpm2.PCRSelection, parentPassword, ownerPassword string) (k *Key, err error) {
        if !isHierarchy(parent) {
                // TODO add support for normal objects with Create() and Load()
                return nil, fmt.Errorf("unsupported parent handle: %x", parent)
        }

        handle, pubArea, _, _, _, _, err :=
-               tpm2.CreatePrimaryEx(rw, parent, tpm2.PCRSelection{}, "", "", template)
+               tpm2.CreatePrimaryEx(rw, parent, pcr, parentPassword, ownerPassword, template)
        if err != nil {
                return nil, err
        }

I think something like this would solve the issue without introducing any new complexities in the codebase?

jkl73 commented 3 years ago

password can be added as ownerPassword here which is straightforward. However I think the PCR field in the CreatePrimaryEx is for the creation data. In order to have the PCR auth for the key, we probably need to use the PCRSessionAuth we did for the Seal function. https://github.com/google/go-tpm-tools/blob/70c4d48316ea5e19a2e25930a2575eba3c808600/client/keys.go#L237