/** * 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: * * The PKCS11 session handle is directly mapped on the * Trusted Foundations Software session handle (S_HANDLE). */ #include "pkcs11_internal.h" /* ------------------------------------------------------------------------ Public Functions ------------------------------------------------------------------------- */ CK_RV PKCS11_EXPORT C_OpenSession(CK_SLOT_ID slotID, /* the slot's ID */ CK_FLAGS flags, /* defined in CK_SESSION_INFO */ CK_VOID_PTR pApplication, /* pointer passed to callback */ CK_NOTIFY Notify, /* notification callback function */ CK_SESSION_HANDLE* phSession) /* receives new session handle */ { CK_RV nErrorCode = CKR_OK; uint32_t nErrorOrigin = TEEC_ORIGIN_API; TEEC_Result nTeeError; TEEC_Operation sOperation; PPKCS11_PRIMARY_SESSION_CONTEXT pSession = NULL; PPKCS11_SECONDARY_SESSION_CONTEXT pSecondarySession = NULL; uint32_t nLoginType; uint32_t nLoginData = 0; void* pLoginData = NULL; bool bIsPrimarySession; char* pSignatureFile = NULL; uint32_t nSignatureFileLen = 0; uint8_t nParamType3 = TEEC_NONE; /* Prevent the compiler from complaining about unused parameters */ do{(void)pApplication;}while(0); do{(void)Notify;}while(0); if (phSession == NULL) { return CKR_ARGUMENTS_BAD; } /* Check Cryptoki is initialized */ if (!g_bCryptokiInitialized) { return CKR_CRYPTOKI_NOT_INITIALIZED; } if ((flags & CKVF_OPEN_SUB_SESSION) == 0) { *phSession = CK_INVALID_HANDLE; /* * Allocate the session context */ pSession = (PPKCS11_PRIMARY_SESSION_CONTEXT)malloc(sizeof(PKCS11_PRIMARY_SESSION_CONTEXT)); if (pSession == NULL) { return CKR_DEVICE_MEMORY; } pSession->sHeader.nMagicWord = PKCS11_SESSION_MAGIC; pSession->sHeader.nSessionTag = PKCS11_PRIMARY_SESSION_TAG; memset(&pSession->sSession, 0, sizeof(TEEC_Session)); pSession->sSecondarySessionTable.pRoot = NULL_PTR; /* The structure must be initialized first (in a portable manner) to make it work on Win32 */ memset(&pSession->sSecondarySessionTableMutex, 0, sizeof(pSession->sSecondarySessionTableMutex)); libMutexInit(&pSession->sSecondarySessionTableMutex); switch (slotID) { case CKV_TOKEN_SYSTEM_SHARED: case CKV_TOKEN_USER_SHARED: nLoginType = TEEC_LOGIN_PUBLIC; break; case CKV_TOKEN_SYSTEM: case CKV_TOKEN_USER: default: nLoginType = TEEC_LOGIN_AUTHENTICATION; break; } /* Group tokens */ if ((slotID >= 0x00010000) && (slotID <= 0x0002FFFF)) { nLoginType = TEEC_LOGIN_GROUP; /* The 16 lower-order bits encode the group identifier */ nLoginData = (uint32_t)slotID & 0x0000FFFF; pLoginData = (void*)&nLoginData; /* Update the slotID for the system / PKCS11 service */ if ((slotID >= 0x00010000) && (slotID <= 0x0001FFFF)) { /* System group token */ slotID = 3; /* CKV_TOKEN_SYSTEM_GROUP */ } else /* ((slotID >= 0x00020000) && (slotID <= 0x0002FFFF)) */ { /* User group token */ slotID = 0x4014; /* CKV_TOKEN_USER_GROUP */ } } retry: memset(&sOperation, 0, sizeof(TEEC_Operation)); if (nLoginType == TEEC_LOGIN_AUTHENTICATION) { nTeeError = TEEC_ReadSignatureFile((void **)&pSignatureFile, &nSignatureFileLen); if (nTeeError != TEEC_ERROR_ITEM_NOT_FOUND) { if (nTeeError != TEEC_SUCCESS) { goto error; } sOperation.params[3].tmpref.buffer = pSignatureFile; sOperation.params[3].tmpref.size = nSignatureFileLen; nParamType3 = TEEC_MEMREF_TEMP_INPUT; } else { /* No signature file found. * Should use LOGIN_APPLICATION for now * Can not use TEEC_LOGIN_AUTHENTICATION as this means that all .exe wil need a signature file * - a bit annoying for when passing the tests */ nLoginType = TEEC_LOGIN_USER_APPLICATION; } } sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_NONE, TEEC_NONE, TEEC_NONE, nParamType3); nTeeError = TEEC_OpenSession(&g_sContext, &pSession->sSession, /* OUT session */ &SERVICE_UUID, /* destination UUID */ nLoginType, /* connectionMethod */ pLoginData, /* connectionData */ &sOperation, /* IN OUT operation */ NULL /* OUT returnOrigin, optional */ ); if (nTeeError != TEEC_SUCCESS) { /* No need of the returnOrigin as this is not specific to P11 */ if ( (nTeeError == TEEC_ERROR_NOT_SUPPORTED) && (nLoginType == TEEC_LOGIN_AUTHENTICATION)) { /* We could not open a session with the login TEEC_LOGIN_AUTHENTICATION */ /* If it is not supported by the product, */ /* retry with fallback to TEEC_LOGIN_USER_APPLICATION */ nLoginType = TEEC_LOGIN_USER_APPLICATION; goto retry; } /* The ERROR_ACCESS_DENIED, if returned, will be converted into CKR_TOKEN_NOT_PRESENT * For the External Cryptographic API, this means that the authentication * of the calling application fails. */ goto error; } memset(&sOperation, 0, sizeof(TEEC_Operation)); sOperation.params[0].value.a = slotID; sOperation.params[0].value.b = flags; /* access flags */ sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_NONE, TEEC_NONE, TEEC_NONE); nTeeError = TEEC_InvokeCommand(&pSession->sSession, SERVICE_SYSTEM_PKCS11_C_OPEN_SESSION_COMMAND_ID & 0x00007FFF, &sOperation, /* IN OUT operation */ &nErrorOrigin /* OUT returnOrigin, optional */ ); if (nTeeError != TEEC_SUCCESS) { goto error; } *phSession = (CK_SESSION_HANDLE)pSession; pSession->hCryptoSession = sOperation.params[0].value.a; return CKR_OK; } else { bool bResult; /* Check that {*phSession} is a valid primary session handle */ if ((!ckInternalSessionIsOpenedEx(*phSession, &bIsPrimarySession)) || (!bIsPrimarySession)) { return CKR_SESSION_HANDLE_INVALID; } pSession = (PPKCS11_PRIMARY_SESSION_CONTEXT)(*phSession); /* allocate the secondary session context */ pSecondarySession = (PKCS11_SECONDARY_SESSION_CONTEXT*)malloc(sizeof(PKCS11_SECONDARY_SESSION_CONTEXT)); if (pSecondarySession == NULL) { return CKR_DEVICE_MEMORY; } pSecondarySession->sHeader.nMagicWord = PKCS11_SESSION_MAGIC; pSecondarySession->sHeader.nSessionTag = PKCS11_SECONDARY_SESSION_TAG; pSecondarySession->pPrimarySession = pSession; libMutexLock(&pSession->sSecondarySessionTableMutex); bResult = libObjectHandle16Add(&pSession->sSecondarySessionTable, &pSecondarySession->sSecondarySessionNode); libMutexUnlock(&pSession->sSecondarySessionTableMutex); if (bResult == false) { free(pSecondarySession); return CKR_DEVICE_MEMORY; } memset(&sOperation, 0, sizeof(TEEC_Operation)); sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_NONE, TEEC_NONE, TEEC_NONE); nTeeError = TEEC_InvokeCommand(&pSession->sSession, (pSession->hCryptoSession << 16) | (1 << 15) | (SERVICE_SYSTEM_PKCS11_C_OPEN_SESSION_COMMAND_ID & 0x00007FFF), &sOperation, /* IN OUT operation */ &nErrorOrigin /* OUT returnOrigin, optional */ ); if (nTeeError != TEEC_SUCCESS) { goto error; } *phSession = (CK_SESSION_HANDLE)pSecondarySession; pSecondarySession->hSecondaryCryptoSession = sOperation.params[0].value.a; return CKR_OK; } error: nErrorCode = (nErrorOrigin == TEEC_ORIGIN_TRUSTED_APP ? nTeeError : ckInternalTeeErrorToCKError(nTeeError)); if ((flags & CKVF_OPEN_SUB_SESSION) == 0) { libMutexDestroy(&pSession->sSecondarySessionTableMutex); free(pSession); } else { libMutexLock(&pSession->sSecondarySessionTableMutex); libObjectHandle16Remove(&pSession->sSecondarySessionTable,&pSecondarySession->sSecondarySessionNode); libMutexUnlock(&pSession->sSecondarySessionTableMutex); free(pSecondarySession); } return nErrorCode; } CK_RV PKCS11_EXPORT C_CloseSession(CK_SESSION_HANDLE hSession) /* the session's handle */ { CK_RV nErrorCode = CKR_OK; uint32_t nErrorOrigin = TEEC_ORIGIN_API; TEEC_Result nTeeError; TEEC_Operation sOperation; bool bIsPrimarySession; /* Check Cryptoki is initialized */ if (!g_bCryptokiInitialized) { return CKR_CRYPTOKI_NOT_INITIALIZED; } if (!ckInternalSessionIsOpenedEx(hSession, &bIsPrimarySession)) { return CKR_SESSION_HANDLE_INVALID; } if (bIsPrimarySession) { LIB_OBJECT_NODE_HANDLE16* pObject; PPKCS11_SECONDARY_SESSION_CONTEXT pSecSession; PPKCS11_PRIMARY_SESSION_CONTEXT pSession = (PPKCS11_PRIMARY_SESSION_CONTEXT)hSession; hSession = pSession->hCryptoSession; memset(&sOperation, 0, sizeof(TEEC_Operation)); sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_NONE, TEEC_NONE, TEEC_NONE, TEEC_NONE); nTeeError = TEEC_InvokeCommand(&pSession->sSession, (pSession->hCryptoSession << 16 ) | (SERVICE_SYSTEM_PKCS11_C_CLOSE_SESSION_COMMAND_ID & 0x00007FFF), &sOperation, /* IN OUT operation */ &nErrorOrigin /* OUT returnOrigin, optional */ ); if (nTeeError != TEEC_SUCCESS) { goto end; } TEEC_CloseSession(&pSession->sSession); memset(&pSession->sSession, 0, sizeof(TEEC_Session)); /* Free all secondary session contexts */ libMutexLock(&pSession->sSecondarySessionTableMutex); pObject = libObjectHandle16RemoveOne(&pSession->sSecondarySessionTable); while (pObject != NULL) { /* find all secondary session contexts, and release associated resources */ pSecSession = LIB_OBJECT_CONTAINER_OF(pObject, //ptr PKCS11_SECONDARY_SESSION_CONTEXT,//type sSecondarySessionNode);//member /* free secondary session context */ free(pSecSession); pObject = libObjectHandle16RemoveOne(&pSession->sSecondarySessionTable); } libMutexUnlock(&pSession->sSecondarySessionTableMutex); libMutexDestroy(&pSession->sSecondarySessionTableMutex); /* free primary session context */ free(pSession); } else { PPKCS11_SECONDARY_SESSION_CONTEXT pSecSession = (PPKCS11_SECONDARY_SESSION_CONTEXT)hSession; PPKCS11_PRIMARY_SESSION_CONTEXT pSession; uint32_t nCommandID = ( (pSecSession->hSecondaryCryptoSession & 0xFFFF) << 16 ) | (1 << 15) | (SERVICE_SYSTEM_PKCS11_C_CLOSE_SESSION_COMMAND_ID & 0x00007FFF); /* every pre-check are fine, then, update the local handles */ hSession = pSecSession->pPrimarySession->hCryptoSession; pSession = (PPKCS11_PRIMARY_SESSION_CONTEXT)(pSecSession->pPrimarySession); memset(&sOperation, 0, sizeof(TEEC_Operation)); sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_NONE, TEEC_NONE, TEEC_NONE, TEEC_NONE); nTeeError = TEEC_InvokeCommand(&pSession->sSession, nCommandID, &sOperation, /* IN OUT operation */ &nErrorOrigin /* OUT returnOrigin, optional */ ); if (nTeeError != TEEC_SUCCESS) { goto end; } /* remove the object from the table */ libMutexLock(&pSession->sSecondarySessionTableMutex); libObjectHandle16Remove(&pSecSession->pPrimarySession->sSecondarySessionTable, &pSecSession->sSecondarySessionNode); libMutexUnlock(&pSession->sSecondarySessionTableMutex); /* free secondary session context */ free(pSecSession); } end: nErrorCode = (nErrorOrigin == TEEC_ORIGIN_TRUSTED_APP ? nTeeError : ckInternalTeeErrorToCKError(nTeeError)); return nErrorCode; } CK_RV PKCS11_EXPORT C_Login(CK_SESSION_HANDLE hSession, /* the session's handle */ CK_USER_TYPE userType, /* the user type */ const CK_UTF8CHAR* pPin, /* the user's PIN */ CK_ULONG ulPinLen) /* the length of the PIN */ { /* Prevent the compiler from complaining about unused variables */ do{(void)hSession;}while(0); do{(void)userType;}while(0); do{(void)pPin;}while(0); do{(void)ulPinLen;}while(0); return CKR_OK; } CK_RV PKCS11_EXPORT C_Logout(CK_SESSION_HANDLE hSession) /* the session's handle */ { do{(void)hSession;}while(0); return CKR_OK; }