blob: d9cade981d8c8482cb168c84ed52ef6ef5e9ea2c [file] [log] [blame]
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +01001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
5 * Copyright 2017 Facebook Inc.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#include <console/cbmem_console.h>
18#include <console/console.h>
19#include <reset.h>
20#include <security/tpm/tspi.h>
21#include <security/tpm/tss.h>
22#include <stdlib.h>
23#include <string.h>
24
25#if IS_ENABLED(CONFIG_TPM1)
26static uint32_t tpm1_invoke_state_machine(void)
27{
Philipp Deppenwiese4d2af9d2018-08-14 09:46:55 -070028 uint8_t disabled;
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +010029 uint8_t deactivated;
30 uint32_t result = TPM_SUCCESS;
31
32 /* Check that the TPM is enabled and activated. */
Philipp Deppenwiese4d2af9d2018-08-14 09:46:55 -070033 result = tlcl_get_flags(&disabled, &deactivated, NULL);
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +010034 if (result != TPM_SUCCESS) {
35 printk(BIOS_ERR, "TPM: Can't read capabilities.\n");
36 return result;
37 }
38
Philipp Deppenwiese4d2af9d2018-08-14 09:46:55 -070039 if (disabled) {
40 printk(BIOS_INFO, "TPM: is disabled. Enabling...\n");
41
42 result = tlcl_set_enable();
43 if (result != TPM_SUCCESS) {
44 printk(BIOS_ERR, "TPM: Can't set enabled state.\n");
45 return result;
46 }
47 }
48
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +010049 if (!!deactivated != IS_ENABLED(CONFIG_TPM_DEACTIVATE)) {
50 printk(BIOS_INFO,
51 "TPM: Unexpected TPM deactivated state. Toggling...\n");
52 result = tlcl_set_deactivated(!deactivated);
53 if (result != TPM_SUCCESS) {
54 printk(BIOS_ERR,
55 "TPM: Can't toggle deactivated state.\n");
56 return result;
57 }
58
59 deactivated = !deactivated;
60 result = TPM_E_MUST_REBOOT;
61 }
62
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +010063 return result;
64}
65#endif
66
Joel Kitching9937a062018-10-11 18:16:59 +080067static uint32_t tpm_setup_s3_helper(void)
68{
69 uint32_t result;
70
71 result = tlcl_resume();
72 switch (result) {
73 case TPM_SUCCESS:
74 break;
75
76 case TPM_E_INVALID_POSTINIT:
77 /*
78 * We're on a platform where the TPM maintains power
79 * in S3, so it's already initialized.
80 */
81 printk(BIOS_INFO, "TPM: Already initialized.\n");
82 result = TPM_SUCCESS;
83 break;
84
85 default:
86 printk(BIOS_ERR, "TPM: Resume failed (%#x).\n", result);
87 break;
88
89 }
90
91 return result;
92}
93
94static uint32_t tpm_setup_epilogue(uint32_t result)
95{
96 if (result != TPM_SUCCESS)
97 post_code(POST_TPM_FAILURE);
98 else
99 printk(BIOS_INFO, "TPM: setup succeeded\n");
100
101 return result;
102}
103
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100104/*
105 * tpm_setup starts the TPM and establishes the root of trust for the
106 * anti-rollback mechanism. SetupTPM can fail for three reasons. 1 A bug. 2 a
107 * TPM hardware failure. 3 An unexpected TPM state due to some attack. In
108 * general we cannot easily distinguish the kind of failure, so our strategy is
109 * to reboot in recovery mode in all cases. The recovery mode calls SetupTPM
110 * again, which executes (almost) the same sequence of operations. There is a
111 * good chance that, if recovery mode was entered because of a TPM failure, the
112 * failure will repeat itself. (In general this is impossible to guarantee
113 * because we have no way of creating the exact TPM initial state at the
114 * previous boot.) In recovery mode, we ignore the failure and continue, thus
115 * giving the recovery kernel a chance to fix things (that's why we don't set
116 * bGlobalLock). The choice is between a knowingly insecure device and a
117 * bricked device.
118 *
119 * As a side note, observe that we go through considerable hoops to avoid using
120 * the STCLEAR permissions for the index spaces. We do this to avoid writing
121 * to the TPM flashram at every reboot or wake-up, because of concerns about
122 * the durability of the NVRAM.
123 */
124uint32_t tpm_setup(int s3flag)
125{
126 uint32_t result;
127
128 result = tlcl_lib_init();
129 if (result != TPM_SUCCESS) {
130 printk(BIOS_ERR, "TPM: Can't initialize.\n");
Joel Kitching9937a062018-10-11 18:16:59 +0800131 return tpm_setup_epilogue(result);
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100132 }
133
134 /* Handle special init for S3 resume path */
135 if (s3flag) {
Joel Kitching9937a062018-10-11 18:16:59 +0800136 printk(BIOS_INFO, "TPM: Handle S3 resume.\n");
137 return tpm_setup_epilogue(tpm_setup_s3_helper());
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100138 }
139
140 result = tlcl_startup();
141 if (result != TPM_SUCCESS) {
142 printk(BIOS_ERR, "TPM: Can't run startup command.\n");
Joel Kitching9937a062018-10-11 18:16:59 +0800143 return tpm_setup_epilogue(result);
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100144 }
145
146 result = tlcl_assert_physical_presence();
147 if (result != TPM_SUCCESS) {
148 /*
149 * It is possible that the TPM was delivered with the physical
150 * presence command disabled. This tries enabling it, then
151 * tries asserting PP again.
152 */
153 result = tlcl_physical_presence_cmd_enable();
154 if (result != TPM_SUCCESS) {
Joel Kitching9937a062018-10-11 18:16:59 +0800155 printk(BIOS_ERR, "TPM: Can't enable physical presence command.\n");
156 return tpm_setup_epilogue(result);
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100157 }
158
159 result = tlcl_assert_physical_presence();
160 if (result != TPM_SUCCESS) {
Joel Kitching9937a062018-10-11 18:16:59 +0800161 printk(BIOS_ERR, "TPM: Can't assert physical presence.\n");
162 return tpm_setup_epilogue(result);
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100163 }
164 }
165
166#if IS_ENABLED(CONFIG_TPM1)
167 result = tpm1_invoke_state_machine();
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100168#endif
169
Joel Kitching9937a062018-10-11 18:16:59 +0800170 return tpm_setup_epilogue(result);
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100171}
172
173uint32_t tpm_clear_and_reenable(void)
174{
175 uint32_t result;
176
177 printk(BIOS_INFO, "TPM: Clear and re-enable\n");
178 result = tlcl_force_clear();
179 if (result != TPM_SUCCESS) {
180 printk(BIOS_ERR, "TPM: Can't initiate a force clear.\n");
181 return result;
182 }
183
184#if IS_ENABLED(CONFIG_TPM1)
185 result = tlcl_set_enable();
186 if (result != TPM_SUCCESS) {
187 printk(BIOS_ERR, "TPM: Can't set enabled state.\n");
188 return result;
189 }
190
191 result = tlcl_set_deactivated(0);
192 if (result != TPM_SUCCESS) {
193 printk(BIOS_ERR, "TPM: Can't set deactivated state.\n");
194 return result;
195 }
196#endif
197
198 return TPM_SUCCESS;
199}
200
Philipp Deppenwiesef8499722018-07-30 01:27:47 +0200201uint32_t tpm_extend_pcr(int pcr, uint8_t *digest,
202 size_t digest_len, const char *name)
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100203{
Philipp Deppenwiesef8499722018-07-30 01:27:47 +0200204 uint32_t result;
205
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100206 if (!digest)
207 return TPM_E_IOERROR;
208
Philipp Deppenwiesef8499722018-07-30 01:27:47 +0200209 result = tlcl_extend(pcr, digest, NULL);
210 if (result != TPM_SUCCESS)
211 return result;
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100212
Furquan Shaikh38f3ffa2018-07-31 14:26:39 -0700213 tcpa_log_add_table_entry(name, pcr, digest, digest_len);
Philipp Deppenwiesef8499722018-07-30 01:27:47 +0200214
Furquan Shaikh38f3ffa2018-07-31 14:26:39 -0700215 return TPM_SUCCESS;
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100216}