From 57a0ce424edaab83efe0c3d73a6d16205f13e2f3 Mon Sep 17 00:00:00 2001 From: Chris Coulson Date: Wed, 10 Apr 2024 23:30:32 +0100 Subject: [PATCH] Add extra private type field to HandleContext There used to be something similar, but then it was removed and the handle type was used to select the union contents, but then these fields needed to be sized because they may or may not be empty depending on the context. Instead, reintroduce a distinct context type that is separate from the handle type, have this correspond to concrete go types, and have some of these types map to nothing in the union. This way, we can guarantee that ObjectContext.Public will always return something, except after HandleContext.Dispose is called, and we can avoid returning ObjectContext and NVIndexContext implementations where it really doesn't make sense. --- cmds_context.go | 58 ++-- cmds_context_test.go | 54 +++- cmds_hashhmac.go | 4 +- cmds_hierarchy.go | 13 +- cmds_nv.go | 52 ++-- cmds_nv_test.go | 4 +- cmds_object.go | 16 +- cmds_session.go | 13 +- export_test.go | 2 +- policyutil/builder.go | 2 +- policyutil/path_resolver.go | 6 +- policyutil/policy.go | 6 +- policyutil/policy_test.go | 34 +-- policyutil/resources.go | 2 +- policyutil/walker.go | 2 +- resources.go | 525 +++++++++++++++++++++++------------- resources_test.go | 37 +-- testutil/transport.go | 2 +- 18 files changed, 522 insertions(+), 310 deletions(-) diff --git a/cmds_context.go b/cmds_context.go index b92c7a2..c225a5b 100644 --- a/cmds_context.go +++ b/cmds_context.go @@ -18,11 +18,13 @@ import ( // integrity protects the context with a key derived from the hierarchy proof. If saveContext does // not correspond to a transient object or a session, then it will return an error. // -// On successful completion, it returns a Context instance that can be passed to -// [TPMContext.ContextLoad]. Note that this function wraps the context data returned from the TPM +// On successful completion, it returns a Context structure that can be passed to +// [TPMContext.ContextLoad]. Note that this function wraps the context blob returned from the TPM // with some host-side state associated with the resource, so that it can be restored fully in -// [TPMContext.ContextLoad]. If saveContext corresponds to a session, the host-side state that is -// added to the returned context blob includes the session key. +// [TPMContext.ContextLoad]. This means that the context structure cannot be passed directly to the +// TPM using the TPM2_ContextLoad command, but [TPMContext.ContextLoad] must be used instead. If +// saveContext corresponds to a session, the host-side state that is added to the returned context +// blob includes the session key. // // If saveContext corresponds to a session, then TPM2_ContextSave also removes resources associated // with the session from the TPM (it becomes a saved session rather than a loaded session). In this @@ -55,14 +57,21 @@ func (t *TPMContext) ContextSave(saveContext HandleContext) (context *Context, e // ContextLoad executes the TPM2_ContextLoad command with the supplied Context, in order to restore // a context previously saved from [TPMContext.ContextSave]. // -// If the size field of the integrity HMAC in the context blob is greater than the size of the -// largest digest algorithm, a *[TPMError] with an error code of [ErrorSize] is returned. If the -// context blob is shorter than the size indicated for the integrity HMAC, a *[TPMError] with an -// error code of [ErrorInsufficient] is returned. +// Note that the context blob returned from [TPMContext.ContextSave] wraps the context blob returned +// from the TPM with some host-side state that can be used by this function to reconstruct a +// HandleContext. This function expects a context structure created by [TPMContext.ContextSave] as +// opposed to one created directly by the TPM2_ContextSave command on the TPM. // -// If the size of the context's integrity HMAC does not match the context integrity digest -// algorithm for the TPM, or the context blob is too short, a *[TPMParameterError] error with an -// error code of [ErrorSize] will be returned. If the integrity HMAC check fails, a +// If the size field of the integrity HMAC in the unwrapped context blob is greater than the size of +// the largest digest algorithm, a *[TPMError] with an error code of [ErrorSize] is returned. If the +// unwrapped context blob is shorter than the indicated size of the integrity HMAC, a *[TPMError] error +// with an error code of [ErrorInsufficient] is returned. +// +// If the size of the integrity HMAC in the unwrapped context blob does not match the size of the +// context integrity digest algorithm for the TPM, or the unwrapped context blob is too short, a +// *[TPMParameterError] error with an error code of [ErrorSize] is returned. +// +// If the integrity HMAC check for the context including the unwrapped blob fails, a // *[TPMParameterError] with an error code of [ErrorIntegrity] will be returned. // // If the hierarchy that the context is part of is disabled, a *[TPMParameterError] error with an @@ -127,15 +136,22 @@ func (t *TPMContext) ContextLoad(context *Context) (loadedContext HandleContext, if loadedHandle.Type() != HandleTypeTransient { return nil, &InvalidResponseError{CommandContextLoad, fmt.Errorf("handle %v returned from TPM is the wrong type", loadedHandle)} } - hc = newObjectContext(loadedHandle, hc.Name(), hc.(ObjectContext).Public()) + switch obj := hc.(type) { + case ObjectContext: + return newObjectContext(loadedHandle, hc.Name(), obj.Public()), nil + case ResourceContext: + return newResourceContext(loadedHandle, hc.Name()), nil + default: + return newHandleContext(loadedHandle), nil + } case HandleTypeHMACSession, HandleTypePolicySession: if loadedHandle != context.SavedHandle { return nil, &InvalidResponseError{CommandContextLoad, fmt.Errorf("handle %v returned from TPM is incorrect", loadedHandle)} } + return hc, nil default: panic("not reached") } - return hc, nil } // FlushContext executes the TPM2_FlushContext command on the handle referenced by flushContext, @@ -190,8 +206,8 @@ func (t *TPMContext) FlushContext(flushContext HandleContext) error { // handle, a *[TPMError] error with an error code of [ErrorNVDefined] will be returned. // // On successful completion of persisting a transient object, it returns a ResourceContext that -// corresponds to the persistent object. If object was created with [NewLimitedResourceContext], -// then a similarly limited context will be returned for the new persistent object. On successful +// corresponds to the persistent object. If object can be type asserted to [ObjectContext], then +// the returned ResourceContext can also be type asserted to [ObjectContext]. On successful // completion of evicting a persistent object, it returns a nil ResourceContext, and object will be // invalidated. func (t *TPMContext) EvictControl(auth, object ResourceContext, persistentHandle Handle, authAuthSession SessionContext, sessions ...SessionContext) (ResourceContext, error) { @@ -218,13 +234,13 @@ func (t *TPMContext) EvictControl(auth, object ResourceContext, persistentHandle name := make(Name, len(object.Name())) copy(name, object.Name()) - switch { - case object.Handle() == persistentHandle: + if object.Handle() == persistentHandle { + // we evicted an object object.Dispose() return nil, nil - case public != nil: - return newObjectContext(persistentHandle, name, public), nil - default: - return newLimitedResourceContext(persistentHandle, name), nil } + if public == nil { + return newResourceContext(persistentHandle, name), nil + } + return newObjectContext(persistentHandle, name, public), nil } diff --git a/cmds_context_test.go b/cmds_context_test.go index b48e1f8..6bbcd9f 100644 --- a/cmds_context_test.go +++ b/cmds_context_test.go @@ -52,7 +52,7 @@ func (s *contextSuiteBase) testEvictControl(c *C, data *testEvictControlData) { c.Check(persist.Handle(), Equals, HandleUnassigned) - _, _, _, err = s.TPM.ReadPublic(NewLimitedHandleContext(data.handle)) + _, _, _, err = s.TPM.ReadPublic(NewHandleContext(data.handle)) c.Assert(err, internal_testutil.ConvertibleTo, &TPMHandleError{}) c.Check(err.(*TPMHandleError), DeepEquals, &TPMHandleError{TPMError: &TPMError{Command: CommandReadPublic, Code: ErrorHandle}, Index: 1}) } @@ -126,7 +126,7 @@ func (s *contextSuite) TestContextSaveSession(c *C) { func (s *contextSuite) TestContextSaveLimitedResourceContext(c *C) { object := s.CreateStoragePrimaryKeyRSA(c) - lr := NewLimitedResourceContext(object.Handle(), object.Name()) + lr := NewResourceContext(object.Handle(), object.Name()) context, err := s.TPM.ContextSave(lr) c.Assert(err, IsNil) @@ -138,7 +138,7 @@ func (s *contextSuite) TestContextSaveLimitedResourceContext(c *C) { func (s *contextSuite) TestContextSaveLimitedHandleContext(c *C) { session := s.StartAuthSession(c, nil, nil, SessionTypeHMAC, nil, HashAlgorithmSHA256) - lh := NewLimitedHandleContext(session.Handle()) + lh := NewHandleContext(session.Handle()) context, err := s.TPM.ContextSave(lh) c.Assert(err, IsNil) @@ -210,7 +210,7 @@ func (s *contextSuite) TestContextSaveAndLoadSession(c *C) { func (s *contextSuite) TestContextSaveAndLoadSessionLimitedHandle(c *C) { session := s.StartAuthSession(c, nil, nil, SessionTypePolicy, nil, HashAlgorithmSHA256) - lh := NewLimitedHandleContext(session.Handle()) + lh := NewHandleContext(session.Handle()) context, err := s.TPM.ContextSave(lh) c.Assert(err, IsNil) @@ -219,12 +219,10 @@ func (s *contextSuite) TestContextSaveAndLoadSessionLimitedHandle(c *C) { c.Assert(err, IsNil) var sample SessionContext - c.Assert(restored, Implements, &sample) + c.Assert(restored, Not(Implements), &sample) c.Check(restored.Handle(), Equals, lh.Handle()) c.Check(restored.Name(), DeepEquals, lh.Name()) - c.Assert(restored, internal_testutil.ConvertibleTo, &SessionContextImpl{}) - c.Check(restored.(*SessionContextImpl).Data(), IsNil) c.Check(s.TPM.DoesHandleExist(restored.Handle()), internal_testutil.IsTrue) } @@ -232,7 +230,7 @@ func (s *contextSuite) TestContextSaveAndLoadSessionLimitedHandle(c *C) { func (s *contextSuite) TestContextSaveAndLoadTransientLimitedResource(c *C) { object := s.CreateStoragePrimaryKeyRSA(c) - lr := NewLimitedResourceContext(object.Handle(), object.Name()) + lr := NewResourceContext(object.Handle(), object.Name()) context, err := s.TPM.ContextSave(lr) c.Assert(err, IsNil) @@ -243,6 +241,9 @@ func (s *contextSuite) TestContextSaveAndLoadTransientLimitedResource(c *C) { var sample ResourceContext c.Check(restored, Implements, &sample) + var sample2 ObjectContext + c.Check(restored, Not(Implements), &sample2) + c.Check(restored.Handle().Type(), Equals, HandleTypeTransient) c.Check(restored.Handle(), Not(Equals), lr.Handle()) c.Check(restored.Name(), DeepEquals, lr.Name()) @@ -255,7 +256,7 @@ func (s *contextSuite) TestContextSaveAndLoadTransientLimitedResource(c *C) { func (s *contextSuite) TestContextSaveAndLoadTransientLimitedHandle(c *C) { object := s.CreateStoragePrimaryKeyRSA(c) - lh := NewLimitedHandleContext(object.Handle()) + lh := NewHandleContext(object.Handle()) context, err := s.TPM.ContextSave(lh) c.Assert(err, IsNil) @@ -264,11 +265,11 @@ func (s *contextSuite) TestContextSaveAndLoadTransientLimitedHandle(c *C) { c.Assert(err, IsNil) var sample ResourceContext - c.Check(restored, Implements, &sample) + c.Check(restored, Not(Implements), &sample) c.Check(restored.Handle().Type(), Equals, HandleTypeTransient) c.Check(restored.Handle(), Not(Equals), lh.Handle()) - c.Check(restored.Name(), DeepEquals, lh.Name()) + c.Check(restored.Name(), DeepEquals, Name(mu.MustMarshalToBytes(restored.Handle()))) c.Check(s.TPM.DoesHandleExist(restored.Handle()), internal_testutil.IsTrue) } @@ -300,7 +301,7 @@ func (s *contextSuite) TestFlushContextTransient(c *C) { c.Check(object.Handle(), Equals, HandleUnassigned) - _, _, _, err := s.TPM.ReadPublic(NewLimitedHandleContext(handle)) + _, _, _, err := s.TPM.ReadPublic(NewHandleContext(handle)) c.Assert(err, internal_testutil.ConvertibleTo, &TPMWarning{}) c.Check(err.(*TPMWarning), DeepEquals, &TPMWarning{Command: CommandReadPublic, Code: WarningReferenceH0}) } @@ -317,3 +318,32 @@ func (s *contextSuite) TestFlushContextSession(c *C) { c.Assert(err, IsNil) c.Check(handle, Not(internal_testutil.IsOneOf(Equals)), handles) } + +func (s *contextSuite) TestEvictControlLimitedResource(c *C) { + object := s.CreatePrimary(c, HandleOwner, testutil.NewRSAStorageKeyTemplate()) + + lr := NewResourceContext(object.Handle(), object.Name()) + handle := s.NextAvailableHandle(c, 0x81000000) + + persist, err := s.TPM.EvictControl(s.TPM.OwnerHandleContext(), lr, handle, nil) + c.Assert(err, IsNil) + c.Check(persist.Handle(), Equals, handle) + c.Check(persist.Name(), DeepEquals, lr.Name()) + + var sample ObjectContext + c.Check(persist, Not(Implements), &sample) + + _, name, _, err := s.TPM.ReadPublic(persist) + c.Assert(err, IsNil) + c.Check(name, DeepEquals, lr.Name()) + + persist2, err := s.TPM.EvictControl(s.TPM.OwnerHandleContext(), persist, handle, nil) + c.Check(err, IsNil) + c.Check(persist2, IsNil) + + c.Check(persist.Handle(), Equals, HandleUnassigned) + + _, _, _, err = s.TPM.ReadPublic(NewHandleContext(handle)) + c.Assert(err, internal_testutil.ConvertibleTo, &TPMHandleError{}) + c.Check(err.(*TPMHandleError), DeepEquals, &TPMHandleError{TPMError: &TPMError{Command: CommandReadPublic, Code: ErrorHandle}, Index: 1}) +} diff --git a/cmds_hashhmac.go b/cmds_hashhmac.go index 7a7f921..da497e5 100644 --- a/cmds_hashhmac.go +++ b/cmds_hashhmac.go @@ -43,7 +43,7 @@ func (t *TPMContext) HMACStart(context ResourceContext, auth Auth, hashAlg HashA return nil, err } - rc := newLimitedResourceContext(sequenceHandle, nil) + rc := newResourceContext(sequenceHandle, nil) authValue := make([]byte, len(auth)) copy(authValue, auth) rc.SetAuthValue(authValue) @@ -71,7 +71,7 @@ func (t *TPMContext) HashSequenceStart(auth Auth, hashAlg HashAlgorithmId, sessi return nil, err } - rc := newLimitedResourceContext(sequenceHandle, nil) + rc := newResourceContext(sequenceHandle, nil) authValue := make([]byte, len(auth)) copy(authValue, auth) rc.SetAuthValue(authValue) diff --git a/cmds_hierarchy.go b/cmds_hierarchy.go index a76f459..424bfd1 100644 --- a/cmds_hierarchy.go +++ b/cmds_hierarchy.go @@ -114,12 +114,13 @@ import ( // On success, a ResourceContext instance will be returned that corresponds to the newly created // object on the TPM. It will not be necessary to call [ResourceContext].SetAuthValue on it - this // function sets the correct authorization value so that it can be used in subsequent commands that -// require knowledge of the authorization value. If the Type field of inPublic is -// [ObjectTypeKeyedHash] or [ObjectTypeSymCipher], then the returned *Public object will have a -// Unique field that is the digest of the sensitive data and the value of the object's seed in the -// sensitive area, computed using the object's name algorithm. If the Type field of inPublic is -// [ObjectTypeECC] or [ObjectTypeRSA], then the returned *Public object will have a Unique field -// containing details about the public part of the key, computed from the private part of the key. +// require knowledge of the authorization value. The returned ResourceContext can be type asserted +// to [ObjectContext]. If the Type field of inPublic is [ObjectTypeKeyedHash] or +// [ObjectTypeSymCipher], then the returned *Public object will have a Unique field that is the digest +// of the sensitive data and the value of the object's seed in the sensitive area, computed using the +// object's name algorithm. If the Type field of inPublic is [ObjectTypeECC] or [ObjectTypeRSA], then +// the returned *Public object will have a Unique field containing details about the public part of the +// key, computed from the private part of the key. // // The returned *CreationData will contain a digest computed from the values of PCRs selected by // the creationPCR parameter at creation time in the PCRDigest field. It will also contain the diff --git a/cmds_nv.go b/cmds_nv.go index 4d9e179..cb1ed40 100644 --- a/cmds_nv.go +++ b/cmds_nv.go @@ -189,7 +189,8 @@ func (t *TPMContext) NVDefineSpaceRaw(authContext ResourceContext, auth Auth, pu // On successful completion, the NV index will be defined and a ResourceContext corresponding to // the new index will be returned. It will not be necessary to call [ResourceContext].SetAuthValue // on the returned ResourceContext - this function sets the correct authorization value so that it -// can be used in subsequent commands that require knowledge of it. +// can be used in subsequent commands that require knowledge of it. The returned ResourceContext +// can be type asserted to [NVIndexContext]. func (t *TPMContext) NVDefineSpace(authContext ResourceContext, auth Auth, publicInfo *NVPublic, authContextAuthSession SessionContext, sessions ...SessionContext) (ResourceContext, error) { if publicInfo == nil { return nil, makeInvalidArgError("publicInfo", "nil value") @@ -317,8 +318,8 @@ func (t *TPMContext) NVReadPublic(nvIndex HandleContext, sessions ...SessionCont // will be returned. // // On successful completion, the [AttrNVWritten] flag will be set if this is the first time that -// the index has been written to. The name of nvIndex will be updated accordingly as long as it -// wasn't created with [NewLimitedResourceContext]. +// the index has been written to. If nvIndex can be type asserted to [NVIndexContext], the name of +// nvIndex will be updated accordingly. func (t *TPMContext) NVWriteRaw(authContext, nvIndex ResourceContext, data MaxNVBuffer, offset uint16, authContextAuthSession SessionContext, sessions ...SessionContext) error { if err := t.StartCommand(CommandNVWrite). AddHandles(UseResourceContextWithAuth(authContext, authContextAuthSession), UseHandleContext(nvIndex)). @@ -401,7 +402,8 @@ func (c *nvWriteHelperContext) run(sessions ...SessionContext) error { // will be returned. // // On successful completion, the [AttrNVWritten] flag will be set if this is the first time that -// the index has been written to. +// the index has been written to. If nvIndex can be type asserted to [NVIndexContext], the name of +// nvIndex will be updated accordingly. func (t *TPMContext) NVWrite(authContext, nvIndex ResourceContext, data []byte, offset uint16, authContextAuthSession SessionContext, sessions ...SessionContext) error { if err := t.initPropertiesIfNeeded(); err != nil { return err @@ -423,7 +425,7 @@ func (t *TPMContext) NVWrite(authContext, nvIndex ResourceContext, data []byte, // NVSetPinCounterParams is a convenience function for [TPMContext.NVWrite] for updating the // contents of the NV pin pass or NV pin fail index associated with nvIndex. If the type of nvIndex // is not NVTypePinPass of NVTypePinFail, an error will be returned. This will return an error if -// nvIndex was created with [NewLimitedResourceContext]. +// nvIndex cannot be type asserted to [NVIndexContext]. // // The command requires authorization, defined by the state of the [AttrNVPPWrite], // [AttrNVOwnerWrite], [AttrNVAuthWrite] and [AttrNVPolicyWrite] attributes. The handle used for @@ -446,7 +448,8 @@ func (t *TPMContext) NVWrite(authContext, nvIndex ResourceContext, data []byte, // of [ErrorNVLocked] will be returned. // // On successful completion, the [AttrNVWritten] flag will be set if this is the first time that -// the index has been written to. +// the index has been written to. If nvIndex can be type asserted to [NVIndexContext], the name of +// nvIndex will be updated accordingly. func (t *TPMContext) NVSetPinCounterParams(authContext, nvIndex ResourceContext, params *NVPinCounterParams, authContextAuthSession SessionContext, sessions ...SessionContext) error { context, isNv := nvIndex.(NVIndexContext) if !isNv { @@ -486,8 +489,8 @@ func (t *TPMContext) NVSetPinCounterParams(authContext, nvIndex ResourceContext, // [ErrorAttributes] will be returned for handle index 2. // // On successful completion, the [AttrNVWritten] flag will be set if this is the first time that -// the index has been written to. The name of nvIndex will be updated accordingly as long as it -// wasn't created with [NewLimitedResourceContext]. +// the index has been written to. If nvIndex can be type asserted to [NVIndexContext], the name of +// nvIndex will be updated accordingly. func (t *TPMContext) NVIncrement(authContext, nvIndex ResourceContext, authContextAuthSession SessionContext, sessions ...SessionContext) error { if err := t.StartCommand(CommandNVIncrement). AddHandles(UseResourceContextWithAuth(authContext, authContextAuthSession), UseHandleContext(nvIndex)). @@ -529,8 +532,8 @@ func (t *TPMContext) NVIncrement(authContext, nvIndex ResourceContext, authConte // [ErrorAttributes] will be returned for handle index 2. // // On successful completion, the [AttrNVWritten] flag will be set if this is the first time that -// the index has been written to. The name of nvIndex will be updated accordingly as long as it -// wasn't created with [NewLimitedResourceContext]. +// the index has been written to. If nvIndex can be type asserted to [NVIndexContext], the name of +// nvIndex will be updated accordingly. func (t *TPMContext) NVExtend(authContext, nvIndex ResourceContext, data MaxNVBuffer, authContextAuthSession SessionContext, sessions ...SessionContext) error { if err := t.StartCommand(CommandNVExtend). AddHandles(UseResourceContextWithAuth(authContext, authContextAuthSession), UseHandleContext(nvIndex)). @@ -573,8 +576,8 @@ func (t *TPMContext) NVExtend(authContext, nvIndex ResourceContext, data MaxNVBu // [ErrorAttributes] will be returned for handle index 2. // // On successful completion, the [AttrNVWritten] flag will be set if this is the first time that -// the index has been written to. The name of nvIndex will be updated accordingly as long as it -// wasn't created with [NewLimitedResourceContext]. +// the index has been written to. If nvIndex can be type asserted to [NVIndexContext], the name of +// nvIndex will be updated accordingly. func (t *TPMContext) NVSetBits(authContext, nvIndex ResourceContext, bits uint64, authContextAuthSession SessionContext, sessions ...SessionContext) error { if err := t.StartCommand(CommandNVSetBits). AddHandles(UseResourceContextWithAuth(authContext, authContextAuthSession), UseHandleContext(nvIndex)). @@ -614,11 +617,10 @@ func (t *TPMContext) NVSetBits(authContext, nvIndex ResourceContext, bits uint64 // *[TPMHandleError] error with an error code of [ErrorAttributes] will be returned for handle // index 2. // -// On successful completion, the [AttrNVWriteLocked] attribute will be set. The name of nvIndex -// will be updated accordingly as long as it wasn't created with [NewLimitedResourceContext]. -// The attribute will be cleared again (and writes will be reenabled) on the next TPM reset or TPM -// restart unless the index has the [AttrNVWriteDefine] attribute set and [AttrNVWritten] attribute -// is set. +// On successful completion, the [AttrNVWriteLocked] attribute will be set. If nvIndex can be type +// asserted to [NVIndexContext], the name of nvIndex will be updated accordingly. The attribute will +// be cleared again (and writes will be reenabled) on the next TPM reset or TPM restart unless the +// index has the [AttrNVWriteDefine] attribute set and [AttrNVWritten] attribute is set. func (t *TPMContext) NVWriteLock(authContext, nvIndex ResourceContext, authContextAuthSession SessionContext, sessions ...SessionContext) error { if err := t.StartCommand(CommandNVWriteLock). AddHandles(UseResourceContextWithAuth(authContext, authContextAuthSession), UseHandleContext(nvIndex)). @@ -808,8 +810,7 @@ func (t *TPMContext) nvReadUint64(authContext, nvIndex ResourceContext, authCont // NVReadBits is a convenience function for [TPMContext.NVRead] for reading the contents of the NV // bit field index associated with nvIndex. If the type of nvIndex is not [NVTypeBits], an error -// will be returned. This will return an error if nvIndex was created with -// [NewLimitedResourceContext]. +// will be returned. This will return an error if nvIndex cannot be type asserted to [NVIndexContext]. // // The command requires authorization, defined by the state of the [AttrNVPPRead], // [AttrNVOwnerRead], [AttrNVAuthRead] and [AttrNVPolicyRead] attributes. The handle used for @@ -848,8 +849,8 @@ func (t *TPMContext) NVReadBits(authContext, nvIndex ResourceContext, authContex // NVReadCounter is a convenience function for [TPMContext.NVRead] for reading the contents of the // NV counter index associated with nvIndex. If the type of nvIndex is not [NVTypeCounter], an -// error will be returned. This will return an error if nvIndex was created with -// [NewLimitedResourceContext]. +// error will be returned. This will return an error if nvIndex cannot be type asserted to +// [NVIndexContext]. // // The command requires authorization, defined by the state of the [AttrNVPPRead], // [AttrNVOwnerRead], [AttrNVAuthRead] and [AttrNVPolicyRead] attributes. The handle used for @@ -889,7 +890,7 @@ func (t *TPMContext) NVReadCounter(authContext, nvIndex ResourceContext, authCon // NVReadPinCounterParams is a convenience function for [TPMContext.NVRead] for reading the // contents of the NV pin pass or NV pin fail index associated with nvIndex. If the type of nvIndex // is not [NVTypePinPass] or [NVTypePinFail], an error will be returned. This will return an error -// if nvIndex was created with [NewLimitedResourceContext]. +// if nvIndex cannot be type asserted to [NVIndexContext]. // // The command requires authorization, defined by the state of the [AttrNVPPRead], // [AttrNVOwnerRead], [AttrNVAuthRead] and [AttrNVPolicyRead] attributes. The handle used for @@ -957,10 +958,9 @@ func (t *TPMContext) NVReadPinCounterParams(authContext, nvIndex ResourceContext // If the index doesn't have the [AttrNVReadStClear] attribute set, then a *[TPMHandleError] error // with an error code of [ErrorAttributes] will be returned for handle index 2. // -// On successful completion, the [AttrNVReadLocked] attribute will be set. The name of nvIndex will -// be updated accordingly as long as it wasn't created with [NewLimitedResourceContext]. The -// attribute will be cleared again (and reads will be reenabled) on the next TPM reset or TPM -// restart. +// On successful completion, the [AttrNVReadLocked] attribute will be set. If nvIndex can be type +// asserted to [NVIndexContext], the name of nvIndex will be updated accordingly. The attribute +// will be cleared again (and reads will be reenabled) on the next TPM reset or TPM restart. func (t *TPMContext) NVReadLock(authContext, nvIndex ResourceContext, authContextAuthSession SessionContext, sessions ...SessionContext) error { if err := t.StartCommand(CommandNVReadLock). AddHandles(UseResourceContextWithAuth(authContext, authContextAuthSession), UseHandleContext(nvIndex)). diff --git a/cmds_nv_test.go b/cmds_nv_test.go index ad03f6d..ee566ff 100644 --- a/cmds_nv_test.go +++ b/cmds_nv_test.go @@ -108,7 +108,7 @@ func (s *nvSuiteBase) testDefineAndUndefineSpace(c *C, data *testNVDefineAndUnde c.Assert(authArea, internal_testutil.LenEquals, 1) c.Check(authArea[0].SessionHandle, Equals, sessionHandle) - _, _, err = s.TPM.NVReadPublic(NewLimitedHandleContext(data.publicInfo.Index)) + _, _, err = s.TPM.NVReadPublic(NewHandleContext(data.publicInfo.Index)) c.Assert(err, internal_testutil.ConvertibleTo, &TPMHandleError{}) c.Check(err.(*TPMHandleError), DeepEquals, &TPMHandleError{TPMError: &TPMError{Command: CommandNVReadPublic, Code: ErrorHandle}, Index: 1}) } @@ -213,7 +213,7 @@ func (s *nvSuitePlatform) testUndefineSpaceSpecial(c *C, data *testNVUndefineSpa c.Check(authArea[0].SessionHandle, Equals, sessionHandles[0]) c.Check(authArea[1].SessionHandle, Equals, sessionHandles[1]) - _, _, err := s.TPM.NVReadPublic(NewLimitedHandleContext(pub.Index)) + _, _, err := s.TPM.NVReadPublic(NewHandleContext(pub.Index)) c.Assert(err, internal_testutil.ConvertibleTo, &TPMHandleError{}) c.Check(err.(*TPMHandleError), DeepEquals, &TPMHandleError{TPMError: &TPMError{Command: CommandNVReadPublic, Code: ErrorHandle}, Index: 1}) diff --git a/cmds_object.go b/cmds_object.go index 485b19e..8ccd198 100644 --- a/cmds_object.go +++ b/cmds_object.go @@ -235,7 +235,7 @@ func (t *TPMContext) Create(parentContext ResourceContext, inSensitive *Sensitiv // On success, a ResourceContext corresponding to the newly loaded transient object will be // returned. If subsequent use of the returned ResourceContext requires knowledge of the // authorization value of the corresponding TPM resource, this should be provided by calling -// [ResourceContext].SetAuthValue. +// [ResourceContext].SetAuthValue. The return ResourceContext can be type asserted to [ObjectContext]. func (t *TPMContext) Load(parentContext ResourceContext, inPrivate Private, inPublic *Public, parentContextAuthSession SessionContext, sessions ...SessionContext) (objectContext ResourceContext, err error) { var objectHandle Handle var name Name @@ -341,6 +341,7 @@ func (t *TPMContext) Load(parentContext ResourceContext, inPrivate Private, inPu // returned. If inPrivate has been provided, it will not be necessary to call // [ResourceContext].SetAuthValue on it - this function sets the correct authorization value so // that it can be used in subsequent commands that require knowledge of the authorization value. +// The return ResourceContext can be type asserted to [ObjectContext]. func (t *TPMContext) LoadExternal(inPrivate *Sensitive, inPublic *Public, hierarchy Handle, sessions ...SessionContext) (objectContext ResourceContext, err error) { var objectHandle Handle var name Name @@ -667,12 +668,13 @@ func (t *TPMContext) ObjectChangeAuth(objectContext, parentContext ResourceConte // object on the TPM, along with the private and public parts. It will not be necessary to call // [ResourceContext].SetAuthValue on the returned ResourceContext - this function sets the correct // authorization value so that it can be used in subsequent commands that require knowledge of the -// authorization value. If the Type field of the template is [ObjectTypeKeyedHash] or -// [ObjectTypeSymCipher], then the returned *Public object will have a Unique field that is the -// digest of the sensitive data and the value of the object's seed in the sensitive area, computed -// using the object's name algorithm. If the Type field of the template is [ObjectTypeECC] or -// [ObjectTypeRSA], then the returned *Public object will have a Unique field containing details -// about the public part of the key, computed from the private part of the key. +// authorization value. The returned ResourceContext can be type asserted to [ObjectContext]. If +// the Type field of the template is [ObjectTypeKeyedHash] or [ObjectTypeSymCipher], then the +// returned *Public object will have a Unique field that is the digest of the sensitive data and +// the value of the object's seed in the sensitive area, computed using the object's name algorithm. +// If the Type field of the template is [ObjectTypeECC] or [ObjectTypeRSA], then the returned *Public +// object will have a Unique field containing details about the public part of the key, computed from +// the private part of the key. func (t *TPMContext) CreateLoaded(parentContext ResourceContext, inSensitive *SensitiveCreate, inPublic PublicTemplate, parentContextAuthSession SessionContext, sessions ...SessionContext) (objectContext ResourceContext, outPrivate Private, outPublic *Public, err error) { if inSensitive == nil { inSensitive = &SensitiveCreate{} diff --git a/cmds_session.go b/cmds_session.go index 0bca614..19bcc11 100644 --- a/cmds_session.go +++ b/cmds_session.go @@ -25,16 +25,17 @@ import ( // parameter encryption where used. The size of the digest algorithm is used to determine the nonce // size used for the session. // -// If tpmKey is provided then a salted session is created. The key must correspond to an asymmetric +// If tpmKey is provided then a salted session is created. In this case, it must be possible to +// type assert the provided key to [ObjectContext]. The key must correspond to an asymmetric // decrypt key in the TPM - it must have a type of [ObjectTypeRSA] or [ObjectTypeECC] and it must // have the [AttrDecrypt] attribute set. In this case, a random salt value will be established // which will contribute to the session key derivation. If tpmKey has the type of [ObjectTypeRSA], // the random salt will be created on the host and RSA-OAEP encrypted with the public part of -// tpmKey before being sent to the TPM. If tpmKey has the type of [ObjectTypeECC], ECDH is used to -// derive a random salt, using tpmKey and an ephemeral host key. If tpmKey is provided but does not -// correspond to an asymmetric key, a *[TPMHandleError] error with an error code of [ErrorKey] will -// be returned for handle index 1. If tpmKey is provided but corresponds to an object with only its -// public part loaded, a *[TPMHandleError] error with an error code of [ErrorHandle] will be +// tpmKey before being sent to the TPM. If tpmKey has the type of [ObjectTypeECC], a random salt +// is established using ECDH key exchange and an ephemeral host key. If tpmKey is provided but does +// not correspond to an asymmetric key, a *[TPMHandleError] error with an error code of [ErrorKey] +// will be returned for handle index 1. If tpmKey is provided but corresponds to an object with only +// its public part loaded, a *[TPMHandleError] error with an error code of [ErrorHandle] will be // returned for handle index 1. If tpmKey is provided but does not correspond to a decrypt key, a // *[TPMHandleError] error with an error code of [ErrorAttributes] will be returned for handle // index 1. diff --git a/export_test.go b/export_test.go index 64341e7..e364249 100644 --- a/export_test.go +++ b/export_test.go @@ -32,7 +32,7 @@ func (c *CommandContext) Cmd() *CmdContext { } func (c *NvIndexContextImpl) Public() *NVPublic { - return c.Data.NV.Data + return c.Data.NV } func (c *ResponseContext) Dispatcher() commandDispatcher { diff --git a/policyutil/builder.go b/policyutil/builder.go index cad6e10..92047bb 100644 --- a/policyutil/builder.go +++ b/policyutil/builder.go @@ -38,7 +38,7 @@ func (r *policyBuilderBranchRunner) authResourceName() tpm2.Name { func (*policyBuilderBranchRunner) loadExternal(public *tpm2.Public) (ResourceContext, error) { // the handle is not relevant here - resource := tpm2.NewLimitedResourceContext(0x80000000, public.Name()) + resource := tpm2.NewResourceContext(0x80000000, public.Name()) return newResourceContext(resource, nil), nil } diff --git a/policyutil/path_resolver.go b/policyutil/path_resolver.go index a5ae054..185f69b 100644 --- a/policyutil/path_resolver.go +++ b/policyutil/path_resolver.go @@ -163,7 +163,7 @@ func (s *policyPathWildcardResolver) filterUsageIncompatibleBranches() error { delete(s.detailsMap, p) continue } - pub, err := s.tpm.NVReadPublic(tpm2.NewLimitedHandleContext(authHandle.Handle())) + pub, err := s.tpm.NVReadPublic(tpm2.NewHandleContext(authHandle.Handle())) if err != nil { return fmt.Errorf("cannot obtain NV index public area: %w", err) } @@ -415,7 +415,7 @@ func (s *policyPathWildcardResolver) filterNVIncompatibleBranches() error { info, exists := nvInfo[nv.Index] if !exists { // Read the index info from the TPM - pub, err := s.tpm.NVReadPublic(tpm2.NewLimitedHandleContext(nv.Index)) + pub, err := s.tpm.NVReadPublic(tpm2.NewHandleContext(nv.Index)) if tpm2.IsTPMHandleError(err, tpm2.ErrorHandle, tpm2.AnyCommandCode, tpm2.AnyHandleIndex) { // if no NV index exists, then this branch won't work. nvResult[key] = nvAssertionStatusIncompatible @@ -470,7 +470,7 @@ func (s *policyPathWildcardResolver) filterNVIncompatibleBranches() error { } defer session.Flush() - rc := tpm2.NewLimitedResourceContext(nv.Index, nv.Name) + rc := tpm2.NewResourceContext(nv.Index, nv.Name) params := &PolicyExecuteParams{ Usage: NewPolicySessionUsage(tpm2.CommandNVRead, []NamedHandle{rc, rc}, uint16(len(nv.OperandB)), nv.Offset).WithoutAuthValue(), } diff --git a/policyutil/policy.go b/policyutil/policy.go index ee3c6ae..d389a8c 100644 --- a/policyutil/policy.go +++ b/policyutil/policy.go @@ -1757,7 +1757,7 @@ func (r *policyComputeRunner) authResourceName() tpm2.Name { func (r *policyComputeRunner) loadExternal(public *tpm2.Public) (ResourceContext, error) { // the handle is not relevant here - resource := tpm2.NewLimitedResourceContext(0x80000000, public.Name()) + resource := tpm2.NewResourceContext(0x80000000, public.Name()) return newResourceContext(resource, nil), nil } @@ -1970,7 +1970,7 @@ func (r *policyValidateRunner) authResourceName() tpm2.Name { func (r *policyValidateRunner) loadExternal(public *tpm2.Public) (ResourceContext, error) { // the handle is not relevant here - resource := tpm2.NewLimitedResourceContext(0x80000000, public.Name()) + resource := tpm2.NewResourceContext(0x80000000, public.Name()) return newResourceContext(resource, nil), nil } @@ -2370,7 +2370,7 @@ func (r *policyStringifierRunner) authResourceName() tpm2.Name { func (r *policyStringifierRunner) loadExternal(public *tpm2.Public) (ResourceContext, error) { // the handle is not relevant here - resource := tpm2.NewLimitedResourceContext(0x80000000, public.Name()) + resource := tpm2.NewResourceContext(0x80000000, public.Name()) return newResourceContext(resource, nil), nil } diff --git a/policyutil/policy_test.go b/policyutil/policy_test.go index 6ce6ddd..39579d5 100644 --- a/policyutil/policy_test.go +++ b/policyutil/policy_test.go @@ -2522,7 +2522,7 @@ func (s *policySuite) TestPolicyBranchAutoSelectNoUsage(c *C) { func (s *policySuite) TestPolicyBranchAutoSelectWithUsage1(c *C) { s.testPolicyBranches(c, &testExecutePolicyBranchesData{ - usage: NewPolicySessionUsage(tpm2.CommandNVChangeAuth, []NamedHandle{tpm2.NewLimitedResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...))}, tpm2.Auth("foo")), + usage: NewPolicySessionUsage(tpm2.CommandNVChangeAuth, []NamedHandle{tpm2.NewResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...))}, tpm2.Auth("foo")), expectedCommands: tpm2.CommandCodeList{ tpm2.CommandPolicyNvWritten, tpm2.CommandPolicyAuthValue, @@ -2535,7 +2535,7 @@ func (s *policySuite) TestPolicyBranchAutoSelectWithUsage1(c *C) { func (s *policySuite) TestPolicyBranchAutoSelectWithUsage2(c *C) { s.testPolicyBranches(c, &testExecutePolicyBranchesData{ - usage: NewPolicySessionUsage(tpm2.CommandNVChangeAuth, []NamedHandle{tpm2.NewLimitedResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...))}, tpm2.Auth("foo")).WithoutAuthValue(), + usage: NewPolicySessionUsage(tpm2.CommandNVChangeAuth, []NamedHandle{tpm2.NewResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...))}, tpm2.Auth("foo")).WithoutAuthValue(), expectedCommands: tpm2.CommandCodeList{ tpm2.CommandPolicyNvWritten, tpm2.CommandContextSave, @@ -2555,7 +2555,7 @@ func (s *policySuite) TestPolicyBranchAutoSelectWithUsage2(c *C) { func (s *policySuite) TestPolicyBranchAutoSelectWithUsageAndIgnore(c *C) { s.testPolicyBranches(c, &testExecutePolicyBranchesData{ - usage: NewPolicySessionUsage(tpm2.CommandNVChangeAuth, []NamedHandle{tpm2.NewLimitedResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...))}, tpm2.Auth("foo")).WithoutAuthValue(), + usage: NewPolicySessionUsage(tpm2.CommandNVChangeAuth, []NamedHandle{tpm2.NewResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...))}, tpm2.Auth("foo")).WithoutAuthValue(), ignoreAuthorizations: []PolicyAuthorizationID{ {AuthName: tpm2.MakeHandleName(tpm2.HandleOwner), PolicyRef: []byte("foo")}, }, @@ -2799,7 +2799,7 @@ func (s *policySuite) TestPolicyBranchesMultipleNodesAutoSelectOneNoUsage(c *C) func (s *policySuite) TestPolicyBranchesMultipleNodesAutoSelectWithUsage1(c *C) { s.testPolicyBranchesMultipleNodes(c, &testExecutePolicyBranchesMultipleNodesData{ - usage: NewPolicySessionUsage(tpm2.CommandNVChangeAuth, []NamedHandle{tpm2.NewLimitedResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...))}, tpm2.Auth("foo")), + usage: NewPolicySessionUsage(tpm2.CommandNVChangeAuth, []NamedHandle{tpm2.NewResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...))}, tpm2.Auth("foo")), expectedCommands: tpm2.CommandCodeList{ tpm2.CommandPolicyNvWritten, tpm2.CommandPolicyAuthValue, @@ -2814,7 +2814,7 @@ func (s *policySuite) TestPolicyBranchesMultipleNodesAutoSelectWithUsage1(c *C) func (s *policySuite) TestPolicyBranchesMultipleNodesAutoSelectWithUsage2(c *C) { s.testPolicyBranchesMultipleNodes(c, &testExecutePolicyBranchesMultipleNodesData{ - usage: NewPolicySessionUsage(tpm2.CommandNVWriteLock, []NamedHandle{tpm2.NewLimitedResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...)), tpm2.NewLimitedResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...))}), + usage: NewPolicySessionUsage(tpm2.CommandNVWriteLock, []NamedHandle{tpm2.NewResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...)), tpm2.NewResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...))}), expectedCommands: tpm2.CommandCodeList{ tpm2.CommandPolicyNvWritten, tpm2.CommandPolicyAuthValue, @@ -2829,7 +2829,7 @@ func (s *policySuite) TestPolicyBranchesMultipleNodesAutoSelectWithUsage2(c *C) func (s *policySuite) TestPolicyBranchesMultipleNodesAutoSelectWithUsage3(c *C) { s.testPolicyBranchesMultipleNodes(c, &testExecutePolicyBranchesMultipleNodesData{ - usage: NewPolicySessionUsage(tpm2.CommandNVWriteLock, []NamedHandle{tpm2.NewLimitedResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...)), tpm2.NewLimitedResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...))}).WithoutAuthValue(), + usage: NewPolicySessionUsage(tpm2.CommandNVWriteLock, []NamedHandle{tpm2.NewResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...)), tpm2.NewResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...))}).WithoutAuthValue(), expectedCommands: tpm2.CommandCodeList{ tpm2.CommandPolicyNvWritten, tpm2.CommandContextSave, @@ -2852,7 +2852,7 @@ func (s *policySuite) TestPolicyBranchesMultipleNodesAutoSelectWithUsage3(c *C) func (s *policySuite) TestPolicyBranchesMultipleNodesAutoSelectOneWithUsage(c *C) { s.testPolicyBranchesMultipleNodes(c, &testExecutePolicyBranchesMultipleNodesData{ path: "branch2", - usage: NewPolicySessionUsage(tpm2.CommandNVWriteLock, []NamedHandle{tpm2.NewLimitedResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...)), tpm2.NewLimitedResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...))}), + usage: NewPolicySessionUsage(tpm2.CommandNVWriteLock, []NamedHandle{tpm2.NewResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...)), tpm2.NewResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...))}), expectedCommands: tpm2.CommandCodeList{ tpm2.CommandPolicyNvWritten, tpm2.CommandContextSave, @@ -2875,7 +2875,7 @@ func (s *policySuite) TestPolicyBranchesMultipleNodesAutoSelectOneWithUsage(c *C func (s *policySuite) TestPolicyBranchesMultipleNodesAutoSelectWildcard1(c *C) { s.testPolicyBranchesMultipleNodes(c, &testExecutePolicyBranchesMultipleNodesData{ path: "*/branch4", - usage: NewPolicySessionUsage(tpm2.CommandNVChangeAuth, []NamedHandle{tpm2.NewLimitedResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...))}, tpm2.Auth("foo")), + usage: NewPolicySessionUsage(tpm2.CommandNVChangeAuth, []NamedHandle{tpm2.NewResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...))}, tpm2.Auth("foo")), expectedCommands: tpm2.CommandCodeList{ tpm2.CommandPolicyNvWritten, tpm2.CommandPolicyAuthValue, @@ -2891,7 +2891,7 @@ func (s *policySuite) TestPolicyBranchesMultipleNodesAutoSelectWildcard1(c *C) { func (s *policySuite) TestPolicyBranchesMultipleNodesAutoSelectWildcard2(c *C) { s.testPolicyBranchesMultipleNodes(c, &testExecutePolicyBranchesMultipleNodesData{ path: "*/branch4", - usage: NewPolicySessionUsage(tpm2.CommandNVChangeAuth, []NamedHandle{tpm2.NewLimitedResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...))}, tpm2.Auth("foo")).WithoutAuthValue(), + usage: NewPolicySessionUsage(tpm2.CommandNVChangeAuth, []NamedHandle{tpm2.NewResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...))}, tpm2.Auth("foo")).WithoutAuthValue(), expectedCommands: tpm2.CommandCodeList{ tpm2.CommandPolicyNvWritten, tpm2.CommandContextSave, @@ -2914,7 +2914,7 @@ func (s *policySuite) TestPolicyBranchesMultipleNodesAutoSelectWildcard2(c *C) { func (s *policySuite) TestPolicyBranchesMultipleNodesAutoSelectWildcard3(c *C) { s.testPolicyBranchesMultipleNodes(c, &testExecutePolicyBranchesMultipleNodesData{ path: "**/branch4", - usage: NewPolicySessionUsage(tpm2.CommandNVChangeAuth, []NamedHandle{tpm2.NewLimitedResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...))}, tpm2.Auth("foo")), + usage: NewPolicySessionUsage(tpm2.CommandNVChangeAuth, []NamedHandle{tpm2.NewResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...))}, tpm2.Auth("foo")), expectedCommands: tpm2.CommandCodeList{ tpm2.CommandPolicyNvWritten, tpm2.CommandPolicyAuthValue, @@ -3139,7 +3139,7 @@ func (s *policySuite) TestPolicyBranchesEmbeddedNodesAutoSelectOneNoUsage(c *C) func (s *policySuite) TestPolicyBranchesEmbeddedNodesAutoSelectOneWithUsage(c *C) { s.testPolicyBranchesEmbeddedNodes(c, &testExecutePolicyBranchesEmbeddedNodesData{ path: "branch4", - usage: NewPolicySessionUsage(tpm2.CommandNVWriteLock, []NamedHandle{tpm2.NewLimitedResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...)), tpm2.NewLimitedResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...))}), + usage: NewPolicySessionUsage(tpm2.CommandNVWriteLock, []NamedHandle{tpm2.NewResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...)), tpm2.NewResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...))}), expectedCommands: tpm2.CommandCodeList{ tpm2.CommandPolicyNvWritten, tpm2.CommandContextSave, @@ -3161,7 +3161,7 @@ func (s *policySuite) TestPolicyBranchesEmbeddedNodesAutoSelectOneWithUsage(c *C func (s *policySuite) TestPolicyBranchesEmbeddedNodesAutoSelectWithUsage1(c *C) { s.testPolicyBranchesEmbeddedNodes(c, &testExecutePolicyBranchesEmbeddedNodesData{ - usage: NewPolicySessionUsage(tpm2.CommandNVChangeAuth, []NamedHandle{tpm2.NewLimitedResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...))}, tpm2.Auth("foo")), + usage: NewPolicySessionUsage(tpm2.CommandNVChangeAuth, []NamedHandle{tpm2.NewResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...))}, tpm2.Auth("foo")), expectedCommands: tpm2.CommandCodeList{ tpm2.CommandPolicyNvWritten, tpm2.CommandPolicyAuthValue, @@ -3176,7 +3176,7 @@ func (s *policySuite) TestPolicyBranchesEmbeddedNodesAutoSelectWithUsage1(c *C) func (s *policySuite) TestPolicyBranchesEmbeddedNodesAutoSelectWithUsage2(c *C) { s.testPolicyBranchesEmbeddedNodes(c, &testExecutePolicyBranchesEmbeddedNodesData{ - usage: NewPolicySessionUsage(tpm2.CommandNVWriteLock, []NamedHandle{tpm2.NewLimitedResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...)), tpm2.NewLimitedResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...))}), + usage: NewPolicySessionUsage(tpm2.CommandNVWriteLock, []NamedHandle{tpm2.NewResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...)), tpm2.NewResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...))}), expectedCommands: tpm2.CommandCodeList{ tpm2.CommandPolicyNvWritten, tpm2.CommandPolicyAuthValue, @@ -3191,7 +3191,7 @@ func (s *policySuite) TestPolicyBranchesEmbeddedNodesAutoSelectWithUsage2(c *C) func (s *policySuite) TestPolicyBranchesEmbeddedNodesAutoSelectWithUsage3(c *C) { s.testPolicyBranchesEmbeddedNodes(c, &testExecutePolicyBranchesEmbeddedNodesData{ - usage: NewPolicySessionUsage(tpm2.CommandNVChangeAuth, []NamedHandle{tpm2.NewLimitedResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...))}, tpm2.Auth("foo")).WithoutAuthValue(), + usage: NewPolicySessionUsage(tpm2.CommandNVChangeAuth, []NamedHandle{tpm2.NewResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...))}, tpm2.Auth("foo")).WithoutAuthValue(), expectedCommands: tpm2.CommandCodeList{ tpm2.CommandPolicyNvWritten, tpm2.CommandContextSave, @@ -3214,7 +3214,7 @@ func (s *policySuite) TestPolicyBranchesEmbeddedNodesAutoSelectWithUsage3(c *C) func (s *policySuite) TestPolicyBranchesEmbeddedNodesAutoSelectWildcard1(c *C) { s.testPolicyBranchesEmbeddedNodes(c, &testExecutePolicyBranchesEmbeddedNodesData{ path: "*/branch3", - usage: NewPolicySessionUsage(tpm2.CommandNVChangeAuth, []NamedHandle{tpm2.NewLimitedResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...))}, tpm2.Auth("foo")), + usage: NewPolicySessionUsage(tpm2.CommandNVChangeAuth, []NamedHandle{tpm2.NewResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...))}, tpm2.Auth("foo")), expectedCommands: tpm2.CommandCodeList{ tpm2.CommandPolicyNvWritten, tpm2.CommandPolicyAuthValue, @@ -3230,7 +3230,7 @@ func (s *policySuite) TestPolicyBranchesEmbeddedNodesAutoSelectWildcard1(c *C) { func (s *policySuite) TestPolicyBranchesEmbeddedNodesAutoSelectWildcard2(c *C) { s.testPolicyBranchesEmbeddedNodes(c, &testExecutePolicyBranchesEmbeddedNodesData{ path: "*/branch6", - usage: NewPolicySessionUsage(tpm2.CommandNVChangeAuth, []NamedHandle{tpm2.NewLimitedResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...))}, tpm2.Auth("foo")).WithoutAuthValue(), + usage: NewPolicySessionUsage(tpm2.CommandNVChangeAuth, []NamedHandle{tpm2.NewResourceContext(0x01000000, append(tpm2.Name{0x00, 0x0b}, make(tpm2.Name, 32)...))}, tpm2.Auth("foo")).WithoutAuthValue(), expectedCommands: tpm2.CommandCodeList{ tpm2.CommandPolicyNvWritten, tpm2.CommandContextSave, @@ -3526,7 +3526,7 @@ func (s *policySuite) TestPolicyDuplicationSelectNoIncludeObjectName(c *C) { s.testPolicyDuplicationSelect(c, &testExecutePolicyDuplicationSelectData{ newParent: newParent, includeObject: false, - usage: NewPolicySessionUsage(tpm2.CommandDuplicate, []NamedHandle{tpm2.NewLimitedResourceContext(0x80000000, object), tpm2.NewLimitedResourceContext(0x80000001, newParent)}, tpm2.Data{}, tpm2.SymDefObject{Algorithm: tpm2.SymObjectAlgorithmNull}), + usage: NewPolicySessionUsage(tpm2.CommandDuplicate, []NamedHandle{tpm2.NewResourceContext(0x80000000, object), tpm2.NewResourceContext(0x80000001, newParent)}, tpm2.Data{}, tpm2.SymDefObject{Algorithm: tpm2.SymObjectAlgorithmNull}), }) } diff --git a/policyutil/resources.go b/policyutil/resources.go index a302097..8dd1cbc 100644 --- a/policyutil/resources.go +++ b/policyutil/resources.go @@ -687,7 +687,7 @@ func newMockPolicyResources(authorizedPolicies PolicyAuthorizedPolicies) *mockPo func (*mockPolicyResources) loadedResource(name tpm2.Name) (ResourceContext, error) { // the handle is not relevant here - return newResourceContext(tpm2.NewLimitedResourceContext(0x80000000, name), nil), nil + return newResourceContext(tpm2.NewResourceContext(0x80000000, name), nil), nil } func (r *mockPolicyResources) policy(name tpm2.Name) (*Policy, error) { diff --git a/policyutil/walker.go b/policyutil/walker.go index ea5e569..56877af 100644 --- a/policyutil/walker.go +++ b/policyutil/walker.go @@ -96,7 +96,7 @@ func (r *treeWalker) authResourceName() tpm2.Name { func (w *treeWalker) loadExternal(public *tpm2.Public) (ResourceContext, error) { // the handle is not relevant here - resource := tpm2.NewLimitedResourceContext(0x80000000, public.Name()) + resource := tpm2.NewResourceContext(0x80000000, public.Name()) return newResourceContext(resource, nil), nil } diff --git a/resources.go b/resources.go index 8c85853..23d4f04 100644 --- a/resources.go +++ b/resources.go @@ -8,7 +8,6 @@ import ( "bytes" "crypto" _ "crypto/sha256" - "encoding/binary" "errors" "fmt" "io" @@ -103,8 +102,7 @@ type ObjectContext interface { ResourceContext // Public is the public area associated with the object. This will return nil - // if the context was created via NewLimitedHandleContext or - // NewLimitedResourceContext, or HandleContext.Dispose was called. + // if HandleContext.Dispose was called. Public() *Public } @@ -125,53 +123,80 @@ type sessionContextData struct { State SessionContextState } -type publicSized struct { - Data *Public `tpm2:"sized"` +type handleContextU struct { + Object *Public + NV *NVPublic + Session *sessionContextData } -type nvPublicSized struct { - Data *NVPublic `tpm2:"sized"` +func (d *handleContextU) Select(selector reflect.Value) interface{} { + switch selector.Interface().(handleContextType) { + case handleContextTypePermanent, handleContextTypeLimitedResource, handleContextTypeLimited: + return mu.NilUnionValue + case handleContextTypeNVIndex: + return &d.NV + case handleContextTypeSession: + return &d.Session + case handleContextTypeObject: + return &d.Object + default: + return nil + } } -type sessionContextDataSized struct { - Data *sessionContextData `tpm2:"sized"` -} +type handleContextType uint8 -type handleContextU struct { - Object *publicSized - NV *nvPublicSized - Session *sessionContextDataSized -} +const ( + handleContextTypePermanent handleContextType = 1 // corresponds to permanentContext + handleContextTypeNVIndex handleContextType = 2 // corresponds to nvIndexContext + handleContextTypeSession handleContextType = 3 // corresponds to sessionContext + handleContextTypeObject handleContextType = 4 // corresponds to objectContext -func (d *handleContextU) Select(selector reflect.Value) interface{} { - switch selector.Interface().(Handle).Type() { + // handleContextTypeLimitedResource corresponds to resourceContext. This can represent a + // NV index or object for which we have a name but no public area. + handleContextTypeLimitedResource handleContextType = 5 + + // handleContextLimited corresponds to handleContext. This can represent any TPM resource + // for which we only have a handle. The name will be set to the handle, which is ok for + // permanent resources and sessions, but it means that NV indexes and objects are unsuitable + // in any commands that use sessions. + handleContextTypeLimited handleContextType = 6 + + // handleContextTypeDisposed exists to prevent serializing handles where HandleContext.Dispose + // has been called. + handleContextTypeDisposed handleContextType = 7 +) + +func handleContextTypeFromHandle(handle Handle) handleContextType { + switch handle.Type() { case HandleTypePCR, HandleTypePermanent: - return mu.NilUnionValue - case HandleTypeTransient, HandleTypePersistent: - return &d.Object + return handleContextTypePermanent case HandleTypeNVIndex: - return &d.NV + return handleContextTypeNVIndex case HandleTypeHMACSession, HandleTypePolicySession: - return &d.Session + return handleContextTypeSession + case HandleTypeTransient, HandleTypePersistent: + return handleContextTypeObject default: - return nil + panic("invalid handle type") } } type handleContext struct { - H Handle - N Name - Data *handleContextU + HandleType handleContextType + HandleHandle Handle + HandleName Name + Data *handleContextU } var _ HandleContext = (*handleContext)(nil) func (h *handleContext) Handle() Handle { - return h.H + return h.HandleHandle } func (h *handleContext) Name() Name { - return h.N + return h.HandleName } func (h *handleContext) SerializeToBytes() []byte { @@ -192,60 +217,133 @@ func (h *handleContext) SerializeToWriter(w io.Writer) error { } func (h *handleContext) Dispose() { - h.H = HandleUnassigned - h.N = nil + h.HandleType = handleContextTypeDisposed + h.HandleHandle = HandleUnassigned + h.HandleName = MakeHandleName(HandleUnassigned) h.Data = new(handleContextU) } func (h *handleContext) checkValid() error { - switch h.H.Type() { - case HandleTypePCR, HandleTypeNVIndex, HandleTypePermanent, HandleTypeTransient, HandleTypePersistent: - return nil - case HandleTypeHMACSession, HandleTypePolicySession: - data := h.Data.Session.Data - if data == nil { - return nil + switch h.HandleType { + case handleContextTypePermanent: + switch h.HandleHandle.Type() { + case HandleTypePCR, HandleTypePermanent: + // ok + default: + return errors.New("unexpected handle type for permanent context") + } + expectedName := MakeHandleName(h.HandleHandle) + if !bytes.Equal(h.HandleName, expectedName) { + return errors.New("unexpected name for permanent context") + } + case handleContextTypeNVIndex: + switch h.HandleHandle.Type() { + case HandleTypeNVIndex: + // ok + default: + return errors.New("unexpected handle type for NV index context") + } + if h.Data.NV.NameAlg.Available() { + expectedName, err := h.Data.NV.ComputeName() + if err != nil { + return fmt.Errorf("cannot compute name of public area in NV index context: %w", err) + } + if !bytes.Equal(h.HandleName, expectedName) { + return errors.New("unexpected name for NV index context") + } + } + case handleContextTypeSession: + switch h.HandleHandle.Type() { + case HandleTypeHMACSession, HandleTypePolicySession: + // ok + default: + return errors.New("unexpected handle type for session context") + } + expectedName := MakeHandleName(h.HandleHandle) + if !bytes.Equal(h.HandleName, expectedName) { + return errors.New("unexpected name for session context") } + data := h.Data.Session if !data.Params.HashAlg.Available() { - return errors.New("digest algorithm for session context is not available") + return errors.New("session context digest algorithm is not available") } - switch h.H.Type() { + if len(data.Params.SessionKey) > 0 && len(data.Params.SessionKey) != data.Params.HashAlg.Size() { + return errors.New("inconsistent digest algorithm and session key length for session context") + } + switch h.HandleHandle.Type() { case HandleTypeHMACSession: + if data.Params.IsBound && len(data.Params.SessionKey) == 0 { + return errors.New("inconsistent bind parameters and session key length for HMAC session context") + } + if data.Params.IsBound && len(data.Params.BoundEntity) == 0 || !data.Params.IsBound && len(data.Params.BoundEntity) > 0 { + return errors.New("inconsistent bind parameters for HMAC session context") + } if data.State.NeedsPassword || data.State.NeedsAuthValue { - return errors.New("invalid policy session HMAC type for HMAC session context") + return errors.New("invalid policy session auth type for HMAC session context") } case HandleTypePolicySession: - // ok + if data.Params.IsBound || len(data.Params.BoundEntity) > 0 { + return errors.New("invalid bind parameters for policy session context") + } + if data.State.NeedsPassword && data.State.NeedsAuthValue { + return errors.New("inconsistent auth types for policy session context") + } default: panic("not reached") } return nil + case handleContextTypeObject: + switch h.HandleHandle.Type() { + case HandleTypeTransient, HandleTypePersistent: + // ok + default: + return errors.New("unexpected handle type for object context") + } + if h.Data.Object.NameAlg.Available() { + expectedName, err := h.Data.Object.ComputeName() + if err != nil { + return fmt.Errorf("cannot compute name of public area in object context: %w", err) + } + if !bytes.Equal(h.HandleName, expectedName) { + return errors.New("unexpected name for object context") + } + } + case handleContextTypeLimitedResource: + switch h.HandleHandle.Type() { + case HandleTypeNVIndex, HandleTypeTransient, HandleTypePersistent: + // ok + default: + return errors.New("unexpected handle type for limited resource context") + } + case handleContextTypeLimited: + switch h.HandleHandle.Type() { + case HandleTypePCR, HandleTypeNVIndex, HandleTypeHMACSession, HandleTypePolicySession, HandleTypePermanent, HandleTypeTransient, HandleTypePersistent: + // ok + default: + return errors.New("unexpected handle type for limited context") + } + expectedName := mu.MustMarshalToBytes(h.HandleHandle) + if !bytes.Equal(h.HandleName, expectedName) { + return errors.New("unexpected name for limited context") + } default: - // shouldn't happen because it should have failed to unmarshal - panic("invalid context type") + panic("not reached") } + + return nil } -func newLimitedHandleContext(handle Handle) HandleContext { +func newHandleContext(handle Handle) HandleContext { switch handle.Type() { - case HandleTypePCR, HandleTypePermanent: - return newPermanentContext(handle) - case HandleTypeNVIndex: - name := make(Name, binary.Size(Handle(0))) - binary.BigEndian.PutUint32(name, uint32(handle)) - - return newNVIndexContext(handle, name, nil) - case HandleTypeHMACSession, HandleTypePolicySession: - return newSessionContext(handle, nil) - case HandleTypeTransient, HandleTypePersistent: - name := make(Name, binary.Size(Handle(0))) - binary.BigEndian.PutUint32(name, uint32(handle)) - - return newObjectContext(handle, name, nil) + case HandleTypePCR, HandleTypeNVIndex, HandleTypeHMACSession, HandleTypePolicySession, HandleTypePermanent, HandleTypeTransient, HandleTypePersistent: + return &handleContext{ + HandleType: handleContextTypeLimited, + HandleHandle: handle, + HandleName: mu.MustMarshalToBytes(handle), + } default: panic("invalid handle type") } - } type resourceContext struct { @@ -253,12 +351,16 @@ type resourceContext struct { authValue []byte } -func newLimitedResourceContext(handle Handle, name Name) ResourceContext { +func newResourceContext(handle Handle, name Name) ResourceContext { switch handle.Type() { - case HandleTypeNVIndex: - return newNVIndexContext(handle, name, nil) - case HandleTypeTransient, HandleTypePersistent: - return newObjectContext(handle, name, nil) + case HandleTypePCR, HandleTypeNVIndex, HandleTypePermanent, HandleTypeTransient, HandleTypePersistent: + return &resourceContext{ + handleContext: handleContext{ + HandleType: handleContextTypeLimitedResource, + HandleHandle: handle, + HandleName: name, + }, + } default: panic("invalid handle type") } @@ -286,18 +388,18 @@ type permanentContext struct { func newPermanentContext(handle Handle) *permanentContext { switch handle.Type() { case HandleTypePCR, HandleTypePermanent: - // ok + return &permanentContext{ + resourceContext: resourceContext{ + handleContext: handleContext{ + HandleType: handleContextTypePermanent, + HandleHandle: handle, + HandleName: MakeHandleName(handle), + }, + }, + } default: panic("invalid handle type") } - - name := make(Name, binary.Size(Handle(0))) - binary.BigEndian.PutUint32(name, uint32(handle)) - return &permanentContext{ - resourceContext: resourceContext{ - handleContext: handleContext{ - H: handle, - N: name}}} } var _ ResourceContext = (*permanentContext)(nil) @@ -315,17 +417,23 @@ type objectContext struct { func newObjectContext(handle Handle, name Name, public *Public) *objectContext { switch handle.Type() { case HandleTypeTransient, HandleTypePersistent: - // ok + if public == nil { + panic("nil public area") + } + return &objectContext{ + resourceContext: resourceContext{ + handleContext: handleContext{ + HandleType: handleContextTypeObject, + HandleHandle: handle, + HandleName: name, + Data: &handleContextU{Object: public}, + }, + }, + } default: panic("invalid handle type") } - return &objectContext{ - resourceContext: resourceContext{ - handleContext: handleContext{ - H: handle, - N: name, - Data: &handleContextU{Object: &publicSized{Data: public}}}}} } func (t *TPMContext) newObjectContextFromTPM(context HandleContext, sessions ...SessionContext) (ResourceContext, error) { @@ -342,11 +450,7 @@ func (t *TPMContext) newObjectContextFromTPM(context HandleContext, sessions ... var _ ObjectContext = (*objectContext)(nil) func (r *objectContext) Public() *Public { - if r.Data.Object == nil { - // This context was disposed. - return nil - } - return r.Data.Object.Data + return r.Data.Object } type nvIndexContext struct { @@ -356,17 +460,23 @@ type nvIndexContext struct { func newNVIndexContext(handle Handle, name Name, public *NVPublic) *nvIndexContext { switch handle.Type() { case HandleTypeNVIndex: - // ok + if public == nil { + panic("nil public area") + } + return &nvIndexContext{ + resourceContext: resourceContext{ + handleContext: handleContext{ + HandleType: handleContextTypeNVIndex, + HandleHandle: handle, + HandleName: name, + Data: &handleContextU{NV: public}, + }, + }, + } default: panic("invalid handle type") } - return &nvIndexContext{ - resourceContext: resourceContext{ - handleContext: handleContext{ - H: handle, - N: name, - Data: &handleContextU{NV: &nvPublicSized{Data: public}}}}} } func (t *TPMContext) newNVIndexContextFromTPM(context HandleContext, sessions ...SessionContext) (ResourceContext, error) { @@ -386,20 +496,20 @@ func (t *TPMContext) newNVIndexContextFromTPM(context HandleContext, sessions .. var _ NVIndexContext = (*nvIndexContext)(nil) func (r *nvIndexContext) Type() NVType { - if r.Data.NV == nil || r.Data.NV.Data == nil { - // This context was disposed or is limited + if r.Data.NV == nil { + // This context was disposed return 0 } - return r.Data.NV.Data.Attrs.Type() + return r.Data.NV.Attrs.Type() } func (r *nvIndexContext) SetAttr(a NVAttributes) { - if r.Data.NV == nil || r.Data.NV.Data == nil { - // This context was disposed or is limited + if r.Data.NV == nil { + // This context was disposed return } - r.Data.NV.Data.Attrs |= a - r.N = r.Data.NV.Data.Name() + r.Data.NV.Attrs |= a + r.HandleName = r.Data.NV.Name() } type sessionContext struct { @@ -410,27 +520,30 @@ type sessionContext struct { func newSessionContext(handle Handle, data *sessionContextData) *sessionContext { switch handle.Type() { case HandleTypeHMACSession, HandleTypePolicySession: - // ok + if data == nil { + panic("nil session data") + } default: if handle != HandlePW { panic("invalid handle type") } } - name := make(Name, binary.Size(Handle(0))) - binary.BigEndian.PutUint32(name, uint32(handle)) return &sessionContext{ handleContext: &handleContext{ - H: handle, - N: name, - Data: &handleContextU{Session: &sessionContextDataSized{Data: data}}}} + HandleType: handleContextTypeSession, + HandleHandle: handle, + HandleName: MakeHandleName(handle), + Data: &handleContextU{Session: data}, + }, + } } var _ SessionContext = (*sessionContext)(nil) -func (r *sessionContext) Available() bool { - return r.Data() != nil -} +//func (r *sessionContext) Available() bool { +// return r.Data() != nil +//} func (r *sessionContext) Params() SessionContextParams { d := r.Data() @@ -508,11 +621,7 @@ func (r *sessionContext) ExcludeAttrs(attrs SessionAttributes) SessionContext { } func (r *sessionContext) Data() *sessionContextData { - if r.handleContext.Data.Session == nil { - // This handle context was disposed. - return nil - } - return r.handleContext.Data.Session.Data + return r.handleContext.Data.Session } func pwSession() SessionContext { @@ -531,7 +640,7 @@ func (t *TPMContext) newResourceContextFromTPM(handle HandleContext, sessions .. case HandleTypeTransient, HandleTypePersistent: rc, err = t.newObjectContextFromTPM(handle, sessions...) default: - panic("invalid handle type") + return nil, errors.New("invalid handle type") } switch { @@ -557,14 +666,17 @@ func (t *TPMContext) newResourceContextFromTPM(handle HandleContext, sessions .. // If any sessions are supplied, the public area is read from the TPM twice. The second time uses // the supplied sessions. // -// This function will panic if handle doesn't correspond to a NV index, transient object or -// persistent object. +// This function will return an error if handle doesn't correspond to a NV index, transient object +// or persistent object. // // If subsequent use of the returned ResourceContext requires knowledge of the authorization value // of the corresponding TPM resource, this should be provided by calling // [ResourceContext].SetAuthValue. +// +// If the specified handle is an object, the returned context can be type asserted to [ObjectContext]. +// If the specified handle is a NV index, the returned context can be type asserted to [NVIndexContext]. func (t *TPMContext) NewResourceContext(handle Handle, sessions ...SessionContext) (ResourceContext, error) { - rc, err := t.newResourceContextFromTPM(newLimitedHandleContext(handle)) + rc, err := t.newResourceContextFromTPM(newHandleContext(handle)) if err != nil { return nil, err } @@ -587,41 +699,59 @@ func (t *TPMContext) NewResourceContext(handle Handle, sessions ...SessionContex // If any sessions are supplied, the public area is read from the TPM twice. The second time uses // the supplied sessions. // -// This function will panic if handle doesn't correspond to a NV index, transient object or -// persistent object. +// This function will return an error if handle doesn't correspond to a NV index, transient object +// or persistent object. // // If subsequent use of the returned ResourceContext requires knowledge of the authorization value // of the corresponding TPM resource, this should be provided by calling // [ResourceContext].SetAuthValue. // +// If the specified handle is an object, the returned context can be type asserted to [ObjectContext]. +// If the specified handle is a NV index, the returned context can be type asserted to [NVIndexContext]. +// // Deprecated: Use [TPMContext.NewResourceContext] instead. func (t *TPMContext) CreateResourceContextFromTPM(handle Handle, sessions ...SessionContext) (ResourceContext, error) { return t.NewResourceContext(handle, sessions...) } -// NewLimitedHandleContext creates a new HandleContext for the specified handle. The returned -// HandleContext can not be used in any commands other than [TPMContext.FlushContext], -// [TPMContext.ReadPublic] or [TPMContext.NVReadPublic], and it cannot be used with any sessions. +// NewHandleContext creates a new HandleContext for the specified handle. The returned +// HandleContext cannot be type asserted to [ResourceContext] or [SessionContext] and can +// only be used in commands that don't use sessions, such as [TPMContext.FlushContext], +// [TPMContext.ReadPublic] or [TPMContext.NVReadPublic]. // -// This function will panic if handle doesn't correspond to a session, transient or persistent -// object, or NV index. -func NewLimitedHandleContext(handle Handle) HandleContext { +// This function will panic if handle doesn't correspond to a session, transient or +// persistent object, or NV index. +func NewHandleContext(handle Handle) HandleContext { switch handle.Type() { case HandleTypeNVIndex, HandleTypeHMACSession, HandleTypePolicySession, HandleTypeTransient, HandleTypePersistent: - return newLimitedHandleContext(handle) + return newHandleContext(handle) default: panic("invalid handle type") } } -// CreatePartialHandleContext creates a new HandleContext for the specified handle. The returned -// HandleContext is partial and cannot be used in any command other than [TPMContext.FlushContext], -// [TPMContext.ReadPublic] or [TPMContext.NVReadPublic], and it cannot be used with any sessions. +// NewLimitedHandleContext creates a new HandleContext for the specified handle. The +// returned HandleContext cannot be type asserted to [ResourceContext] or [SessionContext] +// and can only be used in commands that don't use sessions, such as [TPMContext.FlushContext], +// [TPMContext.ReadPublic] or [TPMContext.NVReadPublic]. // -// This function will panic if handle doesn't correspond to a session, transient or persistent -// object, or NV index. +// This function will panic if handle doesn't correspond to a session, transient or +// persistent object, or NV index. // -// Deprecated: Use [NewLimitedHandleContext]. +// Deprecated: use [NewHandleContext]. +func NewLimitedHandleContext(handle Handle) HandleContext { + return NewHandleContext(handle) +} + +// CreatePartialHandleContext creates a new HandleContext for the specified handle. The +// returned HandleContext cannot be type asserted to [ResourceContext] or [SessionContext] +// and can only be used in commands that don't use sessions, such as [TPMContext.FlushContext], +// [TPMContext.ReadPublic] or [TPMContext.NVReadPublic]. +// +// This function will panic if handle doesn't correspond to a session, transient or +// persistent object, or NV index. +// +// Deprecated: Use [NewHandleContext]. func CreatePartialHandleContext(handle Handle) HandleContext { return NewLimitedHandleContext(handle) } @@ -724,31 +854,28 @@ func NewHandleContextFromReader(r io.Reader) (HandleContext, error) { return nil, errors.New("context blob contains trailing bytes") } - switch data.Handle().Type() { - case HandleTypePCR, HandleTypePermanent: - return nil, errors.New("cannot create a permanent context from serialized data") - } - if err := data.checkValid(); err != nil { return nil, err } - var hc HandleContext - switch data.Handle().Type() { - case HandleTypeNVIndex: - hc = &nvIndexContext{resourceContext: resourceContext{handleContext: *data}} - case HandleTypeHMACSession, HandleTypePolicySession: - if data.Data.Session.Data != nil { - data.Data.Session.Data.State.IsExclusive = false - } - hc = &sessionContext{handleContext: data} - case HandleTypeTransient, HandleTypePersistent: - hc = &objectContext{resourceContext: resourceContext{handleContext: *data}} + switch data.HandleType { + case handleContextTypePermanent: + return newPermanentContext(data.Handle()), nil + case handleContextTypeNVIndex: + return newNVIndexContext(data.Handle(), data.Name(), data.Data.NV), nil + case handleContextTypeSession: + data.Data.Session.State.IsExclusive = false + return newSessionContext(data.Handle(), data.Data.Session), nil + case handleContextTypeObject: + return newObjectContext(data.Handle(), data.Name(), data.Data.Object), nil + case handleContextTypeLimitedResource: + return newResourceContext(data.Handle(), data.Name()), nil + case handleContextTypeLimited: + return newHandleContext(data.Handle()), nil default: + // this should have been caught earlier panic("not reached") } - - return hc, nil } // CreateHandleContextFromReader returns a new HandleContext created from the serialized data read @@ -786,22 +913,6 @@ func NewHandleContextFromBytes(b []byte) (HandleContext, int, error) { return rc, len(b) - buf.Len(), nil } -// NewLimitedResourceContext creates a new ResourceContext with the specified handle and name. The -// returned ResourceContext has limited functionality - eg, it cannot be used in functions that -// require knowledge of the public area associated with the resource (such as -// [TPMContext.StartAuthSession] and some NV functions). -// -// This function will panic if handle doesn't correspond to a transient or persistent object, or an -// NV index. -func NewLimitedResourceContext(handle Handle, name Name) ResourceContext { - switch handle.Type() { - case HandleTypeNVIndex, HandleTypeTransient, HandleTypePersistent: - return newLimitedResourceContext(handle, name) - default: - panic("invalid handle type") - } -} - // CreateHandleContextFromBytes returns a new HandleContext created from the serialized data read // from the supplied byte slice. This should contain data that was previously created by // [HandleContext].SerializeToBytes or [HandleContext].SerializeToWriter. @@ -818,13 +929,56 @@ func CreateHandleContextFromBytes(b []byte) (HandleContext, int, error) { return NewHandleContextFromBytes(b) } +// NewResourceContext creates a new ResourceContext with the specified handle and name. The +// returned ResourceContext has limited functionality - eg, it cannot bs used in functions that +// require knowledge of the public area associated with the resource (such as +// [TPMContext.StartAuthSession]), and some NV functions that modify the attributes of an index +// will not update its name. It cannot be type asserted to [ObjectContext] or [NVIndexContext]. +// +// If subsequent use of the returned ResourceContext requires knowledge of the authorization value +// of the corresponding TPM resource, this should be provided by calling +// [ResourceContext].SetAuthValue. +// +// This function will panic if handle doesn't correspond to a transient or persistent object, or an +// NV index. +func NewResourceContext(handle Handle, name Name) ResourceContext { + switch handle.Type() { + case HandleTypeNVIndex, HandleTypeTransient, HandleTypePersistent: + return newResourceContext(handle, name) + default: + panic("invalid handle type") + } +} + +// NewLimitedResourceContext creates a new ResourceContext with the specified handle and name. The +// returned ResourceContext has limited functionality - eg, it cannot bs used in functions that +// require knowledge of the public area associated with the resource (such as +// [TPMContext.StartAuthSession], and some NV functions that modify the attributes of an index +// will not update its name. It cannot be type asserted to [ObjectContext] or [NVIndexContext]. +// +// If subsequent use of the returned ResourceContext requires knowledge of the authorization value +// of the corresponding TPM resource, this should be provided by calling +// [ResourceContext].SetAuthValue. +// +// This function will panic if handle doesn't correspond to a transient or persistent object, or an +// NV index. +// +// Deprecated: use [NewResourceContext]. +func NewLimitedResourceContext(handle Handle, name Name) ResourceContext { + return NewResourceContext(handle, name) +} + // NewNVIndexResourceContextFromPub returns a new ResourceContext created from the provided // public area. If subsequent use of the returned ResourceContext requires knowledge of the // authorization value of the corresponding TPM resource, this should be provided by calling -// [ResourceContext].SetAuthValue. +// [ResourceContext].SetAuthValue. The returned context can be type asserted to +// [NVIndexContext]. // // This requires that the associated name algorithm is linked into the current binary. func NewNVIndexResourceContextFromPub(pub *NVPublic) (ResourceContext, error) { + if pub.Index.Type() != HandleTypeNVIndex { + return nil, errors.New("invalid handle type") + } name, err := pub.ComputeName() if err != nil { return nil, fmt.Errorf("cannot compute name from public area: %v", err) @@ -836,15 +990,22 @@ func NewNVIndexResourceContextFromPub(pub *NVPublic) (ResourceContext, error) { // and associated name. This is useful for creating a ResourceContext for an object that uses a // name algorithm that is not available. If subsequent use of the returned ResourceContext requires // knowledge of the authorization value of the corresponding TPM resource, this should be provided -// by calling [ResourceContext].SetAuthValue. +// by calling [ResourceContext].SetAuthValue. The returned context can be type asserted to +// [NVIndexContext]. +// +// This does not check the consistency of the name and public area. +// +// It will panic if the Index field of the supplied public area has a handle type other than +// [HandleTypeNVIndex]. func NewNVIndexResourceContext(pub *NVPublic, name Name) ResourceContext { return newNVIndexContext(pub.Index, name, pub) } -// CreateNVIndexResourceContextFromPublic returns a new ResourceContext created from the provided -// public area. If subsequent use of the returned ResourceContext requires knowledge of the -// authorization value of the corresponding TPM resource, this should be provided by calling -// [ResourceContext].SetAuthValue. +// CreateNVIndexResourceContextFromPublic returns a new ResourceContext created from the +// provided public area. If subsequent use of the returned ResourceContext requires knowledge +// of the authorization value of the corresponding TPM resource, this should be provided by +// calling [ResourceContext].SetAuthValue. The returned context can be type asserted to +// [NVIndexContext]. // // This requires that the associated name algorithm is linked into the current binary. // @@ -856,7 +1017,8 @@ func CreateNVIndexResourceContextFromPublic(pub *NVPublic) (ResourceContext, err // NewObjectResourceContextFromPub returns a new ResourceContext created from the provided // public area. If subsequent use of the returned ResourceContext requires knowledge of the // authorization value of the corresponding TPM resource, this should be provided by calling -// [ResourceContext].SetAuthValue. +// [ResourceContext].SetAuthValue. The returned context can be type asserted to +// [ObjectContext]. // // This requires that the associated name algorithm is linked into the current binary. func NewObjectResourceContextFromPub(handle Handle, pub *Public) (ResourceContext, error) { @@ -876,22 +1038,21 @@ func NewObjectResourceContextFromPub(handle Handle, pub *Public) (ResourceContex // associated name. This is useful for creating a ResourceContext for an object that uses a name // algorithm that is not available. If subsequent use of the returned ResourceContext requires // knowledge of the authorization value of the corresponding TPM resource, this should be provided -// by calling [ResourceContext].SetAuthValue. +// by calling [ResourceContext].SetAuthValue. The returned context can be type asserted to +// [ObjectContext]. +// +// This does not check the consistency of the name and public area. // // This will panic if the handle type is not [HandleTypeTransient] or [HandleTypePersistent]. func NewObjectResourceContext(handle Handle, pub *Public, name Name) ResourceContext { - switch handle.Type() { - case HandleTypeTransient, HandleTypePersistent: - return newObjectContext(handle, name, pub) - default: - panic("invalid handle type") - } + return newObjectContext(handle, name, pub) } -// CreateObjectResourceContextFromPublic returns a new ResourceContext created from the provided +// CreateObjectResourceContextFromPub returns a new ResourceContext created from the provided // public area. If subsequent use of the returned ResourceContext requires knowledge of the // authorization value of the corresponding TPM resource, this should be provided by calling -// [ResourceContext].SetAuthValue. +// [ResourceContext].SetAuthValue. The returned context can be type asserted to +// [ObjectContext]. // // This requires that the associated name algorithm is linked into the current binary. // diff --git a/resources_test.go b/resources_test.go index 056791a..1925658 100644 --- a/resources_test.go +++ b/resources_test.go @@ -43,7 +43,7 @@ func (s *resourcesSuite) testNewObjectResourceContextFromTPM(c *C, data *testNew c.Check(rc.(ObjectContext).Public(), DeepEquals, data.public) } -func (s *resourcesSuite) TestNewResourceContextTransient(c *C) { +func (s *resourcesSuite) TestNewResourceContextFromTPMTransient(c *C) { rc := s.CreateStoragePrimaryKeyRSA(c) s.testNewObjectResourceContextFromTPM(c, &testNewObjectResourceContextFromTPMData{ handle: rc.Handle(), @@ -51,7 +51,7 @@ func (s *resourcesSuite) TestNewResourceContextTransient(c *C) { name: rc.Name()}) } -func (s *resourcesSuite) TestNewResourceContextPersistent(c *C) { +func (s *resourcesSuite) TestNewResourceContextFromTPMPersistent(c *C) { rc := s.CreateStoragePrimaryKeyRSA(c) rc = s.EvictControl(c, HandleOwner, rc, s.NextAvailableHandle(c, 0x81000008)) s.testNewObjectResourceContextFromTPM(c, &testNewObjectResourceContextFromTPMData{ @@ -99,12 +99,13 @@ func (s *resourcesSuite) TestNewResourceContextUnavailableNV(c *C) { s.testNewResourceContextUnavailable(c, 0x018100ff) } -func (s *resourcesSuite) TestNewResourceContextPanicsForWrongType(c *C) { - c.Check(func() { s.TPM.NewResourceContext(HandleOwner) }, PanicMatches, "invalid handle type") +func (s *resourcesSuite) TestNewResourceContextErrorsForWrongType(c *C) { + _, err := s.TPM.NewResourceContext(HandleOwner) + c.Check(err, ErrorMatches, `invalid handle type`) } -func (s *resourcesSuite) testNewLimitedHandleContext(c *C, handle Handle) { - hc := NewLimitedHandleContext(handle) +func (s *resourcesSuite) testNewHandleContext(c *C, handle Handle) { + hc := NewHandleContext(handle) c.Assert(hc, NotNil) c.Check(hc.Handle(), Equals, handle) @@ -113,33 +114,33 @@ func (s *resourcesSuite) testNewLimitedHandleContext(c *C, handle Handle) { c.Check(hc.Name(), DeepEquals, name) } -func (s *resourcesSuite) TestNewLimitedHandleContextSession(c *C) { +func (s *resourcesSuite) TestNewHandleContextSession(c *C) { session := s.StartAuthSession(c, nil, nil, SessionTypeHMAC, nil, HashAlgorithmSHA256) - s.testNewLimitedHandleContext(c, session.Handle()) + s.testNewHandleContext(c, session.Handle()) } -func (s *resourcesSuite) TestNewLimitedHandleContextTransient(c *C) { +func (s *resourcesSuite) TestNewHandleContextTransient(c *C) { rc := s.CreateStoragePrimaryKeyRSA(c) - s.testNewLimitedHandleContext(c, rc.Handle()) + s.testNewHandleContext(c, rc.Handle()) } -func (s *resourcesSuite) TestNewLimitedHandleContextForWrongType(c *C) { - c.Check(func() { NewLimitedHandleContext(0x00000000) }, PanicMatches, "invalid handle type") +func (s *resourcesSuite) TestNewHandleContextForWrongType(c *C) { + c.Check(func() { NewHandleContext(0x00000000) }, PanicMatches, "invalid handle type") } -func (s *resourcesSuite) testNewLimitedResourceContext(c *C, handle Handle, name Name) { - rc := NewLimitedResourceContext(handle, name) +func (s *resourcesSuite) testNewResourceContext(c *C, handle Handle, name Name) { + rc := NewResourceContext(handle, name) c.Assert(rc, NotNil) c.Check(rc.Handle(), Equals, handle) c.Check(rc.Name(), DeepEquals, name) } -func (s *resourcesSuite) TestNewLimitedResourceContextTransient(c *C) { - s.testNewLimitedResourceContext(c, 0x80000001, internal_testutil.DecodeHexString(c, "000b000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")) +func (s *resourcesSuite) TestNewResourceContextTransient(c *C) { + s.testNewResourceContext(c, 0x80000001, internal_testutil.DecodeHexString(c, "000b000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")) } -func (s *resourcesSuite) TestNewLimitedResourceContextPersistent(c *C) { - s.testNewLimitedResourceContext(c, 0x81000002, internal_testutil.DecodeHexString(c, "0004000102030405060708090a0b0c0d0e0f10111213")) +func (s *resourcesSuite) TestNewResourceContextPersistent(c *C) { + s.testNewResourceContext(c, 0x81000002, internal_testutil.DecodeHexString(c, "0004000102030405060708090a0b0c0d0e0f10111213")) } type testNewObjectHandleContextFromBytesData struct { diff --git a/testutil/transport.go b/testutil/transport.go index cc9a197..bc66b64 100644 --- a/testutil/transport.go +++ b/testutil/transport.go @@ -861,7 +861,7 @@ func (t *Transport) removeResources(errs []error, tpm *tpm2.TPMContext) []error errs = append(errs, fmt.Errorf("cannot undefine %v: %w", info.handle, err)) } case tpm2.HandleTypeHMACSession, tpm2.HandleTypePolicySession, tpm2.HandleTypeTransient: - tpm.FlushContext(tpm2.NewLimitedHandleContext(info.handle)) + tpm.FlushContext(tpm2.NewHandleContext(info.handle)) case tpm2.HandleTypePersistent: auth := tpm.GetPermanentContext(info.auth()) object, err := tpm2.NewObjectResourceContextFromPub(info.handle, info.pub)