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

tpm2: Create TPM2 keys with noDA attribute if no user auth is required #352

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
13 changes: 12 additions & 1 deletion tpm2/export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ type KeyData_v2 = keyData_v2
type KeyData_v3 = keyData_v3
type AdditionalData_v3 = additionalData_v3
type KeyDataError = keyDataError
type SealedKeyDataParams = makeSealedKeyDataParams
type MakeSealedKeyDataParams = makeSealedKeyDataParams
type KeyDataPolicy = keyDataPolicy
type KeyDataPolicy_v0 = keyDataPolicy_v0
type KeyDataPolicy_v1 = keyDataPolicy_v1
Expand All @@ -83,6 +83,9 @@ func NewSealedObjectKeySealer(tpm *Connection) keySealer {
return &sealedObjectKeySealer{tpm}
}

type KeyDataConstructor = keyDataConstructor
type KeySealer = keySealer

type PcrPolicyVersionOption = pcrPolicyVersionOption
type PolicyDataError = policyDataError
type PolicyOrData_v0 = policyOrData_v0
Expand Down Expand Up @@ -191,6 +194,14 @@ func MockEnsurePcrPolicyCounter(fn func(*tpm2.TPMContext, tpm2.Handle, *tpm2.Pub
}
}

func MockMakeSealedKeyData(fn func(*tpm2.TPMContext, *MakeSealedKeyDataParams, KeySealer, KeyDataConstructor, tpm2.SessionContext) (*secboot.KeyData, secboot.PrimaryKey, secboot.DiskUnlockKey, error)) (restore func()) {
orig := makeSealedKeyData
makeSealedKeyData = fn
return func() {
makeSealedKeyData = orig
}
}

