예제 #1
0
 public TpmException(TpmRc rawResponse, string errorDescription, TpmStructureBase cmdParms)
     : base(errorDescription)
 {
     ErrorString = TpmErrorHelpers.ErrorNumber(rawResponse).ToString();
     RawResponse = rawResponse;
     CmdParms    = cmdParms;
 }
예제 #2
0
        public async Task <Tpm2CreateResponse> CreateAsync(
            TpmHandle parentHandle,
            SensitiveCreate inSensitive,
            TpmPublic inPublic,
            byte[] outsideInfo,
            PcrSelection[] creationPCR)
        {
            var inS = new Tpm2CreateRequest(parentHandle, inSensitive, inPublic, outsideInfo, creationPCR);
            TpmStructureBase outSBase = null;
            await Task.Run(() => DispatchMethod(TpmCc.Create, inS, typeof(Tpm2CreateResponse), out outSBase, 1, 0));

            var outS = (Tpm2CreateResponse)outSBase;

            return(outS);
        }
예제 #3
0
        public async Task <ISignatureUnion> SignAsync(
            TpmHandle keyHandle,
            byte[] digest,
            ISigSchemeUnion inScheme,
            TkHashcheck validation)
        {
            var inS = new Tpm2SignRequest(keyHandle, digest, inScheme, validation);
            TpmStructureBase outSBase = null;
            await Task.Run(() => DispatchMethod(TpmCc.Sign, inS,
                                                typeof(Tpm2SignResponse),
                                                out outSBase, 1, 0));

            var outS = (Tpm2SignResponse)outSBase;

            return(outS.signature);
        }
예제 #4
0
        public async Task <Tpm2CreatePrimaryResponse> CreatePrimaryAsync(
            TpmHandle primaryHandle,
            SensitiveCreate inSensitive,
            TpmPublic inPublic,
            byte[] outsideInfo,
            PcrSelection[] creationPCR)
        {
            var inS = new Tpm2CreatePrimaryRequest {
                primaryHandle = primaryHandle,
                inSensitive   = inSensitive,
                inPublic      = inPublic,
                outsideInfo   = outsideInfo,
                creationPCR   = creationPCR
            };
            TpmStructureBase outSBase = null;
            await Task.Run(() =>
                           DispatchMethod(TpmCc.CreatePrimary, inS, typeof(Tpm2CreatePrimaryResponse), out outSBase, 1, 1));

            var outS = (Tpm2CreatePrimaryResponse)outSBase;

            return(outS);
        }
예제 #5
0
        /// <summary>
        /// Splits a TpmStructureBase command or response, and splits it into 
        /// handles and the parms data
        /// </summary>
        /// <param name="s"></param>
        /// <param name="numHandles"></param>
        /// <param name="handles"></param>
        /// <param name="parms"></param>
        public static void Fragment(TpmStructureBase s, uint numHandles, out TpmHandle[] handles, out byte[] parms)
        {
            handles = new TpmHandle[numHandles];
            // Get the handles (note we need to return the actual object because it contains the name.
            // The handles are always first, and will be simple fields or get/set props.
            MemberInfo[] fields;
            try
            {
                fields = s.GetType().GetMembers(BindingFlags.Public | BindingFlags.Instance);
            }
            catch (Exception)
            {
                throw;
            }

            int fieldPos = 0;
            for (int j = 0; j < numHandles; j++)
            {
                MemberInfo f;
                do
                {
                    // Ignore setters
                    f = fields[fieldPos++];
                } while (f.Name.StartsWith("set_"));
                // Either a simple field
                var ff = f as FieldInfo;
                if (ff != null)
                {
                    handles[j] = (TpmHandle)ff.GetValue(s);
                }
                // A get or set accessor
                var mm = f as MethodInfo;
                if (mm != null)
                {
                    object hRep = mm.Invoke(s, null);
                    handles[j] = hRep is TpmHandle ? (TpmHandle)hRep : ((TpmHandleX)hRep).Handle;
                }
            }
            // And the rest is the parms
            byte[] b = Marshaller.GetTpmRepresentation(s);
            parms = new byte[b.Length - numHandles * 4];
            Array.Copy(b, (int)numHandles * 4, parms, 0, b.Length - (int)numHandles * 4);
        }
