public TpmException(TpmRc rawResponse, string errorDescription, TpmStructureBase cmdParms) : base(errorDescription) { ErrorString = TpmErrorHelpers.ErrorNumber(rawResponse).ToString(); RawResponse = rawResponse; CmdParms = cmdParms; }
public override void DispatchCommand(CommandModifier active, byte[] inBuf, out byte[] outBuf) { if (TbsHandle == UIntPtr.Zero) { throw new Exception("TBS context not created."); } var resultBuf = new byte[4096]; uint resultByteCount = (uint)resultBuf.Length; TpmRc result = TpmRc.Success; TbsWrapper.TBS_RESULT tbsRes = TbsWrapper.NativeMethods. Tbsip_Submit_Command(TbsHandle, (TbsWrapper.TBS_COMMAND_LOCALITY)active.ActiveLocality, active.ActivePriority, inBuf, (uint)inBuf.Length, resultBuf, ref resultByteCount); string errMsg; if (tbsRes == TbsWrapper.TBS_RESULT.SUCCESS) { if (resultByteCount != 0) { outBuf = new byte[resultByteCount]; Array.Copy(resultBuf, outBuf, (int)resultByteCount); return; } result = TpmRc.TbsUnknownError; errMsg = Globs.GetResourceString("SubmitError2"); } else { errMsg = new Win32Exception((int)result).Message; } outBuf = TpmErrorHelpers.BuildErrorResponseBuffer(result); } // TbsDevice.DispatchCommand
/// <summary> /// Dispatch a command to the underlying TPM. This method implements all /// significant functionality. It examines the command stream and performs /// (approximately) the following actions: /// 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 cc = commandHeader.CommandCode; // Lookup command CommandInfo command = Tpm2.CommandInfoFromCommandCode(cc); if (command == null) { throw new Exception("Unrecognized command"); } if (cc == TpmCc.ContextLoad || cc == TpmCc.ContextSave) { Debug.WriteLine("ContextLoad and ContextSave are not supported in this build"); 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 false // LibTester may intentionally use invalid handles, therefore it always // work in the passthru mode (all correctness checks by TSS infra suppressed) if (!Tpm2._TssBehavior.Passthrough && (neededObjects == null || neededSessions == null)) #endif if (neededObjects == null || neededSessions == null) { // 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. var expectedResponses = Tpm._GetExpectedResponses(); if (!LoadEntities(neededEntities)) { throw new Exception("Failed to make space for objects or sessions"); } else { // 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); } // Re-create the command using translated object and session handles byte[] commandBuf = CommandProcessor.CreateCommand(commandHeader.CommandCode, inHandles, inSessions, commandParmsNoHandles); if (!Tpm2._TssBehavior.Passthrough) { Debug.Assert(commandBuf.Length == inBuf.Length); } byte[] responseBuf; // TODO: Virtualize TPM2_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. // ulong firstCtxSeqNum = 0; while (true) { Tpm._ExpectResponses(expectedResponses); TpmDevice.DispatchCommand(active, commandBuf, out responseBuf); TpmRc res = GetResultCode(responseBuf); if (res == TpmRc.Success || expectedResponses != null && expectedResponses.Contains(res)) { break; } if (res == TpmRc.ContextGap) { ulong seqNum = ShortenSessionContextGap(firstCtxSeqNum); if (seqNum == 0) { break; // Failed to handle CONTEXT_GAP error } if (firstCtxSeqNum == 0) { firstCtxSeqNum = seqNum; } //if (firstCtxSeqNum != 0) // Console.WriteLine("DispatchCommand: CONTEXT_GAP handled"); continue; } 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; } if (!MakeSpace(slotType, neededEntities)) { // Failed to make an object slot in the TPM responseBuf = TpmErrorHelpers.BuildErrorResponseBuffer(TpmRc.Memory); break; } } // Parse the response from the TPM 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); // In case of 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); outBuf = CommandProcessor.CreateResponse(resultCode, responseHandles, responseSessions, responseParmsNoHandles); Debug.Assert(outBuf.Length == responseBuf.Length); } // lock(this) }
public TpmException(TpmRc rawResponse, string errorDescription) : base(errorDescription) { ErrorString = TpmErrorHelpers.ErrorNumber(rawResponse).ToString(); RawResponse = rawResponse; }