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