예제 #6
0
 /// <summary>
 /// Log the command / response to the debug stream
 /// </summary>
 /// <param name="commandCode"></param>
 /// <param name="theStruct"></param>
 /// <param name="outOrIn"></param>
 private void Log(TpmCc commandCode, TpmStructureBase theStruct, int outOrIn)
 {
     if (!CommandLogging)
         return;
     Debug.WriteLine("COMMAND " + Enum.GetName(typeof (TpmCc), commandCode));
     switch (outOrIn)
     {
         case 0:
             Debug.WriteLine("COMMAND STRUCTURE");
             break;
         case 1:
             Debug.WriteLine("RESPONSE STRUCTURE");
             break;
     }
     string ss = theStruct.ToString();
     Debug.WriteLine(ss);
 }
예제 #7
0
        } // DoParmEncryption()


        /// <summary>
        /// Updates information associated by the library with TPM entity handles upon
        /// successful completion of a command that either creates a new entity or
        /// changes the properties of an existing one.
        /// 
        /// Some important data associated with TPM entities cannot be retrieved from
        /// TPM either because of their sensitivity or because of substantial overhead.
        /// The information of the former kind is an auth value (for permanent handles,
        /// transient and persistent objects, NV indices) and a bound handle (for
        /// sessions). Information tracked for the sake of performance optimization
        /// is objects and NV index name.
        /// </summary>
        /// <param name="ordinal"></param>
        /// <param name="inParms"></param>
        /// <param name="inHandles"></param>
        // ReSharper disable once UnusedParameter.Local
        private void UpdateHandleData(TpmCc ordinal, TpmStructureBase inParms, TpmHandle[] inHandles, TpmStructureBase outParms)
        {
            switch (ordinal)
            {
                case TpmCc.Create:
                {
                    var req = (Tpm2CreateRequest)inParms;
                    var resp = (Tpm2CreateResponse)outParms;
                    TpmHash priv = TpmHash.FromData(PrivHashAlg, resp.outPrivate.buffer);
                    AuthValues[priv] = Globs.CopyData(req.inSensitive.userAuth);
                    break;
                }
                case TpmCc.CreatePrimary:
                {
                    var req = (Tpm2CreatePrimaryRequest)inParms;
                    var resp = (Tpm2CreatePrimaryResponse)outParms;
                    resp.objectHandle.Auth = req.inSensitive.userAuth;
                    ProcessName(resp.objectHandle, resp.name, resp.outPublic);
                    break;
                }
                case TpmCc.Load:
                {
                    var req = (Tpm2LoadRequest)inParms;
                    var resp = (Tpm2LoadResponse)outParms;
                    TpmHash priv = TpmHash.FromData(PrivHashAlg, req.inPrivate.buffer);
                    if (AuthValues.ContainsKey(priv))
                        resp.objectHandle.Auth = AuthValues[priv];
                    ProcessName(resp.objectHandle, resp.name, req.inPublic);
                    break;
                }
                case TpmCc.LoadExternal:
                {
                    var req = (Tpm2LoadExternalRequest)inParms;
                    var resp = (Tpm2LoadExternalResponse)outParms;
                    byte[] name = req.inPublic.GetName();
                    ProcessName(resp.objectHandle, resp.name, req.inPublic);
                    break;
                }
                case TpmCc.StartAuthSession:
                {
                    var req = (Tpm2StartAuthSessionRequest)inParms;
                    var resp = (Tpm2StartAuthSessionResponse)outParms;
                    SessionParams[resp.sessionHandle] =
                            new AuthSession(req.sessionType, req.tpmKey, req.bind,
                                            req.nonceCaller, resp.nonceTPM,
                                            req.symmetric, req.authHash);
                    break;
                }
                case TpmCc.HmacStart:
                {
                    var req = (Tpm2HmacStartRequest)inParms;
                    var resp = (Tpm2HmacStartResponse)outParms;
                    resp.sequenceHandle.Auth = req.auth;
                    resp.sequenceHandle.Name = null;
                    break;
                }
                case TpmCc.NvDefineSpace:
                {
                    var req = (Tpm2NvDefineSpaceRequest)inParms;
                    req.publicInfo.nvIndex.Auth = req.auth;
                    req.publicInfo.nvIndex.Name = null;
                    break;
                }
                case TpmCc.NvChangeAuth:
                {
                    var req = (Tpm2NvChangeAuthRequest)inParms;
                    req.nvIndex.Auth = req.newAuth;
                    break;
                }
                case TpmCc.ObjectChangeAuth:
                {
                    var req = (Tpm2ObjectChangeAuthRequest)inParms;
                    var resp = (Tpm2ObjectChangeAuthResponse)outParms;
                    TpmHash priv = TpmHash.FromData(PrivHashAlg, resp.outPrivate.buffer);
                    AuthValues[priv] = Globs.CopyData(req.newAuth);
                    break;
                }
                case TpmCc.HierarchyChangeAuth:
                {
                    var req = (Tpm2HierarchyChangeAuthRequest)inParms;
                    AuthValue auth = Globs.CopyData(req.newAuth);
                    switch (req.authHandle.handle)
                    {
                        case (uint)TpmRh.Owner: OwnerAuth = auth; break;
                        case (uint)TpmRh.Endorsement: EndorsementAuth = auth; break;
                        case (uint)TpmRh.Platform: PlatformAuth = auth; break;
                        case (uint)TpmRh.Lockout: LockoutAuth = auth; break;
                    }
                    req.authHandle.Auth = auth;
                    break;
                }
                case TpmCc.PcrSetAuthValue:
                {
                    var req = (Tpm2PcrSetAuthValueRequest)inParms;
                    req.pcrHandle.Auth = req.auth;
                    if (PcrHandles == null)
                    {
                        uint numPcrs = GetProperty(this, Pt.PcrCount);
                        PcrHandles = new TpmHandle[numPcrs];
                    }
                    int pcrId = (int)req.pcrHandle.GetOffset();
                    Debug.Assert(pcrId < PcrHandles.Length);
                    PcrHandles[pcrId] = req.pcrHandle;
                    break;
                }
                case TpmCc.EvictControl:
                {
                    var req = (Tpm2EvictControlRequest)inParms;
                    var resp = (Tpm2EvictControlResponse)outParms;
                    if (req.objectHandle.GetType() != Ht.Persistent)
                    {
                        req.persistentHandle.Auth = req.objectHandle.Auth;
                        req.persistentHandle.Name = req.objectHandle.Name;
                    }
                    break;
                }
                case TpmCc.Clear:
                {
                    OwnerAuth = new AuthValue();
                    EndorsementAuth = new AuthValue();
                    LockoutAuth = new AuthValue();
                    break;
                }
                case TpmCc.NvWrite:
                {
                    var req = (Tpm2NvWriteRequest)inParms;
                    // Force name recalculation before next use
                    req.nvIndex.Name = null;
                    break;
                }
                case TpmCc.NvWriteLock:
                {
                    var req = (Tpm2NvWriteLockRequest)inParms;
                    // Force name recalculation before next use
                    req.nvIndex.Name = null;
                    break;
                }
                case TpmCc.NvReadLock:
                {
                    var req = (Tpm2NvReadLockRequest)inParms;
                    // Force name recalculation before next use
                    req.nvIndex.Name = null;
                    break;
                }
                case TpmCc.HashSequenceStart:
                {
                    var req = (Tpm2HashSequenceStartRequest)inParms;
                    var resp = (Tpm2HashSequenceStartResponse)outParms;
                    resp.sequenceHandle.Auth = req.auth;
                    break;
                }
                case TpmCc.Startup:
                {
                    var req = (Tpm2StartupRequest)inParms;
                    if (req.startupType == Su.Clear)
                    {
                        PlatformAuth = new AuthValue();
                    }
                    break;
                }
                case TpmCc.ContextSave:
                {
                    var req = (Tpm2ContextSaveRequest)inParms;
                    var resp = (Tpm2ContextSaveResponse)outParms;
                    resp.context.savedHandle.Auth = req.saveHandle.Auth;
                    resp.context.savedHandle.Name = req.saveHandle.Name;
                    break;
                }
                case TpmCc.ContextLoad:
                {
                    var req = (Tpm2ContextLoadRequest)inParms;
                    var resp = (Tpm2ContextLoadResponse)outParms;
                    resp.loadedHandle.Auth = req.context.savedHandle.Auth;
                    resp.loadedHandle.Name = req.context.savedHandle.Name;
                    break;
                }
                case TpmCc.NvUndefineSpaceSpecial:
                {
                    var req = (Tpm2NvUndefineSpaceSpecialRequest)inParms;
                    req.nvIndex.Auth = null;
                    break;
                }
            }
        } // UpdateHandleData()