func MockNewKeyDataPolicy(fn func(tpm2.HashAlgorithmId, *tpm2.Public, string, *tpm2.NVPublic, bool) (KeyDataPolicy, tpm2.Digest, error)) (restore func()) {
orig := newKeyDataPolicy
newKeyDataPolicy = fn
Expand Down
12 changes: 9 additions & 3 deletions tpm2/key_sealer.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ type keySealer interface {
// and with the specified name algorithm and authorization policy. It returns
// the private and public parts of the object, and an optional secret value if
// the returned object has to be imported.
CreateSealedObject(data []byte, nameAlg tpm2.HashAlgorithmId, policy tpm2.Digest) (tpm2.Private, *tpm2.Public, tpm2.EncryptedSecret, error)
CreateSealedObject(data []byte, nameAlg tpm2.HashAlgorithmId, policy tpm2.Digest, noDA bool) (tpm2.Private, *tpm2.Public, tpm2.EncryptedSecret, error)
}

// sealedObjectKeySealer is an implementation of keySealer that seals data to
Expand All @@ -42,7 +42,7 @@ type sealedObjectKeySealer struct {
tpm *Connection
}

func (s *sealedObjectKeySealer) CreateSealedObject(data []byte, nameAlg tpm2.HashAlgorithmId, policy tpm2.Digest) (tpm2.Private, *tpm2.Public, tpm2.EncryptedSecret, error) {
func (s *sealedObjectKeySealer) CreateSealedObject(data []byte, nameAlg tpm2.HashAlgorithmId, policy tpm2.Digest, noDA bool) (tpm2.Private, *tpm2.Public, tpm2.EncryptedSecret, error) {
// Obtain a context for the SRK now. If we're called immediately after ProvisionTPM without
// closing the Connection, we use the context cached by ProvisionTPM, which corresponds to
// the object provisioned. If not, we just unconditionally provision a new SRK as this function
Expand Down Expand Up @@ -79,6 +79,9 @@ func (s *sealedObjectKeySealer) CreateSealedObject(data []byte, nameAlg tpm2.Has
// Define the template
template := templates.NewSealedObject(nameAlg)
template.Attrs &^= tpm2.AttrUserWithAuth
if noDA {
template.Attrs |= tpm2.AttrNoDA
}
template.AuthPolicy = policy

// Now create the sealed key object. The command is integrity protected so if the object
Expand All @@ -101,9 +104,12 @@ type importableObjectKeySealer struct {
tpmKey *tpm2.Public
}

func (s *importableObjectKeySealer) CreateSealedObject(data []byte, nameAlg tpm2.HashAlgorithmId, policy tpm2.Digest) (tpm2.Private, *tpm2.Public, tpm2.EncryptedSecret, error) {
func (s *importableObjectKeySealer) CreateSealedObject(data []byte, nameAlg tpm2.HashAlgorithmId, policy tpm2.Digest, noDA bool) (tpm2.Private, *tpm2.Public, tpm2.EncryptedSecret, error) {
pub, sensitive := util.NewExternalSealedObject(nameAlg, nil, data)
pub.Attrs &^= tpm2.AttrUserWithAuth
if noDA {
pub.Attrs |= tpm2.AttrNoDA
}
pub.AuthPolicy = policy

// Now create the importable sealed key object (duplication object).
Expand Down
52 changes: 44 additions & 8 deletions tpm2/key_sealer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,19 +59,24 @@ type testCreateSealedObjectData struct {
data tpm2.SensitiveData
nameAlg tpm2.HashAlgorithmId
policyDigest tpm2.Digest
noDA bool
session tpm2.SessionContext
}

func (s *sealedObjectKeySealerSuite) testCreateSealedObject(c *C, data *testCreateSealedObjectData) {
sealer := NewSealedObjectKeySealer(s.TPM())

priv, pub, importSymSeed, err := sealer.CreateSealedObject(data.data, data.nameAlg, data.policyDigest)
priv, pub, importSymSeed, err := sealer.CreateSealedObject(data.data, data.nameAlg, data.policyDigest, data.noDA)
c.Assert(err, IsNil)
c.Check(importSymSeed, IsNil)

c.Check(pub.Type, Equals, tpm2.ObjectTypeKeyedHash)
c.Check(pub.NameAlg, Equals, data.nameAlg)
c.Check(pub.Attrs, Equals, tpm2.AttrFixedParent|tpm2.AttrFixedTPM)
expectedAttrs := tpm2.AttrFixedParent | tpm2.AttrFixedTPM
if data.noDA {
expectedAttrs |= tpm2.AttrNoDA
}
c.Check(pub.Attrs, Equals, expectedAttrs)
c.Check(pub.AuthPolicy, DeepEquals, data.policyDigest)
c.Check(pub.Params, DeepEquals,
&tpm2.PublicParamsU{
Expand All @@ -96,6 +101,7 @@ func (s *sealedObjectKeySealerSuite) TestCreateSealedObject(c *C) {
data: []byte("foo"),
nameAlg: tpm2.HashAlgorithmSHA256,
policyDigest: make([]byte, 32),
noDA: true,
session: s.StartAuthSession(c, nil, nil, tpm2.SessionTypePolicy, nil, tpm2.HashAlgorithmSHA256)})
}

Expand All @@ -108,6 +114,7 @@ func (s *sealedObjectKeySealerSuite) TestCreateSealedObjectWithNewConnection(c *
data: []byte("foo"),
nameAlg: tpm2.HashAlgorithmSHA256,
policyDigest: make([]byte, 32),
noDA: true,
session: s.StartAuthSession(c, nil, nil, tpm2.SessionTypePolicy, nil, tpm2.HashAlgorithmSHA256)})
}

Expand All @@ -122,6 +129,7 @@ func (s *sealedObjectKeySealerSuite) TestCreateSealedObjectMissingSRK(c *C) {
data: []byte("foo"),
nameAlg: tpm2.HashAlgorithmSHA256,
policyDigest: make([]byte, 32),
noDA: true,
session: s.StartAuthSession(c, nil, nil, tpm2.SessionTypePolicy, nil, tpm2.HashAlgorithmSHA256)})
}

Expand All @@ -130,6 +138,7 @@ func (s *sealedObjectKeySealerSuite) TestCreateSealedObjectDifferentData(c *C) {
data: []byte("bar"),
nameAlg: tpm2.HashAlgorithmSHA256,
policyDigest: make([]byte, 32),
noDA: true,
session: s.StartAuthSession(c, nil, nil, tpm2.SessionTypePolicy, nil, tpm2.HashAlgorithmSHA256)})
}

Expand All @@ -138,6 +147,7 @@ func (s *sealedObjectKeySealerSuite) TestCreateSealedObjectDifferentNameAlg(c *C
data: []byte("foo"),
nameAlg: tpm2.HashAlgorithmSHA1,
policyDigest: make([]byte, 20),
noDA: true,
session: s.StartAuthSession(c, nil, nil, tpm2.SessionTypePolicy, nil, tpm2.HashAlgorithmSHA1)})
}

Expand All @@ -152,9 +162,19 @@ func (s *sealedObjectKeySealerSuite) TestCreateSealedObjectDifferentPolicy(c *C)
data: []byte("foo"),
nameAlg: tpm2.HashAlgorithmSHA256,
policyDigest: trial.GetDigest(),
noDA: true,
session: session})
}

func (s *sealedObjectKeySealerSuite) TestCreateSealedObjectWithDA(c *C) {
s.testCreateSealedObject(c, &testCreateSealedObjectData{
data: []byte("foo"),
nameAlg: tpm2.HashAlgorithmSHA256,
policyDigest: make([]byte, 32),
noDA: false,
session: s.StartAuthSession(c, nil, nil, tpm2.SessionTypePolicy, nil, tpm2.HashAlgorithmSHA256)})
}

type importableObjectKeySealerSuite struct{}

