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)