Chapter 8

Using TPM Keys

This chapter will walk you through creating a key hierarchy using TPM-generated keys. Depending on the environment (corporate, home, and so on), the code provided will most likely not be appropriate as is to suit your needs. However, this chapter will give an example of one way to implement each of the many types of operations you might like to do to create your own TPM key hierarchy.

The code in this chapter and the chapters that follow will make liberal use of external libraries to simplify tasks that the TSS doesn’t provide APIs for natively. This will include symmetric encryption, creating software keys, loading and writing keys to disk, and so on. Two choices for these external libraries are OpenSSL’s libcrypto and libgcrypt, each of which are released under different open source licenses. The examples that follow will use OpenSSL library calls. Before writing your own code, make sure you review the license for each available library and choose the one that suits you best.

Creating a Key Hierarchy

Creating a key hierarchy using TPM keys will usually involve creating a new tree structure under the SRK for use by an individual user. The structure of the tree should be such that each user has separate keys to sign and encrypt with, keys that are migratable and not migratable, and an identity key. The following code will implement just such a hierarchy, and in addition, show how to wrap an external software key with a TPM key, migrate a key using an external migration authority, and create a TPM maintenance archive. The code will show you how to do the following:

  • Seed the TPM’s random number generator.
  • Wrap an external software key with a TPM parent key.
  • Register keys in system and user persistent storage.
  • Create an Attestation Identity Key.
  • Lock keys to PCR values.
  • Sign keys with other keys.
  • Do TPM maintenance.
  • Migrate a key using a migration authority’s key.

Utility Functions

There are a few functions used through the sample code that are simple, but would be too lengthy to usefully be listed here. These functions will hopefully prove to be useful in building more complex trusted computing applications. First, we’ll walk through these functions, and then introduce the functions that build on them.

        char *strresult(TSS_RESULT);

strresult() takes a TSS_RESULT code and converts it to a character string. This function is most useful in providing informative error messages to the user.

        TSS_FLAG get_tss_key_size(unsigned int size);

get_tss_key_size() takes an RSA key size in bits and converts it to a TSS key size flag for passing to a Tspi_Context_CreateObject() call.

MyFunc_CreatePubKey() simplifies the multiple calls to the TSS needed to create a software TSS key object from an OpenSSL public key object. It takes an OpenSSL RSA key object handle and a padding type and returns the newly created TSS key handle. Keep in mind that the TPM is not involved in this function at all and that the manipulations of the hKey object are done entirely in software in the TSP library.

Listing 8.1. MyFunc_CreatePubKey

#include <stdio.h>

#include <openssl/rsa.h>
#include <openssl/err.h>

