// 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