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