/*
* Licensed Materials - Property of IBM
*
* trousers - An open source TCG Software Stack
*
* (C) Copyright International Business Machines Corp. 2004-2007
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <errno.h>
#include "trousers/tss.h"
#include "trousers_types.h"
#include "trousers_types.h"
#include "tcs_tsp.h"
#include "tcs_utils.h"
#include "tcs_int_literals.h"
#include "capabilities.h"
#include "tcsps.h"
#include "tcslog.h"
TCS_CONTEXT_HANDLE InternalContext = 0x30000000;
TSS_UUID SRK_UUID = TSS_UUID_SRK;
void
LogData(char *string, UINT32 data)
{
#if 0
/* commenting out temporarily, logs getting too chatty */
LogDebug("%s %08x", string, data);
#endif
}
void
LogResult(char *string, TCPA_RESULT result)
{
#if 0
/* commenting out temporarily, logs getting too chatty */
LogDebug("Leaving %s with result 0x%08x", string, result);
#endif
}
UINT16
Decode_UINT16(BYTE * in)
{
UINT16 temp = 0;
temp = (in[1] & 0xFF);
temp |= (in[0] << 8);
return temp;
}
void
UINT64ToArray(UINT64 i, BYTE * out)
{
out[0] = (BYTE) ((i >> 56) & 0xFF);
out[1] = (BYTE) ((i >> 48) & 0xFF);
out[2] = (BYTE) ((i >> 40) & 0xFF);
out[3] = (BYTE) ((i >> 32) & 0xFF);
out[4] = (BYTE) ((i >> 24) & 0xFF);
out[5] = (BYTE) ((i >> 16) & 0xFF);
out[6] = (BYTE) ((i >> 8) & 0xFF);
out[7] = (BYTE) (i & 0xFF);
}
void
UINT32ToArray(UINT32 i, BYTE * out)
{
out[0] = (BYTE) ((i >> 24) & 0xFF);
out[1] = (BYTE) ((i >> 16) & 0xFF);
out[2] = (BYTE) ((i >> 8) & 0xFF);
out[3] = (BYTE) (i & 0xFF);
}
void
UINT16ToArray(UINT16 i, BYTE * out)
{
out[0] = (BYTE) ((i >> 8) & 0xFF);
out[1] = (BYTE) (i & 0xFF);
}
UINT32
Decode_UINT32(BYTE * y)
{
UINT32 x = 0;
x = y[0];
x = ((x << 8) | (y[1] & 0xFF));
x = ((x << 8) | (y[2] & 0xFF));
x = ((x << 8) | (y[3] & 0xFF));
return x;
}
UINT64
Decode_UINT64(BYTE *y)
{
UINT64 x = 0;
x = y[0];
x = ((x << 8) | (y[1] & 0xFF));
x = ((x << 8) | (y[2] & 0xFF));
x = ((x << 8) | (y[3] & 0xFF));
x = ((x << 8) | (y[4] & 0xFF));
x = ((x << 8) | (y[5] & 0xFF));
x = ((x << 8) | (y[6] & 0xFF));
x = ((x << 8) | (y[7] & 0xFF));
return x;
}
void
LoadBlob_UINT64(UINT64 *offset, UINT64 in, BYTE * blob)
{
if (blob)
UINT64ToArray(in, &blob[*offset]);
*offset += sizeof(UINT64);
}
void
LoadBlob_UINT32(UINT64 *offset, UINT32 in, BYTE * blob)
{
if (blob)
UINT32ToArray(in, &blob[*offset]);
*offset += sizeof(UINT32);
}
void
LoadBlob_UINT16(UINT64 *offset, UINT16 in, BYTE * blob)
{
if (blob)
UINT16ToArray(in, &blob[*offset]);
*offset += sizeof(UINT16);
}
void
UnloadBlob_UINT64(UINT64 *offset, UINT64 * out, BYTE * blob)
{
if (out)
*out = Decode_UINT64(&blob[*offset]);
*offset += sizeof(UINT64);
}
void
UnloadBlob_UINT32(UINT64 *offset, UINT32 * out, BYTE * blob)
{
if (out)
*out = Decode_UINT32(&blob[*offset]);
*offset += sizeof(UINT32);
}
void
UnloadBlob_UINT16(UINT64 *offset, UINT16 * out, BYTE * blob)
{
if (out)
*out = Decode_UINT16(&blob[*offset]);
*offset += sizeof(UINT16);
}
void
LoadBlob_BYTE(UINT64 *offset, BYTE data, BYTE * blob)
{
if (blob)
blob[*offset] = data;
(*offset)++;
}
void
UnloadBlob_BYTE(UINT64 *offset, BYTE * dataOut, BYTE * blob)
{
if (dataOut)
*dataOut = blob[*offset];
(*offset)++;
}
void
LoadBlob_BOOL(UINT64 *offset, TSS_BOOL data, BYTE * blob)
{
if (blob)
blob[*offset] = data;
(*offset)++;
}
void
UnloadBlob_BOOL(UINT64 *offset, TSS_BOOL *dataOut, BYTE * blob)
{
if (dataOut)
*dataOut = blob[*offset];
(*offset)++;
}
void
LoadBlob(UINT64 *offset, UINT32 size, BYTE *container, BYTE *object)
{
if (container)
memcpy(&container[*offset], object, size);
(*offset) += (UINT64) size;
}
void
UnloadBlob(UINT64 *offset, UINT32 size, BYTE *container, BYTE *object)
{
if (object)
memcpy(object, &container[*offset], size);
(*offset) += (UINT64) size;
}
void
LoadBlob_Header(UINT16 tag, UINT32 paramSize, UINT32 ordinal, BYTE * blob)
{
UINT16ToArray(tag, &blob[0]);
LogData("Header Tag:", tag);
UINT32ToArray(paramSize, &blob[2]);
LogData("Header ParamSize:", paramSize);
UINT32ToArray(ordinal, &blob[6]);
LogData("Header Ordinal:", ordinal);
#if 0
LogInfo("Blob's TPM Ordinal: 0x%x", ordinal);
#endif
}
#ifdef TSS_DEBUG
TSS_RESULT
LogUnloadBlob_Header(BYTE * blob, UINT32 * size, char *file, int line)
{
TSS_RESULT result;
UINT16 temp = Decode_UINT16(blob);
LogData("UnloadBlob_Tag:", (temp));
*size = Decode_UINT32(&blob[2]);
LogData("UnloadBlob_Header, size:", *size);
LogData("UnloadBlob_Header, returnCode:", Decode_UINT32(&blob[6]));
if ((result = Decode_UINT32(&blob[6]))) {
LogTPMERR(result, file, line);
}
return result;
}
#else
TSS_RESULT
UnloadBlob_Header(BYTE * blob, UINT32 * size)
{
UINT16 temp = Decode_UINT16(blob);
LogData("UnloadBlob_Tag:", (temp));
*size = Decode_UINT32(&blob[2]);
LogData("UnloadBlob_Header, size:", *size);
LogData("UnloadBlob_Header, returnCode:", Decode_UINT32(&blob[6]));
return Decode_UINT32(&blob[6]);
}
#endif
void
LoadBlob_Auth(UINT64 *offset, BYTE * blob, TPM_AUTH * auth)
{
LoadBlob_UINT32(offset, auth->AuthHandle, blob);
LoadBlob(offset, TCPA_NONCE_SIZE, blob, auth->NonceOdd.nonce);
LoadBlob_BOOL(offset, auth->fContinueAuthSession, blob);
LoadBlob(offset, TCPA_AUTHDATA_SIZE, blob, (BYTE *)&auth->HMAC);
}
void
UnloadBlob_Auth(UINT64 *offset, BYTE * blob, TPM_AUTH * auth)
{
if (!auth) {
UnloadBlob(offset, TCPA_NONCE_SIZE, blob, NULL);
UnloadBlob_BOOL(offset, NULL, blob);
UnloadBlob(offset, TCPA_DIGEST_SIZE, blob, NULL);
return;
}
UnloadBlob(offset, TCPA_NONCE_SIZE, blob, auth->NonceEven.nonce);
UnloadBlob_BOOL(offset, &auth->fContinueAuthSession, blob);
UnloadBlob(offset, TCPA_DIGEST_SIZE, blob, (BYTE *)&auth->HMAC);
}
void
UnloadBlob_VERSION(UINT64 *offset, BYTE *blob, TPM_VERSION *out)
{
if (!out) {
*offset += (sizeof(BYTE) * 4);
return;
}
UnloadBlob_BYTE(offset, &out->major, blob);
UnloadBlob_BYTE(offset, &out->minor, blob);
UnloadBlob_BYTE(offset, &out->revMajor, blob);
UnloadBlob_BYTE(offset, &out->revMinor, blob);
}
void
LoadBlob_VERSION(UINT64 *offset, BYTE *blob, TPM_VERSION *ver)
{
LoadBlob_BYTE(offset, ver->major, blob);
LoadBlob_BYTE(offset, ver->minor, blob);
LoadBlob_BYTE(offset, ver->revMajor, blob);
LoadBlob_BYTE(offset, ver->revMinor, blob);
}
void
UnloadBlob_TCPA_VERSION(UINT64 *offset, BYTE *blob, TCPA_VERSION *out)
{
if (!out) {
*offset += (sizeof(BYTE) * 4);
return;
}
UnloadBlob_BYTE(offset, &out->major, blob);
UnloadBlob_BYTE(offset, &out->minor, blob);
UnloadBlob_BYTE(offset, &out->revMajor, blob);
UnloadBlob_BYTE(offset, &out->revMinor, blob);
}
void
LoadBlob_TCPA_VERSION(UINT64 *offset, BYTE *blob, TCPA_VERSION *ver)
{
LoadBlob_BYTE(offset, ver->major, blob);
LoadBlob_BYTE(offset, ver->minor, blob);
LoadBlob_BYTE(offset, ver->revMajor, blob);
LoadBlob_BYTE(offset, ver->revMinor, blob);
}
TSS_RESULT
UnloadBlob_KEY_PARMS(UINT64 *offset, BYTE *blob, TCPA_KEY_PARMS *keyParms)
{
if (!keyParms) {
UINT32 parmSize;
UnloadBlob_UINT32(offset, NULL, blob);
UnloadBlob_UINT16(offset, NULL, blob);
UnloadBlob_UINT16(offset, NULL, blob);
UnloadBlob_UINT32(offset, &parmSize, blob);
if (parmSize > 0)
UnloadBlob(offset, parmSize, blob, NULL);
return TSS_SUCCESS;
}
UnloadBlob_UINT32(offset, &keyParms->algorithmID, blob);
UnloadBlob_UINT16(offset, &keyParms->encScheme, blob);
UnloadBlob_UINT16(offset, &keyParms->sigScheme, blob);
UnloadBlob_UINT32(offset, &keyParms->parmSize, blob);
if (keyParms->parmSize == 0)
keyParms->parms = NULL;
else {
keyParms->parms = malloc(keyParms->parmSize);
if (keyParms->parms == NULL) {
LogError("malloc of %u bytes failed.", keyParms->parmSize);
keyParms->parmSize = 0;
return TCSERR(TSS_E_OUTOFMEMORY);
}
UnloadBlob(offset, keyParms->parmSize, blob, keyParms->parms);
}
return TSS_SUCCESS;
}
void
UnloadBlob_KEY_FLAGS(UINT64 *offset, BYTE *blob, TCPA_KEY_FLAGS *flags)
{
if (!flags) {
UnloadBlob_UINT32(offset, NULL, blob);
return;
}
UnloadBlob_UINT32(offset, flags, blob);
}
TSS_RESULT
UnloadBlob_CERTIFY_INFO(UINT64 *offset, BYTE *blob, TCPA_CERTIFY_INFO *certify)
{
TSS_RESULT rc;
if (!certify) {
TPM_VERSION version;
UINT32 size;
UnloadBlob_VERSION(offset, blob, &version);
UnloadBlob_UINT16(offset, NULL, blob);
UnloadBlob_KEY_FLAGS(offset, blob, NULL);
UnloadBlob_BOOL(offset, NULL, blob);
if ((rc = UnloadBlob_KEY_PARMS(offset, blob, NULL)))
return rc;
UnloadBlob(offset, TCPA_DIGEST_SIZE, blob, NULL);
UnloadBlob(offset, TCPA_NONCE_SIZE, blob, NULL);
UnloadBlob_BOOL(offset, NULL, blob);
UnloadBlob_UINT32(offset, &size, blob);
if (size > 0)
UnloadBlob(offset, size, blob, NULL);
if (Decode_UINT16((BYTE *) &version) == TPM_TAG_CERTIFY_INFO2){
/* This is a TPM_CERTIFY_INFO2 structure. */
/* Read migrationAuthority. */
UnloadBlob_UINT32(offset, &size, blob);
if (size > 0)
UnloadBlob(offset, size, blob, NULL);
}
return TSS_SUCCESS;
}
UnloadBlob_VERSION(offset, blob, (TPM_VERSION *)&certify->version);
UnloadBlob_UINT16(offset, &certify->keyUsage, blob);
UnloadBlob_KEY_FLAGS(offset, blob, &certify->keyFlags);
UnloadBlob_BOOL(offset, (TSS_BOOL *)&certify->authDataUsage, blob);
if ((rc = UnloadBlob_KEY_PARMS(offset, blob, &certify->algorithmParms)))
return rc;
UnloadBlob(offset, TCPA_DIGEST_SIZE, blob, certify->pubkeyDigest.digest);
UnloadBlob(offset, TCPA_NONCE_SIZE, blob, certify->data.nonce);
UnloadBlob_BOOL(offset, (TSS_BOOL *)&certify->parentPCRStatus, blob);
UnloadBlob_UINT32(offset, &certify->PCRInfoSize, blob);
if (certify->PCRInfoSize > 0) {
certify->PCRInfo = (BYTE *)malloc(certify->PCRInfoSize);
if (certify->PCRInfo == NULL) {
LogError("malloc of %u bytes failed.", certify->PCRInfoSize);
certify->PCRInfoSize = 0;
free(certify->algorithmParms.parms);
certify->algorithmParms.parms = NULL;
certify->algorithmParms.parmSize = 0;
return TCSERR(TSS_E_OUTOFMEMORY);
}
UnloadBlob(offset, certify->PCRInfoSize, blob, certify->PCRInfo);
} else {
certify->PCRInfo = NULL;
}
if (Decode_UINT16((BYTE *) &certify->version) == TPM_TAG_CERTIFY_INFO2){
/* This is a TPM_CERTIFY_INFO2 structure. */
/* Read migrationAuthority. */
UINT32 size;
UnloadBlob_UINT32(offset, &size, blob);
if (size > 0)
UnloadBlob(offset, size, blob, NULL);
}
return TSS_SUCCESS;
}
TSS_RESULT
UnloadBlob_KEY_HANDLE_LIST(UINT64 *offset, BYTE *blob, TCPA_KEY_HANDLE_LIST *list)
{
UINT16 i;
if (!list) {
UINT16 size;
UnloadBlob_UINT16(offset, &size, blob);
*offset += (size * sizeof(UINT32));
return TSS_SUCCESS;
}
UnloadBlob_UINT16(offset, &list->loaded, blob);
if (list->loaded == 0) {
list->handle = NULL;
return TSS_SUCCESS;
}
list->handle = malloc(list->loaded * sizeof (UINT32));
if (list->handle == NULL) {
LogError("malloc of %zd bytes failed.", list->loaded * sizeof (UINT32));
list->loaded = 0;
return TCSERR(TSS_E_OUTOFMEMORY);
}
for (i = 0; i < list->loaded; i++)
UnloadBlob_UINT32(offset, &list->handle[i], blob);
return TSS_SUCCESS;
}
void
LoadBlob_DIGEST(UINT64 *offset, BYTE *blob, TPM_DIGEST *digest)
{
LoadBlob(offset, TPM_SHA1_160_HASH_LEN, blob, digest->digest);
}
void
UnloadBlob_DIGEST(UINT64 *offset, BYTE *blob, TPM_DIGEST *digest)
{
UnloadBlob(offset, TPM_SHA1_160_HASH_LEN, blob, digest->digest);
}
void
LoadBlob_NONCE(UINT64 *offset, BYTE *blob, TPM_NONCE *nonce)
{
LoadBlob(offset, TCPA_NONCE_SIZE, blob, nonce->nonce);
}
void
UnloadBlob_NONCE(UINT64 *offset, BYTE *blob, TPM_NONCE *nonce)
{
UnloadBlob(offset, TCPA_NONCE_SIZE, blob, nonce->nonce);
}
void
LoadBlob_AUTHDATA(UINT64 *offset, BYTE *blob, TPM_AUTHDATA *authdata)
{
LoadBlob(offset, TPM_SHA1_160_HASH_LEN, blob, authdata->authdata);
}
void
UnloadBlob_AUTHDATA(UINT64 *offset, BYTE *blob, TPM_AUTHDATA *authdata)
{
UnloadBlob(offset, TPM_SHA1_160_HASH_LEN, blob, authdata->authdata);
}