Skip to content

Instantly share code, notes, and snippets.

@chrisccoulson
Last active August 3, 2021 23:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chrisccoulson/9d3a7e6e4d2d330e60dbd6174985becd to your computer and use it in GitHub Desktop.
Save chrisccoulson/9d3a7e6e4d2d330e60dbd6174985becd to your computer and use it in GitHub Desktop.
test_tpmauth.go
// This tests behaviour of authorization value handling. Some things to note
// from the reference TPM implementation:
// - Authorization values for objects are stored padded with trailing zeroes to
// the size of the object's name algorithm.
// - Authorization values for hierarchies and NV indices are stored with trailing
// zeroes removed.
// - EntityGetAuthValue removes trailing zeroes from an entity's authorization
// value, prior to its use in the front end code when comparing comparing it
// against a password session or using it to compute a HMAC key for a HMAC
// session, or in the TPM2_StartAuthSession when computing the session key.
// - The front end code removes trailing zeroes from a password session.
// - TPM2_LoadExternal doesn't modify the authorization value of external
// objects.
// - TPM2_Import pads the authorization value of imported objects to the size
// of the object's name algorithm.
package main
import (
"bytes"
"crypto"
"crypto/rand"
_ "crypto/sha256"
"encoding/binary"
"errors"
"fmt"
"os"
"github.com/canonical/go-tpm2"
"github.com/canonical/go-tpm2/testutil"
"github.com/jessevdk/go-flags"
"gopkg.in/check.v1"
)
type options struct {
TPM string `long:"tpm" description:"Test the TPM at the specified character device" default:"/dev/tpm0" optional:"true" optional-value:"/dev/tpm0"`
Mssim *uint `long:"mssim" description:"Test the TPM simulator on the specified local port" optional:"true" optional-value:"2321"`
Verbose []bool `short:"v" long:"verbose" description:"Enable verbose output"`
}
var opts options
type authSuite struct {
testutil.TPMTest
}
func (s *authSuite) SetUpSuite(c *check.C) {
s.TPMFeatures = testutil.TPMFeatureOwnerHierarchy|testutil.TPMFeatureNV
}
var _ = check.Suite(&authSuite{})
func (s *authSuite) createSealedObject(c *check.C, parent tpm2.ResourceContext, userAuth tpm2.Auth) (tpm2.Private, *tpm2.Public) {
sensitive := tpm2.SensitiveCreate{
UserAuth: userAuth,
Data: make([]byte, 32)}
template := tpm2.Public{
Type: tpm2.ObjectTypeKeyedHash,
NameAlg: tpm2.HashAlgorithmSHA256,
Attrs: tpm2.AttrUserWithAuth | tpm2.AttrNoDA,
Params: &tpm2.PublicParamsU{KeyedHashDetail: &tpm2.KeyedHashParams{Scheme: tpm2.KeyedHashScheme{Scheme: tpm2.KeyedHashSchemeNull}}}}
priv, pub, _, _, _, err := s.TPM.Create(parent, &sensitive, &template, nil, nil, nil)
c.Assert(err, check.IsNil)
return priv, pub
}
func (s *authSuite) createAndLoadSealedObject(c *check.C, parent tpm2.ResourceContext, userAuth tpm2.Auth) tpm2.ResourceContext {
priv, pub := s.createSealedObject(c, parent, userAuth)
object, err := s.TPM.Load(parent, priv, pub, nil)
c.Assert(err, check.IsNil)
return object
}
func (s *authSuite) TestObject(c *check.C) {
primary := s.CreateStoragePrimaryKeyRSA(c)
object := s.createAndLoadSealedObject(c, primary, []byte("password"))
object.SetAuthValue([]byte("password"))
_, err := s.TPM.Unseal(object, nil)
c.Check(err, check.IsNil)
}
func (s *authSuite) TestObjectAuthValueWithTrailingZeroes(c *check.C) {
primary := s.CreateStoragePrimaryKeyRSA(c)
object := s.createAndLoadSealedObject(c, primary, []byte("password\x00\x00"))
object.SetAuthValue([]byte("password"))
_, err := s.TPM.Unseal(object, nil)
// We created an object with an auth value that has trailing zeroes.
// The reference TPM implementation pads the auth value to the size of
// the name algorithm anyway, and EntityGetAuthValue removes the trailing
// zeroes when checking the auth value. The frontend removes trailing zeroes
// from the password session, so this should work fine.
c.Check(err, check.IsNil)
}
func (s *authSuite) TestObjectAuthValueWithTrailingZeroesAndUnboundHMACSession(c *check.C) {
primary := s.CreateStoragePrimaryKeyRSA(c)
object := s.createAndLoadSealedObject(c, primary, []byte("password\x00\x00"))
session := s.StartAuthSession(c, nil, nil, tpm2.SessionTypeHMAC, nil, tpm2.HashAlgorithmSHA256)
object.SetAuthValue([]byte("password"))
_, err := s.TPM.Unseal(object, session)
// We created an object with an auth value that has trailing zeroes.
// The reference TPM implementation pads the auth value to the size of
// the name algorithm anyway, EntityGetAuthValue removes the trailing
// zeroes when computing the HMAC key, and so do we, so this should
// work fine.
c.Check(err, check.IsNil)
}
func (s *authSuite) TestObjectAuthValueWithTrailingZeroesAndBoundHMACSession(c *check.C) {
primary := s.CreateStoragePrimaryKeyRSA(c)
object := s.createAndLoadSealedObject(c, primary, []byte("password\x00\x00"))
object.SetAuthValue([]byte("password"))
session := s.StartAuthSession(c, nil, object, tpm2.SessionTypeHMAC, nil, tpm2.HashAlgorithmSHA256)
_, err := s.TPM.Unseal(object, session)
// We created an object with an auth value that has trailing zeroes.
// The reference TPM implementation pads the auth value to the size of
// the name algorithm anyway, EntityGetAuthValue removes the trailing
// zeroes when computing the session key, and so do we, so this should
// work fine.
c.Check(err, check.IsNil)
}
func (s *authSuite) TestObjectSize(c *check.C) {
primary := s.CreateStoragePrimaryKeyRSA(c)
priv, _ := s.createSealedObject(c, primary, []byte("password\x00\x00"))
// The reference TPM implementation pads the auth value of objects to the size
// of the name algorithm, and EntityGetAuthValue removes the trailing zeroes
// when the auth value is used later. This is to avoid leaking the size of
// the authorization value from the TPM. Other tests check the sensitive
// area from duplicated objects, but check that the size isn't leaked in
// an object currently protected by the TPM by checking that the private
// area has the expected size.
//
// The private area consists of the following fields (the sensitive
// area is encrypted):
// ============================================
// = size (2 bytes) | outer HMAC (32 bytes) =
// = size (2 bytes) | symmetric IV (16 bytes) =
// = size of sensitive area (2 bytes) =
// = sensitiveType (2 bytes) =
// = size (2 bytes) | authValue (32 bytes) =
// = size (2 bytes) | seedValue (32 bytes) =
// = size (2 bytes) | sensitive (32 bytes) =
// ============================================
// The size of the private area might be 134 bytes on A TPM that behaves
// incorrectly
c.Check(priv, testutil.LenEquals, 158)
}
func (s *authSuite) TestHierarchy(c *check.C) {
s.HierarchyChangeAuth(c, tpm2.HandleOwner, []byte("password\x00\x00"))
_, _, _, _, _, err := s.TPM.CreatePrimary(s.TPM.OwnerHandleContext(), nil, testutil.NewRSAStorageKeyTemplate(), nil, nil, nil)
c.Assert(err, check.IsNil)
}
func (s *authSuite) TestHierarchyAuthValueWithTrailingZeroes(c *check.C) {
s.HierarchyChangeAuth(c, tpm2.HandleOwner, []byte("password\x00\x00"))
_, _, _, _, _, err := s.TPM.CreatePrimary(s.TPM.OwnerHandleContext(), nil, testutil.NewRSAStorageKeyTemplate(), nil, nil, nil)
// We changed the storage hierarchy auth value to one that has trailing
// zeroes. The reference TPM implementation removes the trailing zeroes
// before storing it to NV, and the frontend removes trailing zeroes
// from the password session, so this should work fine.
c.Assert(err, check.IsNil)
}
func (s *authSuite) TestHierarchyAuthValueWithTrailingZeroesAndUnboundHMACSession(c *check.C) {
s.HierarchyChangeAuth(c, tpm2.HandleOwner, []byte("password\x00\x00"))
session := s.StartAuthSession(c, nil, nil, tpm2.SessionTypeHMAC, nil, tpm2.HashAlgorithmSHA256)
_, _, _, _, _, err := s.TPM.CreatePrimary(s.TPM.OwnerHandleContext(), nil, testutil.NewRSAStorageKeyTemplate(), nil, nil, session)
// We changed the storage hierarchy auth value to one that has trailing
// zeroes. The reference TPM implementation removes the trailing zeroes
// before storing it to NV, and we remove trailing zeroes when computing
// the HMAC key, so this should work fine.
c.Assert(err, check.IsNil)
}
func (s *authSuite) TestHierarchyAuthValueWithTrailingZeroesAndBoundHMACSession(c *check.C) {
s.HierarchyChangeAuth(c, tpm2.HandleOwner, []byte("password\x00\x00"))
session := s.StartAuthSession(c, nil, s.TPM.OwnerHandleContext(), tpm2.SessionTypeHMAC, nil, tpm2.HashAlgorithmSHA256)
_, _, _, _, _, err := s.TPM.CreatePrimary(s.TPM.OwnerHandleContext(), nil, testutil.NewRSAStorageKeyTemplate(), nil, nil, session)
// We changed the storage hierarchy auth value to one that has trailing
// zeroes. The reference TPM implementation removes the trailing zeroes
// before storing it to NV, and we remove trailing zeroes when computing
// the session key, so this should work fine.
c.Assert(err, check.IsNil)
}
func (s *authSuite) TestHierarchyAuthValueAllZeroes(c *check.C) {
s.HierarchyChangeAuth(c, tpm2.HandleOwner, []byte("\x00\x00\x00\x00"))
props, err := s.TPM.GetCapabilityTPMProperties(tpm2.PropertyPermanent, 1)
c.Assert(err, check.IsNil)
c.Assert(props, testutil.LenEquals, 1)
c.Check(props[0].Property, check.Equals, tpm2.PropertyPermanent)
// We changed the storage hierarchy auth value to all zeroes. As the
// reference TPM implementation removes trailing zeroes before storing it
// to NV, the TPM should indicate that the auth value isn't set.
c.Check(tpm2.PermanentAttributes(props[0].Value)&tpm2.AttrOwnerAuthSet, check.Equals, tpm2.PermanentAttributes(0))
}
func (s *authSuite) makeSealedObjectExternal() (*tpm2.Public, *tpm2.Sensitive) {
key := make([]byte, 32)
seed := make([]byte, crypto.SHA256.Size())
rand.Read(seed)
h := crypto.SHA256.New()
h.Write(seed)
h.Write(key)
unique := h.Sum(nil)
authValue := make(tpm2.Auth, crypto.SHA256.Size())
copy(authValue, []byte("password"))
sensitive := tpm2.Sensitive{
Type: tpm2.ObjectTypeKeyedHash,
AuthValue: authValue,
SeedValue: seed,
Sensitive: &tpm2.SensitiveCompositeU{Bits: key}}
public := tpm2.Public{
Type: tpm2.ObjectTypeKeyedHash,
NameAlg: tpm2.HashAlgorithmSHA256,
Attrs: tpm2.AttrUserWithAuth | tpm2.AttrNoDA,
Params: &tpm2.PublicParamsU{KeyedHashDetail: &tpm2.KeyedHashParams{Scheme: tpm2.KeyedHashScheme{Scheme: tpm2.KeyedHashSchemeNull}}},
Unique: &tpm2.PublicIDU{KeyedHash: unique}}
return &public, &sensitive
}
func (s *authSuite) TestLoadExternal(c *check.C) {
public, sensitive := s.makeSealedObjectExternal()
object, err := s.TPM.LoadExternal(sensitive, public, tpm2.HandleNull)
c.Check(err, check.IsNil)
_, err = s.TPM.Unseal(object, nil)
// We loaded an external object with an authorization value padded to the
// size of the object's name algorithm. As EntityGetAuthValue removes the
// trailing zeroes when checking the auth value and the frontend removes
// trailing zeroes from the password session, this should work fine.
c.Check(err, check.IsNil)
}
func (s *authSuite) TestLoadExternalWithUnboundHMACSession(c *check.C) {
public, sensitive := s.makeSealedObjectExternal()
object, err := s.TPM.LoadExternal(sensitive, public, tpm2.HandleNull)
c.Check(err, check.IsNil)
session := s.StartAuthSession(c, nil, nil, tpm2.SessionTypeHMAC, nil, tpm2.HashAlgorithmSHA256)
_, err = s.TPM.Unseal(object, session)
// We loaded an external object with an authorization value padded to the
// size of the object's name algorithm. As EntityGetAuthValue removes the
// trailing zeroes when computing the HMAC key, and so do we, this
// should work fine.
c.Check(err, check.IsNil)
}
func (s *authSuite) TestLoadExternalWithBoundHMACSession(c *check.C) {
public, sensitive := s.makeSealedObjectExternal()
object, err := s.TPM.LoadExternal(sensitive, public, tpm2.HandleNull)
c.Check(err, check.IsNil)
session := s.StartAuthSession(c, nil, object, tpm2.SessionTypeHMAC, nil, tpm2.HashAlgorithmSHA256)
_, err = s.TPM.Unseal(object, session)
// We loaded an external object with an authorization value padded to the
// size of the object's name algorithm. As EntityGetAuthValue removes the
// trailing zeroes when computing the session key, and so do we, this
// should work fine.
c.Check(err, check.IsNil)
}
func (s *authSuite) importObjectFromSensitive(c *check.C, parent tpm2.ResourceContext, public *tpm2.Public, sensitive *tpm2.Sensitive) tpm2.Private {
parentPub, _, _, err := s.TPM.ReadPublic(parent)
c.Assert(err, check.IsNil)
_, duplicate, symSeed, err := tpm2.CreateDuplicationObjectFromSensitive(sensitive, public, parentPub, nil, nil)
c.Assert(err, check.IsNil)
priv, err := s.TPM.Import(parent, nil, public, duplicate, symSeed, nil, nil)
c.Assert(err, check.IsNil)
return priv
}
func (s *authSuite) importObjectFromSensitiveAndLoad(c *check.C, parent tpm2.ResourceContext, public *tpm2.Public, sensitive *tpm2.Sensitive) tpm2.ResourceContext {
priv := s.importObjectFromSensitive(c, parent, public, sensitive)
object, err := s.TPM.Load(parent, priv, public, nil)
c.Assert(err, check.IsNil)
return object
}
func (s *authSuite) TestImport(c *check.C) {
primary := s.CreateStoragePrimaryKeyRSA(c)
pub, sensitive := s.makeSealedObjectExternal()
object := s.importObjectFromSensitiveAndLoad(c, primary, pub, sensitive)
object.SetAuthValue([]byte("password"))
_, err := s.TPM.Unseal(object, nil)
// We imported an object with an authorization value padded to the
// size of the object's name algorithm. As EntityGetAuthValue removes the
// trailing zeroes when checking the auth value and the frontend removes
// trailing zeroes from the password session, this should work fine.
c.Check(err, check.IsNil)
}
func (s *authSuite) TestImportWithUnboundHMACSession(c *check.C) {
primary := s.CreateStoragePrimaryKeyRSA(c)
pub, sensitive := s.makeSealedObjectExternal()
object := s.importObjectFromSensitiveAndLoad(c, primary, pub, sensitive)
object.SetAuthValue([]byte("password"))
session := s.StartAuthSession(c, nil, nil, tpm2.SessionTypeHMAC, nil, tpm2.HashAlgorithmSHA256)
_, err := s.TPM.Unseal(object, session)
// We imported an object with an authorization value padded to the
// size of the object's name algorithm. As EntityGetAuthValue removes the
// trailing zeroes when computing the HMAC key, and so do we, this
// should work fine.
c.Check(err, check.IsNil)
}
func (s *authSuite) TestImportWithBoundHMACSession(c *check.C) {
primary := s.CreateStoragePrimaryKeyRSA(c)
pub, sensitive := s.makeSealedObjectExternal()
object := s.importObjectFromSensitiveAndLoad(c, primary, pub, sensitive)
object.SetAuthValue([]byte("password"))
session := s.StartAuthSession(c, nil, object, tpm2.SessionTypeHMAC, nil, tpm2.HashAlgorithmSHA256)
_, err := s.TPM.Unseal(object, session)
// We imported an object with an authorization value padded to the
// size of the object's name algorithm. As EntityGetAuthValue removes the
// trailing zeroes when computing the session key, and so do we, this
// should work fine.
c.Check(err, check.IsNil)
}
func (s *authSuite) TestImportWithShortAuthValue(c *check.C) {
primary := s.CreateStoragePrimaryKeyRSA(c)
pub, sensitive := s.makeSealedObjectExternal()
sensitive.AuthValue = []byte("password\x00\x00")
object := s.importObjectFromSensitiveAndLoad(c, primary, pub, sensitive)
object.SetAuthValue([]byte("password"))
_, err := s.TPM.Unseal(object, nil)
// We imported an object with an authorization value with some trailing
// zeroes but not padded to the size of the object's name algorithm. The
// reference TPM implementation fixes this, so this should work fine.
c.Check(err, check.IsNil)
}
func (s *authSuite) TestImportWithShortAuthValueAndUnboundHMACSession(c *check.C) {
primary := s.CreateStoragePrimaryKeyRSA(c)
pub, sensitive := s.makeSealedObjectExternal()
sensitive.AuthValue = []byte("password\x00\x00")
object := s.importObjectFromSensitiveAndLoad(c, primary, pub, sensitive)
object.SetAuthValue([]byte("password"))
session := s.StartAuthSession(c, nil, nil, tpm2.SessionTypeHMAC, nil, tpm2.HashAlgorithmSHA256)
_, err := s.TPM.Unseal(object, session)
// We imported an object with an authorization value with some trailing
// zeroes but not padded to the size of the object's name algorithm. The
// reference TPM implementation fixes this, so this should work fine.
c.Check(err, check.IsNil)
}
func (s *authSuite) TestImportWithShortAuthValueAndBoundHMACSession(c *check.C) {
primary := s.CreateStoragePrimaryKeyRSA(c)
pub, sensitive := s.makeSealedObjectExternal()
sensitive.AuthValue = []byte("password\x00\x00")
object := s.importObjectFromSensitiveAndLoad(c, primary, pub, sensitive)
object.SetAuthValue([]byte("password"))
session := s.StartAuthSession(c, nil, object, tpm2.SessionTypeHMAC, nil, tpm2.HashAlgorithmSHA256)
_, err := s.TPM.Unseal(object, session)
// We imported an object with an authorization value with some trailing
// zeroes but not padded to the size of the object's name algorithm. The
// reference TPM implementation fixes this, so this should work fine.
c.Check(err, check.IsNil)
}
func (s *authSuite) TestDuplicateObject(c *check.C) {
primary := s.CreateStoragePrimaryKeyRSA(c)
template := testutil.NewRSAStorageKeyTemplate()
template.Attrs &^= tpm2.AttrFixedTPM|tpm2.AttrFixedParent
trial, _ := tpm2.ComputeAuthPolicy(tpm2.HashAlgorithmSHA256)
trial.PolicyCommandCode(tpm2.CommandDuplicate)
template.AuthPolicy = trial.GetDigest()
inSensitive := tpm2.SensitiveCreate{UserAuth: []byte("password")}
priv, pub, _, _, _, err := s.TPM.Create(primary, &inSensitive, template, nil, nil, nil)
c.Assert(err, check.IsNil)
object, err := s.TPM.Load(primary, priv, pub, nil)
c.Assert(err, check.IsNil)
session := s.StartAuthSession(c, nil, nil, tpm2.SessionTypePolicy, nil, tpm2.HashAlgorithmSHA256)
c.Check(s.TPM.PolicyCommandCode(session, tpm2.CommandDuplicate), check.IsNil)
_, duplicate, _, err := s.TPM.Duplicate(object, nil, nil, nil, session)
c.Assert(err, check.IsNil)
sensitive, err := tpm2.UnwrapDuplicationObjectToSensitive(duplicate, pub, nil, tpm2.HashAlgorithmNull, nil, nil, nil, nil)
c.Assert(err, check.IsNil)
// We duplicated an object created by the TPM. The reference TPM implementation
// pads the auth value of objects to the size of the name algorithm, and we should
// see this in the duplicated sensitive area.
c.Check(sensitive.AuthValue, testutil.LenEquals, crypto.SHA256.Size())
}
func (s *authSuite) TestDuplicateImported(c *check.C) {
primary := s.CreateStoragePrimaryKeyRSA(c)
public, sensitive := s.makeSealedObjectExternal()
trial, _ := tpm2.ComputeAuthPolicy(tpm2.HashAlgorithmSHA256)
trial.PolicyCommandCode(tpm2.CommandDuplicate)
public.AuthPolicy = trial.GetDigest()
object := s.importObjectFromSensitiveAndLoad(c, primary, public, sensitive)
session := s.StartAuthSession(c, nil, nil, tpm2.SessionTypePolicy, nil, tpm2.HashAlgorithmSHA256)
c.Check(s.TPM.PolicyCommandCode(session, tpm2.CommandDuplicate), check.IsNil)
_, duplicate, _, err := s.TPM.Duplicate(object, nil, nil, nil, session)
c.Assert(err, check.IsNil)
sensitive2, err := tpm2.UnwrapDuplicationObjectToSensitive(duplicate, public, nil, tpm2.HashAlgorithmNull, nil, nil, nil, nil)
c.Assert(err, check.IsNil)
// We duplicated an object imported into the TPM. As the object already
// had an authorization value padded to the size of the name algorithm,
// we should see the unmodified value in the duplicated sensitive area.
c.Check(sensitive2.AuthValue, check.DeepEquals, sensitive.AuthValue)
}
func (s *authSuite) TestDuplicateImportedWithShortAuthValue1(c *check.C) {
primary := s.CreateStoragePrimaryKeyRSA(c)
public, sensitive := s.makeSealedObjectExternal()
trial, _ := tpm2.ComputeAuthPolicy(tpm2.HashAlgorithmSHA256)
trial.PolicyCommandCode(tpm2.CommandDuplicate)
public.AuthPolicy = trial.GetDigest()
sensitive.AuthValue = []byte("password\x00\x00")
object := s.importObjectFromSensitiveAndLoad(c, primary, public, sensitive)
session := s.StartAuthSession(c, nil, nil, tpm2.SessionTypePolicy, nil, tpm2.HashAlgorithmSHA256)
c.Check(s.TPM.PolicyCommandCode(session, tpm2.CommandDuplicate), check.IsNil)
_, duplicate, _, err := s.TPM.Duplicate(object, nil, nil, nil, session)
c.Assert(err, check.IsNil)
sensitive2, err := tpm2.UnwrapDuplicationObjectToSensitive(duplicate, public, nil, tpm2.HashAlgorithmNull, nil, nil, nil, nil)
c.Assert(err, check.IsNil)
expectedAuthValue := make(tpm2.Auth, public.NameAlg.Size())
copy(expectedAuthValue, sensitive.AuthValue)
// We duplicated an object imported into the TPM. The object had an authorization
// value that wasn't padded to the size of the name algorithm. The reference TPM
// implementation corrects this, so we should see the corrected version in the
// duplicated sensitive area.
c.Check(sensitive2.AuthValue, check.DeepEquals, expectedAuthValue)
}
func (s *authSuite) TestObjectSizeImported(c *check.C) {
primary := s.CreateStoragePrimaryKeyRSA(c)
public, sensitive := s.makeSealedObjectExternal()
priv := s.importObjectFromSensitive(c, primary, public, sensitive)
// The reference TPM implementation pads the auth value of objects to the size
// of the name algorithm, and EntityGetAuthValue removes the trailing zeroes
// when the auth value is used later. This is to avoid leaking the size of
// the authorization value from the TPM. Other tests check the sensitive
// area from duplicated objects, but check that the size isn't leaked in
// an object currently protected by the TPM by checking that the private
// area has the expected size.
//
// The private area consists of the following fields (the sensitive
// area is encrypted):
// ============================================
// = size (2 bytes) | outer HMAC (32 bytes) =
// = size (2 bytes) | symmetric IV (16 bytes) =
// = size of sensitive area (2 bytes) =
// = sensitiveType (2 bytes) =
// = size (2 bytes) | authValue (32 bytes) =
// = size (2 bytes) | seedValue (32 bytes) =
// = size (2 bytes) | sensitive (32 bytes) =
// ============================================
// The size of the private area might be 134 bytes on A TPM that behaves
// incorrectly
c.Check(priv, testutil.LenEquals, 158)
}
func (s *authSuite) TestNVIndex(c *check.C) {
pub := tpm2.NVPublic{
Index: s.NextAvailableHandle(c, 0x01800000),
NameAlg: tpm2.HashAlgorithmSHA256,
Attrs: tpm2.NVTypeOrdinary.WithAttrs(tpm2.AttrNVAuthRead|tpm2.AttrNVAuthWrite|tpm2.AttrNVNoDA),
Size: 8}
index, err := s.TPM.NVDefineSpace(s.TPM.OwnerHandleContext(), []byte("password"), &pub, nil)
c.Assert(err, check.IsNil)
c.Check(s.TPM.NVWrite(index, index, nil, 0, nil), check.IsNil)
}
func (s *authSuite) TestNVIndexAuthValueWithTrailingZeroes(c *check.C) {
pub := tpm2.NVPublic{
Index: s.NextAvailableHandle(c, 0x01800000),
NameAlg: tpm2.HashAlgorithmSHA256,
Attrs: tpm2.NVTypeOrdinary.WithAttrs(tpm2.AttrNVAuthRead|tpm2.AttrNVAuthWrite|tpm2.AttrNVNoDA),
Size: 8}
index, err := s.TPM.NVDefineSpace(s.TPM.OwnerHandleContext(), []byte("password\x00\x00"), &pub, nil)
c.Assert(err, check.IsNil)
// We created a NV index with an auth value that has trailing zeroes.
// The reference TPM implementation removes the trailing zeroes before
// storing it to NV, and the frontend removes trailing zeroes
// from the password session, so this should work fine.
c.Check(s.TPM.NVWrite(index, index, nil, 0, nil), check.IsNil)
}
func (s *authSuite) TestNVIndexAuthValueWithTrailingZeroesAndUnboundHMACSession(c *check.C) {
pub := tpm2.NVPublic{
Index: s.NextAvailableHandle(c, 0x01800000),
NameAlg: tpm2.HashAlgorithmSHA256,
Attrs: tpm2.NVTypeOrdinary.WithAttrs(tpm2.AttrNVAuthRead|tpm2.AttrNVAuthWrite|tpm2.AttrNVNoDA),
Size: 8}
index, err := s.TPM.NVDefineSpace(s.TPM.OwnerHandleContext(), []byte("password\x00\x00"), &pub, nil)
c.Assert(err, check.IsNil)
session := s.StartAuthSession(c, nil, nil, tpm2.SessionTypeHMAC, nil, tpm2.HashAlgorithmSHA256)
// We created a NV index with an auth value that has trailing zeroes.
// The reference TPM implementation removes the trailing zeroes before
// storing it to NV, and we remove the trailing zeroes when computing
// the HMAC key, so this should work fine.
c.Check(s.TPM.NVWrite(index, index, nil, 0, session), check.IsNil)
}
func (s *authSuite) TestNVIndexAuthValueWithTrailingZeroesAndBoundHMACSession(c *check.C) {
pub := tpm2.NVPublic{
Index: s.NextAvailableHandle(c, 0x01800000),
NameAlg: tpm2.HashAlgorithmSHA256,
Attrs: tpm2.NVTypeOrdinary.WithAttrs(tpm2.AttrNVAuthRead|tpm2.AttrNVAuthWrite|tpm2.AttrNVNoDA),
Size: 8}
index, err := s.TPM.NVDefineSpace(s.TPM.OwnerHandleContext(), []byte("password\x00\x00"), &pub, nil)
c.Assert(err, check.IsNil)
session := s.StartAuthSession(c, nil, index, tpm2.SessionTypeHMAC, nil, tpm2.HashAlgorithmSHA256)
// We created a NV index with an auth value that has trailing zeroes.
// The reference TPM implementation removes the trailing zeroes before
// storing it to NV, and we remove the trailing zeroes when computing
// the session key, so this should work fine.
c.Check(s.TPM.NVWrite(index, index, nil, 0, session), check.IsNil)
}
func printTPMInfo() {
var tcti tpm2.TCTI
var err error
if opts.Mssim != nil {
tcti, err = tpm2.OpenMssim("", *opts.Mssim)
} else {
tcti, err = tpm2.OpenTPMDevice(opts.TPM)
}
if err != nil {
fmt.Fprintf(os.Stderr, "cannot open TPM device: %v", err)
return
}
tpm, _ := tpm2.NewTPMContext(tcti)
defer tpm.Close()
manufacturer, err := tpm.GetManufacturer()
if err != nil {
fmt.Fprintf(os.Stderr, "cannot determine TPM manufacturer: %v", err)
return
}
fmt.Printf("TPM manufacturer: %v\n", manufacturer)
props, err := tpm.GetCapabilityTPMProperties(tpm2.PropertyVendorString1, 7)
if err != nil {
fmt.Fprintf(os.Stderr, "cannot obtain TPM properties: %v", err)
return
}
vendorString := new(bytes.Buffer)
var firmwareVersion [8]byte
for _, prop := range props {
switch prop.Property {
case tpm2.PropertyVendorString1, tpm2.PropertyVendorString2, tpm2.PropertyVendorString3, tpm2.PropertyVendorString4:
binary.Write(vendorString, binary.BigEndian, prop.Value)
case tpm2.PropertyFirmwareVersion1:
binary.BigEndian.PutUint32(firmwareVersion[0:], prop.Value)
case tpm2.PropertyFirmwareVersion2:
binary.BigEndian.PutUint32(firmwareVersion[4:], prop.Value)
}
}
vendorBytes := vendorString.Bytes()
vendor, _ := vendorString.ReadString(0)
fmt.Printf("TPM vendor string: %s\n", vendor)
fmt.Printf("TPM vendor string (bytes): 0x%x\n", vendorBytes)
fmt.Printf("TPM firmware version: 0x%x\n", firmwareVersion)
}
func run() error {
if _, err := flags.Parse(&opts); err != nil {
return err
}
if opts.Mssim != nil {
testutil.TPMBackend = testutil.TPMBackendMssim
testutil.MssimPort = *opts.Mssim
shutdown, err := testutil.LaunchTPMSimulator(nil)
if err != nil {
return fmt.Errorf("cannot start simulator: %v", err)
}
defer shutdown()
} else {
testutil.TPMBackend = testutil.TPMBackendDevice
testutil.TPMDevicePath = opts.TPM
}
testutil.PermittedTPMFeatures = testutil.TPMFeatureOwnerHierarchy|testutil.TPMFeatureNV
printTPMInfo()
if opts.Mssim == nil {
fmt.Println("")
fmt.Println("This may take a few minutes to run on a real TPM device.")
fmt.Println("Interrupting this test will prevent the fixture from restoring ")
fmt.Println("the TPM to the state it was at the start of the test!")
}
conf := new(check.RunConf)
if len(opts.Verbose) >= 1 {
conf.Verbose = true
}
if len(opts.Verbose) >= 2 {
conf.Stream = true
}
results := check.RunAll(conf)
println(results.String())
if !results.Passed() {
return errors.New("not all tests passed")
}
return nil
}
func main() {
if err := run(); err != nil {
switch e := err.(type) {
case *flags.Error:
// flags already prints this
if e.Type != flags.ErrHelp {
os.Exit(1)
}
default:
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment