blob: fccf2245198b4528f0fbd98a6cb75a2ef8e6bb87 [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
67/*
68 * tpm_setup starts the TPM and establishes the root of trust for the
69 * anti-rollback mechanism. SetupTPM can fail for three reasons. 1 A bug. 2 a
70 * TPM hardware failure. 3 An unexpected TPM state due to some attack. In
71 * general we cannot easily distinguish the kind of failure, so our strategy is
72 * to reboot in recovery mode in all cases. The recovery mode calls SetupTPM
73 * again, which executes (almost) the same sequence of operations. There is a
74 * good chance that, if recovery mode was entered because of a TPM failure, the
75 * failure will repeat itself. (In general this is impossible to guarantee
76 * because we have no way of creating the exact TPM initial state at the
77 * previous boot.) In recovery mode, we ignore the failure and continue, thus
78 * giving the recovery kernel a chance to fix things (that's why we don't set
79 * bGlobalLock). The choice is between a knowingly insecure device and a
80 * bricked device.
81 *
82 * As a side note, observe that we go through considerable hoops to avoid using
83 * the STCLEAR permissions for the index spaces. We do this to avoid writing
84 * to the TPM flashram at every reboot or wake-up, because of concerns about
85 * the durability of the NVRAM.
86 */
87uint32_t tpm_setup(int s3flag)
88{
89 uint32_t result;
90
91 result = tlcl_lib_init();
92 if (result != TPM_SUCCESS) {
93 printk(BIOS_ERR, "TPM: Can't initialize.\n");
94 goto out;
95 }
96
97 /* Handle special init for S3 resume path */
98 if (s3flag) {
99 result = tlcl_resume();
100 if (result == TPM_E_INVALID_POSTINIT)
101 printk(BIOS_INFO, "TPM: Already initialized.\n");
102
103 return TPM_SUCCESS;
104 }
105
106 result = tlcl_startup();
107 if (result != TPM_SUCCESS) {
108 printk(BIOS_ERR, "TPM: Can't run startup command.\n");
109 goto out;
110 }
111
112 result = tlcl_assert_physical_presence();
113 if (result != TPM_SUCCESS) {
114 /*
115 * It is possible that the TPM was delivered with the physical
116 * presence command disabled. This tries enabling it, then
117 * tries asserting PP again.
118 */
119 result = tlcl_physical_presence_cmd_enable();
120 if (result != TPM_SUCCESS) {
121 printk(
Philipp Deppenwiese4d2af9d2018-08-14 09:46:55 -0700122 BIOS_ERR,
123 "TPM: Can't enable physical presence command.\n");
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100124 goto out;
125 }
126
127 result = tlcl_assert_physical_presence();
128 if (result != TPM_SUCCESS) {
129 printk(BIOS_ERR,
130 "TPM: Can't assert physical presence.\n");
131 goto out;
132 }
133 }
134
135#if IS_ENABLED(CONFIG_TPM1)
136 result = tpm1_invoke_state_machine();
137 if (result != TPM_SUCCESS)
138 return result;
139#endif
140
141out:
142 if (result != TPM_SUCCESS)
143 post_code(POST_TPM_FAILURE);
144 else
145 printk(BIOS_INFO, "TPM: setup succeeded\n");
146
147 return result;
148}
149
150uint32_t tpm_clear_and_reenable(void)
151{
152 uint32_t result;
153
154 printk(BIOS_INFO, "TPM: Clear and re-enable\n");
155 result = tlcl_force_clear();
156 if (result != TPM_SUCCESS) {
157 printk(BIOS_ERR, "TPM: Can't initiate a force clear.\n");
158 return result;
159 }
160
161#if IS_ENABLED(CONFIG_TPM1)
162 result = tlcl_set_enable();
163 if (result != TPM_SUCCESS) {
164 printk(BIOS_ERR, "TPM: Can't set enabled state.\n");
165 return result;
166 }
167
168 result = tlcl_set_deactivated(0);
169 if (result != TPM_SUCCESS) {
170 printk(BIOS_ERR, "TPM: Can't set deactivated state.\n");
171 return result;
172 }
173#endif
174
175 return TPM_SUCCESS;
176}
177
Philipp Deppenwiesef8499722018-07-30 01:27:47 +0200178uint32_t tpm_extend_pcr(int pcr, uint8_t *digest,
179 size_t digest_len, const char *name)
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100180{
Philipp Deppenwiesef8499722018-07-30 01:27:47 +0200181 uint32_t result;
182
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100183 if (!digest)
184 return TPM_E_IOERROR;
185
Philipp Deppenwiesef8499722018-07-30 01:27:47 +0200186 result = tlcl_extend(pcr, digest, NULL);
187 if (result != TPM_SUCCESS)
188 return result;
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100189
Furquan Shaikh38f3ffa2018-07-31 14:26:39 -0700190 tcpa_log_add_table_entry(name, pcr, digest, digest_len);
Philipp Deppenwiesef8499722018-07-30 01:27:47 +0200191
Furquan Shaikh38f3ffa2018-07-31 14:26:39 -0700192 return TPM_SUCCESS;
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100193}