diff --git a/tpm2/reflect.go b/tpm2/reflect.go index 60c9d586..d32473eb 100644 --- a/tpm2/reflect.go +++ b/tpm2/reflect.go @@ -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", diff --git a/tpm2/structures.go b/tpm2/structures.go index 78b031e4..11a0261e 100644 --- a/tpm2/structures.go +++ b/tpm2/structures.go @@ -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 } diff --git a/tpm2/test/hmac_start_test.go b/tpm2/test/hmac_start_test.go index 88ef4a44..cfb61112 100644 --- a/tpm2/test/hmac_start_test.go +++ b/tpm2/test/hmac_start_test.go @@ -88,6 +88,7 @@ func TestHmacStart(t *testing.T) { Handle: rspHS.SequenceHandle, Auth: PasswordAuth(password), } + for len(data) > maxInputBuffer { sequenceUpdate := SequenceUpdate{ SequenceHandle: authHandle, @@ -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 @@ -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) + } + }) + } + } diff --git a/tpm2/test/rsa_encryption_test.go b/tpm2/test/rsa_encryption_test.go index 926e23d7..17011852 100644 --- a/tpm2/test/rsa_encryption_test.go +++ b/tpm2/test/rsa_encryption_test.go @@ -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, diff --git a/tpm2/tpm2.go b/tpm2/tpm2.go index 7b124f71..ede45ee9 100644 --- a/tpm2/tpm2.go +++ b/tpm2/tpm2.go @@ -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 @@ -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 } @@ -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