blob: cfa533b880cb6d7376e7464052e080510454e5b4 [file] [log] [blame]
Jacob Garberfa8f5672020-05-18 13:18:19 -06001/* SPDX-License-Identifier: BSD-3-Clause */
Vadim Bendebury245d4572016-04-05 16:01:57 -07002
3#include <console/console.h>
4#include <endian.h>
Vadim Bendebury245d4572016-04-05 16:01:57 -07005#include <string.h>
Vadim Bendebury245d4572016-04-05 16:01:57 -07006#include <vb2_api.h>
Philipp Deppenwiese86391f12017-10-18 21:54:24 +02007#include <security/tpm/tis.h>
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +01008#include <security/tpm/tss.h>
Vadim Bendebury245d4572016-04-05 16:01:57 -07009
Philipp Deppenwiesed88fb362017-10-18 20:26:18 +020010#include "tss_structures.h"
11#include "tss_marshaling.h"
Vadim Bendebury245d4572016-04-05 16:01:57 -070012
13/*
14 * This file provides interface between firmware and TPM2 device. The TPM1.2
15 * API was copied as is and relevant functions modified to comply with the
16 * TPM2 specification.
17 */
18
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +010019void *tpm_process_command(TPM_CC command, void *command_body)
Vadim Bendebury245d4572016-04-05 16:01:57 -070020{
Aaron Durbinee049fa2017-03-25 00:38:45 -050021 struct obuf ob;
22 struct ibuf ib;
23 size_t out_size;
Duncan Laurieed75b272016-07-15 04:51:45 -070024 size_t in_size;
Aaron Durbinee049fa2017-03-25 00:38:45 -050025 const uint8_t *sendb;
Vadim Bendebury245d4572016-04-05 16:01:57 -070026 /* Command/response buffer. */
Arthur Heymans0ca944b2019-11-20 19:51:06 +010027 static uint8_t cr_buffer[TPM_BUFFER_SIZE];
Victor Prupisf7060202016-08-19 10:45:04 -070028
Arthur Heymans0ca944b2019-11-20 19:51:06 +010029 obuf_init(&ob, cr_buffer, sizeof(cr_buffer));
Aaron Durbinee049fa2017-03-25 00:38:45 -050030
31 if (tpm_marshal_command(command, command_body, &ob) < 0) {
32 printk(BIOS_ERR, "command %#x\n", command);
Vadim Bendebury245d4572016-04-05 16:01:57 -070033 return NULL;
34 }
35
Aaron Durbinee049fa2017-03-25 00:38:45 -050036 sendb = obuf_contents(&ob, &out_size);
37
Vadim Bendebury245d4572016-04-05 16:01:57 -070038 in_size = sizeof(cr_buffer);
Arthur Heymans0ca944b2019-11-20 19:51:06 +010039 if (tis_sendrecv(sendb, out_size, cr_buffer, &in_size)) {
Vadim Bendebury245d4572016-04-05 16:01:57 -070040 printk(BIOS_ERR, "tpm transaction failed\n");
41 return NULL;
42 }
43
Arthur Heymans0ca944b2019-11-20 19:51:06 +010044 ibuf_init(&ib, cr_buffer, in_size);
Aaron Durbinee049fa2017-03-25 00:38:45 -050045
46 return tpm_unmarshal_response(command, &ib);
Vadim Bendebury245d4572016-04-05 16:01:57 -070047}
48
Furquan Shaikhcc3365a2016-09-30 12:53:19 -070049static uint32_t tlcl_send_startup(TPM_SU type)
50{
51 struct tpm2_startup startup;
52 struct tpm2_response *response;
53
54 startup.startup_type = type;
55 response = tpm_process_command(TPM2_Startup, &startup);
56
Joel Kitchingc5d0a2e2018-10-12 15:52:00 +080057 /* IO error, tpm2_response pointer is empty. */
58 if (response == NULL) {
59 printk(BIOS_ERR, "%s: TPM communication error\n", __func__);
60 return TPM_E_IOERROR;
Furquan Shaikhcc3365a2016-09-30 12:53:19 -070061 }
Joel Kitchingc5d0a2e2018-10-12 15:52:00 +080062
Joel Kitchingf97ff0c2018-09-26 17:52:54 +080063 printk(BIOS_INFO, "%s: Startup return code is %x\n",
64 __func__, response->hdr.tpm_code);
Joel Kitchingc5d0a2e2018-10-12 15:52:00 +080065
66 switch (response->hdr.tpm_code) {
67 case TPM_RC_INITIALIZE:
68 /* TPM already initialized. */
69 return TPM_E_INVALID_POSTINIT;
70 case TPM2_RC_SUCCESS:
71 return TPM_SUCCESS;
72 }
73
74 /* Collapse any other errors into TPM_E_IOERROR. */
Joel Kitchingf97ff0c2018-09-26 17:52:54 +080075 return TPM_E_IOERROR;
Furquan Shaikhcc3365a2016-09-30 12:53:19 -070076}
77
Vadim Bendebury245d4572016-04-05 16:01:57 -070078uint32_t tlcl_resume(void)
79{
Furquan Shaikhcc3365a2016-09-30 12:53:19 -070080 return tlcl_send_startup(TPM_SU_STATE);
Vadim Bendebury245d4572016-04-05 16:01:57 -070081}
82
Joel Kitching2e690ee2018-11-15 16:48:53 +080083static uint32_t tlcl_send_shutdown(TPM_SU type)
84{
85 struct tpm2_shutdown shutdown;
86 struct tpm2_response *response;
87
88 shutdown.shutdown_type = type;
89 response = tpm_process_command(TPM2_Shutdown, &shutdown);
90
91 /* IO error, tpm2_response pointer is empty. */
92 if (response == NULL) {
93 printk(BIOS_ERR, "%s: TPM communication error\n", __func__);
94 return TPM_E_IOERROR;
95 }
96
97 printk(BIOS_INFO, "%s: Shutdown return code is %x\n",
98 __func__, response->hdr.tpm_code);
99
100 if (response->hdr.tpm_code == TPM2_RC_SUCCESS)
101 return TPM_SUCCESS;
102
103 /* Collapse any other errors into TPM_E_IOERROR. */
104 return TPM_E_IOERROR;
105}
106
107uint32_t tlcl_save_state(void)
108{
109 return tlcl_send_shutdown(TPM_SU_STATE);
110}
111
Vadim Bendebury245d4572016-04-05 16:01:57 -0700112uint32_t tlcl_assert_physical_presence(void)
113{
114 /*
115 * Nothing to do on TPM2 for this, use platform hierarchy availability
116 * instead.
117 */
118 return TPM_SUCCESS;
119}
120
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700121/*
Julius Wernerb3426c02019-09-11 14:24:47 -0700122 * The caller will provide the digest in a 32 byte buffer, let's consider it a
123 * sha256 digest.
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700124 */
Vadim Bendebury245d4572016-04-05 16:01:57 -0700125uint32_t tlcl_extend(int pcr_num, const uint8_t *in_digest,
126 uint8_t *out_digest)
127{
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700128 struct tpm2_pcr_extend_cmd pcr_ext_cmd;
129 struct tpm2_response *response;
130
131 pcr_ext_cmd.pcrHandle = HR_PCR + pcr_num;
Julius Wernerb3426c02019-09-11 14:24:47 -0700132 pcr_ext_cmd.digests.count = 1;
133 pcr_ext_cmd.digests.digests[0].hashAlg = TPM_ALG_SHA256;
134 memcpy(pcr_ext_cmd.digests.digests[0].digest.sha256, in_digest,
135 sizeof(pcr_ext_cmd.digests.digests[0].digest.sha256));
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700136
137 response = tpm_process_command(TPM2_PCR_Extend, &pcr_ext_cmd);
138
Julius Wernerb3426c02019-09-11 14:24:47 -0700139 printk(BIOS_INFO, "%s: response is %x\n",
Vadim Bendeburyf5ef6992016-07-03 22:20:17 -0700140 __func__, response ? response->hdr.tpm_code : -1);
141 if (!response || response->hdr.tpm_code)
142 return TPM_E_IOERROR;
143
Vadim Bendebury245d4572016-04-05 16:01:57 -0700144 return TPM_SUCCESS;
145}
146
147uint32_t tlcl_finalize_physical_presence(void)
148{
149 /* Nothing needs to be done with tpm2. */
150 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
151 return TPM_SUCCESS;
152}
153
154uint32_t tlcl_force_clear(void)
155{
Vadim Bendeburyadfbbde2016-07-03 15:56:41 -0700156 struct tpm2_response *response;
157
158 response = tpm_process_command(TPM2_Clear, NULL);
159 printk(BIOS_INFO, "%s: response is %x\n",
160 __func__, response ? response->hdr.tpm_code : -1);
161
162 if (!response || response->hdr.tpm_code)
163 return TPM_E_IOERROR;
164
Vadim Bendebury245d4572016-04-05 16:01:57 -0700165 return TPM_SUCCESS;
166}
167
Christian Walterc9ac0bc2020-01-28 19:54:33 +0100168uint32_t tlcl_clear_control(bool disable)
169{
170 struct tpm2_response *response;
171 struct tpm2_clear_control_cmd cc = {
172 .disable = 0,
173 };
174
175 response = tpm_process_command(TPM2_ClearControl, &cc);
176 printk(BIOS_INFO, "%s: response is %x\n",
177 __func__, response ? response->hdr.tpm_code : -1);
178
179 if (!response || response->hdr.tpm_code)
180 return TPM_E_IOERROR;
181
182 return TPM_SUCCESS;
183}
184
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100185static uint8_t tlcl_init_done;
Furquan Shaikh8b5d04e2016-11-10 09:49:05 -0800186
187/* This function is called directly by vboot, uses vboot return types. */
Vadim Bendebury245d4572016-04-05 16:01:57 -0700188uint32_t tlcl_lib_init(void)
189{
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100190 if (tlcl_init_done)
Furquan Shaikh8b5d04e2016-11-10 09:49:05 -0800191 return VB2_SUCCESS;
192
Frans Hendriks3891d272019-06-12 11:14:55 +0200193 if (tis_init()) {
194 printk(BIOS_ERR, "%s: tis_init returned error\n", __func__);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700195 return VB2_ERROR_UNKNOWN;
Frans Hendriks3891d272019-06-12 11:14:55 +0200196 }
197
198 if (tis_open()) {
199 printk(BIOS_ERR, "%s: tis_open returned error\n", __func__);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700200 return VB2_ERROR_UNKNOWN;
Frans Hendriks3891d272019-06-12 11:14:55 +0200201 }
Furquan Shaikh8b5d04e2016-11-10 09:49:05 -0800202
Arthur Heymans0ca944b2019-11-20 19:51:06 +0100203 tlcl_init_done = 1;
Furquan Shaikh8b5d04e2016-11-10 09:49:05 -0800204
Vadim Bendebury245d4572016-04-05 16:01:57 -0700205 return VB2_SUCCESS;
206}
207
208uint32_t tlcl_physical_presence_cmd_enable(void)
209{
210 printk(BIOS_INFO, "%s:%s:%d\n", __FILE__, __func__, __LINE__);
211 return TPM_SUCCESS;
212}
213
214uint32_t tlcl_read(uint32_t index, void *data, uint32_t length)
215{
216 struct tpm2_nv_read_cmd nv_readc;
217 struct tpm2_response *response;
218
219 memset(&nv_readc, 0, sizeof(nv_readc));
220
221 nv_readc.nvIndex = HR_NV_INDEX + index;
222 nv_readc.size = length;
223
224 response = tpm_process_command(TPM2_NV_Read, &nv_readc);
225
226 /* Need to map tpm error codes into internal values. */
227 if (!response)
228 return TPM_E_READ_FAILURE;
229
230 printk(BIOS_INFO, "%s:%d index %#x return code %x\n",
231 __FILE__, __LINE__, index, response->hdr.tpm_code);
232 switch (response->hdr.tpm_code) {
233 case 0:
234 break;
235
Vadim Bendebury08f93592017-06-21 12:23:22 -0700236 /* Uninitialized, returned if the space hasn't been written. */
237 case TPM_RC_NV_UNINITIALIZED:
238 /*
239 * Bad index, cr50 specific value, returned if the space
240 * hasn't been defined.
241 */
242 case TPM_RC_CR50_NV_UNDEFINED:
Vadim Bendebury245d4572016-04-05 16:01:57 -0700243 return TPM_E_BADINDEX;
244
245 default:
246 return TPM_E_READ_FAILURE;
247 }
248
249 if (length > response->nvr.buffer.t.size)
250 return TPM_E_RESPONSE_TOO_LARGE;
251
252 if (length < response->nvr.buffer.t.size)
253 return TPM_E_READ_EMPTY;
254
255 memcpy(data, response->nvr.buffer.t.buffer, length);
256
257 return TPM_SUCCESS;
258}
259
260uint32_t tlcl_self_test_full(void)
261{
262 struct tpm2_self_test st;
263 struct tpm2_response *response;
264
265 st.yes_no = 1;
266
267 response = tpm_process_command(TPM2_SelfTest, &st);
268 printk(BIOS_INFO, "%s: response is %x\n",
269 __func__, response ? response->hdr.tpm_code : -1);
270 return TPM_SUCCESS;
271}
272
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700273uint32_t tlcl_lock_nv_write(uint32_t index)
Vadim Bendebury245d4572016-04-05 16:01:57 -0700274{
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700275 struct tpm2_response *response;
Martin Roth50863da2021-10-01 14:37:30 -0600276 /* TPM Will reject attempts to write at non-defined index. */
Vadim Bendebury4c0851c2016-07-03 17:08:10 -0700277 struct tpm2_nv_write_lock_cmd nv_wl = {
278 .nvIndex = HR_NV_INDEX + index,
279 };
280
281 response = tpm_process_command(TPM2_NV_WriteLock, &nv_wl);
282
283 printk(BIOS_INFO, "%s: response is %x\n",
284 __func__, response ? response->hdr.tpm_code : -1);
285
286 if (!response || response->hdr.tpm_code)
287 return TPM_E_IOERROR;
288
Vadim Bendebury245d4572016-04-05 16:01:57 -0700289 return TPM_SUCCESS;
290}
291
292uint32_t tlcl_startup(void)
293{
Furquan Shaikhcc3365a2016-09-30 12:53:19 -0700294 return tlcl_send_startup(TPM_SU_CLEAR);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700295}
296
297uint32_t tlcl_write(uint32_t index, const void *data, uint32_t length)
298{
299 struct tpm2_nv_write_cmd nv_writec;
300 struct tpm2_response *response;
301
302 memset(&nv_writec, 0, sizeof(nv_writec));
303
304 nv_writec.nvIndex = HR_NV_INDEX + index;
305 nv_writec.data.t.size = length;
306 nv_writec.data.t.buffer = data;
307
308 response = tpm_process_command(TPM2_NV_Write, &nv_writec);
309
Vadim Bendebury1ec76032016-07-05 22:30:16 -0700310 printk(BIOS_INFO, "%s: response is %x\n",
311 __func__, response ? response->hdr.tpm_code : -1);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700312
Vadim Bendebury1ec76032016-07-05 22:30:16 -0700313 /* Need to map tpm error codes into internal values. */
314 if (!response || response->hdr.tpm_code)
315 return TPM_E_WRITE_FAILURE;
Vadim Bendebury245d4572016-04-05 16:01:57 -0700316
317 return TPM_SUCCESS;
318}
319
Aseda Aboagye4ad04202021-05-24 16:47:09 -0700320uint32_t tlcl_set_bits(uint32_t index, uint64_t bits)
321{
322 struct tpm2_nv_setbits_cmd nvsb_cmd;
323 struct tpm2_response *response;
324
325 /* Prepare the command structure */
326 memset(&nvsb_cmd, 0, sizeof(nvsb_cmd));
327
328 nvsb_cmd.nvIndex = HR_NV_INDEX + index;
329 nvsb_cmd.bits = bits;
330
331 response = tpm_process_command(TPM2_NV_SetBits, &nvsb_cmd);
332
333 printk(BIOS_INFO, "%s: response is %x\n",
334 __func__, response ? response->hdr.tpm_code : -1);
335
336 /* Need to map tpm error codes into internal values. */
337 if (!response || response->hdr.tpm_code)
338 return TPM_E_WRITE_FAILURE;
339
340 return TPM_SUCCESS;
341}
342
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100343uint32_t tlcl_define_space(uint32_t space_index, size_t space_size,
344 const TPMA_NV nv_attributes,
345 const uint8_t *nv_policy, size_t nv_policy_size)
Vadim Bendebury245d4572016-04-05 16:01:57 -0700346{
347 struct tpm2_nv_define_space_cmd nvds_cmd;
348 struct tpm2_response *response;
349
350 /* Prepare the define space command structure. */
351 memset(&nvds_cmd, 0, sizeof(nvds_cmd));
352
353 nvds_cmd.publicInfo.dataSize = space_size;
354 nvds_cmd.publicInfo.nvIndex = HR_NV_INDEX + space_index;
355 nvds_cmd.publicInfo.nameAlg = TPM_ALG_SHA256;
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100356 nvds_cmd.publicInfo.attributes = nv_attributes;
Vadim Bendebury245d4572016-04-05 16:01:57 -0700357
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100358 /*
359 * Use policy digest based on default pcr0 value. This makes
360 * sure that the space can not be deleted as soon as PCR0
361 * value has been extended from default.
362 */
363 if (nv_policy && nv_policy_size) {
364 nvds_cmd.publicInfo.authPolicy.t.buffer = nv_policy;
365 nvds_cmd.publicInfo.authPolicy.t.size = nv_policy_size;
Vadim Bendebury289ee8f2016-11-11 09:36:50 -0800366 }
Vadim Bendebury245d4572016-04-05 16:01:57 -0700367
368 response = tpm_process_command(TPM2_NV_DefineSpace, &nvds_cmd);
Philipp Deppenwiesec07f8fb2018-02-27 19:40:52 +0100369 printk(BIOS_INFO, "%s: response is %x\n", __func__,
370 response ? response->hdr.tpm_code : -1);
Vadim Bendebury245d4572016-04-05 16:01:57 -0700371
372 if (!response)
373 return TPM_E_NO_DEVICE;
374
Martin Roth50863da2021-10-01 14:37:30 -0600375 /* Map TPM2 return codes into common vboot representation. */
Lee Leahy45fde702017-03-08 18:02:24 -0800376 switch (response->hdr.tpm_code) {
Vadim Bendeburyaf8ae932016-11-11 14:15:31 -0800377 case TPM2_RC_SUCCESS:
378 return TPM_SUCCESS;
379 case TPM2_RC_NV_DEFINED:
380 return TPM_E_NV_DEFINED;
381 default:
382 return TPM_E_INTERNAL_INCONSISTENCY;
383 }
Vadim Bendebury245d4572016-04-05 16:01:57 -0700384}
Aaron Durbinf56c7782017-01-10 17:44:42 -0600385
Frans Hendriks7e220ca2019-06-28 10:18:22 +0200386uint16_t tlcl_get_hash_size_from_algo(TPMI_ALG_HASH hash_algo)
387{
388 uint16_t value;
389
390 switch (hash_algo) {
391 case TPM_ALG_ERROR:
392 value = 1;
393 break;
394 case TPM_ALG_SHA1:
395 value = SHA1_DIGEST_SIZE;
396 break;
397 case TPM_ALG_SHA256:
398 value = SHA256_DIGEST_SIZE;
399 break;
400 case TPM_ALG_SHA384:
401 value = SHA384_DIGEST_SIZE;
402 break;
403 case TPM_ALG_SHA512:
404 value = SHA512_DIGEST_SIZE;
405 break;
406 case TPM_ALG_SM3_256:
407 value = SM3_256_DIGEST_SIZE;
408 break;
409 default:
410 printk(BIOS_SPEW, "%s: unknown hash algorithm %d\n", __func__,
411 hash_algo);
412 value = 0;
413 };
414
415 return value;
416}
417
Aaron Durbinf56c7782017-01-10 17:44:42 -0600418uint32_t tlcl_disable_platform_hierarchy(void)
419{
420 struct tpm2_response *response;
421 struct tpm2_hierarchy_control_cmd hc = {
422 .enable = TPM_RH_PLATFORM,
423 .state = 0,
424 };
425
426 response = tpm_process_command(TPM2_Hierarchy_Control, &hc);
427
428 if (!response || response->hdr.tpm_code)
429 return TPM_E_INTERNAL_INCONSISTENCY;
430
431 return TPM_SUCCESS;
432}
Frans Hendriks589eff72019-06-26 10:43:40 +0200433
434uint32_t tlcl_get_capability(TPM_CAP capability, uint32_t property,
435 uint32_t property_count,
436 TPMS_CAPABILITY_DATA *capability_data)
437{
438 struct tpm2_get_capability cmd;
439 struct tpm2_response *response;
440
441 cmd.capability = capability;
442 cmd.property = property;
443 cmd.propertyCount = property_count;
444
445 if (property_count > 1) {
446 printk(BIOS_ERR, "%s: property_count more than one not "
447 "supported yet\n", __func__);
448 return TPM_E_IOERROR;
449 }
450
451 response = tpm_process_command(TPM2_GetCapability, &cmd);
452
453 if (!response) {
454 printk(BIOS_ERR, "%s: Command Failed\n", __func__);
455 return TPM_E_IOERROR;
456 }
457
458 memcpy(capability_data, &response->gc.cd, sizeof(TPMS_CAPABILITY_DATA));
459 return TPM_SUCCESS;
460}