Documentation on Extensible TPM Simulator

The code in this archive is a fork of the original TPM Emulator code written by Mario Strasser and Heiko Stamer (with contributions from several others). This code is forked from version 0.7.3 of the original emulator, with the goal of supporting experiments in TPM extensions - this code adds support for clean, dynamically loadable key types and/or new commands, and provides some timing features that aim to reflect operation times of real TPM chips in the emulator. We will refer to this branch as the "Extensible TPM Emulator."

This project is part of the trusted computing research at the SPAN (Security Privacy and Networking) Lab at the University of North Carolina at Greensboro - full thanks and credits are at the bottom of this file. The homepage of the extensible emulator is http://span.uncg.edu/tpmsim

If you are interested in the original TPM emulator, it can be found at http://tpm-emulator.berlios.de/

LICENSE AND RIGHTS

The extensibility and plugin framework, as well as timing extensions are Copyright (C) Stephen R. Tate, 2010-2012. The original TPM emulator code is Copyright (C) 2004-2011 Mario Strasser and ETH Zurich. The original emulator and the Extensible Emulator fork are free software - you may redistribute it and/or modify it under the terms of the GNU Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

OVERVIEW

The Extensible TPM Emulator supports binary plugins that can be loaded through command-line options when the emulator is run. If no plugins are loaded, then the running emulator should be functionally the same as the original version 0.7.3 emulator. Plugins can be compiled separately from the TPM emulator, and so adding new functionality does not require changing the basic TPM emulator code.

Plugins can define new commands and/or new key types. For example, a plugin could be written to experiment with using elliptic curve cryptography as a new key type for storage and signing keys. If this plugin were compiled as "tpmsim_plugin_ecc", then you could run the emulator with the command line

tpmd -Lecc

and then this plugin would be loaded. To find the plugin, the code first looks in the current directory, then in the directories listed in the standard LD_LIBRARY_PATH environment variable, and then finally in the installation directory {prefix}/lib/tpmsim/plugins (where "prefix" is the install prefix defined when the emulator is built - by default this is "/usr/local").

Below, we describe the three main contributions of the extensible emulator, and how to use them: How to add new commands (and override existing TPM commands); how to add support for new key types; and how the timing simulation works.

GENERAL PLUGIN STRUCTURE

For an example of a plugin, see the plugins/randoracle directory in the source code. When you write a plugin, it must have a function named "plugin_init()", which is called with no arguments when the plugin is loaded. From this function you can add new command sets by calling commands_add_set or add new key types by calling keytype_add. For more information on how these work, see below.

For proper compilation an linking, it is probably easiest to write your plugin under the "plugins" directory of the simulator package after adding the directory to CMakeLists.txt in the plugins directory and setting up the CMakeLists.txt file in your plugin directory. Even if you are compiling separately from the actual simulator, this will allow you to use cmake to build a proper make file for building and linking the plugin.

ADDING NEW COMMANDS

