diff options
Diffstat (limited to 'src/tcs/tcsi_transport.c')
-rw-r--r-- | src/tcs/tcsi_transport.c | 513 |
1 files changed, 513 insertions, 0 deletions
diff --git a/src/tcs/tcsi_transport.c b/src/tcs/tcsi_transport.c new file mode 100644 index 0000000..38a3b32 --- /dev/null +++ b/src/tcs/tcsi_transport.c @@ -0,0 +1,513 @@ + +/* + * 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; + 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, 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, ¶mSize))) { + 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; + 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(TPM_ORD_ExecuteTransport, &wrappedOffset, + &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| */ + 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| */ + 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, ¶mSize))) { + 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], ¶mSize))) { + 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, 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, ¶mSize))) { + 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; +} |