var _ = Suite(&importableObjectKeySealerSuite{})
Expand All @@ -167,12 +187,16 @@ func (s *importableObjectKeySealerSuite) testCreateSealedObject(c *C, data *test

sealer := NewImportableObjectKeySealer(srk)

priv, pub, importSymSeed, err := sealer.CreateSealedObject(data.data, data.nameAlg, data.policyDigest)
priv, pub, importSymSeed, err := sealer.CreateSealedObject(data.data, data.nameAlg, data.policyDigest, data.noDA)
c.Assert(err, IsNil)

c.Check(pub.Type, Equals, tpm2.ObjectTypeKeyedHash)
c.Check(pub.NameAlg, Equals, data.nameAlg)
c.Check(pub.Attrs, Equals, tpm2.ObjectAttributes(0))
expectedAttrs := tpm2.ObjectAttributes(0)
if data.noDA {
expectedAttrs |= tpm2.AttrNoDA
}
c.Check(pub.Attrs, Equals, expectedAttrs)
c.Check(pub.AuthPolicy, DeepEquals, data.policyDigest)
c.Check(pub.Params, DeepEquals,
&tpm2.PublicParamsU{
Expand All @@ -191,21 +215,24 @@ func (s *importableObjectKeySealerSuite) TestCreateSealedObject(c *C) {
s.testCreateSealedObject(c, &testCreateSealedObjectData{
data: []byte("foo"),
nameAlg: tpm2.HashAlgorithmSHA256,
policyDigest: make([]byte, 32)})
policyDigest: make([]byte, 32),
noDA: true})
}

func (s *importableObjectKeySealerSuite) TestCreateSealedObjectDifferentData(c *C) {
s.testCreateSealedObject(c, &testCreateSealedObjectData{
data: []byte("bar"),
nameAlg: tpm2.HashAlgorithmSHA256,
policyDigest: make([]byte, 32)})
policyDigest: make([]byte, 32),
noDA: true})
}

func (s *importableObjectKeySealerSuite) TestCreateSealedObjectiDifferentNameAlg(c *C) {
s.testCreateSealedObject(c, &testCreateSealedObjectData{
data: []byte("foo"),
nameAlg: tpm2.HashAlgorithmSHA1,
policyDigest: make([]byte, 20)})
policyDigest: make([]byte, 20),
noDA: true})
}

func (s *importableObjectKeySealerSuite) TestCreateSealedObjectWithDifferentPolicy(c *C) {
Expand All @@ -215,5 +242,14 @@ func (s *importableObjectKeySealerSuite) TestCreateSealedObjectWithDifferentPoli
s.testCreateSealedObject(c, &testCreateSealedObjectData{
data: []byte("foo"),
nameAlg: tpm2.HashAlgorithmSHA256,
policyDigest: trial.GetDigest()})
policyDigest: trial.GetDigest(),
noDA: true})
}

func (s *importableObjectKeySealerSuite) TestCreateSealedObjectWithDA(c *C) {
s.testCreateSealedObject(c, &testCreateSealedObjectData{
data: []byte("foo"),
nameAlg: tpm2.HashAlgorithmSHA256,
policyDigest: make([]byte, 32),
noDA: false})
}
26 changes: 23 additions & 3 deletions tpm2/keydata.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (

"github.com/canonical/go-tpm2"
"github.com/canonical/go-tpm2/mu"
"github.com/canonical/go-tpm2/objectutil"

"golang.org/x/xerrors"

Expand Down Expand Up @@ -162,14 +163,33 @@ func (k *sealedKeyDataBase) load(tpm *tpm2.TPMContext, parent tpm2.ResourceConte

// validateData performs correctness checks on this object.
func (k *sealedKeyDataBase) validateData(tpm *tpm2.TPMContext, role string) (*tpm2.NVPublic, error) {
sealedKeyTemplate := makeImportableSealedKeyTemplate()
optsInternal := []objectutil.PublicTemplateOption{
objectutil.WithUserAuthMode(objectutil.RequirePolicy),
objectutil.WithProtectionGroupMode(objectutil.NonDuplicable),
objectutil.WithDuplicationMode(objectutil.FixedParent),
}
optsExternal := []objectutil.PublicTemplateOption{
objectutil.WithUserAuthMode(objectutil.RequirePolicy),
objectutil.WithProtectionGroupMode(objectutil.NonDuplicable),
objectutil.WithDuplicationMode(objectutil.DuplicationRoot),
}
if k.data.Policy().RequireUserAuth() {
optsInternal = append(optsInternal, objectutil.WithDictionaryAttackProtection())
optsExternal = append(optsExternal, objectutil.WithDictionaryAttackProtection())
} else {
optsInternal = append(optsInternal, objectutil.WithoutDictionaryAttackProtection())
optsExternal = append(optsExternal, objectutil.WithoutDictionaryAttackProtection())
}
internalSealedKeyTemplate := objectutil.NewSealedObjectTemplate(optsInternal...)
externalSealedKeyTemplate := objectutil.NewSealedObjectTemplate(optsExternal...)

// Perform some initial checks on the sealed data object's public area to
// make sure it's a sealed data object.
if k.data.Public().Type != sealedKeyTemplate.Type {
if k.data.Public().Type != internalSealedKeyTemplate.Type {
return nil, keyDataError{errors.New("sealed key object has the wrong type")}
}
if k.data.Public().Attrs&^(tpm2.AttrFixedTPM|tpm2.AttrFixedParent) != sealedKeyTemplate.Attrs {
attrs := k.data.Public().Attrs
if attrs != internalSealedKeyTemplate.Attrs && attrs != externalSealedKeyTemplate.Attrs {
return nil, keyDataError{errors.New("sealed key object has the wrong attributes")}
}

Expand Down
Loading
Loading