blob: 754f835719bc47135b5549dde3eff545dcd75543 [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{
Aaron Durbinee049fa2017-03-25 00:38:45 -050026 struct obuf ob;
27 struct ibuf ib;
28 size_t out_size;
Duncan Laurieed75b272016-07-15 04:51:45 -070029 size_t in_size;
Aaron Durbinee049fa2017-03-25 00:38:45 -050030 const uint8_t *sendb;
Vadim Bendebury245d4572016-04-05 16:01:57 -070031 /* Command/response buffer. */
Victor Prupisf7060202016-08-19 10:45:04 -070032 static uint8_t cr_buffer[TPM_BUFFER_SIZE] CAR_GLOBAL;
33
34 uint8_t *cr_buffer_ptr = car_get_var_ptr(cr_buffer);
Vadim Bendebury245d4572016-04-05 16:01:57 -070035
Aaron Durbinee049fa2017-03-25 00:38:45 -050036 obuf_init(&ob, cr_buffer_ptr, sizeof(cr_buffer));
37
38 if (tpm_marshal_command(command, command_body, &ob) < 0) {
39 printk(BIOS_ERR, "command %#x\n", command);
Vadim Bendebury245d4572016-04-05 16:01:57 -070040 return NULL;
41 }
42
Aaron Durbinee049fa2017-03-25 00:38:45 -050043 sendb = obuf_contents(&ob, &out_size);
44
Vadim Bendebury245d4572016-04-05 16:01:57 -070045 in_size = sizeof(cr_buffer);
Aaron Durbinee049fa2017-03-25 00:38:45 -050046 if (tis_sendrecv(sendb, out_size, cr_buffer_ptr, &in_size)) {
Vadim Bendebury245d4572016-04-05 16:01:57 -070047 printk(BIOS_ERR, "tpm transaction failed\n");
48 return NULL;
49 }
50
Aaron Durbinee049fa2017-03-25 00:38:45 -050051 ibuf_init(&ib, cr_buffer_ptr, in_size);
52
53 return tpm_unmarshal_response(command, &ib);
Vadim Bendebury245d4572016-04-05 16:01:57 -070054}
55
56
57uint32_t tlcl_get_permanent_flags(TPM_PERMANENT_FLAGS *pflags)
58{
59 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
60 return TPM_SUCCESS;
61}
62
Furquan Shaikhcc3365a2016-09-30 12:53:19 -070063static uint32_t tlcl_send_startup(TPM_SU type)
64{
65 struct tpm2_startup startup;
66 struct tpm2_response *response;
67
68 startup.startup_type = type;
69 response = tpm_process_command(TPM2_Startup, &startup);
70
71 if (response && response->hdr.tpm_code &&
72 (response->hdr.tpm_code != TPM_RC_INITIALIZE)) {
73 printk(BIOS_INFO, "%s: Startup return code is %x\n",
74 __func__, response->hdr.tpm_code);
75 return TPM_E_IOERROR;
76 }
77 return TPM_SUCCESS;
78
79}
80
Vadim Bendebury245d4572016-04-05 16:01:57 -070081uint32_t tlcl_resume(void)
82{
Furquan Shaikhcc3365a2016-09-30 12:53:19 -070083 return tlcl_send_startup(TPM_SU_STATE);
Vadim Bendebury245d4572016-04-05 16:01:57 -070084}
85
86uint32_t tlcl_assert_physical_presence(void)
87{
88 /*
89 * Nothing to do on TPM2 for this, use platform hierarchy availability
90 * instead.
91 */
92 return TPM_SUCCESS;
93}
94
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -070095/*
96 * The caller will provide the digest in a 32 byte buffer, let's consider it a
97 * sha256 digest.
98 */
Vadim Bendebury245d4572016-04-05 16:01:57 -070099uint32_t tlcl_extend(int pcr_num, const uint8_t *in_digest,
100 uint8_t *out_digest)
101{
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700102 struct tpm2_pcr_extend_cmd pcr_ext_cmd;
103 struct tpm2_response *response;
104
105 pcr_ext_cmd.pcrHandle = HR_PCR + pcr_num;
106 pcr_ext_cmd.digests.count = 1;
107 pcr_ext_cmd.digests.digests[0].hashAlg = TPM_ALG_SHA256;
108 memcpy(pcr_ext_cmd.digests.digests[0].digest.sha256, in_digest,
109 sizeof(pcr_ext_cmd.digests.digests[0].digest.sha256));
110
111 response = tpm_process_command(TPM2_PCR_Extend, &pcr_ext_cmd);
112
113 printk(BIOS_INFO, "%s: response is %x\n",
114 __func__, response ? response->hdr.tpm_code : -1);
115 if (!response || response->hdr.tpm_code)
116 return TPM_E_IOERROR;
117
Vadim Bendebury245d4572016-04-05 16:01:57 -0700118 return TPM_SUCCESS;
119}
120
121uint32_t tlcl_finalize_physical_presence(void)
122{
123 /* Nothing needs to be done with tpm2. */
124 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
125 return TPM_SUCCESS;
126}
127
128uint32_t tlcl_force_clear(void)
129{
Vadim Bendeburyadfbbde2016-07-03 15:56:41 -0700130 struct tpm2_response *response;
131
132 response = tpm_process_command(TPM2_Clear, NULL);
133 printk(BIOS_INFO, "%s: response is %x\n",
134 __func__, response ? response->hdr.tpm_code : -1);
135
136 if (!response || response->hdr.tpm_code)
137 return TPM_E_IOERROR;
138
Vadim Bendebury245d4572016-04-05 16:01:57 -0700139 return TPM_SUCCESS;
140}
141
142uint32_t tlcl_get_flags(uint8_t *disable, uint8_t *deactivated,
143 uint8_t *nvlocked)
144{
145 /*
146 * TPM2 does not map directly into these flags TPM1.2 based firmware
147 * expects to be able to retrieve.
148 *
149 * In any case, if any of these conditions are present, the following
150 * firmware flow would be interrupted and will have a chance to report
151 * an error. Let's just hardcode an "All OK" response for now.
152 */
153
154 if (disable)
155 *disable = 0;
156
157 if (nvlocked)
158 *nvlocked = 1;
159
160 if (deactivated)
161 *deactivated = 0;
162
163 return TPM_SUCCESS;
164}
165
Furquan Shaikh8b5d04e2016-11-10 09:49:05 -0800166static uint8_t tlcl_init_done CAR_GLOBAL;
167
168/* This function is called directly by vboot, uses vboot return types. */
Vadim Bendebury245d4572016-04-05 16:01:57 -0700169uint32_t tlcl_lib_init(void)
170{
Furquan Shaikh8b5d04e2016-11-10 09:49:05 -0800171 uint8_t done = car_get_var(tlcl_init_done);
172 if (done)
173 return VB2_SUCCESS;
174
Vadim Bendebury245d4572016-04-05 16:01:57 -0700175 if (tis_init())
176 return VB2_ERROR_UNKNOWN;
177 if (tis_open())
178 return VB2_ERROR_UNKNOWN;
Furquan Shaikh8b5d04e2016-11-10 09:49:05 -0800179
180 car_set_var(tlcl_init_done, 1);
181
Vadim Bendebury245d4572016-04-05 16:01:57 -0700182 return VB2_SUCCESS;
183}
184
185uint32_t tlcl_physical_presence_cmd_enable(void)
186{
187 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
188 return TPM_SUCCESS;
189}
190
191uint32_t tlcl_read(uint32_t index, void *data, uint32_t length)
192{
193 struct tpm2_nv_read_cmd nv_readc;
194 struct tpm2_response *response;
195
196 memset(&nv_readc, 0, sizeof(nv_readc));
197
198 nv_readc.nvIndex = HR_NV_INDEX + index;
199 nv_readc.size = length;
200
201 response = tpm_process_command(TPM2_NV_Read, &nv_readc);
202
203 /* Need to map tpm error codes into internal values. */
204 if (!response)
205 return TPM_E_READ_FAILURE;
206
207 printk(BIOS_INFO, "%s:%d index %#x return code %x\n",
208 __FILE__, __LINE__, index, response->hdr.tpm_code);
209 switch (response->hdr.tpm_code) {
210 case 0:
211 break;
212
213 case 0x28b:
214 return TPM_E_BADINDEX;
215
216 default:
217 return TPM_E_READ_FAILURE;
218 }
219
220 if (length > response->nvr.buffer.t.size)
221 return TPM_E_RESPONSE_TOO_LARGE;
222
223 if (length < response->nvr.buffer.t.size)
224 return TPM_E_READ_EMPTY;
225
226 memcpy(data, response->nvr.buffer.t.buffer, length);
227
228 return TPM_SUCCESS;
229}
230
231uint32_t tlcl_self_test_full(void)
232{
233 struct tpm2_self_test st;
234 struct tpm2_response *response;
235
236 st.yes_no = 1;
237
238 response = tpm_process_command(TPM2_SelfTest, &st);
239 printk(BIOS_INFO, "%s: response is %x\n",
240 __func__, response ? response->hdr.tpm_code : -1);
241 return TPM_SUCCESS;
242}
243
244uint32_t tlcl_set_deactivated(uint8_t flag)
245{
246 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
247 return TPM_SUCCESS;
248}
249
250uint32_t tlcl_set_enable(void)
251{
252 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
253 return TPM_SUCCESS;
254}
255
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700256uint32_t tlcl_lock_nv_write(uint32_t index)
Vadim Bendebury245d4572016-04-05 16:01:57 -0700257{
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700258 struct tpm2_response *response;
259 /* TPM Wll reject attempts to write at non-defined index. */
260 struct tpm2_nv_write_lock_cmd nv_wl = {
261 .nvIndex = HR_NV_INDEX + index,
262 };
263
264 response = tpm_process_command(TPM2_NV_WriteLock, &nv_wl);
265
266 printk(BIOS_INFO, "%s: response is %x\n",
267 __func__, response ? response->hdr.tpm_code : -1);
268
269 if (!response || response->hdr.tpm_code)
270 return TPM_E_IOERROR;
271
Vadim Bendebury245d4572016-04-05 16:01:57 -0700272 return TPM_SUCCESS;
273}
274
275uint32_t tlcl_startup(void)
276{
Furquan Shaikhcc3365a2016-09-30 12:53:19 -0700277 return tlcl_send_startup(TPM_SU_CLEAR);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700278}
279
280uint32_t tlcl_write(uint32_t index, const void *data, uint32_t length)
281{
282 struct tpm2_nv_write_cmd nv_writec;
283 struct tpm2_response *response;
284
285 memset(&nv_writec, 0, sizeof(nv_writec));
286
287 nv_writec.nvIndex = HR_NV_INDEX + index;
288 nv_writec.data.t.size = length;
289 nv_writec.data.t.buffer = data;
290
291 response = tpm_process_command(TPM2_NV_Write, &nv_writec);
292
Vadim Bendebury1ec76032016-07-05 22:30:16 -0700293 printk(BIOS_INFO, "%s: response is %x\n",
294 __func__, response ? response->hdr.tpm_code : -1);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700295
Vadim Bendebury1ec76032016-07-05 22:30:16 -0700296 /* Need to map tpm error codes into internal values. */
297 if (!response || response->hdr.tpm_code)
298 return TPM_E_WRITE_FAILURE;
Vadim Bendebury245d4572016-04-05 16:01:57 -0700299
300 return TPM_SUCCESS;
301}
302
Vadim Bendebury7ee057c2016-07-03 15:24:23 -0700303uint32_t tlcl_define_space(uint32_t space_index, size_t space_size)
Vadim Bendebury245d4572016-04-05 16:01:57 -0700304{
305 struct tpm2_nv_define_space_cmd nvds_cmd;
306 struct tpm2_response *response;
Vadim Bendebury7ee057c2016-07-03 15:24:23 -0700307 /*
Vadim Bendebury289ee8f2016-11-11 09:36:50 -0800308 * Different sets of NVRAM space attributes apply to the "ro" spaces,
309 * i.e. those which should not be possible to delete or modify once
310 * the RO exits, and the rest of the NVRAM spaces.
Vadim Bendebury7ee057c2016-07-03 15:24:23 -0700311 */
Vadim Bendebury289ee8f2016-11-11 09:36:50 -0800312 const TPMA_NV ro_space_attributes = {
313 .TPMA_NV_PPWRITE = 1,
314 .TPMA_NV_AUTHREAD = 1,
315 .TPMA_NV_PPREAD = 1,
316 .TPMA_NV_PLATFORMCREATE = 1,
317 .TPMA_NV_WRITE_STCLEAR = 1,
318 .TPMA_NV_POLICY_DELETE = 1,
319 };
320 const TPMA_NV default_space_attributes = {
321 .TPMA_NV_PPWRITE = 1,
322 .TPMA_NV_AUTHREAD = 1,
323 .TPMA_NV_PPREAD = 1,
324 .TPMA_NV_PLATFORMCREATE = 1,
Vadim Bendebury7ee057c2016-07-03 15:24:23 -0700325 };
Vadim Bendebury245d4572016-04-05 16:01:57 -0700326
327 /* Prepare the define space command structure. */
328 memset(&nvds_cmd, 0, sizeof(nvds_cmd));
329
330 nvds_cmd.publicInfo.dataSize = space_size;
331 nvds_cmd.publicInfo.nvIndex = HR_NV_INDEX + space_index;
332 nvds_cmd.publicInfo.nameAlg = TPM_ALG_SHA256;
333
Vadim Bendebury289ee8f2016-11-11 09:36:50 -0800334 /* RO only NV spaces should be impossible to destroy. */
335 if ((space_index == FIRMWARE_NV_INDEX) ||
336 (space_index == REC_HASH_NV_INDEX)) {
337 /*
338 * This policy digest was obtained using TPM2_PolicyPCR
339 * selecting only PCR_0 with a value of all zeros.
340 */
341 const uint8_t pcr0_unchanged_policy[] = {
342 0x09, 0x93, 0x3C, 0xCE, 0xEB, 0xB4, 0x41, 0x11,
343 0x18, 0x81, 0x1D, 0xD4, 0x47, 0x78, 0x80, 0x08,
344 0x88, 0x86, 0x62, 0x2D, 0xD7, 0x79, 0x94, 0x46,
345 0x62, 0x26, 0x68, 0x8E, 0xEE, 0xE6, 0x6A, 0xA1
346 };
Vadim Bendebury245d4572016-04-05 16:01:57 -0700347
Vadim Bendebury289ee8f2016-11-11 09:36:50 -0800348 nvds_cmd.publicInfo.attributes = ro_space_attributes;
349 /*
350 * Use policy digest based on default pcr0 value. This makes
351 * sure that the space can not be deleted as soon as PCR0
352 * value has been extended from default.
353 */
354 nvds_cmd.publicInfo.authPolicy.t.buffer = pcr0_unchanged_policy;
Lee Leahy73402172017-03-10 15:23:24 -0800355 nvds_cmd.publicInfo.authPolicy.t.size =
356 sizeof(pcr0_unchanged_policy);
Vadim Bendebury289ee8f2016-11-11 09:36:50 -0800357 } else {
358 nvds_cmd.publicInfo.attributes = default_space_attributes;
359 }
Vadim Bendebury245d4572016-04-05 16:01:57 -0700360
361 response = tpm_process_command(TPM2_NV_DefineSpace, &nvds_cmd);
362 printk(BIOS_INFO, "%s: response is %x\n",
363 __func__, response ? response->hdr.tpm_code : -1);
364
365 if (!response)
366 return TPM_E_NO_DEVICE;
367
Vadim Bendeburyaf8ae932016-11-11 14:15:31 -0800368 /* Map TPM2 retrun codes into common vboot represenation. */
Lee Leahy45fde702017-03-08 18:02:24 -0800369 switch (response->hdr.tpm_code) {
Vadim Bendeburyaf8ae932016-11-11 14:15:31 -0800370 case TPM2_RC_SUCCESS:
371 return TPM_SUCCESS;
372 case TPM2_RC_NV_DEFINED:
373 return TPM_E_NV_DEFINED;
374 default:
375 return TPM_E_INTERNAL_INCONSISTENCY;
376 }
Vadim Bendebury245d4572016-04-05 16:01:57 -0700377}
Aaron Durbinf56c7782017-01-10 17:44:42 -0600378
379uint32_t tlcl_disable_platform_hierarchy(void)
380{
381 struct tpm2_response *response;
382 struct tpm2_hierarchy_control_cmd hc = {
383 .enable = TPM_RH_PLATFORM,
384 .state = 0,
385 };
386
387 response = tpm_process_command(TPM2_Hierarchy_Control, &hc);
388
389 if (!response || response->hdr.tpm_code)
390 return TPM_E_INTERNAL_INCONSISTENCY;
391
392 return TPM_SUCCESS;
393}
Aaron Durbineeb77372017-03-08 11:23:11 -0600394
395uint32_t tlcl_cr50_enable_nvcommits(void)
396{
397 uint16_t sub_command = TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS;
398 struct tpm2_response *response;
399
400 printk(BIOS_INFO, "Enabling cr50 nvmem commmits\n");
401
402 response = tpm_process_command(TPM2_CR50_VENDOR_COMMAND, &sub_command);
403
404 if (response == NULL || (response && response->hdr.tpm_code)) {
405 if (response)
406 printk(BIOS_INFO, "%s: failed %x\n", __func__,
407 response->hdr.tpm_code);
408 else
409 printk(BIOS_INFO, "%s: failed\n", __func__);
410 return TPM_E_IOERROR;
411 }
412 return TPM_SUCCESS;
413}
Vadim Bendebury021ec282017-03-22 16:01:53 -0700414
415uint32_t tlcl_cr50_enable_update(uint16_t timeout_ms,
416 uint8_t *num_restored_headers)
417{
418 struct tpm2_response *response;
419 uint16_t command_body[] = {
420 TPM2_CR50_SUB_CMD_TURN_UPDATE_ON, timeout_ms
421 };
422
423 printk(BIOS_INFO, "Checking cr50 for pending updates\n");
424
425 response = tpm_process_command(TPM2_CR50_VENDOR_COMMAND, command_body);
426
427 if (!response || response->hdr.tpm_code)
428 return TPM_E_INTERNAL_INCONSISTENCY;
429
430 *num_restored_headers = response->vcr.num_restored_headers;
431 return TPM_SUCCESS;
432}