Commands are added (or overridden) through the use of "command sets" that are added through plugins. A command is described with a command_info structure (defined in plugins/plugins.h), which specifies the command code (ordinal) for the command, gives a string representation of the command name for printing in a debugging statement, provides a pointer to the function to call when the command is requested, and provides flags saying whether the command can be called when the TPM is disabled or deactivated. To add a command set (which a plugin can do in the plugin_init() function), call commands_add_set(numCommands, cmds) where numCommands is the number of commands in this command set, and cmds is an array of command_info structures. The array should list commands in order of increasing ordinal, since commands are found by binary search on the command set arrays (the commands_add_set() function will check this, and reject a command set if this doesn't hold). See the end of the tpm_cmd_handler.c file for an example of how this works, with a command set provided for standard TPM functions.

Command sets are searched in the reverse of the order in which they are added, so later plugins override earlier ones (including the standard TPM commands, which are the first loaded). So if, for some reason, you wanted to replace the TPM_LoadKey2 command, you could add a new version to a command set, load it, and since it is found before the standard TPM_LoadKey2 command your new code effectively replaces the standard version of TPM_LoadKey2. Note that the code for the standard TPM_LoadKey2 still exists in the emulator - it just isn't called for that ordinal any more.

Each new command must have an ordinal assigned to it, and we have defined a way to assign ordinals so that they don't conflict with real TPM commands or with other extensions - see the comments at the top of plugins/key_functions.h to see how this works.

Operations on Key Structures from Commands

The most basic type of data that commands operate on is a cryptographic key. In the original emulator code, all keys were RSA keys, so much of the code worked only for RSA keys. All of the key operations have now been replaced by generic calls to "key functions." These functions are all defined in the key_functions.c file, and for the most part just redirect the call to the code for the specific key type (RSA keys or whatever). The names of these functions follow a specific naming convention, formed as key_[inputfields]_[verb]_[outputfields] - all [inputfields] are assumed to be fully initialized (and must contain something that specifies the type of the key), and [outputfields] refer to objects which are assumed to be fully uninitialized. If the command succeeds, then all fields in the [outputfields] structure are initialized, and if the command succeeds none are (and consequently don't need to be freed - see below for Memory Management). The most common verb is "init", and allows a structure to be initialized. For example, key_keydata_init_pubkey() uses an existing TPM_KEY_DATA structure to initialize a TPM_PUBKEY structure. For more information on individual functions, see the documentation in key_functions.h.

Memory Management

Memory management in the emulator is somewhat tricky. This fork of the code keeps the memory management structure from the original TPM emulator - this code does a few tricky things that improve efficiency (so that temporary read-only objects don't have to do dynamic memory allocation), but adds some subtle issues in managing objects. The following is our reverse-engineered understanding of the memory management used in the original TPM emulator (and hence also in this fork) - it may or may not be the same as the way the original emulator author envisioned it. Structures and the memory that they use are either independent or dependent on another structure or buffer, depending on how they are initialized --- memory is managed differently for these two different object contexts, which we describe below.

An independent object has memory allocated specifically for that object and must free any storage that is has allocated before the object is destroyed. Any object in which fields are set individually, and tpm_malloc() is used to allocate storage, is independent. Objects initialized by 'key_..._init_...()" functions are also independent (see the previous section on naming conventions in the key_ functions). For example, in the tpm_compute_key_data_digest() function (in tpm_storage.c) there is a TPM_STORE_PUBKEY object named store. This object is initialized using a "key_..._init_...()" function, so is an independent object. This means that before this TPM_STORE_PUBKEY object is destroyed (by a return, since it is a local variable), it must free any allocations belonging to it, which is why each "return" after the successful _init_ of the object is preceded by a "free_TPM_STORE_PUBKEY(store)" call.

Dependent objects do not allocate their own storage, but rather re-use storage from other objects by setting pointers into the other object. This has three consequences: First, memory used by a dependent object should not be freed - that is the job of the object that it depends on. Secondly, the object should be treated as read-only in order to maintain consistency between objects that use the same shared memory space. And third, the object that this depends on may not be destroyed before the dependent object is destroyed (otherwise the memory it uses is freed up and unpredictable). All objects that are initialized by any of the unmarshal functions (with one exception - see below) are dependent objects, so should be treated as read-only, but do not need to be freed. For an example of this, see the execute_TPM_TakeOwnership() function in tpm_cmd_handler.c. The srkParams variable is a TPM_KEY object that is initialized using an unmarshal function, with storage coming from the req structure. In our terminology, "srkParams" is a dependent object, which depends on the "req" object. Because of this we don't need to free memory used by srkParams before the end of the function, srkParams should be used as a read-only structure (it is, but you have to trace through called functions to verify this), and srkParams needs to be destroyed before the object that it depends on (which is true since "req" comes from the calling function, and srkParams is destroyed on return to the calling function). One other way that dependent objects are created is through a "shallow copy" using memcpy() - this is only done in a few places in the code, but if this is done the created object should follow same rules as other dependent objects.

Every structure should be either fully independent or fully dependent, and should not mix fields where some are independent and some are dependent. The exception to this rule is in the TPM_KEY_DATA and TPM_PUBKEY_DATA structures - these are for internal emulator use of keys, and each includes a field which is a "native" representation of a key (bnativekey and bnativepubkey, respectively). These native keys are just blocks of storage to the emulator, but are used for holding the representation of a key in whatever form the underlying cryptographic library requires. For example, a "native key" in RSA is a tpm_rsa_private_key_t structure. Without knowing (or restricting) how the cryptographic library uses these native keys, we don't know whether they use dynamically allocated storage or not, so assume they are all independent objects, even when part of a dependent structure. This means that if the native key field has been initialized in these two structures, regardless of how it was initialized, the field should be freed before the object is destroyed. If the rest of the object is independent, then this is done through the normal free_TPM_... function on the object as a whole. If the rest of the object is dependent, then you should JUST free the native field using a call to key_parms_native_free() or key_parms_nativepk_free().

One final note on an assumption with TPM commands: each command execution starts with an execute_TPM_...() function, which unmarshals input parameters from the "req" object, and then calls a function which does the real work of the command, where output parameters are represented by pointers to uninitialized objects allocated in the execute_TPM_...() function. The work function initializes these objects if and only if the command succeeds - if the command does not succeed, the work function knows which objects (if any) have been initialized and which have not, so it must make the appropriate free calls before returning with an error code. Because of this, if there is an error return, the execute_TPM_...() function does not need to free up any memory from the output structures. However, on a successful return these output objects are all initialized as independent objects - the execute_TPM_...() function marshals the output objects into the response structure, and then must call the appropriate free functions on these output objects before returning (since they are independent objects).

If all of that is confusing, just trace through a few examples. You as the programmer have to keep track of when objects are initialized, when they are not, when they are dependent, and when they are independent. That's a little extra overhead for the programmer, but the rules can be consistently applied and have some efficiency savings over just allocating storage for every object.

Persistent storage for TPM extensions

Some TPM extensions might require persistent storage inside the simulated TPM, similar to the way the EK, SRK, and monotonic counters are maintained in the standard TPM specification. This need is complicated somewhat by the fact that the simulator might not always be started with the same set of plugins, so stored persistent data might not always make sense if the controlling plugin isn't loaded - however this data still needs to be saved whenever persistent data is updated. To solve this, the on-disk format for persistent data consists of a plugin identifier, a length field, followed by that many bytes. The data is loaded and stays in this "blob of bytes" form until it is actually needed by a plugin, at which point the plugin is responsible for converting the blob into a usable form. The plugin must also provide a pointer to a function which can convert the data back into the blob of bytes for storage on disk. If an item in persistent storage is used by a plugin that is not loaded, then it stays as a generic blob of bytes which can be re-saved when the TPM simulator exits, even if that blob can't be interpreted or used by any part of the running simulator.

To make use of persistent storage, a plugin writer must provide three functions for the persistent data that they use: a function to initialize the native format of the persistent data to default values, a function to convert from the internal (plugin-usable) format to the generic blob of bytes, and a function to do the reverse conversion. Pointers to these three functions are saved in a TPM_EXTENSION_FUNCTIONS structure - see the plugin.h header for more information, and see the distributed hashtree plugin (for hashtree implementation of virtual monotonic counters) for an example usage.

ADDING NEW KEY TYPES

Adding a new key types means defining functions for each of the keytype functions, which provide type-specific operations on keys (and are called from the key_...() functions). To register a new keytype (e.g., from the plugin_init() function), you provide a pointer to a keytype_info structure - this is mostly just a collection of links to functions that operate on this keytype. For a full listing of functions and what they do, see the documentation in plugins/base/keytype_null.c - one way to start writing a plugin is to copy this file, do a global replace of "null_" with a prefix for your keytype (e.g., you could replace "null_" with "ecc_"), and then go through function by function adding the necessary code. For an example of a functional keytype, refer to plugins/base/keytype_rsa.c

TIMING-ACCURATE SIMULATION

A goal of this simulator is to not just simulate the functionality of TPM extensions, but also reflect reasonable time estimates of operations - both standard and new. Detailed information about how the timing-accurate extensions are designed and were verified can be found in the following paper:

The basic idea is that time is determined primarily by cryptographic operations. While other operations are performed in executing a TPM command, they are primarily bookkeeping operations that take very little time compared to cryptographic operations. Each command that is executed in the TPM simulator adds to a "timing delay" variable in cryptographic operations, accumulating the time that the operation should require. At the end of the command execution, the return is delayed by an appropriate amount of time so that the execution takes the calculated amount of time. Different TPMs require different amounts of time for basic operations, so "timing profiles" are defined for different real TPMs. These timing profiles can be found in the "timing" directory.

New commands using standard (RSA) keys should automatically have appropriate timing delays inserted. If you create a new keytype and you want the timing estimates to work, you must find a way to estimate the appropriate timing, and then add calls to TPMTiming_addDelay...() functions so that the delays are inserted when the key functions are called.

THANKS AND CREDITS

This project based on research funded by the U.S. National Science Foundation, under NSF award 0915735.

The main project and extension/plugin design was done by Stephen Tate, and coding for various components was done by:

CONTACT

For more information about this project, please contact Steve Tate at srtate@uncg.edu