/* * Licensed Materials - Property of IBM * * trousers - An open source TCG Software Stack * * (C) Copyright International Business Machines Corp. 2007 * */ #include #include #include #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; }