예제 #8
0
        /// <summary>
        /// Handles TPM response value.
        /// Converts the error code into a human-readable form, invokes callbacks and
        /// encapsulates error info into a .Net exception.
        /// </summary>
        /// <param name="responseTag"></param>
        /// <param name="responseParamSize"></param>
        /// <param name="resultCode"></param>
        /// <param name="inParms"></param>
        /// <returns></returns>
        // ReSharper disable once UnusedParameter.Local
        private bool ProcessError(TpmSt responseTag, uint responseParamSize,
                                  TpmRc resultCode, TpmStructureBase inParms)
        {
            string errorString;

            AssertExpectedResponsesValid();

            // Process TPM success case (both expected success, and unexpected success)
            if (resultCode == TpmRc.Success)
            {
                LastError = TpmRc.Success;
                if (IsSuccessExpected())
                {
                    return true;
                }
                // Else we have unexpectedly succeeded

                // If TolerateErrors is set, then no error indication is provided apart
                // from setting LastReponseCode (the caller must query to find that
                // the error does not match).
                if (TolerateErrors)
                {
                    return false;
                }
                // If there is an installed error handler invoke it.
                if (TheErrorHandler != null)
                {
                    TheErrorHandler(resultCode, ExpectedResponses);
                    return false;
                }
                // ReSharper disable once ConvertIfStatementToConditionalTernaryExpression
                if (ExpectedResponses.Length == 1)
                {
                    errorString = string.Format("Error {0} was expected but command {1} succeeded",
                                                ExpectedResponses[0],
                                                CurrentCommand);
                }
                else
                {
                    errorString = string.Format("Errors {{{0}}} were expected but command {1} succeeded",
                                                string.Join(", ", ExpectedResponses),
                                                CurrentCommand);
                }

                _ClearCommandContext();
                throw new TssException(errorString);
            }
            // Else we have an error
            if (responseTag != TpmSt.NoSessions)
            {
                throw new Exception("Ill-formed responseTag (not NoSessions)");
            }
            if (responseParamSize != 10)
            {
                throw new Exception("Ill-formed reponseParamSize (not 10)");
            }

            // There are two encodings for errors - format 0 and format 1.
            var resultCodeValue = (uint)resultCode;
            bool formatOneErrorType = TpmErrorHelpers.IsFmt1(resultCode);

            // Extract the actual error number
            LastError = TpmErrorHelpers.ErrorNumber(resultCode);

            string errorEntity = "Unknown";
            uint errorEntityIndex = 0;
            string errorParmName = "Unknown";
            if (formatOneErrorType)
            {
                errorEntityIndex = (resultCodeValue & 0xF00U) >> 8;
                if ((resultCodeValue & 0x40) != 0)
                {
                    errorEntity = "Parameter";
                    errorParmName = GetParmName(inParms.GetType(), errorEntityIndex);
                }
                else
                {
                    if (errorEntityIndex >= 8)
                    {
                        errorEntityIndex -= 8;
                        errorEntity = "Session";
                    }
                    else
                    {
                        errorEntity = "Handle";
                    }
                }
            }
            string errorDetails = FormatString("\r\n" +
                                               "Details: \n" +
                                               "[Code=TpmRc.{0}],"+
                                               "[RawCode=0x{1:X},{1}]\n" +
                                               "[ErrorEntity={2}], [ParmNum={3}]\n" +
                                               "[ParmName={4}]",
                                               new Object[] {
                                                   LastError.ToString(), 
                                                   resultCodeValue,
                                                   errorEntity,
                                                   errorEntityIndex,
                                                   errorParmName
                                               });
            // We have found out all we can about the error.  Now process it according to the tpm context

            // AllowErrors() specifies that errors should be handled silently
            if ((OuterCommand == TpmCc.None && IsErrorAllowed(LastError)) ||
                (OuterCommand != TpmCc.None && LastError == TpmRc.Canceled))
            {
                return false;
            }

            if (OuterCommand != TpmCc.None || ExpectedResponses == null)
            {
                errorString = string.Format("Error {{{0}}} was returned for command {1}.",
                                            LastError, CurrentCommand);
            }
            else
            {
                errorString = string.Format("Error {{{0}}} was returned instead of {{{1}}} for command {2}.",
                                            LastError,
                                            string.Join(", ", ExpectedResponses),
                                            CurrentCommand);
            }

            if (AreErrorsExpected())
            {
                // We have a mismatched error. If a warning handler is installed, call it.
                if (TheWarningHandler != null)
                {
                    TheWarningHandler(errorString);
                    _ClearCommandContext();
                    return false;
                }
            }

            // Otherwise propagate the unexpected error as an exception
            _ClearCommandContext();
            errorString += errorDetails;
            throw new TpmException(resultCode, errorString);
        }
