/** * Copyright(c) 2011 Trusted Logic. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name Trusted Logic nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "tee_client_api.h" #include "schannel6_protocol.h" #include "s_error.h" #include "s_version.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * SCX_VERSION_INFORMATION_BUFFER structure description * Description of the sVersionBuffer handed over from user space to kernel space * This field is filled after an IOCTL call and handed back to user space */ typedef struct { uint8_t sDriverDescription[65]; uint8_t sSecureWorldDescription[65]; } SCX_VERSION_INFORMATION_BUFFER; /* The IOCTLs to the driver */ #define IOCTL_SCX_GET_VERSION \ _IO('z', 0) #define IOCTL_SCX_EXCHANGE \ _IOWR('z', 1, SCHANNEL6_COMMAND) #define IOCTL_SCX_GET_DESCRIPTION \ _IOR('z', 2, SCX_VERSION_INFORMATION_BUFFER) /* Expected driver interface version. */ #define SM_DRIVER_VERSION 0x04000000 #define SCX_DEFAULT_DEVICE_NAME "tf_driver" #define SCX_PARAM_TYPE_GET(nParamTypes, i) (((nParamTypes) >> (4*i)) & 0xF) #define VAR_NOT_USED(variable) do{(void)(variable);}while(0); #define SIZE_4KB 0x1000 #define SIZE_1MB 0x100000 /* ------------------------------------------------------------------------ */ /* UTILS */ /* ------------------------------------------------------------------------ */ #ifdef NDEBUG /* Compile-out the traces */ #define TRACE_ERROR(...) #define TRACE_WARNING(...) #define TRACE_INFO(...) #else static void TRACE_ERROR(const char* format, ...) { va_list ap; va_start(ap, format); fprintf(stderr, "TRACE: ERROR: "); vfprintf(stderr, format, ap); fprintf(stderr, "\n"); va_end(ap); } static void TRACE_WARNING(const char* format, ...) { va_list ap; va_start(ap, format); fprintf(stderr, "TRACE: WARNING: "); vfprintf(stderr, format, ap); fprintf(stderr, "\n"); va_end(ap); } static void TRACE_INFO(const char* format, ...) { va_list ap; va_start(ap, format); fprintf(stderr, "TRACE: "); vfprintf(stderr, format, ap); fprintf(stderr, "\n"); va_end(ap); } #endif /* NDEBUG */ /* * ==================================================== * Internal functions * ===================================================== */ static void scxYield(void) { sleep(0); } /* ------------------------------------------------------------------------ */ /* * Exchange a message with the Secure World * by calling the ioctl command of the linux driver * * @param pContext * @param pCommand a SChannel command message that must have been filled except for the operation parameters * @param pAnswer a placeholder for the SChannel answer * @param pOperation a TEEC_Operation structure that contains the operation parameters (and types) * and is updated with the SChannel answer data as appropriate. This parameter is * used only for the open and invoke operations */ static TEEC_Result scxExchangeMessage( IN TEEC_Context* pContext, IN SCHANNEL6_COMMAND* pCommand, OUT SCHANNEL6_ANSWER* pAnswer, IN TEEC_Operation* pOperation) { TEEC_Result nResult = TEEC_SUCCESS; TRACE_INFO("scxExchangeMessage[0x%X]\n",pContext); if (pOperation != NULL) { /* Determine message parameters from operation parameters */ uint32_t i; SCHANNEL6_COMMAND_PARAM* pSCXParams; /* Note that nParamType is at the same position in an open and an invoke message */ pCommand->sHeader.nMessageInfo = pOperation->paramTypes; if (pCommand->sHeader.nMessageType == SCX_OPEN_CLIENT_SESSION) { pSCXParams = pCommand->sOpenClientSession.sParams; } else { /* An invoke-command */ pSCXParams = pCommand->sInvokeClientCommand.sParams; } for (i = 0; i < 4; i++) { uint32_t nTEECParamType = SCX_PARAM_TYPE_GET(pOperation->paramTypes, i); TEEC_Parameter* pTEECParam = &pOperation->params[i]; SCHANNEL6_COMMAND_PARAM* pSCXParam = &pSCXParams[i]; if (nTEECParamType & SCX_PARAM_TYPE_MEMREF_FLAG) { if (nTEECParamType & SCX_PARAM_TYPE_REGISTERED_MEMREF_FLAG) { /* A registered memref */ pSCXParam->sMemref.hBlock = pTEECParam->memref.parent->imp._hBlock; if (nTEECParamType == TEEC_MEMREF_WHOLE) { /* A memref on the whole shared memory */ /* Set the direction from the shared memory flags */ pCommand->sInvokeClientCommand.nParamTypes |= (pTEECParam->memref.parent->flags & (SCX_PARAM_TYPE_INPUT_FLAG | SCX_PARAM_TYPE_OUTPUT_FLAG)) << (4*i); pSCXParam->sMemref.nSize = pTEECParam->memref.parent->size; pSCXParam->sMemref.nOffset = 0; } else { /* A partial memref */ pSCXParam->sMemref.nSize = pTEECParam->memref.size; pSCXParam->sMemref.nOffset = pTEECParam->memref.offset; } } else { /* A temporary memref */ /* Set nOffset to the address in the client. This allows the server to allocate a block with the same alignment and also to detect a NULL tmpref. */ pSCXParam->sTempMemref.nOffset = (uint32_t)pTEECParam->tmpref.buffer; pSCXParam->sTempMemref.nDescriptor = (uint32_t)pTEECParam->tmpref.buffer; pSCXParam->sTempMemref.nSize = pTEECParam->tmpref.size; } } else if (nTEECParamType & SCX_PARAM_TYPE_INPUT_FLAG) { /* An input value */ pSCXParam->sValue.a = pTEECParam->value.a; pSCXParam->sValue.b = pTEECParam->value.b; } } } pCommand->sHeader.nOperationID = (uint32_t)pAnswer; nResult = ioctl((S_HANDLE)pContext->imp._hConnection, IOCTL_SCX_EXCHANGE, pCommand); if (nResult != S_SUCCESS) { TRACE_INFO("scxExchangeMessage[0x%X]: Ioctl returned error: 0x%x (0x%x - %d)\n",pContext,nResult,errno,errno); switch(errno) { case ENOMEM: nResult=TEEC_ERROR_OUT_OF_MEMORY; break; case EACCES: nResult=TEEC_ERROR_ACCESS_DENIED; break; default: nResult=TEEC_ERROR_COMMUNICATION; break; } } if (pOperation != NULL) { /* Update the operation parameters from the answer message */ uint32_t i; SCHANNEL6_ANSWER_PARAM * pSCXAnswers; if (pAnswer->sHeader.nMessageType == SCX_OPEN_CLIENT_SESSION) { /* Open session */ pSCXAnswers = pAnswer->sOpenClientSession.sAnswers; } else { /* Invoke case */ pSCXAnswers = pAnswer->sInvokeClientCommand.sAnswers; } for (i = 0; i < 4; i++) { uint32_t nSCXParamType; nSCXParamType = SCX_GET_PARAM_TYPE(pCommand->sHeader.nMessageInfo, i); if (nSCXParamType & SCX_PARAM_TYPE_OUTPUT_FLAG) { if (nSCXParamType & SCX_PARAM_TYPE_MEMREF_FLAG) { /* Trick: the size field is at the same position in a memref or a tmpref */ pOperation->params[i].memref.size = pSCXAnswers[i].sSize.nSize; } else { /* An output value */ pOperation->params[i].value.a = pSCXAnswers[i].sValue.a; pOperation->params[i].value.b = pSCXAnswers[i].sValue.b; } } } } return nResult; } /* ------------------------------------------------------------------------ */ static void* scxAllocateSharedMemory( IN uint32_t nLength) { if (nLength == 0) { /* This is valid, although we don't want to call mmap. Just return a dummy non-NULL pointer */ return (void*)0x10; } else { return mmap( 0,nLength, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, 0,0); } } /* ------------------------------------------------------------------------ */ static void scxReleaseSharedMemory(IN void* pBuffer, IN uint32_t nLength) { if (nLength == 0) { return; } if (munmap(pBuffer, nLength)!= 0) { TRACE_WARNING("scxReleaseSharedMemory returned 0x%x \n",errno); } } /* ------------------------------------------------------------------------ */ uint64_t scxGetCurrentTime(void) { uint64_t currentTime = 0; struct timeval now; gettimeofday(&now,NULL); currentTime = now.tv_sec; currentTime = (currentTime * 1000) + (now.tv_usec / 1000); return currentTime; } /* ------------------------------------------------------------------------ */ /* * ==================================================== * TEE Client API * ===================================================== */ /** * Get a time-limit equal to now + relative timeout expressed in milliseconds. **/ void TEEC_GetTimeLimit( TEEC_Context* sContext, uint32_t nTimeout, TEEC_TimeLimit* sTimeLimit) { uint64_t nTimeLimit = 0; VAR_NOT_USED(sContext); TRACE_INFO("TEEC_GetTimeLimit(0x%X, %u ms)", sContext, nTimeout); if (nTimeout == 0xFFFFFFFF ) { /* Infinite timeout */ nTimeLimit = SCTIME_INFINITE; } else { nTimeLimit = scxGetCurrentTime() + nTimeout; } TRACE_INFO("GetTimeLimit %ld\n",nTimeLimit); memcpy(sTimeLimit, &nTimeLimit, sizeof(TEEC_TimeLimit)); } //----------------------------------------------------------------------------------------------------- TEEC_Result TEEC_InitializeContext( const char* pDeviceName, TEEC_Context* pContext) { TEEC_Result nError = TEEC_SUCCESS; S_HANDLE hDriver = S_HANDLE_NULL; char sFullDeviceName[PATH_MAX]; uint32_t nVersion; if(pDeviceName == NULL) { pDeviceName = SCX_DEFAULT_DEVICE_NAME; } strcpy(sFullDeviceName, "/dev/"); strcat(sFullDeviceName, pDeviceName); hDriver = open(sFullDeviceName, O_RDWR, 0); if (hDriver == (uint32_t)-1) { TRACE_ERROR("scxOpen: open() failed 0x%x\n", errno); switch(errno) { case ENOMEM: nError = TEEC_ERROR_OUT_OF_MEMORY; goto error; case EINTR: break; default: nError = TEEC_ERROR_COMMUNICATION; goto error; } } fcntl(hDriver, F_SETFD, FD_CLOEXEC); nVersion = ioctl(hDriver, IOCTL_SCX_GET_VERSION); if (nVersion != SM_DRIVER_VERSION) { TRACE_ERROR("scxOpen: Not expected driver version: 0x%x instead of 0x%x\n", nVersion,SM_DRIVER_VERSION); switch(errno) { case ENOMEM: nError=TEEC_ERROR_OUT_OF_MEMORY; break; default: nError=TEEC_ERROR_COMMUNICATION; break; } close(hDriver); } error: if(nError == TEEC_SUCCESS) { pContext->imp._hConnection = hDriver; } else { TRACE_ERROR("scxOpen failed 0x%x\n", nError); pContext->imp._hConnection = 0; } return nError; } //----------------------------------------------------------------------------------------------------- void TEEC_FinalizeContext(TEEC_Context* pContext) { TRACE_INFO("TEEC_FinalizeContext[0x%X]", pContext); if (pContext == NULL) return; close(pContext->imp._hConnection); pContext->imp._hConnection = 0; } //----------------------------------------------------------------------------------------------------- TEEC_Result TEEC_OpenSession ( TEEC_Context* context, TEEC_Session* session, /* OUT */ const TEEC_UUID* destination, /* The trusted application UUID we want to open the session with */ uint32_t connectionMethod, /* LoginType*/ void* connectionData, /* LoginData */ TEEC_Operation* operation, /* payload. If operation is NULL then no data buffers are exchanged with the Trusted Application, and the operation cannot be cancelled by the Client Application */ uint32_t* errorOrigin) { return TEEC_OpenSessionEx(context, session, NULL, destination, connectionMethod, connectionData, operation, errorOrigin); } //----------------------------------------------------------------------------------------------------- void TEEC_CloseSession (TEEC_Session* session) { TEEC_Context* context; SCHANNEL6_ANSWER sAnswer; SCHANNEL6_COMMAND sCommand; if (session == NULL) return; context = session->imp._pContext; memset(&sCommand,0,sizeof(sCommand)); sCommand.sHeader.nMessageType = SCX_CLOSE_CLIENT_SESSION; sCommand.sHeader.nMessageSize = (sizeof(SCHANNEL6_CLOSE_CLIENT_SESSION_COMMAND) - sizeof(SCHANNEL6_COMMAND_HEADER))/sizeof(uint32_t); sCommand.sCloseClientSession.hClientSession = session->imp._hClientSession; scxExchangeMessage(context, &sCommand, &sAnswer, NULL); /* we ignore the error code of scxExchangeMessage */ session->imp._hClientSession = S_HANDLE_NULL; session->imp._pContext = NULL; } //----------------------------------------------------------------------------------------------------- TEEC_Result TEEC_InvokeCommand( TEEC_Session* session, uint32_t commandID, TEEC_Operation* operation, uint32_t* errorOrigin) { return TEEC_InvokeCommandEx(session, NULL, commandID, operation, errorOrigin); } //----------------------------------------------------------------------------------------------------- /* Used to implement both register and allocate */ static TEEC_Result TEEC_RegisterSharedMemory0( TEEC_Context* context, TEEC_SharedMemory* sharedMem) { TEEC_Result nResult; SCHANNEL6_COMMAND sCommand; SCHANNEL6_ANSWER sAnswer; TRACE_INFO("TEEC_RegisterSharedMemory0 (%p, %p)",context, sharedMem); memset(&sCommand, 0, sizeof(sCommand)); sCommand.sRegisterSharedMemory.nMessageSize = (sizeof(SCHANNEL6_REGISTER_SHARED_MEMORY_COMMAND) - sizeof(SCHANNEL6_COMMAND_HEADER))/4; sCommand.sRegisterSharedMemory.nMessageType = SCX_REGISTER_SHARED_MEMORY; sCommand.sRegisterSharedMemory.nMemoryFlags = sharedMem->flags; sCommand.sRegisterSharedMemory.nSharedMemSize = sharedMem->size; sCommand.sRegisterSharedMemory.nSharedMemStartOffset = 0; sCommand.sRegisterSharedMemory.nSharedMemDescriptors[0] = (uint32_t)sharedMem->buffer; nResult = scxExchangeMessage(context, &sCommand, &sAnswer, NULL); if (nResult == TEEC_SUCCESS) { nResult = sAnswer.sRegisterSharedMemory.nErrorCode; } if (nResult == TEEC_SUCCESS) { sharedMem->imp._pContext = context; sharedMem->imp._hBlock = sAnswer.sRegisterSharedMemory.hBlock; } return nResult; } //----------------------------------------------------------------------------------------------------- TEEC_Result TEEC_RegisterSharedMemory( TEEC_Context* context, TEEC_SharedMemory* sharedMem) { TRACE_INFO("TEEC_RegisterSharedMemory (%p)",context); sharedMem->imp._pContext = NULL; sharedMem->imp._hBlock = S_HANDLE_NULL; sharedMem->imp._bAllocated = false; return TEEC_RegisterSharedMemory0(context, sharedMem); } //----------------------------------------------------------------------------------------------------- TEEC_Result TEEC_AllocateSharedMemory( TEEC_Context* context, TEEC_SharedMemory* sharedMem) { TEEC_Result nResult; TRACE_INFO("TEEC_AllocateSharedMemory (%p)",context); sharedMem->imp._pContext = NULL; sharedMem->imp._hBlock = S_HANDLE_NULL; sharedMem->buffer = scxAllocateSharedMemory(sharedMem->size); if (sharedMem->buffer == NULL) { return TEEC_ERROR_OUT_OF_MEMORY; } sharedMem->imp._bAllocated = true; nResult = TEEC_RegisterSharedMemory0(context, sharedMem); if (nResult != TEEC_SUCCESS) { scxReleaseSharedMemory(sharedMem->buffer,sharedMem->size); sharedMem->buffer = NULL; } return nResult; } //----------------------------------------------------------------------------------------------------- void TEEC_ReleaseSharedMemory ( TEEC_SharedMemory* sharedMem) { SCHANNEL6_ANSWER sAnswer; SCHANNEL6_COMMAND sMessage; TEEC_Context* context; context = (TEEC_Context *)sharedMem->imp._pContext; memset(&sMessage, 0, sizeof(SCHANNEL6_COMMAND)); sMessage.sReleaseSharedMemory.nMessageType = SCX_RELEASE_SHARED_MEMORY; sMessage.sReleaseSharedMemory.nMessageSize = (sizeof(SCHANNEL6_RELEASE_SHARED_MEMORY_COMMAND) - sizeof(SCHANNEL6_COMMAND_HEADER))/sizeof(uint32_t); sMessage.sReleaseSharedMemory.hBlock = sharedMem->imp._hBlock; scxExchangeMessage(context,&sMessage, &sAnswer, NULL); if (sharedMem->imp._bAllocated) { scxReleaseSharedMemory(sharedMem->buffer,sharedMem->size); /* Update parameters: * In this case the Implementation MUST set the buffer and size fields of the sharedMem structure * to NULL and 0 respectively before returning. */ sharedMem->buffer = NULL; sharedMem->size = 0; } sharedMem->imp._pContext = NULL; sharedMem->imp._hBlock = S_HANDLE_NULL; } //----------------------------------------------------------------------------------------------------- void TEEC_RequestCancellation(TEEC_Operation* operation) { uint32_t nOperationState; TEEC_Result nResult; if (operation == NULL) return; retry: nOperationState = operation->started; if (nOperationState == 2) { /* Operation already finished. Return immediately */ return; } else if (nOperationState == 1) { /* Operation is in progress */ TEEC_Context* context; SCHANNEL6_ANSWER sAnswer; SCHANNEL6_COMMAND sMessage; context = operation->imp._pContext; memset(&sMessage,0,sizeof(sMessage)); sMessage.sHeader.nMessageType = SCX_CANCEL_CLIENT_OPERATION; sMessage.sHeader.nMessageSize = (sizeof(SCHANNEL6_CANCEL_CLIENT_OPERATION_COMMAND) - sizeof(SCHANNEL6_COMMAND_HEADER))/4; sMessage.sCancelClientOperation.hClientSession = operation->imp._hSession; sMessage.sCancelClientOperation.nCancellationID = (uint32_t)operation; nResult = scxExchangeMessage(context,&sMessage, &sAnswer, NULL); if (nResult != TEEC_SUCCESS) { /* Communication failure. Ignore the error: the operation is already cancelled anyway */ return; } if (sAnswer.sCancelClientOperation.nErrorCode == S_SUCCESS) { /* Command was successfully cancelled */ return; } /* Otherwise, the command has not yet reached the secure world or has already finished and we must retry */ } /* This applies as well when nOperationState == 0. In this case, the operation has not yet started yet and we don't even have a pointer to the context */ scxYield(); goto retry; } //----------------------------------------------------------------------------------------------------- TEEC_Result TEEC_ReadSignatureFile( void** ppSignatureFile, uint32_t* pnSignatureFileLength) { TEEC_Result nErrorCode = TEEC_SUCCESS; uint32_t nBytesRead; uint32_t nSignatureSize = 0; uint8_t* pSignature = NULL; FILE* pSignatureFile = NULL; char sFileName[PATH_MAX + 1 + 5]; /* Allocate room for the signature extension */ long nFileSize; *pnSignatureFileLength = 0; *ppSignatureFile = NULL; if (realpath("/proc/self/exe", sFileName) == NULL) { TRACE_ERROR("TEEC_ReadSignatureFile: realpath failed [%d]", errno); return TEEC_ERROR_OS; } /* Work out the signature file name */ strcat(sFileName, ".ssig"); pSignatureFile = fopen(sFileName, "rb"); if (pSignatureFile == NULL) { /* Signature doesn't exist */ return TEEC_ERROR_ITEM_NOT_FOUND; } if (fseek(pSignatureFile, 0, SEEK_END) != 0) { TRACE_ERROR("TEEC_ReadSignatureFile: fseek(%s) failed [%d]", sFileName, errno); nErrorCode = TEEC_ERROR_OS; goto error; } nFileSize = ftell(pSignatureFile); if (nFileSize < 0) { TRACE_ERROR("TEEC_ReadSignatureFile: ftell(%s) failed [%d]", sFileName, errno); nErrorCode = TEEC_ERROR_OS; goto error; } nSignatureSize = (uint32_t)nFileSize; if (nSignatureSize != 0) { pSignature = malloc(nSignatureSize); if (pSignature == NULL) { TRACE_ERROR("TEEC_ReadSignatureFile: Heap - Out of memory for %u bytes", nSignatureSize); nErrorCode = TEEC_ERROR_OUT_OF_MEMORY; goto error; } rewind(pSignatureFile); nBytesRead = fread(pSignature, 1, nSignatureSize, pSignatureFile); if (nBytesRead < nSignatureSize) { TRACE_ERROR("TEEC_ReadSignatureFile: fread failed [%d]", errno); nErrorCode = TEEC_ERROR_OS; goto error; } } fclose(pSignatureFile); *pnSignatureFileLength = nSignatureSize; *ppSignatureFile = pSignature; return S_SUCCESS; error: fclose(pSignatureFile); free(pSignature); return nErrorCode; } //----------------------------------------------------------------------------------------------------- TEEC_Result TEEC_OpenSessionEx ( TEEC_Context* context, TEEC_Session* session, /* OUT */ const TEEC_TimeLimit* timeLimit, const TEEC_UUID* destination, /* The trusted application UUID we want to open the session with */ uint32_t connectionMethod, /* LoginType*/ void* connectionData, /* LoginData */ TEEC_Operation* operation, /* payload. If operation is NULL then no data buffers are exchanged with the Trusted Application, and the operation cannot be cancelled by the Client Application */ uint32_t* returnOrigin) { TEEC_Result nError; uint32_t nReturnOrigin; SCHANNEL6_ANSWER sAnswer; SCHANNEL6_COMMAND sCommand; memset(&sCommand, 0, sizeof(SCHANNEL6_COMMAND)); sCommand.sHeader.nMessageType = SCX_OPEN_CLIENT_SESSION; sCommand.sHeader.nMessageSize = (sizeof(SCHANNEL6_OPEN_CLIENT_SESSION_COMMAND) - 20 -sizeof(SCHANNEL6_COMMAND_HEADER))/sizeof(uint32_t); if (timeLimit == NULL) { sCommand.sOpenClientSession.sTimeout = SCTIME_INFINITE; } else { sCommand.sOpenClientSession.sTimeout = *(uint64_t*)timeLimit; } sCommand.sOpenClientSession.sDestinationUUID = *((S_UUID*)destination); sCommand.sOpenClientSession.nLoginType = connectionMethod; if ((connectionMethod == TEEC_LOGIN_GROUP)||(connectionMethod == TEEC_LOGIN_GROUP_APPLICATION)) { /* connectionData MUST point to a uint32_t which contains the group * which this Client Application wants to connect as. The Linux Driver * is responsible for securely ensuring that the Client Application * instance is actually a member of this group. */ if (connectionData != NULL) { *(uint32_t*)sCommand.sOpenClientSession.sLoginData = *(uint32_t*)connectionData; sCommand.sHeader.nMessageSize += sizeof(uint32_t); } } sCommand.sOpenClientSession.nCancellationID = (uint32_t)operation; // used for TEEC_RequestCancellation if (operation != NULL) { operation->imp._pContext = context; operation->imp._hSession = S_HANDLE_NULL; operation->started = 1; } nError = scxExchangeMessage(context, &sCommand, &sAnswer, operation); if (operation != NULL) operation->started = 2; if (nError != TEEC_SUCCESS) { nReturnOrigin = TEEC_ORIGIN_COMMS; } else { nError = sAnswer.sOpenClientSession.nErrorCode; nReturnOrigin = sAnswer.sOpenClientSession.nReturnOrigin; } if (returnOrigin != NULL) *returnOrigin = nReturnOrigin; if (nError == S_SUCCESS) { session->imp._hClientSession = sAnswer.sOpenClientSession.hClientSession; session->imp._pContext = context; } return nError; } //----------------------------------------------------------------------------------------------------- TEEC_Result TEEC_InvokeCommandEx( TEEC_Session* session, const TEEC_TimeLimit* timeLimit, uint32_t commandID, TEEC_Operation* operation, uint32_t* returnOrigin) { TEEC_Result nError; SCHANNEL6_ANSWER sAnswer; SCHANNEL6_COMMAND sCommand; uint32_t nReturnOrigin; TEEC_Context * context; context = (TEEC_Context *)session->imp._pContext; memset(&sCommand, 0, sizeof(SCHANNEL6_COMMAND)); sCommand.sHeader.nMessageType = SCX_INVOKE_CLIENT_COMMAND; sCommand.sHeader.nMessageSize = (sizeof(SCHANNEL6_INVOKE_CLIENT_COMMAND_COMMAND) - sizeof(SCHANNEL6_COMMAND_HEADER))/sizeof(uint32_t); sCommand.sInvokeClientCommand.nClientCommandIdentifier = commandID; if (timeLimit == NULL) { sCommand.sInvokeClientCommand.sTimeout = SCTIME_INFINITE; } else { sCommand.sInvokeClientCommand.sTimeout = *(uint64_t*)timeLimit; } sCommand.sInvokeClientCommand.hClientSession = session->imp._hClientSession; sCommand.sInvokeClientCommand.nCancellationID = (uint32_t)operation; // used for TEEC_RequestCancellation if (operation != NULL) { operation->imp._pContext = session->imp._pContext; operation->imp._hSession = session->imp._hClientSession; operation->started = 1; } nError = scxExchangeMessage(context, &sCommand, &sAnswer, operation); if (operation != NULL) { operation->started = 2; operation->imp._hSession = S_HANDLE_NULL; operation->imp._pContext = NULL; } if (nError != TEEC_SUCCESS) { nReturnOrigin = TEEC_ORIGIN_COMMS; } else { nError = sAnswer.sInvokeClientCommand.nErrorCode; nReturnOrigin = sAnswer.sInvokeClientCommand.nReturnOrigin; } if (returnOrigin != NULL) *returnOrigin = nReturnOrigin; return nError; } //----------------------------------------------------------------------------------------------------- /* * Retrieves information about the implementation */ void TEEC_GetImplementationInfo( TEEC_Context* context, TEEC_ImplementationInfo* description) { TRACE_INFO("TEEC_GetImplementationInfo"); memset(description, 0, sizeof(TEEC_ImplementationInfo)); strcpy(description->apiDescription, S_VERSION_STRING); if (context != NULL) { SCX_VERSION_INFORMATION_BUFFER sInfoBuffer; uint32_t nResult; nResult = ioctl((S_HANDLE)context->imp._hConnection, IOCTL_SCX_GET_DESCRIPTION, &sInfoBuffer); if (nResult != S_SUCCESS) { TRACE_ERROR("TEEC_GetImplementationInfo[0x%X]: ioctl returned error: 0x%x ( %d)\n",context, nResult, errno); return; } memcpy(description->commsDescription, sInfoBuffer.sDriverDescription, 64); description->commsDescription[64] = 0; memcpy(description->TEEDescription, sInfoBuffer.sSecureWorldDescription, 64); description->TEEDescription[64] = 0; } } void TEEC_GetImplementationLimits( TEEC_ImplementationLimits* limits) { memset(limits, 0, sizeof(TEEC_ImplementationLimits)); /* A temp mem ref can not be mapped on more than 1Mb */ limits->pageSize = SIZE_4KB; limits->tmprefMaxSize = SIZE_1MB; limits->sharedMemMaxSize = SIZE_1MB * 8; }