coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
tss.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: BSD-3-Clause */
2 
3 /*
4  * A lightweight TPM command library.
5  *
6  * The general idea is that TPM commands are array of bytes whose
7  * fields are mostly compile-time constant. The goal is to build much
8  * of the commands at compile time (or build time) and change some of
9  * the fields at run time as needed. The code in
10  * utility/tlcl_generator.c builds structures containing the commands,
11  * as well as the offsets of the fields that need to be set at run
12  * time.
13  */
14 
15 #include <assert.h>
16 #include <string.h>
17 #include <security/tpm/tis.h>
18 #include <vb2_api.h>
19 #include <security/tpm/tss.h>
20 
21 #include "tss_internal.h"
22 #include "tss_commands.h"
23 
24 #include <console/console.h>
25 #define VBDEBUG(format, args...) printk(BIOS_DEBUG, format, ## args)
26 
27 static int tpm_send_receive(const uint8_t *request,
28  uint32_t request_length,
29  uint8_t *response,
30  uint32_t *response_length)
31 {
32  size_t len = *response_length;
33  if (tis_sendrecv(request, request_length, response, &len))
34  return VB2_ERROR_UNKNOWN;
35  /* check 64->32bit overflow and (re)check response buffer overflow */
36  if (len > *response_length)
37  return VB2_ERROR_UNKNOWN;
38  *response_length = len;
39  return VB2_SUCCESS;
40 }
41 
42 /* Sets the size field of a TPM command. */
43 static inline void set_tpm_command_size(uint8_t *buffer, uint32_t size)
44 {
45  to_tpm_uint32(buffer + sizeof(uint16_t), size);
46 }
47 
48 /* Gets the size field of a TPM command. */
49 __attribute__((unused))
50 static inline int tpm_command_size(const uint8_t *buffer)
51 {
52  uint32_t size;
53  from_tpm_uint32(buffer + sizeof(uint16_t), &size);
54  return (int) size;
55 }
56 
57 /* Gets the code field of a TPM command. */
58 static inline int tpm_command_code(const uint8_t *buffer)
59 {
60  uint32_t code;
61  from_tpm_uint32(buffer + sizeof(uint16_t) + sizeof(uint32_t), &code);
62  return code;
63 }
64 
65 /* Gets the return code field of a TPM result. */
66 static inline int tpm_return_code(const uint8_t *buffer)
67 {
68  return tpm_command_code(buffer);
69 }
70 
71 /*
72  * Like TlclSendReceive below, but do not retry if NEEDS_SELFTEST or
73  * DOING_SELFTEST errors are returned.
74  */
76  uint8_t *response, int max_length)
77 {
78  uint32_t response_length = max_length;
80 
81  result = tpm_send_receive(request, tpm_command_size(request),
82  response, &response_length);
83  if (result != 0) {
84  /* Communication with TPM failed, so response is garbage */
85  VBDEBUG("TPM: command 0x%x send/receive failed: 0x%x\n",
86  tpm_command_code(request), result);
87  return result;
88  }
89  /* Otherwise, use the result code from the response */
90  result = tpm_return_code(response);
91 
92  /* TODO: add paranoia about returned response_length vs. max_length
93  * (and possibly expected length from the response header). See
94  * crosbug.com/17017 */
95 
96  VBDEBUG("TPM: command 0x%x returned 0x%x\n",
97  tpm_command_code(request), result);
98 
99 return result;
100 }
101 
102 /* Sends a TPM command and gets a response. Returns 0 if success or the TPM
103  * error code if error. Waits for the self test to complete if needed. */
104 uint32_t tlcl_send_receive(const uint8_t *request, uint8_t *response,
105  int max_length)
106 {
107  uint32_t result = tlcl_send_receive_no_retry(request, response,
108  max_length);
109  /* If the command fails because the self test has not completed, try it
110  * again after attempting to ensure that the self test has completed. */
113  if (result != TPM_SUCCESS)
114  return result;
115 #if defined(TPM_BLOCKING_CONTINUESELFTEST) || defined(VB_RECOVERY_MODE)
116  /* Retry only once */
117  result = tlcl_send_receive_no_retry(request, response,
118  max_length);
119 #else
120  /* This needs serious testing. The TPM specification says: "iii.
121  * The caller MUST wait for the actions of TPM_ContinueSelfTest
122  * to complete before reissuing the command C1." But, if
123  * ContinueSelfTest is non-blocking, how do we know that the
124  * actions have completed other than trying again? */
125  do {
126  result = tlcl_send_receive_no_retry(request, response,
127  max_length);
128  } while (result == TPM_E_DOING_SELFTEST);
129 #endif
130  }
131  return result;
132 }
133 
134 /* Sends a command and returns the error code. */
135 static uint32_t send(const uint8_t *command)
136 {
138  return tlcl_send_receive(command, response, sizeof(response));
139 }
140 
141 /* Exported functions. */
142 
144 
146 {
147  if (tlcl_init_done)
148  return VB2_SUCCESS;
149 
150  if (tis_init())
151  return VB2_ERROR_UNKNOWN;
152  if (tis_open())
153  return VB2_ERROR_UNKNOWN;
154 
155  tlcl_init_done = 1;
156 
157  return VB2_SUCCESS;
158 }
159 
161 {
162  VBDEBUG("TPM: Startup\n");
163  return send(tpm_startup_cmd.buffer);
164 }
165 
167 {
168  VBDEBUG("TPM: Resume\n");
169  return send(tpm_resume_cmd.buffer);
170 }
171 
173 {
174  VBDEBUG("TPM: Save state\n");
175  return send(tpm_savestate_cmd.buffer);
176 }
177 
179 {
180  VBDEBUG("TPM: Self test full\n");
182 }
183 
185 {
187  VBDEBUG("TPM: Continue self test\n");
188  /* Call the No Retry version of SendReceive to avoid recursion. */
190  response, sizeof(response));
191 }
192 
194 {
195  struct s_tpm_nv_definespace_cmd cmd;
196  VBDEBUG("TPM: TlclDefineSpace(0x%x, 0x%x, %d)\n", index, perm, size);
197  memcpy(&cmd, &tpm_nv_definespace_cmd, sizeof(cmd));
201  return send(cmd.buffer);
202 }
203 
205 {
206  struct s_tpm_nv_write_cmd cmd;
208  const int total_length =
210 
211  VBDEBUG("TPM: %s(0x%x, %d)\n", __func__, index, length);
212  memcpy(&cmd, &tpm_nv_write_cmd, sizeof(cmd));
213  assert(total_length <= TPM_LARGE_ENOUGH_COMMAND_SIZE);
214  set_tpm_command_size(cmd.buffer, total_length);
215 
218  if (length > 0)
220 
221  return tlcl_send_receive(cmd.buffer, response, sizeof(response));
222 }
223 
225 {
226  struct s_tpm_nv_read_cmd cmd;
228  uint32_t result_length;
230 
231  VBDEBUG("TPM: %s(0x%x, %d)\n", __func__, index, length);
232  memcpy(&cmd, &tpm_nv_read_cmd, sizeof(cmd));
235 
236  result = tlcl_send_receive(cmd.buffer, response, sizeof(response));
237  if (result == TPM_SUCCESS && length > 0) {
238  uint8_t *nv_read_cursor = response + kTpmResponseHeaderLength;
239  from_tpm_uint32(nv_read_cursor, &result_length);
240  if (result_length > length)
241  return TPM_E_IOERROR;
242  nv_read_cursor += sizeof(uint32_t);
243  memcpy(data, nv_read_cursor, result_length);
244  }
245 
246  return result;
247 }
248 
250 {
251  VBDEBUG("TPM: Asserting physical presence\n");
252  return send(tpm_ppassert_cmd.buffer);
253 }
254 
256 {
257  VBDEBUG("TPM: Enable the physical presence command\n");
258  return send(tpm_ppenable_cmd.buffer);
259 }
260 
262 {
263  VBDEBUG("TPM: Enable PP cmd, disable HW pp, and set lifetime lock\n");
265 }
266 
268 {
269  VBDEBUG("TPM: Set NV locked\n");
270  return tlcl_define_space(TPM_NV_INDEX_LOCK, 0, 0);
271 }
272 
274 {
275  VBDEBUG("TPM: Force clear\n");
277 }
278 
280 {
281  VBDEBUG("TPM: Enabling TPM\n");
283 }
284 
286 {
288  VBDEBUG("TPM: SetDeactivated(%d)\n", flag);
289  memcpy(&cmd, &tpm_physicalsetdeactivated_cmd, sizeof(cmd));
290  *(cmd.buffer + cmd.deactivated) = flag;
291  return send(cmd.buffer);
292 }
293 
295 {
297  uint32_t size;
299  sizeof(response));
300  if (result != TPM_SUCCESS)
301  return result;
302  from_tpm_uint32(response + kTpmResponseHeaderLength, &size);
303  if (size != sizeof(TPM_PERMANENT_FLAGS))
304  return TPM_E_IOERROR;
305  memcpy(pflags, response + kTpmResponseHeaderLength + sizeof(size),
306  sizeof(TPM_PERMANENT_FLAGS));
307  return result;
308 }
309 
311  uint8_t *nvlocked)
312 {
313  TPM_PERMANENT_FLAGS pflags;
315  if (result == TPM_SUCCESS) {
316  if (disable)
317  *disable = pflags.disable;
318  if (deactivated)
319  *deactivated = pflags.deactivated;
320  if (nvlocked)
321  *nvlocked = pflags.nvLocked;
322  VBDEBUG("TPM: flags disable=%d, deactivated=%d, nvlocked=%d\n",
323  pflags.disable, pflags.deactivated, pflags.nvLocked);
324  }
325  return result;
326 }
327 
329 {
330  VBDEBUG("TPM: Set global lock\n");
331  return tlcl_write(TPM_NV_INDEX0, NULL, 0);
332 }
333 
334 uint32_t tlcl_extend(int pcr_num, const uint8_t *in_digest,
335  uint8_t *out_digest)
336 {
337  struct s_tpm_extend_cmd cmd;
340 
341  memcpy(&cmd, &tpm_extend_cmd, sizeof(cmd));
342  to_tpm_uint32(cmd.buffer + tpm_extend_cmd.pcrNum, pcr_num);
343  memcpy(cmd.buffer + cmd.inDigest, in_digest, kPcrDigestLength);
344 
345  result = tlcl_send_receive(cmd.buffer, response, sizeof(response));
346  if (result != TPM_SUCCESS)
347  return result;
348 
349  if (out_digest)
350  memcpy(out_digest, response + kTpmResponseHeaderLength,
352  return result;
353 }
354 
356 {
357  struct s_tpm_getpermissions_cmd cmd;
359  uint8_t *nvdata;
361  uint32_t size;
362 
363  memcpy(&cmd, &tpm_getpermissions_cmd, sizeof(cmd));
365  result = tlcl_send_receive(cmd.buffer, response, sizeof(response));
366  if (result != TPM_SUCCESS)
367  return result;
368 
369  nvdata = response + kTpmResponseHeaderLength + sizeof(size);
370  from_tpm_uint32(nvdata + kNvDataPublicPermissionsOffset, permissions);
371  return result;
372 }
void * memcpy(void *dest, const void *src, size_t n)
Definition: memcpy.c:7
#define assert(statement)
Definition: assert.h:74
int tis_sendrecv(const uint8_t *sendbuf, size_t sbuf_size, uint8_t *recvbuf, size_t *rbuf_len)
Definition: tis.c:81
int tis_open(void)
Definition: tis.c:33
int tis_init(void)
Definition: tis.c:65
uint64_t length
Definition: fw_cfg_if.h:1
result
Definition: mrc_cache.c:35
u8 buffer[C2P_BUFFER_MAXSIZE]
Definition: psp_smm.c:18
#define NULL
Definition: stddef.h:19
unsigned short uint16_t
Definition: stdint.h:11
unsigned int uint32_t
Definition: stdint.h:14
unsigned char uint8_t
Definition: stdint.h:8
uint16_t inDigest
Definition: tss_commands.h:8
uint8_t buffer[34]
Definition: tss_commands.h:6
uint16_t pcrNum
Definition: tss_commands.h:7
uint8_t buffer[10]
Definition: tss_commands.h:67
uint8_t buffer[22]
Definition: tss_commands.h:41
uint8_t buffer[22]
Definition: tss_commands.h:136
uint8_t buffer[256]
Definition: tss_commands.h:143
uint8_t buffer[12]
Definition: tss_commands.h:124
uint8_t buffer[12]
Definition: tss_commands.h:118
uint8_t buffer[12]
Definition: tss_commands.h:89
uint8_t buffer[10]
Definition: tss_commands.h:95
uint8_t buffer[12]
Definition: tss_commands.h:100
uint32_t tlcl_send_receive(const uint8_t *request, uint8_t *response, int max_length)
Perform a raw TPM request/response transaction.
Definition: tss.c:104
uint32_t tlcl_set_deactivated(uint8_t flag)
Definition: tss.c:285
uint32_t tlcl_set_global_lock(void)
Set the bGlobalLock flag, which only a reboot can clear.
Definition: tss.c:328
uint32_t tlcl_save_state(void)
Save TPM state by sending either TPM_SaveState() (TPM1.2) or TPM_Shutdown(ST_STATE) (TPM2....
Definition: tss.c:172
uint32_t tlcl_assert_physical_presence(void)
Assert physical presence in software.
Definition: tss.c:249
static uint8_t tlcl_init_done
Definition: tss.c:143
uint32_t tlcl_set_enable(void)
Definition: tss.c:279
uint32_t tlcl_define_space(uint32_t index, uint32_t perm, uint32_t size)
Definition: tss.c:193
uint32_t tlcl_get_permissions(uint32_t index, uint32_t *permissions)
Get the permission bits for the NVRAM space with |index|.
Definition: tss.c:355
uint32_t tlcl_continue_self_test(void)
Run the self test in the background.
Definition: tss.c:184
static void set_tpm_command_size(uint8_t *buffer, uint32_t size)
Definition: tss.c:43
uint32_t tlcl_force_clear(void)
Issue a ForceClear.
Definition: tss.c:273
static uint32_t tlcl_send_receive_no_retry(const uint8_t *request, uint8_t *response, int max_length)
Definition: tss.c:75
uint32_t tlcl_get_flags(uint8_t *disable, uint8_t *deactivated, uint8_t *nvlocked)
Definition: tss.c:310
uint32_t tlcl_self_test_full(void)
Run the self test.
Definition: tss.c:178
uint32_t tlcl_finalize_physical_presence(void)
Finalize the physical presence settings: software PP is enabled, hardware PP is disabled,...
Definition: tss.c:261
static uint32_t send(const uint8_t *command)
Definition: tss.c:135
static int tpm_command_code(const uint8_t *buffer)
Definition: tss.c:58
#define VBDEBUG(format, args...)
Definition: tss.c:25
static int tpm_command_size(const uint8_t *buffer)
Definition: tss.c:50
uint32_t tlcl_lib_init(void)
Call this first.
Definition: tss.c:145
uint32_t tlcl_set_nv_locked(void)
Set the nvLocked bit.
Definition: tss.c:267
uint32_t tlcl_startup(void)
Send a TPM_Startup(ST_CLEAR).
Definition: tss.c:160
uint32_t tlcl_write(uint32_t index, const void *data, uint32_t length)
Write [length] bytes of [data] to space at [index].
Definition: tss.c:204
uint32_t tlcl_extend(int pcr_num, const uint8_t *in_digest, uint8_t *out_digest)
Perform a TPM_Extend.
Definition: tss.c:334
uint32_t tlcl_physical_presence_cmd_enable(void)
Enable the physical presence command.
Definition: tss.c:255
uint32_t tlcl_get_permanent_flags(TPM_PERMANENT_FLAGS *pflags)
Definition: tss.c:294
static int tpm_return_code(const uint8_t *buffer)
Definition: tss.c:66
uint32_t tlcl_read(uint32_t index, void *data, uint32_t length)
Read [length] bytes from space at [index] into [data].
Definition: tss.c:224
static int tpm_send_receive(const uint8_t *request, uint32_t request_length, uint8_t *response, uint32_t *response_length)
Definition: tss.c:27
uint32_t tlcl_resume(void)
Resume by sending a TPM_Startup(ST_STATE).
Definition: tss.c:166
#define TPM_NV_INDEX0
#define TPM_LARGE_ENOUGH_COMMAND_SIZE
#define TPM_NV_INDEX_LOCK
const struct s_tpm_extend_cmd tpm_extend_cmd
const struct s_tpm_ppassert_cmd tpm_ppassert_cmd
const struct s_tpm_nv_definespace_cmd tpm_nv_definespace_cmd
const struct s_tpm_nv_write_cmd tpm_nv_write_cmd
const struct s_tpm_selftestfull_cmd tpm_selftestfull_cmd
const int kWriteInfoLength
Definition: tss_commands.h:165
const struct s_tpm_finalizepp_cmd tpm_finalizepp_cmd
const struct s_tpm_getflags_cmd tpm_getflags_cmd
const struct s_tpm_getpermissions_cmd tpm_getpermissions_cmd
const int kNvDataPublicPermissionsOffset
Definition: tss_commands.h:166
const struct s_tpm_startup_cmd tpm_startup_cmd
const struct s_tpm_physicalsetdeactivated_cmd tpm_physicalsetdeactivated_cmd
const struct s_tpm_ppenable_cmd tpm_ppenable_cmd
const struct s_tpm_savestate_cmd tpm_savestate_cmd
const struct s_tpm_forceclear_cmd tpm_forceclear_cmd
const struct s_tpm_nv_read_cmd tpm_nv_read_cmd
const struct s_tpm_physicalenable_cmd tpm_physicalenable_cmd
const struct s_tpm_resume_cmd tpm_resume_cmd
const struct s_tpm_continueselftest_cmd tpm_continueselftest_cmd
#define TPM_SUCCESS
Definition: tss_common.h:9
#define TPM_E_IOERROR
Definition: tss_errors.h:21
#define TPM_E_NEEDS_SELFTEST
Definition: tss_errors.h:26
#define TPM_E_DOING_SELFTEST
Definition: tss_errors.h:27
#define kTpmResponseHeaderLength
Definition: tss_internal.h:13
static void to_tpm_uint32(uint8_t *buffer, uint32_t x)
Definition: tss_internal.h:24
#define kPcrDigestLength
Definition: tss_internal.h:16
#define kTpmRequestHeaderLength
Definition: tss_internal.h:12
static void from_tpm_uint32(const uint8_t *buffer, uint32_t *x)
Definition: tss_internal.h:36