Skip to content

Commit eb8cc83

Browse files
authored
Merge pull request #181 from Chounoki/tpm20
Implement VerifyHMAC function and its tests.
2 parents ca64ac8 + 6cb3413 commit eb8cc83

File tree

2 files changed

+123
-1
lines changed

2 files changed

+123
-1
lines changed

service/biz/tpm20_utils.go

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@ package biz
1717

1818
import (
1919
"bytes"
20+
"crypto/hmac"
2021
"crypto/rand"
2122
"crypto/rsa"
2223
"crypto/sha256"
24+
"crypto/subtle"
2325
"crypto/x509"
2426
"encoding/binary"
2527
"encoding/pem"
@@ -41,6 +43,10 @@ var (
4143
ErrInputNil = errors.New("input cannot be nil")
4244
// ErrInvalidPubKeyAttributes is returned when public key attributes are invalid.
4345
ErrInvalidPubKeyAttributes = errors.New("invalid public key attributes")
46+
// ErrHMACNotMatch is returned when the HMAC does not match the expected one.
47+
ErrHMACNotMatch = errors.New("HMAC does not match")
48+
// ErrWrongAlgo is returned when an algorithm is not as expected.
49+
ErrWrongAlgo = errors.New("unexpected algorithm")
4450
// ErrUnsupportedKeyTemplate is returned when the key template is unsupported.
4551
ErrUnsupportedKeyTemplate = errors.New("unsupported key template")
4652
)
@@ -285,7 +291,40 @@ func (u *DefaultTPM20Utils) WrapHMACKeytoRSAPublicKey(rsaPub *rsa.PublicKey, hma
285291

286292
// VerifyHMAC verifies the HMAC signature of the message.
287293
func (u *DefaultTPM20Utils) VerifyHMAC(message []byte, signature []byte, hmacSensitive *tpm20.TPMTSensitive) error {
288-
// TODO: Implement this function.
294+
if hmacSensitive == nil {
295+
return fmt.Errorf("VerifyHMAC: hmacSensitive cannot be empty, %w", ErrInputNil)
296+
}
297+
if len(message) == 0 {
298+
return fmt.Errorf("VerifyHMAC: message cannot be empty, %w", ErrInputNil)
299+
}
300+
if len(signature) == 0 {
301+
return fmt.Errorf("VerifyHMAC: signature cannot be empty, %w", ErrInputNil)
302+
}
303+
304+
sig, err := tpm20.Unmarshal[tpm20.TPMTSignature](signature)
305+
if err != nil {
306+
return fmt.Errorf("VerifyHMAC: failed to unmarshal signature, %w", err)
307+
}
308+
ha, err := sig.Signature.HMAC()
309+
if err != nil {
310+
return fmt.Errorf("VerifyHMAC: failed to get HMAC from signature, %w", err)
311+
}
312+
if ha.HashAlg != tpm20.TPMAlgSHA256 {
313+
return fmt.Errorf("VerifyHMAC: wrong HMAC algorithm: %v (expected SHA256), %w", ha.HashAlg, ErrWrongAlgo)
314+
}
315+
316+
bits, err := hmacSensitive.Sensitive.Bits()
317+
if err != nil {
318+
return fmt.Errorf("VerifyHMAC: failed to get HMAC key from hmacSensitive, %w", err)
319+
}
320+
// The HMAC is over SHA256(message).
321+
digest := sha256.Sum256(message)
322+
h := hmac.New(sha256.New, bits.Buffer)
323+
h.Write(digest[:])
324+
if subtle.ConstantTimeCompare(ha.Digest, h.Sum(nil)) != 1 {
325+
return fmt.Errorf("VerifyHMAC: HMAC verification failed, %w", ErrHMACNotMatch)
326+
}
327+
289328
return nil
290329
}
291330

service/biz/tpm20_utils_test.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1013,6 +1013,89 @@ func TestWrapHMACKeytoRSAPublicKey_Failure(t *testing.T) {
10131013
}
10141014
}
10151015

1016+
func TestVerifyHMAC(t *testing.T) {
1017+
u := &DefaultTPM20Utils{}
1018+
// The following test vectors are true values generated by using a TPM hardware simulator.
1019+
// Generation code reference: https://github.com/TrustedComputingGroup/tpm-fw-attestation-reference-code/blob/main/go/pkg/host/host.go
1020+
message := []byte{0xFF, 0x54, 0x43, 0x47, 0x80, 0x17, 0x00, 0x22, 0x00, 0x0B, 0xCF, 0x1E, 0xC6, 0x7A, 0xE7, 0x6A, 0x85, 0xAD, 0x78, 0xDC, 0xE2, 0x84, 0x3F, 0x9A, 0x2B, 0x37, 0x25, 0x23, 0xCA, 0x27, 0x1B, 0x09, 0xE9, 0x72, 0x24, 0x33, 0x16, 0x05, 0x35, 0x7B, 0xD0, 0xCB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x17, 0x06, 0x19, 0x00, 0x16, 0x36, 0x36, 0x00, 0x22, 0x00, 0x0B, 0x01, 0x01, 0x3B, 0xBF, 0x20, 0xFB, 0xAB, 0x85, 0x80, 0x0C, 0xCA, 0xB6, 0xBB, 0x6A, 0x2B, 0x07, 0xA9, 0x01, 0x52, 0x26, 0x48, 0x77, 0xD3, 0x85, 0xB4, 0x2E, 0xF0, 0x2C, 0x34, 0x70, 0xA6, 0x75, 0x00, 0x22, 0x00, 0x0B, 0xCF, 0x1E, 0xC6, 0x7A, 0xE7, 0x6A, 0x85, 0xAD, 0x78, 0xDC, 0xE2, 0x84, 0x3F, 0x9A, 0x2B, 0x37, 0x25, 0x23, 0xCA, 0x27, 0x1B, 0x09, 0xE9, 0x72, 0x24, 0x33, 0x16, 0x05, 0x35, 0x7B, 0xD0, 0xCB}
1021+
signature := []byte{0x00, 0x05, 0x00, 0x0B, 0x39, 0x24, 0x94, 0x25, 0x51, 0x21, 0xA8, 0x57, 0x24, 0x94, 0x7E, 0x04, 0x4D, 0xAF, 0x7A, 0x23, 0x45, 0x40, 0x2A, 0xD2, 0xDD, 0x4E, 0x4B, 0x5F, 0x63, 0x30, 0x5B, 0x34, 0xA2, 0x10, 0xAD, 0x57}
1022+
hmacKey := []byte{0x08, 0x99, 0x71, 0xA1, 0x94, 0xAA, 0x90, 0x6C, 0xF9, 0x0C, 0xE2, 0xEE, 0xE4, 0x3C, 0x9B, 0xD7, 0x91, 0xB4, 0x63, 0x58, 0x39, 0xED, 0xCE, 0x5A, 0xBB, 0x6E, 0x78, 0xDA, 0x1C, 0x4F, 0xE0, 0x97}
1023+
sensitive := &tpm20.TPMTSensitive{
1024+
SensitiveType: tpm20.TPMAlgKeyedHash,
1025+
Sensitive: tpm20.NewTPMUSensitiveComposite(tpm20.TPMAlgKeyedHash, &tpm20.TPM2BSensitiveData{
1026+
Buffer: hmacKey,
1027+
}),
1028+
}
1029+
sensitiveIncorrect := &tpm20.TPMTSensitive{
1030+
SensitiveType: tpm20.TPMAlgKeyedHash,
1031+
Sensitive: tpm20.NewTPMUSensitiveComposite(tpm20.TPMAlgKeyedHash, &tpm20.TPM2BSensitiveData{
1032+
Buffer: append(hmacKey[10:], hmacKey[:10]...),
1033+
}),
1034+
}
1035+
1036+
successTests := []struct {
1037+
name string
1038+
message []byte
1039+
signature []byte
1040+
sensitive *tpm20.TPMTSensitive
1041+
}{
1042+
{
1043+
name: "HMAC Match",
1044+
message: message,
1045+
signature: signature,
1046+
sensitive: sensitive,
1047+
},
1048+
}
1049+
for _, tc := range successTests {
1050+
t.Run(tc.name, func(t *testing.T) {
1051+
if err := u.VerifyHMAC(tc.message, tc.signature, tc.sensitive); err != nil {
1052+
t.Errorf("TestVerifyHMAC() returned an unexpected error %v", err)
1053+
}
1054+
})
1055+
}
1056+
1057+
failureTests := []struct {
1058+
name string
1059+
message []byte
1060+
signature []byte
1061+
sensitive *tpm20.TPMTSensitive
1062+
wantErr error
1063+
}{
1064+
{
1065+
name: "Nil Sensitive",
1066+
message: message,
1067+
signature: signature,
1068+
wantErr: ErrInputNil,
1069+
},
1070+
{
1071+
name: "Nil Message",
1072+
signature: signature,
1073+
sensitive: sensitive,
1074+
wantErr: ErrInputNil,
1075+
},
1076+
{
1077+
name: "Nil Signature",
1078+
message: message,
1079+
sensitive: sensitive,
1080+
wantErr: ErrInputNil,
1081+
},
1082+
{
1083+
name: "HMAC Not Match",
1084+
message: message,
1085+
signature: signature,
1086+
sensitive: sensitiveIncorrect,
1087+
wantErr: ErrHMACNotMatch,
1088+
},
1089+
}
1090+
for _, tc := range failureTests {
1091+
t.Run(tc.name, func(t *testing.T) {
1092+
if err := u.VerifyHMAC(tc.message, tc.signature, tc.sensitive); !errors.Is(err, tc.wantErr) {
1093+
t.Errorf("TestVerifyHMAC() failed, want error %v, got error %v", tc.wantErr, err)
1094+
}
1095+
})
1096+
}
1097+
}
1098+
10161099
func TestVerifyIdevidAttributes(t *testing.T) {
10171100
u := DefaultTPM20Utils{}
10181101

0 commit comments

Comments
 (0)