in TSS.NET/TSS.Net/Tpm2.cs [1701:1887]
private void PrepareRequestSessions(CommandInfo commandInfo, TpmHandle[] inHandles)
{
if (OuterCommand != TpmCc.None)
{
// Nested commands must not use sessions
return;
}
Debug.Assert(commandInfo.AuthHandleCountIn <= inHandles.Length);
// Does the command require authorization and not all sessions are provided?
if (!_Behavior.Strict && commandInfo.AuthHandleCountIn > Sessions.Length)
{
// Allocate missing sessions
if (Sessions.Length == 0)
{
Sessions = new SessionBase[commandInfo.AuthHandleCountIn];
}
else
{
SessionBase[] explicitSessions = Sessions;
Sessions = new SessionBase[commandInfo.AuthHandleCountIn];
explicitSessions.CopyTo(Sessions, 0);
}
}
if (Sessions.Length == 0)
{
return;
}
for (int i = 0; i < Sessions.Length; ++i)
{
SessionBase s = Sessions[i];
// Is authorization for this handle explicitly suppressed?
if (s == SessionBase.None)
continue;
TpmHandle authHandle = null;
if (i < commandInfo.AuthHandleCountIn)
{
authHandle = inHandles[i];
switch (authHandle.handle)
{
case (uint)TpmRh.Owner:
authHandle.Auth = OwnerAuth;
break;
case (uint)TpmRh.Endorsement:
authHandle.Auth = EndorsementAuth;
break;
case (uint)TpmRh.Platform:
authHandle.Auth = PlatformAuth;
break;
case (uint)TpmRh.Lockout:
authHandle.Auth = LockoutAuth;
break;
default:
if (authHandle.GetType() == Ht.Pcr && PcrHandles != null)
{
int pcrId = (int)authHandle.GetOffset();
if (pcrId < PcrHandles.Length &&
PcrHandles[pcrId] != null)
{
authHandle.Auth = PcrHandles[pcrId].Auth;
}
else if (authHandle.handle >= (uint)TpmRh.Act0 && authHandle.handle <= (uint)TpmRh.ActF)
{
authHandle.Auth = PlatformAuth;
}
}
break;
}
}
if (SessionBase.IsPlaceholder(s))
{
// Create missing session
if (s == SessionBase.Hmac ||
s == SessionBase.Default && _GetUnderlyingDevice().NeedsHMAC)
{
// When used from inside command injection callback, all HMAC
// sessions must be created explicitly to avoid additional
// command nesting level.
if (InjectCmdCallbackInvoked)
throw new Exception("No implicit HMAC sessions allowed " +
"in a command injection callback");
bool done;
do {
done = true;
try {
s = Sessions[i] = CancelSafeStartAuthSession(TpmSe.Hmac, AutoAuthHashAlg);
}
catch (TpmException e)
{
if ( GetBaseErrorCode(e.RawResponse) == TpmRc.Hash
&& AutoAuthHashAlg != TpmAlgId.Sha1)
{
if (AutoAuthHashAlg == TpmAlgId.Sha384)
AutoAuthHashAlg = TpmAlgId.Sha256;
else if (AutoAuthHashAlg == TpmAlgId.Sha256)
AutoAuthHashAlg = TpmAlgId.Sha1;
else
AutoAuthHashAlg = TpmAlgId.Sha384;
done = false;
}
else
throw;
}
} while (!done);
// Stash away session object to flush it from TPM after the command completion
TempSessions.Add(Sessions[i]);
}
else
{
s = Sessions[i] = new Pwap(authHandle.Auth);
}
}
if (s.Handle != TpmRh.Pw && !_InitializeSession(s as AuthSession))
{
// There are no session parameters associated with the session
// handle (e.g., when the session was created by other Tpm2 object).
Globs.Throw("Wrong session handle");
}
s.AuthHandle = authHandle;
}
foreach (TpmHandle h in inHandles)
{
if (h.Name == null)
{
// When used from inside command injection callback, TpmHandle.Name
// property of input handles must be initialized before command invocation
// to avoid additional command nesting level (ReadPublic or NvReadPublic).
// This can be done by explicitly calling handle.GetName(tpm)
// method before using this handle in the TPM command.
if (InjectCmdCallbackInvoked)
throw new Exception("Unitialized Name property in a handle " +
"used by command injection callback");
byte[] name = null;
// Use try-catch to intercept possible TpmRc.Handle or TpmRc.Sequence errors
try
{
switch (h.GetType())
{
case Ht.Transient:
case Ht.Persistent:
{
byte[] qualName = null;
ReadPublic(h, out name, out qualName);
break;
}
case Ht.NvIndex:
{
NvPublic pub = NvReadPublic(h, out name);
// Do not cache the name of the NV index if it is
// not yet written or if it has an attribute that
// allows its written state to be reset or its
// contents to be locked.
if (!pub.attributes.HasFlag(NvAttr.Written) ||
0 != (pub.attributes & NvAttr.Orderly |
(NvAttr.ReadStclear | NvAttr.ClearStclear |
NvAttr.Writedefine | NvAttr.Globallock)))
{
TempNames.Add(h);
}
break;
}
}
}
catch (TpmException)
{
// Failed to read public part of the object. Leave its name empty.
}
h.Name = name;
}
}
// Roll the nonces.
RollNonces();
// Determine if parameter encryption/decryption is necessary.
PrepareParmEncryptionSessions();
}