More Complex Errors
An example of a more complex error is an HMAC authorization error. This error is indicated by the error code, TPM_RC_AUTH_FAIL. The description of this error is, “the authorization HMAC check failed and DA counter incremented,” and high-order bits in the error code tell which session is seeing the HMAC error.
Unfortunately, it isn't nearly so easy to debug this error. Many steps go into calculating the HMAC: key generation, hashing of input and/or output parameters, and the HMAC calculation. There are also many input parameters that feed into these steps: nonces, keys, and the type of authorization session. Any error in the data or steps used to generate the HMAC will result in a bad HMAC.
The only effective way we've found to debug these errors is to enhance the debug trace capabilities to display all the inputs and outputs for the key generation, hashing, and HMAC calculation steps. A very careful analysis of these inputs while carefully comparing to the TPM specification usually pinpoints the failure. This type of debugging requires very detailed knowledge of the TPM 2.0 specification—in particular, all the nuances of how HMACs are calculated.
The last category of errors consists of those that resist all other attempts at debugging. Typically these occur when implementing new TPM commands or features. There's no debug trace data from a previously working program to compare to, and error-code analysis doesn't pinpoint the problem. Fortunately, the situation isn't at all desperate; with the simulator, these errors can be easily debugged.
A common error in this category is a scheme error, TPM_RC_SCHEME. This error indicates something wrong with the scheme for a key, either when creating it or when using it. Schemes are typically unions of structures, each of which contains multiple fields. Much of the understanding of how to set up schemes is non-intuitive, especially to newcomers to TPM 2.0.
Often, the best way to debug these errors or any other errors that have resisted easier debugging techniques is to run the code against the TPM 2.0 simulator and single-step through the simulator. This provides an inside view of what the TPM is expecting to receive and why it's returning an error. Of course, this assumes that you have access to the source code of the simulator. With the TPM source code, you can step into the TPM 2.0 simulator and figure out exactly why the TPM is complaining.
The steps to debug this way are as follows:
1. Build and start the TPM 2.0 simulator on a Windows system in Visual Studio. Review the instructions in Chapter 6 that describe how to do this. Select the “Debug” pull-down tab, and select “Start Debugging” to start the simulator running in debug mode.
2. Port your failing program to run against the simulator. The easiest way to do this is to create a subroutine using the System API functions and then add that subroutine to the list of test routines called by the System API test code. This way, because the System API test code, by default, communicates with the simulator, you don't have to develop a TPM 2.0 driver to talk to the simulator or deal with the simulator-specific platform commands to turn on the simulator, set the locality, and so on. You also get a TAB and resource manager for free. If you don't go this route, you must do all this work yourself.
3. Start your failing program in the debugger of your choice,  step to the place where it sends the failing command, and stop. Use a combination of single-stepping and breakpoints to get to this place.
4. Pause the simulator in its instance of Visual Studio by selecting the “Debug” pull-down and selecting “Break All”.
5. Set a breakpoint in the simulator at an entry point that you know you'll hit. If you're new to the simulator, set a breakpoint at the _rpc Send_Command function in the TPMCmdp.c source file.
6. Start the simulator running again, by selecting the Debug pull-down and selecting Continue.
7. In the test program's debugger, select the proper command to cause the test program to continue running from the breakpoint where it was stopped.
8. The simulator stops at the breakpoint you selected in the simulator code. From here you can debug into various subroutines and eventually figure out why the TPM is generating the error.
-  Currently all TCG members have access to this source code.
-  Currently, only one TPM 2.0 simulator is available, and it only runs under Microsoft Visual Studio.If and when this changes, all steps related to debugging through the simulator will need to be altered accordingly.
-  Because communication with the TPM 2.0 simulator is via sockets, the test program can be built and debugged on a remote system running any operating system. This means any debugger can be used to debug the test program. Chapter 6 describes how to run the test program on a remote system.