blob: c8e7e90e7b38843e6a3dcac465c9a2b08c139edb [file] [log] [blame]
Vadim Bendebury245d4572016-04-05 16:01:57 -07001/*
2 * Copyright 2016 The Chromium OS Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
7#include <console/console.h>
8#include <endian.h>
9#include <lib/tpm2_tlcl_structures.h>
10#include <string.h>
11#include <tpm.h>
12#include <vb2_api.h>
13
14#include "tpm2_marshaling.h"
15
16/*
17 * This file provides interface between firmware and TPM2 device. The TPM1.2
18 * API was copied as is and relevant functions modified to comply with the
19 * TPM2 specification.
20 */
21
22static void *tpm_process_command(TPM_CC command, void *command_body)
23{
Duncan Laurieed75b272016-07-15 04:51:45 -070024 ssize_t out_size;
25 size_t in_size;
Vadim Bendebury245d4572016-04-05 16:01:57 -070026 /* Command/response buffer. */
27 static uint8_t cr_buffer[TPM_BUFFER_SIZE];
28
29 out_size = tpm_marshal_command(command, command_body,
30 cr_buffer, sizeof(cr_buffer));
31 if (out_size < 0) {
32 printk(BIOS_ERR, "command %#x, cr size %zd\n",
33 command, out_size);
34 return NULL;
35 }
36
37 in_size = sizeof(cr_buffer);
38 if (tis_sendrecv(cr_buffer, out_size,
39 cr_buffer, &in_size)) {
40 printk(BIOS_ERR, "tpm transaction failed\n");
41 return NULL;
42 }
43
44 return tpm_unmarshal_response(command, cr_buffer, in_size);
45}
46
47
48uint32_t tlcl_get_permanent_flags(TPM_PERMANENT_FLAGS *pflags)
49{
50 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
51 return TPM_SUCCESS;
52}
53
54uint32_t tlcl_resume(void)
55{
56 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
57 return TPM_SUCCESS;
58}
59
60uint32_t tlcl_assert_physical_presence(void)
61{
62 /*
63 * Nothing to do on TPM2 for this, use platform hierarchy availability
64 * instead.
65 */
66 return TPM_SUCCESS;
67}
68
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -070069/*
70 * The caller will provide the digest in a 32 byte buffer, let's consider it a
71 * sha256 digest.
72 */
Vadim Bendebury245d4572016-04-05 16:01:57 -070073uint32_t tlcl_extend(int pcr_num, const uint8_t *in_digest,
74 uint8_t *out_digest)
75{
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -070076 struct tpm2_pcr_extend_cmd pcr_ext_cmd;
77 struct tpm2_response *response;
78
79 pcr_ext_cmd.pcrHandle = HR_PCR + pcr_num;
80 pcr_ext_cmd.digests.count = 1;
81 pcr_ext_cmd.digests.digests[0].hashAlg = TPM_ALG_SHA256;
82 memcpy(pcr_ext_cmd.digests.digests[0].digest.sha256, in_digest,
83 sizeof(pcr_ext_cmd.digests.digests[0].digest.sha256));
84
85 response = tpm_process_command(TPM2_PCR_Extend, &pcr_ext_cmd);
86
87 printk(BIOS_INFO, "%s: response is %x\n",
88 __func__, response ? response->hdr.tpm_code : -1);
89 if (!response || response->hdr.tpm_code)
90 return TPM_E_IOERROR;
91
Vadim Bendebury245d4572016-04-05 16:01:57 -070092 return TPM_SUCCESS;
93}
94
95uint32_t tlcl_finalize_physical_presence(void)
96{
97 /* Nothing needs to be done with tpm2. */
98 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
99 return TPM_SUCCESS;
100}
101
102uint32_t tlcl_force_clear(void)
103{
Vadim Bendeburyadfbbde2016-07-03 15:56:41 -0700104 struct tpm2_response *response;
105
106 response = tpm_process_command(TPM2_Clear, NULL);
107 printk(BIOS_INFO, "%s: response is %x\n",
108 __func__, response ? response->hdr.tpm_code : -1);
109
110 if (!response || response->hdr.tpm_code)
111 return TPM_E_IOERROR;
112
Vadim Bendebury245d4572016-04-05 16:01:57 -0700113 return TPM_SUCCESS;
114}
115
116uint32_t tlcl_get_flags(uint8_t *disable, uint8_t *deactivated,
117 uint8_t *nvlocked)
118{
119 /*
120 * TPM2 does not map directly into these flags TPM1.2 based firmware
121 * expects to be able to retrieve.
122 *
123 * In any case, if any of these conditions are present, the following
124 * firmware flow would be interrupted and will have a chance to report
125 * an error. Let's just hardcode an "All OK" response for now.
126 */
127
128 if (disable)
129 *disable = 0;
130
131 if (nvlocked)
132 *nvlocked = 1;
133
134 if (deactivated)
135 *deactivated = 0;
136
137 return TPM_SUCCESS;
138}
139
140uint32_t tlcl_lib_init(void)
141{
142 /*
143 * This function is called directly by vboot, uses vboot return
144 * types.
145 */
146 if (tis_init())
147 return VB2_ERROR_UNKNOWN;
148 if (tis_open())
149 return VB2_ERROR_UNKNOWN;
150 return VB2_SUCCESS;
151}
152
153uint32_t tlcl_physical_presence_cmd_enable(void)
154{
155 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
156 return TPM_SUCCESS;
157}
158
159uint32_t tlcl_read(uint32_t index, void *data, uint32_t length)
160{
161 struct tpm2_nv_read_cmd nv_readc;
162 struct tpm2_response *response;
163
164 memset(&nv_readc, 0, sizeof(nv_readc));
165
166 nv_readc.nvIndex = HR_NV_INDEX + index;
167 nv_readc.size = length;
168
169 response = tpm_process_command(TPM2_NV_Read, &nv_readc);
170
171 /* Need to map tpm error codes into internal values. */
172 if (!response)
173 return TPM_E_READ_FAILURE;
174
175 printk(BIOS_INFO, "%s:%d index %#x return code %x\n",
176 __FILE__, __LINE__, index, response->hdr.tpm_code);
177 switch (response->hdr.tpm_code) {
178 case 0:
179 break;
180
181 case 0x28b:
182 return TPM_E_BADINDEX;
183
184 default:
185 return TPM_E_READ_FAILURE;
186 }
187
188 if (length > response->nvr.buffer.t.size)
189 return TPM_E_RESPONSE_TOO_LARGE;
190
191 if (length < response->nvr.buffer.t.size)
192 return TPM_E_READ_EMPTY;
193
194 memcpy(data, response->nvr.buffer.t.buffer, length);
195
196 return TPM_SUCCESS;
197}
198
199uint32_t tlcl_self_test_full(void)
200{
201 struct tpm2_self_test st;
202 struct tpm2_response *response;
203
204 st.yes_no = 1;
205
206 response = tpm_process_command(TPM2_SelfTest, &st);
207 printk(BIOS_INFO, "%s: response is %x\n",
208 __func__, response ? response->hdr.tpm_code : -1);
209 return TPM_SUCCESS;
210}
211
212uint32_t tlcl_set_deactivated(uint8_t flag)
213{
214 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
215 return TPM_SUCCESS;
216}
217
218uint32_t tlcl_set_enable(void)
219{
220 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
221 return TPM_SUCCESS;
222}
223
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700224uint32_t tlcl_lock_nv_write(uint32_t index)
Vadim Bendebury245d4572016-04-05 16:01:57 -0700225{
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700226 struct tpm2_response *response;
227 /* TPM Wll reject attempts to write at non-defined index. */
228 struct tpm2_nv_write_lock_cmd nv_wl = {
229 .nvIndex = HR_NV_INDEX + index,
230 };
231
232 response = tpm_process_command(TPM2_NV_WriteLock, &nv_wl);
233
234 printk(BIOS_INFO, "%s: response is %x\n",
235 __func__, response ? response->hdr.tpm_code : -1);
236
237 if (!response || response->hdr.tpm_code)
238 return TPM_E_IOERROR;
239
Vadim Bendebury245d4572016-04-05 16:01:57 -0700240 return TPM_SUCCESS;
241}
242
243uint32_t tlcl_startup(void)
244{
245 struct tpm2_startup startup;
246 struct tpm2_response *response;
247
248 startup.startup_type = TPM_SU_CLEAR;
249 response = tpm_process_command(TPM2_Startup, &startup);
250 if (response && response->hdr.tpm_code &&
251 (response->hdr.tpm_code != TPM_RC_INITIALIZE)) {
252 printk(BIOS_INFO, "startup return code is %x\n",
253 response->hdr.tpm_code);
254 return TPM_E_IOERROR;
255 }
256 return TPM_SUCCESS;
257}
258
259uint32_t tlcl_write(uint32_t index, const void *data, uint32_t length)
260{
261 struct tpm2_nv_write_cmd nv_writec;
262 struct tpm2_response *response;
263
264 memset(&nv_writec, 0, sizeof(nv_writec));
265
266 nv_writec.nvIndex = HR_NV_INDEX + index;
267 nv_writec.data.t.size = length;
268 nv_writec.data.t.buffer = data;
269
270 response = tpm_process_command(TPM2_NV_Write, &nv_writec);
271
Vadim Bendebury1ec76032016-07-05 22:30:16 -0700272 printk(BIOS_INFO, "%s: response is %x\n",
273 __func__, response ? response->hdr.tpm_code : -1);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700274
Vadim Bendebury1ec76032016-07-05 22:30:16 -0700275 /* Need to map tpm error codes into internal values. */
276 if (!response || response->hdr.tpm_code)
277 return TPM_E_WRITE_FAILURE;
Vadim Bendebury245d4572016-04-05 16:01:57 -0700278
279 return TPM_SUCCESS;
280}
281
Vadim Bendebury7ee057c2016-07-03 15:24:23 -0700282uint32_t tlcl_define_space(uint32_t space_index, size_t space_size)
Vadim Bendebury245d4572016-04-05 16:01:57 -0700283{
284 struct tpm2_nv_define_space_cmd nvds_cmd;
285 struct tpm2_response *response;
Vadim Bendebury7ee057c2016-07-03 15:24:23 -0700286 /*
287 * This policy digest was obtained using TPM2_PolicyPCR selecting only
288 * PCR_0 with a value of all zeros.
289 */
290 static const uint8_t pcr0_unchanged_policy[] = {
291 0x09, 0x93, 0x3C, 0xCE, 0xEB, 0xB4, 0x41, 0x11,
292 0x18, 0x81, 0x1D, 0xD4, 0x47, 0x78, 0x80, 0x08,
293 0x88, 0x86, 0x62, 0x2D, 0xD7, 0x79, 0x94, 0x46,
294 0x62, 0x26, 0x68, 0x8E, 0xEE, 0xE6, 0x6A, 0xA1
295 };
Vadim Bendebury245d4572016-04-05 16:01:57 -0700296
297 /* Prepare the define space command structure. */
298 memset(&nvds_cmd, 0, sizeof(nvds_cmd));
299
300 nvds_cmd.publicInfo.dataSize = space_size;
301 nvds_cmd.publicInfo.nvIndex = HR_NV_INDEX + space_index;
302 nvds_cmd.publicInfo.nameAlg = TPM_ALG_SHA256;
303
Elyes HAOUAS91e0e3c2016-07-30 15:51:13 +0200304 /* Attributes common for all NVRAM spaces used by firmware. */
Vadim Bendebury245d4572016-04-05 16:01:57 -0700305 nvds_cmd.publicInfo.attributes.TPMA_NV_PPWRITE = 1;
306 nvds_cmd.publicInfo.attributes.TPMA_NV_AUTHREAD = 1;
307 nvds_cmd.publicInfo.attributes.TPMA_NV_PPREAD = 1;
308 nvds_cmd.publicInfo.attributes.TPMA_NV_PLATFORMCREATE = 1;
Vadim Bendebury7ee057c2016-07-03 15:24:23 -0700309 nvds_cmd.publicInfo.attributes.TPMA_NV_WRITE_STCLEAR = 1;
310 nvds_cmd.publicInfo.attributes.TPMA_NV_POLICY_DELETE = 1;
Vadim Bendebury245d4572016-04-05 16:01:57 -0700311
Vadim Bendebury7ee057c2016-07-03 15:24:23 -0700312 /*
313 * Use policy digest based on default pcr0 value. This makes sure that
314 * the space can not be deleted as soon as PCR0 value has been
315 * extended from default.
316 */
317 nvds_cmd.publicInfo.authPolicy.t.buffer = pcr0_unchanged_policy;
318 nvds_cmd.publicInfo.authPolicy.t.size = sizeof(pcr0_unchanged_policy);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700319
320 response = tpm_process_command(TPM2_NV_DefineSpace, &nvds_cmd);
321 printk(BIOS_INFO, "%s: response is %x\n",
322 __func__, response ? response->hdr.tpm_code : -1);
323
324 if (!response)
325 return TPM_E_NO_DEVICE;
326
327 return response->hdr.tpm_code ? TPM_E_INTERNAL_INCONSISTENCY :
328 TPM_SUCCESS;
329}