Tpm2Lib.Tbs.DispatchCommand C# (CSharp) Method

DispatchCommand() private method

Dispatch a command to the underlying TPM. This method implements all significant functionality. DispatchCommand examines the command stream and performs (approximately) the following functions 1) If the command references a handle (session or transient object) then TBS makes sure that the entity is loaded. If it is, then the handle is "translated" to the underlying TPM handle. If it is not, then TBS checks to see if it has a saved context for the entity, and if so loads it. 2) If the command will fill a slot, then TBS ensures that a slot is available. It does this by ContextSaving the LRU entity of the proper type (that is not used in this command).
private DispatchCommand ( TbsContext caller, Tpm2Lib.CommandModifier active, byte inBuf, byte &outBuf ) : void
caller TbsContext
active Tpm2Lib.CommandModifier
inBuf byte
outBuf byte
return void
        internal void DispatchCommand(TbsContext caller, CommandModifier active, byte[] inBuf, out byte[] outBuf)
        {
            lock (this)
            {
                CommandNumber++;
                // ReSharper disable once CompareOfFloatsByEqualityOperator
                if (StateSaveProbability != 0.0)
                {
                    // S3 debug support
                    DebugStateSave();
                    LastStateSaveCommandNumber = CommandNumber;
                }

                CommandHeader commandHeader;
                TpmHandle[] inHandles;
                SessionIn[] inSessions;
                byte[] commandParmsNoHandles;
                bool legalCommand = CommandProcessor.CrackCommand(inBuf, out commandHeader, out inHandles, out inSessions, out commandParmsNoHandles);

                if (!legalCommand)
                {
                    // Is a diagnostics command.  Pass through to TPM (a real RM would refuse).
                    TpmDevice.DispatchCommand(active, inBuf, out outBuf);
                    return;
                }

                TpmCc commandCode = commandHeader.CommandCode;

                // Lookup command
                CommandInfo command = Tpm2.CommandInfoFromCommandCode(commandCode);
                if (command == null)
                {
                    throw new Exception("Unrecognized command");
                }

                if (commandCode == TpmCc.ContextLoad || commandCode == TpmCc.ContextSave)
                {
                    //throw new Exception("ContextLoad and ContextSave not supported in this build");
#if !NETFX_CORE
                    Console.Error.WriteLine("ContextLoad and ContextSave not supported in this build");
#endif
                    outBuf = Marshaller.GetTpmRepresentation(new Object[] {
                        TpmSt.NoSessions,
                        (uint)10,
                        TpmRc.NotUsed });
                }

                // Look up referenced objects and sessions
                ObjectContext[] neededObjects = GetReferencedObjects(caller, inHandles);
                ObjectContext[] neededSessions = GetSessions(caller, inSessions);
                ObjectContext[] neededEntities =
                        neededObjects != null
                            ? neededSessions != null
                                ? neededObjects.Concat(neededSessions).ToArray()
                                : neededObjects
                            : neededSessions;
                if (neededObjects == null || neededSessions == null)
                {
                    // This means that one or more of the handles was not registered for the context
                    byte[] ret = FormatError(TpmRc.Handle);
                    outBuf = ret;
                    return;
                }

                // Load referenced objects and sessions (free slots if needed)
                // It's important to load all object and session handles in a single call
                // to LoadEntities(), as for some commands (e.g. GetSessionAuditDigest)
                // the objects array may contain session handles. In this case the session
                // handles loaded by the invocation of LoadEntities for neededObjects
                // may be evicted again during the subsequent call for neededSessions.
                bool loadOk = LoadEntities(neededEntities);
                if (!loadOk)
                {
                    throw new Exception("Failed to make space for objects or sessions at to execute command");
                }

                // At this point everything referenced should be loaded, and there will be a free slot if needed
                // so we can translate the input handles to the underlying handles 
                ReplaceHandlesIn(inHandles, inSessions, neededObjects, neededSessions);

                // create the translated command from the various components we have been manipulating
                byte[] commandBuf = CommandProcessor.CreateCommand(commandHeader.CommandCode, inHandles, inSessions, commandParmsNoHandles);
                Debug.Assert(commandBuf.Length == inBuf.Length);

                byte[] responseBuf;
                
                // Todo: Virtualize GetCapability for handle enumeration.

                //
                // Execute command on underlying TPM device.
                // If we get an ObjectMemory or SessionMemory error we try to make more space and try again
                // Note: If the TPM device throws an error above we let it propagate out.  There should be no side 
                // effects on TPM state that the TBS cares about.
                //
                do
                {
                    TpmDevice.DispatchCommand(active, commandBuf, out responseBuf);
                    TpmRc res = GetResultCode(responseBuf);
                    if (res == TpmRc.Success)
                    {
                        break;
                    }

                    var slotType = SlotType.NoSlot;
                    if (res == TpmRc.ObjectHandles || res == TpmRc.ObjectMemory)
                    {
                        slotType = SlotType.ObjectSlot;
                    }
                    else if (res == TpmRc.SessionHandles || res == TpmRc.SessionMemory)
                    {
                        slotType = SlotType.SessionSlot;
                    }
                    else
                    {
                        // Command failure not related to resources
                        break;
                    }
                    bool slotMade = MakeSpace(slotType, neededEntities);
                    if (!slotMade)
                    {
                        throw new Exception("Failed to make an object slot in the TPM");
                    }
                } while (true);

                // Parse the response from the TPM
                // TODO: Make this use the new methods in Tpm2

                // ReSharper disable once UnusedVariable
                var mOut = new Marshaller(responseBuf);
                TpmSt responseTag;
                uint responseParamSize;
                TpmRc resultCode;
                TpmHandle[] responseHandles;
                SessionOut[] responseSessions;
                byte[] responseParmsNoHandles, responseParmsWithHandles;

                CommandProcessor.SplitResponse(responseBuf,
                                               command.HandleCountOut,
                                               out responseTag,
                                               out responseParamSize,
                                               out resultCode,
                                               out responseHandles,
                                               out responseSessions,
                                               out responseParmsNoHandles,
                                               out responseParmsWithHandles);

                // If we have an error there is no impact on the loaded sessions, but we update
                // the LRU values because the user will likely try again.
                if (resultCode != TpmRc.Success)
                {
                    outBuf = responseBuf;
                    UpdateLastUseCount(new[] {neededObjects, neededSessions});
                    return;
                }

                // Update TBS database with any newly created TPM objects
                ProcessUpdatedTpmState(caller, command, responseHandles, neededObjects);

                // And if there were any newly created objects use the new DB entries to translate the handles
                ReplaceHandlesOut(responseHandles);
                byte[] translatedResponse = CommandProcessor.CreateResponse(resultCode, responseHandles, responseSessions, responseParmsNoHandles);

                outBuf = translatedResponse;
                Debug.Assert(outBuf.Length == responseBuf.Length);
            } // lock(this)
        }

Usage Example

Exemplo n.º 1
0
 public override void DispatchCommand(CommandModifier active, byte[] inBuf, out byte[] outBuf)
 {
     Tbs.DispatchCommand(this, active, inBuf, out outBuf);
 }