/// <summary> /// 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). /// </summary> /// <param name="caller"></param> /// <param name="active"></param> /// <param name="inBuf"></param> /// <param name="outBuf"></param> /// <exception cref="Exception"></exception> 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) }
public override void DispatchCommand(CommandModifier active, byte[] inBuf, out byte[] outBuf) { Tbs.DispatchCommand(this, active, inBuf, out outBuf); }
/// <summary> /// Send TPM-command buffer to device /// </summary> /// <param name="active">Locality and priority</param> /// <param name="inBuf">command buffer</param> /// <param name="outBuf">response buffer</param> public virtual void DispatchCommand(CommandModifier active, byte[] inBuf, out byte[] outBuf) { outBuf = new byte[4]; throw new Exception("Should never be here"); }