private void PrepareRequestSessions()

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();
        }