예제 #9
0
        /// <summary>
        /// DispatchMethod is called by auto-generated command action code. It assembles a byte[] containing
        /// the formatted TPM command based on the params passed in explicitly, and the sessions currently attached
        /// to the TPM object.  It processes the TPM response and converts it into an instantiation of the 
        /// requested object.
        /// </summary>
        /// <param name="ordinal"></param>
        /// <param name="inParms"></param>
        /// <param name="expectedResponseType"></param>
        /// <param name="outParms"></param>
        /// <param name="numInHandlesNotUsed"></param>
        /// <param name="numOutHandlesNotUsed"></param>
        /// <returns></returns>
        internal bool DispatchMethod(
            TpmCc ordinal,
            TpmStructureBase inParms,
            Type expectedResponseType,
            out TpmStructureBase outParms,
            int numInHandlesNotUsed,
            int numOutHandlesNotUsed)
        {
            outParms = null;
            // todo - ClearCommandContext should be moved to the front of this
            // routine (and we should make local copies of the context-values we depend upon)
            // There are uncaught exceptions that can be generated that would skip
            // ClearCOmmandCOntext and leave the Tpm2 with some leftover state.

            byte[] response;

            if (CurrentCommand != TpmCc.None)
            {
                OuterCommand = CurrentCommand;
            }
            CurrentCommand = ordinal;

            // The AlternateActionCallback allows alternate processing (or filtering/data
            // collection on the executing command stream.
            if (TheAlternateActionCallback != null)
            {
                bool desiredSuccessCode;
                bool alternate = TheAlternateActionCallback(ordinal,
                                                            inParms,
                                                            expectedResponseType,
                                                            out outParms,
                                                            out desiredSuccessCode);
                if (alternate)
                {
                    _ClearCommandContext();
                    return desiredSuccessCode;
                }
            }

            CommandInfo commandInfo = CommandInfoFromCommandCode(ordinal);
            byte[] parms;
            TpmHandle[] inHandles;

            try
            {
                // Get the handles and the parameters from the command input structure
                CommandProcessor.Fragment(inParms, commandInfo.HandleCountIn, out inHandles, out parms);

                // Start processing sessions
                PrepareRequestSessions(commandInfo, inHandles);
            }
            catch (Exception e)
            {
                Debug.Assert(outParms == null);
                if (e is TpmException)
                {
                    if (IsErrorAllowed(((TpmException)e).RawResponse))
                    {
                        outParms = (TpmStructureBase)Activator.CreateInstance(expectedResponseType);
                    }
                }
                _ClearCommandPrelaunchContext();
                _ClearCommandContext();
                if (outParms != null)
                {
                    return false;
                }
                throw;
            }

            // The caller can install observer/modifier callbacks, and request repeated
            // execution of the same command.
            bool repeat = false;
            byte[] parmsCopy = null;

            if (TheCmdParamsCallback != null)
            {
                parmsCopy = Globs.CopyData(parms);
            }

            // Response atoms
            TpmSt responseTag;
            TpmRc resultCode;
            uint responseParamSize;
            byte[] outParmsNoHandles, outParmsWithHandles;
            TpmHandle[] outHandles;
            SessionOut[] outSessions;

            // In normal processing there is just one pass through this do-while loop
            // If command observation/modification callbacks are installed, then the
            // caller repeats the command as long as necessary.
            bool invokeCallbacks = OuterCommand == TpmCc.None && !CpHashMode && !DoNotDispatchCommand;
            do try
            {
                if (TheCmdParamsCallback != null && invokeCallbacks)
                {
                    parms = Globs.CopyData(parmsCopy);
                    TheCmdParamsCallback(commandInfo, ref parms, inHandles);
                }

                // If there are any encrypting sessions then next we encrypt the data in place
                parms = DoParmEncryption(parms, commandInfo, 0, Direction.Command);

                // Now do the HMAC (note that the handles are needed for name-replacement)
                SessionIn[] inSessions = CreateRequestSessions(parms, inHandles);

                // CpHashMode is enabled for a single command through tpm.GetCpHash().TpmCommand(...)
                if (OuterCommand == TpmCc.None && CpHashMode)
                {
                    CommandParmHash.HashData = GetCommandHash(CommandParmHash.HashAlg, parms, inHandles);
                    outParms = (TpmStructureBase)Activator.CreateInstance(expectedResponseType);
                    CpHashMode = false;
                    _ClearCommandContext();
                    return true;
                }

                // Create the command buffer
                byte[] command = CommandProcessor.CreateCommand(ordinal, inHandles, inSessions, parms);

                // And dispatch the command
                Log(ordinal, inParms, 0);

                if (DoNotDispatchCommand)
                {
                    CommandBytes = command;
                    outParms = (TpmStructureBase)Activator.CreateInstance(expectedResponseType);
                    DoNotDispatchCommand = false;
                    _ClearCommandContext();
                    return true;
                }

                if (TheCmdBufCallback != null && invokeCallbacks)
                {
                    TheCmdBufCallback(ref command);
                }

                // And actually dispatch the command into the underlying device
                DateTime commandSentTime, responseReceivedTime;
                int nvRateRecoveryCount = 0;

                // No more than 4 retries on NV_RATE error
                for (;;)
                {
                    responseReceivedTime = commandSentTime = DateTime.Now;

                    if (!TestCycleNv)
                    {
                        commandSentTime = DateTime.Now;
                        Device.DispatchCommand(ActiveModifiers, command, out response);
                        responseReceivedTime = DateTime.Now;
                    }
                    else
                    {
                        // In TestCycleNv we submit the command with NV not-available.  If the TPM indicates that
                        // NV is not available we re-submit.
                        try
                        {
                            // Once with NV off
                            Device.SignalNvOff();
                            Device.DispatchCommand(ActiveModifiers, command, out response);
                            Device.SignalNvOn();
                            // And if it did not work, try again with NV on
                            TpmRc respCode = CommandProcessor.GetResponseCode(response);
                            if ((uint)respCode == 0x923U || respCode == TpmRc.Lockout)
                            {
                                Device.DispatchCommand(ActiveModifiers, command, out response);
                            }

                        }
                        catch (Exception)
                        {
                            Device.SignalNvOn();
                            throw;
                        }
                    }

                    // Convert the byte[] response into its constituent parts.
                    CommandProcessor.SplitResponse(response,
                                                   commandInfo.HandleCountOut,
                                                   out responseTag,
                                                   out responseParamSize,
                                                   out resultCode,
                                                   out outHandles,
                                                   out outSessions,
                                                   out outParmsNoHandles,
                                                   out outParmsWithHandles);

                    if (resultCode != TpmRc.NvRate || ++nvRateRecoveryCount > 4)
                    {
                        break;
                    }
                    //Console.WriteLine(">>>> NV_RATE: Retrying... Attempt {0}", nvRateRecoveryCount);
                    Thread.Sleep((int)Tpm2.GetProperty(this, Pt.NvWriteRecovery) + 100);
                }

                // Invoke the trace callback if installed        
                if (TheTraceCallback != null)
                {
                    TheTraceCallback(command, response);
                }

                // Collect basic statistics on command execution
                if (TheCmdStatsCallback != null && invokeCallbacks)
                {
                    repeat = TheCmdStatsCallback(ordinal, GetBaseErrorCode(resultCode),
                                        (responseReceivedTime - commandSentTime).TotalSeconds);
                }

                if (repeat && resultCode == TpmRc.Success)
                {
                    // Update session state
                    ProcessResponseSessions(outSessions);
                    int offset = (int)commandInfo.HandleCountOut * 4;
                    outParmsWithHandles = DoParmEncryption(outParmsWithHandles, commandInfo, offset, Direction.Response);
                    var m = new Marshaller(outParmsWithHandles);
                    outParms = (TpmStructureBase)m.Get(expectedResponseType, "");
#if false
                    m = new Marshaller(command);
                    TpmSt tag = m.Get<TpmSt>();
                    uint cmdSize = m.Get<uint>();
                    TpmCc actualCmd = m.Get<TpmCc>();
                    var actualHandles = new TpmHandle[inHandles.Length];
                    for (int i = 0; i < inHandles.Length; ++i)
                    {
                        actualHandles[i] = m.Get<TpmHandle>();
                    }
                    for (int i = 0; i < inSessions.Length; ++i)
                    {
                        m.Get<SessionIn>();
                    }
                    var actualParms = m.GetArray<byte>(m.GetValidLength() - m.GetGetPos());
                    if (m.GetValidLength() != cmdSize)
                    {
                        throw new Exception("Command length in header does not match input byte-stream");
                    }
#endif
                    CommandHeader actualHeader;
                    TpmHandle[] actualHandles;
                    SessionIn[] actualSessions;
                    byte[] actualParmsBuf;
                    CommandProcessor.CrackCommand(command, out actualHeader, out actualHandles, out actualSessions, out actualParmsBuf);
                    m = new Marshaller();
                    foreach (TpmHandle h in actualHandles)
                    {
                        m.Put(h, "handle");
                    }
                    m.Put(actualParmsBuf, "parms");
                    var actualParms = (TpmStructureBase)Activator.CreateInstance(inParms.GetType());
                    actualParms.ToHost(m);
                    UpdateHandleData(actualHeader.CommandCode, actualParms, actualHandles, outParms);
                    //ValidateResponseSessions(outHandles, outSessions, ordinal, resultCode, outParmsNoHandles);

                    foreach (var h in outHandles)
                    {
                        CancelSafeFlushContext(h);
                    }
                } // if (repeat && resultCode == TpmRc.Success)
            }
            catch (Exception)
            {
                _ClearCommandPrelaunchContext();
                _ClearCommandContext();
                throw;
            }
            while (repeat);

            // Update the audit session if needed
            if (AuditThisCommand)
            {
                AuditThisCommand = false;
                if (CommandAuditHash == null)
                    throw new Exception("No audit hash set for this command stream");
                byte[] parmHash = GetCommandHash(CommandAuditHash.HashAlg, parms, inHandles);
                byte[] expectedResponseHash = GetExpectedResponseHash(CommandAuditHash.HashAlg,
                                                                      outParmsNoHandles,
                                                                      ordinal,
                                                                      resultCode);
                CommandAuditHash.Extend(Globs.Concatenate(parmHash, expectedResponseHash));
            }

            // FlushContest that may be executed as part of _ClearCommandPrelaunchContext()
            // must be executed before any command-related info is updated.
            _ClearCommandPrelaunchContext();

            // Process errors if there are any
            bool commandSucceeded = ProcessError(responseTag, responseParamSize, resultCode, inParms);
            try
            {
                if (commandSucceeded)
                {
                    ProcessResponseSessions(outSessions);
                    int offset = (int)commandInfo.HandleCountOut * 4;
                    outParmsWithHandles = DoParmEncryption(outParmsWithHandles, commandInfo, offset, Direction.Response);

                    var mt = new Marshaller(outParmsWithHandles);
                    outParms = (TpmStructureBase)mt.Get(expectedResponseType, "");
                    if (TheParamsTraceCallback != null)
                    {
                        TheParamsTraceCallback(ordinal, inParms, outParms);
                    }

                    UpdateHandleData(ordinal, inParms, inHandles, outParms);
                    ValidateResponseSessions(outHandles, outSessions, ordinal, resultCode, outParmsNoHandles);

                    foreach (var s in Sessions) if (s is AuthSession)
                    {
                        var sess = s as AuthSession;
                        if (sess.Attrs.HasFlag(SessionAttr.Audit) && !TpmHandle.IsNull(sess.BindObject))
                        {
                            sess.BindObject = TpmRh.Null;
                            break; // only one audit session is expected
                        }
                    }
                }
                else
                {
                    outParms = (TpmStructureBase)Activator.CreateInstance(expectedResponseType);
                }
            }
            finally
            {
                // Check in case an exception happened before outParms was initialized
                // ReSharper disable once CSharpWarnings::CS0183
                if (outParms is TpmStructureBase)
                {
                    Log(ordinal, outParms, 1);
                }
                // Clear all per-invocation state (e.g. sessions, errors expected) ready for next command
                _ClearCommandContext();
            }
            return commandSucceeded;
        }