#include <tss/tss_error.h>
#include <tss/tss_defines.h>
#include <tss/tss_typedef.h>
#include <tss/tss_structs.h>
#include <tss/tspi.h>
TSS_RESULT
MyFunc_CreatePubKey(RSA *rsa, int padding, TSS_HKEY *hKey)
{
    TSS_RESULT result;
    UINT32 encScheme, sizeN, keySize;
    BYTE n[2048];

    switch (padding) {
        case RSA_PKCS1_PADDING:
            encScheme = TSS_ES_RSAESPKCSV15;
            break;
        case RSA_PKCS1_OAEP_PADDING:
            encScheme = TSS_ES_RSAESOAEP_SHA1_MGF1;
            break;
        case RSA_NO_PADDING:
            encScheme = TSS_ES_NONE;
            break;
        default:
            return TSS_E_INTERNAL_ERROR;
            break;
    }

    if ((keySize = get_tss_key_size(RSA_size(rsa) * 8)) == 0)
        return TSS_E_BAD_PARAMETER;

    /* Create the TSS key object */
    result = Tspi_Context_CreateObject(hContext,
                                       TSS_OBJECT_TYPE_RSAKEY,
                                       TSS_KEY_TYPE_LEGACY | keySize,
                                       hKey);
    if (result != TSS_SUCCESS) {
        LogError("Tspi_Context_CreateObject failed: %s",
                 strresult(result));
        return result;
    }

    /* Get the public 'n' value from the openssl key */
    if ((sizeN = BN_bn2bin(rsa->n, n)) <= 0) {
        LogError("BN_bn2bin failed");
        ERR_print_errors_fp(stdout); // Call OpenSSL's error function
        Tspi_Context_CloseObject(hContext, *hKey);
        return TSS_E_FAIL;
    }

    /* Set the public key data in the TSS object */
    result = Tspi_SetAttribData(*hKey, TSS_TSPATTRIB_KEY_BLOB,
                                TSS_TSPATTRIB_KEYBLOB_PUBLIC_KEY,
                                sizeN,n);
    if (result != TSS_SUCCESS) {
        LogError("Tspi_SetAttribData failed: %s", strresult(result));
        Tspi_Context_CloseObject(hContext, *hKey);
        return result;
    }

    /* Set the key's algorithm */
    result = Tspi_SetAttribUint32(*hKey, TSS_TSPATTRIB_KEY_INFO,
                                  TSS_TSPATTRIB_KEYINFO_ALGORITHM,
                                  TSS_ALG_RSA);
    if (result != TSS_SUCCESS) {
        LogError("Tspi_SetAttribUint32 failed: %s", strresult(result));
        Tspi_Context_CloseObject(hContext, *hKey);
        return result;
    }

    /* set the key's number of primes */
    result = Tspi_SetAttribUint32(*hKey, TSS_TSPATTRIB_RSAKEY_INFO,
                                  TSS_TSPATTRIB_KEYINFO_RSA_PRIMES, 2);
    if (result != TSS_SUCCESS) {
        LogError("Tspi_SetAttribUint32 failed: %s", strresult(result));
        Tspi_Context_CloseObject(hContext, *hKey);
        return result;
    }

    /* Set the key's encryption scheme */
    result = Tspi_SetAttribUint32(*hKey, TSS_TSPATTRIB_KEY_INFO,
                                  TSS_TSPATTRIB_KEYINFO_ENCSCHEME,
                                  encScheme);
    if (result != TSS_SUCCESS) {
        LogError("Tspi_SetAttribUint32 failed: %s", strresult(result));
        Tspi_Context_CloseObject(hContext, *hKey);
        return result;
    }

    return TSS_SUCCESS;
}

MyFunc_CreateTPMKey() makes all the calls to the TSS needed to create a new key. It takes a TSS handle to the new key’s parent key, a set of initialization flags that describe the new key, and a handle to a PCRs object that the new key will optionally be bound to. If the new key will require a password, the TSS will prompt the user for it using a GUI pop-up. This function relies on the default mode of operation to pop up a dialog box to prompt a user for a password when the new key’s creation requires one.

Listing 8.2. MyFunc_CreateTPMKey

#include <stdio.h>

#include <tss/tss_error.h>
#include <tss/tss_defines.h>
#include <tss/tss_typedef.h>
#include <tss/tss_structs.h>
#include <tss/tspi.h>

TSS_RESULT
MyFunc_CreateTPMKey(TSS_HKEY hParentKey,
                    TSS_FLAG initFlags,
                    TSS_HPCRS hPcrs,
                    TSS_HKEY *hKey)
{
    TSS_RESULT result;
    TSS_HPOLICY hPolicy;

    /* create the key object */
    result = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_RSAKEY,
                                       initFlags, hKey);
    if (result) {
        LogError("Tspi_Context_CreateObject failed: %s",
                 strresult(result));
        return result;
    }

    /* Get the policy object, implicitly created when we created the
     * key object */
    result = Tspi_GetPolicyObject(*hKey, TSS_POLICY_USAGE, &hPolicy);
    if (result) {
        LogError("Tspi_GetPolicyObject failed: %s", strresult(result));
        Tspi_Context_CloseObject(hContext, *hKey);
        return result;
    }

   /* If we're creating this key with no password, set the secret
    * mode so that the popup will be supressed */
   if (!(initFlags & TSS_KEY_AUTHORIZATION)) {
       result = Tspi_Policy_SetSecret(hPolicy, TSS_SECRET_MODE_NONE,
                                      0, NULL);
   }
   /* Make the call to the TPM to create the key */
   result = Tspi_Key_CreateKey(*hKey, hParentKey, hPcrs);
   if (result) {
       LogError("Tspi_Key_CreateKey failed: %s", strresult(result));
       Tspi_Context_CloseObject(hContext, *hKey);
       return result;
   }

   return TSS_SUCCESS;
}

