/** * 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. */ /* * Implementation Notes: * * This API is NOT thread-safe. Indeed this Cryptoki implementation * only supports option 1 defined in PKCS#11, section 6.5.2: * "The application can specify that it will not be accessing the library concurrently * from multiple threads, and so the library need not worry about performing any type * of locking for the sake of thread-safety." */ #include "pkcs11_internal.h" /* ------------------------------------------------------------------------ System Service UUID ------------------------------------------------------------------------- */ const TEEC_UUID SERVICE_UUID = SERVICE_SYSTEM_UUID; /* ------------------------------------------------------------------------ Definition of the global TEE Context ------------------------------------------------------------------------- */ TEEC_Context g_sContext; /* A mutex that protects the access to the global context and to the g_bContextRefCounter flag */ LIB_MUTEX g_sContextMutex = LIB_MUTEX_INITIALIZER; /* Whether the context has already been initialized or not */ uint32_t g_nContextRefCounter = 0; bool g_bCryptokiInitialized = false; /* ------------------------------------------------------------------------ Internal global TEE context management ------------------------------------------------------------------------- */ void stubMutexLock(void) { libMutexLock(&g_sContextMutex); } void stubMutexUnlock(void) { libMutexUnlock(&g_sContextMutex); } /* This API must be protected by stubMutexLock/Unlock */ TEEC_Result stubInitializeContext(void) { TEEC_Result nTeeError; if (g_nContextRefCounter) { g_nContextRefCounter ++; return TEEC_SUCCESS; } nTeeError = TEEC_InitializeContext(NULL, &g_sContext); if (nTeeError == TEEC_SUCCESS) { g_nContextRefCounter = 1; } return nTeeError; } /* This API must be protected by stubMutexLock/Unlock */ void stubFinalizeContext(void) { if (g_nContextRefCounter > 0) { g_nContextRefCounter --; } if (g_nContextRefCounter == 0) { TEEC_FinalizeContext(&g_sContext); memset(&g_sContext, 0, sizeof(TEEC_Context)); } } /* ------------------------------------------------------------------------ Internal monitor management ------------------------------------------------------------------------- */ /** * Check that hSession is a valid primary session, * or a valid secondary session attached to a valid primary session. * * input: * S_HANDLE hSession: the session handle to check * output: * bool* pBoolIsPrimarySession: a boolean set to true if the session is primary, * set to false if the session if the session is secondary * returned boolean: set to true iff : * - either hSession is a valid primary session * - or hSession is a valid secondary session attached to a valid primary session **/ bool ckInternalSessionIsOpenedEx(S_HANDLE hSession, bool* pBoolIsPrimarySession) { PPKCS11_SESSION_CONTEXT_HEADER pHeader = (PPKCS11_SESSION_CONTEXT_HEADER)hSession; PPKCS11_PRIMARY_SESSION_CONTEXT pSession = NULL; if ((pHeader == NULL) || (pHeader->nMagicWord != PKCS11_SESSION_MAGIC)) { return FALSE; } if (pHeader->nSessionTag == PKCS11_PRIMARY_SESSION_TAG) /* primary session */ { pSession = (PPKCS11_PRIMARY_SESSION_CONTEXT)pHeader; *pBoolIsPrimarySession = true; /* check that primary session is valid */ return (pSession->hCryptoSession != CK_INVALID_HANDLE); } else if (pHeader->nSessionTag == PKCS11_SECONDARY_SESSION_TAG) /*secondary session */ { PPKCS11_SECONDARY_SESSION_CONTEXT pSecSession = (PPKCS11_SECONDARY_SESSION_CONTEXT)pHeader; *pBoolIsPrimarySession = false; /* check that primary session is still valid */ pSession = pSecSession->pPrimarySession; if ( (pSession == NULL) || (pSession->sHeader.nMagicWord != PKCS11_SESSION_MAGIC) || (pSession->sHeader.nSessionTag != PKCS11_PRIMARY_SESSION_TAG)) { return FALSE; } if (pSession->hCryptoSession == CK_INVALID_HANDLE) { return FALSE; } /* check that secondary session is valid */ return (pSecSession->hSecondaryCryptoSession != CK_INVALID_HANDLE); } else { return FALSE; } } /* ------------------------------------------------------------------------ Internal error management ------------------------------------------------------------------------- */ CK_RV ckInternalTeeErrorToCKError(TEEC_Result nError) { switch (nError) { case TEEC_SUCCESS: return CKR_OK; case TEEC_ERROR_BAD_PARAMETERS: case TEEC_ERROR_BAD_FORMAT: return CKR_ARGUMENTS_BAD; case TEEC_ERROR_OUT_OF_MEMORY: return CKR_HOST_MEMORY; case TEEC_ERROR_ACCESS_DENIED: return CKR_TOKEN_NOT_PRESENT; default: return CKR_DEVICE_ERROR; } } /* ------------------------------------------------------------------------ Public Functions ------------------------------------------------------------------------- */ CK_RV PKCS11_EXPORT C_Initialize(CK_VOID_PTR pInitArgs) { CK_RV nErrorCode; TEEC_Result nTeeError; if (pInitArgs != NULL_PTR) { return CKR_ARGUMENTS_BAD; } stubMutexLock(); if (g_bCryptokiInitialized) { nErrorCode = CKR_CRYPTOKI_ALREADY_INITIALIZED; } else { nTeeError = stubInitializeContext(); if (nTeeError == TEEC_SUCCESS) { g_bCryptokiInitialized = true; } nErrorCode = ckInternalTeeErrorToCKError(nTeeError); } stubMutexUnlock(); return nErrorCode; } CK_RV PKCS11_EXPORT C_Finalize(CK_VOID_PTR pReserved) { CK_RV nErrorCode; if (pReserved != NULL_PTR) { return CKR_ARGUMENTS_BAD; } stubMutexLock(); if (g_bCryptokiInitialized) { stubFinalizeContext(); g_bCryptokiInitialized = false; nErrorCode = CKR_OK; } else { nErrorCode = CKR_CRYPTOKI_NOT_INITIALIZED; } stubMutexUnlock(); return nErrorCode; } static const CK_INFO sImplementationInfo = { {2, 20}, /* cryptokiVersion, spec 2.20 */ "Trusted Logic", /* manufacturerID */ 0, /* flags */ "PKCS#11", /* libraryDescription */ {3, 0} /* libraryVersion */ }; CK_RV PKCS11_EXPORT C_GetInfo(CK_INFO_PTR pInfo) { if (!g_bCryptokiInitialized) { return CKR_CRYPTOKI_NOT_INITIALIZED; } if (pInfo == NULL_PTR) { return CKR_ARGUMENTS_BAD; } memcpy(pInfo, &sImplementationInfo, sizeof(CK_INFO)); return CKR_OK; }