blob: 49a6cea083617a85270215617bf4442379060994 [file] [log] [blame]
Vadim Bendebury245d4572016-04-05 16:01:57 -07001/*
2 * Copyright 2016 The Chromium OS Authors. All rights reserved.
Frans Hendriks589eff72019-06-26 10:43:40 +02003 * Copyright 2017-2019 Eltan B.V.
Vadim Bendebury245d4572016-04-05 16:01:57 -07004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#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. */
Arthur Heymans0ca944b2019-11-20 19:51:06 +010032 static uint8_t cr_buffer[TPM_BUFFER_SIZE];
Victor Prupisf7060202016-08-19 10:45:04 -070033
Arthur Heymans0ca944b2019-11-20 19:51:06 +010034 obuf_init(&ob, cr_buffer, sizeof(cr_buffer));
Aaron Durbinee049fa2017-03-25 00:38:45 -050035
36 if (tpm_marshal_command(command, command_body, &ob) < 0) {
37 printk(BIOS_ERR, "command %#x\n", command);
Vadim Bendebury245d4572016-04-05 16:01:57 -070038 return NULL;
39 }
40
Aaron Durbinee049fa2017-03-25 00:38:45 -050041 sendb = obuf_contents(&ob, &out_size);
42
Vadim Bendebury245d4572016-04-05 16:01:57 -070043 in_size = sizeof(cr_buffer);
Arthur Heymans0ca944b2019-11-20 19:51:06 +010044 if (tis_sendrecv(sendb, out_size, cr_buffer, &in_size)) {
Vadim Bendebury245d4572016-04-05 16:01:57 -070045 printk(BIOS_ERR, "tpm transaction failed\n");
46 return NULL;
47 }
48
Arthur Heymans0ca944b2019-11-20 19:51:06 +010049 ibuf_init(&ib, cr_buffer, in_size);
Aaron Durbinee049fa2017-03-25 00:38:45 -050050
51 return tpm_unmarshal_response(command, &ib);
Vadim Bendebury245d4572016-04-05 16:01:57 -070052}
53
Furquan Shaikhcc3365a2016-09-30 12:53:19 -070054static uint32_t tlcl_send_startup(TPM_SU type)
55{
56 struct tpm2_startup startup;
57 struct tpm2_response *response;
58
59 startup.startup_type = type;
60 response = tpm_process_command(TPM2_Startup, &startup);
61
Joel Kitchingc5d0a2e2018-10-12 15:52:00 +080062 /* IO error, tpm2_response pointer is empty. */
63 if (response == NULL) {
64 printk(BIOS_ERR, "%s: TPM communication error\n", __func__);
65 return TPM_E_IOERROR;
Furquan Shaikhcc3365a2016-09-30 12:53:19 -070066 }
Joel Kitchingc5d0a2e2018-10-12 15:52:00 +080067
Joel Kitchingf97ff0c2018-09-26 17:52:54 +080068 printk(BIOS_INFO, "%s: Startup return code is %x\n",
69 __func__, response->hdr.tpm_code);
Joel Kitchingc5d0a2e2018-10-12 15:52:00 +080070
71 switch (response->hdr.tpm_code) {
72 case TPM_RC_INITIALIZE:
73 /* TPM already initialized. */
74 return TPM_E_INVALID_POSTINIT;
75 case TPM2_RC_SUCCESS:
76 return TPM_SUCCESS;
77 }
78
79 /* Collapse any other errors into TPM_E_IOERROR. */
Joel Kitchingf97ff0c2018-09-26 17:52:54 +080080 return TPM_E_IOERROR;
Furquan Shaikhcc3365a2016-09-30 12:53:19 -070081}
82
Vadim Bendebury245d4572016-04-05 16:01:57 -070083uint32_t tlcl_resume(void)
84{
Furquan Shaikhcc3365a2016-09-30 12:53:19 -070085 return tlcl_send_startup(TPM_SU_STATE);
Vadim Bendebury245d4572016-04-05 16:01:57 -070086}
87
Joel Kitching2e690ee2018-11-15 16:48:53 +080088static uint32_t tlcl_send_shutdown(TPM_SU type)
89{
90 struct tpm2_shutdown shutdown;
91 struct tpm2_response *response;
92
93 shutdown.shutdown_type = type;
94 response = tpm_process_command(TPM2_Shutdown, &shutdown);
95
96 /* IO error, tpm2_response pointer is empty. */
97 if (response == NULL) {
98 printk(BIOS_ERR, "%s: TPM communication error\n", __func__);
99 return TPM_E_IOERROR;
100 }
101
102 printk(BIOS_INFO, "%s: Shutdown return code is %x\n",
103 __func__, response->hdr.tpm_code);
104
105 if (response->hdr.tpm_code == TPM2_RC_SUCCESS)
106 return TPM_SUCCESS;
107
108 /* Collapse any other errors into TPM_E_IOERROR. */
109 return TPM_E_IOERROR;
110}
111
112uint32_t tlcl_save_state(void)
113{
114 return tlcl_send_shutdown(TPM_SU_STATE);
115}
116
Vadim Bendebury245d4572016-04-05 16:01:57 -0700117uint32_t tlcl_assert_physical_presence(void)
118{
119 /*
120 * Nothing to do on TPM2 for this, use platform hierarchy availability
121 * instead.
122 */
123 return TPM_SUCCESS;
124}
125
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700126/*
Julius Wernerb3426c02019-09-11 14:24:47 -0700127 * The caller will provide the digest in a 32 byte buffer, let's consider it a
128 * sha256 digest.
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700129 */
Vadim Bendebury245d4572016-04-05 16:01:57 -0700130uint32_t tlcl_extend(int pcr_num, const uint8_t *in_digest,
131 uint8_t *out_digest)
132{
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700133 struct tpm2_pcr_extend_cmd pcr_ext_cmd;
134 struct tpm2_response *response;
135
136 pcr_ext_cmd.pcrHandle = HR_PCR + pcr_num;
Julius Wernerb3426c02019-09-11 14:24:47 -0700137 pcr_ext_cmd.digests.count = 1;
138 pcr_ext_cmd.digests.digests[0].hashAlg = TPM_ALG_SHA256;
139 memcpy(pcr_ext_cmd.digests.digests[0].digest.sha256, in_digest,
140 sizeof(pcr_ext_cmd.digests.digests[0].digest.sha256));
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700141
142 response = tpm_process_command(TPM2_PCR_Extend, &pcr_ext_cmd);
143
Julius Wernerb3426c02019-09-11 14:24:47 -0700144 printk(BIOS_INFO, "%s: response is %x\n",
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700145 __func__, response ? response->hdr.tpm_code : -1);
146 if (!response || response->hdr.tpm_code)
147 return TPM_E_IOERROR;
148
Vadim Bendebury245d4572016-04-05 16:01:57 -0700149 return TPM_SUCCESS;
150}
151
152uint32_t tlcl_finalize_physical_presence(void)
153{
154 /* Nothing needs to be done with tpm2. */
155 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
156 return TPM_SUCCESS;
157}
158
159uint32_t tlcl_force_clear(void)
160{
Vadim Bendeburyadfbbde2016-07-03 15:56:41 -0700161 struct tpm2_response *response;
162
163 response = tpm_process_command(TPM2_Clear, NULL);
164 printk(BIOS_INFO, "%s: response is %x\n",
165 __func__, response ? response->hdr.tpm_code : -1);
166
167 if (!response || response->hdr.tpm_code)
168 return TPM_E_IOERROR;
169
Vadim Bendebury245d4572016-04-05 16:01:57 -0700170 return TPM_SUCCESS;
171}
172
Christian Walterc9ac0bc2020-01-28 19:54:33 +0100173uint32_t tlcl_clear_control(bool disable)
174{
175 struct tpm2_response *response;
176 struct tpm2_clear_control_cmd cc = {
177 .disable = 0,
178 };
179
180 response = tpm_process_command(TPM2_ClearControl, &cc);
181 printk(BIOS_INFO, "%s: response is %x\n",
182 __func__, response ? response->hdr.tpm_code : -1);
183
184 if (!response || response->hdr.tpm_code)
185 return TPM_E_IOERROR;
186
187 return TPM_SUCCESS;
188}
189
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100190static uint8_t tlcl_init_done;
Furquan Shaikh8b5d04e2016-11-10 09:49:05 -0800191
192/* This function is called directly by vboot, uses vboot return types. */
Vadim Bendebury245d4572016-04-05 16:01:57 -0700193uint32_t tlcl_lib_init(void)
194{
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100195 if (tlcl_init_done)
Furquan Shaikh8b5d04e2016-11-10 09:49:05 -0800196 return VB2_SUCCESS;
197
Frans Hendriks3891d272019-06-12 11:14:55 +0200198 if (tis_init()) {
199 printk(BIOS_ERR, "%s: tis_init returned error\n", __func__);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700200 return VB2_ERROR_UNKNOWN;
Frans Hendriks3891d272019-06-12 11:14:55 +0200201 }
202
203 if (tis_open()) {
204 printk(BIOS_ERR, "%s: tis_open returned error\n", __func__);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700205 return VB2_ERROR_UNKNOWN;
Frans Hendriks3891d272019-06-12 11:14:55 +0200206 }
Furquan Shaikh8b5d04e2016-11-10 09:49:05 -0800207
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100208 tlcl_init_done = 1;
Furquan Shaikh8b5d04e2016-11-10 09:49:05 -0800209
Vadim Bendebury245d4572016-04-05 16:01:57 -0700210 return VB2_SUCCESS;
211}
212
213uint32_t tlcl_physical_presence_cmd_enable(void)
214{
215 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
216 return TPM_SUCCESS;
217}
218
219uint32_t tlcl_read(uint32_t index, void *data, uint32_t length)
220{
221 struct tpm2_nv_read_cmd nv_readc;
222 struct tpm2_response *response;
223
224 memset(&nv_readc, 0, sizeof(nv_readc));
225
226 nv_readc.nvIndex = HR_NV_INDEX + index;
227 nv_readc.size = length;
228
229 response = tpm_process_command(TPM2_NV_Read, &nv_readc);
230
231 /* Need to map tpm error codes into internal values. */
232 if (!response)
233 return TPM_E_READ_FAILURE;
234
235 printk(BIOS_INFO, "%s:%d index %#x return code %x\n",
236 __FILE__, __LINE__, index, response->hdr.tpm_code);
237 switch (response->hdr.tpm_code) {
238 case 0:
239 break;
240
Vadim Bendebury08f93592017-06-21 12:23:22 -0700241 /* Uninitialized, returned if the space hasn't been written. */
242 case TPM_RC_NV_UNINITIALIZED:
243 /*
244 * Bad index, cr50 specific value, returned if the space
245 * hasn't been defined.
246 */
247 case TPM_RC_CR50_NV_UNDEFINED:
Vadim Bendebury245d4572016-04-05 16:01:57 -0700248 return TPM_E_BADINDEX;
249
250 default:
251 return TPM_E_READ_FAILURE;
252 }
253
254 if (length > response->nvr.buffer.t.size)
255 return TPM_E_RESPONSE_TOO_LARGE;
256
257 if (length < response->nvr.buffer.t.size)
258 return TPM_E_READ_EMPTY;
259
260 memcpy(data, response->nvr.buffer.t.buffer, length);
261
262 return TPM_SUCCESS;
263}
264
265uint32_t tlcl_self_test_full(void)
266{
267 struct tpm2_self_test st;
268 struct tpm2_response *response;
269
270 st.yes_no = 1;
271
272 response = tpm_process_command(TPM2_SelfTest, &st);
273 printk(BIOS_INFO, "%s: response is %x\n",
274 __func__, response ? response->hdr.tpm_code : -1);
275 return TPM_SUCCESS;
276}
277
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700278uint32_t tlcl_lock_nv_write(uint32_t index)
Vadim Bendebury245d4572016-04-05 16:01:57 -0700279{
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700280 struct tpm2_response *response;
281 /* TPM Wll reject attempts to write at non-defined index. */
282 struct tpm2_nv_write_lock_cmd nv_wl = {
283 .nvIndex = HR_NV_INDEX + index,
284 };
285
286 response = tpm_process_command(TPM2_NV_WriteLock, &nv_wl);
287
288 printk(BIOS_INFO, "%s: response is %x\n",
289 __func__, response ? response->hdr.tpm_code : -1);
290
291 if (!response || response->hdr.tpm_code)
292 return TPM_E_IOERROR;
293
Vadim Bendebury245d4572016-04-05 16:01:57 -0700294 return TPM_SUCCESS;
295}
296
297uint32_t tlcl_startup(void)
298{
Furquan Shaikhcc3365a2016-09-30 12:53:19 -0700299 return tlcl_send_startup(TPM_SU_CLEAR);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700300}
301
302uint32_t tlcl_write(uint32_t index, const void *data, uint32_t length)
303{
304 struct tpm2_nv_write_cmd nv_writec;
305 struct tpm2_response *response;
306
307 memset(&nv_writec, 0, sizeof(nv_writec));
308
309 nv_writec.nvIndex = HR_NV_INDEX + index;
310 nv_writec.data.t.size = length;
311 nv_writec.data.t.buffer = data;
312
313 response = tpm_process_command(TPM2_NV_Write, &nv_writec);
314
Vadim Bendebury1ec76032016-07-05 22:30:16 -0700315 printk(BIOS_INFO, "%s: response is %x\n",
316 __func__, response ? response->hdr.tpm_code : -1);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700317
Vadim Bendebury1ec76032016-07-05 22:30:16 -0700318 /* Need to map tpm error codes into internal values. */
319 if (!response || response->hdr.tpm_code)
320 return TPM_E_WRITE_FAILURE;
Vadim Bendebury245d4572016-04-05 16:01:57 -0700321
322 return TPM_SUCCESS;
323}
324
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100325uint32_t tlcl_define_space(uint32_t space_index, size_t space_size,
326 const TPMA_NV nv_attributes,
327 const uint8_t *nv_policy, size_t nv_policy_size)
Vadim Bendebury245d4572016-04-05 16:01:57 -0700328{
329 struct tpm2_nv_define_space_cmd nvds_cmd;
330 struct tpm2_response *response;
331
332 /* Prepare the define space command structure. */
333 memset(&nvds_cmd, 0, sizeof(nvds_cmd));
334
335 nvds_cmd.publicInfo.dataSize = space_size;
336 nvds_cmd.publicInfo.nvIndex = HR_NV_INDEX + space_index;
337 nvds_cmd.publicInfo.nameAlg = TPM_ALG_SHA256;
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100338 nvds_cmd.publicInfo.attributes = nv_attributes;
Vadim Bendebury245d4572016-04-05 16:01:57 -0700339
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100340 /*
341 * Use policy digest based on default pcr0 value. This makes
342 * sure that the space can not be deleted as soon as PCR0
343 * value has been extended from default.
344 */
345 if (nv_policy && nv_policy_size) {
346 nvds_cmd.publicInfo.authPolicy.t.buffer = nv_policy;
347 nvds_cmd.publicInfo.authPolicy.t.size = nv_policy_size;
Vadim Bendebury289ee8f2016-11-11 09:36:50 -0800348 }
Vadim Bendebury245d4572016-04-05 16:01:57 -0700349
350 response = tpm_process_command(TPM2_NV_DefineSpace, &nvds_cmd);
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100351 printk(BIOS_INFO, "%s: response is %x\n", __func__,
352 response ? response->hdr.tpm_code : -1);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700353
354 if (!response)
355 return TPM_E_NO_DEVICE;
356
Vadim Bendeburyaf8ae932016-11-11 14:15:31 -0800357 /* Map TPM2 retrun codes into common vboot represenation. */
Lee Leahy45fde702017-03-08 18:02:24 -0800358 switch (response->hdr.tpm_code) {
Vadim Bendeburyaf8ae932016-11-11 14:15:31 -0800359 case TPM2_RC_SUCCESS:
360 return TPM_SUCCESS;
361 case TPM2_RC_NV_DEFINED:
362 return TPM_E_NV_DEFINED;
363 default:
364 return TPM_E_INTERNAL_INCONSISTENCY;
365 }
Vadim Bendebury245d4572016-04-05 16:01:57 -0700366}
Aaron Durbinf56c7782017-01-10 17:44:42 -0600367
Frans Hendriks7e220ca2019-06-28 10:18:22 +0200368uint16_t tlcl_get_hash_size_from_algo(TPMI_ALG_HASH hash_algo)
369{
370 uint16_t value;
371
372 switch (hash_algo) {
373 case TPM_ALG_ERROR:
374 value = 1;
375 break;
376 case TPM_ALG_SHA1:
377 value = SHA1_DIGEST_SIZE;
378 break;
379 case TPM_ALG_SHA256:
380 value = SHA256_DIGEST_SIZE;
381 break;
382 case TPM_ALG_SHA384:
383 value = SHA384_DIGEST_SIZE;
384 break;
385 case TPM_ALG_SHA512:
386 value = SHA512_DIGEST_SIZE;
387 break;
388 case TPM_ALG_SM3_256:
389 value = SM3_256_DIGEST_SIZE;
390 break;
391 default:
392 printk(BIOS_SPEW, "%s: unknown hash algorithm %d\n", __func__,
393 hash_algo);
394 value = 0;
395 };
396
397 return value;
398}
399
Aaron Durbinf56c7782017-01-10 17:44:42 -0600400uint32_t tlcl_disable_platform_hierarchy(void)
401{
402 struct tpm2_response *response;
403 struct tpm2_hierarchy_control_cmd hc = {
404 .enable = TPM_RH_PLATFORM,
405 .state = 0,
406 };
407
408 response = tpm_process_command(TPM2_Hierarchy_Control, &hc);
409
410 if (!response || response->hdr.tpm_code)
411 return TPM_E_INTERNAL_INCONSISTENCY;
412
413 return TPM_SUCCESS;
414}
Frans Hendriks589eff72019-06-26 10:43:40 +0200415
416uint32_t tlcl_get_capability(TPM_CAP capability, uint32_t property,
417 uint32_t property_count,
418 TPMS_CAPABILITY_DATA *capability_data)
419{
420 struct tpm2_get_capability cmd;
421 struct tpm2_response *response;
422
423 cmd.capability = capability;
424 cmd.property = property;
425 cmd.propertyCount = property_count;
426
427 if (property_count > 1) {
428 printk(BIOS_ERR, "%s: property_count more than one not "
429 "supported yet\n", __func__);
430 return TPM_E_IOERROR;
431 }
432
433 response = tpm_process_command(TPM2_GetCapability, &cmd);
434
435 if (!response) {
436 printk(BIOS_ERR, "%s: Command Failed\n", __func__);
437 return TPM_E_IOERROR;
438 }
439
440 memcpy(capability_data, &response->gc.cd, sizeof(TPMS_CAPABILITY_DATA));
441 return TPM_SUCCESS;
442}