internal override TpmHash GetPolicyDigest(TpmAlgId hashAlg) { TpmCc commandCode = 0; if (TicketType == TpmSt.AuthSecret) { commandCode = TpmCc.PolicySecret; } else if (TicketType == TpmSt.AuthSigned) { commandCode = TpmCc.PolicySigned; } else { Globs.Throw <ArgumentException>("Ticket type is not recognized"); return(new TpmHash(hashAlg)); } if (ObjectName == null) { ObjectName = AuthorizingKey.GetName(); } var m = new Marshaller(); m.Put(commandCode, "ordinal"); m.Put(ObjectName, "name"); return(GetNextAcePolicyDigest(hashAlg).Extend(m.GetBytes()).Extend(PolicyRef)); }
private void LogTestAttributes(TpmSt sessionTag, TpmCc command) { if (!TestCategorizer.CommandDefined(command)) { return; } if (sessionTag.Equals(TpmSt.Null)) { TestIsThreadSafe = false; TestWithinMinTpmProfile = false; return; } bool threadSafe = TestCategorizer.GetThreadSafety(command); if (!threadSafe) { TestIsThreadSafe = false; } if (!TestCategorizer.InProfile0(command)) { TestWithinMinTpmProfile = false; return; } // else is P0 command. What privileges are needed? NecessaryPrivilege priv = TestCategorizer.GetNecessaryPrivileges(command); if (priv > MaximumPrivilege) { MaximumPrivilege = priv; } }
private void LogCommandExecution(TpmCc cc, TpmRc rc, TimeSpan executionTime) { NumCommands++; if (!KnownCommandCodes.Contains(cc.ToString())) { cc = TpmCc.None; } if (!CmdStats.ContainsKey(cc)) { CmdStats.Add(cc, new CommandStats()); } CommandStats stat = CmdStats[cc]; if (rc == TpmRc.Success) { stat.NumSuccess++; stat.SuccessExecutionTime += executionTime; } else { stat.NumFailures++; stat.FailureExecutionTime += executionTime; if (!stat.FailureResponses.Contains(rc)) { stat.FailureResponses.Add(rc); } } // No need to update stat.CallerTests here. Current test will be logged // in the command execution statistics in the TestCompleted() notification. }
internal MinTpmNecessaryPrivileges(TpmCc code, bool admin, bool stdUser, bool OkInLockout) { CommandCode = code; AdminAccessible = admin; StandardUserAccessible = stdUser; AllowedInLockout = OkInLockout; }
/// <summary> /// Implements the first step of the policy digest update (see the PolicyUpdate() /// method), and also used by PolicyAuthorizeNV. /// </summary> internal TpmHash PolicyUpdate1(TpmHash currentHash, TpmCc commandCode, byte[] name) { var m = new Marshaller(); m.Put(commandCode, "commandCode"); m.Put(name, "name"); return(currentHash.Extend(m.GetBytes())); }
// Return true if the command available for MinTpm internal static bool CommandDefinedForMinTpm(TpmCc command) { foreach (MinTpmNecessaryPrivileges c in NecessaryPrivileges) { if (c.CommandCode.Equals(command) == true) { return(true); } } return(false); }
private void Decode_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e) { TpmCc commandCode; Output.Text = CommandProcessor.ParseCommand(CommandStream.Text, out commandCode); if (m_DecodedCommandCode != commandCode && commandCode != TpmCc.None) { m_DecodedCommandCode = commandCode; } }
// Get expected privileges to execute command internal static NecessaryPrivilege GetNecessaryPrivileges(TpmCc code) { MinTpmNecessaryPrivileges priv = Privileges[code]; if (priv.StandardUserAccessible) { return(NecessaryPrivilege.User); } if (priv.AdminAccessible) { return(NecessaryPrivilege.Admin); } return(NecessaryPrivilege.Special); }
/// <summary> /// Check if this TPM implements the given command. /// The method sends the GetCapability command the first time it is called, /// and reuses its results during subsequent invocations. /// </summary> /// <param name="commandCode">The command code to check.</param> /// <returns>true if the given command is supported by this TPM instance.</returns> public bool IsImplemented(TpmCc commandCode) { if (ImplementedCommands == null || ImplementedCommands.Length == 0) { ICapabilitiesUnion caps; uint totalCommands = Tpm2.GetProperty(Tpm, Pt.TotalCommands); Tpm.GetCapability(Cap.Commands, (uint)TpmCc.First, totalCommands, out caps); ImplementedCommands = Globs.ConvertAll((caps as CcaArray).commandAttributes, cmdAttr => (TpmCc)(cmdAttr & CcAttr.commandIndexBitMask)) .ToArray(); Debug.Assert(ImplementedCommands.Length != 0); } return(ImplementedCommands.Contains(commandCode)); }
private void ValidateHandleUsage(TpmCc command, byte[] inBuf) { CommandInfo commInfo = Tpm2.CommandInfoFromCommandCode(command); if (commInfo.HandleCountIn == 0) { return; } // else see if any of the inHandles are TpmRh.Platform CrackedCommand cc = CommandProcessor.CrackCommand(inBuf); TpmHandle[] handles = cc.Handles; foreach (TpmHandle h in handles) { if (h == TpmRh.Platform) { TestUsesPlatformAuth = true; } } }
/// <summary> /// Populates the page with content passed during navigation. Any saved state is also /// provided when recreating a page from a prior session. /// </summary> /// <param name="sender"> /// The source of the event; typically <see cref="NavigationHelper"/>. /// </param> /// <param name="e">Event data that provides both the navigation parameter passed to /// <see cref="Frame.Navigate(Type, Object)"/> when this page was initially requested and /// a dictionary of state preserved by this page during an earlier /// session. The state will be null the first time a page is visited.</param> private void LoadState(object sender, LoadStateEventArgs e) { if (SuspensionManager.SessionState.ContainsKey(m_SettingDecodedCommandCode)) { int index; if (Int32.TryParse((string)SuspensionManager.SessionState[m_SettingDecodedCommandCode], out index)) { m_DecodedCommandCode = (TpmCc)index; } } if (SuspensionManager.SessionState.ContainsKey(m_SettingCommandStream)) { CommandStream.Text = (string)SuspensionManager.SessionState[m_SettingCommandStream]; } if (SuspensionManager.SessionState.ContainsKey(m_SettingDecodedCommand)) { Output.Text = (string)SuspensionManager.SessionState[m_SettingDecodedCommand]; } }
public CommandHeader(CommandHeader the_CommandHeader) { if((Object) the_CommandHeader == null ) throw new ArgumentException(Globs.GetResourceString("parmError")); Tag = the_CommandHeader.Tag; CommandSize = the_CommandHeader.CommandSize; CommandCode = the_CommandHeader.CommandCode; }
} // 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()
///<param name = "the_auth">TPM_RH_PLATFORM+PP Auth Index: 1 Auth Role: USER + Physical Presence</param> ///<param name = "the_setList">list of commands to be added to those that will require that Physical Presence be asserted</param> ///<param name = "the_clearList">list of commands that will no longer require that Physical Presence be asserted</param> public Tpm2PpCommandsRequest( TpmHandle the_auth, TpmCc[] the_setList, TpmCc[] the_clearList ) { this.auth = the_auth; this.setList = the_setList; this.clearList = the_clearList; }
/// <summary> /// Check if this TPM implements the given command. /// The method sends the GetCapability command the first time it is called, /// and reuses its results during subsequent invocations. /// </summary> /// <param name="commandCode">The command code to check.</param> /// <returns>true if the given command is supported by this TPM instance.</returns> public bool IsImplemented(TpmCc commandCode) { return(true); }
// Determines whether the command is in the minimal (MinTPM) profile internal static bool InProfile0(TpmCc code) { return(Privileges.ContainsKey(code)); }
public void PolicyCommandCode( TpmHandle policySession, TpmCc code ) { Tpm2PolicyCommandCodeRequest inS = new Tpm2PolicyCommandCodeRequest(); inS.policySession = policySession; inS.code = code; TpmStructureBase outSBase; DispatchMethod(TpmCc.PolicyCommandCode, (TpmStructureBase) inS, typeof(Tpm2PolicyCommandCodeResponse), out outSBase, 1, 0); }
///<param name = "the_commandCodes">a list of command codes The maximum only applies to a command code list in a command. The response size is limited only by the size of the parameter buffer.</param> public CcArray( TpmCc[] the_commandCodes ) { this.commandCodes = the_commandCodes; }
/// <summary> /// Clear per-invocation state like tpm._ExpectError() /// </summary> private void _ClearCommandContext() { if (OuterCommand != TpmCc.None) { CurrentCommand = OuterCommand; OuterCommand = TpmCc.None; return; } _LastCommand = CurrentCommand; CurrentCommand = TpmCc.None; ExpectedResponses = null; Sessions = new SessionBase[0]; DecSession = null; EncSession = null; NonceTpmDec = null; NonceTpmEnc = null; if (TolerateErrorsPermanently <= 0) { TolerateErrors = false; } }
/// <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; }
// TODO: add NumAuthHandles and USER/ADMIN auth requirements public CommandInfo( TpmCc theCode, uint inHandleCount, uint outHandleCount, uint inAuthHandleCount, Type inStructType, Type outStructType, uint parmCryptInfo, string origInputHandleTypes) { CommandCode = theCode; HandleCountIn = inHandleCount; HandleCountOut = outHandleCount; AuthHandleCountIn = inAuthHandleCount; InStructType = inStructType; OutStructType = outStructType; TheParmCryptInfo = (ParmCryptInfo)parmCryptInfo; InHandleOrigTypes = origInputHandleTypes; }
/// <summary> /// Create a TPM command byte stream from constituent components /// </summary> /// <param name="commandCode"></param> /// <param name="handles"></param> /// <param name="sessions"></param> /// <param name="parmsWithoutHandles"></param> /// <returns></returns> public static byte[] CreateCommand( TpmCc commandCode, TpmHandle[] handles, SessionIn[] sessions, byte[] parmsWithoutHandles) { // ReSharper disable once UnusedVariable CommandInfo commandInfo = Tpm2.CommandInfoFromCommandCode(commandCode); var m = new Marshaller(); TpmSt tag = sessions.Length == 0 ? TpmSt.NoSessions : TpmSt.Sessions; m.Put(tag, "tag"); m.PushLength(4); m.Put(commandCode, "commandCode"); foreach (TpmHandle h in handles) { m.Put(h, "handle"); } if (tag == TpmSt.Sessions) { var m2 = new Marshaller(); foreach (SessionIn s in sessions) { m2.Put(s, "session"); } m.PutUintPrependedArray(m2.GetBytes(), "sessions"); } m.Put(parmsWithoutHandles, "parms"); m.PopAndSetLengthToTotalLength(); return m.GetBytes(); }
/// <summary> /// Return a structure describing a command given a commandCode /// </summary> /// <param name="commandCode"></param> /// <returns></returns> public static CommandInfo CommandInfoFromCommandCode(TpmCc commandCode) { // TODO: faster lookup CommandInfo command = null; // ReSharper disable once LoopCanBeConvertedToQuery foreach (CommandInfo theInfo in CommandInformation.Info) { if (theInfo.CommandCode == commandCode) { command = theInfo; break; } } return command; }
/// <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); }
/// <summary> /// The response hash includes the command ordinal, response code, and the actual command bytes. /// </summary> /// <param name="hashAlg"></param> /// <param name="commandCode"></param> /// <param name="responseCode"></param> /// <param name="responseParmsNoHandles"></param> /// <returns></returns> private byte[] GetExpectedResponseHash( TpmAlgId hashAlg, byte[] responseParmsNoHandles, TpmCc commandCode, TpmRc responseCode) { var temp = new Marshaller(); temp.Put(responseCode, "responseCode"); temp.Put(commandCode, "currentCommand"); temp.Put(responseParmsNoHandles, null); byte[] parmsHash = CryptoLib.HashData(hashAlg, temp.GetBytes()); return parmsHash; }
///<param name = "the_Tag">Command tag (sessions, or no sessions)</param> ///<param name = "the_CommandSize">Total command buffer length</param> ///<param name = "the_CommandCode">Command code</param> public CommandHeader( TpmSt the_Tag, uint the_CommandSize, TpmCc the_CommandCode ) { this.Tag = the_Tag; this.CommandSize = the_CommandSize; this.CommandCode = the_CommandCode; }
/// <summary> /// Return an updated policy hash according to the TPM specification. /// </summary> /// <param name="?"></param> /// <param name="currentHash"></param> /// <param name="commandCode"></param> /// <param name="name"></param> /// <param name="refData"></param> /// <returns></returns> internal TpmHash PolicyUpdate(TpmHash currentHash, TpmCc commandCode, byte[] name, byte[] refData) { var m = new Marshaller(); m.Put(commandCode, "commandCode"); m.Put(name, "name"); TpmHash h1 = currentHash.Extend(m.GetBytes()); TpmHash h2 = h1.Extend(refData); return h2; }
public void SetCommandCodeAuditStatus( TpmHandle auth, TpmAlgId auditAlg, TpmCc[] setList, TpmCc[] clearList ) { Tpm2SetCommandCodeAuditStatusRequest inS = new Tpm2SetCommandCodeAuditStatusRequest(); inS.auth = auth; inS.auditAlg = auditAlg; inS.setList = setList; inS.clearList = clearList; TpmStructureBase outSBase; DispatchMethod(TpmCc.SetCommandCodeAuditStatus, (TpmStructureBase) inS, typeof(Tpm2SetCommandCodeAuditStatusResponse), out outSBase, 1, 0); }
// Does the command mutate global state? internal static bool CommandDefined(TpmCc command) { return(ThreadSafety.ContainsKey(command)); }
public void PpCommands( TpmHandle auth, TpmCc[] setList, TpmCc[] clearList ) { Tpm2PpCommandsRequest inS = new Tpm2PpCommandsRequest(); inS.auth = auth; inS.setList = setList; inS.clearList = clearList; TpmStructureBase outSBase; DispatchMethod(TpmCc.PpCommands, (TpmStructureBase) inS, typeof(Tpm2PpCommandsResponse), out outSBase, 1, 0); }
/// <summary> /// Return an updated policy digest in accordance with the TPM 2.0 Specification /// Section 23.2.3 Policy Digest Update Function /// </summary> internal TpmHash PolicyUpdate(TpmHash currentHash, TpmCc commandCode, byte[] name, byte[] refData) { return PolicyUpdate1(currentHash, commandCode, name).Extend(refData); }
/// <summary> /// This command indicates that the authorization will be limited to a specific command code. /// </summary> public TpmPolicyCommand(TpmCc commandCode, string branchName = "") : base(branchName) { AllowedCommand = commandCode; }
public bool IsImplemented(TpmCc cmd) { return(SupportedCommands.Contains(cmd)); }
// This is installed as the raw command callback handler on the underlying TPM. // It is used to generate low-level test statistics (number of commands executed, // etc.), dumps of the conversation with the TPM and to keep a record of all // command sequences seen that contain types that we haven't seen before. // In the case of a multi-context TPM this will be called on different threads, // but locking should be handled safely by MainTestLogger. void ICommandCallbacks.PostCallback(byte[] inBuf, byte[] outBuf) { TimeSpan cmdExecutionTime = DateTime.Now - CurCmdStartTime; if (inBuf.Length < 10) { return; } Marshaller m = new Marshaller(inBuf); TpmSt sessionTag = m.Get <TpmSt>(); uint parmSize = m.Get <UInt32>(); TpmCc commandCode = m.Get <TpmCc>(); if (commandCode == TpmCc.Clear) { ClearWasExecuted = true; } Marshaller mOut = new Marshaller(outBuf); TpmSt responseTag = mOut.Get <TpmSt>(); uint responseParamSize = mOut.Get <uint>(); TpmRc responseCode = mOut.Get <TpmRc>(); if (ValidateTestAttributes) { // ValidateTestAttributes should not be set for a stress run LogTestAttributes(sessionTag, commandCode); try { if (responseCode == TpmRc.Success) { ValidateHandleUsage(commandCode, inBuf); } } catch (Exception) { // Invalid command buffer can mess this up } } if (sessionTag.Equals(TpmSt.Null)) { return; } // There are two encoding for errors - formats 0 and 1. Decode the error type uint resultCodeValue = (uint)responseCode; bool formatOneErrorType = ((resultCodeValue & 0x80) != 0); uint resultCodeMask = formatOneErrorType ? 0xBFU : 0x97FU; TpmRc maskedError = (TpmRc)((uint)responseCode & resultCodeMask); lock (this) { // log the command info to the test logger so that it can collect stats LogCommandExecution(commandCode, maskedError, cmdExecutionTime); } #if false // Keep a copy of successfully executed commands that contain types we have // not seen so far. This is for tests that need good-command candidate strings, // like TestCommandDispatcherCoverage. // Code 0x80280400 is returned by TBS when the command is blocked by Windows. if (maskedError == TpmRc.Success && !Tpm2.IsTbsError(resultCodeValue)) { // look at all types in command string. If we have a new type we keep it CrackedCommand cc = CommandProcessor.CrackCommand(inBuf); CommandInfo info = CommandInformation.Info.First(x => x.CommandCode == cc.Header.CommandCode); byte[] inStructBytes = Globs.Concatenate( Globs.GetZeroBytes((int)info.HandleCountIn * 4), cc.CommandParms); Marshaller mx = new Marshaller(inStructBytes); TpmStructureBase bb = (TpmStructureBase)mx.Get(info.InStructType, ""); // If a new type is contained, save this command for testing in // TestDispatcherCoverage. if (HasNewTypes(bb)) { ExecutedCommandInfo.Add(inBuf); } } else #else if (maskedError != TpmRc.Success) #endif { // If a command failed, we can get here only if the corresponding // expected error assertion was specified. ++NumAsserts; } ReportProgress(); // output TPM IO to a text file for later processing if (Logger.LogTpmIo) { while (TpmIoWriter == null) { try { string ioLogPath; if (Logger.LogPath != null) { ioLogPath = System.IO.Path.Combine(Logger.LogPath, "tpm_io.txt"); } else { string fileName; lock (this) { fileName = "tpm_io-" + DateTime.Now.ToString("yyyy-MMM-dd-HH"); if (PrevLogName == fileName) { fileName += "(" + ++PrevLogInstance + ")"; } else { PrevLogName = fileName; PrevLogInstance = 1; } } fileName += ".txt"; #if TSS_MIN_API ioLogPath = fileName; #else string docsPath = Environment.GetFolderPath( Environment.SpecialFolder.MyDocuments); ioLogPath = System.IO.Path.Combine(docsPath, fileName); #endif } TpmIoWriter = new StreamWriter(new FileStream(ioLogPath, FileMode.Create)); Logger.WriteToLog("Dumping TPM I/O to " + ioLogPath); } catch (Exception e) { string message = "Failed to open the tpm_io.txt file for writing.\n" + "Error: " + e.Message; Logger.WriteErrorToLog(message); } } // get the test source code line that initiated the command string caller = "unknown"; #if !TSS_NO_STACK StackTrace trace = new StackTrace(true); StackFrame[] frames = trace.GetFrames(); int frameCount = frames.Length; StackFrame f = null; // start at 1 to not count the currently executing function for (int j = 1; j < frameCount; j++) { f = frames[j]; if (f.GetMethod().DeclaringType.Assembly == Logger.TestAssembly) { caller = f.GetFileName() + ":" + f.GetFileLineNumber(); break; } } #endif string commandCodeString = Enum.GetName(typeof(TpmCc), commandCode); string inString = "{MALFORMED COMMAND BUFFER}"; string outString = "{MALFORMED RESPONSE BUFFER}"; try { inString = CommandProcessor.ParseCommand(inBuf); } catch (Exception) { } try { outString = CommandProcessor.ParseResponse(commandCodeString, outBuf); } catch (Exception) { } lock (this) { TpmIoWriter.WriteLine(commandCode); TpmIoWriter.WriteLine(caller); TpmIoWriter.WriteLine(">>>> Raw input"); TpmIoWriter.WriteLine(Globs.HexFromByteArray(inBuf)); TpmIoWriter.WriteLine(">>>> Raw output"); TpmIoWriter.WriteLine(Globs.HexFromByteArray(outBuf)); TpmIoWriter.WriteLine(">>>> Parsed input"); TpmIoWriter.WriteLine(inString); TpmIoWriter.WriteLine(">>>> Parsed output"); TpmIoWriter.WriteLine(outString); TpmIoWriter.WriteLine("-----------------------------------------"); TpmIoWriter.Flush(); } } if (ChainedCallbacks != null) { ChainedCallbacks.PostCallback(inBuf, outBuf); } } // ICommandCallbacks.PostCallback
internal static bool GetThreadSafety(TpmCc command) { return(ThreadSafety[command]); }
} // ProcessResponseSessions private void ValidateResponseSessions( TpmHandle[] outHandles, SessionOut[] outSessions, TpmCc commandCode, TpmRc responseCode, byte[] outParmsNoHandles) { int numSessions = Sessions.Length; if (numSessions == 0 || numSessions > outSessions.Length) { return; } int outSessionCount = 0; foreach (SessionBase s in Sessions) { SessionOut outSess = outSessions[outSessionCount++]; if (s is Pwap) { if (outSess.nonceTpm.Length != 0) { throw new TpmFailure("PWAP returned non-empty nonce"); } if (outSess.auth.Length != 0) { throw new TpmFailure("PWAP returned non-empty auth value"); } } // ReSharper disable once CanBeReplacedWithTryCastAndCheckForNull else if (s is AuthSession) { var sess = s as AuthSession; byte[] parmsHash = GetExpectedResponseHash(sess.AuthHash, outParmsNoHandles, commandCode, responseCode); byte[] expectedHmac = sess.GetAuthHmac(parmsHash, Direction.Response); if (outSess.auth.Length != 0) { if (!Globs.ArraysAreEqual(outSess.auth, expectedHmac)) { throw new TpmFailure("Bad response HMAC"); } } } else { throw new TpmFailure("Invalid response session type"); } } } // ValidateResponseSessions
/// <summary> /// Return an updated policy digest in accordance with the TPM 2.0 Specification /// Section 23.2.3 Policy Digest Update Function /// </summary> internal TpmHash PolicyUpdate(TpmHash currentHash, TpmCc commandCode, byte[] name, byte[] refData) { return(PolicyUpdate1(currentHash, commandCode, name).Extend(refData)); }
/// <summary> /// Implements the first step of the policy digest update (see the PolicyUpdate() /// method), and also used by PolicyAuthorizeNV. /// </summary> internal TpmHash PolicyUpdate1(TpmHash currentHash, TpmCc commandCode, byte[] name) { var m = new Marshaller(); m.Put(commandCode, "commandCode"); m.Put(name, "name"); return currentHash.Extend(m.GetBytes()); }
internal CommandThreadSafety(TpmCc code, bool safe) { CommandCode = code; ThreadSafe = safe; }
internal void TestCompleted(TestContext ctx) { double testTime = (DateTime.Now - ctx.CurTestStartTime).TotalMilliseconds; string TestName = ctx.CurTestMethod; TestStatus status = ctx.CurTestStatus; Debug.Assert((status & ~(TestStatus.OK | TestStatus.Aborted | TestStatus.Failed)) == 0, "No test status set"); lock (TestRoutinesStats) { if (!TestRoutinesStats.ContainsKey(TestName)) { TestRoutinesStats.Add(TestName, new TestStats()); } TestStats s = TestRoutinesStats[TestName]; s.TotalExecutionTime += (int)testTime; if (status == TestStatus.OK) { s.NumSuccess++; } else { // Multiple failure statuses are possible in case the test used // restart feature. if ((status & TestStatus.Failed) != 0) { s.NumFailed++; } if ((status & TestStatus.Aborted) != 0) { s.NumAborted++; } } } lock (CumulativeCmdStats) { // Merge in statistics accumulated in the test context during this // test run. TotalNumCommands += ctx.NumCommands; TotalNumAsserts += ctx.NumAsserts; foreach (var kv in ctx.CmdStats) { TpmCc cc = kv.Key; CommandStats stat = kv.Value; if (!CumulativeCmdStats.ContainsKey(cc)) { Debug.Assert(stat.CallerTests.Count == 0); stat.CallerTests.Add(ctx.CurTestMethod); CumulativeCmdStats.Add(cc, stat); } else { CommandStats cumulStat = CumulativeCmdStats[cc]; cumulStat.NumSuccess += stat.NumSuccess; cumulStat.NumFailures += stat.NumFailures; cumulStat.FailureResponses = new SortedSet <TpmRc>( cumulStat.FailureResponses.Union(stat.FailureResponses)); cumulStat.SuccessExecutionTime += stat.SuccessExecutionTime; cumulStat.FailureExecutionTime += stat.FailureExecutionTime; if (!cumulStat.CallerTests.Contains(ctx.CurTestMethod)) { cumulStat.CallerTests.Add(ctx.CurTestMethod); } } } } }
/// <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"); Console.Error.WriteLine("ContextLoad and ContextSave 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); 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) bool loadOk = LoadEntities(neededObjects); bool loadOk2 = LoadEntities(neededSessions); if (!loadOk || !loadOk2) { 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 resCode = GetResultCode(responseBuf); if (resCode == TpmRc.Success) { break; } if (resCode == TpmRc.ObjectMemory) { bool slotMade = MakeSpace(SlotType.ObjectSlot, neededObjects); if (!slotMade) { throw new Exception("Failed to make an object slot in the TPM"); } continue; } if (resCode == TpmRc.SessionMemory) { bool slotMade = MakeSpace(SlotType.SessionSlot, neededSessions); if (!slotMade) { throw new Exception("Failed to make a session slot in the TPM"); } continue; } break; } 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) }
///<param name = "the_auth">TPM_RH_OWNER or TPM_RH_PLATFORM+{PP} Auth Index: 1 Auth Role: USER</param> ///<param name = "the_auditAlg">hash algorithm for the audit digest; if TPM_ALG_NULL, then the hash is not changed</param> ///<param name = "the_setList">list of commands that will be added to those that will be audited</param> ///<param name = "the_clearList">list of commands that will no longer be audited</param> public Tpm2SetCommandCodeAuditStatusRequest( TpmHandle the_auth, TpmAlgId the_auditAlg, TpmCc[] the_setList, TpmCc[] the_clearList ) { this.auth = the_auth; this.auditAlg = the_auditAlg; this.setList = the_setList; this.clearList = the_clearList; }
public Tpm2PolicyCommandCodeRequest() { policySession = new TpmHandle(); code = new TpmCc(); }
public Tpm2PolicyCommandCodeRequest(Tpm2PolicyCommandCodeRequest the_Tpm2PolicyCommandCodeRequest) { if((Object) the_Tpm2PolicyCommandCodeRequest == null ) throw new ArgumentException(Globs.GetResourceString("parmError")); policySession = the_Tpm2PolicyCommandCodeRequest.policySession; code = the_Tpm2PolicyCommandCodeRequest.code; }
public TpmPolicyCommand(TpmCc commandCode, string branchName = "", string nodeId = null) : base(branchName, nodeId) { AllowedCommand = commandCode; }
///<param name = "the_policySession">handle for the policy session being extended Auth Index: None</param> ///<param name = "the_code">the allowed commandCode</param> public Tpm2PolicyCommandCodeRequest( TpmHandle the_policySession, TpmCc the_code ) { this.policySession = the_policySession; this.code = the_code; }
/// <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 CommandHeader() { Tag = new TpmSt(); CommandSize = 0; CommandCode = new TpmCc(); }