/**
* 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;
}