Skip to content

Commit

Permalink
policyutil: handle TPM2_PolicyDuplicationSelect with missing object name
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisccoulson committed Apr 9, 2024
1 parent ca90fb1 commit 592b5cf
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 38 deletions.
24 changes: 10 additions & 14 deletions policyutil/branch.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,18 +210,14 @@ func (s *policyPathWildcardResolver) filterUsageIncompatibleBranches() error {

for p, d := range s.detailsMap {
code, set := d.CommandCode()
if set && code != s.usage.commandCode {
if set && code != s.usage.CommandCode() {
delete(s.detailsMap, p)
continue
}

cpHash, set := d.CpHash()
if set {
var handleNames []Named
for _, handle := range s.usage.handles {
handleNames = append(handleNames, handle)
}
usageCpHash, err := ComputeCpHash(s.sessionAlg, s.usage.commandCode, handleNames, s.usage.params...)
usageCpHash, err := s.usage.CpHash(s.sessionAlg)
if err != nil {
return fmt.Errorf("cannot obtain cpHash from usage parameters: %w", err)
}
Expand All @@ -233,11 +229,7 @@ func (s *policyPathWildcardResolver) filterUsageIncompatibleBranches() error {

nameHash, set := d.NameHash()
if set {
var handleNames []Named
for _, handle := range s.usage.handles {
handleNames = append(handleNames, handle)
}
usageNameHash, err := ComputeNameHash(s.sessionAlg, handleNames...)
usageNameHash, err := s.usage.NameHash(s.sessionAlg)
if err != nil {
return fmt.Errorf("cannot obtain nameHash from usage parameters: %w", err)
}
Expand All @@ -247,14 +239,14 @@ func (s *policyPathWildcardResolver) filterUsageIncompatibleBranches() error {
}
}

if d.AuthValueNeeded && s.usage.noAuthValue {
if d.AuthValueNeeded && !s.usage.AllowAuthValue() {
delete(s.detailsMap, p)
continue
}

nvWritten, set := d.NvWritten()
if set {
authHandle := s.usage.handles[s.usage.authIndex]
authHandle := s.usage.AuthHandle()
if authHandle.Handle().Type() != tpm2.HandleTypeNVIndex {
delete(s.detailsMap, p)
continue
Expand Down Expand Up @@ -547,7 +539,7 @@ func (s *policyPathWildcardResolver) filterNVIncompatibleBranches() error {

rc := tpm2.NewLimitedResourceContext(nv.Index, nv.Name)
params := &PolicyExecuteParams{
Usage: NewPolicySessionUsage(tpm2.CommandNVRead, []NamedHandle{rc, rc}, uint16(len(nv.OperandB)), nv.Offset).NoAuthValue(),
Usage: NewPolicySessionUsage(tpm2.CommandNVRead, []NamedHandle{rc, rc}, uint16(len(nv.OperandB)), nv.Offset).WithoutAuthValue(),
}

resources := new(nullPolicyResources)
Expand Down Expand Up @@ -852,6 +844,10 @@ func (w *treeWalker) resources() policyResources {
return w.policyResources
}

func (r *treeWalker) authResourceName() tpm2.Name {
return nil
}

func (w *treeWalker) loadExternal(public *tpm2.Public) (ResourceContext, error) {
// the handle is not relevant here
resource := tpm2.NewLimitedResourceContext(0x80000000, public.Name())
Expand Down
28 changes: 19 additions & 9 deletions policyutil/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ func (r *policyBuilderBranchRunner) resources() policyResources {
return &r.policyResources
}

func (r *policyBuilderBranchRunner) authResourceName() tpm2.Name {
return nil
}

func (*policyBuilderBranchRunner) loadExternal(public *tpm2.Public) (ResourceContext, error) {
// the handle is not relevant here
resource := tpm2.NewLimitedResourceContext(0x80000000, public.Name())
Expand Down Expand Up @@ -262,7 +266,7 @@ func (b *PolicyBuilderBranch) PolicySecret(authObject Named, policyRef tpm2.Nonc
}

authObjectName := authObject.Name()
if !authObjectName.IsValid() {
if len(authObjectName) == 0 || !authObjectName.IsValid() {
return nil, b.policy.fail("PolicySecret", errors.New("invalid authObject name"))
}

Expand Down Expand Up @@ -292,7 +296,7 @@ func (b *PolicyBuilderBranch) PolicySigned(authKey *tpm2.Public, policyRef tpm2.
}

authKeyName := authKey.Name()
if !authKeyName.IsValid() {
if len(authKeyName) == 0 || !authKeyName.IsValid() {
return nil, b.policy.fail("PolicySigned", errors.New("invalid authKey"))
}

Expand Down Expand Up @@ -536,9 +540,14 @@ func (b *PolicyBuilderBranch) PolicyPCR(values tpm2.PCRValues) (tpm2.Digest, err
}

// PolicyDuplicationSelect adds a TPM2_PolicyDuplicationSelect assertion to this branch in order
// to permit duplication of object to newParent with the [tpm2.TPMContext.Duplicate] function. Note
// that object must be supplied even if includeObject is false because the assertion sets the name
// hash of the session context to restrict the usage of the session to the specified pair of objects.
// to permit duplication of object to newParent with the [tpm2.TPMContext.Duplicate] function.
// If includeObject is true, then the assertion is bound to both object and newParent. If
// includeObject is false then the assertion is only bound to newParent. In this case, supplying
// object is optional. Note that when the TPM2_PolicyDuplicationSelect assertions is executed,
// the object name must be supplied because the assertion sets the name hash of the session. If
// object is supplied here, then it will be included in the policy and used when the assertion is
// executed. If it isn't supplied here, then it will be obtained from the [PolicySessionUsage]
// supplied to [Policy.Execute].
func (b *PolicyBuilderBranch) PolicyDuplicationSelect(object, newParent Named, includeObject bool) (tpm2.Digest, error) {
if err := b.prepareToModifyBranch(); err != nil {
return nil, b.policy.fail("PolicyDuplicationSelect", err)
Expand All @@ -547,15 +556,16 @@ func (b *PolicyBuilderBranch) PolicyDuplicationSelect(object, newParent Named, i
var objectName tpm2.Name
if object != nil {
objectName = object.Name()
if !objectName.IsValid() {
return nil, b.policy.fail("PolicyDuplicationSelect", errors.New("invalid object name"))
}
}
if (includeObject && len(objectName) == 0) || !objectName.IsValid() {
return nil, b.policy.fail("PolicyDuplicationSelect", errors.New("invalid object name"))
}

var newParentName tpm2.Name
if newParent != nil {
newParentName = newParent.Name()
}
if newParentName.Type() == tpm2.NameTypeNone || !newParentName.IsValid() {
if len(newParentName) == 0 || !newParentName.IsValid() {
return nil, b.policy.fail("PolicyDuplicationSelect", errors.New("invalid newParent name"))
}

Expand Down
37 changes: 34 additions & 3 deletions policyutil/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -897,9 +897,13 @@ func (s *builderSuite) testPolicyDuplicationSelect(c *C, data *testBuildPolicyDu
c.Check(err, IsNil)
c.Check(digest, DeepEquals, data.expectedDigest)

var objectName tpm2.Name
if data.object != nil {
objectName = data.object.Name()
}
expectedPolicy := NewMockPolicy(
TaggedHashList{{HashAlg: tpm2.HashAlgorithmSHA256, Digest: data.expectedDigest}}, nil,
NewMockPolicyDuplicationSelectElement(data.object.Name(), data.newParent.Name(), data.includeObject))
NewMockPolicyDuplicationSelectElement(objectName, data.newParent.Name(), data.includeObject))

digest, policy, err := builder.Policy()
c.Check(err, IsNil)
Expand All @@ -909,7 +913,7 @@ func (s *builderSuite) testPolicyDuplicationSelect(c *C, data *testBuildPolicyDu
Policy {
# digest TPM_ALG_SHA256:%#x
PolicyDuplicationSelect(objectName:%#x, newParentName:%#x, includeObject:%t)
}`, data.expectedDigest, data.object.Name(), data.newParent.Name(), data.includeObject))
}`, data.expectedDigest, objectName, data.newParent.Name(), data.includeObject))
digest, err = builder.Digest()
c.Check(digest, DeepEquals, data.expectedDigest)
}
Expand Down Expand Up @@ -946,6 +950,17 @@ func (s *builderSuite) TestPolicyDuplicationSelectNoIncludeObject(c *C) {
expectedDigest: internal_testutil.DecodeHexString(c, "a9ceacb309fb05bdc45784f0647641bcd2f3a05a10ed94c5525413c7da33234e")})
}

func (s *builderSuite) TestPolicyDuplicationSelectNoIncludeObjectName(c *C) {
h := crypto.SHA256.New()
io.WriteString(h, "bar")
newParent := tpm2.Name(mu.MustMarshalToBytes(tpm2.HashAlgorithmSHA256, mu.Raw(h.Sum(nil))))

s.testPolicyDuplicationSelect(c, &testBuildPolicyDuplicationSelectData{
newParent: newParent,
includeObject: false,
expectedDigest: internal_testutil.DecodeHexString(c, "a9ceacb309fb05bdc45784f0647641bcd2f3a05a10ed94c5525413c7da33234e")})
}

func (s *builderSuite) TestPolicyDuplicationSelectDifferentNames(c *C) {
h := crypto.SHA256.New()
io.WriteString(h, "bar")
Expand All @@ -971,8 +986,24 @@ func (s *builderSuite) TestPolicyDuplicationSelectInvalidNewParentName(c *C) {
}

func (s *builderSuite) TestPolicyDuplicationSelectInvalidObjectName(c *C) {
h := crypto.SHA256.New()
io.WriteString(h, "bar")
newParent := tpm2.Name(mu.MustMarshalToBytes(tpm2.HashAlgorithmSHA256, mu.Raw(h.Sum(nil))))

builder := NewPolicyBuilder(tpm2.HashAlgorithmSHA256)
_, err := builder.RootBranch().PolicyDuplicationSelect(tpm2.Name{0, 0}, newParent, true)
c.Check(err, ErrorMatches, `invalid object name`)
_, _, err = builder.Policy()
c.Check(err, ErrorMatches, `could not build policy: encountered an error when calling PolicyDuplicationSelect: invalid object name`)
}

func (s *builderSuite) TestPolicyDuplicationSelectMissingObjectName(c *C) {
h := crypto.SHA256.New()
io.WriteString(h, "bar")
newParent := tpm2.Name(mu.MustMarshalToBytes(tpm2.HashAlgorithmSHA256, mu.Raw(h.Sum(nil))))

builder := NewPolicyBuilder(tpm2.HashAlgorithmSHA256)
_, err := builder.RootBranch().PolicyDuplicationSelect(tpm2.Name{0, 0}, nil, true)
_, err := builder.RootBranch().PolicyDuplicationSelect(nil, newParent, true)
c.Check(err, ErrorMatches, `invalid object name`)
_, _, err = builder.Policy()
c.Check(err, ErrorMatches, `could not build policy: encountered an error when calling PolicyDuplicationSelect: invalid object name`)
Expand Down
65 changes: 62 additions & 3 deletions policyutil/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ type policyRunner interface {
tickets() policyTickets
resources() policyResources

authResourceName() tpm2.Name
loadExternal(public *tpm2.Public) (ResourceContext, error)
authorize(auth ResourceContext, askForPolicy bool, usage *PolicySessionUsage, prefer tpm2.SessionType) (SessionContext, error)
runBranch(branches policyBranches) (selected int, err error)
Expand Down Expand Up @@ -775,7 +776,11 @@ type policyDuplicationSelectElement struct {
func (*policyDuplicationSelectElement) name() string { return "TPM2_PolicyDuplicationSelect assertion" }

func (e *policyDuplicationSelectElement) run(runner policyRunner) error {
return runner.session().PolicyDuplicationSelect(e.Object, e.NewParent, e.IncludeObject)
object := e.Object
if len(object) == 0 && !e.IncludeObject {
object = runner.authResourceName()
}
return runner.session().PolicyDuplicationSelect(object, e.NewParent, e.IncludeObject)
}

type policyPasswordElement struct{}
Expand Down Expand Up @@ -1096,6 +1101,13 @@ func (r *policyExecuteRunner) resources() policyResources {
return r.policyResources
}

func (r *policyExecuteRunner) authResourceName() tpm2.Name {
if r.usage == nil {
return nil
}
return r.usage.handles[r.usage.authIndex].Name()
}

func (r *policyExecuteRunner) loadExternal(public *tpm2.Public) (ResourceContext, error) {
if public.IsAsymmetric() {
return r.tpm.LoadExternal(nil, public, tpm2.HandleOwner)
Expand Down Expand Up @@ -1421,13 +1433,48 @@ func (u *PolicySessionUsage) WithAuthIndex(index uint8) *PolicySessionUsage {
return u
}

// NoAuthValue indicates that the policy session is being used to authorize a
// WithoutAuthValue indicates that the policy session is being used to authorize a
// resource that the authorization value cannot be determined for.
func (u *PolicySessionUsage) NoAuthValue() *PolicySessionUsage {
func (u *PolicySessionUsage) WithoutAuthValue() *PolicySessionUsage {
u.noAuthValue = true
return u
}

// CommandCode returns the command code for this usage.
func (u PolicySessionUsage) CommandCode() tpm2.CommandCode {
return u.commandCode
}

// CpHash returns the command parameter hash for this usage for the specified session
// algorithm.
func (u PolicySessionUsage) CpHash(alg tpm2.HashAlgorithmId) (tpm2.Digest, error) {
var handleNames []Named
for _, handle := range u.handles {
handleNames = append(handleNames, handle)
}
return ComputeCpHash(alg, u.commandCode, handleNames, u.params...)
}

// NameHash returns the name hash for this usage for the specified session algorithm.
func (u PolicySessionUsage) NameHash(alg tpm2.HashAlgorithmId) (tpm2.Digest, error) {
var handleNames []Named
for _, handle := range u.handles {
handleNames = append(handleNames, handle)
}
return ComputeNameHash(alg, handleNames...)
}

// AllowAuthValue indicates whether this usage permits use of the auth value for the
// resource being authorized.
func (u PolicySessionUsage) AllowAuthValue() bool {
return !u.noAuthValue
}

// AuthHandle returns the handle for the resource being authorized.
func (u PolicySessionUsage) AuthHandle() NamedHandle {
return u.handles[u.authIndex]
}

// PolicyAuthorizationID contains an identifier for a TPM2_PolicySecret,
// TPM2_PolicySigned or TPM2_PolicyAuthorize assertion.
type PolicyAuthorizationID = PolicyAuthorizationDetails
Expand Down Expand Up @@ -1709,6 +1756,10 @@ func (r *policyComputeRunner) resources() policyResources {
return &r.policyResources
}

func (r *policyComputeRunner) authResourceName() tpm2.Name {
return nil
}

func (r *policyComputeRunner) loadExternal(public *tpm2.Public) (ResourceContext, error) {
// the handle is not relevant here
resource := tpm2.NewLimitedResourceContext(0x80000000, public.Name())
Expand Down Expand Up @@ -1918,6 +1969,10 @@ func (r *policyValidateRunner) resources() policyResources {
return &r.policyResources
}

func (r *policyValidateRunner) authResourceName() tpm2.Name {
return nil
}

func (r *policyValidateRunner) loadExternal(public *tpm2.Public) (ResourceContext, error) {
// the handle is not relevant here
resource := tpm2.NewLimitedResourceContext(0x80000000, public.Name())
Expand Down Expand Up @@ -2319,6 +2374,10 @@ func (r *policyStringifierRunner) resources() policyResources {
return r.policyResources
}

func (r *policyStringifierRunner) authResourceName() tpm2.Name {
return nil
}

func (r *policyStringifierRunner) loadExternal(public *tpm2.Public) (ResourceContext, error) {
// the handle is not relevant here
resource := tpm2.NewLimitedResourceContext(0x80000000, public.Name())
Expand Down
Loading

0 comments on commit 592b5cf

Please sign in to comment.