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  * The PKCS11 session handle is directly mapped on the
35  * Trusted Foundations Software session handle (S_HANDLE).
36  */
37 
38 #include "pkcs11_internal.h"
39 
40 
41 /* ------------------------------------------------------------------------
42                           Public Functions
43 ------------------------------------------------------------------------- */
44 
45 
C_OpenSession(CK_SLOT_ID slotID,CK_FLAGS flags,CK_VOID_PTR pApplication,CK_NOTIFY Notify,CK_SESSION_HANDLE * phSession)46 CK_RV PKCS11_EXPORT C_OpenSession(CK_SLOT_ID              slotID,        /* the slot's ID */
47                                     CK_FLAGS              flags,         /* defined in CK_SESSION_INFO */
48                                     CK_VOID_PTR           pApplication,  /* pointer passed to callback */
49                                     CK_NOTIFY             Notify,        /* notification callback function */
50                                     CK_SESSION_HANDLE*    phSession)     /* receives new session handle */
51 {
52    CK_RV                   nErrorCode = CKR_OK;
53    uint32_t                nErrorOrigin = TEEC_ORIGIN_API;
54    TEEC_Result             nTeeError;
55    TEEC_Operation          sOperation;
56    PPKCS11_PRIMARY_SESSION_CONTEXT   pSession = NULL;
57    PPKCS11_SECONDARY_SESSION_CONTEXT pSecondarySession = NULL;
58    uint32_t                nLoginType;
59    uint32_t                nLoginData = 0;
60    void*                   pLoginData = NULL;
61    bool                    bIsPrimarySession;
62    char*                   pSignatureFile = NULL;
63    uint32_t                nSignatureFileLen = 0;
64    uint8_t                 nParamType3 = TEEC_NONE;
65 
66    /* Prevent the compiler from complaining about unused parameters */
67    do{(void)pApplication;}while(0);
68    do{(void)Notify;}while(0);
69 
70    if (phSession == NULL)
71    {
72       return CKR_ARGUMENTS_BAD;
73    }
74 
75       /* Check Cryptoki is initialized */
76    if (!g_bCryptokiInitialized)
77    {
78       return CKR_CRYPTOKI_NOT_INITIALIZED;
79    }
80 
81    if ((flags & CKVF_OPEN_SUB_SESSION) == 0)
82    {
83       *phSession = CK_INVALID_HANDLE;
84 
85       /*
86       * Allocate the session context
87       */
88       pSession = (PPKCS11_PRIMARY_SESSION_CONTEXT)malloc(sizeof(PKCS11_PRIMARY_SESSION_CONTEXT));
89       if (pSession == NULL)
90       {
91          return CKR_DEVICE_MEMORY;
92       }
93 
94       pSession->sHeader.nMagicWord  = PKCS11_SESSION_MAGIC;
95       pSession->sHeader.nSessionTag = PKCS11_PRIMARY_SESSION_TAG;
96       memset(&pSession->sSession, 0, sizeof(TEEC_Session));
97       pSession->sSecondarySessionTable.pRoot = NULL_PTR;
98 
99       /* The structure must be initialized first (in a portable manner)
100          to make it work on Win32 */
101       memset(&pSession->sSecondarySessionTableMutex, 0,
102                sizeof(pSession->sSecondarySessionTableMutex));
103       libMutexInit(&pSession->sSecondarySessionTableMutex);
104 
105       switch (slotID)
106       {
107       case CKV_TOKEN_SYSTEM_SHARED:
108       case CKV_TOKEN_USER_SHARED:
109          nLoginType = TEEC_LOGIN_PUBLIC;
110          break;
111 
112       case CKV_TOKEN_SYSTEM:
113       case CKV_TOKEN_USER:
114       default:
115          nLoginType = TEEC_LOGIN_AUTHENTICATION;
116          break;
117       }
118 
119       /* Group tokens */
120       if ((slotID >= 0x00010000) && (slotID <= 0x0002FFFF))
121       {
122          nLoginType = TEEC_LOGIN_GROUP;
123 
124          /* The 16 lower-order bits encode the group identifier */
125          nLoginData = (uint32_t)slotID & 0x0000FFFF;
126          pLoginData = (void*)&nLoginData;
127 
128          /* Update the slotID for the system / PKCS11 service */
129          if ((slotID >= 0x00010000) && (slotID <= 0x0001FFFF))
130          {
131             /* System group token */
132             slotID = 3;       /* CKV_TOKEN_SYSTEM_GROUP */
133          }
134          else  /* ((slotID >= 0x00020000) && (slotID <= 0x0002FFFF)) */
135          {
136             /* User group token */
137             slotID = 0x4014;  /* CKV_TOKEN_USER_GROUP */
138          }
139       }
140 
141 retry:
142       memset(&sOperation, 0, sizeof(TEEC_Operation));
143 
144       if (nLoginType == TEEC_LOGIN_AUTHENTICATION)
145       {
146           nTeeError = TEEC_ReadSignatureFile((void **)&pSignatureFile, &nSignatureFileLen);
147           if (nTeeError != TEEC_ERROR_ITEM_NOT_FOUND)
148           {
149               if (nTeeError != TEEC_SUCCESS)
150               {
151                   goto error;
152               }
153 
154               sOperation.params[3].tmpref.buffer = pSignatureFile;
155               sOperation.params[3].tmpref.size   = nSignatureFileLen;
156               nParamType3 = TEEC_MEMREF_TEMP_INPUT;
157           }
158           else
159           {
160               /* No signature file found.
161               * Should use LOGIN_APPLICATION for now
162               * Can not use TEEC_LOGIN_AUTHENTICATION as this means that all .exe wil need a signature file
163               * - a bit annoying for when passing the tests
164               */
165               nLoginType = TEEC_LOGIN_USER_APPLICATION;
166           }
167       }
168 
169       sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_NONE, TEEC_NONE, TEEC_NONE, nParamType3);
170       nTeeError = TEEC_OpenSession(&g_sContext,
171                                 &pSession->sSession,        /* OUT session */
172                                 &SERVICE_UUID,              /* destination UUID */
173                                 nLoginType,                 /* connectionMethod */
174                                 pLoginData,                 /* connectionData */
175                                 &sOperation,                /* IN OUT operation */
176                                 NULL                        /* OUT returnOrigin, optional */
177                                 );
178       if (nTeeError != TEEC_SUCCESS)
179       {
180          /* No need of the returnOrigin as this is not specific to P11 */
181 
182          if (  (nTeeError == TEEC_ERROR_NOT_SUPPORTED) &&
183                (nLoginType == TEEC_LOGIN_AUTHENTICATION))
184          {
185             /* We could not open a session with the login TEEC_LOGIN_AUTHENTICATION */
186             /* If it is not supported by the product, */
187             /* retry with fallback to TEEC_LOGIN_USER_APPLICATION */
188             nLoginType = TEEC_LOGIN_USER_APPLICATION;
189             goto retry;
190          }
191 
192          /* The ERROR_ACCESS_DENIED, if returned, will be converted into CKR_TOKEN_NOT_PRESENT
193           * For the External Cryptographic API, this means that the authentication
194           * of the calling application fails.
195           */
196          goto error;
197       }
198 
199       memset(&sOperation, 0, sizeof(TEEC_Operation));
200       sOperation.params[0].value.a = slotID;
201       sOperation.params[0].value.b = flags;  /* access flags */
202       sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_NONE, TEEC_NONE, TEEC_NONE);
203       nTeeError = TEEC_InvokeCommand(&pSession->sSession,
204                                   SERVICE_SYSTEM_PKCS11_C_OPEN_SESSION_COMMAND_ID & 0x00007FFF,
205                                   &sOperation,              /* IN OUT operation */
206                                   &nErrorOrigin             /* OUT returnOrigin, optional */
207                                  );
208       if (nTeeError != TEEC_SUCCESS)
209       {
210          goto error;
211       }
212 
213       *phSession = (CK_SESSION_HANDLE)pSession;
214       pSession->hCryptoSession = sOperation.params[0].value.a;
215 
216       return CKR_OK;
217    }
218    else
219    {
220       bool bResult;
221 
222       /* Check that {*phSession} is a valid primary session handle */
223       if ((!ckInternalSessionIsOpenedEx(*phSession, &bIsPrimarySession)) ||
224          (!bIsPrimarySession))
225       {
226          return CKR_SESSION_HANDLE_INVALID;
227       }
228 
229       pSession = (PPKCS11_PRIMARY_SESSION_CONTEXT)(*phSession);
230 
231       /* allocate the secondary session context */
232       pSecondarySession = (PKCS11_SECONDARY_SESSION_CONTEXT*)malloc(sizeof(PKCS11_SECONDARY_SESSION_CONTEXT));
233       if (pSecondarySession == NULL)
234       {
235          return CKR_DEVICE_MEMORY;
236       }
237       pSecondarySession->sHeader.nMagicWord  = PKCS11_SESSION_MAGIC;
238       pSecondarySession->sHeader.nSessionTag = PKCS11_SECONDARY_SESSION_TAG;
239       pSecondarySession->pPrimarySession = pSession;
240 
241       libMutexLock(&pSession->sSecondarySessionTableMutex);
242       bResult = libObjectHandle16Add(&pSession->sSecondarySessionTable,
243                                     &pSecondarySession->sSecondarySessionNode);
244       libMutexUnlock(&pSession->sSecondarySessionTableMutex);
245       if (bResult == false)
246       {
247          free(pSecondarySession);
248          return CKR_DEVICE_MEMORY;
249       }
250 
251       memset(&sOperation, 0, sizeof(TEEC_Operation));
252       sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_NONE, TEEC_NONE, TEEC_NONE);
253       nTeeError = TEEC_InvokeCommand(&pSession->sSession,
254                                   (pSession->hCryptoSession << 16) |
255                                     (1 << 15) |
256                                     (SERVICE_SYSTEM_PKCS11_C_OPEN_SESSION_COMMAND_ID & 0x00007FFF),
257                                   &sOperation,                 /* IN OUT operation */
258                                   &nErrorOrigin                /* OUT returnOrigin, optional */
259                                  );
260       if (nTeeError != TEEC_SUCCESS)
261       {
262          goto error;
263       }
264 
265       *phSession = (CK_SESSION_HANDLE)pSecondarySession;
266       pSecondarySession->hSecondaryCryptoSession = sOperation.params[0].value.a;
267 
268       return CKR_OK;
269    }
270 
271 error:
272    nErrorCode = (nErrorOrigin == TEEC_ORIGIN_TRUSTED_APP ?
273                   nTeeError :
274                   ckInternalTeeErrorToCKError(nTeeError));
275 
276    if ((flags & CKVF_OPEN_SUB_SESSION) == 0)
277    {
278       libMutexDestroy(&pSession->sSecondarySessionTableMutex);
279       free(pSession);
280    }
281    else
282    {
283       libMutexLock(&pSession->sSecondarySessionTableMutex);
284       libObjectHandle16Remove(&pSession->sSecondarySessionTable,&pSecondarySession->sSecondarySessionNode);
285       libMutexUnlock(&pSession->sSecondarySessionTableMutex);
286       free(pSecondarySession);
287    }
288 
289    return nErrorCode;
290 }
291 
C_CloseSession(CK_SESSION_HANDLE hSession)292 CK_RV PKCS11_EXPORT C_CloseSession(CK_SESSION_HANDLE hSession) /* the session's handle */
293 {
294    CK_RV                   nErrorCode = CKR_OK;
295    uint32_t                nErrorOrigin = TEEC_ORIGIN_API;
296    TEEC_Result             nTeeError;
297    TEEC_Operation          sOperation;
298    bool                    bIsPrimarySession;
299 
300    /* Check Cryptoki is initialized */
301    if (!g_bCryptokiInitialized)
302    {
303       return CKR_CRYPTOKI_NOT_INITIALIZED;
304    }
305 
306    if (!ckInternalSessionIsOpenedEx(hSession, &bIsPrimarySession))
307    {
308       return CKR_SESSION_HANDLE_INVALID;
309    }
310 
311    if (bIsPrimarySession)
312    {
313       LIB_OBJECT_NODE_HANDLE16*           pObject;
314       PPKCS11_SECONDARY_SESSION_CONTEXT   pSecSession;
315       PPKCS11_PRIMARY_SESSION_CONTEXT     pSession = (PPKCS11_PRIMARY_SESSION_CONTEXT)hSession;
316 
317       hSession = pSession->hCryptoSession;
318 
319       memset(&sOperation, 0, sizeof(TEEC_Operation));
320       sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_NONE, TEEC_NONE, TEEC_NONE, TEEC_NONE);
321       nTeeError = TEEC_InvokeCommand(&pSession->sSession,
322                                   (pSession->hCryptoSession << 16 ) |
323                                     (SERVICE_SYSTEM_PKCS11_C_CLOSE_SESSION_COMMAND_ID & 0x00007FFF),
324                                   &sOperation,                 /* IN OUT operation */
325                                   &nErrorOrigin                /* OUT returnOrigin, optional */
326                                  );
327       if (nTeeError != TEEC_SUCCESS)
328       {
329          goto end;
330       }
331 
332       TEEC_CloseSession(&pSession->sSession);
333       memset(&pSession->sSession, 0, sizeof(TEEC_Session));
334 
335       /* Free all secondary session contexts */
336       libMutexLock(&pSession->sSecondarySessionTableMutex);
337       pObject = libObjectHandle16RemoveOne(&pSession->sSecondarySessionTable);
338       while (pObject != NULL)
339       {
340          /* find all secondary session contexts,
341             and release associated resources */
342 
343          pSecSession = LIB_OBJECT_CONTAINER_OF(pObject, //ptr
344                                                PKCS11_SECONDARY_SESSION_CONTEXT,//type
345                                                sSecondarySessionNode);//member
346 
347          /* free secondary session context */
348          free(pSecSession);
349 
350          pObject = libObjectHandle16RemoveOne(&pSession->sSecondarySessionTable);
351       }
352       libMutexUnlock(&pSession->sSecondarySessionTableMutex);
353 
354       libMutexDestroy(&pSession->sSecondarySessionTableMutex);
355 
356       /* free primary session context */
357       free(pSession);
358    }
359    else
360    {
361       PPKCS11_SECONDARY_SESSION_CONTEXT pSecSession = (PPKCS11_SECONDARY_SESSION_CONTEXT)hSession;
362       PPKCS11_PRIMARY_SESSION_CONTEXT   pSession;
363 
364       uint32_t nCommandID = ( (pSecSession->hSecondaryCryptoSession & 0xFFFF) << 16 ) |
365                               (1 << 15) |
366                               (SERVICE_SYSTEM_PKCS11_C_CLOSE_SESSION_COMMAND_ID & 0x00007FFF);
367 
368       /* every pre-check are fine, then, update the local handles */
369       hSession = pSecSession->pPrimarySession->hCryptoSession;
370       pSession = (PPKCS11_PRIMARY_SESSION_CONTEXT)(pSecSession->pPrimarySession);
371 
372       memset(&sOperation, 0, sizeof(TEEC_Operation));
373       sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_NONE, TEEC_NONE, TEEC_NONE, TEEC_NONE);
374       nTeeError = TEEC_InvokeCommand(&pSession->sSession,
375                                   nCommandID,
376                                   &sOperation,                 /* IN OUT operation */
377                                   &nErrorOrigin                /* OUT returnOrigin, optional */
378                                  );
379       if (nTeeError != TEEC_SUCCESS)
380       {
381          goto end;
382       }
383 
384       /* remove the object from the table */
385       libMutexLock(&pSession->sSecondarySessionTableMutex);
386       libObjectHandle16Remove(&pSecSession->pPrimarySession->sSecondarySessionTable, &pSecSession->sSecondarySessionNode);
387       libMutexUnlock(&pSession->sSecondarySessionTableMutex);
388 
389       /* free secondary session context */
390       free(pSecSession);
391    }
392 
393 end:
394    nErrorCode = (nErrorOrigin == TEEC_ORIGIN_TRUSTED_APP ?
395                   nTeeError :
396                   ckInternalTeeErrorToCKError(nTeeError));
397    return nErrorCode;
398 }
399 
400 
C_Login(CK_SESSION_HANDLE hSession,CK_USER_TYPE userType,const CK_UTF8CHAR * pPin,CK_ULONG ulPinLen)401 CK_RV PKCS11_EXPORT C_Login(CK_SESSION_HANDLE hSession,  /* the session's handle */
402                               CK_USER_TYPE      userType,  /* the user type */
403                               const CK_UTF8CHAR*   pPin,      /* the user's PIN */
404                               CK_ULONG          ulPinLen)  /* the length of the PIN */
405 {
406    /* Prevent the compiler from complaining about unused variables */
407    do{(void)hSession;}while(0);
408    do{(void)userType;}while(0);
409    do{(void)pPin;}while(0);
410    do{(void)ulPinLen;}while(0);
411 
412    return CKR_OK;
413 }
414 
C_Logout(CK_SESSION_HANDLE hSession)415 CK_RV PKCS11_EXPORT C_Logout(CK_SESSION_HANDLE hSession) /* the session's handle */
416 {
417    do{(void)hSession;}while(0);
418 
419    return CKR_OK;
420 }
421