blob: 5764fb08dd09597cc7bc6a3f17ff8c2f98937a05 [file] [log] [blame]
/*
* Licensed Materials - Property of IBM
*
* trousers - An open source TCG Software Stack
*
* (C) Copyright International Business Machines Corp. 2007
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "trousers/tss.h"
#include "trousers_types.h"
#include "tcs_tsp.h"
#include "tcs_utils.h"
#include "tcs_int_literals.h"
#include "capabilities.h"
#include "tcslog.h"
#include "tcsps.h"
#include "req_mgr.h"
TSS_RESULT
TCSP_EstablishTransport_Internal(TCS_CONTEXT_HANDLE hContext,
UINT32 ulTransControlFlags,
TCS_KEY_HANDLE hEncKey,
UINT32 ulTransSessionInfoSize,
BYTE* rgbTransSessionInfo,
UINT32 ulSecretSize,
BYTE* rgbSecret,
TPM_AUTH* pEncKeyAuth,
TPM_MODIFIER_INDICATOR* pbLocality,
TCS_HANDLE* hTransSession,
UINT32* ulCurrentTicks,
BYTE** prgbCurrentTicks,
TPM_NONCE* pTransNonce)
{
TSS_RESULT result;
UINT32 paramSize;
UINT64 offset;
TPM_KEY_HANDLE keySlot = TPM_KH_TRANSPORT;
BYTE txBlob[TSS_TPM_TXBLOB_SIZE];
if ((result = ctx_verify_context(hContext)))
return result;
if (ulTransControlFlags == TSS_TCSATTRIB_TRANSPORT_EXCLUSIVE) {
if ((result = ctx_req_exclusive_transport(hContext)))
return result;
}
if (pEncKeyAuth) {
if ((result = auth_mgr_check(hContext, &pEncKeyAuth->AuthHandle)))
return result;
}
/* if hEncKey is set to TPM_KH_TRANSPORT, that's the signal to the TPM that this will be
* an unencrypted transport session, so we don't need to check that its loaded */
if (hEncKey != TPM_KH_TRANSPORT) {
if ((result = ensureKeyIsLoaded(hContext, hEncKey, &keySlot)))
return result;
}
offset = TSS_TPM_TXBLOB_HDR_LEN;
LoadBlob_UINT32(&offset, keySlot, NULL);
LoadBlob(&offset, ulTransSessionInfoSize, NULL, rgbTransSessionInfo);
LoadBlob_UINT32(&offset, ulSecretSize, NULL);
LoadBlob(&offset, ulSecretSize, NULL, rgbSecret);
if (pEncKeyAuth) {
LoadBlob_Auth(&offset, NULL, pEncKeyAuth);
}
if (offset > TSS_TPM_TXBLOB_SIZE) {
return TCSERR(TSS_E_BAD_PARAMETER);
}
offset = TSS_TPM_TXBLOB_HDR_LEN;
LoadBlob_UINT32(&offset, keySlot, txBlob);
LoadBlob(&offset, ulTransSessionInfoSize, txBlob, rgbTransSessionInfo);
LoadBlob_UINT32(&offset, ulSecretSize, txBlob);
LoadBlob(&offset, ulSecretSize, txBlob, rgbSecret);
if (pEncKeyAuth) {
LoadBlob_Auth(&offset, txBlob, pEncKeyAuth);
LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, offset, TPM_ORD_EstablishTransport,
txBlob);
} else
LoadBlob_Header(TPM_TAG_RQU_COMMAND, offset, TPM_ORD_EstablishTransport, txBlob);
if ((result = req_mgr_submit_req(txBlob)))
goto done;
if ((result = UnloadBlob_Header(txBlob, &paramSize))) {
LogDebugFn("UnloadBlob_Header failed: rc=0x%x", result);
goto done;
}
offset = TSS_TPM_TXBLOB_HDR_LEN;
UnloadBlob_UINT32(&offset, hTransSession, txBlob);
UnloadBlob_UINT32(&offset, pbLocality, txBlob);
*ulCurrentTicks = sizeof(TPM_STRUCTURE_TAG)
+ sizeof(UINT64)
+ sizeof(UINT16)
+ sizeof(TPM_NONCE);
*prgbCurrentTicks = malloc(*ulCurrentTicks);
if (*prgbCurrentTicks == NULL) {
result = TCSERR(TSS_E_OUTOFMEMORY);
goto done;
}
UnloadBlob(&offset, *ulCurrentTicks, txBlob, *prgbCurrentTicks);
UnloadBlob(&offset, sizeof(TPM_NONCE), txBlob, (BYTE *)pTransNonce);
if (pEncKeyAuth)
UnloadBlob_Auth(&offset, txBlob, pEncKeyAuth);
ctx_set_transport_enabled(hContext, *hTransSession);
done:
auth_mgr_release_auth(pEncKeyAuth, NULL, hContext);
return result;
}
TSS_RESULT
TCSP_ExecuteTransport_Internal(TCS_CONTEXT_HANDLE hContext,
TPM_COMMAND_CODE unWrappedCommandOrdinal,
UINT32 ulWrappedCmdParamInSize,
BYTE* rgbWrappedCmdParamIn,
UINT32* pulHandleListSize, /* in, out */
TCS_HANDLE** rghHandles, /* in, out */
TPM_AUTH* pWrappedCmdAuth1, /* in, out */
TPM_AUTH* pWrappedCmdAuth2, /* in, out */
TPM_AUTH* pTransAuth, /* in, out */
UINT64* punCurrentTicks,
TPM_MODIFIER_INDICATOR* pbLocality,
TPM_RESULT* pulWrappedCmdReturnCode,
UINT32* ulWrappedCmdParamOutSize,
BYTE** rgbWrappedCmdParamOut)
{
TSS_RESULT result;
UINT32 paramSize, wrappedSize, val1 = 0, val2 = 0, *pVal1 = NULL, *pVal2 = NULL;
TCS_HANDLE handle1 = 0, handle2 = 0;
UINT64 offset, wrappedOffset = 0, tmpOffset;
BYTE txBlob[TSS_TPM_TXBLOB_SIZE];
if (*pulHandleListSize > 2) {
LogDebugFn("************ EXPAND KEYSLOT SIZE *********");
return TCSERR(TSS_E_INTERNAL_ERROR);
}
if ((result = ctx_verify_context(hContext)))
return result;
if (pWrappedCmdAuth1)
if ((result = auth_mgr_check(hContext, &pWrappedCmdAuth1->AuthHandle)))
goto done;
if (pWrappedCmdAuth2)
if ((result = auth_mgr_check(hContext, &pWrappedCmdAuth2->AuthHandle)))
goto done;
switch (unWrappedCommandOrdinal) {
/* If the command is FlushSpecific, we get handle that needs to be freed, but we don't know
* what type it is. */
case TPM_ORD_FlushSpecific:
if (*pulHandleListSize == 0) { /* invalid */
result = TCSERR(TSS_E_BAD_PARAMETER);
goto done;
}
/* If this is a transport handle, remove the context's reference to the session */
ctx_set_transport_disabled(hContext, rghHandles[0]);
/* Is it a key? If so, jump to the get_slot_lite and key management calls below */
if (ctx_has_key_loaded(hContext, *rghHandles[0]))
goto map_key_handles;
/* fall through */
case TPM_ORD_Terminate_Handle:
if (!auth_mgr_check(hContext, rghHandles[0]))
auth_mgr_release_auth_handle(*rghHandles[0], hContext, FALSE);
/* If the handle is an auth handle or any other kind of handle, there's no
* mapping done in the TCS, so pass its value straight to the TPM and jump over
* the switch statement below where we assume FLushSpecific is being done on a
* key */
handle1 = val1 = *rghHandles[0];
pVal1 = &val1;
goto build_command;
default:
break;
}
map_key_handles:
if (*pulHandleListSize == 2) {
handle2 = (*rghHandles)[1];
if ((result = get_slot_lite(hContext, handle2, &val2))) {
*pulHandleListSize = 0;
goto done;
}
pVal2 = &val2;
}
if (*pulHandleListSize >= 1) {
handle1 = *rghHandles[0];
*pulHandleListSize = 0;
if ((result = get_slot_lite(hContext, handle1, &val1)))
goto done;
pVal1 = &val1;
}
switch (unWrappedCommandOrdinal) {
case TPM_ORD_EvictKey:
case TPM_ORD_FlushSpecific:
{
if ((result = ctx_remove_key_loaded(hContext, handle1)))
goto done;
if ((result = key_mgr_dec_ref_count(handle1)))
goto done;
/* we can't call key_mgr_ref_cnt() here since it calls TPM_EvictKey directly */
mc_set_slot_by_handle(handle1, NULL_TPM_HANDLE);
break;
}
case TPM_ORD_OIAP:
{
/* are the maximum number of auth sessions open? */
if (auth_mgr_req_new(hContext) == FALSE) {
if ((result = auth_mgr_swap_out(hContext)))
goto done;
}
break;
}
case TPM_ORD_OSAP:
{
UINT16 entityType;
UINT32 entityValue, newEntValue;
/* are the maximum number of auth sessions open? */
if (auth_mgr_req_new(hContext) == FALSE) {
if ((result = auth_mgr_swap_out(hContext)))
goto done;
}
offset = 0;
UnloadBlob_UINT16(&offset, &entityType, rgbWrappedCmdParamIn);
UnloadBlob_UINT32(&offset, &entityValue, rgbWrappedCmdParamIn);
if (entityType == TCPA_ET_KEYHANDLE || entityType == TCPA_ET_KEY) {
if (ensureKeyIsLoaded(hContext, entityValue, &newEntValue))
return TCSERR(TSS_E_KEY_NOT_LOADED);
/* OSAP is never encrypted in a transport session, so changing
* rgbWrappedCmdParamIn is ok here */
offset = sizeof(UINT16);
LoadBlob_UINT32(&offset, newEntValue, rgbWrappedCmdParamIn);
}
break;
}
case TPM_ORD_DSAP:
{
UINT16 entityType;
UINT32 keyHandle, tpmKeyHandle;
/* are the maximum number of auth sessions open? */
if (auth_mgr_req_new(hContext) == FALSE) {
if ((result = auth_mgr_swap_out(hContext)))
goto done;
}
offset = 0;
UnloadBlob_UINT16(&offset, &entityType, rgbWrappedCmdParamIn);
UnloadBlob_UINT32(&offset, &keyHandle, rgbWrappedCmdParamIn);
if (ensureKeyIsLoaded(hContext, keyHandle, &tpmKeyHandle)) {
result = TCSERR(TSS_E_KEY_NOT_LOADED);
goto done;
}
/* DSAP's only encrypted paramter is entityValue, so replacing keyHandle inside
* rgbWrappedCmdParamIn is ok */
offset = sizeof(UINT16);
LoadBlob_UINT32(&offset, tpmKeyHandle, rgbWrappedCmdParamIn);
}
default:
break;
}
build_command:
if ((result = tpm_rqu_build_checked(TPM_ORD_ExecuteTransport, &wrappedOffset, TSS_TPM_TXBLOB_SIZE,
&txBlob[TSS_TXBLOB_WRAPPEDCMD_OFFSET], unWrappedCommandOrdinal,
pVal1, pVal2, ulWrappedCmdParamInSize, rgbWrappedCmdParamIn,
pWrappedCmdAuth1, pWrappedCmdAuth2)))
goto done;
/* The blob we'll load here looks like this:
*
* |TAGet|LENet|ORDet|wrappedCmdSize|wrappedCmd|AUTHet|
*
* wrappedCmd looks like this:
*
* |TAGw|LENw|ORDw|HANDLESw|DATAw|AUTH1w|AUTH2w|
*
* w = wrapped command info
* et = execute transport command info
*
* Note that the wrapped command was loaded into the blob by the tpm_rqu_build call
* above.
*
*/
offset = TSS_TPM_TXBLOB_HDR_LEN;
/* Load wrapped command size: |wrappedCmdSize| */
tmpOffset = offset;
LoadBlob_UINT32(&tmpOffset, wrappedOffset, NULL);
if (tmpOffset > TSS_TPM_TXBLOB_SIZE) {
result = TCSERR(TSS_E_BAD_PARAMETER);
goto done;
}
LoadBlob_UINT32(&offset, wrappedOffset, txBlob);
/* offset + wrappedOffset is the position of the execute transport auth struct */
offset += wrappedOffset;
if (pTransAuth) {
/* Load the auth for the execute transport command: |AUTHet| */
tmpOffset = offset;
LoadBlob_Auth(&tmpOffset, NULL, pTransAuth);
if (tmpOffset > TSS_TPM_TXBLOB_SIZE) {
result = TCSERR(TSS_E_BAD_PARAMETER);
goto done;
}
LoadBlob_Auth(&offset, txBlob, pTransAuth);
/* Load the outer header: |TAGet|LENet|ORDet| */
LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, offset, TPM_ORD_ExecuteTransport,
txBlob);
} else {
/* Load the outer header: |TAGet|LENet|ORDet| */
LoadBlob_Header(TPM_TAG_RQU_COMMAND, offset, TPM_ORD_ExecuteTransport, txBlob);
}
if ((result = req_mgr_submit_req(txBlob)))
goto done;
/* Unload the Execute Transport (outer) header */
if ((result = UnloadBlob_Header(txBlob, &paramSize))) {
LogDebugFn("UnloadBlob_Header failed: rc=0x%x", result);
goto done;
}
/* The response from the TPM looks like this:
*
* |TAGet|LENet|RCet|currentTicks|locality|wrappedRspSize|wrappedRsp|AUTHet|
*
* and wrappedRsp looks like:
*
* |TAGw|LENw|RCw|HANDLESw|DATAw|AUTH1w|AUTH2w|
*/
offset = TSS_TPM_TXBLOB_HDR_LEN;
UnloadBlob_UINT64(&offset, punCurrentTicks, txBlob);
UnloadBlob_UINT32(&offset, pbLocality, txBlob);
/* Unload the wrapped response size: |wrappedRspSize| */
UnloadBlob_UINT32(&offset, &wrappedSize, txBlob);
/* We've parsed right up to wrappedRsp, so save off this offset for later */
wrappedOffset = offset;
/* The current offset + the response size will be the offset of |AUTHet| */
offset += wrappedSize;
if (pTransAuth)
UnloadBlob_Auth(&offset, txBlob, pTransAuth);
/* Now parse through the returned response @ wrappedOffset */
if ((result = UnloadBlob_Header(&txBlob[wrappedOffset], &paramSize))) {
LogDebugFn("Wrapped command (Ordinal 0x%x) failed: rc=0x%x",
unWrappedCommandOrdinal, result);
/* This is the result of the wrapped command. If its not success, return its value
* in the pulWrappedCmdReturnCode variable and return indicating that the execute
* transport command was successful */
*pulWrappedCmdReturnCode = result;
*ulWrappedCmdParamOutSize = 0;
*rgbWrappedCmdParamOut = NULL;
auth_mgr_release_auth(pWrappedCmdAuth1, pWrappedCmdAuth2, hContext);
return TSS_SUCCESS;
}
*pulWrappedCmdReturnCode = TSS_SUCCESS;
pVal1 = pVal2 = NULL;
switch (unWrappedCommandOrdinal) {
/* The commands below have 1 outgoing handle */
case TPM_ORD_LoadKey2:
pVal1 = &val1;
break;
default:
break;
}
result = tpm_rsp_parse(TPM_ORD_ExecuteTransport, &txBlob[wrappedOffset], paramSize,
pVal1, pVal2, ulWrappedCmdParamOutSize, rgbWrappedCmdParamOut,
pWrappedCmdAuth1, pWrappedCmdAuth2);
offset = 0;
switch (unWrappedCommandOrdinal) {
case TPM_ORD_LoadKey2:
{
TCS_KEY_HANDLE tcs_handle = NULL_TCS_HANDLE;
if ((result = load_key_final(hContext, handle1, &tcs_handle, NULL, val1)))
goto done;
*rghHandles[0] = tcs_handle;
*pulHandleListSize = 1;
break;
}
case TPM_ORD_DSAP:
case TPM_ORD_OSAP:
case TPM_ORD_OIAP:
{
UINT32 handle;
UnloadBlob_UINT32(&offset, &handle, *rgbWrappedCmdParamOut);
result = auth_mgr_add(hContext, handle);
break;
}
default:
break;
}
done:
auth_mgr_release_auth(pWrappedCmdAuth1, pWrappedCmdAuth2, hContext);
return result;
}
TSS_RESULT
TCSP_ReleaseTransportSigned_Internal(TCS_CONTEXT_HANDLE hContext,
TCS_KEY_HANDLE hSignatureKey,
TPM_NONCE* AntiReplayNonce,
TPM_AUTH* pKeyAuth, /* in, out */
TPM_AUTH* pTransAuth, /* in, out */
TPM_MODIFIER_INDICATOR* pbLocality,
UINT32* pulCurrentTicksSize,
BYTE** prgbCurrentTicks,
UINT32* pulSignatureSize,
BYTE** prgbSignature)
{
TSS_RESULT result;
UINT32 paramSize;
UINT64 offset;
TPM_KEY_HANDLE keySlot;
BYTE txBlob[TSS_TPM_TXBLOB_SIZE];
if ((result = ctx_verify_context(hContext)))
return result;
if (pKeyAuth) {
if ((result = auth_mgr_check(hContext, &pKeyAuth->AuthHandle)))
return result;
}
if ((result = ensureKeyIsLoaded(hContext, hSignatureKey, &keySlot)))
return result;
offset = TSS_TPM_TXBLOB_HDR_LEN;
LoadBlob_UINT32(&offset, keySlot, NULL);
LoadBlob(&offset, sizeof(TPM_NONCE), NULL, (BYTE *)AntiReplayNonce);
if (pKeyAuth) {
LoadBlob_Auth(&offset, NULL, pKeyAuth);
LoadBlob_Auth(&offset, NULL, pTransAuth);
} else {
LoadBlob_Auth(&offset, NULL, pTransAuth);
}
if (offset > TSS_TPM_TXBLOB_SIZE) {
result = TCSERR(TSS_E_BAD_PARAMETER);
goto done;
}
offset = TSS_TPM_TXBLOB_HDR_LEN;
LoadBlob_UINT32(&offset, keySlot, txBlob);
LoadBlob(&offset, sizeof(TPM_NONCE), txBlob, (BYTE *)AntiReplayNonce);
if (pKeyAuth) {
LoadBlob_Auth(&offset, txBlob, pKeyAuth);
LoadBlob_Auth(&offset, txBlob, pTransAuth);
LoadBlob_Header(TPM_TAG_RQU_AUTH2_COMMAND, offset, TPM_ORD_ReleaseTransportSigned,
txBlob);
} else {
LoadBlob_Auth(&offset, txBlob, pTransAuth);
LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, offset, TPM_ORD_ReleaseTransportSigned,
txBlob);
}
if ((result = req_mgr_submit_req(txBlob)))
goto done;
if ((result = UnloadBlob_Header(txBlob, &paramSize))) {
LogDebugFn("UnloadBlob_Header failed: rc=0x%x", result);
goto done;
}
/* unconditionally disable our accounting of the session */
ctx_set_transport_disabled(hContext, NULL);
offset = TSS_TPM_TXBLOB_HDR_LEN;
UnloadBlob_UINT32(&offset, pbLocality, txBlob);
*pulCurrentTicksSize = sizeof(TPM_STRUCTURE_TAG)
+ sizeof(UINT64)
+ sizeof(UINT16)
+ sizeof(TPM_NONCE);
*prgbCurrentTicks = malloc(*pulCurrentTicksSize);
if (*prgbCurrentTicks == NULL) {
result = TCSERR(TSS_E_OUTOFMEMORY);
goto done;
}
UnloadBlob(&offset, *pulCurrentTicksSize, txBlob, *prgbCurrentTicks);
UnloadBlob_UINT32(&offset, pulSignatureSize, txBlob);
*prgbSignature = malloc(*pulSignatureSize);
if (*prgbSignature == NULL) {
free(*prgbCurrentTicks);
result = TCSERR(TSS_E_OUTOFMEMORY);
goto done;
}
UnloadBlob(&offset, *pulSignatureSize, txBlob, *prgbSignature);
if (pKeyAuth)
UnloadBlob_Auth(&offset, txBlob, pKeyAuth);
UnloadBlob_Auth(&offset, txBlob, pTransAuth);
done:
auth_mgr_release_auth(pKeyAuth, NULL, hContext);
return result;
}