blob: 967612ad2016770767220a161319bf51e2f9d4cf [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
Vadim Bendebury289ee8f2016-11-11 09:36:50 -08007#include <antirollback.h>
Victor Prupisf7060202016-08-19 10:45:04 -07008#include <arch/early_variables.h>
Vadim Bendebury245d4572016-04-05 16:01:57 -07009#include <console/console.h>
10#include <endian.h>
11#include <lib/tpm2_tlcl_structures.h>
12#include <string.h>
13#include <tpm.h>
14#include <vb2_api.h>
15
16#include "tpm2_marshaling.h"
17
18/*
19 * This file provides interface between firmware and TPM2 device. The TPM1.2
20 * API was copied as is and relevant functions modified to comply with the
21 * TPM2 specification.
22 */
23
24static void *tpm_process_command(TPM_CC command, void *command_body)
25{
Duncan Laurieed75b272016-07-15 04:51:45 -070026 ssize_t out_size;
27 size_t in_size;
Vadim Bendebury245d4572016-04-05 16:01:57 -070028 /* Command/response buffer. */
Victor Prupisf7060202016-08-19 10:45:04 -070029 static uint8_t cr_buffer[TPM_BUFFER_SIZE] CAR_GLOBAL;
30
31 uint8_t *cr_buffer_ptr = car_get_var_ptr(cr_buffer);
Vadim Bendebury245d4572016-04-05 16:01:57 -070032
33 out_size = tpm_marshal_command(command, command_body,
Victor Prupisf7060202016-08-19 10:45:04 -070034 cr_buffer_ptr, sizeof(cr_buffer));
Vadim Bendebury245d4572016-04-05 16:01:57 -070035 if (out_size < 0) {
36 printk(BIOS_ERR, "command %#x, cr size %zd\n",
37 command, out_size);
38 return NULL;
39 }
40
41 in_size = sizeof(cr_buffer);
Victor Prupisf7060202016-08-19 10:45:04 -070042 if (tis_sendrecv(cr_buffer_ptr, out_size,
43 cr_buffer_ptr, &in_size)) {
Vadim Bendebury245d4572016-04-05 16:01:57 -070044 printk(BIOS_ERR, "tpm transaction failed\n");
45 return NULL;
46 }
47
Victor Prupisf7060202016-08-19 10:45:04 -070048 return tpm_unmarshal_response(command, cr_buffer_ptr, in_size);
Vadim Bendebury245d4572016-04-05 16:01:57 -070049}
50
51
52uint32_t tlcl_get_permanent_flags(TPM_PERMANENT_FLAGS *pflags)
53{
54 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
55 return TPM_SUCCESS;
56}
57
Furquan Shaikhcc3365a2016-09-30 12:53:19 -070058static uint32_t tlcl_send_startup(TPM_SU type)
59{
60 struct tpm2_startup startup;
61 struct tpm2_response *response;
62
63 startup.startup_type = type;
64 response = tpm_process_command(TPM2_Startup, &startup);
65
66 if (response && response->hdr.tpm_code &&
67 (response->hdr.tpm_code != TPM_RC_INITIALIZE)) {
68 printk(BIOS_INFO, "%s: Startup return code is %x\n",
69 __func__, response->hdr.tpm_code);
70 return TPM_E_IOERROR;
71 }
72 return TPM_SUCCESS;
73
74}
75
Vadim Bendebury245d4572016-04-05 16:01:57 -070076uint32_t tlcl_resume(void)
77{
Furquan Shaikhcc3365a2016-09-30 12:53:19 -070078 return tlcl_send_startup(TPM_SU_STATE);
Vadim Bendebury245d4572016-04-05 16:01:57 -070079}
80
81uint32_t tlcl_assert_physical_presence(void)
82{
83 /*
84 * Nothing to do on TPM2 for this, use platform hierarchy availability
85 * instead.
86 */
87 return TPM_SUCCESS;
88}
89
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -070090/*
91 * The caller will provide the digest in a 32 byte buffer, let's consider it a
92 * sha256 digest.
93 */
Vadim Bendebury245d4572016-04-05 16:01:57 -070094uint32_t tlcl_extend(int pcr_num, const uint8_t *in_digest,
95 uint8_t *out_digest)
96{
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -070097 struct tpm2_pcr_extend_cmd pcr_ext_cmd;
98 struct tpm2_response *response;
99
100 pcr_ext_cmd.pcrHandle = HR_PCR + pcr_num;
101 pcr_ext_cmd.digests.count = 1;
102 pcr_ext_cmd.digests.digests[0].hashAlg = TPM_ALG_SHA256;
103 memcpy(pcr_ext_cmd.digests.digests[0].digest.sha256, in_digest,
104 sizeof(pcr_ext_cmd.digests.digests[0].digest.sha256));
105
106 response = tpm_process_command(TPM2_PCR_Extend, &pcr_ext_cmd);
107
108 printk(BIOS_INFO, "%s: response is %x\n",
109 __func__, response ? response->hdr.tpm_code : -1);
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_finalize_physical_presence(void)
117{
118 /* Nothing needs to be done with tpm2. */
119 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
120 return TPM_SUCCESS;
121}
122
123uint32_t tlcl_force_clear(void)
124{
Vadim Bendeburyadfbbde2016-07-03 15:56:41 -0700125 struct tpm2_response *response;
126
127 response = tpm_process_command(TPM2_Clear, NULL);
128 printk(BIOS_INFO, "%s: response is %x\n",
129 __func__, response ? response->hdr.tpm_code : -1);
130
131 if (!response || response->hdr.tpm_code)
132 return TPM_E_IOERROR;
133
Vadim Bendebury245d4572016-04-05 16:01:57 -0700134 return TPM_SUCCESS;
135}
136
137uint32_t tlcl_get_flags(uint8_t *disable, uint8_t *deactivated,
138 uint8_t *nvlocked)
139{
140 /*
141 * TPM2 does not map directly into these flags TPM1.2 based firmware
142 * expects to be able to retrieve.
143 *
144 * In any case, if any of these conditions are present, the following
145 * firmware flow would be interrupted and will have a chance to report
146 * an error. Let's just hardcode an "All OK" response for now.
147 */
148
149 if (disable)
150 *disable = 0;
151
152 if (nvlocked)
153 *nvlocked = 1;
154
155 if (deactivated)
156 *deactivated = 0;
157
158 return TPM_SUCCESS;
159}
160
Furquan Shaikh8b5d04e2016-11-10 09:49:05 -0800161static uint8_t tlcl_init_done CAR_GLOBAL;
162
163/* This function is called directly by vboot, uses vboot return types. */
Vadim Bendebury245d4572016-04-05 16:01:57 -0700164uint32_t tlcl_lib_init(void)
165{
Furquan Shaikh8b5d04e2016-11-10 09:49:05 -0800166 uint8_t done = car_get_var(tlcl_init_done);
167 if (done)
168 return VB2_SUCCESS;
169
Vadim Bendebury245d4572016-04-05 16:01:57 -0700170 if (tis_init())
171 return VB2_ERROR_UNKNOWN;
172 if (tis_open())
173 return VB2_ERROR_UNKNOWN;
Furquan Shaikh8b5d04e2016-11-10 09:49:05 -0800174
175 car_set_var(tlcl_init_done, 1);
176
Vadim Bendebury245d4572016-04-05 16:01:57 -0700177 return VB2_SUCCESS;
178}
179
180uint32_t tlcl_physical_presence_cmd_enable(void)
181{
182 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
183 return TPM_SUCCESS;
184}
185
186uint32_t tlcl_read(uint32_t index, void *data, uint32_t length)
187{
188 struct tpm2_nv_read_cmd nv_readc;
189 struct tpm2_response *response;
190
191 memset(&nv_readc, 0, sizeof(nv_readc));
192
193 nv_readc.nvIndex = HR_NV_INDEX + index;
194 nv_readc.size = length;
195
196 response = tpm_process_command(TPM2_NV_Read, &nv_readc);
197
198 /* Need to map tpm error codes into internal values. */
199 if (!response)
200 return TPM_E_READ_FAILURE;
201
202 printk(BIOS_INFO, "%s:%d index %#x return code %x\n",
203 __FILE__, __LINE__, index, response->hdr.tpm_code);
204 switch (response->hdr.tpm_code) {
205 case 0:
206 break;
207
208 case 0x28b:
209 return TPM_E_BADINDEX;
210
211 default:
212 return TPM_E_READ_FAILURE;
213 }
214
215 if (length > response->nvr.buffer.t.size)
216 return TPM_E_RESPONSE_TOO_LARGE;
217
218 if (length < response->nvr.buffer.t.size)
219 return TPM_E_READ_EMPTY;
220
221 memcpy(data, response->nvr.buffer.t.buffer, length);
222
223 return TPM_SUCCESS;
224}
225
226uint32_t tlcl_self_test_full(void)
227{
228 struct tpm2_self_test st;
229 struct tpm2_response *response;
230
231 st.yes_no = 1;
232
233 response = tpm_process_command(TPM2_SelfTest, &st);
234 printk(BIOS_INFO, "%s: response is %x\n",
235 __func__, response ? response->hdr.tpm_code : -1);
236 return TPM_SUCCESS;
237}
238
239uint32_t tlcl_set_deactivated(uint8_t flag)
240{
241 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
242 return TPM_SUCCESS;
243}
244
245uint32_t tlcl_set_enable(void)
246{
247 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
248 return TPM_SUCCESS;
249}
250
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700251uint32_t tlcl_lock_nv_write(uint32_t index)
Vadim Bendebury245d4572016-04-05 16:01:57 -0700252{
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700253 struct tpm2_response *response;
254 /* TPM Wll reject attempts to write at non-defined index. */
255 struct tpm2_nv_write_lock_cmd nv_wl = {
256 .nvIndex = HR_NV_INDEX + index,
257 };
258
259 response = tpm_process_command(TPM2_NV_WriteLock, &nv_wl);
260
261 printk(BIOS_INFO, "%s: response is %x\n",
262 __func__, response ? response->hdr.tpm_code : -1);
263
264 if (!response || response->hdr.tpm_code)
265 return TPM_E_IOERROR;
266
Vadim Bendebury245d4572016-04-05 16:01:57 -0700267 return TPM_SUCCESS;
268}
269
270uint32_t tlcl_startup(void)
271{
Furquan Shaikhcc3365a2016-09-30 12:53:19 -0700272 return tlcl_send_startup(TPM_SU_CLEAR);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700273}
274
275uint32_t tlcl_write(uint32_t index, const void *data, uint32_t length)
276{
277 struct tpm2_nv_write_cmd nv_writec;
278 struct tpm2_response *response;
279
280 memset(&nv_writec, 0, sizeof(nv_writec));
281
282 nv_writec.nvIndex = HR_NV_INDEX + index;
283 nv_writec.data.t.size = length;
284 nv_writec.data.t.buffer = data;
285
286 response = tpm_process_command(TPM2_NV_Write, &nv_writec);
287
Vadim Bendebury1ec76032016-07-05 22:30:16 -0700288 printk(BIOS_INFO, "%s: response is %x\n",
289 __func__, response ? response->hdr.tpm_code : -1);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700290
Vadim Bendebury1ec76032016-07-05 22:30:16 -0700291 /* Need to map tpm error codes into internal values. */
292 if (!response || response->hdr.tpm_code)
293 return TPM_E_WRITE_FAILURE;
Vadim Bendebury245d4572016-04-05 16:01:57 -0700294
295 return TPM_SUCCESS;
296}
297
Vadim Bendebury7ee057c2016-07-03 15:24:23 -0700298uint32_t tlcl_define_space(uint32_t space_index, size_t space_size)
Vadim Bendebury245d4572016-04-05 16:01:57 -0700299{
300 struct tpm2_nv_define_space_cmd nvds_cmd;
301 struct tpm2_response *response;
Vadim Bendebury7ee057c2016-07-03 15:24:23 -0700302 /*
Vadim Bendebury289ee8f2016-11-11 09:36:50 -0800303 * Different sets of NVRAM space attributes apply to the "ro" spaces,
304 * i.e. those which should not be possible to delete or modify once
305 * the RO exits, and the rest of the NVRAM spaces.
Vadim Bendebury7ee057c2016-07-03 15:24:23 -0700306 */
Vadim Bendebury289ee8f2016-11-11 09:36:50 -0800307 const TPMA_NV ro_space_attributes = {
308 .TPMA_NV_PPWRITE = 1,
309 .TPMA_NV_AUTHREAD = 1,
310 .TPMA_NV_PPREAD = 1,
311 .TPMA_NV_PLATFORMCREATE = 1,
312 .TPMA_NV_WRITE_STCLEAR = 1,
313 .TPMA_NV_POLICY_DELETE = 1,
314 };
315 const TPMA_NV default_space_attributes = {
316 .TPMA_NV_PPWRITE = 1,
317 .TPMA_NV_AUTHREAD = 1,
318 .TPMA_NV_PPREAD = 1,
319 .TPMA_NV_PLATFORMCREATE = 1,
Vadim Bendebury7ee057c2016-07-03 15:24:23 -0700320 };
Vadim Bendebury245d4572016-04-05 16:01:57 -0700321
322 /* Prepare the define space command structure. */
323 memset(&nvds_cmd, 0, sizeof(nvds_cmd));
324
325 nvds_cmd.publicInfo.dataSize = space_size;
326 nvds_cmd.publicInfo.nvIndex = HR_NV_INDEX + space_index;
327 nvds_cmd.publicInfo.nameAlg = TPM_ALG_SHA256;
328
Vadim Bendebury289ee8f2016-11-11 09:36:50 -0800329 /* RO only NV spaces should be impossible to destroy. */
330 if ((space_index == FIRMWARE_NV_INDEX) ||
331 (space_index == REC_HASH_NV_INDEX)) {
332 /*
333 * This policy digest was obtained using TPM2_PolicyPCR
334 * selecting only PCR_0 with a value of all zeros.
335 */
336 const uint8_t pcr0_unchanged_policy[] = {
337 0x09, 0x93, 0x3C, 0xCE, 0xEB, 0xB4, 0x41, 0x11,
338 0x18, 0x81, 0x1D, 0xD4, 0x47, 0x78, 0x80, 0x08,
339 0x88, 0x86, 0x62, 0x2D, 0xD7, 0x79, 0x94, 0x46,
340 0x62, 0x26, 0x68, 0x8E, 0xEE, 0xE6, 0x6A, 0xA1
341 };
Vadim Bendebury245d4572016-04-05 16:01:57 -0700342
Vadim Bendebury289ee8f2016-11-11 09:36:50 -0800343 nvds_cmd.publicInfo.attributes = ro_space_attributes;
344 /*
345 * Use policy digest based on default pcr0 value. This makes
346 * sure that the space can not be deleted as soon as PCR0
347 * value has been extended from default.
348 */
349 nvds_cmd.publicInfo.authPolicy.t.buffer = pcr0_unchanged_policy;
Lee Leahy73402172017-03-10 15:23:24 -0800350 nvds_cmd.publicInfo.authPolicy.t.size =
351 sizeof(pcr0_unchanged_policy);
Vadim Bendebury289ee8f2016-11-11 09:36:50 -0800352 } else {
353 nvds_cmd.publicInfo.attributes = default_space_attributes;
354 }
Vadim Bendebury245d4572016-04-05 16:01:57 -0700355
356 response = tpm_process_command(TPM2_NV_DefineSpace, &nvds_cmd);
357 printk(BIOS_INFO, "%s: response is %x\n",
358 __func__, response ? response->hdr.tpm_code : -1);
359
360 if (!response)
361 return TPM_E_NO_DEVICE;
362
Vadim Bendeburyaf8ae932016-11-11 14:15:31 -0800363 /* Map TPM2 retrun codes into common vboot represenation. */
Lee Leahy45fde702017-03-08 18:02:24 -0800364 switch (response->hdr.tpm_code) {
Vadim Bendeburyaf8ae932016-11-11 14:15:31 -0800365 case TPM2_RC_SUCCESS:
366 return TPM_SUCCESS;
367 case TPM2_RC_NV_DEFINED:
368 return TPM_E_NV_DEFINED;
369 default:
370 return TPM_E_INTERNAL_INCONSISTENCY;
371 }
Vadim Bendebury245d4572016-04-05 16:01:57 -0700372}
Aaron Durbinf56c7782017-01-10 17:44:42 -0600373
374uint32_t tlcl_disable_platform_hierarchy(void)
375{
376 struct tpm2_response *response;
377 struct tpm2_hierarchy_control_cmd hc = {
378 .enable = TPM_RH_PLATFORM,
379 .state = 0,
380 };
381
382 response = tpm_process_command(TPM2_Hierarchy_Control, &hc);
383
384 if (!response || response->hdr.tpm_code)
385 return TPM_E_INTERNAL_INCONSISTENCY;
386
387 return TPM_SUCCESS;
388}
Aaron Durbineeb77372017-03-08 11:23:11 -0600389
390uint32_t tlcl_cr50_enable_nvcommits(void)
391{
392 uint16_t sub_command = TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS;
393 struct tpm2_response *response;
394
395 printk(BIOS_INFO, "Enabling cr50 nvmem commmits\n");
396
397 response = tpm_process_command(TPM2_CR50_VENDOR_COMMAND, &sub_command);
398
399 if (response == NULL || (response && response->hdr.tpm_code)) {
400 if (response)
401 printk(BIOS_INFO, "%s: failed %x\n", __func__,
402 response->hdr.tpm_code);
403 else
404 printk(BIOS_INFO, "%s: failed\n", __func__);
405 return TPM_E_IOERROR;
406 }
407 return TPM_SUCCESS;
408}