blob: c67fdfaa4935247c517bf1a508867b09ff819e01 [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
Joel Kitchingc5d0a2e2018-10-12 15:52:00 +080064 /* IO error, tpm2_response pointer is empty. */
65 if (response == NULL) {
66 printk(BIOS_ERR, "%s: TPM communication error\n", __func__);
67 return TPM_E_IOERROR;
Furquan Shaikhcc3365a2016-09-30 12:53:19 -070068 }
Joel Kitchingc5d0a2e2018-10-12 15:52:00 +080069
Joel Kitchingf97ff0c2018-09-26 17:52:54 +080070 printk(BIOS_INFO, "%s: Startup return code is %x\n",
71 __func__, response->hdr.tpm_code);
Joel Kitchingc5d0a2e2018-10-12 15:52:00 +080072
73 switch (response->hdr.tpm_code) {
74 case TPM_RC_INITIALIZE:
75 /* TPM already initialized. */
76 return TPM_E_INVALID_POSTINIT;
77 case TPM2_RC_SUCCESS:
78 return TPM_SUCCESS;
79 }
80
81 /* Collapse any other errors into TPM_E_IOERROR. */
Joel Kitchingf97ff0c2018-09-26 17:52:54 +080082 return TPM_E_IOERROR;
Furquan Shaikhcc3365a2016-09-30 12:53:19 -070083}
84
Vadim Bendebury245d4572016-04-05 16:01:57 -070085uint32_t tlcl_resume(void)
86{
Furquan Shaikhcc3365a2016-09-30 12:53:19 -070087 return tlcl_send_startup(TPM_SU_STATE);
Vadim Bendebury245d4572016-04-05 16:01:57 -070088}
89
90uint32_t tlcl_assert_physical_presence(void)
91{
92 /*
93 * Nothing to do on TPM2 for this, use platform hierarchy availability
94 * instead.
95 */
96 return TPM_SUCCESS;
97}
98
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -070099/*
100 * The caller will provide the digest in a 32 byte buffer, let's consider it a
101 * sha256 digest.
102 */
Vadim Bendebury245d4572016-04-05 16:01:57 -0700103uint32_t tlcl_extend(int pcr_num, const uint8_t *in_digest,
104 uint8_t *out_digest)
105{
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700106 struct tpm2_pcr_extend_cmd pcr_ext_cmd;
107 struct tpm2_response *response;
108
109 pcr_ext_cmd.pcrHandle = HR_PCR + pcr_num;
110 pcr_ext_cmd.digests.count = 1;
111 pcr_ext_cmd.digests.digests[0].hashAlg = TPM_ALG_SHA256;
112 memcpy(pcr_ext_cmd.digests.digests[0].digest.sha256, in_digest,
113 sizeof(pcr_ext_cmd.digests.digests[0].digest.sha256));
114
115 response = tpm_process_command(TPM2_PCR_Extend, &pcr_ext_cmd);
116
117 printk(BIOS_INFO, "%s: response is %x\n",
118 __func__, response ? response->hdr.tpm_code : -1);
119 if (!response || response->hdr.tpm_code)
120 return TPM_E_IOERROR;
121
Vadim Bendebury245d4572016-04-05 16:01:57 -0700122 return TPM_SUCCESS;
123}
124
125uint32_t tlcl_finalize_physical_presence(void)
126{
127 /* Nothing needs to be done with tpm2. */
128 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
129 return TPM_SUCCESS;
130}
131
132uint32_t tlcl_force_clear(void)
133{
Vadim Bendeburyadfbbde2016-07-03 15:56:41 -0700134 struct tpm2_response *response;
135
136 response = tpm_process_command(TPM2_Clear, NULL);
137 printk(BIOS_INFO, "%s: response is %x\n",
138 __func__, response ? response->hdr.tpm_code : -1);
139
140 if (!response || response->hdr.tpm_code)
141 return TPM_E_IOERROR;
142
Vadim Bendebury245d4572016-04-05 16:01:57 -0700143 return TPM_SUCCESS;
144}
145
Furquan Shaikh8b5d04e2016-11-10 09:49:05 -0800146static uint8_t tlcl_init_done CAR_GLOBAL;
147
148/* This function is called directly by vboot, uses vboot return types. */
Vadim Bendebury245d4572016-04-05 16:01:57 -0700149uint32_t tlcl_lib_init(void)
150{
Furquan Shaikh8b5d04e2016-11-10 09:49:05 -0800151 uint8_t done = car_get_var(tlcl_init_done);
152 if (done)
153 return VB2_SUCCESS;
154
Vadim Bendebury245d4572016-04-05 16:01:57 -0700155 if (tis_init())
156 return VB2_ERROR_UNKNOWN;
157 if (tis_open())
158 return VB2_ERROR_UNKNOWN;
Furquan Shaikh8b5d04e2016-11-10 09:49:05 -0800159
160 car_set_var(tlcl_init_done, 1);
161
Vadim Bendebury245d4572016-04-05 16:01:57 -0700162 return VB2_SUCCESS;
163}
164
165uint32_t tlcl_physical_presence_cmd_enable(void)
166{
167 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
168 return TPM_SUCCESS;
169}
170
171uint32_t tlcl_read(uint32_t index, void *data, uint32_t length)
172{
173 struct tpm2_nv_read_cmd nv_readc;
174 struct tpm2_response *response;
175
176 memset(&nv_readc, 0, sizeof(nv_readc));
177
178 nv_readc.nvIndex = HR_NV_INDEX + index;
179 nv_readc.size = length;
180
181 response = tpm_process_command(TPM2_NV_Read, &nv_readc);
182
183 /* Need to map tpm error codes into internal values. */
184 if (!response)
185 return TPM_E_READ_FAILURE;
186
187 printk(BIOS_INFO, "%s:%d index %#x return code %x\n",
188 __FILE__, __LINE__, index, response->hdr.tpm_code);
189 switch (response->hdr.tpm_code) {
190 case 0:
191 break;
192
Vadim Bendebury08f93592017-06-21 12:23:22 -0700193 /* Uninitialized, returned if the space hasn't been written. */
194 case TPM_RC_NV_UNINITIALIZED:
195 /*
196 * Bad index, cr50 specific value, returned if the space
197 * hasn't been defined.
198 */
199 case TPM_RC_CR50_NV_UNDEFINED:
Vadim Bendebury245d4572016-04-05 16:01:57 -0700200 return TPM_E_BADINDEX;
201
202 default:
203 return TPM_E_READ_FAILURE;
204 }
205
206 if (length > response->nvr.buffer.t.size)
207 return TPM_E_RESPONSE_TOO_LARGE;
208
209 if (length < response->nvr.buffer.t.size)
210 return TPM_E_READ_EMPTY;
211
212 memcpy(data, response->nvr.buffer.t.buffer, length);
213
214 return TPM_SUCCESS;
215}
216
217uint32_t tlcl_self_test_full(void)
218{
219 struct tpm2_self_test st;
220 struct tpm2_response *response;
221
222 st.yes_no = 1;
223
224 response = tpm_process_command(TPM2_SelfTest, &st);
225 printk(BIOS_INFO, "%s: response is %x\n",
226 __func__, response ? response->hdr.tpm_code : -1);
227 return TPM_SUCCESS;
228}
229
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700230uint32_t tlcl_lock_nv_write(uint32_t index)
Vadim Bendebury245d4572016-04-05 16:01:57 -0700231{
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700232 struct tpm2_response *response;
233 /* TPM Wll reject attempts to write at non-defined index. */
234 struct tpm2_nv_write_lock_cmd nv_wl = {
235 .nvIndex = HR_NV_INDEX + index,
236 };
237
238 response = tpm_process_command(TPM2_NV_WriteLock, &nv_wl);
239
240 printk(BIOS_INFO, "%s: response is %x\n",
241 __func__, response ? response->hdr.tpm_code : -1);
242
243 if (!response || response->hdr.tpm_code)
244 return TPM_E_IOERROR;
245
Vadim Bendebury245d4572016-04-05 16:01:57 -0700246 return TPM_SUCCESS;
247}
248
249uint32_t tlcl_startup(void)
250{
Furquan Shaikhcc3365a2016-09-30 12:53:19 -0700251 return tlcl_send_startup(TPM_SU_CLEAR);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700252}
253
254uint32_t tlcl_write(uint32_t index, const void *data, uint32_t length)
255{
256 struct tpm2_nv_write_cmd nv_writec;
257 struct tpm2_response *response;
258
259 memset(&nv_writec, 0, sizeof(nv_writec));
260
261 nv_writec.nvIndex = HR_NV_INDEX + index;
262 nv_writec.data.t.size = length;
263 nv_writec.data.t.buffer = data;
264
265 response = tpm_process_command(TPM2_NV_Write, &nv_writec);
266
Vadim Bendebury1ec76032016-07-05 22:30:16 -0700267 printk(BIOS_INFO, "%s: response is %x\n",
268 __func__, response ? response->hdr.tpm_code : -1);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700269
Vadim Bendebury1ec76032016-07-05 22:30:16 -0700270 /* Need to map tpm error codes into internal values. */
271 if (!response || response->hdr.tpm_code)
272 return TPM_E_WRITE_FAILURE;
Vadim Bendebury245d4572016-04-05 16:01:57 -0700273
274 return TPM_SUCCESS;
275}
276
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100277uint32_t tlcl_define_space(uint32_t space_index, size_t space_size,
278 const TPMA_NV nv_attributes,
279 const uint8_t *nv_policy, size_t nv_policy_size)
Vadim Bendebury245d4572016-04-05 16:01:57 -0700280{
281 struct tpm2_nv_define_space_cmd nvds_cmd;
282 struct tpm2_response *response;
283
284 /* Prepare the define space command structure. */
285 memset(&nvds_cmd, 0, sizeof(nvds_cmd));
286
287 nvds_cmd.publicInfo.dataSize = space_size;
288 nvds_cmd.publicInfo.nvIndex = HR_NV_INDEX + space_index;
289 nvds_cmd.publicInfo.nameAlg = TPM_ALG_SHA256;
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100290 nvds_cmd.publicInfo.attributes = nv_attributes;
Vadim Bendebury245d4572016-04-05 16:01:57 -0700291
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100292 /*
293 * Use policy digest based on default pcr0 value. This makes
294 * sure that the space can not be deleted as soon as PCR0
295 * value has been extended from default.
296 */
297 if (nv_policy && nv_policy_size) {
298 nvds_cmd.publicInfo.authPolicy.t.buffer = nv_policy;
299 nvds_cmd.publicInfo.authPolicy.t.size = nv_policy_size;
Vadim Bendebury289ee8f2016-11-11 09:36:50 -0800300 }
Vadim Bendebury245d4572016-04-05 16:01:57 -0700301
302 response = tpm_process_command(TPM2_NV_DefineSpace, &nvds_cmd);
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100303 printk(BIOS_INFO, "%s: response is %x\n", __func__,
304 response ? response->hdr.tpm_code : -1);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700305
306 if (!response)
307 return TPM_E_NO_DEVICE;
308
Vadim Bendeburyaf8ae932016-11-11 14:15:31 -0800309 /* Map TPM2 retrun codes into common vboot represenation. */
Lee Leahy45fde702017-03-08 18:02:24 -0800310 switch (response->hdr.tpm_code) {
Vadim Bendeburyaf8ae932016-11-11 14:15:31 -0800311 case TPM2_RC_SUCCESS:
312 return TPM_SUCCESS;
313 case TPM2_RC_NV_DEFINED:
314 return TPM_E_NV_DEFINED;
315 default:
316 return TPM_E_INTERNAL_INCONSISTENCY;
317 }
Vadim Bendebury245d4572016-04-05 16:01:57 -0700318}
Aaron Durbinf56c7782017-01-10 17:44:42 -0600319
320uint32_t tlcl_disable_platform_hierarchy(void)
321{
322 struct tpm2_response *response;
323 struct tpm2_hierarchy_control_cmd hc = {
324 .enable = TPM_RH_PLATFORM,
325 .state = 0,
326 };
327
328 response = tpm_process_command(TPM2_Hierarchy_Control, &hc);
329
330 if (!response || response->hdr.tpm_code)
331 return TPM_E_INTERNAL_INCONSISTENCY;
332
333 return TPM_SUCCESS;
334}