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#include <assert.h>
32#include <stdlib.h>
33#include <string.h>
34
35#define MTC_EXPORTS
36#include "mtc.h"
37
38/* Included for the TEE management */
39#include "pkcs11_internal.h"
40
41
42/*------------------------------------------------------------------------------
43   Defines
44------------------------------------------------------------------------------*/
45
46/**
47 * The magic word.
48 */
49#define MTC_SESSION_MAGIC  ( (uint32_t)0x4D544300 )   /* "MTC\0" */
50
51/**
52 * The MTC session context
53 */
54typedef struct
55{
56   /* Magic word, must be set to {MTC_SESSION_MAGIC}. */
57   uint32_t    nMagicWord;
58
59   /* MTC Identifier */
60   uint32_t nCounterIdentifier;
61
62   /* TEEC session and cryptoki session */
63   TEEC_Session sSession;
64   uint32_t     hCryptoSession;
65
66} MTC_SESSION_CONTEXT;
67
68
69static bool g_bMTCInitialized = false;
70
71
72/*------------------------------------------------------------------------------
73   Static functions
74------------------------------------------------------------------------------*/
75
76static S_RESULT static_getMonotonicCounter(S_HANDLE hCounter,
77                                           S_MONOTONIC_COUNTER_VALUE* psValue,
78                                           bool bIncrement)
79{
80   TEEC_Result          nError;
81   TEEC_Operation       sOperation;
82   MTC_SESSION_CONTEXT* pSession = NULL;
83   uint32_t             nCommandID;
84
85   if (!g_bMTCInitialized)
86   {
87      return S_ERROR_BAD_STATE;
88   }
89
90   pSession = (MTC_SESSION_CONTEXT *)hCounter;
91   if ((pSession == NULL) || (pSession->nMagicWord != MTC_SESSION_MAGIC))
92   {
93      return S_ERROR_BAD_PARAMETERS;
94   }
95
96   if (bIncrement)
97   {
98      nCommandID = SERVICE_SYSTEM_PKCS11_INCREMENT_MTC_COMMAND_ID;
99   }
100   else
101   {
102      nCommandID = SERVICE_SYSTEM_PKCS11_GET_MTC_COMMAND_ID;
103   }
104
105   sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_NONE, TEEC_NONE, TEEC_NONE);
106   sOperation.params[0].value.a = pSession->nCounterIdentifier;
107   sOperation.params[0].value.b = 0;
108   nError = TEEC_InvokeCommand(&pSession->sSession,
109                            (pSession->hCryptoSession << 16 ) |
110                              (nCommandID & 0x00007FFF),
111                            &sOperation,
112                            NULL);
113
114   psValue->nLow  = sOperation.params[0].value.a;
115   psValue->nHigh = sOperation.params[0].value.b;
116
117   return nError;
118}
119
120/*------------------------------------------------------------------------------
121   API
122------------------------------------------------------------------------------*/
123
124MTC_EXPORT S_RESULT SMonotonicCounterInit(void)
125{
126   TEEC_Result nTeeError;
127
128   stubMutexLock();
129   if (g_bMTCInitialized)
130   {
131      nTeeError = TEEC_SUCCESS;
132   }
133   else
134   {
135      nTeeError = stubInitializeContext();
136      if (nTeeError == TEEC_SUCCESS)
137      {
138         g_bMTCInitialized = true;
139      }
140   }
141   stubMutexUnlock();
142
143   return nTeeError;
144}
145
146MTC_EXPORT void SMonotonicCounterTerminate(void)
147{
148   stubMutexLock();
149   if (g_bMTCInitialized)
150   {
151      stubFinalizeContext();
152      g_bMTCInitialized = false;
153   }
154   stubMutexUnlock();
155}
156
157MTC_EXPORT S_RESULT SMonotonicCounterOpen(
158                 uint32_t nCounterIdentifier,
159                 OUT S_HANDLE* phCounter)
160{
161   TEEC_Result                nError;
162   TEEC_Operation             sOperation;
163   MTC_SESSION_CONTEXT*       pSession = NULL;
164   S_MONOTONIC_COUNTER_VALUE  nCounterValue;
165
166   if (phCounter == NULL)
167   {
168      return S_ERROR_BAD_PARAMETERS;
169   }
170
171   *phCounter = S_HANDLE_NULL;
172
173   if (!g_bMTCInitialized)
174   {
175      return S_ERROR_BAD_STATE;
176   }
177
178   if (nCounterIdentifier != S_MONOTONIC_COUNTER_GLOBAL)
179   {
180      return S_ERROR_ITEM_NOT_FOUND;
181   }
182
183   pSession = (MTC_SESSION_CONTEXT*)malloc(sizeof(MTC_SESSION_CONTEXT));
184   if (pSession == NULL)
185   {
186      return S_ERROR_OUT_OF_MEMORY;
187   }
188   memset(pSession, 0, sizeof(MTC_SESSION_CONTEXT));
189   pSession->nMagicWord = MTC_SESSION_MAGIC;
190
191   /* Open a TEE session with the system service */
192   nError = TEEC_OpenSession(&g_sContext,
193                             &pSession->sSession,
194                             &SERVICE_UUID,
195                             TEEC_LOGIN_PUBLIC,
196                             NULL,
197                             NULL, /* No operation parameters */
198                             NULL);
199   if (nError != TEEC_SUCCESS)
200   {
201      goto error;
202   }
203
204   /* Open a cryptoki session */
205   sOperation.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INOUT, TEEC_NONE, TEEC_NONE, TEEC_NONE);
206   sOperation.params[0].value.a = CKV_TOKEN_SYSTEM_SHARED;
207   sOperation.params[0].value.b = CKF_RW_SESSION | CKF_SERIAL_SESSION;
208   nError = TEEC_InvokeCommand(&pSession->sSession,
209                               SERVICE_SYSTEM_PKCS11_C_OPEN_SESSION_COMMAND_ID & 0x00007FFF,
210                               &sOperation,
211                               NULL);
212   if (nError != TEEC_SUCCESS)
213   {
214      TEEC_CloseSession(&pSession->sSession);
215      goto error;
216   }
217
218   pSession->hCryptoSession = sOperation.params[0].value.a;
219   pSession->nCounterIdentifier = nCounterIdentifier;
220
221   nError = SMonotonicCounterGet((S_HANDLE)pSession, &nCounterValue);
222   if (nError != TEEC_SUCCESS)
223   {
224      SMonotonicCounterClose((S_HANDLE)pSession);
225      return nError;
226   }
227
228   *phCounter = (S_HANDLE)pSession;
229
230   return TEEC_SUCCESS;
231
232error:
233   free(pSession);
234   return nError;
235}
236
237MTC_EXPORT void SMonotonicCounterClose(S_HANDLE hCounter)
238{
239   MTC_SESSION_CONTEXT* pSession;
240
241   if (!g_bMTCInitialized)
242   {
243      return;
244   }
245
246   pSession = (MTC_SESSION_CONTEXT *)hCounter;
247   if ((pSession == NULL) || (pSession->nMagicWord != MTC_SESSION_MAGIC))
248   {
249      return;
250   }
251
252   (void)TEEC_InvokeCommand(&pSession->sSession,
253                            (pSession->hCryptoSession << 16 ) |
254                              (SERVICE_SYSTEM_PKCS11_C_CLOSE_SESSION_COMMAND_ID & 0x00007FFF),
255                            NULL, /* No operation parameters */
256                            NULL);
257
258   TEEC_CloseSession(&pSession->sSession);
259   free(pSession);
260}
261
262MTC_EXPORT S_RESULT SMonotonicCounterGet(
263                 S_HANDLE hCounter,
264                 S_MONOTONIC_COUNTER_VALUE* psCurrentValue)
265{
266   return static_getMonotonicCounter(hCounter, psCurrentValue, false);
267}
268
269MTC_EXPORT S_RESULT SMonotonicCounterIncrement(
270                 S_HANDLE hCounter,
271                 S_MONOTONIC_COUNTER_VALUE* psNewValue)
272{
273   return static_getMonotonicCounter(hCounter, psNewValue, true);
274}
275