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 ------------------------------------------------------------------------- */
46 const TEEC_UUID SERVICE_UUID = SERVICE_SYSTEM_UUID;
47 
48 /* ------------------------------------------------------------------------
49     Definition of the global TEE Context
50 ------------------------------------------------------------------------- */
51 TEEC_Context g_sContext;
52 /* A mutex that protects the access to the global context and to the
53    g_bContextRefCounter flag */
54 LIB_MUTEX g_sContextMutex = LIB_MUTEX_INITIALIZER;
55 /* Whether the context has already been initialized or not */
56 uint32_t  g_nContextRefCounter = 0;
57 
58 bool g_bCryptokiInitialized = false;
59 
60 /* ------------------------------------------------------------------------
61    Internal global TEE context management
62 ------------------------------------------------------------------------- */
63 
stubMutexLock(void)64 void stubMutexLock(void)
65 {
66    libMutexLock(&g_sContextMutex);
67 }
68 
stubMutexUnlock(void)69 void stubMutexUnlock(void)
70 {
71    libMutexUnlock(&g_sContextMutex);
72 }
73 
74 /* This API must be protected by stubMutexLock/Unlock */
stubInitializeContext(void)75 TEEC_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 */
stubFinalizeContext(void)95 void 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 **/
ckInternalSessionIsOpenedEx(S_HANDLE hSession,bool * pBoolIsPrimarySession)126 bool 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 
ckInternalTeeErrorToCKError(TEEC_Result nError)177 CK_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 ------------------------------------------------------------------------- */
C_Initialize(CK_VOID_PTR pInitArgs)199 CK_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 
C_Finalize(CK_VOID_PTR pReserved)228 CK_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 
253 static 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 
C_GetInfo(CK_INFO_PTR pInfo)262 CK_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