MyFunc_WrapKey() provides a convenient interface to wrapping an OpenSSL-generated key with a TPM key. It takes a path to the OpenSSL key on disk, a TSS handle to the new key’s parent key, a set of initialization flags that describe the new key, and a handle to a PCRs object that the new key will optionally be bound to. If the new key will require a password, the TSS will prompt the user for it using a GUI pop-up. This function relies on the default mode of operation to pop up a dialog box to prompt a user for a password when the new key’s creation requires one.

Listing 8.3. MyFunc_WrapKey

#include <stdio.h>

#include <openssl/rsa.h>
#include <openssl/err.h>

#include <tss/tss_error.h>
#include <tss/tss_defines.h>
#include <tss/tss_typedef.h>
#include <tss/tss_structs.h>
#include <tss/tspi.h>

TSS_RESULT
MyFunc_WrapKey(char *path,
               TSS_HKEY hParentKey,
               TSS_FLAG initFlags,
               TSS_HPCRS hPcrs,
               TSS_HKEY *hKey)
{
    RSA           *rsa;
    UINT32        pubKeyLen;
    BYTE          *pubKey;
    TSS_RESULT    result;
    unsigned char n[2048], p[2048];
    int           sizeN, sizeP;
    UINT32        keySize;

    /* Read in the plaintext key from disk. */
    if ((rsa = openssl_read_key(path)) == NULL) {
         LogError("Failed opening OpenSSL key file!");
         return TSS_E_FAIL;
    }

    /* Pull the SRK's pub key into the hSRK object. Note that this is
     * not necessary for any key but the SRK. The SRK's pub key is not
     * stored in system persistent storage as other keys are. This
     * protects it from being loaded by unauthorized users who could
     * then use it to identify the machine from across the Internet. */
    result = Tspi_Key_GetPubKey(hSRK, &pubKeyLen, &pubKey);
    if (result) {
        LogError("Tspi_Key_GetPubKey failed: %s", strresult(result));
        RSA_free(rsa);
        return result;
    }

    /* Free here since the pubKey data is stored internally to the
     * hSRK object in addition to being returned above */
    Tspi_Context_FreeMemory(hContext, pubKey);

    /* convert the OpenSSL key's size in bits to a TSS key size flag
     * suitable for including in initFlags. */
    if ((keySize = get_tss_key_size(RSA_size(rsa) * 8)) == 0)
        return TSS_E_BAD_PARAMETER;

    /* create the TSS key object */
    result = Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_RSAKEY,
                                       keySize | initFlags, hKey);
    if (result != TSS_SUCCESS) {
        LogError("Tspi_Context_CreateObject failed: %s",
                 strresult(result));
        return result;
    }

    /* This function handles the OpenSSL calls to extract the public N
     * and private P, parts of the software RSA key. Both of these
     * components will be put into the wrapped TSS key object. */
    if (openssl_get_modulus_and_prime(rsa, &sizeN, n, &sizeP, p) != 0) {
        Tspi_Context_CloseObject(hContext, *hKey);
        *hKey = 0;
        return result;
    }

    /* set the public key data in the TSS object */
    result = Tspi_SetAttribData(*hKey, TSS_TSPATTRIB_KEY_BLOB,
                                TSS_TSPATTRIB_KEYBLOB_PUBLIC_KEY,
                                sizeN, n);
    if (result != TSS_SUCCESS) {
        LogError("Tspi_SetAttribData failed: %s", strresult(result));
        Tspi_Context_CloseObject(hContext, *hKey);
        *hKey = 0;
        return result;
    }

    /* set the private key data in the TSS object */
    result = Tspi_SetAttribData(*hKey, TSS_TSPATTRIB_KEY_BLOB,
                                TSS_TSPATTRIB_KEYBLOB_PRIVATE_KEY,
                                sizeP, p);
    if (result != TSS_SUCCESS) {
        LogError("Tspi_SetAttribData failed: %s", strresult(result));
        Tspi_Context_CloseObject(hContext, *hKey);
        *hKey = 0;
        return result;
    }

    /* Call the TSS to do the key wrapping */
    result = Tspi_Key_WrapKey(*hKey, hParentKey, hPcrs);
    if (result != TSS_SUCCESS) {
        LogError("Tspi_Key_WrapKey failed: %s", strresult(result));
        Tspi_Context_CloseObject(hContext, *hKey);
        *hKey = 0;
    }

    RSA_free(rsa);

    return result;
}

