blob: ae8625c0b28add345a6fd2e9b2aad9ff2428e3b8 [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>
Vadim Bendebury245d4572016-04-05 16:01:57 -070010#include <string.h>
Vadim Bendebury245d4572016-04-05 16:01:57 -070011#include <vb2_api.h>
12
Philipp Deppenwiesed88fb362017-10-18 20:26:18 +020013#include "tss_structures.h"
14#include "tss_marshaling.h"
15#include "../tis.h"
Philipp Deppenwiese64e2d192017-10-18 17:13:07 +020016#include "../antirollback.h"
Vadim Bendebury245d4572016-04-05 16:01:57 -070017
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
Vadim Bendebury08f93592017-06-21 12:23:22 -0700213 /* Uninitialized, returned if the space hasn't been written. */
214 case TPM_RC_NV_UNINITIALIZED:
215 /*
216 * Bad index, cr50 specific value, returned if the space
217 * hasn't been defined.
218 */
219 case TPM_RC_CR50_NV_UNDEFINED:
Vadim Bendebury245d4572016-04-05 16:01:57 -0700220 return TPM_E_BADINDEX;
221
222 default:
223 return TPM_E_READ_FAILURE;
224 }
225
226 if (length > response->nvr.buffer.t.size)
227 return TPM_E_RESPONSE_TOO_LARGE;
228
229 if (length < response->nvr.buffer.t.size)
230 return TPM_E_READ_EMPTY;
231
232 memcpy(data, response->nvr.buffer.t.buffer, length);
233
234 return TPM_SUCCESS;
235}
236
237uint32_t tlcl_self_test_full(void)
238{
239 struct tpm2_self_test st;
240 struct tpm2_response *response;
241
242 st.yes_no = 1;
243
244 response = tpm_process_command(TPM2_SelfTest, &st);
245 printk(BIOS_INFO, "%s: response is %x\n",
246 __func__, response ? response->hdr.tpm_code : -1);
247 return TPM_SUCCESS;
248}
249
250uint32_t tlcl_set_deactivated(uint8_t flag)
251{
252 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
253 return TPM_SUCCESS;
254}
255
256uint32_t tlcl_set_enable(void)
257{
258 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
259 return TPM_SUCCESS;
260}
261
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700262uint32_t tlcl_lock_nv_write(uint32_t index)
Vadim Bendebury245d4572016-04-05 16:01:57 -0700263{
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700264 struct tpm2_response *response;
265 /* TPM Wll reject attempts to write at non-defined index. */
266 struct tpm2_nv_write_lock_cmd nv_wl = {
267 .nvIndex = HR_NV_INDEX + index,
268 };
269
270 response = tpm_process_command(TPM2_NV_WriteLock, &nv_wl);
271
272 printk(BIOS_INFO, "%s: response is %x\n",
273 __func__, response ? response->hdr.tpm_code : -1);
274
275 if (!response || response->hdr.tpm_code)
276 return TPM_E_IOERROR;
277
Vadim Bendebury245d4572016-04-05 16:01:57 -0700278 return TPM_SUCCESS;
279}
280
281uint32_t tlcl_startup(void)
282{
Furquan Shaikhcc3365a2016-09-30 12:53:19 -0700283 return tlcl_send_startup(TPM_SU_CLEAR);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700284}
285
286uint32_t tlcl_write(uint32_t index, const void *data, uint32_t length)
287{
288 struct tpm2_nv_write_cmd nv_writec;
289 struct tpm2_response *response;
290
291 memset(&nv_writec, 0, sizeof(nv_writec));
292
293 nv_writec.nvIndex = HR_NV_INDEX + index;
294 nv_writec.data.t.size = length;
295 nv_writec.data.t.buffer = data;
296
297 response = tpm_process_command(TPM2_NV_Write, &nv_writec);
298
Vadim Bendebury1ec76032016-07-05 22:30:16 -0700299 printk(BIOS_INFO, "%s: response is %x\n",
300 __func__, response ? response->hdr.tpm_code : -1);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700301
Vadim Bendebury1ec76032016-07-05 22:30:16 -0700302 /* Need to map tpm error codes into internal values. */
303 if (!response || response->hdr.tpm_code)
304 return TPM_E_WRITE_FAILURE;
Vadim Bendebury245d4572016-04-05 16:01:57 -0700305
306 return TPM_SUCCESS;
307}
308
Vadim Bendebury7ee057c2016-07-03 15:24:23 -0700309uint32_t tlcl_define_space(uint32_t space_index, size_t space_size)
Vadim Bendebury245d4572016-04-05 16:01:57 -0700310{
311 struct tpm2_nv_define_space_cmd nvds_cmd;
312 struct tpm2_response *response;
Vadim Bendebury7ee057c2016-07-03 15:24:23 -0700313 /*
Vadim Bendebury289ee8f2016-11-11 09:36:50 -0800314 * Different sets of NVRAM space attributes apply to the "ro" spaces,
315 * i.e. those which should not be possible to delete or modify once
316 * the RO exits, and the rest of the NVRAM spaces.
Vadim Bendebury7ee057c2016-07-03 15:24:23 -0700317 */
Vadim Bendebury289ee8f2016-11-11 09:36:50 -0800318 const TPMA_NV ro_space_attributes = {
319 .TPMA_NV_PPWRITE = 1,
320 .TPMA_NV_AUTHREAD = 1,
321 .TPMA_NV_PPREAD = 1,
322 .TPMA_NV_PLATFORMCREATE = 1,
323 .TPMA_NV_WRITE_STCLEAR = 1,
324 .TPMA_NV_POLICY_DELETE = 1,
325 };
326 const TPMA_NV default_space_attributes = {
327 .TPMA_NV_PPWRITE = 1,
328 .TPMA_NV_AUTHREAD = 1,
329 .TPMA_NV_PPREAD = 1,
330 .TPMA_NV_PLATFORMCREATE = 1,
Vadim Bendebury7ee057c2016-07-03 15:24:23 -0700331 };
Vadim Bendebury245d4572016-04-05 16:01:57 -0700332
333 /* Prepare the define space command structure. */
334 memset(&nvds_cmd, 0, sizeof(nvds_cmd));
335
336 nvds_cmd.publicInfo.dataSize = space_size;
337 nvds_cmd.publicInfo.nvIndex = HR_NV_INDEX + space_index;
338 nvds_cmd.publicInfo.nameAlg = TPM_ALG_SHA256;
339
Vadim Bendebury289ee8f2016-11-11 09:36:50 -0800340 /* RO only NV spaces should be impossible to destroy. */
341 if ((space_index == FIRMWARE_NV_INDEX) ||
342 (space_index == REC_HASH_NV_INDEX)) {
343 /*
344 * This policy digest was obtained using TPM2_PolicyPCR
345 * selecting only PCR_0 with a value of all zeros.
346 */
347 const uint8_t pcr0_unchanged_policy[] = {
348 0x09, 0x93, 0x3C, 0xCE, 0xEB, 0xB4, 0x41, 0x11,
349 0x18, 0x81, 0x1D, 0xD4, 0x47, 0x78, 0x80, 0x08,
350 0x88, 0x86, 0x62, 0x2D, 0xD7, 0x79, 0x94, 0x46,
351 0x62, 0x26, 0x68, 0x8E, 0xEE, 0xE6, 0x6A, 0xA1
352 };
Vadim Bendebury245d4572016-04-05 16:01:57 -0700353
Vadim Bendebury289ee8f2016-11-11 09:36:50 -0800354 nvds_cmd.publicInfo.attributes = ro_space_attributes;
355 /*
356 * Use policy digest based on default pcr0 value. This makes
357 * sure that the space can not be deleted as soon as PCR0
358 * value has been extended from default.
359 */
360 nvds_cmd.publicInfo.authPolicy.t.buffer = pcr0_unchanged_policy;
Lee Leahy73402172017-03-10 15:23:24 -0800361 nvds_cmd.publicInfo.authPolicy.t.size =
362 sizeof(pcr0_unchanged_policy);
Vadim Bendebury289ee8f2016-11-11 09:36:50 -0800363 } else {
364 nvds_cmd.publicInfo.attributes = default_space_attributes;
365 }
Vadim Bendebury245d4572016-04-05 16:01:57 -0700366
367 response = tpm_process_command(TPM2_NV_DefineSpace, &nvds_cmd);
368 printk(BIOS_INFO, "%s: response is %x\n",
369 __func__, response ? response->hdr.tpm_code : -1);
370
371 if (!response)
372 return TPM_E_NO_DEVICE;
373
Vadim Bendeburyaf8ae932016-11-11 14:15:31 -0800374 /* Map TPM2 retrun codes into common vboot represenation. */
Lee Leahy45fde702017-03-08 18:02:24 -0800375 switch (response->hdr.tpm_code) {
Vadim Bendeburyaf8ae932016-11-11 14:15:31 -0800376 case TPM2_RC_SUCCESS:
377 return TPM_SUCCESS;
378 case TPM2_RC_NV_DEFINED:
379 return TPM_E_NV_DEFINED;
380 default:
381 return TPM_E_INTERNAL_INCONSISTENCY;
382 }
Vadim Bendebury245d4572016-04-05 16:01:57 -0700383}
Aaron Durbinf56c7782017-01-10 17:44:42 -0600384
385uint32_t tlcl_disable_platform_hierarchy(void)
386{
387 struct tpm2_response *response;
388 struct tpm2_hierarchy_control_cmd hc = {
389 .enable = TPM_RH_PLATFORM,
390 .state = 0,
391 };
392
393 response = tpm_process_command(TPM2_Hierarchy_Control, &hc);
394
395 if (!response || response->hdr.tpm_code)
396 return TPM_E_INTERNAL_INCONSISTENCY;
397
398 return TPM_SUCCESS;
399}
Aaron Durbineeb77372017-03-08 11:23:11 -0600400
401uint32_t tlcl_cr50_enable_nvcommits(void)
402{
403 uint16_t sub_command = TPM2_CR50_SUB_CMD_NVMEM_ENABLE_COMMITS;
404 struct tpm2_response *response;
405
406 printk(BIOS_INFO, "Enabling cr50 nvmem commmits\n");
407
408 response = tpm_process_command(TPM2_CR50_VENDOR_COMMAND, &sub_command);
409
410 if (response == NULL || (response && response->hdr.tpm_code)) {
411 if (response)
412 printk(BIOS_INFO, "%s: failed %x\n", __func__,
413 response->hdr.tpm_code);
414 else
415 printk(BIOS_INFO, "%s: failed\n", __func__);
416 return TPM_E_IOERROR;
417 }
418 return TPM_SUCCESS;
419}
Vadim Bendebury021ec282017-03-22 16:01:53 -0700420
421uint32_t tlcl_cr50_enable_update(uint16_t timeout_ms,
422 uint8_t *num_restored_headers)
423{
424 struct tpm2_response *response;
425 uint16_t command_body[] = {
426 TPM2_CR50_SUB_CMD_TURN_UPDATE_ON, timeout_ms
427 };
428
429 printk(BIOS_INFO, "Checking cr50 for pending updates\n");
430
431 response = tpm_process_command(TPM2_CR50_VENDOR_COMMAND, command_body);
432
433 if (!response || response->hdr.tpm_code)
434 return TPM_E_INTERNAL_INCONSISTENCY;
435
436 *num_restored_headers = response->vcr.num_restored_headers;
437 return TPM_SUCCESS;
438}