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