1/**
2 * Copyright(c) 2011 Trusted Logic.   All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 *  * Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 *  * Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in
12 *    the documentation and/or other materials provided with the
13 *    distribution.
14 *  * Neither the name Trusted Logic nor the names of its
15 *    contributors may be used to endorse or promote products derived
16 *    from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/*
32 * Implementation Notes:
33 *
34 * This API is NOT thread-safe. Indeed this Cryptoki implementation
35 * only supports option 1 defined in PKCS#11, section 6.5.2:
36 * "The application can specify that it will not be accessing the library concurrently
37 * from multiple threads, and so the library need not worry about performing any type
38 * of locking for the sake of thread-safety."
39 */
40
41#include "pkcs11_internal.h"
42
43/* ------------------------------------------------------------------------
44    System Service UUID
45------------------------------------------------------------------------- */
46const TEEC_UUID SERVICE_UUID = SERVICE_SYSTEM_UUID;
47
48/* ------------------------------------------------------------------------
49    Definition of the global TEE Context
50------------------------------------------------------------------------- */
51TEEC_Context g_sContext;
52/* A mutex that protects the access to the global context and to the
53   g_bContextRefCounter flag */
54LIB_MUTEX g_sContextMutex = LIB_MUTEX_INITIALIZER;
55/* Whether the context has already been initialized or not */
56uint32_t  g_nContextRefCounter = 0;
57
58bool g_bCryptokiInitialized = false;
59
60/* ------------------------------------------------------------------------
61   Internal global TEE context management
62------------------------------------------------------------------------- */
63
64void stubMutexLock(void)
65{
66   libMutexLock(&g_sContextMutex);
67}
68
69void stubMutexUnlock(void)
70{
71   libMutexUnlock(&g_sContextMutex);
72}
73
74/* This API must be protected by stubMutexLock/Unlock */
75TEEC_Result stubInitializeContext(void)
76{
77   TEEC_Result nTeeError;
78
79   if (g_nContextRefCounter)
80   {
81      g_nContextRefCounter ++;
82      return TEEC_SUCCESS;
83   }
84
85   nTeeError = TEEC_InitializeContext(NULL, &g_sContext);
86   if (nTeeError == TEEC_SUCCESS)
87   {
88      g_nContextRefCounter = 1;
89   }
90
91   return nTeeError;
92}
93
94/* This API must be protected by stubMutexLock/Unlock */
95void stubFinalizeContext(void)
96{
97   if (g_nContextRefCounter > 0)
98   {
99      g_nContextRefCounter --;
100   }
101
102   if (g_nContextRefCounter == 0)
103   {
104      TEEC_FinalizeContext(&g_sContext);
105      memset(&g_sContext, 0, sizeof(TEEC_Context));
106   }
107}
108
109
110/* ------------------------------------------------------------------------
111                          Internal monitor management
112------------------------------------------------------------------------- */
113/**
114* Check that hSession is a valid primary session,
115* or a valid secondary session attached to a valid primary session.
116*
117* input:
118*   S_HANDLE hSession: the session handle to check
119* output:
120*   bool* pBoolIsPrimarySession: a boolean set to true if the session is primary,
121*             set to false if the session if the session is secondary
122*   returned boolean: set to true iff :
123*              - either hSession is a valid primary session
124*              - or hSession is a valid secondary session attached to a valid primary session
125**/
126bool ckInternalSessionIsOpenedEx(S_HANDLE hSession, bool* pBoolIsPrimarySession)
127{
128   PPKCS11_SESSION_CONTEXT_HEADER   pHeader = (PPKCS11_SESSION_CONTEXT_HEADER)hSession;
129   PPKCS11_PRIMARY_SESSION_CONTEXT  pSession = NULL;
130
131   if ((pHeader == NULL) || (pHeader->nMagicWord != PKCS11_SESSION_MAGIC))
132   {
133      return FALSE;
134   }
135   if (pHeader->nSessionTag == PKCS11_PRIMARY_SESSION_TAG) /* primary session */
136   {
137      pSession = (PPKCS11_PRIMARY_SESSION_CONTEXT)pHeader;
138
139      *pBoolIsPrimarySession = true;
140
141      /* check that primary session is valid */
142      return (pSession->hCryptoSession != CK_INVALID_HANDLE);
143   }
144   else if (pHeader->nSessionTag == PKCS11_SECONDARY_SESSION_TAG) /*secondary session */
145   {
146      PPKCS11_SECONDARY_SESSION_CONTEXT pSecSession = (PPKCS11_SECONDARY_SESSION_CONTEXT)pHeader;
147
148      *pBoolIsPrimarySession = false;
149
150      /* check that primary session is still valid */
151      pSession = pSecSession->pPrimarySession;
152      if (  (pSession == NULL) ||
153            (pSession->sHeader.nMagicWord != PKCS11_SESSION_MAGIC) ||
154            (pSession->sHeader.nSessionTag != PKCS11_PRIMARY_SESSION_TAG))
155      {
156         return FALSE;
157      }
158
159      if (pSession->hCryptoSession == CK_INVALID_HANDLE)
160      {
161         return FALSE;
162      }
163
164      /* check that secondary session is valid */
165      return (pSecSession->hSecondaryCryptoSession != CK_INVALID_HANDLE);
166   }
167   else
168   {
169     return FALSE;
170   }
171}
172
173/* ------------------------------------------------------------------------
174                          Internal error management
175------------------------------------------------------------------------- */
176
177CK_RV ckInternalTeeErrorToCKError(TEEC_Result nError)
178{
179   switch (nError)
180   {
181      case TEEC_SUCCESS:
182         return CKR_OK;
183
184      case TEEC_ERROR_BAD_PARAMETERS:
185      case TEEC_ERROR_BAD_FORMAT:
186         return CKR_ARGUMENTS_BAD;
187      case TEEC_ERROR_OUT_OF_MEMORY:
188         return CKR_HOST_MEMORY;
189      case TEEC_ERROR_ACCESS_DENIED:
190         return CKR_TOKEN_NOT_PRESENT;
191      default:
192         return CKR_DEVICE_ERROR;
193   }
194}
195
196/* ------------------------------------------------------------------------
197                          Public Functions
198------------------------------------------------------------------------- */
199CK_RV PKCS11_EXPORT C_Initialize(CK_VOID_PTR pInitArgs)
200{
201   CK_RV       nErrorCode;
202   TEEC_Result nTeeError;
203
204   if (pInitArgs != NULL_PTR)
205   {
206      return CKR_ARGUMENTS_BAD;
207   }
208
209   stubMutexLock();
210   if (g_bCryptokiInitialized)
211   {
212      nErrorCode = CKR_CRYPTOKI_ALREADY_INITIALIZED;
213   }
214   else
215   {
216      nTeeError = stubInitializeContext();
217      if (nTeeError == TEEC_SUCCESS)
218      {
219         g_bCryptokiInitialized = true;
220      }
221      nErrorCode = ckInternalTeeErrorToCKError(nTeeError);
222   }
223   stubMutexUnlock();
224
225   return nErrorCode;
226}
227
228CK_RV PKCS11_EXPORT C_Finalize(CK_VOID_PTR pReserved)
229{
230   CK_RV nErrorCode;
231
232   if (pReserved != NULL_PTR)
233   {
234      return CKR_ARGUMENTS_BAD;
235   }
236
237   stubMutexLock();
238   if (g_bCryptokiInitialized)
239   {
240      stubFinalizeContext();
241      g_bCryptokiInitialized = false;
242      nErrorCode = CKR_OK;
243   }
244   else
245   {
246      nErrorCode = CKR_CRYPTOKI_NOT_INITIALIZED;
247   }
248   stubMutexUnlock();
249
250   return nErrorCode;
251}
252
253static const CK_INFO sImplementationInfo =
254{
255   {2, 20},         /* cryptokiVersion, spec 2.20 */
256   "Trusted Logic", /* manufacturerID */
257   0,               /* flags */
258   "PKCS#11",       /* libraryDescription */
259   {3, 0}           /* libraryVersion */
260};
261
262CK_RV PKCS11_EXPORT C_GetInfo(CK_INFO_PTR pInfo)
263{
264   if (!g_bCryptokiInitialized)
265   {
266      return CKR_CRYPTOKI_NOT_INITIALIZED;
267   }
268   if (pInfo == NULL_PTR)
269   {
270      return CKR_ARGUMENTS_BAD;
271   }
272
273   memcpy(pInfo, &sImplementationInfo, sizeof(CK_INFO));
274   return CKR_OK;
275}
276