Desktop version

Home arrow Computer Science arrow A Practical Guide to TPM 2.0

Feature API

The TSS Feature API (FAPI) was created specifically to make the most-used facilities of the TPM 2.0 easily available to programmers. As such, it does not allow use of all the corner cases that a TPM is capable of doing.

It was designed with the hope that 80% of programs that would eventually use the TPM could be written by using the FAPI without having to resort to using other TSS APIs. It was also designed to minimize the number of calls you have to use and the number of parameters you have to define.

One way this was accomplished was by using a profile file to create default selections so you don't have to select algorithms, key sizes, crypto modes, and signing schemas explicitly when creating and using keys. It's assumed that users are normally the ones who wish to select a matched set of algorithms, and you can default to user-selected configurations. In cases where you want to explicitly select a configuration file, you may do this as well, but default configurations are always selected by the user. FAPI implementations ship with pre-created configuration files for most common choices. For example:

• The P_RSA2048SHA1 profile uses RSA 2048-bit asymmetric keys using PKCS1 version 1.5 for a signing scheme, SHA-1 for the hash algorithm, and AES128 with CFB mode for asymmetric encryption.

• The P_RSA2048SHA256 profile uses RSA 2048-bit asymmetric keys using PKCS#1 version 1.5 for a signing scheme, SHA-256 for the hash algorithm, and AES-128 with CFB mode for asymmetric encryption.

• The P_ECCP256 profile uses NIST ECC with prime field 256-bit asymmetric keys using ECDSA as a signing schema, SHA-1 for the hash algorithm, and AES-128 with CFB mode for asymmetric encryption.

Path descriptions are used to identify to the FAPI where to find keys, policies, NV, and other TPM objects and entities. Paths have a basic structure that looks like this:

<Profile name> / <Hierarchy> / <Object Ancestor> / key tree

If the profile name is omitted, the default profile chosen by the user is assumed.

If the hierarchy is omitted, then the storage hierarchy is assumed. The storage hiearchy is H_S, the Endorsement hiearchy is H_E, and the Platform hierarchy is H_P. The object ancestor can be one of the following values:

• SNK: The system ancestor for non-duplicable keys

• SDK: The system ancestor for duplicable keys

• UNK: The user ancestor for non-duplicable keys

• UDK: The user ancestor for duplicable keys

• NV: For NV indexes

• Policy: For instances of policies

The key tree is simply a list of parent and children keys separated by / characters.

The path is insensitive to capitalization.

Let's look at some examples. Assuming the user has chosen the configuration file

P_RSA2048SHA1, all of the following paths are equivalent:

P_RSA2048SHA1/H_S/SNK/myVPNkey H_S/SNK/myVPNkey

SNK/myVPNkey

P_RSA2048SHA1/H_S/SNK/MYVPNKEY H_S/SNK/MYVPNKEY

SNK/MYVPNKEY

An ECC P-256 NIST signing key under a user's backup storage key might be:

P_ECCP256/UDK/backupStorageKey/mySigningKey

The FAPI also has some basic names for default types of entities. Keys:

• ASYM_STORAGE_KEY: An asymmetric key used to store other

keys/data.

• EK: An endorsement key that has a certificate used to prove that it (and, in the process, prove that other keys) belongs to a genuine TPM.

• ASYM_RESTRICTED_SIGNING_KEY: A key like the AIK of 1.2, but that can also sign any external data that doesn't claim to come from the TPM.

• HMAC_KEY: An unrestricted symmetric key. Its main use is as an HMAC key that can be used to sign (HMAC) data that isn't a hash produced by the TPM.

NV:

• NV_MEMORY: Normal NV memory.

• NV_BITFIELD: a 64-bit bitfield.

• NV_COUNTER: A 64-bit counter.

• NV_PCR: A NV_PCR that uses the template hash algorithm.

• NV_TEMP_READ_DISABLE: Can have its readability turned off for a boot cycle.

Standard polies and authentications:

• TSS2_POLICY_NULL: A NULL policy (empty buffer) that can never be satisfied.

• TSS2_AUTH_NULL: A zero-length password, trivially satisfied.

• TSS2_POLICY_AUTHVALUE: Points to the object's authorization data.

• TSS2_POLICY_SECRET_EH: Points to the endorsement hierarchy's authorization data.

• TSS2_POLICY_SECRET_SH: Points to the storage hierarchy's authorization data.

• TSS2_POLICY_SECRET_PH: Points to the platform hierarchy's authorization data.

• TSS2_POLICY_SECRET_DA: Points to the dictionary attack handle's authorization data.

• TSS2_POLICY_TRIVIAL: Points to a policy of all zeroes. This is easy to satisfy because every policy session starts with its policy buffer equal to this policy. This can be used to create an entity that can be trivially satisfied with the FAPI.

All objects created and used by FAPI commands are authorized by a policy. This doesn't mean the authorization value can't be used: it can be used if the policy is TSS2_POLICY_AUTHVALUE. However, under the covers, a password session is never used. And if an authorization value is used, it's always done with a salted HMAC session.

One structure used constantly in the FAPI is TSS2_SIZED_BUFFER. This structure consists of two things: a size and a pointer to a buffer. The size represents the size of the buffer:

typedef struct { size_t size;uint8_t *buffer;} TSS2_SIZED_BUFFER;

You need to know one more thing before writing a program: at the beginning of your program, you must create a context, which you must destroy when you're done with it.

