void TestFailureMode(Tpm2 tpm, TestContext testCtx) { tpm._GetUnderlyingDevice().TestFailureMode(); tpm._ExpectError(TpmRc.Failure) .SelfTest(1); TpmRc testResult = TpmRc.None; byte[] outData = tpm.GetTestResult(out testResult); testCtx.Assert("TestResult", testResult == TpmRc.Failure); testCtx.Assert("OutData", outData != null && outData.Length > 0); // Make sure that selected capabilities can be retrieved even when TPM is in failure mode Tpm2.GetProperty(tpm, Pt.Manufacturer); Tpm2.GetProperty(tpm, Pt.VendorString1); Tpm2.GetProperty(tpm, Pt.VendorTpmType); Tpm2.GetProperty(tpm, Pt.FirmwareVersion1); // Check if other commands fail as expected while in failure mode. tpm._ExpectError(TpmRc.Failure) .GetRandom(8); // Bring TPM back to normal. tpm._GetUnderlyingDevice().PowerCycle(); tpm.Startup(Su.Clear); } // TestFailureMode
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. }
public TpmException(TpmRc rawResponse, string errorDescription, TpmStructureBase cmdParms) : base(errorDescription) { ErrorString = TpmErrorHelpers.ErrorNumber(rawResponse).ToString(); RawResponse = rawResponse; CmdParms = cmdParms; }
/// <summary> /// Composes and returns a valid TPM response buffer containg the given /// error response code. /// </summary> /// <param name="errorCode"></param> /// <returns></returns> public static byte[] BuildErrorResponseBuffer(TpmRc errorCode) { return(Marshaller.GetTpmRepresentation(new Object[] { TpmSt.NoSessions, (uint)10, errorCode })); }
/// <summary> /// Returns error number, i.e. what is left after masking out auxiliary data /// (such as format selector, version, and bad parameter index) from the /// response code returned by TPM. /// </summary> public static TpmRc ErrorNumber(TpmRc rawResponse) { const uint Fmt1 = (uint)TpmRc.RcFmt1; // Format 1 code (TPM 2 only) const uint Ver1 = (uint)TpmRc.RcVer1; // TPM 1 code (format 0 only) const uint Warn = (uint)TpmRc.RcWarn; // Code is a warning (format 0 only) uint mask = IsFmt1(rawResponse) ? Fmt1 | 0x3F : Warn | Ver1 | 0x7F; return((TpmRc)((uint)rawResponse & mask)); }
/// <summary> /// Create a 10 byte error response that matches TPM error responses. /// </summary> /// <param name="errorCode"></param> /// <returns></returns> private byte[] FormatError(TpmRc errorCode) { var m = new Marshaller(); m.Put(TpmSt.NoSessions, ""); m.Put((uint)10, ""); m.Put(errorCode, ""); return(m.GetBytes()); }
public override void CancelContext() { TpmRc result = TbsWrapper.NativeMethods.Tbsip_Cancel_Commands(TbsHandle); if (result != TpmRc.Success) { Debug.WriteLine("TbsStubs.Tbsip_Cancel_Command error 0x{0:x}", result); throw new Exception("Tbsip_Cancel_Command() failed. Error {" + result + "}"); } }
internal override TpmRc Execute(Tpm2 tpm, AuthSession sess, PolicyTree policy) { byte[] nonceTpm = UseNonceTpm ? Globs.CopyData(sess.NonceTpm) : new byte[0]; TpmHandle sigKey; // If we have both the authorizing signature and the corresponding // signing key handle, we are good to go. if (AuthSig == null) { var dataToSign = new Marshaller(); dataToSign.Put(nonceTpm, ""); // If we have a signing key we can build the challenge here // (else we need to call out) if (SwSigningKey != null) { dataToSign.Put(ExpirationTime, ""); dataToSign.Put(CpHash, ""); dataToSign.Put(PolicyRef, ""); // Just ask the key to sign the challenge AuthSig = SwSigningKey.Sign(dataToSign.GetBytes()); sigKey = tpm.LoadExternal(null, SigningKeyPub, TpmRh.Owner); } else { TpmPublic verifier; AuthSig = AssociatedPolicy.ExecuteSignerCallback(this, nonceTpm, out verifier); sigKey = tpm.LoadExternal(null, verifier, TpmRh.Owner); } } else { sigKey = tpm.LoadExternal(null, SigningKeyPub, TpmRh.Owner); } Timeout = tpm.PolicySigned(sigKey, sess, nonceTpm, CpHash, PolicyRef, ExpirationTime, AuthSig, out Ticket); TpmRc responseCode = tpm._GetLastResponseCode(); tpm.FlushContext(sigKey); if (!KeepAuth) { AuthSig = null; } return(responseCode); }
public override void Connect() { TbsWrapper.TBS_CONTEXT_PARAMS contextParams; UIntPtr tbsContext = UIntPtr.Zero; contextParams.Version = TbsWrapper.TBS_CONTEXT_VERSION.TWO; contextParams.Flags = TbsWrapper.TBS_CONTEXT_CREATE_FLAGS.IncludeTpm20; TpmRc result = TbsWrapper.NativeMethods.Tbsi_Context_Create(ref contextParams, ref tbsContext); Debug.WriteLine(Globs.GetResourceString("TbsHandle:") + tbsContext.ToUInt32()); if (result != TpmRc.Success) { throw new Exception("Can't create TBS context: Error {" + result + "}"); } TbsHandle = tbsContext; OriginalHandle = tbsContext; }
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
public CancelationCtx (Tpm2 t, string cmd) { tpm = t; cmdName = cmd; origTolerateErrors = tpm.TolerateErrors; origLastError = tpm.LastError; }
/// <summary> /// Checks if the given response code uses Format-One. /// </summary> public static bool IsFmt1(TpmRc responseCode) { return(((uint)responseCode & 0x80) != 0); }
/// <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; }
public bool NeedRetry() { lastError = tpm.LastError; if (lastError == TpmRc.Canceled) thereWasCancelation = true; else return false; return attempt++ < 25; }
/// <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) }
// 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
public Tpm2GetTestResultResponse() { outData = null; testResult = new TpmRc(); }
public static string GetErrorString(Type inParmsType, uint resultCode, out TpmRc theMaskedError) { // There are two encoding for errors - format 0 and format 1. Decode the error type var resultCodeValue = resultCode; bool formatOneErrorType = ((resultCodeValue & 0x80) != 0); uint resultCodeMask = formatOneErrorType ? 0xBFU : 0x97FU; // Extract the actual error code uint maskedErrorVal = resultCode & resultCodeMask; var maskedError = (TpmRc)maskedErrorVal; theMaskedError = maskedError; string errorEntity = "Unknown"; uint errorEntityIndex = 0; string errorParmName = "Unknown"; if (formatOneErrorType) { errorEntityIndex = (resultCodeValue & 0xF00U) >> 8; if (errorEntityIndex == 0) { // ReSharper disable once RedundantAssignment errorEntity = "Unknown"; } if ((resultCodeValue & 0x40) != 0) { errorEntity = "Parameter"; errorParmName = GetParmName(inParmsType, errorEntityIndex); } else { if (errorEntityIndex >= 8) { errorEntityIndex -= 8; errorEntity = "Session"; } else { errorEntity = "handle"; } } } string errorString = String.Format( "[Code=TpmRc.{0}],[FullVal=0x{1:X},{1}]\n" + "[ErrorEntity={2}],[ParmNum={3}]" + "[ParmName={4}]", new Object[] { maskedError.ToString(), //(uint)maskedError, resultCodeValue, errorEntity, errorEntityIndex, errorParmName }); return errorString; }
private bool IsErrorAllowed(TpmRc rc) { return TolerateErrors || AreErrorsExpected() && ExpectedResponses.Count(x => x == rc) > 0; }
/// <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) }
/// <summary> /// Tpm2 will typically throw an exception if an error is returned. If an error is expected then this command instructs the Tpm2 to /// throw an exception in anything other than the expected error is returned. This behavior is cleared when a command is invoked. /// </summary> /// <param name="errorCode"></param> /// <returns></returns> public Tpm2 _ExpectError(TpmRc errorCode) { return _ExpectResponses(errorCode); }
public static byte[] CreateResponse( TpmRc responseCode, TpmHandle[] handles, SessionOut[] sessions, byte[] responseParmsNoHandles) { var m = new Marshaller(); TpmSt tag = sessions.Length == 0 ? TpmSt.NoSessions : TpmSt.Sessions; m.Put(tag, "tag"); m.PushLength(4); m.Put(responseCode, "responseCode"); foreach (TpmHandle h in handles) { m.Put(h, "handle"); } if (tag == TpmSt.Sessions) { m.Put((uint)responseParmsNoHandles.Length, "parmsLenght"); } m.Put(responseParmsNoHandles, "parms"); foreach (SessionOut s in sessions) m.Put(s, "session"); m.PopAndSetLengthToTotalLength(); return m.GetBytes(); }
public static void SplitResponse( byte[] response, uint numHandles, out TpmSt tag, out uint paramSize, out TpmRc responseCode, out TpmHandle[] handles, out SessionOut[] sessions, out byte[] responseParmsNoHandles, out byte[] responseParmsWithHandles) { var m = new Marshaller(response); tag = m.Get<TpmSt>(); paramSize = m.Get<uint>(); responseCode = m.Get<TpmRc>(); // If error we only get the header if (responseCode != TpmRc.Success) { handles = new TpmHandle[0]; sessions = new SessionOut[0]; responseParmsNoHandles = new byte[0]; responseParmsWithHandles = new byte[0]; return; } handles = new TpmHandle[numHandles]; for (int j = 0; j < numHandles; j++) { handles[j] = m.Get<TpmHandle>(); } uint parmsEnd = m.GetValidLength(); if (tag == TpmSt.Sessions) { var sessionOffset = m.Get<uint>(); uint startOfParmsX = m.GetGetPos(); parmsEnd = startOfParmsX + sessionOffset; m.SetGetPos(parmsEnd); var sessX = new List<SessionOut>(); while (m.GetGetPos() < m.GetValidLength()) { var s = m.Get<SessionOut>(); sessX.Add(s); } sessions = sessX.ToArray(); m.SetGetPos(startOfParmsX); } else { sessions = new SessionOut[0]; } uint startOfParms = m.GetGetPos(); uint parmsLength = parmsEnd - m.GetGetPos(); // Get the response buf with no handles responseParmsNoHandles = new byte[parmsLength]; Array.Copy(response, (int)startOfParms, responseParmsNoHandles, 0, (int)parmsLength); // Get the response buf with handles responseParmsWithHandles = new byte[parmsLength + numHandles * 4]; Array.Copy(response, 10, responseParmsWithHandles, 0, (int)numHandles * 4); Array.Copy(response, (int)startOfParms, responseParmsWithHandles, (int)numHandles * 4, (int)parmsLength); }
/// <summary> /// Handles TPM response value. /// Converts the error code into a human-readable form, invokes callbacks and /// encapsulates error info into a .Net exception. /// </summary> /// <param name="responseTag"></param> /// <param name="responseParamSize"></param> /// <param name="resultCode"></param> /// <param name="inParms"></param> /// <returns></returns> // ReSharper disable once UnusedParameter.Local private bool ProcessError(TpmSt responseTag, uint responseParamSize, TpmRc resultCode, TpmStructureBase inParms) { string errorString; AssertExpectedResponsesValid(); // Process TPM success case (both expected success, and unexpected success) if (resultCode == TpmRc.Success) { LastError = TpmRc.Success; if (IsSuccessExpected()) { return true; } // Else we have unexpectedly succeeded // If TolerateErrors is set, then no error indication is provided apart // from setting LastReponseCode (the caller must query to find that // the error does not match). if (TolerateErrors) { return false; } // If there is an installed error handler invoke it. if (TheErrorHandler != null) { TheErrorHandler(resultCode, ExpectedResponses); return false; } // ReSharper disable once ConvertIfStatementToConditionalTernaryExpression if (ExpectedResponses.Length == 1) { errorString = string.Format("Error {0} was expected but command {1} succeeded", ExpectedResponses[0], CurrentCommand); } else { errorString = string.Format("Errors {{{0}}} were expected but command {1} succeeded", string.Join(", ", ExpectedResponses), CurrentCommand); } _ClearCommandContext(); throw new TssException(errorString); } // Else we have an error if (responseTag != TpmSt.NoSessions) { throw new Exception("Ill-formed responseTag (not NoSessions)"); } if (responseParamSize != 10) { throw new Exception("Ill-formed reponseParamSize (not 10)"); } // There are two encodings for errors - format 0 and format 1. var resultCodeValue = (uint)resultCode; bool formatOneErrorType = TpmErrorHelpers.IsFmt1(resultCode); // Extract the actual error number LastError = TpmErrorHelpers.ErrorNumber(resultCode); string errorEntity = "Unknown"; uint errorEntityIndex = 0; string errorParmName = "Unknown"; if (formatOneErrorType) { errorEntityIndex = (resultCodeValue & 0xF00U) >> 8; if ((resultCodeValue & 0x40) != 0) { errorEntity = "Parameter"; errorParmName = GetParmName(inParms.GetType(), errorEntityIndex); } else { if (errorEntityIndex >= 8) { errorEntityIndex -= 8; errorEntity = "Session"; } else { errorEntity = "Handle"; } } } string errorDetails = FormatString("\r\n" + "Details: \n" + "[Code=TpmRc.{0}],"+ "[RawCode=0x{1:X},{1}]\n" + "[ErrorEntity={2}], [ParmNum={3}]\n" + "[ParmName={4}]", new Object[] { LastError.ToString(), resultCodeValue, errorEntity, errorEntityIndex, errorParmName }); // We have found out all we can about the error. Now process it according to the tpm context // AllowErrors() specifies that errors should be handled silently if ((OuterCommand == TpmCc.None && IsErrorAllowed(LastError)) || (OuterCommand != TpmCc.None && LastError == TpmRc.Canceled)) { return false; } if (OuterCommand != TpmCc.None || ExpectedResponses == null) { errorString = string.Format("Error {{{0}}} was returned for command {1}.", LastError, CurrentCommand); } else { errorString = string.Format("Error {{{0}}} was returned instead of {{{1}}} for command {2}.", LastError, string.Join(", ", ExpectedResponses), CurrentCommand); } if (AreErrorsExpected()) { // We have a mismatched error. If a warning handler is installed, call it. if (TheWarningHandler != null) { TheWarningHandler(errorString); _ClearCommandContext(); return false; } } // Otherwise propagate the unexpected error as an exception _ClearCommandContext(); errorString += errorDetails; throw new TpmException(resultCode, errorString); }
public Tpm2GetTestResultResponse(Tpm2GetTestResultResponse the_Tpm2GetTestResultResponse) { if((Object) the_Tpm2GetTestResultResponse == null ) throw new ArgumentException(Globs.GetResourceString("parmError")); outData = the_Tpm2GetTestResultResponse.outData; testResult = the_Tpm2GetTestResultResponse.testResult; }
// Send TPM-command buffer to device public override void DispatchCommand( CommandModifier mod, byte[] cmdBuf, out byte[] respBuf) { if (TctiCtx != null && TctiCtxPtr != IntPtr.Zero) { TpmRc rc = TctiCtx.transmit(TctiCtxPtr, (ulong)cmdBuf.Length, cmdBuf); if (rc != TpmRc.Success) { throw new TssException($"TCTI_CTX::transmit() failed: error {rc}"); } ulong bytesReceived = (ulong)_responseBuffer.Length; rc = TctiCtx.receive(TctiCtxPtr, ref bytesReceived, _responseBuffer, 5 * 60 * 1000); if (rc != TpmRc.Success) { throw new TssException($"TCTI_CTX::receive() failed: error {rc}"); } respBuf = new byte[bytesReceived]; Array.Copy(_responseBuffer, respBuf, (int)bytesReceived); } else if (TrmDevice != null) { TrmDevice.DispatchCommand(mod, cmdBuf, out respBuf); return; } else if (_tpmIO != null) { _tpmIO.Write(cmdBuf, 0, cmdBuf.Length); int count = 0; int bytesRead = 0; do { bytesRead = _tpmIO.Read(_responseBuffer, 0, _responseBuffer.Length); if (bytesRead > 0) { break; } #if WINDOWS_UWP Task.Delay(TpmIORetryBackoffTime).Wait(); #else Thread.Sleep(TpmIORetryBackoffTime); #endif Debug.WriteLine($"TPM {_tpmDevicePath} retry {count}."); } while (count++ < TpmIORetryCount); if (bytesRead <= 0) { throw new IOException($"No response from {_tpmDevicePath}"); } respBuf = new byte[bytesRead]; Array.Copy(_responseBuffer, respBuf, bytesRead); } else { throw new InvalidOperationException("TPM context is not initialized."); } }
///<param name = "the_outData">test result data contains manufacturer-specific information</param> ///<param name = "the_testResult"></param> public Tpm2GetTestResultResponse( byte[] the_outData, TpmRc the_testResult ) { this.outData = the_outData; this.testResult = the_testResult; }
/// <summary> /// This sample illustrates the use of a simple TPM policy session. The policy demands /// PCR 1, 2, 3 set to current values, and the command be issued at locality zero. /// </summary> static void SimplePolicy(Tpm2 tpm) { Console.WriteLine("Simple Policy sample:"); // // Check if policy commands are implemented by TPM. This list // could include all the other used commands as well. // This check here makes sense for policy commands, because // usually a policy has to be executed in full. If a command // out of the chain of policy commands is not implemented in the // TPM, the policy cannot be satisfied. // var usedCommands = new[] { TpmCc.PolicyPCR }; foreach (var commandCode in usedCommands) { if (!tpm.Helpers.IsImplemented(commandCode)) { Console.WriteLine("Cancel Simple Policy sample, because command {0} is not implemented by TPM.", commandCode); return; } } // // First read the PCR values // var pcrs = new uint[] { 1, 2, 3 }; var sel = new PcrSelection(TpmAlgId.Sha, pcrs); PcrSelection[] selOut; Tpm2bDigest[] pcrValues; tpm.PcrRead(new[] { sel }, out selOut, out pcrValues); Console.WriteLine("PCR Selections:\n"); foreach (PcrSelection s in selOut) { Console.WriteLine(s.ToString()); } Console.WriteLine("PCR Values:\n"); foreach (var v in pcrValues) { Console.WriteLine(v.ToString()); } // // Save the current PCR values in a convenient data structure // var expectedPcrVals = new PcrValueCollection(selOut, pcrValues); // // Tpm2Lib encapsulates a set of policy assertions as the PolicyTree class. // var policy = new PolicyTree(TpmAlgId.Sha256); // // Set the policy: Locality AND PolicyPcr. This form of CreatePOlicy // only creates a single chain. Note that all well-formed policy chains // must have leaf identifiers. Leaf identifiers are just strings that // are unique in a policy so that the framework can be told what // chain to evaluate. // policy.Create( new PolicyAce[] { new TpmPolicyPcr(expectedPcrVals), "leaf" } ); // // Ask Tpm2Lib for the expected policy-hash for this policy // TpmHash expectedPolicyHash = policy.GetPolicyDigest(); // // Create a sealed primary object with the policy-hash we just calculated // var dataToSeal = new byte[] { 1, 2, 3, 4, 5, 4, 3, 2, 1 }; TpmHandle primHandle = CreateSealedPrimaryObject(tpm, dataToSeal, null, expectedPolicyHash.HashData); // // Create an actual TPM policy session to evaluate the policy // AuthSession session = tpm.StartAuthSessionEx(TpmSe.Policy, TpmAlgId.Sha256); // // Run the policy on the TPM // session.RunPolicy(tpm, policy, "leaf"); // // Unseal the object // byte[] unsealedData = tpm[session].Unseal(primHandle); Console.WriteLine("Unsealed data: " + BitConverter.ToString(unsealedData)); // // Change a PCR and make sure that the policy no longer works // var nullAuth = new AuthValue(); tpm[nullAuth].PcrEvent(TpmHandle.Pcr(3), new byte[] { 1, 2, 3 }); tpm.PolicyRestart(session.Handle); // // Run the policy again - an error will be returned // TpmRc policyError = session.RunPolicy(tpm, policy, null, true); // // And the session will be unusable // unsealedData = tpm[session]._ExpectError(TpmRc.PolicyFail).Unseal(primHandle); // // Clean up // tpm.FlushContext(session.Handle); tpm.FlushContext(primHandle); }
/// <summary> /// Create a 10 byte error response that matches TPM error responses. /// </summary> /// <param name="errorCode"></param> /// <returns></returns> private byte[] FormatError(TpmRc errorCode) { var m = new Marshaller(); m.Put(TpmSt.NoSessions, ""); m.Put((uint)10, ""); m.Put(errorCode, ""); return m.GetBytes(); }
public TpmException(TpmRc rawResponse, string errorDescription) : base(errorDescription) { ErrorString = TpmErrorHelpers.ErrorNumber(rawResponse).ToString(); RawResponse = rawResponse; }
public static TpmRc GetBaseErrorCode(TpmRc resultCode) { var resultCodeValue = (uint)resultCode; bool formatOneErrorType = ((resultCodeValue & 0x80) != 0); uint resultCodeMask = formatOneErrorType ? 0xBFU : 0x97FU; // Extract the actual error code uint maskedErrorVal = (uint)resultCode & resultCodeMask; var maskedError = (TpmRc)maskedErrorVal; return maskedError; }
} // 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
public Tpm2GetTestResultResponse() { outData = new byte[0]; testResult = new TpmRc(); }
/// <summary> /// This sample demonstrates the creation and use of a storage root key that /// behaves like the Storage Root Key (SRK) defined in TPM1.2. /// To do this we need to create a new primary, and then use EvictControl /// to make it NV-resident. /// </summary> /// <param name="tpm">Reference to TPM object</param> static void StorageRootKey(Tpm2 tpm) { // // This template asks the TPM to create an 2048 bit RSA storage key // with an associated AES key for symmetric data protection. The term // "SRKs" is not used in TPM2.0, but we use it here to // not // var srkTemplate = new TpmPublic(TpmAlgId.Sha1, // Name algorithm ObjectAttr.Restricted | // Storage keys must be restricted ObjectAttr.Decrypt | // Storage keys are Decrypt keys ObjectAttr.FixedParent | ObjectAttr.FixedTPM | // Non-duplicable (like 1.2) ObjectAttr.UserWithAuth | ObjectAttr.SensitiveDataOrigin, new byte[0], // No policy new RsaParms(new SymDefObject(TpmAlgId.Aes, 128, TpmAlgId.Cfb), new NullAsymScheme(), // No signature 2048, 0), // 2048-bit RSA new Tpm2bPublicKeyRsa()); // // Authorization for the key we are about to create // var srkAuth = new byte[0]; AuthValue childAuthVal = AuthValue.FromRandom(8); TssObject swKey = TssObject.CreateStorageParent(srkTemplate, childAuthVal); TpmPublic srkPublic; CreationData srkCreationData; TkCreation srkCreationTicket; byte[] srkCreationHash; // // Ask the TPM to create a new primary RSA/AES primary storage key // TpmHandle keyHandle = tpm[_ownerAuth].CreatePrimary( TpmHandle.RhOwner, // In the owner-hierarchy new SensitiveCreate(srkAuth, new byte[0]), // With this auth-value srkTemplate, // Describes key new byte[0], // For creation ticket new PcrSelection[0], // For creation ticket out srkPublic, // Out pubKey and attrs out srkCreationData, // Not used here out srkCreationHash, // Ibid out srkCreationTicket); // Ibid // // print out text-versions of the public key just created // Console.WriteLine("New SRK public key\n" + srkPublic.ToString()); // // The caller provides the handle for persistent keys // TpmHandle srkHandle = TpmHandle.Persistent(0x5000); // // Ae will make the "SRK" persistent in an NV-slot, so clean up anything // that is already there // tpm[_ownerAuth]._AllowErrors().EvictControl(TpmHandle.RhOwner, srkHandle, srkHandle); TpmRc lastError = tpm._GetLastResponseCode(); // // Make the SRK NV-resident // tpm[_ownerAuth].EvictControl(TpmHandle.RhOwner, keyHandle, srkHandle); Console.WriteLine("SRK is persistent now."); }