blob: e579bff78efb29637f66f624d9f20d6ff7e19363 [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
Joel Kitching2e690ee2018-11-15 16:48:53 +080090static uint32_t tlcl_send_shutdown(TPM_SU type)
91{
92 struct tpm2_shutdown shutdown;
93 struct tpm2_response *response;
94
95 shutdown.shutdown_type = type;
96 response = tpm_process_command(TPM2_Shutdown, &shutdown);
97
98 /* IO error, tpm2_response pointer is empty. */
99 if (response == NULL) {
100 printk(BIOS_ERR, "%s: TPM communication error\n", __func__);
101 return TPM_E_IOERROR;
102 }
103
104 printk(BIOS_INFO, "%s: Shutdown return code is %x\n",
105 __func__, response->hdr.tpm_code);
106
107 if (response->hdr.tpm_code == TPM2_RC_SUCCESS)
108 return TPM_SUCCESS;
109
110 /* Collapse any other errors into TPM_E_IOERROR. */
111 return TPM_E_IOERROR;
112}
113
114uint32_t tlcl_save_state(void)
115{
116 return tlcl_send_shutdown(TPM_SU_STATE);
117}
118
Vadim Bendebury245d4572016-04-05 16:01:57 -0700119uint32_t tlcl_assert_physical_presence(void)
120{
121 /*
122 * Nothing to do on TPM2 for this, use platform hierarchy availability
123 * instead.
124 */
125 return TPM_SUCCESS;
126}
127
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700128/*
129 * The caller will provide the digest in a 32 byte buffer, let's consider it a
130 * sha256 digest.
131 */
Vadim Bendebury245d4572016-04-05 16:01:57 -0700132uint32_t tlcl_extend(int pcr_num, const uint8_t *in_digest,
133 uint8_t *out_digest)
134{
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700135 struct tpm2_pcr_extend_cmd pcr_ext_cmd;
136 struct tpm2_response *response;
137
138 pcr_ext_cmd.pcrHandle = HR_PCR + pcr_num;
139 pcr_ext_cmd.digests.count = 1;
140 pcr_ext_cmd.digests.digests[0].hashAlg = TPM_ALG_SHA256;
141 memcpy(pcr_ext_cmd.digests.digests[0].digest.sha256, in_digest,
142 sizeof(pcr_ext_cmd.digests.digests[0].digest.sha256));
143
144 response = tpm_process_command(TPM2_PCR_Extend, &pcr_ext_cmd);
145
146 printk(BIOS_INFO, "%s: response is %x\n",
147 __func__, response ? response->hdr.tpm_code : -1);
148 if (!response || response->hdr.tpm_code)
149 return TPM_E_IOERROR;
150
Vadim Bendebury245d4572016-04-05 16:01:57 -0700151 return TPM_SUCCESS;
152}
153
154uint32_t tlcl_finalize_physical_presence(void)
155{
156 /* Nothing needs to be done with tpm2. */
157 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
158 return TPM_SUCCESS;
159}
160
161uint32_t tlcl_force_clear(void)
162{
Vadim Bendeburyadfbbde2016-07-03 15:56:41 -0700163 struct tpm2_response *response;
164
165 response = tpm_process_command(TPM2_Clear, NULL);
166 printk(BIOS_INFO, "%s: response is %x\n",
167 __func__, response ? response->hdr.tpm_code : -1);
168
169 if (!response || response->hdr.tpm_code)
170 return TPM_E_IOERROR;
171
Vadim Bendebury245d4572016-04-05 16:01:57 -0700172 return TPM_SUCCESS;
173}
174
Furquan Shaikh8b5d04e2016-11-10 09:49:05 -0800175static uint8_t tlcl_init_done CAR_GLOBAL;
176
177/* This function is called directly by vboot, uses vboot return types. */
Vadim Bendebury245d4572016-04-05 16:01:57 -0700178uint32_t tlcl_lib_init(void)
179{
Furquan Shaikh8b5d04e2016-11-10 09:49:05 -0800180 uint8_t done = car_get_var(tlcl_init_done);
181 if (done)
182 return VB2_SUCCESS;
183
Vadim Bendebury245d4572016-04-05 16:01:57 -0700184 if (tis_init())
185 return VB2_ERROR_UNKNOWN;
186 if (tis_open())
187 return VB2_ERROR_UNKNOWN;
Furquan Shaikh8b5d04e2016-11-10 09:49:05 -0800188
189 car_set_var(tlcl_init_done, 1);
190
Vadim Bendebury245d4572016-04-05 16:01:57 -0700191 return VB2_SUCCESS;
192}
193
194uint32_t tlcl_physical_presence_cmd_enable(void)
195{
196 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
197 return TPM_SUCCESS;
198}
199
200uint32_t tlcl_read(uint32_t index, void *data, uint32_t length)
201{
202 struct tpm2_nv_read_cmd nv_readc;
203 struct tpm2_response *response;
204
205 memset(&nv_readc, 0, sizeof(nv_readc));
206
207 nv_readc.nvIndex = HR_NV_INDEX + index;
208 nv_readc.size = length;
209
210 response = tpm_process_command(TPM2_NV_Read, &nv_readc);
211
212 /* Need to map tpm error codes into internal values. */
213 if (!response)
214 return TPM_E_READ_FAILURE;
215
216 printk(BIOS_INFO, "%s:%d index %#x return code %x\n",
217 __FILE__, __LINE__, index, response->hdr.tpm_code);
218 switch (response->hdr.tpm_code) {
219 case 0:
220 break;
221
Vadim Bendebury08f93592017-06-21 12:23:22 -0700222 /* Uninitialized, returned if the space hasn't been written. */
223 case TPM_RC_NV_UNINITIALIZED:
224 /*
225 * Bad index, cr50 specific value, returned if the space
226 * hasn't been defined.
227 */
228 case TPM_RC_CR50_NV_UNDEFINED:
Vadim Bendebury245d4572016-04-05 16:01:57 -0700229 return TPM_E_BADINDEX;
230
231 default:
232 return TPM_E_READ_FAILURE;
233 }
234
235 if (length > response->nvr.buffer.t.size)
236 return TPM_E_RESPONSE_TOO_LARGE;
237
238 if (length < response->nvr.buffer.t.size)
239 return TPM_E_READ_EMPTY;
240
241 memcpy(data, response->nvr.buffer.t.buffer, length);
242
243 return TPM_SUCCESS;
244}
245
246uint32_t tlcl_self_test_full(void)
247{
248 struct tpm2_self_test st;
249 struct tpm2_response *response;
250
251 st.yes_no = 1;
252
253 response = tpm_process_command(TPM2_SelfTest, &st);
254 printk(BIOS_INFO, "%s: response is %x\n",
255 __func__, response ? response->hdr.tpm_code : -1);
256 return TPM_SUCCESS;
257}
258
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700259uint32_t tlcl_lock_nv_write(uint32_t index)
Vadim Bendebury245d4572016-04-05 16:01:57 -0700260{
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700261 struct tpm2_response *response;
262 /* TPM Wll reject attempts to write at non-defined index. */
263 struct tpm2_nv_write_lock_cmd nv_wl = {
264 .nvIndex = HR_NV_INDEX + index,
265 };
266
267 response = tpm_process_command(TPM2_NV_WriteLock, &nv_wl);
268
269 printk(BIOS_INFO, "%s: response is %x\n",
270 __func__, response ? response->hdr.tpm_code : -1);
271
272 if (!response || response->hdr.tpm_code)
273 return TPM_E_IOERROR;
274
Vadim Bendebury245d4572016-04-05 16:01:57 -0700275 return TPM_SUCCESS;
276}
277
278uint32_t tlcl_startup(void)
279{
Furquan Shaikhcc3365a2016-09-30 12:53:19 -0700280 return tlcl_send_startup(TPM_SU_CLEAR);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700281}
282
283uint32_t tlcl_write(uint32_t index, const void *data, uint32_t length)
284{
285 struct tpm2_nv_write_cmd nv_writec;
286 struct tpm2_response *response;
287
288 memset(&nv_writec, 0, sizeof(nv_writec));
289
290 nv_writec.nvIndex = HR_NV_INDEX + index;
291 nv_writec.data.t.size = length;
292 nv_writec.data.t.buffer = data;
293
294 response = tpm_process_command(TPM2_NV_Write, &nv_writec);
295
Vadim Bendebury1ec76032016-07-05 22:30:16 -0700296 printk(BIOS_INFO, "%s: response is %x\n",
297 __func__, response ? response->hdr.tpm_code : -1);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700298
Vadim Bendebury1ec76032016-07-05 22:30:16 -0700299 /* Need to map tpm error codes into internal values. */
300 if (!response || response->hdr.tpm_code)
301 return TPM_E_WRITE_FAILURE;
Vadim Bendebury245d4572016-04-05 16:01:57 -0700302
303 return TPM_SUCCESS;
304}
305
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100306uint32_t tlcl_define_space(uint32_t space_index, size_t space_size,
307 const TPMA_NV nv_attributes,
308 const uint8_t *nv_policy, size_t nv_policy_size)
Vadim Bendebury245d4572016-04-05 16:01:57 -0700309{
310 struct tpm2_nv_define_space_cmd nvds_cmd;
311 struct tpm2_response *response;
312
313 /* Prepare the define space command structure. */
314 memset(&nvds_cmd, 0, sizeof(nvds_cmd));
315
316 nvds_cmd.publicInfo.dataSize = space_size;
317 nvds_cmd.publicInfo.nvIndex = HR_NV_INDEX + space_index;
318 nvds_cmd.publicInfo.nameAlg = TPM_ALG_SHA256;
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100319 nvds_cmd.publicInfo.attributes = nv_attributes;
Vadim Bendebury245d4572016-04-05 16:01:57 -0700320
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100321 /*
322 * Use policy digest based on default pcr0 value. This makes
323 * sure that the space can not be deleted as soon as PCR0
324 * value has been extended from default.
325 */
326 if (nv_policy && nv_policy_size) {
327 nvds_cmd.publicInfo.authPolicy.t.buffer = nv_policy;
328 nvds_cmd.publicInfo.authPolicy.t.size = nv_policy_size;
Vadim Bendebury289ee8f2016-11-11 09:36:50 -0800329 }
Vadim Bendebury245d4572016-04-05 16:01:57 -0700330
331 response = tpm_process_command(TPM2_NV_DefineSpace, &nvds_cmd);
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100332 printk(BIOS_INFO, "%s: response is %x\n", __func__,
333 response ? response->hdr.tpm_code : -1);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700334
335 if (!response)
336 return TPM_E_NO_DEVICE;
337
Vadim Bendeburyaf8ae932016-11-11 14:15:31 -0800338 /* Map TPM2 retrun codes into common vboot represenation. */
Lee Leahy45fde702017-03-08 18:02:24 -0800339 switch (response->hdr.tpm_code) {
Vadim Bendeburyaf8ae932016-11-11 14:15:31 -0800340 case TPM2_RC_SUCCESS:
341 return TPM_SUCCESS;
342 case TPM2_RC_NV_DEFINED:
343 return TPM_E_NV_DEFINED;
344 default:
345 return TPM_E_INTERNAL_INCONSISTENCY;
346 }
Vadim Bendebury245d4572016-04-05 16:01:57 -0700347}
Aaron Durbinf56c7782017-01-10 17:44:42 -0600348
349uint32_t tlcl_disable_platform_hierarchy(void)
350{
351 struct tpm2_response *response;
352 struct tpm2_hierarchy_control_cmd hc = {
353 .enable = TPM_RH_PLATFORM,
354 .state = 0,
355 };
356
357 response = tpm_process_command(TPM2_Hierarchy_Control, &hc);
358
359 if (!response || response->hdr.tpm_code)
360 return TPM_E_INTERNAL_INCONSISTENCY;
361
362 return TPM_SUCCESS;
363}