MyFunc_CreateAIK() creates an Attestation Identity Key. It takes a handle to the OpenSSL public key object of the Privacy CA and an identity label to bind the AIK to and returns a TSS handle to the new AIK, the size of the newly issued credential, and the credential itself. If the new key will require a password, the TSS will prompt the user for it using a GUI pop-up. This function relies on the default mode of operation to pop up a dialog box to prompt a user for a password when the new key’s creation requires one.

Given the complex process of creating an Attestation Identity Key, the interactions between the TSS application and the Privacy CA are presented here as function calls in the same process space as the application. At the time of this writing, no Privacy CA’s yet exist to handle the issuing of certificates based on TPM AIKs, so the implementation of a Privacy CA’s functionality in an application may prove to be useful in the short term.

Listing 8.4. MyFunc_CreateAIK

#include <stdio.h>

#include <openssl/rsa.h>
#include <openssl/err.h>

#include <tss/tss_error.h>
#include <tss/tss_defines.h>
#include <tss/tss_typedef.h>
#include <tss/tss_structs.h>
#include <tss/tspi.h>

TSS_RESULT
MyFunc_CreateAIK(RSA *PrivacyCA_rsa,
                 BYTE *label,
                 UINT32 labelLen,
                 TSS_HKEY *hAIKey,
                 UINT32 *credentialSize,
                 BYTE **credential)
{
    TSS_FLAG            initFlags;
    TSS_HKEY            hCAKey;
    TSS_RESULT          result;
    BYTE                *identityReqBlob;
    UINT32              ulIdentityReqBlobLen;
    UINT32              utilityBlobSize, credLen;
    UINT16              offset;
    TCPA_IDENTITY_REQ   identityReq;
    TCPA_IDENTITY_PROOF identityProof;
    TCPA_SYMMETRIC_KEY  symKey;
    BYTE                utilityBlob[2048], *cred;
    int                 padding = RSA_PKCS1_OAEP_PADDING;
    UINT32              asymBlobSize, symBlobSize;
    BYTE                *asymBlob, *symBlob;

    initFlags       = TSS_KEY_TYPE_IDENTITY | TSS_KEY_SIZE_2048 |
                      TSS_KEY_VOLATILE | TSS_KEY_NO_AUTHORIZATION |
                      TSS_KEY_NOT_MIGRATABLE;

    /* Create Identity Key Object */
    result = Tspi_Context_CreateObject(hContext,
                                       TSS_OBJECT_TYPE_RSAKEY,
                                       initFlags, hAIKey);
    if (result != TSS_SUCCESS) {
        LogError("Tspi_Context_CreateObject failed: %s",
                 strresult(result));
        return result;
    }

    /* Convert the CA's key from an OpenSSL to a TSS key object */
    if ((result = MyFunc_CreatePubKey(PrivacyCA_rsa, RSA_PKCS1_PADDING,
                                      &hCAKey))) {
        LogError("MyFunc_CreatePubKey failed: %s", strresult(result));
        return result;
    }

    /* Create an Identity Request blob to send to the Privacy CA */
    result = Tspi_TPM_CollateIdentityRequest(hTPM, hSRK, hCAKey,
                                             labelLen, label,
                                             *hAIKey, TSS_ALG_AES,
                                             &ulIdentityReqBlobLen,
                                             &identityReqBlob);
    if (result != TSS_SUCCESS) {
        LogError("Tspi_TPM_CollateIdentityRequest failed: %s",
                 strresult(result));
        return result;
    }

    /* Unload the TCPA_IDENTITY_REQ blobs created by the TPM. This
     * function will take a binary, flattened TPM_IDENTITY_REQ structure
     * and expand it into an unflattened version, calling malloc when
     * necessary. */
    offset = 0;
    if ((result = UnloadBlob_IDENTITY_REQ(&offset, identityReqBlob,
                                          &identityReq))) {
        LogError("UnloadBlob_IDENTITY_REQ failed: %s", strresult(result));
        return result;
    }

    /* Decrypt the asymmetric blob, which contains the symmetric key used
     * to encrypt the symmetric blob. */
    if (RSA_private_decrypt(identityReq.asymSize, identityReq.asymBlob,
                            utilityBlob, PrivacyCA_rsa, padding) <= 0) {
        LogError("RSA_private_decrypt failed");
        ERR_print_errors_fp(stderr);
        return TSS_E_FAIL;

    offset = 0;
    if ((result = UnloadBlob_SYMMETRIC_KEY(&offset, utilityBlob,
                                           &symKey))) {
        LogError("UnloadBlob_SYMMETRIC_KEY failed: %s",
                 strresult(result));
        return result;
    }

    /* Verify that we're using the algorithm as specified by the TPM */
    switch (symKey.algId) {
        case TCPA_ALG_AES:
            break;
        default:
            LogError("symmetric blob encrypted with an unknown cipher");
            return result;
            break;
    }

    utilityBlobSize = sizeof(utilityBlob);
    if ((result = openssl_decrypt_ECB(TSS_ALG_AES, symKey.data,
                                      identityReq.symBlob,
                                      identityReq.symSize,
                                      utilityBlob,
                                      &utilityBlobSize))) {
        LogError("openssl_decrypt_ECB failed: %s", strresult(result));
        return result;
    }

    offset = 0;
    if ((result = UnloadBlob_IDENTITY_PROOF(&offset, utilityBlob,
                                            &identityProof))) {
         LogError("UnloadBlob_IDENTITY_PROOF failed: %s",
                  strresult(result));
         return result;
    }

    /* Allow the Privacy CA to verify the identity binding */
    if ((result = PrivacyCA_verify_identity_binding(hContext, hTPM,
                                                    hCAKey, *hAIKey,
                                                    &identityProof))) {
         LogError("Identity Binding signature doesn't match!");
         LogError("PrivacyCA_verify_identity_binding failed: %s",
                  strresult(result));
         return result;
    }

    /* Binding is verified, load the identity key into the TPM */
    if ((result = Tspi_Key_LoadKey(*hAIKey, hSRK))) {
        LogError("Tspi_Key_LoadKey failed: %s", strresult(result));
        return result;
    }

    if ((result = PrivacyCA_create_credential(hContext, hTPM, *hAIKey,
                                              &asymBlobSize, &asymBlob,
                                              &symBlobSize, &symBlob))) {
        LogError("PrivacyCA_create_credential failed: %s",
                 strresult(result));
        return result;
    }

    /* Activate the TPM identity, receiving back the decrypted credential,
     * which was issued by the Privacy CA. */
    result = Tspi_TPM_ActivateIdentity(hTPM, *hAIKey, asymBlobSize,
                                       asymBlob, symBlobSize,
                                       symBlob, &credLen, &cred);
    if (result) {
        LogError("Tspi_TPM_ActivateIdentity failed: %s",
                 strresult(result));
        return result;
    }
    *credential = cred;
    *credentialSize = credLen;
    return TSS_SUCCESS;
}

MyFunc_GetRandom() reads data from the system’s random device. It takes the numbers of bytes to read from the device and a buffer to write it to. This function is used to gather random data to feed to the TPM’s random number generator for entropy.

Listing 8.5. MyFunc_GetRandom

TSS_RESULT
MyFunc_GetRandom(UINT32 size, BYTE *data)
{
    FILE *f = NULL;

    f = fopen(RANDOM_DEVICE, "r");
    if (f == NULL) {
        LogError("open of %s failed: %s", RANDOM_DEVICE,
                 strerror(errno));
        return TSS_E_INTERNAL_ERROR;
    }

    if (fread(data, size, 1, f) == 0) {
        LogError("fread of %s failed: %s", RANDOM_DEVICE,
                 strerror(errno));
        fclose(f);
        return TSS_E_INTERNAL_ERROR;
    }

    fclose(f);

    return TSS_SUCCESS;
}

MyFunc_CreateKeyHierarchy() builds on the previous utility functions to give an example of how to create a full-featured TPM key hierarchy. Where appropriate, software keys are read from disk using an OpenSSL interface. Additional features of the TSS are used as examples, such as binding one of the keys to a current PCR value and signing two keys using the created AIK. In some cases, the result of the operation (such as the returned key signature) is discarded, where in an actual implementation, the result would be stored somewhere. The use of this additional data is left as an exercise for the reader. Please note that error checking has been left out of the code to save space.

Listing 8.6. MyFunc_CreateKeyHierarchy

int
MyFunc_CreateKeyHierarchy()
{
    TSS_HPOLICY    hSRKPolicy;
    BYTE           entropyData[ENTROPY_SIZE];
    BYTE           secretData[] = TSS_WELL_KNOWN_SECRET;
    TSS_FLAG       initFlags;
    TSS_UUID       swMigKeyUuid, systemMigKeyUuid;
    TSS_HKEY       hUserSWMigKey, hSystemMigKey, hKeyPcrs;
    TSS_HKEY       hMigKeyBind, hSealingKey, hMAKey;
    TSS_HKEY       hAIKey, hMtncKey;
    TSS_HPOLICY    hUserSWMigKeyPolicy;
    TSS_HPCRS      hPcrs;

    UINT32         pcrLen;
    BYTE           *pcrValue;

    TSS_RESULT     result;
    TSS_BOOL       tpmState;

    BYTE           userPass[MAX_PASS_LEN];
    BYTE           *random;

    UINT32         aik_label_len, credSize;
    BYTE           *aik_label, *cred;
    TSS_UUID       AIKUuid;

    TSS_VALIDATION validationData;

    BYTE           *ticket;
    UINT32         ticketLen;

    BYTE           *mtncBlob, *migBlob;
    UINT32         mtncBlobLen, migBlobLen;

    /* OpenSSL objects */
    RSA *ca_rsa, *migration_pub_rsa, *maintenance_pub_rsa;

    /* Make any necessary setup calls to OpenSSL */
    init_external_libraries();

    Tspi_Context_Create(&hContext);

    Tspi_Context_Connect(hContext, NULL);

    Tspi_Context_GetTpmObject(hContext, &hTPM);


    /* Add entropy to the TPM's random number generator from the
     * system's random device */
    MyFunc_GetRandom(ENTROPY_SIZE, entropyData);

    Tspi_TPM_StirRandom(hTPM, ENTROPY_SIZE, entropyData);

    /* Load the SRK from storage in the System Persistent Store */
    Tspi_Context_LoadKeyByUUID(hContext, TSS_PS_TYPE_SYSTEM, SRK_UUID,
                               &hSRK);

    /* Set the SRK's password since it will be referenced below */
    Tspi_GetPolicyObject(hContext, TSS_POLICY_USAGE, &hSRKPolicy);

    Tspi_Policy_SetSecret(hSRKPolicy, TSS_SECRET_MODE_SHA1,
                          sizeof(secretData) + 1, secretData);

    /* Wrap the software generated key with the SRK's public key.
     * initFlags is set to make this key a migratable storage key
     * that requires a password. */

    initFlags = TSS_KEY_TYPE_STORAGE | TSS_KEY_MIGRATABLE |
                TSS_KEY_AUTHORIZATION;

    MyFunc_WrapKey(SOFTWARE_KEY_FILE_PATH, hSRK, initFlags, 0,
                   &hUserSWMigKey)));

    /* Register the wrapped key in user persistent storage */
    Tspi_Context_RegisterKey(hContext, hUserSWMigKey,
                             TSS_PS_TYPE_USER, swMigKeyUuid,
                             TSS_PS_TYPE_SYSTEM, SRK_UUID);

    Tspi_GetPolicyObject(hUserSWMigKey, TSS_POLICY_USAGE,
                         &hUserSWMigKeyPolicy);


    /* Call an OpenSSL routine to get a password from the user for the
     * wrapped key. This approach will be useful when a GUI environment
     * isn't available to receive a password from the user */

    EVP_read_pw_string(userPass, MAX_PASS_LEN, "Password: ", 0);

    Tspi_Policy_SetSecret(hUserSWMigKeyPolicy, TSS_SECRET_MODE_PLAIN,
                          strlen(userPass), userPass);

    /* Zero-out the password entered, keeping it in memory for the
     * smallest amount of time possible */
    memset(userPass, 0, MAX_PASS_LEN);


    /* create a non-migratable signing key not bound to any PCRs */
    initFlags = TSS_KEY_TYPE_SIGNING | TSS_KEY_SIZE_2048 |
                TSS_KEY_NOT_MIGRATABLE;

    /* Pass '0' as the handle to the PCRs object, to keep the TSS from
     * binding this key to any PCRs */
    MyFunc_CreateTPMKey(hSRK, initFlags, 0, &hSystemMigKey);

    /* Register the key in system persistent storage */
    Tspi_Context_RegisterKey(hContext, hSystemMigKey, TSS_PS_TYPE_SYSTEM,
                             systemMigKeyUuid, TSS_PS_TYPE_SYSTEM,
                             SRK_UUID);


    /* Create a PCR composite object with the current values of PCRs
     * 4 and 5 */
    Tspi_Context_CreateObject(hContext, TSS_OBJECT_TYPE_PCRS, 0, &hPcrs);

    Tspi_TPM_PcrRead(hTPM, 4, &pcrLen, &pcrValue);

    Tspi_PcrComposite_SetPcrValue(hPcrs, 4, pcrLen, pcrValue);

    /* Free the pcrValue data returned from the Tspi_TPM_PcrRead()
     * function. At this point, the value of the PCR register has been
     * copied into the PCR object hPcrs by the TSS. */
    Tspi_Context_FreeMemory(hContext, pcrValue);

    Tspi_TPM_PcrRead(hTPM, 5, &pcrLen, &pcrValue);

    Tspi_PcrComposite_SetPcrValue(hPcrs, 5, pcrLen, pcrValue);

    Tspi_Context_FreeMemory(hContext, pcrValue);


    /* Create a non-migratable signing key bound to PCRs 4 and 5 */
    initFlags = TSS_KEY_TYPE_SIGNING | TSS_KEY_SIZE_2048 |
                TSS_KEY_NOT_MIGRATABLE;

    /* Passing the hPcrs handle here ensures the new key is bound to
     * PCRs 4 and 5. If the value of those PCRs changes, the key will
     * become unusable until a platform reset can return them to their
     * present state */

    MyFunc_CreateTPMKey(hSRK, initFlags, hPcrs, &hKeyPcrs);

   /* Create an Attestation Identity Key */

   /* Read in the Privacy CA's key from disk */
   ca_rsa = openssl_read_key(CA_KEY_FILE_PATH);

   aik_label = "My Identity Label";
   aik_label_len = strlen(aik_label) + 1;

   /* Create the AIK */
   MyFunc_CreateAIK(ca_rsa, aik_label, aik_label_len, &hAIKey,
                    &credSize, &cred);

   /* Write the credential to disk here. Storing this credential should
    * be part of maintaining an individual user's TPM-based key
    * hierarchy */

   Tspi_Context_FreeMemory(hContext, cred);

   /* Register the AIK in system persistent storage */
   Tspi_Context_RegisterKey(hContext, hAIKey, TSS_PS_TYPE_SYSTEM,
                            AIKUuid, TSS_PS_TYPE_SYSTEM, SRK_UUID);


   /* Sign a key with the AIK. Initialize the validation data parameter
    * to Tspi_Key_CertifyKey in order to verify it later. */
   Tspi_TPM_GetRandom(hTPM, sizeof(TCPA_NONCE), &random);

   memcpy(&validationData.ExternalData, random, sizeof(TCPA_NONCE));
   Tspi_Context_FreeMemory(hContext, random);

   /* Sign hSystemMigKey with the AIK */
   Tspi_Key_CertifyKey(hSystemMigKey, hAIKey, &validationData);

   /* Here, use the data returned in validationData to verify that the
    * returned key signature is correct.  Then, store the signature in
    * a place of your choosing */

   Tspi_Context_FreeMemory(hContext, validationData.ValidationData);
   Tspi_Context_FreeMemory(hContext, validationData.Data);


   /* Sign another key with the AIK */
   Tspi_TPM_GetRandom(hTPM, sizeof(TCPA_NONCE), &random);

   memcpy(&validationData.ExternalData, random, sizeof(TCPA_NONCE));
   Tspi_Context_FreeMemory(hContext, random);

   /* Sign hKeyPcrs with the AIK */
   Tspi_Key_CertifyKey(hKeyPcrs, hAIKey, &validationData);

   /* Here, use the data returned in validationData to verify that the
    * returned key signature is correct.  Then, store the signature in
    * a place of your choosing */

   Tspi_Context_FreeMemory(hContext, validationData.ValidationData);
   Tspi_Context_FreeMemory(hContext, validationData.Data);


   /* Create a binding key underneath the migratable storage key we
    * wrapped above. Note that this key *must* be migratable, since
    * its parent is migratable. */
   initFlags = TSS_KEY_TYPE_BIND | TSS_KEY_SIZE_2048 |
               TSS_KEY_MIGRATABLE;

   MyFunc_CreateTPMKey(hUserSWMigKey, initFlags, 0, &hMigKeyBind);


   /* Create a storage (sealing) key under the SRK */
   initFlags = TSS_KEY_TYPE_STORAGE | TSS_KEY_SIZE_2048 |
               TSS_KEY_NOT_MIGRATABLE;

   MyFunc_CreateTPMKey(hSRK, initFlags, 0, &hSealingKey);


   /* Migrate a key using a migration authority */

   /* Read in the migration authority's public key from a file */
   migration_pub_rsa = openssl_read_key(MIGRATION_KEY_FILE_PATH);

   MyFunc_CreatePubKey(migration_pub_rsa, RSA_PKCS1_PADDING, &hMAKey);

   RSA_free(migration_pub_rsa);

   /* Create a migration ticket using the MA's key */
   Tspi_TPM_AuthorizeMigrationTicket(hTPM, hMAKey, TSS_MS_REWRAP,
                                     &ticketLen, &ticket);

   /* Use the migration ticket to migrate hSystemMigKey into a migration
    * blob. */
   Tspi_Key_CreateMigrationBlob(hSystemMigKey, hSRK, ticketLen, ticket,
                                0, NULL, &migBlobLen, &migBlob);

   /* migBlob can now be migrated to another TPM */

   Tspi_Context_FreeMemory(hContext, ticket);
   Tspi_Context_FreeMemory(hContext, migBlob);


   /* Can this TPM do maintenance? */
   Tspi_TPM_GetStatus(hTPM, TSS_TPMSTATUS_ALLOWMAINTENANCE, &tpmState);
   if (result != TSS_SUCCESS) {
       LogError("Tspi_TPM_GetStatus failed: %s", strresult(result));
       return result;
   } else if (tpmState == TRUE) {

       /* This TPM can do maintenance, let's create a maintenance
        * archive */

       /* Read in the migration authority's public key from file */
       maintenance_pub_rsa =
                     openssl_read_key(MAINTENANCE_KEY_FILE_PATH);

       MyFunc_CreatePubKey(maintenance_pub_rsa, RSA_PKCS1_PADDING,
                           &hMtncKey);

       /* Load the manufacturer's maintenance pub key into the TPM */
       Tspi_TPM_LoadMaintenancePubKey(hTPM, hMtncKey, NULL);
       Tspi_TPM_CreateMaintenanceArchive(hTPM, FALSE, 0, NULL,
                                         &mtncBlobLen, &mtncBlob);

       /* Keep even the owner from doing maintenance until the TPM
        * changes ownership */
       Tspi_TPM_KillMaintenanceFeature(hTPM);

       Tspi_Context_FreeMemory(hContext, mtncBlob);
       RSA_free(maintenance_pub_rsa);
   }


   /* Flush secrets associated with this policy. This can be called
    * for any policy that may contain secret data, including the TPM
    * object's policy to clear the owner secret. */
   Tspi_Policy_FlushSecret(hUserSWMigKeyPolicy);


   Tspi_Context_CloseObject(hContext, hUserSWMigKey);

   /* Free all memory associated with the context */
   Tspi_Context_FreeMemory(hContext, NULL);

   Tspi_Context_Close(hContext);

   return TSS_SUCCESS;
}

Summary

This chapter contained example code to perform many of the tasks needed to create a TPM key hierarchy using TSS calls and helper functions. You can use the example code to do the following:

  • Seed the TPM’s random number generator.
  • Wrap an external software key with a TPM parent key.
  • Register keys in system and user persistent storage.
  • Create an Attestation Identity Key.
  • Lock keys to PCR values.
  • Sign keys with other keys.
  • Do TPM maintenance.
  • Migrate a key using a migration authority’s key.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.218.5.12