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