blob: e6ec57c8118123c462f76fdc9fc572777f670308 [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 Kitchingf97ff0c2018-09-26 17:52:54 +080064 if (response && (response->hdr.tpm_code == 0 ||
65 response->hdr.tpm_code == TPM_RC_INITIALIZE)) {
66 return TPM_SUCCESS;
Furquan Shaikhcc3365a2016-09-30 12:53:19 -070067 }
Joel Kitchingf97ff0c2018-09-26 17:52:54 +080068 printk(BIOS_INFO, "%s: Startup return code is %x\n",
69 __func__, response->hdr.tpm_code);
70 return TPM_E_IOERROR;
Furquan Shaikhcc3365a2016-09-30 12:53:19 -070071}
72
Vadim Bendebury245d4572016-04-05 16:01:57 -070073uint32_t tlcl_resume(void)
74{
Furquan Shaikhcc3365a2016-09-30 12:53:19 -070075 return tlcl_send_startup(TPM_SU_STATE);
Vadim Bendebury245d4572016-04-05 16:01:57 -070076}
77
78uint32_t tlcl_assert_physical_presence(void)
79{
80 /*
81 * Nothing to do on TPM2 for this, use platform hierarchy availability
82 * instead.
83 */
84 return TPM_SUCCESS;
85}
86
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -070087/*
88 * The caller will provide the digest in a 32 byte buffer, let's consider it a
89 * sha256 digest.
90 */
Vadim Bendebury245d4572016-04-05 16:01:57 -070091uint32_t tlcl_extend(int pcr_num, const uint8_t *in_digest,
92 uint8_t *out_digest)
93{
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -070094 struct tpm2_pcr_extend_cmd pcr_ext_cmd;
95 struct tpm2_response *response;
96
97 pcr_ext_cmd.pcrHandle = HR_PCR + pcr_num;
98 pcr_ext_cmd.digests.count = 1;
99 pcr_ext_cmd.digests.digests[0].hashAlg = TPM_ALG_SHA256;
100 memcpy(pcr_ext_cmd.digests.digests[0].digest.sha256, in_digest,
101 sizeof(pcr_ext_cmd.digests.digests[0].digest.sha256));
102
103 response = tpm_process_command(TPM2_PCR_Extend, &pcr_ext_cmd);
104
105 printk(BIOS_INFO, "%s: response is %x\n",
106 __func__, response ? response->hdr.tpm_code : -1);
107 if (!response || response->hdr.tpm_code)
108 return TPM_E_IOERROR;
109
Vadim Bendebury245d4572016-04-05 16:01:57 -0700110 return TPM_SUCCESS;
111}
112
113uint32_t tlcl_finalize_physical_presence(void)
114{
115 /* Nothing needs to be done with tpm2. */
116 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
117 return TPM_SUCCESS;
118}
119
120uint32_t tlcl_force_clear(void)
121{
Vadim Bendeburyadfbbde2016-07-03 15:56:41 -0700122 struct tpm2_response *response;
123
124 response = tpm_process_command(TPM2_Clear, NULL);
125 printk(BIOS_INFO, "%s: response is %x\n",
126 __func__, response ? response->hdr.tpm_code : -1);
127
128 if (!response || response->hdr.tpm_code)
129 return TPM_E_IOERROR;
130
Vadim Bendebury245d4572016-04-05 16:01:57 -0700131 return TPM_SUCCESS;
132}
133
Furquan Shaikh8b5d04e2016-11-10 09:49:05 -0800134static uint8_t tlcl_init_done CAR_GLOBAL;
135
136/* This function is called directly by vboot, uses vboot return types. */
Vadim Bendebury245d4572016-04-05 16:01:57 -0700137uint32_t tlcl_lib_init(void)
138{
Furquan Shaikh8b5d04e2016-11-10 09:49:05 -0800139 uint8_t done = car_get_var(tlcl_init_done);
140 if (done)
141 return VB2_SUCCESS;
142
Vadim Bendebury245d4572016-04-05 16:01:57 -0700143 if (tis_init())
144 return VB2_ERROR_UNKNOWN;
145 if (tis_open())
146 return VB2_ERROR_UNKNOWN;
Furquan Shaikh8b5d04e2016-11-10 09:49:05 -0800147
148 car_set_var(tlcl_init_done, 1);
149
Vadim Bendebury245d4572016-04-05 16:01:57 -0700150 return VB2_SUCCESS;
151}
152
153uint32_t tlcl_physical_presence_cmd_enable(void)
154{
155 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
156 return TPM_SUCCESS;
157}
158
159uint32_t tlcl_read(uint32_t index, void *data, uint32_t length)
160{
161 struct tpm2_nv_read_cmd nv_readc;
162 struct tpm2_response *response;
163
164 memset(&nv_readc, 0, sizeof(nv_readc));
165
166 nv_readc.nvIndex = HR_NV_INDEX + index;
167 nv_readc.size = length;
168
169 response = tpm_process_command(TPM2_NV_Read, &nv_readc);
170
171 /* Need to map tpm error codes into internal values. */
172 if (!response)
173 return TPM_E_READ_FAILURE;
174
175 printk(BIOS_INFO, "%s:%d index %#x return code %x\n",
176 __FILE__, __LINE__, index, response->hdr.tpm_code);
177 switch (response->hdr.tpm_code) {
178 case 0:
179 break;
180
Vadim Bendebury08f93592017-06-21 12:23:22 -0700181 /* Uninitialized, returned if the space hasn't been written. */
182 case TPM_RC_NV_UNINITIALIZED:
183 /*
184 * Bad index, cr50 specific value, returned if the space
185 * hasn't been defined.
186 */
187 case TPM_RC_CR50_NV_UNDEFINED:
Vadim Bendebury245d4572016-04-05 16:01:57 -0700188 return TPM_E_BADINDEX;
189
190 default:
191 return TPM_E_READ_FAILURE;
192 }
193
194 if (length > response->nvr.buffer.t.size)
195 return TPM_E_RESPONSE_TOO_LARGE;
196
197 if (length < response->nvr.buffer.t.size)
198 return TPM_E_READ_EMPTY;
199
200 memcpy(data, response->nvr.buffer.t.buffer, length);
201
202 return TPM_SUCCESS;
203}
204
205uint32_t tlcl_self_test_full(void)
206{
207 struct tpm2_self_test st;
208 struct tpm2_response *response;
209
210 st.yes_no = 1;
211
212 response = tpm_process_command(TPM2_SelfTest, &st);
213 printk(BIOS_INFO, "%s: response is %x\n",
214 __func__, response ? response->hdr.tpm_code : -1);
215 return TPM_SUCCESS;
216}
217
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700218uint32_t tlcl_lock_nv_write(uint32_t index)
Vadim Bendebury245d4572016-04-05 16:01:57 -0700219{
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700220 struct tpm2_response *response;
221 /* TPM Wll reject attempts to write at non-defined index. */
222 struct tpm2_nv_write_lock_cmd nv_wl = {
223 .nvIndex = HR_NV_INDEX + index,
224 };
225
226 response = tpm_process_command(TPM2_NV_WriteLock, &nv_wl);
227
228 printk(BIOS_INFO, "%s: response is %x\n",
229 __func__, response ? response->hdr.tpm_code : -1);
230
231 if (!response || response->hdr.tpm_code)
232 return TPM_E_IOERROR;
233
Vadim Bendebury245d4572016-04-05 16:01:57 -0700234 return TPM_SUCCESS;
235}
236
237uint32_t tlcl_startup(void)
238{
Furquan Shaikhcc3365a2016-09-30 12:53:19 -0700239 return tlcl_send_startup(TPM_SU_CLEAR);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700240}
241
242uint32_t tlcl_write(uint32_t index, const void *data, uint32_t length)
243{
244 struct tpm2_nv_write_cmd nv_writec;
245 struct tpm2_response *response;
246
247 memset(&nv_writec, 0, sizeof(nv_writec));
248
249 nv_writec.nvIndex = HR_NV_INDEX + index;
250 nv_writec.data.t.size = length;
251 nv_writec.data.t.buffer = data;
252
253 response = tpm_process_command(TPM2_NV_Write, &nv_writec);
254
Vadim Bendebury1ec76032016-07-05 22:30:16 -0700255 printk(BIOS_INFO, "%s: response is %x\n",
256 __func__, response ? response->hdr.tpm_code : -1);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700257
Vadim Bendebury1ec76032016-07-05 22:30:16 -0700258 /* Need to map tpm error codes into internal values. */
259 if (!response || response->hdr.tpm_code)
260 return TPM_E_WRITE_FAILURE;
Vadim Bendebury245d4572016-04-05 16:01:57 -0700261
262 return TPM_SUCCESS;
263}
264
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100265uint32_t tlcl_define_space(uint32_t space_index, size_t space_size,
266 const TPMA_NV nv_attributes,
267 const uint8_t *nv_policy, size_t nv_policy_size)
Vadim Bendebury245d4572016-04-05 16:01:57 -0700268{
269 struct tpm2_nv_define_space_cmd nvds_cmd;
270 struct tpm2_response *response;
271
272 /* Prepare the define space command structure. */
273 memset(&nvds_cmd, 0, sizeof(nvds_cmd));
274
275 nvds_cmd.publicInfo.dataSize = space_size;
276 nvds_cmd.publicInfo.nvIndex = HR_NV_INDEX + space_index;
277 nvds_cmd.publicInfo.nameAlg = TPM_ALG_SHA256;
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100278 nvds_cmd.publicInfo.attributes = nv_attributes;
Vadim Bendebury245d4572016-04-05 16:01:57 -0700279
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100280 /*
281 * Use policy digest based on default pcr0 value. This makes
282 * sure that the space can not be deleted as soon as PCR0
283 * value has been extended from default.
284 */
285 if (nv_policy && nv_policy_size) {
286 nvds_cmd.publicInfo.authPolicy.t.buffer = nv_policy;
287 nvds_cmd.publicInfo.authPolicy.t.size = nv_policy_size;
Vadim Bendebury289ee8f2016-11-11 09:36:50 -0800288 }
Vadim Bendebury245d4572016-04-05 16:01:57 -0700289
290 response = tpm_process_command(TPM2_NV_DefineSpace, &nvds_cmd);
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100291 printk(BIOS_INFO, "%s: response is %x\n", __func__,
292 response ? response->hdr.tpm_code : -1);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700293
294 if (!response)
295 return TPM_E_NO_DEVICE;
296
Vadim Bendeburyaf8ae932016-11-11 14:15:31 -0800297 /* Map TPM2 retrun codes into common vboot represenation. */
Lee Leahy45fde702017-03-08 18:02:24 -0800298 switch (response->hdr.tpm_code) {
Vadim Bendeburyaf8ae932016-11-11 14:15:31 -0800299 case TPM2_RC_SUCCESS:
300 return TPM_SUCCESS;
301 case TPM2_RC_NV_DEFINED:
302 return TPM_E_NV_DEFINED;
303 default:
304 return TPM_E_INTERNAL_INCONSISTENCY;
305 }
Vadim Bendebury245d4572016-04-05 16:01:57 -0700306}
Aaron Durbinf56c7782017-01-10 17:44:42 -0600307
308uint32_t tlcl_disable_platform_hierarchy(void)
309{
310 struct tpm2_response *response;
311 struct tpm2_hierarchy_control_cmd hc = {
312 .enable = TPM_RH_PLATFORM,
313 .state = 0,
314 };
315
316 response = tpm_process_command(TPM2_Hierarchy_Control, &hc);
317
318 if (!response || response->hdr.tpm_code)
319 return TPM_E_INTERNAL_INCONSISTENCY;
320
321 return TPM_SUCCESS;
322}