coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
tspi.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <console/console.h>
5 #include <security/tpm/tspi.h>
6 #include <security/tpm/tss.h>
7 #include <assert.h>
8 #include <security/vboot/misc.h>
9 #include <vb2_api.h>
10 #include <vb2_sha.h>
11 
12 #if CONFIG(TPM1)
13 static uint32_t tpm1_invoke_state_machine(void)
14 {
15  uint8_t disabled;
16  uint8_t deactivated;
18 
19  /* Check that the TPM is enabled and activated. */
20  result = tlcl_get_flags(&disabled, &deactivated, NULL);
21  if (result != TPM_SUCCESS) {
22  printk(BIOS_ERR, "TPM: Can't read capabilities.\n");
23  return result;
24  }
25 
26  if (disabled) {
27  printk(BIOS_INFO, "TPM: is disabled. Enabling...\n");
28 
30  if (result != TPM_SUCCESS) {
31  printk(BIOS_ERR, "TPM: Can't set enabled state.\n");
32  return result;
33  }
34  }
35 
36  if (!!deactivated != CONFIG(TPM_DEACTIVATE)) {
38  "TPM: Unexpected TPM deactivated state. Toggling...\n");
39  result = tlcl_set_deactivated(!deactivated);
40  if (result != TPM_SUCCESS) {
42  "TPM: Can't toggle deactivated state.\n");
43  return result;
44  }
45 
46  deactivated = !deactivated;
48  }
49 
50  return result;
51 }
52 #endif
53 
55 {
57 
58  result = tlcl_resume();
59  switch (result) {
60  case TPM_SUCCESS:
61  break;
62 
64  /*
65  * We're on a platform where the TPM maintains power
66  * in S3, so it's already initialized.
67  */
68  printk(BIOS_INFO, "TPM: Already initialized.\n");
70  break;
71 
72  default:
73  printk(BIOS_ERR, "TPM: Resume failed (%#x).\n", result);
74  break;
75  }
76 
77  return result;
78 }
79 
81 {
82  if (result != TPM_SUCCESS)
84  else
85  printk(BIOS_INFO, "TPM: setup succeeded\n");
86 
87  return result;
88 }
89 
90 static int tpm_is_setup;
91 static inline int tspi_tpm_is_setup(void)
92 {
93  /*
94  * vboot_logic_executed() only starts returning true at the end of
95  * verstage, but the vboot logic itself already wants to extend PCRs
96  * before that. So in the stage where verification actually runs, we
97  * need to check tpm_is_setup. Skip that check in all other stages so
98  * this whole function can be evaluated at compile time.
99  */
100  if (CONFIG(VBOOT)) {
102  return tpm_is_setup;
103  return vboot_logic_executed();
104  }
105 
106  if (CONFIG(TPM_MEASURED_BOOT_INIT_BOOTBLOCK))
107  return ENV_BOOTBLOCK ? tpm_is_setup : 1;
108 
109  if (ENV_RAMSTAGE)
110  return tpm_is_setup;
111 
112  return 0;
113 }
114 
115 /*
116  * tpm_setup starts the TPM and establishes the root of trust for the
117  * anti-rollback mechanism. tpm_setup can fail for three reasons. 1 A bug.
118  * 2 a TPM hardware failure. 3 An unexpected TPM state due to some attack. In
119  * general we cannot easily distinguish the kind of failure, so our strategy is
120  * to reboot in recovery mode in all cases. The recovery mode calls tpm_setup
121  * again, which executes (almost) the same sequence of operations. There is a
122  * good chance that, if recovery mode was entered because of a TPM failure, the
123  * failure will repeat itself. (In general this is impossible to guarantee
124  * because we have no way of creating the exact TPM initial state at the
125  * previous boot.) In recovery mode, we ignore the failure and continue, thus
126  * giving the recovery kernel a chance to fix things (that's why we don't set
127  * bGlobalLock). The choice is between a knowingly insecure device and a
128  * bricked device.
129  *
130  * As a side note, observe that we go through considerable hoops to avoid using
131  * the STCLEAR permissions for the index spaces. We do this to avoid writing
132  * to the TPM flashram at every reboot or wake-up, because of concerns about
133  * the durability of the NVRAM.
134  */
135 uint32_t tpm_setup(int s3flag)
136 {
138 
139  result = tlcl_lib_init();
140  if (result != TPM_SUCCESS) {
141  printk(BIOS_ERR, "TPM: Can't initialize.\n");
142  return tpm_setup_epilogue(result);
143  }
144 
145  /* Handle special init for S3 resume path */
146  if (s3flag) {
147  printk(BIOS_INFO, "TPM: Handle S3 resume.\n");
149  }
150 
151  result = tlcl_startup();
152  if (CONFIG(TPM_STARTUP_IGNORE_POSTINIT)
154  printk(BIOS_DEBUG, "TPM: ignoring invalid POSTINIT\n");
156  }
157  if (result != TPM_SUCCESS) {
158  printk(BIOS_ERR, "TPM: Can't run startup command.\n");
159  return tpm_setup_epilogue(result);
160  }
161 
163  if (result != TPM_SUCCESS) {
164  /*
165  * It is possible that the TPM was delivered with the physical
166  * presence command disabled. This tries enabling it, then
167  * tries asserting PP again.
168  */
170  if (result != TPM_SUCCESS) {
171  printk(BIOS_ERR, "TPM: Can't enable physical presence command.\n");
172  return tpm_setup_epilogue(result);
173  }
174 
176  if (result != TPM_SUCCESS) {
177  printk(BIOS_ERR, "TPM: Can't assert physical presence.\n");
178  return tpm_setup_epilogue(result);
179  }
180  }
181 
182 #if CONFIG(TPM1)
183  result = tpm1_invoke_state_machine();
184 #endif
185  if (CONFIG(TPM_MEASURED_BOOT))
187 
188  tpm_is_setup = 1;
189  return tpm_setup_epilogue(result);
190 }
191 
193 {
195 
196  printk(BIOS_INFO, "TPM: Clear and re-enable\n");
198  if (result != TPM_SUCCESS) {
199  printk(BIOS_ERR, "TPM: Can't initiate a force clear.\n");
200  return result;
201  }
202 
203 #if CONFIG(TPM1)
205  if (result != TPM_SUCCESS) {
206  printk(BIOS_ERR, "TPM: Can't set enabled state.\n");
207  return result;
208  }
209 
211  if (result != TPM_SUCCESS) {
212  printk(BIOS_ERR, "TPM: Can't set deactivated state.\n");
213  return result;
214  }
215 #endif
216 
217  return TPM_SUCCESS;
218 }
219 
220 uint32_t tpm_extend_pcr(int pcr, enum vb2_hash_algorithm digest_algo,
221  const uint8_t *digest, size_t digest_len, const char *name)
222 {
224 
225  if (!digest)
226  return TPM_E_IOERROR;
227 
228  if (tspi_tpm_is_setup()) {
229  result = tlcl_lib_init();
230  if (result != TPM_SUCCESS) {
231  printk(BIOS_ERR, "TPM: Can't initialize library.\n");
232  return result;
233  }
234 
235  printk(BIOS_DEBUG, "TPM: Extending digest for `%s` into PCR %d\n", name, pcr);
236  result = tlcl_extend(pcr, digest, NULL);
237  if (result != TPM_SUCCESS) {
238  printk(BIOS_ERR, "TPM: Extending hash for `%s` into PCR %d failed.\n",
239  name, pcr);
240  return result;
241  }
242  }
243 
244  if (CONFIG(TPM_MEASURED_BOOT))
245  tcpa_log_add_table_entry(name, pcr, digest_algo,
246  digest, digest_len);
247 
248  printk(BIOS_DEBUG, "TPM: Digest of `%s` to PCR %d %s\n",
249  name, pcr, tspi_tpm_is_setup() ? "measured" : "logged");
250 
251  return TPM_SUCCESS;
252 }
253 
254 #if CONFIG(VBOOT_LIB)
256  const char *rname)
257 {
258  uint8_t digest[TPM_PCR_MAX_LEN], digest_len;
261  size_t len;
262  struct vb2_digest_context ctx;
263 
264  if (!rdev || !rname)
265  return TPM_E_INVALID_ARG;
266 
267  digest_len = vb2_digest_size(TPM_MEASURE_ALGO);
268  assert(digest_len <= sizeof(digest));
269  if (vb2_digest_init(&ctx, TPM_MEASURE_ALGO)) {
270  printk(BIOS_ERR, "TPM: Error initializing hash.\n");
271  return TPM_E_HASH_ERROR;
272  }
273  /*
274  * Though one can mmap the full needed region on x86 this is not the
275  * case for e.g. ARM. In order to make this code as universal as
276  * possible across different platforms read the data to hash in chunks.
277  */
278  for (offset = 0; offset < region_device_sz(rdev); offset += len) {
279  len = MIN(sizeof(buf), region_device_sz(rdev) - offset);
280  if (rdev_readat(rdev, buf, offset, len) < 0) {
281  printk(BIOS_ERR, "TPM: Not able to read region %s.\n",
282  rname);
283  return TPM_E_READ_FAILURE;
284  }
285  if (vb2_digest_extend(&ctx, buf, len)) {
286  printk(BIOS_ERR, "TPM: Error extending hash.\n");
287  return TPM_E_HASH_ERROR;
288  }
289  }
290  if (vb2_digest_finalize(&ctx, digest, digest_len)) {
291  printk(BIOS_ERR, "TPM: Error finalizing hash.\n");
292  return TPM_E_HASH_ERROR;
293  }
294  return tpm_extend_pcr(pcr, TPM_MEASURE_ALGO, digest, digest_len, rname);
295 }
296 #endif /* VBOOT_LIB */
const char * name
Definition: mmu.c:92
#define assert(statement)
Definition: assert.h:74
#define MIN(a, b)
Definition: helpers.h:37
#define printk(level,...)
Definition: stdlib.h:16
int tspi_measure_cache_to_pcr(void)
Measure digests cached in TCPA log entries into PCRs.
Definition: crtm.c:140
#define TPM_MEASURE_ALGO
Definition: crtm.h:19
@ CONFIG
Definition: dsi_common.h:201
static struct region_device rdev
Definition: flashconsole.c:14
static size_t offset
Definition: flashconsole.c:16
void tcpa_log_add_table_entry(const char *name, const uint32_t pcr, enum vb2_hash_algorithm digest_algo, const uint8_t *digest, const size_t digest_len)
Add table entry for cbmem TCPA log.
Definition: log.c:79
#define BIOS_INFO
BIOS_INFO - Expected events.
Definition: loglevel.h:113
#define BIOS_DEBUG
BIOS_DEBUG - Verbose output.
Definition: loglevel.h:128
#define BIOS_ERR
BIOS_ERR - System in incomplete state.
Definition: loglevel.h:72
static uint8_t * buf
Definition: uart.c:7
static int verification_should_run(void)
Definition: misc.h:46
static int vboot_logic_executed(void)
Definition: misc.h:66
result
Definition: mrc_cache.c:35
#define post_code(value)
Definition: post_code.h:12
#define POST_TPM_FAILURE
TPM failure.
Definition: post_codes.h:367
static size_t region_device_sz(const struct region_device *rdev)
Definition: region.h:132
ssize_t rdev_readat(const struct region_device *rd, void *b, size_t offset, size_t size)
Definition: region.c:77
#define ENV_BOOTBLOCK
Definition: rules.h:148
#define ENV_RAMSTAGE
Definition: rules.h:150
#define NULL
Definition: stddef.h:19
unsigned int uint32_t
Definition: stdint.h:14
unsigned char uint8_t
Definition: stdint.h:8
uint32_t tlcl_set_deactivated(uint8_t flag)
Definition: tss.c:285
uint32_t tlcl_assert_physical_presence(void)
Assert physical presence in software.
Definition: tss.c:249
uint32_t tlcl_set_enable(void)
Definition: tss.c:279
uint32_t tlcl_force_clear(void)
Issue a ForceClear.
Definition: tss.c:273
uint32_t tlcl_get_flags(uint8_t *disable, uint8_t *deactivated, uint8_t *nvlocked)
Definition: tss.c:310
uint32_t tlcl_lib_init(void)
Call this first.
Definition: tss.c:145
uint32_t tlcl_startup(void)
Send a TPM_Startup(ST_CLEAR).
Definition: tss.c:160
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_resume(void)
Resume by sending a TPM_Startup(ST_STATE).
Definition: tss.c:166
#define TPM_DEACTIVATE
Definition: tpm_ppi.h:66
uint32_t tpm_extend_pcr(int pcr, enum vb2_hash_algorithm digest_algo, const uint8_t *digest, size_t digest_len, const char *name)
Ask vboot for a digest and extend a TPM PCR with it.
Definition: tspi.c:220
static uint32_t tpm_setup_epilogue(uint32_t result)
Definition: tspi.c:80
static int tspi_tpm_is_setup(void)
Definition: tspi.c:91
static uint32_t tpm_setup_s3_helper(void)
Definition: tspi.c:54
static int tpm_is_setup
Definition: tspi.c:90
uint32_t tpm_setup(int s3flag)
Start the TPM and establish the root of trust.
Definition: tspi.c:135
uint32_t tpm_clear_and_reenable(void)
Issue a TPM_Clear and re-enable/reactivate the TPM.
Definition: tspi.c:192
#define TPM_PCR_MAX_LEN
Definition: tspi.h:11
uint32_t tpm_measure_region(const struct region_device *rdev, uint8_t pcr, const char *rname)
Measure a given region device and extend given PCR with the result.
#define HASH_DATA_CHUNK_SIZE
Definition: tspi.h:12
#define TPM_SUCCESS
Definition: tss_common.h:9
#define TPM_E_IOERROR
Definition: tss_errors.h:21
#define TPM_E_HASH_ERROR
Definition: tss_errors.h:42
#define TPM_E_READ_FAILURE
Definition: tss_errors.h:39
#define TPM_E_MUST_REBOOT
Definition: tss_errors.h:31
#define TPM_E_INVALID_ARG
Definition: tss_errors.h:41
#define TPM_E_INVALID_POSTINIT
Definition: tss_errors.h:22