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

Implement TPM2_Duplicate #355

Merged
merged 1 commit into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
181 changes: 181 additions & 0 deletions tpm2/test/duplicate_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
package tpm2test

import (
"testing"

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

// TestDuplicate creates an object under Owner->SRK and duplicates it to
// Endorsement->SRK.
func TestDuplicate(t *testing.T) {
thetpm, err := simulator.OpenSimulator()
if err != nil {
t.Fatalf("could not connect to TPM simulator: %v", err)
}
defer thetpm.Close()

t.Log("### Create Owner SRK")
srkCreateResp, err := CreatePrimary{
PrimaryHandle: TPMRHOwner,
InPublic: New2B(ECCSRKTemplate),
}.Execute(thetpm)
if err != nil {
t.Fatalf("could not generate SRK: %v", err)
}

srk := NamedHandle{
Handle: srkCreateResp.ObjectHandle,
Name: srkCreateResp.Name,
}

policy, err := dupPolicyDigest(thetpm)
if err != nil {
t.Fatalf("dupPolicyDigest: %v", err)
}

keyPass := []byte("foo")

t.Log("### Create Object to be duplicated")
objectCreateLoadedResp, err := CreateLoaded{
ParentHandle: srk,
InSensitive: TPM2BSensitiveCreate{
Sensitive: &TPMSSensitiveCreate{
UserAuth: TPM2BAuth{
Buffer: keyPass,
},
},
},
InPublic: New2BTemplate(&TPMTPublic{
Type: TPMAlgECC,
NameAlg: TPMAlgSHA256,
ObjectAttributes: TPMAObject{
FixedTPM: false,
FixedParent: false,
SensitiveDataOrigin: true,
UserWithAuth: true,
Decrypt: true,
SignEncrypt: true,
},
AuthPolicy: TPM2BDigest{Buffer: policy},
Parameters: NewTPMUPublicParms(
TPMAlgECC,
&TPMSECCParms{
CurveID: TPMECCNistP256,
},
),
Unique: NewTPMUPublicID(
TPMAlgECC,
&TPMSECCPoint{
X: TPM2BECCParameter{Buffer: make([]byte, 32)},
Y: TPM2BECCParameter{Buffer: make([]byte, 32)},
},
),
}),
}.Execute(thetpm)
if err != nil {
t.Fatalf("TPM2_CreateLoaded: %v", err)
}

// We don't need the owner SRK handle anymore.
FlushContext{FlushHandle: srkCreateResp.ObjectHandle}.Execute(thetpm)

t.Log("### Create Endorsement SRK (New Parent)")
srk2CreateResp, err := CreatePrimary{
PrimaryHandle: TPMRHEndorsement,
InPublic: New2B(ECCSRKTemplate),
}.Execute(thetpm)
if err != nil {
t.Fatalf("could not generate SRK: %v", err)
}
defer FlushContext{FlushHandle: srk2CreateResp.ObjectHandle}.Execute(thetpm)

srk2 := NamedHandle{
Handle: srk2CreateResp.ObjectHandle,
Name: srk2CreateResp.Name,
}

t.Log("### Duplicate Object")
duplicateResp, err := Duplicate{
ObjectHandle: AuthHandle{
Handle: objectCreateLoadedResp.ObjectHandle,
Name: objectCreateLoadedResp.Name,
Auth: Policy(TPMAlgSHA256, 16, PolicyCallback(func(tpm transport.TPM, handle TPMISHPolicy, _ TPM2BNonce) error {
_, err := PolicyCommandCode{
PolicySession: handle,
Code: TPMCCDuplicate,
}.Execute(tpm)
return err
})),
},
NewParentHandle: srk2,
Symmetric: TPMTSymDef{
Algorithm: TPMAlgNull,
},
}.Execute(thetpm)
if err != nil {
t.Fatalf("TPM2_Duplicate: %v", err)
}

// We don't need the original object handle anymore.
FlushContext{FlushHandle: objectCreateLoadedResp.ObjectHandle}.Execute(thetpm)

t.Log("### Import Object")
importResp, err := Import{
ParentHandle: AuthHandle{
Handle: srk2.Handle,
Name: srk2.Name,
Auth: PasswordAuth(nil),
},
ObjectPublic: objectCreateLoadedResp.OutPublic,
Duplicate: duplicateResp.Duplicate,
InSymSeed: duplicateResp.OutSymSeed,
Symmetric: TPMTSymDef{
Algorithm: TPMAlgNull,
},
}.Execute(thetpm)
if err != nil {
t.Fatalf("TPM2_Import: %v", err)
}

t.Log("### Load Imported Object")
loadResp, err := Load{
ParentHandle: srk2,
InPrivate: importResp.OutPrivate,
InPublic: objectCreateLoadedResp.OutPublic,
}.Execute(thetpm)
if err != nil {
t.Fatalf("TPM2_Load: %v", err)
}
defer FlushContext{FlushHandle: loadResp.ObjectHandle}.Execute(thetpm)
}

func dupPolicyDigest(thetpm transport.TPM) ([]byte, error) {
sess, cleanup, err := PolicySession(thetpm, TPMAlgSHA256, 16, Trial())
if err != nil {
return nil, err
}
defer cleanup()

_, err = PolicyCommandCode{
PolicySession: sess.Handle(),
Code: TPMCCDuplicate,
}.Execute(thetpm)
if err != nil {
return nil, err
}

pgd, err := PolicyGetDigest{
PolicySession: sess.Handle(),
}.Execute(thetpm)
if err != nil {
return nil, err
}
_, err = FlushContext{FlushHandle: sess.Handle()}.Execute(thetpm)
if err != nil {
return nil, err
}
return pgd.PolicyDigest.Buffer, nil
}
47 changes: 47 additions & 0 deletions tpm2/tpm2.go
Original file line number Diff line number Diff line change
Expand Up @@ -1523,6 +1523,53 @@ func (cmd EvictControl) Execute(t transport.TPM, s ...Session) (*EvictControlRes
return &rsp, nil
}

// Duplicate is the input to TPM2_Duplicate.
// See definition in Part 3, Commands, section 13.1
type Duplicate struct {
// ObjectHandle is the handle of the object to dupliate.
ObjectHandle handle `gotpm:"handle,auth"`

// NewParentHandle is the handle of the new parent.
NewParentHandle handle `gotpm:"handle"`

// EncryptionKeyIn is the optional symmetric encryption key used as the
// inner wrapper. If SymmetricAlg is TPM_ALG_NULL, then this parameter
// shall be the Empty Buffer.
EncryptionKeyIn TPM2BData

// Definition of the symmetric algorithm to use for the inner wrapper.
// It may be TPM_ALG_NULL if no inner wrapper is applied.
Symmetric TPMTSymDef
}

// DuplicateResponse is the response from TPM2_Duplicate.
type DuplicateResponse struct {
// EncryptionKeyOut is the symmetric encryption key used as the
// inner wrapper. If SymmetricAlg is TPM_ALG_NULL, this value
// shall be the Empty Buffer.
EncryptionKeyOut TPM2BData

// Duplicate is the private area of the object. It may be encrypted by
// EncryptionKeyIn and may be doubly encrypted.
Duplicate TPM2BPrivate

// OutSymSeed is the seed protected by the asymmetric algorithms of new
// parent.
OutSymSeed TPM2BEncryptedSecret
}

// Command implements the Command interface.
func (Duplicate) Command() TPMCC { return TPMCCDuplicate }

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

// Import is the input to TPM2_Import.
// See definition in Part 3, Commands, section 13.3
type Import struct {
Expand Down