/** * 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. */ #ifdef __ANDROID32__ #include <stddef.h> #endif #include <stdlib.h> #include <string.h> #define SST_EXPORTS #define EXCLUDE_SERVICE_SYSTEM_SST_BASIC_TYPES #include "sst.h" /* Included for the TEE management */ #include "pkcs11_internal.h" static TEEC_Session g_SSTSession; static bool g_bSSTInitialized = false; /* ------------------------------------------------------------------------ TEEC -> SST error code translation ------------------------------------------------------------------------- */ static SST_ERROR static_SSTConvertErrorCode(TEEC_Result nError) { switch (nError) { case TEEC_SUCCESS: return SST_SUCCESS; case SST_ERROR_BAD_PARAMETERS: case SST_ERROR_ACCESS_DENIED: case SST_ERROR_ACCESS_CONFLICT: case SST_ERROR_CORRUPTED: case SST_ERROR_NO_SPACE: case SST_ERROR_ITEM_NOT_FOUND: case SST_ERROR_OUT_OF_MEMORY: case SST_ERROR_OVERFLOW: return nError; default: return SST_ERROR_GENERIC; } } static TEEC_Session* static_SSTGetSession(void) { if (g_bSSTInitialized) { return &g_SSTSession; } return NULL; } SST_ERROR SST_EXPORT_API SSTInit(void) { TEEC_Result nTeeError = TEEC_SUCCESS; TEEC_Operation sOperation; uint8_t nParamType3 = TEEC_NONE; void* pSignatureFile = NULL; uint32_t nSignatureFileLen = 0; uint32_t nLoginType; stubMutexLock(); if (g_bSSTInitialized) { /* SST library already initialized */ nTeeError = TEEC_SUCCESS; goto end; } nTeeError = stubInitializeContext(); if (nTeeError != TEEC_SUCCESS) { goto end; } /* Check if there is a signature file. * If yes, send it in param3, otherwise use LOGIN_APPLICATION */ nTeeError = TEEC_ReadSignatureFile(&pSignatureFile, &nSignatureFileLen); if (nTeeError == TEEC_ERROR_ITEM_NOT_FOUND) { nLoginType = TEEC_LOGIN_USER_APPLICATION; } else { if (nTeeError != TEEC_SUCCESS) { goto end; } sOperation.params[3].tmpref.buffer = pSignatureFile; sOperation.params[3].tmpref.size = nSignatureFileLen; nParamType3 = TEEC_MEMREF_TEMP_INPUT; nLoginType = TEEC_LOGIN_AUTHENTICATION; } sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_NONE, TEEC_NONE, TEEC_NONE, nParamType3); nTeeError = TEEC_OpenSession(&g_sContext, &g_SSTSession, /* OUT session */ &SERVICE_UUID, /* destination UUID */ nLoginType, /* connectionMethod */ NULL, /* connectionData */ &sOperation, /* IN OUT operation */ NULL /* OUT returnOrigin, optional */ ); if (nTeeError != TEEC_SUCCESS) { goto end_finalize_context; } g_bSSTInitialized = true; stubMutexUnlock(); return SST_SUCCESS; end_finalize_context: stubFinalizeContext(); end: stubMutexUnlock(); return static_SSTConvertErrorCode(nTeeError); } SST_ERROR SST_EXPORT_API SSTTerminate(void) { stubMutexLock(); if (g_bSSTInitialized) { TEEC_CloseSession(&g_SSTSession); stubFinalizeContext(); g_bSSTInitialized = false; } /* else if not intialized => success too */ stubMutexUnlock(); return SST_SUCCESS; } /* ------------------------------------------------------------------------ Other API Functions ------------------------------------------------------------------------- */ /* Check that the input filename is well-formed */ static SST_ERROR static_SSTCheckFileName(const char* pName) { uint32_t i; char c; if (pName == NULL) { return SST_ERROR_BAD_PARAMETERS; } for (i = 0; i <= SST_MAX_FILENAME; i++) { c = pName[i]; if (c == 0) { /* End of the string */ return SST_SUCCESS; } if (c == '/' || c == '\\') { /* Invalid character */ return SST_ERROR_BAD_PARAMETERS; } if (c < 0x20 || c >= 0x7F) { /* Filename contains illegal characters */ return SST_ERROR_BAD_PARAMETERS; } } /* Filename is too long. Zero terminator not found */ return SST_ERROR_BAD_PARAMETERS; } static SST_ERROR static_SSTCheckPattern( const char* pFilenamePattern) { uint32_t i; if(pFilenamePattern == NULL) { return S_SUCCESS; } /** * Check Forbidden characters. */ for (i = 0; pFilenamePattern[i] != 0; i++) { if(pFilenamePattern[i] < 0x20 ) { return S_ERROR_BAD_PARAMETERS; } else if(pFilenamePattern[i] == 0x2F ) /* '/' */ { return S_ERROR_BAD_PARAMETERS; } else if(pFilenamePattern[i] == 0x5C ) /* '\' */ { /** * Must be directly followed by asterisk character or question-mark * character. */ if (! ((pFilenamePattern[i+1] == '*' || pFilenamePattern[i+1] == '?'))) { return S_ERROR_BAD_PARAMETERS; } } else if(pFilenamePattern[i] >= 0x7F ) { return S_ERROR_BAD_PARAMETERS; } } return S_SUCCESS; } SST_ERROR SST_EXPORT_API SSTOpen(const char* pFilename, uint32_t nFlags, uint32_t nReserved, SST_HANDLE* phFile) { TEEC_Session* pSession; TEEC_Result nError; TEEC_Operation sOperation; uint32_t nReturnOrigin; SST_ERROR nErrorCode = SST_SUCCESS; if (phFile == NULL || nReserved != 0) { return SST_ERROR_BAD_PARAMETERS; } *phFile = SST_HANDLE_INVALID; nErrorCode = static_SSTCheckFileName(pFilename); if (nErrorCode != SST_SUCCESS) { return nErrorCode; } pSession = static_SSTGetSession(); if (pSession == NULL) { return SST_ERROR_GENERIC; } sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_TEMP_INPUT, TEEC_NONE, TEEC_NONE); sOperation.params[0].value.a = 1; /* Private storage */ sOperation.params[0].value.b = nFlags; /* Access flags */ sOperation.params[1].tmpref.buffer = (void*)pFilename; sOperation.params[1].tmpref.size = strlen(pFilename); nError = TEEC_InvokeCommand(pSession, SERVICE_SYSTEM_SST_OPEN_COMMAND_ID, /* commandID */ &sOperation, /* IN OUT operation */ &nReturnOrigin /* OUT returnOrigin, optional */ ); if (nError == TEEC_SUCCESS) { *phFile = (SST_HANDLE)sOperation.params[0].value.a; } return static_SSTConvertErrorCode(nError); } SST_ERROR SST_EXPORT_API SSTCloseHandle(SST_HANDLE hFile) { TEEC_Session* pSession; TEEC_Result nError; TEEC_Operation sOperation; uint32_t nReturnOrigin; if (hFile == S_HANDLE_NULL) { return SST_SUCCESS; } pSession = static_SSTGetSession(); if (pSession == NULL) { return SST_ERROR_GENERIC; } sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_NONE, TEEC_NONE, TEEC_NONE); sOperation.params[0].value.a = hFile; nError = TEEC_InvokeCommand(pSession, SERVICE_SYSTEM_SST_CLOSE_COMMAND_ID, /* commandID */ &sOperation, /* IN OUT operation */ &nReturnOrigin /* OUT returnOrigin, optional */ ); return static_SSTConvertErrorCode(nError); } SST_ERROR SST_EXPORT_API SSTWrite(SST_HANDLE hFile, const uint8_t* pBuffer, uint32_t nSize) { TEEC_Session* pSession; TEEC_Result nError; TEEC_Operation sOperation; uint32_t nReturnOrigin; if (pBuffer == NULL) { return SST_ERROR_BAD_PARAMETERS; } if (nSize == 0) { return SST_SUCCESS; } pSession = static_SSTGetSession(); if (pSession == NULL) { return SST_ERROR_GENERIC; } sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_MEMREF_TEMP_INPUT, TEEC_NONE, TEEC_NONE); sOperation.params[0].value.a = hFile; sOperation.params[1].tmpref.buffer = (void*)pBuffer; sOperation.params[1].tmpref.size = nSize; nError = TEEC_InvokeCommand(pSession, SERVICE_SYSTEM_SST_WRITE_COMMAND_ID, /* commandID */ &sOperation, /* IN OUT operation */ &nReturnOrigin /* OUT returnOrigin, optional */ ); return static_SSTConvertErrorCode(nError); } SST_ERROR SST_EXPORT_API SSTRead(SST_HANDLE hFile, uint8_t* pBuffer, uint32_t nSize, uint32_t* pnCount) { TEEC_Session* pSession; TEEC_Result nError; TEEC_Operation sOperation; uint32_t nReturnOrigin; if ((pBuffer == NULL) || (pnCount == NULL)) { return SST_ERROR_BAD_PARAMETERS; } *pnCount = 0; pSession = static_SSTGetSession(); if (pSession == NULL) { return SST_ERROR_GENERIC; } if (nSize == 0) { return SST_SUCCESS; } sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_MEMREF_TEMP_OUTPUT, TEEC_NONE, TEEC_NONE); sOperation.params[0].value.a = hFile; sOperation.params[1].tmpref.buffer = pBuffer; sOperation.params[1].tmpref.size = nSize; nError = TEEC_InvokeCommand(pSession, SERVICE_SYSTEM_SST_READ_COMMAND_ID, /* commandID */ &sOperation, /* IN OUT operation */ &nReturnOrigin /* OUT returnOrigin, optional */ ); *pnCount = sOperation.params[1].tmpref.size; /* The returned buffer size */ return static_SSTConvertErrorCode(nError); } SST_ERROR SST_EXPORT_API SSTSeek(SST_HANDLE hFile, int32_t nOffset, SST_WHENCE whence) { TEEC_Session* pSession; TEEC_Result nError; TEEC_Operation sOperation; uint32_t nReturnOrigin; switch(whence) { case SST_SEEK_SET: case SST_SEEK_CUR: case SST_SEEK_END: break; default: return SST_ERROR_BAD_PARAMETERS; } pSession = static_SSTGetSession(); if (pSession == NULL) { return SST_ERROR_GENERIC; } sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_VALUE_INPUT, TEEC_NONE, TEEC_NONE); sOperation.params[0].value.a = hFile; sOperation.params[1].value.a = nOffset; sOperation.params[1].value.b = (uint32_t)whence; nError = TEEC_InvokeCommand(pSession, SERVICE_SYSTEM_SST_SEEK_COMMAND_ID, /* commandID */ &sOperation, /* IN OUT operation */ &nReturnOrigin /* OUT returnOrigin, optional */ ); return static_SSTConvertErrorCode(nError); } static SST_ERROR SSTGetOffsetAndSize(SST_HANDLE hFile, uint32_t* pnOffset, uint32_t* pnSize) { TEEC_Session* pSession; TEEC_Result nError; TEEC_Operation sOperation; uint32_t nReturnOrigin; pSession = static_SSTGetSession(); if (pSession == NULL) { return SST_ERROR_GENERIC; } if (pnOffset == NULL) { return SST_ERROR_BAD_PARAMETERS; } sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_NONE, TEEC_NONE, TEEC_NONE); sOperation.params[0].value.a = (uint32_t)hFile; nError = TEEC_InvokeCommand(pSession, SERVICE_SYSTEM_SST_GET_OFFSET_AND_SIZE_COMMAND_ID, /* commandID */ &sOperation, /* IN OUT operation */ &nReturnOrigin /* OUT returnOrigin, optional */ ); if (pnOffset != NULL) { *pnOffset = sOperation.params[0].value.a; } if (pnSize != NULL) { *pnSize = sOperation.params[0].value.b; } return static_SSTConvertErrorCode(nError); } SST_ERROR SST_EXPORT_API SSTTell(SST_HANDLE hFile, uint32_t* pnPos) { return SSTGetOffsetAndSize(hFile, pnPos, NULL); } SST_ERROR SST_EXPORT_API SSTGetSize(const char* pFilename, uint32_t* pnSize) { TEEC_Session* pSession; TEEC_Result nError; TEEC_Operation sOperation; uint32_t nReturnOrigin; if ((pFilename == NULL) || (pnSize == NULL)) { return SST_ERROR_BAD_PARAMETERS; } nError = static_SSTCheckFileName(pFilename); if (nError != SST_SUCCESS) { return nError; } pSession = static_SSTGetSession(); if (pSession == NULL) { return SST_ERROR_GENERIC; } sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_TEMP_INPUT, TEEC_NONE, TEEC_NONE); sOperation.params[0].value.a = 1; /* private storage */ sOperation.params[0].value.b = 0; sOperation.params[1].tmpref.buffer = (void*)pFilename; sOperation.params[1].tmpref.size = strlen(pFilename); nError = TEEC_InvokeCommand(pSession, SERVICE_SYSTEM_SST_GET_SIZE_COMMAND_ID, /* commandID */ &sOperation, /* IN OUT operation */ &nReturnOrigin /* OUT returnOrigin, optional */ ); *pnSize = sOperation.params[0].value.a; return static_SSTConvertErrorCode(nError); } SST_ERROR SST_EXPORT_API SSTEof( SST_HANDLE hFile, bool* pbEof) { uint32_t nOffset; uint32_t nSize; SST_ERROR nError; if (pbEof == NULL) return SST_ERROR_BAD_PARAMETERS; nError = SSTGetOffsetAndSize(hFile, &nOffset, &nSize); if (nError == SST_SUCCESS) { if (nOffset >= nSize) { *pbEof = true; } else { *pbEof = false; } } return nError; } SST_ERROR SST_EXPORT_API SSTCloseAndDelete(SST_HANDLE hFile) { TEEC_Session* pSession; TEEC_Result nError; TEEC_Operation sOperation; uint32_t nReturnOrigin; pSession = static_SSTGetSession(); if (pSession == NULL) { return SST_ERROR_GENERIC; } sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_NONE, TEEC_NONE, TEEC_NONE); sOperation.params[0].value.a = hFile; nError = TEEC_InvokeCommand(pSession, SERVICE_SYSTEM_SST_CLOSE_DELETE_COMMAND_ID, /* commandID */ &sOperation, /* IN OUT operation */ &nReturnOrigin /* OUT returnOrigin, optional */ ); return static_SSTConvertErrorCode(nError); } SST_ERROR SST_EXPORT_API SSTTruncate(SST_HANDLE hFile, uint32_t nLength) { TEEC_Session* pSession; TEEC_Result nError; TEEC_Operation sOperation; uint32_t nReturnOrigin; pSession = static_SSTGetSession(); if (pSession == NULL) { return SST_ERROR_GENERIC; } sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_NONE, TEEC_NONE, TEEC_NONE); sOperation.params[0].value.a = hFile; sOperation.params[0].value.b = nLength; nError = TEEC_InvokeCommand(pSession, SERVICE_SYSTEM_SST_TRUNCATE_COMMAND_ID, /* commandID */ &sOperation, /* IN OUT operation */ &nReturnOrigin /* OUT returnOrigin, optional */ ); return static_SSTConvertErrorCode(nError); } SST_ERROR SST_EXPORT_API SSTRename(SST_HANDLE hFile, const char* pNewFilename) { TEEC_Session* pSession; TEEC_Result nError; TEEC_Operation sOperation; uint32_t nReturnOrigin; pSession = static_SSTGetSession(); if (pSession == NULL) { return SST_ERROR_GENERIC; } if (pNewFilename == NULL) { return SST_ERROR_BAD_PARAMETERS; } nError = static_SSTCheckFileName(pNewFilename); if (nError != SST_SUCCESS) { return nError; } sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_MEMREF_TEMP_INPUT, TEEC_NONE, TEEC_NONE); sOperation.params[0].value.a = hFile; sOperation.params[1].tmpref.buffer = (void*)pNewFilename; sOperation.params[1].tmpref.size = strlen(pNewFilename); nError = TEEC_InvokeCommand(pSession, SERVICE_SYSTEM_SST_RENAME_COMMAND_ID, /* commandID */ &sOperation, /* IN OUT operation */ &nReturnOrigin /* OUT returnOrigin, optional */ ); return static_SSTConvertErrorCode(nError); } SST_ERROR SST_EXPORT_API SSTEnumerationStart(const char* pFilenamePattern, uint32_t nReserved1, uint32_t nReserved2, SST_HANDLE* phFileEnumeration) { TEEC_Session* pSession; TEEC_Result nError; TEEC_Operation sOperation; uint32_t nReturnOrigin; if (nReserved1!=0 || nReserved2!=0) { return SST_ERROR_BAD_PARAMETERS; } if (phFileEnumeration==NULL) { return SST_ERROR_BAD_PARAMETERS; } *phFileEnumeration = SST_HANDLE_INVALID; nError = static_SSTCheckPattern(pFilenamePattern); if (nError != SST_SUCCESS) { return nError; } pSession = static_SSTGetSession(); if (pSession == NULL) { return SST_ERROR_GENERIC; } sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_TEMP_INPUT, TEEC_NONE, TEEC_NONE); sOperation.params[0].value.a = 1; /* Private storage */ sOperation.params[1].tmpref.buffer = (void*)pFilenamePattern; if (pFilenamePattern != NULL) { sOperation.params[1].tmpref.size = strlen(pFilenamePattern); } else { sOperation.params[1].tmpref.size = 0; } nError = TEEC_InvokeCommand(pSession, SERVICE_SYSTEM_SST_ENUM_START_COMMAND_ID, /* commandID */ &sOperation, /* IN OUT operation */ &nReturnOrigin /* OUT returnOrigin, optional */ ); *phFileEnumeration = (SST_HANDLE)sOperation.params[0].value.a; return static_SSTConvertErrorCode(nError); } SST_ERROR SST_EXPORT_API SSTEnumerationCloseHandle(SST_HANDLE hFileEnumeration) { TEEC_Session* pSession; TEEC_Result nError; TEEC_Operation sOperation; uint32_t nReturnOrigin; pSession = static_SSTGetSession(); if (pSession == NULL) { return SST_ERROR_GENERIC; } sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT, TEEC_NONE, TEEC_NONE, TEEC_NONE); sOperation.params[0].value.a = hFileEnumeration; nError = TEEC_InvokeCommand(pSession, SERVICE_SYSTEM_SST_ENUM_CLOSE_COMMAND_ID, /* commandID */ &sOperation, /* IN OUT operation */ &nReturnOrigin /* OUT returnOrigin, optional */ ); return static_SSTConvertErrorCode(nError); } SST_ERROR SST_EXPORT_API SSTEnumerationGetNext(SST_HANDLE hFileEnumeration, SST_FILE_INFO** ppFileInfo) { TEEC_Session* pSession; TEEC_Result nError; TEEC_Operation sOperation; uint32_t nReturnOrigin; SST_FILE_INFO* pInfo = NULL; char sFilename[SST_MAX_FILENAME]; if (ppFileInfo==NULL) { return SST_ERROR_BAD_PARAMETERS; } pSession = static_SSTGetSession(); if (pSession == NULL) { return SST_ERROR_GENERIC; } sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_MEMREF_TEMP_OUTPUT, TEEC_NONE, TEEC_NONE); sOperation.params[0].value.a = hFileEnumeration; sOperation.params[1].tmpref.buffer = sFilename; sOperation.params[1].tmpref.size = SST_MAX_FILENAME; nError = TEEC_InvokeCommand(pSession, SERVICE_SYSTEM_SST_ENUM_GETNEXT_COMMAND_ID, /* commandID */ &sOperation, /* IN OUT operation */ &nReturnOrigin /* OUT returnOrigin, optional */ ); if (nError == TEEC_SUCCESS) { if (sOperation.params[1].tmpref.size <= SST_MAX_FILENAME) { pInfo = (SST_FILE_INFO*)malloc(sizeof(SST_FILE_INFO)); if (pInfo == NULL) { return SST_ERROR_OUT_OF_MEMORY; } pInfo->pName = (char*)malloc(sOperation.params[1].tmpref.size+1); if (pInfo->pName == NULL) { free(pInfo); return SST_ERROR_OUT_OF_MEMORY; } memcpy(pInfo->pName, sFilename, sOperation.params[1].tmpref.size); /* Add zero terminator */ pInfo->pName[sOperation.params[1].tmpref.size] = 0; pInfo->nSize = sOperation.params[0].value.b; } } *ppFileInfo = pInfo; return static_SSTConvertErrorCode(nError); } SST_ERROR SST_EXPORT_API SSTDestroyFileInfo(SST_FILE_INFO* pFileInfo) { TEEC_Session* pSession; pSession = static_SSTGetSession(); if (pSession == NULL) { return SST_ERROR_GENERIC; } if (pFileInfo != NULL) { free(pFileInfo->pName); free(pFileInfo); } return SST_SUCCESS; }