Skip to content

Commit

Permalink
Implement TPM2_ObjectChangeAuth (#354)
Browse files Browse the repository at this point in the history
Signed-off-by: Morten Linderud <morten@linderud.pw>
  • Loading branch information
Foxboron authored Apr 11, 2024
1 parent 6b2397c commit dac860f
Show file tree
Hide file tree
Showing 2 changed files with 241 additions and 0 deletions.
212 changes: 212 additions & 0 deletions tpm2/test/object_change_auth_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
package tpm2test

import (
"bytes"
"errors"
"testing"

. "github.com/google/go-tpm/tpm2"
"github.com/google/go-tpm/tpm2/transport/simulator"
)

func TestObjectChangeAuth(t *testing.T) {
thetpm, err := simulator.OpenSimulator()
if err != nil {
t.Fatalf("could not connect to TPM simulator: %v", err)
}
defer thetpm.Close()

// Create the SRK
// Put a password on the SRK to test more of the flows.
createSRKCmd := CreatePrimary{
PrimaryHandle: TPMRHOwner,
InSensitive: TPM2BSensitiveCreate{
Sensitive: &TPMSSensitiveCreate{
UserAuth: TPM2BAuth{
Buffer: []byte(nil),
},
},
},
InPublic: New2B(ECCSRKTemplate),
}
createSRKRsp, err := createSRKCmd.Execute(thetpm)
if err != nil {
t.Fatalf("%v", err)
}
defer func() {
// Flush the SRK
flushSRKCmd := FlushContext{FlushHandle: createSRKRsp.ObjectHandle}
if _, err := flushSRKCmd.Execute(thetpm); err != nil {
t.Errorf("%v", err)
}
}()

// Data we are sealing
data := []byte("secrets")

// Original auth for the key
auth := []byte("oldauth")

// New auth we are changing to
newauth := []byte("newauth")

// Create a sealed blob under the SRK
createBlobCmd := Create{
ParentHandle: AuthHandle{
Handle: createSRKRsp.ObjectHandle,
Name: createSRKRsp.Name,
Auth: PasswordAuth(nil),
},
InSensitive: TPM2BSensitiveCreate{
Sensitive: &TPMSSensitiveCreate{
UserAuth: TPM2BAuth{
Buffer: auth,
},
Data: NewTPMUSensitiveCreate(&TPM2BSensitiveData{
Buffer: data,
}),
},
},
InPublic: New2B(TPMTPublic{
Type: TPMAlgKeyedHash,
NameAlg: TPMAlgSHA256,
ObjectAttributes: TPMAObject{
FixedTPM: true,
FixedParent: true,
UserWithAuth: true,
NoDA: true,
},
}),
}

var createBlobRsp *CreateResponse

t.Run("Create", func(t *testing.T) {
createBlobRsp, err = createBlobCmd.Execute(thetpm)
if err != nil {
t.Fatalf("%v", err)
}
})

loadBlobCmd := Load{
ParentHandle: AuthHandle{
Handle: createSRKRsp.ObjectHandle,
Name: createSRKRsp.Name,
Auth: PasswordAuth(nil),
},
InPrivate: createBlobRsp.OutPrivate,
InPublic: createBlobRsp.OutPublic,
}
loadBlobRsp, err := loadBlobCmd.Execute(thetpm)
if err != nil {
t.Fatalf("%v", err)
}
defer func() {
// Flush the blob
flushBlobCmd := FlushContext{FlushHandle: loadBlobRsp.ObjectHandle}
if _, err := flushBlobCmd.Execute(thetpm); err != nil {
t.Errorf("%v", err)
}
}()

unsealCmd := Unseal{
ItemHandle: NamedHandle{
Handle: loadBlobRsp.ObjectHandle,
Name: loadBlobRsp.Name,
},
}

// Unseal the blob with a password session
t.Run("WithPassword", func(t *testing.T) {
unsealCmd.ItemHandle = AuthHandle{
Handle: loadBlobRsp.ObjectHandle,
Name: loadBlobRsp.Name,
Auth: PasswordAuth(auth),
}
unsealRsp, err := unsealCmd.Execute(thetpm)
if err != nil {
t.Errorf("%v", err)
}
if !bytes.Equal(unsealRsp.OutData.Buffer, data) {
t.Errorf("want %x got %x", data, unsealRsp.OutData.Buffer)
}
})

// Change the auth of the object
t.Run("ObjectChangeAuth", func(t *testing.T) {
oca := ObjectChangeAuth{
ObjectHandle: AuthHandle{
Handle: loadBlobRsp.ObjectHandle,
Name: loadBlobRsp.Name,
Auth: PasswordAuth(auth),
},
ParentHandle: NamedHandle{
Handle: createSRKRsp.ObjectHandle,
Name: createSRKRsp.Name,
},
NewAuth: TPM2BAuth{
Buffer: newauth,
},
}

ocaRsp, err := oca.Execute(thetpm)
if err != nil {
t.Fatalf("failed objectchangeauthrequest: %v", err)
}

// Flush the old handle
flushBlobCmd := FlushContext{FlushHandle: loadBlobRsp.ObjectHandle}
if _, err := flushBlobCmd.Execute(thetpm); err != nil {
t.Errorf("%v", err)
}

// Load the new private blob, and the old public blob
loadBlobCmd := Load{
ParentHandle: AuthHandle{
Handle: createSRKRsp.ObjectHandle,
Name: createSRKRsp.Name,
Auth: PasswordAuth(nil),
},
InPrivate: ocaRsp.OutPrivate,
InPublic: createBlobRsp.OutPublic,
}
loadBlobRsp, err = loadBlobCmd.Execute(thetpm)
if err != nil {
t.Fatalf("%v", err)
}
})

// Unseal the blob with a password session
t.Run("WithOldPassword", func(t *testing.T) {
unsealCmd.ItemHandle = AuthHandle{
Handle: loadBlobRsp.ObjectHandle,
Name: loadBlobRsp.Name,
Auth: PasswordAuth(auth),
}
_, err := unsealCmd.Execute(thetpm)
if !errors.Is(err, TPMRCBadAuth) {
t.Errorf("want TPM_RC_BAD_AUTH, got %v", err)
}
var fmt1 TPMFmt1Error
if !errors.As(err, &fmt1) {
t.Errorf("want a Fmt1Error, got %v", err)
} else if isSession, session := fmt1.Session(); !isSession || session != 1 {
t.Errorf("want TPM_RC_BAD_AUTH on session 1, got %v", err)
}
})

t.Run("WithNewPassword", func(t *testing.T) {
unsealCmd.ItemHandle = AuthHandle{
Handle: loadBlobRsp.ObjectHandle,
Name: loadBlobRsp.Name,
Auth: PasswordAuth(newauth),
}
unsealRsp, err := unsealCmd.Execute(thetpm)
if err != nil {
t.Errorf("%v", err)
}
if !bytes.Equal(unsealRsp.OutData.Buffer, data) {
t.Errorf("want %x got %x", data, unsealRsp.OutData.Buffer)
}
})
}
29 changes: 29 additions & 0 deletions tpm2/tpm2.go
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,35 @@ type UnsealResponse struct {
OutData TPM2BSensitiveData
}

// ObjectChangeAuth is the input to TPM2_ObjectChangeAuth.
// See definition in Part 3, Commands, section 12.8
type ObjectChangeAuth struct {
// TPM handle of an object
ObjectHandle handle `gotpm:"handle,auth"`
// handle of the parent
ParentHandle handle `gotpm:"handle"`
// new authorization value
NewAuth TPM2BAuth
}

// Command implements the Command interface.
func (ObjectChangeAuth) Command() TPMCC { return TPMCCObjectChangeAuth }

// Execute executes the command and returns the response.
func (cmd ObjectChangeAuth) Execute(t transport.TPM, s ...Session) (*ObjectChangeAuthResponse, error) {
var rsp ObjectChangeAuthResponse
if err := execute[ObjectChangeAuthResponse](t, cmd, &rsp, s...); err != nil {
return nil, err
}
return &rsp, nil
}

// ObjectChangeAuthResponse the response from TPM2_ObjectChangeAuth.
type ObjectChangeAuthResponse struct {
// private area containing the new authorization value
OutPrivate TPM2BPrivate
}

// CreateLoaded is the input to TPM2_CreateLoaded.
// See definition in Part 3, Commands, section 12.9
type CreateLoaded struct {
Expand Down

0 comments on commit dac860f

Please sign in to comment.