Skip to content

Commit

Permalink
Fix KnownName() and Empty Buffer sequence handle Names (#371)
Browse files Browse the repository at this point in the history
* Fix KnownName, add Sequence Handle name handling

* Fix RSADecrypt Name in test

* Relax HmacStart.Handle type

* Add additional comment context to change
  • Loading branch information
nckrss authored Sep 20, 2024
1 parent d96ccf7 commit 364d5f2
Show file tree
Hide file tree
Showing 5 changed files with 251 additions and 15 deletions.
10 changes: 10 additions & 0 deletions tpm2/reflect.go
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,16 @@ func cmdNames[R any](cmd Command[R, *R]) ([]TPM2BName, error) {
return nil, fmt.Errorf("invalid 'handle'-tagged member of %q: %v",
reflect.TypeOf(cmd), err)
}

// Special case: handles with an empty name buffer (anonymous:anon)
// See part 1: Architecture, section 32.4.5:
// The Name of a sequence object is an Empty Buffer (sized array with no
// data; indicated by a size field of zero followed by an array
// containing no elements)
if hasTag(reflect.ValueOf(cmd).Type().Field(i), "anon") {
continue
}

name := h.KnownName()
if name == nil {
return nil, fmt.Errorf("missing Name for '%v' parameter",
Expand Down
8 changes: 0 additions & 8 deletions tpm2/structures.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,14 +127,6 @@ func (h TPMHandle) KnownName() *TPM2BName {
result := make([]byte, 4)
binary.BigEndian.PutUint32(result, h.HandleValue())
return &TPM2BName{Buffer: result}
case TPMHTTransient:
// The Name of a sequence object is an Empty Buffer
// See part 1: Architecture, section 32.4.5
if h == TPMIDHSavedSequence {
return &TPM2BName{
Buffer: []byte{},
}
}
}
return nil
}
Expand Down
235 changes: 233 additions & 2 deletions tpm2/test/hmac_start_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ func TestHmacStart(t *testing.T) {
Handle: rspHS.SequenceHandle,
Auth: PasswordAuth(password),
}

for len(data) > maxInputBuffer {
sequenceUpdate := SequenceUpdate{
SequenceHandle: authHandle,
Expand Down Expand Up @@ -123,10 +124,15 @@ func TestHmacStart(t *testing.T) {
password := make([]byte, 8)
_, _ = rand.Read(password)

hierarchies := map[string]TPMHandle{
"Null": TPMRHNull,
"Owner": TPMRHOwner,
"Endorsement": TPMRHEndorsement}

for _, bufferSize := range bufferSizes {
data := make([]byte, bufferSize)
for _, hierarchy := range []TPMHandle{TPMRHNull, TPMRHOwner, TPMRHEndorsement} {
t.Run(fmt.Sprintf("Null hierarchy [bufferSize=%d]", bufferSize), func(t *testing.T) {
for name, hierarchy := range hierarchies {
t.Run(fmt.Sprintf("%s hierarchy [bufferSize=%d]", name, bufferSize), func(t *testing.T) {
_, _ = rand.Read(data)
// HMAC Key is not exported and can not be externally validated,
// run HMAC twice with same data and confirm they are the same
Expand All @@ -138,4 +144,229 @@ func TestHmacStart(t *testing.T) {
})
}
}

t.Run("Same key multiple sequences", func(t *testing.T) {
sas, sasCloser, err := HMACSession(thetpm, TPMAlgSHA256, 16)
if err != nil {
t.Fatalf("could not create hmac key authorization session: %v", err)
}
defer func() {
_ = sasCloser()
}()

createPrimary := CreatePrimary{
PrimaryHandle: AuthHandle{
Handle: TPMRHNull,
Auth: sas,
},
InPublic: New2B(TPMTPublic{
Type: TPMAlgKeyedHash,
NameAlg: TPMAlgSHA256,
ObjectAttributes: TPMAObject{
SignEncrypt: true,
FixedTPM: true,
FixedParent: true,
SensitiveDataOrigin: true,
UserWithAuth: true,
},
Parameters: NewTPMUPublicParms(TPMAlgKeyedHash,
&TPMSKeyedHashParms{
Scheme: TPMTKeyedHashScheme{
Scheme: TPMAlgHMAC,
Details: NewTPMUSchemeKeyedHash(TPMAlgHMAC,
&TPMSSchemeHMAC{
HashAlg: TPMAlgSHA256,
}),
},
}),
}),
}

rspCP, err := createPrimary.Execute(thetpm)
if err != nil {
t.Fatalf("CreatePrimary HMAC key failed: %v", err)
}

flushContext := FlushContext{FlushHandle: rspCP.ObjectHandle}
defer func() {
_, _ = flushContext.Execute(thetpm)
}()

hmacStart := HmacStart{
Handle: AuthHandle{
Handle: rspCP.ObjectHandle,
Name: rspCP.Name,
Auth: sas,
},
Auth: TPM2BAuth{
Buffer: password,
},
HashAlg: TPMAlgNull,
}

rspHS1, err := hmacStart.Execute(thetpm)
if err != nil {
t.Fatalf("HmacStart failed: %v", err)
}

authHandle1 := AuthHandle{
Handle: rspHS1.SequenceHandle,
Auth: PasswordAuth(password),
}

rspHS2, err := hmacStart.Execute(thetpm)
if err != nil {
t.Fatalf("HmacStart failed: %v", err)
}

authHandle2 := AuthHandle{
Handle: rspHS2.SequenceHandle,
Auth: PasswordAuth(password),
}

if rspHS1.SequenceHandle.HandleValue() == rspHS2.SequenceHandle.HandleValue() {
t.Error("sequence handles are not unique")
}

sequenceComplete1 := SequenceComplete{
SequenceHandle: authHandle1,
}

_, err = sequenceComplete1.Execute(thetpm)
if err != nil {
t.Fatalf("SequenceComplete failed: %v", err)
}

sequenceComplete2 := SequenceComplete{
SequenceHandle: authHandle2,
}

_, err = sequenceComplete2.Execute(thetpm)
if err != nil {
t.Fatalf("SequenceComplete failed: %v", err)
}

})

}

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

run := func(t *testing.T, data []byte, password []byte, hierarchy TPMHandle, thetpm transport.TPM) []byte {
maxInputBuffer := 1024

createPrimary := CreatePrimary{
PrimaryHandle: hierarchy,
InPublic: New2B(TPMTPublic{
Type: TPMAlgKeyedHash,
NameAlg: TPMAlgSHA256,
ObjectAttributes: TPMAObject{
SignEncrypt: true,
FixedTPM: true,
FixedParent: true,
SensitiveDataOrigin: true,
UserWithAuth: true,
},
Parameters: NewTPMUPublicParms(TPMAlgKeyedHash,
&TPMSKeyedHashParms{
Scheme: TPMTKeyedHashScheme{
Scheme: TPMAlgHMAC,
Details: NewTPMUSchemeKeyedHash(TPMAlgHMAC,
&TPMSSchemeHMAC{
HashAlg: TPMAlgSHA256,
}),
},
}),
}),
}

rspCP, err := createPrimary.Execute(thetpm)
if err != nil {
t.Fatalf("CreatePrimary HMAC key failed: %v", err)
}

flushContext := FlushContext{FlushHandle: rspCP.ObjectHandle}
defer func() {
_, _ = flushContext.Execute(thetpm)
}()

hmacStart := HmacStart{
Handle: NamedHandle{
Handle: rspCP.ObjectHandle,
Name: rspCP.Name,
},
Auth: TPM2BAuth{
Buffer: password,
},
HashAlg: TPMAlgNull,
}

rspHS, err := hmacStart.Execute(thetpm)
if err != nil {
t.Fatalf("HmacStart failed: %v", err)
}

authHandle := AuthHandle{
Handle: rspHS.SequenceHandle,
Auth: PasswordAuth(password),
}

for len(data) > maxInputBuffer {
sequenceUpdate := SequenceUpdate{
SequenceHandle: authHandle,
Buffer: TPM2BMaxBuffer{
Buffer: data[:maxInputBuffer],
},
}
_, err = sequenceUpdate.Execute(thetpm)
if err != nil {
t.Fatalf("SequenceUpdate failed: %v", err)
}

data = data[maxInputBuffer:]
}

sequenceComplete := SequenceComplete{
SequenceHandle: authHandle,
Buffer: TPM2BMaxBuffer{
Buffer: data,
},
Hierarchy: hierarchy,
}

rspSC, err := sequenceComplete.Execute(thetpm)
if err != nil {
t.Fatalf("SequenceComplete failed: %v", err)
}
return rspSC.Result.Buffer

}

password := make([]byte, 8)
_, _ = rand.Read(password)

hierarchies := map[string]TPMHandle{
"Null": TPMRHNull,
"Owner": TPMRHOwner,
"Endorsement": TPMRHEndorsement}

data := make([]byte, 1024)
for name, hierarchy := range hierarchies {
t.Run(fmt.Sprintf("%s hierarchy [bufferSize=1024]", name), func(t *testing.T) {
_, _ = rand.Read(data)
// HMAC Key is not exported and can not be externally validated,
// run HMAC twice with same data and confirm they are the same
hmac1 := run(t, data, password, hierarchy, thetpm)
hmac2 := run(t, data, password, hierarchy, thetpm)
if !bytes.Equal(hmac1, hmac2) {
t.Errorf("hmac %x is not expected %x", hmac1, hmac2)
}
})
}

}
5 changes: 4 additions & 1 deletion tpm2/test/rsa_encryption_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,10 @@ func TestRSAEncryption(t *testing.T) {
}

decryptCmd := RSADecrypt{
KeyHandle: loadRsp.ObjectHandle,
KeyHandle: NamedHandle{
Handle: loadRsp.ObjectHandle,
Name: loadRsp.Name,
},
CipherText: TPM2BPublicKeyRSA{Buffer: encryptRsp.OutData.Buffer},
InScheme: TPMTRSADecrypt{
Scheme: TPMAlgOAEP,
Expand Down
8 changes: 4 additions & 4 deletions tpm2/tpm2.go
Original file line number Diff line number Diff line change
Expand Up @@ -658,8 +658,8 @@ type HashSequenceStartResponse struct {
// HmacStart is the input to TPM2_HMAC_Start.
// See definition in Part 3, Commands, section 17.2.2
type HmacStart struct {
// HMAC key handle requiring an authorization session for the USER role
Handle AuthHandle `gotpm:"handle,auth"`
// HMAC key handle
Handle handle `gotpm:"handle,auth"`
// authorization value for subsequent use of the sequence
Auth TPM2BAuth
// the hash algorithm to use for the hmac sequence
Expand Down Expand Up @@ -689,7 +689,7 @@ type HmacStartResponse struct {
// See definition in Part 3, Commands, section 17.4
type SequenceUpdate struct {
// handle for the sequence object
SequenceHandle handle `gotpm:"handle,auth"`
SequenceHandle handle `gotpm:"handle,auth,anon"`
// data to be added to hash
Buffer TPM2BMaxBuffer
}
Expand All @@ -713,7 +713,7 @@ type SequenceUpdateResponse struct{}
// See definition in Part 3, Commands, section 17.5
type SequenceComplete struct {
// authorization for the sequence
SequenceHandle handle `gotpm:"handle,auth"`
SequenceHandle handle `gotpm:"handle,auth,anon"`
// data to be added to the hash/HMAC
Buffer TPM2BMaxBuffer
// hierarchy of the ticket for a hash
Expand Down

0 comments on commit 364d5f2

Please sign in to comment.