Let's write an example program that creates a key, uses it to sign “Hello World,” and verifies the signature. Follow these steps:

1. Create a context. Tell it to use the local TPM by setting the second parameter to NULL:

TSS2_CONTEXT *context; Tss2_Context_Intialize(&context, NULL);

2. Create a signing key using the user's default configuration. Here you explicitly tell it to use the P_RSA2048SHA1 profile instead of the default. By using the UNK, you tell it that it's a user key that is non-duplicable. Name it mySigningKey.

Using ASYM_RESTRICTED_SIGNING_KEY makes the key a signing key. You also give it a trivially satisfied policy and a password of NULL:

Tss2_Key_Create(context, // pass in the context I just created "P_RSA2048SHA1/UNK/mySigningKey", // non-duplicable

RSA2048 ASYM_RESTRICTED_SIGNING_KEY, // signing key TSS2_POLICY_TRIVIAL, // trivially policy

TSS2_AUTH_NULL); // the password is NULL

3. Use the key to sign “Hello world.” First you have to hash “Hello World” with an OpenSSL library call:

TSS2_SIZED_BUFFER myHash;

myHash.size=20 myHash.buffer=calloc(20,1);

SHA1("Hello World",sizeof("Hello World"),myHash.buffer);

4. The Sign command returns everything necessary to verify the signature. Because you just created this key, the certificate comes back with a certificate that is empty:

TSS2_SIZED_BUFFER signature, publicKey,certificate;

Tss2_Key_Sign(context, // pass in the context "P_RSA2048SHA1/UNK/mySigningKey", // the signing key

&myHash,

&signature,

&publicKey,

&certificate);

5. At this point you could save the outputs, but instead let's check them:

if (TSS_SUCCESS!=Tss2_Key_Verify(context ,&signature,

&publicKey,&myHash) )

{

printf("The command failed signature verification ");

}

else printf("The command succeeded ");

6. Destroy the buffers that have been allocated, now that you're done with them:

free(myHash.buffer); free(signature.buffer); free(publicKey.buffer);

/* I don't have to free the certificate buffer, because it was empty */

Tss2_Context_Finalize(context);

It's easy to see that this example cheats a little. In particular, the key doesn't require any type of authorization. Next you will learn what to do if authentication is required.

All FAPI functions assume that keys are authenticated only through policy. If a key is to be authenticated with a password, then the password is assigned to the key, and a policy is created using TPM2_PolicyAuthValue. The predefined TSS2_POLICY_AUTHVALUE does

this. However, this leaves you with the bigger question of how to satisfy the policy.

Policy commands come in two flavors. Some policy commands require interaction with the outside world:

• PolicyPassword: Asks for a password

• PolicyAuthValue: Asks for a password

• PolicySecret: Asks for a password

• PolicyNV: Asks for a password

• PolicyOR: Asks for a selection among choices

• PolicyAuthorize: Asks for a selection among authorized choices

• PolicySigned: Asks for a signature from a specific device Other policy commands don't require outside interaction:

• PolicyPCR: Checks the values of the TPM's PCRs

• PolicyLocality: Checks the locality of the command

• PolicyCounterTimer: Checks the counter internal to the TPM

• PolicyCommandCode: Checks what command was sent to the TPM

• PolicyCpHash: Checks the command and parameters sent to the TPM

• PolicyNameHash: Checks the name of the object sent to the TPM

• PolicyDuplicationSelect: Checks the target of duplication of a key

• PolicyNVWritten: Checks if an NV index has ever been written

Many policies require a mix of the two. If a policy requires one of the authorizations of the second type, it's the responsibility of the FAPI to handle it. If it's an authorization of the first type, then you're responsible for providing to the FAPI the parameters it doesn't have access to.

This is done via a callback mechanism. You must register these callbacks in your program so that FAPI knows what do to if it requires a password, selection, or signature. The three callbacks are defined as follows:

• TSS2_PolicyAuthCallback: Used when a password is required

• TSS2_PolicyBranchSelectionCallback: Used when the user needs to select from among more than one policy in a TPolicyOR or TPM2_PolicyAuthorize

• TSS2_PolicySignatureCallback: Used when a signature is required to satisfy the policy

The first is easiest. After a context is registered, you have to create a callback function that is used when the FAPI is asked to execute a function that requires interaction with the user asking for a password. In this case, the FAPI sends back to the program the description of the object that needs to be authorized and requests the authorization data. The FAPI takes care of salting and HMACing this authorization data. The user must do two things: create the function that asks the user for their password, and register this function so that the FAPI can call it.

Here is a simple password-handler function:

myPasswordHandler (TSS2_CONTEXT context,

void *userData,

char const *description,

TSS2_SIZED_BUFFER *auth)

{

/* Here the program asks for the password in some application specific way. It then puts the result into the auth variable. */

return;

}

Here is how you register it with the FAPI so it knows to call the function:

Tss2_SetPolicyAuthCallback(context, TSS2_PolicyAuthCallback, NULL);

Creating and registering the other callbacks is very similar.

At the time of writing this book, the specification for using XML to write a policy for a command has not yet been written, although it's likely to come out in 2014. However, one thing is known: it will be possible for hardware OEMs (for example, a smartcard provider) to provide a library that contains these callback functions. In this case, the callback function will be registered in the policy rather than in the program, so you won't need to provide it. Similarly, software libraries can be used to provide these callback functions in policies. If this is done, you won't have to register any callbacks.

 
< Prev   CONTENTS   Next >

Related topics