blob: 7db746f4e18ede640e4494258ca6ca7180271537 [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>
Philipp Deppenwiese86391f12017-10-18 21:54:24 +020012#include <security/tpm/tis.h>
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +010013#include <security/tpm/tss.h>
Vadim Bendebury245d4572016-04-05 16:01:57 -070014
Philipp Deppenwiesed88fb362017-10-18 20:26:18 +020015#include "tss_structures.h"
16#include "tss_marshaling.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
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +010024void *tpm_process_command(TPM_CC command, void *command_body)
Vadim Bendebury245d4572016-04-05 16:01:57 -070025{
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
Furquan Shaikhcc3365a2016-09-30 12:53:19 -070056static uint32_t tlcl_send_startup(TPM_SU type)
57{
58 struct tpm2_startup startup;
59 struct tpm2_response *response;
60
61 startup.startup_type = type;
62 response = tpm_process_command(TPM2_Startup, &startup);
63
64 if (response && response->hdr.tpm_code &&
65 (response->hdr.tpm_code != TPM_RC_INITIALIZE)) {
66 printk(BIOS_INFO, "%s: Startup return code is %x\n",
67 __func__, response->hdr.tpm_code);
68 return TPM_E_IOERROR;
69 }
70 return TPM_SUCCESS;
71
72}
73
Vadim Bendebury245d4572016-04-05 16:01:57 -070074uint32_t tlcl_resume(void)
75{
Furquan Shaikhcc3365a2016-09-30 12:53:19 -070076 return tlcl_send_startup(TPM_SU_STATE);
Vadim Bendebury245d4572016-04-05 16:01:57 -070077}
78
79uint32_t tlcl_assert_physical_presence(void)
80{
81 /*
82 * Nothing to do on TPM2 for this, use platform hierarchy availability
83 * instead.
84 */
85 return TPM_SUCCESS;
86}
87
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -070088/*
89 * The caller will provide the digest in a 32 byte buffer, let's consider it a
90 * sha256 digest.
91 */
Vadim Bendebury245d4572016-04-05 16:01:57 -070092uint32_t tlcl_extend(int pcr_num, const uint8_t *in_digest,
93 uint8_t *out_digest)
94{
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -070095 struct tpm2_pcr_extend_cmd pcr_ext_cmd;
96 struct tpm2_response *response;
97
98 pcr_ext_cmd.pcrHandle = HR_PCR + pcr_num;
99 pcr_ext_cmd.digests.count = 1;
100 pcr_ext_cmd.digests.digests[0].hashAlg = TPM_ALG_SHA256;
101 memcpy(pcr_ext_cmd.digests.digests[0].digest.sha256, in_digest,
102 sizeof(pcr_ext_cmd.digests.digests[0].digest.sha256));
103
104 response = tpm_process_command(TPM2_PCR_Extend, &pcr_ext_cmd);
105
106 printk(BIOS_INFO, "%s: response is %x\n",
107 __func__, response ? response->hdr.tpm_code : -1);
108 if (!response || response->hdr.tpm_code)
109 return TPM_E_IOERROR;
110
Vadim Bendebury245d4572016-04-05 16:01:57 -0700111 return TPM_SUCCESS;
112}
113
114uint32_t tlcl_finalize_physical_presence(void)
115{
116 /* Nothing needs to be done with tpm2. */
117 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
118 return TPM_SUCCESS;
119}
120
121uint32_t tlcl_force_clear(void)
122{
Vadim Bendeburyadfbbde2016-07-03 15:56:41 -0700123 struct tpm2_response *response;
124
125 response = tpm_process_command(TPM2_Clear, NULL);
126 printk(BIOS_INFO, "%s: response is %x\n",
127 __func__, response ? response->hdr.tpm_code : -1);
128
129 if (!response || response->hdr.tpm_code)
130 return TPM_E_IOERROR;
131
Vadim Bendebury245d4572016-04-05 16:01:57 -0700132 return TPM_SUCCESS;
133}
134
Furquan Shaikh8b5d04e2016-11-10 09:49:05 -0800135static uint8_t tlcl_init_done CAR_GLOBAL;
136
137/* This function is called directly by vboot, uses vboot return types. */
Vadim Bendebury245d4572016-04-05 16:01:57 -0700138uint32_t tlcl_lib_init(void)
139{
Furquan Shaikh8b5d04e2016-11-10 09:49:05 -0800140 uint8_t done = car_get_var(tlcl_init_done);
141 if (done)
142 return VB2_SUCCESS;
143
Vadim Bendebury245d4572016-04-05 16:01:57 -0700144 if (tis_init())
145 return VB2_ERROR_UNKNOWN;
146 if (tis_open())
147 return VB2_ERROR_UNKNOWN;
Furquan Shaikh8b5d04e2016-11-10 09:49:05 -0800148
149 car_set_var(tlcl_init_done, 1);
150
Vadim Bendebury245d4572016-04-05 16:01:57 -0700151 return VB2_SUCCESS;
152}
153
154uint32_t tlcl_physical_presence_cmd_enable(void)
155{
156 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
157 return TPM_SUCCESS;
158}
159
160uint32_t tlcl_read(uint32_t index, void *data, uint32_t length)
161{
162 struct tpm2_nv_read_cmd nv_readc;
163 struct tpm2_response *response;
164
165 memset(&nv_readc, 0, sizeof(nv_readc));
166
167 nv_readc.nvIndex = HR_NV_INDEX + index;
168 nv_readc.size = length;
169
170 response = tpm_process_command(TPM2_NV_Read, &nv_readc);
171
172 /* Need to map tpm error codes into internal values. */
173 if (!response)
174 return TPM_E_READ_FAILURE;
175
176 printk(BIOS_INFO, "%s:%d index %#x return code %x\n",
177 __FILE__, __LINE__, index, response->hdr.tpm_code);
178 switch (response->hdr.tpm_code) {
179 case 0:
180 break;
181
Vadim Bendebury08f93592017-06-21 12:23:22 -0700182 /* Uninitialized, returned if the space hasn't been written. */
183 case TPM_RC_NV_UNINITIALIZED:
184 /*
185 * Bad index, cr50 specific value, returned if the space
186 * hasn't been defined.
187 */
188 case TPM_RC_CR50_NV_UNDEFINED:
Vadim Bendebury245d4572016-04-05 16:01:57 -0700189 return TPM_E_BADINDEX;
190
191 default:
192 return TPM_E_READ_FAILURE;
193 }
194
195 if (length > response->nvr.buffer.t.size)
196 return TPM_E_RESPONSE_TOO_LARGE;
197
198 if (length < response->nvr.buffer.t.size)
199 return TPM_E_READ_EMPTY;
200
201 memcpy(data, response->nvr.buffer.t.buffer, length);
202
203 return TPM_SUCCESS;
204}
205
206uint32_t tlcl_self_test_full(void)
207{
208 struct tpm2_self_test st;
209 struct tpm2_response *response;
210
211 st.yes_no = 1;
212
213 response = tpm_process_command(TPM2_SelfTest, &st);
214 printk(BIOS_INFO, "%s: response is %x\n",
215 __func__, response ? response->hdr.tpm_code : -1);
216 return TPM_SUCCESS;
217}
218
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700219uint32_t tlcl_lock_nv_write(uint32_t index)
Vadim Bendebury245d4572016-04-05 16:01:57 -0700220{
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700221 struct tpm2_response *response;
222 /* TPM Wll reject attempts to write at non-defined index. */
223 struct tpm2_nv_write_lock_cmd nv_wl = {
224 .nvIndex = HR_NV_INDEX + index,
225 };
226
227 response = tpm_process_command(TPM2_NV_WriteLock, &nv_wl);
228
229 printk(BIOS_INFO, "%s: response is %x\n",
230 __func__, response ? response->hdr.tpm_code : -1);
231
232 if (!response || response->hdr.tpm_code)
233 return TPM_E_IOERROR;
234
Vadim Bendebury245d4572016-04-05 16:01:57 -0700235 return TPM_SUCCESS;
236}
237
238uint32_t tlcl_startup(void)
239{
Furquan Shaikhcc3365a2016-09-30 12:53:19 -0700240 return tlcl_send_startup(TPM_SU_CLEAR);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700241}
242
243uint32_t tlcl_write(uint32_t index, const void *data, uint32_t length)
244{
245 struct tpm2_nv_write_cmd nv_writec;
246 struct tpm2_response *response;
247
248 memset(&nv_writec, 0, sizeof(nv_writec));
249
250 nv_writec.nvIndex = HR_NV_INDEX + index;
251 nv_writec.data.t.size = length;
252 nv_writec.data.t.buffer = data;
253
254 response = tpm_process_command(TPM2_NV_Write, &nv_writec);
255
Vadim Bendebury1ec76032016-07-05 22:30:16 -0700256 printk(BIOS_INFO, "%s: response is %x\n",
257 __func__, response ? response->hdr.tpm_code : -1);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700258
Vadim Bendebury1ec76032016-07-05 22:30:16 -0700259 /* Need to map tpm error codes into internal values. */
260 if (!response || response->hdr.tpm_code)
261 return TPM_E_WRITE_FAILURE;
Vadim Bendebury245d4572016-04-05 16:01:57 -0700262
263 return TPM_SUCCESS;
264}
265
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100266uint32_t tlcl_define_space(uint32_t space_index, size_t space_size,
267 const TPMA_NV nv_attributes,
268 const uint8_t *nv_policy, size_t nv_policy_size)
Vadim Bendebury245d4572016-04-05 16:01:57 -0700269{
270 struct tpm2_nv_define_space_cmd nvds_cmd;
271 struct tpm2_response *response;
272
273 /* Prepare the define space command structure. */
274 memset(&nvds_cmd, 0, sizeof(nvds_cmd));
275
276 nvds_cmd.publicInfo.dataSize = space_size;
277 nvds_cmd.publicInfo.nvIndex = HR_NV_INDEX + space_index;
278 nvds_cmd.publicInfo.nameAlg = TPM_ALG_SHA256;
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100279 nvds_cmd.publicInfo.attributes = nv_attributes;
Vadim Bendebury245d4572016-04-05 16:01:57 -0700280
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100281 /*
282 * Use policy digest based on default pcr0 value. This makes
283 * sure that the space can not be deleted as soon as PCR0
284 * value has been extended from default.
285 */
286 if (nv_policy && nv_policy_size) {
287 nvds_cmd.publicInfo.authPolicy.t.buffer = nv_policy;
288 nvds_cmd.publicInfo.authPolicy.t.size = nv_policy_size;
Vadim Bendebury289ee8f2016-11-11 09:36:50 -0800289 }
Vadim Bendebury245d4572016-04-05 16:01:57 -0700290
291 response = tpm_process_command(TPM2_NV_DefineSpace, &nvds_cmd);
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100292 printk(BIOS_INFO, "%s: response is %x\n", __func__,
293 response ? response->hdr.tpm_code : -1);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700294
295 if (!response)
296 return TPM_E_NO_DEVICE;
297
Vadim Bendeburyaf8ae932016-11-11 14:15:31 -0800298 /* Map TPM2 retrun codes into common vboot represenation. */
Lee Leahy45fde702017-03-08 18:02:24 -0800299 switch (response->hdr.tpm_code) {
Vadim Bendeburyaf8ae932016-11-11 14:15:31 -0800300 case TPM2_RC_SUCCESS:
301 return TPM_SUCCESS;
302 case TPM2_RC_NV_DEFINED:
303 return TPM_E_NV_DEFINED;
304 default:
305 return TPM_E_INTERNAL_INCONSISTENCY;
306 }
Vadim Bendebury245d4572016-04-05 16:01:57 -0700307}
Aaron Durbinf56c7782017-01-10 17:44:42 -0600308
309uint32_t tlcl_disable_platform_hierarchy(void)
310{
311 struct tpm2_response *response;
312 struct tpm2_hierarchy_control_cmd hc = {
313 .enable = TPM_RH_PLATFORM,
314 .state = 0,
315 };
316
317 response = tpm_process_command(TPM2_Hierarchy_Control, &hc);
318
319 if (!response || response->hdr.tpm_code)
320 return TPM_E_INTERNAL_INCONSISTENCY;
321
322 return TPM_SUCCESS;
323}