• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Microsoft Reference Implementation for TPM 2.0
2  *
3  *  The copyright in this software is being made available under the BSD License,
4  *  included below. This software may be subject to other third party and
5  *  contributor rights, including patent rights, and no such rights are granted
6  *  under this license.
7  *
8  *  Copyright (c) Microsoft Corporation
9  *
10  *  All rights reserved.
11  *
12  *  BSD License
13  *
14  *  Redistribution and use in source and binary forms, with or without modification,
15  *  are permitted provided that the following conditions are met:
16  *
17  *  Redistributions of source code must retain the above copyright notice, this list
18  *  of conditions and the following disclaimer.
19  *
20  *  Redistributions in binary form must reproduce the above copyright notice, this
21  *  list of conditions and the following disclaimer in the documentation and/or
22  *  other materials provided with the distribution.
23  *
24  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS""
25  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27  *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
28  *  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29  *  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
31  *  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 //**Introduction
37 // This file contains the emulated Physical Presence Interface.
38 
39 #include "assert.h"
40 #include "Admin.h"
41 #include "string.h"
42 
43 #include <tee_internal_api.h>
44 #include <tee_internal_api_extensions.h>
45 
46 #define TPM_CC_EmulatePPI     0x200001FF
47 
48 //
49 // Hand marshaling, unmarshaling, and maximally sized structures for EmulatePPI
50 //
51 #pragma pack (push, 1)
52 typedef struct {
53     TPM_ST tag;
54     UINT32 paramSize;
55     TPM_CC commandCode;
56 } TPM2_COMMAND_HEADER;
57 
58 typedef struct {
59     TPM_ST tag;
60     UINT32 paramSize;
61     TPM_RC responseCode;
62 } TPM2_RESPONSE_HEADER;
63 
64 typedef struct{
65     UINT32 FunctionIndex;
66     UINT32 Op;
67 } EmulatePPI_In;
68 
69 typedef struct{
70     UINT32 Result1;
71     UINT32 Result2;
72     UINT32 Result3;
73 } EmulatePPI_Out;
74 
75 typedef struct{
76     TPM2_COMMAND_HEADER header;
77     EmulatePPI_In inputParameters;
78 } TPM2_EmulatePPI_cmd_t;
79 
80 typedef struct{
81     TPM2_RESPONSE_HEADER header;
82     EmulatePPI_Out outputParameters;
83 } TPM2_EmulatePPI_res_t;
84 #pragma pack (pop)
85 
86 FTPM_PPI_STATE s_PPIState;
87 
88 extern int _plat__NvCommit(void);
89 
90 static void
ExecutePPICommand(_In_ UINT32 FunctionIndex,_In_ UINT32 Op,_Out_ UINT32 * Result1,_Out_ UINT32 * Result2,_Out_ UINT32 * Result3)91 ExecutePPICommand(
92     _In_  UINT32 FunctionIndex,
93     _In_  UINT32 Op,
94     _Out_ UINT32 *Result1,
95     _Out_ UINT32 *Result2,
96     _Out_ UINT32 *Result3
97     )
98 {
99     UINT32 retVal1 = 0;
100     UINT32 retVal2 = 0;
101     UINT32 retVal3 = 0;
102 
103     _admin__RestorePPIState();
104 
105     memset(Result1, 0, sizeof(UINT32));
106     memset(Result2, 0, sizeof(UINT32));
107     memset(Result3, 0, sizeof(UINT32));
108 
109     switch (FunctionIndex) {
110     case FTPM_PPI_CMD_QUERY:
111         retVal1 = 0x1AB;             // Per PPI 1.2 specification
112         break;
113 
114     case FTPM_PPI_CMD_VERSION:
115         retVal1 = FTPM_PPI_VERSION;  // String "1.2"
116         break;
117 
118     case FTPM_PPI_CMD_SUBMIT_OP_REQ:
119     case FTPM_PPI_CMD_GET_PLATFORM_ACTION:
120         retVal1 = 2;                 // Reboot/General Failure
121         break;
122 
123     case FTPM_PPI_CMD_GET_PENDING_OP:
124         retVal1 = 0;                 // Success
125         retVal2 = s_PPIState.PendingPseudoOp;
126         break;
127 
128     case FTPM_PPI_CMD_RETURN_OP_RESP:
129         retVal1 = 0;                 // Success
130         retVal2 = s_PPIState.PseudoOpFromLastBoot;
131         retVal3 = s_PPIState.ReturnResponse;
132         break;
133 
134     case FTPM_PPI_CMD_SUBMIT_USER_LANG:
135         retVal1 = 3;                 // Not Implemented
136         break;
137 
138     case FTPM_PPI_CMD_SUBMIT_OP_REQ2:
139         switch (Op) {
140         case FTPM_PPI_OP_NOP:
141         case FTPM_PPI_OP_ENABLE:
142         case FTPM_PPI_OP_DISABLE:
143         case FTPM_PPI_OP_ACTIVATE:
144         case FTPM_PPI_OP_DEACTIVATE:
145         case FTPM_PPI_OP_CLEAR:                  // Causes Clear
146         case FTPM_PPI_OP_E_A:
147         case FTPM_PPI_OP_D_D:
148         case FTPM_PPI_OP_OWNERINSTALL_TRUE:
149         case FTPM_PPI_OP_OWNERINSTALL_FALSE:
150         case FTPM_PPI_OP_E_A_OI_TRUE:
151         case FTPM_PPI_OP_OI_FALSE_D_D:
152         case FTPM_PPI_OP_FIELD_UPGRADE:
153         case FTPM_PPI_OP_OPERATOR_AUTH:
154         case FTPM_PPI_OP_C_E_A:                  // Causes Clear
155         case FTPM_PPI_OP_SET_NO_PROV_FALSE:
156         case FTPM_PPI_OP_SET_NO_PROV_TRUE:
157         case FTPM_PPI_OP_SET_NO_MAINT_FALSE:
158         case FTPM_PPI_OP_SET_NO_MAINT_TRUE:
159         case FTPM_PPI_OP_E_A_C:                  // Causes Clear
160         case FTPM_PPI_OP_E_A_C_E_A:              // Causes Clear
161             retVal1 = 0;                        // Success
162             s_PPIState.PendingPseudoOp = Op;
163             _admin__SavePPIState();
164             break;
165 
166         case FTPM_PPI_OP_SET_NO_CLEAR_FALSE:
167         case FTPM_PPI_OP_SET_NO_CLEAR_TRUE:
168         default:
169             retVal1 = 1;                       // Not Implemented
170             break;
171         }
172         break;
173 
174     case FTPM_PPI_CMD_GET_USER_CONF:
175         switch (Op) {
176         case FTPM_PPI_OP_NOP:
177         case FTPM_PPI_OP_ENABLE:
178         case FTPM_PPI_OP_DISABLE:
179         case FTPM_PPI_OP_ACTIVATE:
180         case FTPM_PPI_OP_DEACTIVATE:
181         case FTPM_PPI_OP_E_A:
182         case FTPM_PPI_OP_D_D:
183         case FTPM_PPI_OP_OWNERINSTALL_TRUE:
184         case FTPM_PPI_OP_OWNERINSTALL_FALSE:
185         case FTPM_PPI_OP_E_A_OI_TRUE:
186         case FTPM_PPI_OP_OI_FALSE_D_D:
187             retVal1 = 4;    // Allowed and PP user NOT required
188             break;
189 
190         case FTPM_PPI_OP_CLEAR:
191         case FTPM_PPI_OP_C_E_A:
192         case FTPM_PPI_OP_E_A_C:
193         case FTPM_PPI_OP_E_A_C_E_A:
194             retVal1 = 3;    // Allowed and PP user required
195             break;
196 
197         default:
198             retVal1 = 0;    // Not Implemented
199             break;
200         }
201         break;
202 
203     default:
204         break;
205     }
206 
207     memcpy(Result1, &retVal1, sizeof(UINT32));
208     memcpy(Result2, &retVal2, sizeof(UINT32));
209     memcpy(Result3, &retVal3, sizeof(UINT32));
210 }
211 
212 static TPM2_EmulatePPI_res_t PPIResponse;
213 
214 #pragma warning(push)
215 #pragma warning(disable:28196)
216 //
217 // The fTPM TA (OpTEE) may receive, from the TrEE driver, a PPI request
218 // thru it's ACPI inteface rather than via the TPM_Emulate_PPI command
219 // we're used to. This function creates a well formes TPM_Emulate_PPI
220 // command and forwards the request on to _admin__PPICommand to handle.
221 //
222 // Return:
223 //          0 - Omproperly formatted PPI command.
224 //  Otherwise - Return from _admin__PPICommand
225 //
226 int
_admin__PPIRequest(UINT32 CommandSize,__in_ecount (CommandSize)UINT8 * CommandBuffer,UINT32 * ResponseSize,__deref_out_ecount (* ResponseSize)UINT8 ** ResponseBuffer)227 _admin__PPIRequest(
228                                         UINT32  CommandSize,
229     __in_ecount(CommandSize)            UINT8   *CommandBuffer,
230                                         UINT32  *ResponseSize,
231     __deref_out_ecount(*ResponseSize)   UINT8   **ResponseBuffer
232     )
233 {
234     TPM2_EmulatePPI_cmd_t cmd;
235     TPM2_EmulatePPI_res_t rsp;
236     TPM2_EmulatePPI_res_t *rspPtr = &rsp;
237     UINT32 rspLen = sizeof(TPM2_EmulatePPI_res_t);
238     UINT8 *CmdBuffer;
239 
240     // Drop request if CommandSize is invalid
241     if (CommandSize < sizeof(UINT32)) {
242         return 0;
243     }
244 
245     CmdBuffer = CommandBuffer;
246 
247     cmd.header.tag = __builtin_bswap16(TPM_ST_NO_SESSIONS);
248     cmd.header.paramSize = __builtin_bswap32(sizeof(TPM2_EmulatePPI_cmd_t));
249     cmd.header.commandCode = __builtin_bswap32(TPM_CC_EmulatePPI);
250 
251     cmd.inputParameters.FunctionIndex = BYTE_ARRAY_TO_UINT32(CmdBuffer);
252     CmdBuffer += sizeof(UINT32);
253     CommandSize -= sizeof(UINT32);
254 
255     // Parameter checking is done in _admin__PPICommand but we still need
256     // to sanity check the size field so as not to overrun CommandBuffer.
257     if (CommandSize > 0) {
258 
259         if (CommandSize < sizeof(UINT32))
260             return 0;
261 
262         cmd.inputParameters.Op = BYTE_ARRAY_TO_UINT32(CmdBuffer);
263     }
264 
265     if (!_admin__PPICommand(sizeof(TPM2_EmulatePPI_cmd_t),
266                             (UINT8 *)&cmd,
267                             &rspLen,
268                             (UINT8**)&rspPtr)) {
269         return 0;
270     }
271 
272     memcpy(*ResponseBuffer, &(rsp.outputParameters.Result1), (rspLen - sizeof(TPM2_RESPONSE_HEADER)));
273     *ResponseSize = (rspLen - sizeof(TPM2_RESPONSE_HEADER));
274     return 1;
275 }
276 
277 //
278 // Return:
279 //  1 - Command has been consumed
280 //  0 - Not a properly formated PPI command, caller should pass through to TPM
281 //
282 int
_admin__PPICommand(UINT32 CommandSize,__in_ecount (CommandSize)UINT8 * CommandBuffer,UINT32 * ResponseSize,__deref_out_ecount (* ResponseSize)UINT8 ** ResponseBuffer)283 _admin__PPICommand(
284                                         UINT32  CommandSize,
285     __in_ecount(CommandSize)            UINT8   *CommandBuffer,
286                                         UINT32  *ResponseSize,
287     __deref_out_ecount(*ResponseSize)   UINT8   **ResponseBuffer
288 )
289 {
290     TPM2_EmulatePPI_cmd_t cmd;
291     UINT8 *CmdBuffer;
292     UINT32 FunctionIndex;
293     UINT32 Op;
294     UINT32 NumberResults = 0;
295     UINT16 Tag;
296 
297     memset(&PPIResponse, 0, sizeof(PPIResponse));
298     memset(&cmd, 0, sizeof(cmd));
299 
300     CmdBuffer = CommandBuffer;
301 
302     if (CommandSize < sizeof(TPM2_COMMAND_HEADER)) {
303         PPIResponse.header.responseCode = TPM_RC_COMMAND_SIZE;
304         goto Exit;
305     }
306 
307     cmd.header.tag = BYTE_ARRAY_TO_UINT16(CmdBuffer);
308     CmdBuffer += sizeof(UINT16);
309     CommandSize -= sizeof(UINT16);
310 
311     cmd.header.paramSize = BYTE_ARRAY_TO_UINT32(CmdBuffer);
312     CmdBuffer += sizeof(UINT32);
313     CommandSize -= sizeof(UINT32);
314 
315     cmd.header.commandCode = BYTE_ARRAY_TO_UINT32(CmdBuffer);
316     CmdBuffer += sizeof(UINT32);
317     CommandSize -= sizeof(UINT32);
318 
319     //
320     // First check that this must be the command we want to execute
321     //
322     if (cmd.header.commandCode != TPM_CC_EmulatePPI) {
323         return 0;
324     }
325 
326     //
327     // Must not be a session
328     //
329     if (cmd.header.tag != TPM_ST_NO_SESSIONS) {
330         PPIResponse.header.responseCode = TPM_RC_BAD_TAG;
331         goto Exit;
332     }
333 
334     //
335     // Must have enough command space left
336     //
337     if (cmd.header.paramSize < CommandSize) {
338         PPIResponse.header.responseCode = TPM_RC_COMMAND_SIZE;
339         goto Exit;
340     }
341 
342     if (CommandSize < sizeof(UINT32)) {
343         PPIResponse.header.responseCode = TPM_RC_COMMAND_SIZE;
344         goto Exit;
345     }
346 
347     FunctionIndex = BYTE_ARRAY_TO_UINT32(CmdBuffer);
348     CmdBuffer += sizeof(UINT32);
349     CommandSize -= sizeof(UINT32);
350 
351     switch (FunctionIndex) {
352     case FTPM_PPI_CMD_QUERY:
353     case FTPM_PPI_CMD_VERSION:
354     case FTPM_PPI_CMD_SUBMIT_OP_REQ:
355     case FTPM_PPI_CMD_GET_PLATFORM_ACTION:
356     case FTPM_PPI_CMD_SUBMIT_USER_LANG:
357         NumberResults = 1;
358         Op = 0;
359         break;
360 
361     case FTPM_PPI_CMD_GET_PENDING_OP:
362         NumberResults = 2;
363         Op = 0;
364         break;
365 
366     case FTPM_PPI_CMD_RETURN_OP_RESP:
367         NumberResults = 3;
368         Op = 0;
369         break;
370 
371     case FTPM_PPI_CMD_SUBMIT_OP_REQ2:
372     case FTPM_PPI_CMD_GET_USER_CONF:
373         NumberResults = 1;
374 
375         if (CommandSize < sizeof(UINT32)) {
376             PPIResponse.header.responseCode = TPM_RC_COMMAND_SIZE;
377             goto Exit;
378         }
379 
380         Op = BYTE_ARRAY_TO_UINT32(CmdBuffer);
381         CmdBuffer += sizeof(UINT32);
382         CommandSize -= sizeof(UINT32);
383         break;
384 
385     default:
386         NumberResults = 0;
387         PPIResponse.header.responseCode = TPM_RC_FAILURE;
388         goto Exit;
389     }
390 
391 
392     ExecutePPICommand(FunctionIndex,
393                       Op,
394 #pragma warning (push)
395 #pragma warning (disable:4366)  // The result of unary '&' may be unaligned
396                       &PPIResponse.outputParameters.Result1,
397                       &PPIResponse.outputParameters.Result2,
398                       &PPIResponse.outputParameters.Result3);
399 #pragma warning (pop)
400 
401     PPIResponse.header.responseCode = TPM_RC_SUCCESS;
402 
403 Exit:
404     if (PPIResponse.header.responseCode != TPM_RC_SUCCESS) {
405         NumberResults = 0;
406     }
407 
408     *ResponseSize = sizeof(TPM2_RESPONSE_HEADER) + (NumberResults * sizeof(UINT32));
409 
410     //
411     // Fill in tag, and size
412     //
413     Tag = TPM_ST_NO_SESSIONS;
414     PPIResponse.header.tag = BYTE_ARRAY_TO_UINT16((BYTE *)&Tag);
415     PPIResponse.header.paramSize = BYTE_ARRAY_TO_UINT32((BYTE *)ResponseSize);
416     PPIResponse.header.responseCode = BYTE_ARRAY_TO_UINT32((BYTE *)&PPIResponse.header.responseCode);
417 
418     //
419     // Results are in host byte order
420     //
421     memcpy(*ResponseBuffer, &PPIResponse, (sizeof(PPIResponse) < *ResponseSize) ? sizeof(PPIResponse) : *ResponseSize);
422 
423     return 1;
424 }
425 #pragma warning(pop)
426 
427